From 9153f966c1cd87438c31ca9d6116a6fc0f431245 Mon Sep 17 00:00:00 2001 From: David Viejo Date: Thu, 6 Aug 2026 10:38:35 +0200 Subject: [PATCH 1/7] feat(settings): apply releases and restart from the console MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The console already told operators a newer release existed and then left them to SSH in. This adds the missing action to that banner: an "Update now" button that downloads the release, verifies its published SHA-256, swaps the binary and exits so the supervisor restarts temps on it. The download/verify/swap machinery is reused from `temps upgrade`. What is new is deciding honestly whether the process will actually come back, and reporting the result of an operation that kills the process that started it: - Supervision is detected up front (systemd `INVOCATION_ID`, launchd `XPC_SERVICE_NAME`, container markers). Containers and unsupervised processes are refused with the reason and the command to run instead, rather than exiting into permanent downtime. - The attempt is journalled to `/self-update.json` before the exit and resolved on the next boot by comparing the running version to the target, so the console can report "updated to X" or "came back on the old version" instead of a spinner. - The new binary must answer `--version` before it is moved into place, and the replaced one is kept as a `.bak` sibling for rollback. - A missing checksum fails closed here, unlike the interactive CLI where a human can judge. Two independent off switches, since an operator may want to forbid this entirely: - `temps serve --disable-self-update` — bootstrap flag, cannot be cleared over the API. - `self_update.enabled` in settings — runtime toggle in Settings → Platform. The flag wins. Gated on a new `platform:update` permission rather than `settings:write`: replacing the running binary and dropping in-flight requests is a different class of action from editing a config value, so custom roles scoped to settings must not inherit it. Every attempt is audited as `PLATFORM_UPDATE_STARTED` before the process exits. Adds `GET/POST /settings/update` with CLI parity as `temps platform update status|apply`. --- apps/temps-cli/openapi.json | 2 +- apps/temps-cli/src/api/index.ts | 4 +- apps/temps-cli/src/api/sdk.gen.ts | 45 +- apps/temps-cli/src/api/types.gen.ts | 317 +++++- apps/temps-cli/src/commands/platform/index.ts | 248 ++++- crates/temps-auth/src/permissions.rs | 11 + .../temps-cli/src/commands/serve/console.rs | 10 + crates/temps-cli/src/commands/serve/mod.rs | 35 + .../src/commands/serve/self_update.rs | 929 ++++++++++++++++++ crates/temps-cli/src/commands/upgrade.rs | 16 +- crates/temps-config/src/handler.rs | 323 ++++++ crates/temps-config/src/plugin.rs | 5 + crates/temps-core/src/app_settings.rs | 31 + crates/temps-core/src/lib.rs | 7 +- crates/temps-core/src/self_update.rs | 309 ++++++ .../api/client/@tanstack/react-query.gen.ts | 44 +- web/src/api/client/index.ts | 4 +- web/src/api/client/sdk.gen.ts | 29 +- web/src/api/client/types.gen.ts | 250 +++++ web/src/api/platformSettings.ts | 4 + .../alerts/UpdateAvailableBanner.tsx | 124 ++- web/src/components/alerts/UpdateNowDialog.tsx | 373 +++++++ .../settings/PlatformUpdatesCard.tsx | 115 +++ web/src/hooks/useSelfUpdate.ts | 60 ++ web/src/pages/Settings.tsx | 4 + 25 files changed, 3235 insertions(+), 64 deletions(-) create mode 100644 crates/temps-cli/src/commands/serve/self_update.rs create mode 100644 crates/temps-core/src/self_update.rs create mode 100644 web/src/components/alerts/UpdateNowDialog.tsx create mode 100644 web/src/components/settings/PlatformUpdatesCard.tsx create mode 100644 web/src/hooks/useSelfUpdate.ts diff --git a/apps/temps-cli/openapi.json b/apps/temps-cli/openapi.json index 713698cf4..d4523c0be 100644 --- a/apps/temps-cli/openapi.json +++ b/apps/temps-cli/openapi.json @@ -1 +1 @@ -{"openapi":"3.1.0","info":{"title":"Temps","description":"An API for managing projects, deployments, and infrastructure resources","contact":{"name":"Temps Support","url":"https://temps.sh"},"version":"1.0.0"},"servers":[{"url":"/api","description":"Base path for all API endpoints"}],"paths":{"/.well-known/temps.json":{"get":{"tags":["Platform"],"summary":"Get platform information","operationId":"get_platform_info","responses":{"200":{"description":"Successfully retrieved platform information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlatformInfo"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/0/organizations/{org_slug}/chunk-upload/":{"get":{"tags":["sentry-compat"],"summary":"Chunk upload options (stub for sentry-cli compatibility).","description":"sentry-cli checks this endpoint to determine if chunk-based upload is supported.\nWe return a response indicating that chunk upload is NOT supported, which forces\nsentry-cli to fall back to the standard file-by-file upload.","operationId":"chunk_upload_options","parameters":[{"name":"org_slug","in":"path","description":"Organization slug (ignored)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Chunk upload options","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryChunkUploadResponse"}}}}}}},"/0/organizations/{org_slug}/releases/":{"post":{"tags":["sentry-compat"],"summary":"Create a release (stub for sentry-cli compatibility).","description":"sentry-cli calls this before uploading files. Since Temps implicitly creates\nreleases when source maps are uploaded, this is a no-op that returns the\nexpected response format.","operationId":"create_release","parameters":[{"name":"org_slug","in":"path","description":"Organization slug (ignored in single-tenant mode)","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryCreateReleaseRequest"}}},"required":true},"responses":{"201":{"description":"Release created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryReleaseResponse"}}}},"401":{"description":"Unauthorized"}}}},"/0/projects/{org_slug}/{project_slug}/releases/":{"post":{"tags":["sentry-compat"],"summary":"Create a release for a specific project (stub for sentry-cli compatibility).","description":"sentry-cli calls this endpoint (instead of /organizations/.../releases/) when\nboth SENTRY_ORG and SENTRY_PROJECT env vars are set. Behaves identically to\nthe organizations endpoint but validates the project slug.","operationId":"create_project_release","parameters":[{"name":"org_slug","in":"path","description":"Organization slug (ignored in single-tenant mode)","required":true,"schema":{"type":"string"}},{"name":"project_slug","in":"path","description":"Project slug or numeric ID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryCreateReleaseRequest"}}},"required":true},"responses":{"201":{"description":"Release created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryReleaseResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Project not found"}}}},"/0/projects/{org_slug}/{project_slug}/releases/{version}/":{"put":{"tags":["sentry-compat"],"summary":"Finalize a release (stub for sentry-cli compatibility).","description":"sentry-cli calls `releases finalize` after uploading source maps. This sets\nthe dateReleased on the release. Since Temps stores source maps independently\nof releases, this is a no-op that returns the expected response.","operationId":"finalize_project_release","parameters":[{"name":"org_slug","in":"path","description":"Organization slug (ignored)","required":true,"schema":{"type":"string"}},{"name":"project_slug","in":"path","description":"Project slug or numeric ID","required":true,"schema":{"type":"string"}},{"name":"version","in":"path","description":"Release version to finalize","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Release finalized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryReleaseResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Project not found"}}}},"/0/projects/{org_slug}/{project_slug}/releases/{version}/files/":{"get":{"tags":["sentry-compat"],"summary":"List files for a release.","description":"Returns all source maps stored for a specific release in sentry-cli compatible format.","operationId":"list_release_files","parameters":[{"name":"org_slug","in":"path","description":"Organization slug (ignored)","required":true,"schema":{"type":"string"}},{"name":"project_slug","in":"path","description":"Project slug or numeric ID","required":true,"schema":{"type":"string"}},{"name":"version","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of release files","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SentryReleaseFileResponse"}}}}},"401":{"description":"Unauthorized"},"404":{"description":"Project not found"}}},"post":{"tags":["sentry-compat"],"summary":"Upload a source map file for a release.","description":"Accepts the same multipart format as the Sentry release files API.\nThe `name` field should be the URL path of the file (e.g., `~/dist/bundle.js.map`).\n\nThe route has a 50 MiB body limit applied at the router level (Fix #4).\nA per-field size check provides an additional defense-in-depth layer.","operationId":"upload_release_file","parameters":[{"name":"org_slug","in":"path","description":"Organization slug (ignored)","required":true,"schema":{"type":"string"}},{"name":"project_slug","in":"path","description":"Project slug or numeric ID","required":true,"schema":{"type":"string"}},{"name":"version","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"201":{"description":"File uploaded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryReleaseFileResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"404":{"description":"Project not found"},"413":{"description":"Source map file exceeds the 50 MiB per-field limit"}}}},"/_temps/event":{"post":{"tags":["Metrics"],"summary":"Record analytics event","operationId":"record_event_metrics","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventMetricsPayload"}}},"required":true},"responses":{"204":{"description":"Event recorded successfully"},"400":{"description":"Bad request"},"500":{"description":"Internal server error"}}}},"/_temps/session-replay/events":{"post":{"tags":["Analytics"],"summary":"Add events to existing session replay","operationId":"add_session_replay_events","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionReplayEventsRequest"}}},"required":true},"responses":{"200":{"description":"Events added successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddEventsResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Session not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/_temps/session-replay/init":{"post":{"tags":["Analytics"],"summary":"Initialize session replay with metadata","operationId":"init_session_replay","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionReplayInitRequest"}}},"required":true},"responses":{"201":{"description":"Session initialized successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionReplayInitResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/_temps/speed":{"post":{"tags":["Performance"],"summary":"Record performance metrics from client","operationId":"record_speed_metrics","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpeedMetricsPayload"}}},"required":true},"responses":{"204":{"description":"Metrics recorded successfully"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Host not found in route table","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/_temps/speed/update":{"post":{"tags":["Performance"],"summary":"Update late performance metrics","operationId":"update_speed_metrics","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSpeedMetricsPayload"}}},"required":true},"responses":{"204":{"description":"Metrics updated successfully"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Host not found or metrics not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/admin/gate-settings":{"get":{"tags":["AdminGate"],"operationId":"get_admin_gate","responses":{"200":{"description":"Current admin gate config","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminGateResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["AdminGate"],"operationId":"patch_admin_gate","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAdminGateRequest"}}},"required":true},"responses":{"200":{"description":"Updated admin gate config","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminGateResponse"}}}},"400":{"description":"Invalid IP/CIDR/host"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"409":{"description":"Env-overridden or would lock out caller"}},"security":[{"bearer_auth":[]}]}},"/admin/oidc/providers":{"get":{"tags":["Authentication"],"operationId":"list_oidc_providers","responses":{"200":{"description":"OIDC providers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/OidcProviderResponse"}}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Authentication"],"operationId":"create_oidc_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateOidcProviderRequest"}}},"required":true},"responses":{"201":{"description":"OIDC provider created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OidcProviderResponse"}}}},"409":{"description":"Another OIDC provider already uses that name"}},"security":[{"bearer_auth":[]}]}},"/admin/oidc/providers/{provider_id}":{"delete":{"tags":["Authentication"],"operationId":"delete_oidc_provider","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"OIDC provider deleted"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Authentication"],"operationId":"update_oidc_provider","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateOidcProviderRequest"}}},"required":true},"responses":{"200":{"description":"OIDC provider updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OidcProviderResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/admin/oidc/providers/{provider_id}/role-mappings":{"get":{"tags":["Authentication"],"operationId":"list_oidc_role_mappings","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"OIDC role mappings","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/OidcRoleMappingResponse"}}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Authentication"],"operationId":"create_oidc_role_mapping","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateOidcRoleMappingRequest"}}},"required":true},"responses":{"201":{"description":"Role mapping created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OidcRoleMappingResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/admin/oidc/providers/{provider_id}/test":{"post":{"tags":["Authentication"],"operationId":"test_oidc_provider","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Connection test result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OidcTestConnectionResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/admin/oidc/providers/{provider_id}/users":{"get":{"tags":["Authentication"],"operationId":"list_oidc_provider_users","parameters":[{"name":"provider_id","in":"path","description":"OIDC provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Users authenticated via this OIDC provider","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/OidcProviderUserResponse"}}}}},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]}},"/admin/oidc/role-mappings/{mapping_id}":{"delete":{"tags":["Authentication"],"operationId":"delete_oidc_role_mapping","parameters":[{"name":"mapping_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Role mapping deleted"}},"security":[{"bearer_auth":[]}]}},"/agents/webhook/{webhook_id}":{"post":{"tags":["Agents"],"summary":"Public webhook endpoint. Authenticated via `X-Webhook-Token` header.","description":"`POST /api/agents/webhook/{webhook_id}`\nHeader: `X-Webhook-Token: `\n\nThe `webhook_id` in the URL is a short non-secret identifier (safe to log).\nThe actual credential is the secret token in the header.\n\nAccepts any JSON body, which is passed as `user_context` to the agent run.","operationId":"webhook_trigger","parameters":[{"name":"webhook_id","in":"path","description":"Webhook ID (non-secret)","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookTriggerRequest"}}},"required":true},"responses":{"202":{"description":"Agent run created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookTriggerResponse"}}}},"401":{"description":"Missing or invalid X-Webhook-Token header"},"404":{"description":"Invalid webhook ID"},"422":{"description":"Agent disabled"}}}},"/ai/conversations":{"get":{"tags":["AI Chat"],"summary":"List every active conversation across all projects, most-recently-active\nfirst, annotated with project name/slug. Powers the unified \"all chats\"\nswitcher in the AI assistant dock.","operationId":"list_all_conversations","responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GlobalConversationResponse"}}}}},"401":{"description":""},"403":{"description":""}},"security":[{"bearer_auth":[]}]}},"/ai/pricing":{"get":{"tags":["AI Gateway Pricing"],"operationId":"get_pricing","responses":{"200":{"description":"Model pricing information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PricingResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/providers":{"get":{"tags":["AI Gateway Admin"],"operationId":"list_provider_keys","responses":{"200":{"description":"List of provider keys","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProviderKeyResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["AI Gateway Admin"],"operationId":"create_provider_key","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProviderKeyRequest"}}},"required":true},"responses":{"201":{"description":"Provider key created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderKeyResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/providers/test":{"post":{"tags":["AI Gateway Admin"],"operationId":"test_provider_key_inline","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestProviderKeyRequest"}}},"required":true},"responses":{"200":{"description":"Test result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestProviderKeyResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/providers/{id}":{"delete":{"tags":["AI Gateway Admin"],"operationId":"delete_provider_key","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Provider key deleted"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["AI Gateway Admin"],"operationId":"update_provider_key","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProviderKeyRequest"}}},"required":true},"responses":{"200":{"description":"Provider key updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderKeyResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/providers/{id}/test":{"post":{"tags":["AI Gateway Admin"],"operationId":"test_provider_key_by_id","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Test result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestProviderKeyResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Provider key not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/usage/by-provider":{"get":{"tags":["AI Gateway Usage"],"operationId":"get_usage_by_provider","parameters":[{"name":"from","in":"query","description":"ISO 8601 start time (defaults to 24h ago)","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","description":"ISO 8601 end time (defaults to now)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Usage broken down by provider","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProviderUsage"}}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/usage/conversations":{"get":{"tags":["AI Gateway Usage"],"operationId":"get_conversations","parameters":[{"name":"from","in":"query","description":"ISO 8601 start time (defaults to 24h ago)","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","description":"ISO 8601 end time (defaults to now)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max results (defaults to 50, max 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"user_id","in":"query","description":"Filter by user ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"tags","in":"query","description":"Filter by tags (comma-separated)","required":false,"schema":{"type":"string"}},{"name":"model","in":"query","description":"Filter by model name","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Conversation summaries","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ConversationSummary"}}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/usage/conversations/{conversation_id}":{"get":{"tags":["AI Gateway Usage"],"operationId":"get_conversation_detail","parameters":[{"name":"conversation_id","in":"path","description":"Conversation ID","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max results (defaults to 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Invocations within a conversation","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/UsageLogEntry"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/usage/recent":{"get":{"tags":["AI Gateway Usage"],"operationId":"get_usage_recent","parameters":[{"name":"limit","in":"query","description":"Page size (defaults to 20, max 50)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"offset","in":"query","description":"Number of results to skip for pagination (defaults to 0)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"provider","in":"query","description":"Filter by provider name","required":false,"schema":{"type":"string"}},{"name":"model","in":"query","description":"Filter by model name","required":false,"schema":{"type":"string"}},{"name":"status","in":"query","description":"Filter by HTTP status code (exact match)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"cost_gte","in":"query","description":"Cost greater-than-or-equal, in microcents","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"cost_gt","in":"query","description":"Cost strictly greater-than, in microcents","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"cost_lte","in":"query","description":"Cost less-than-or-equal, in microcents","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"cost_lt","in":"query","description":"Cost strictly less-than, in microcents","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"tokens_gte","in":"query","description":"Total tokens greater-than-or-equal","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"tokens_gt","in":"query","description":"Total tokens strictly greater-than","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"tokens_lte","in":"query","description":"Total tokens less-than-or-equal","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"tokens_lt","in":"query","description":"Total tokens strictly less-than","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Page of recent usage log entries","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsageLogPage"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/usage/summary":{"get":{"tags":["AI Gateway Usage"],"operationId":"get_usage_summary","parameters":[{"name":"from","in":"query","description":"ISO 8601 start time (defaults to 24h ago)","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","description":"ISO 8601 end time (defaults to now)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Usage summary for the time range","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsageSummary"}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/usage/timeseries":{"get":{"tags":["AI Gateway Usage"],"operationId":"get_usage_timeseries","parameters":[{"name":"from","in":"query","description":"ISO 8601 start time (defaults to 24h ago)","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","description":"ISO 8601 end time (defaults to now)","required":false,"schema":{"type":"string"}},{"name":"bucket","in":"query","description":"Bucket size: hour, day, week (defaults to day)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Time-series usage data","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TimeseriesBucket"}}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/usage/top-models":{"get":{"tags":["AI Gateway Usage"],"operationId":"get_usage_top_models","parameters":[{"name":"from","in":"query","description":"ISO 8601 start time (defaults to 24h ago)","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","description":"ISO 8601 end time (defaults to now)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max results (defaults to 10)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Top models by request count","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ModelUsage"}}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/v1/chat/completions":{"post":{"tags":["AI Gateway"],"operationId":"chat_completions","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatCompletionRequest"}}},"required":true},"responses":{"200":{"description":"Chat completion response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatCompletionResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}},"404":{"description":"Model not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/v1/embeddings":{"post":{"tags":["AI Gateway"],"operationId":"embeddings","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmbeddingRequest"}}},"required":true},"responses":{"200":{"description":"Embedding response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmbeddingResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}},"404":{"description":"Model not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/v1/models":{"get":{"tags":["AI Gateway"],"operationId":"list_models","responses":{"200":{"description":"List of available models","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelListResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/analytics/active-visitors":{"get":{"tags":["Analytics"],"summary":"Get detailed active visitors","operationId":"get_analytics_active_visitors","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Deployment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"window_minutes","in":"query","description":"Time window in minutes for active visitors (default: 5)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved active visitors","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActiveVisitorsResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/event-detail":{"get":{"tags":["Analytics"],"summary":"Get detailed analytics for a specific event","operationId":"get_event_detail","parameters":[{"name":"event_name","in":"query","description":"Event name to get details for","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date (ISO 8601)","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date (ISO 8601)","required":true,"schema":{"type":"string"}},{"name":"bucket_interval","in":"query","description":"Bucket interval: hour, day, week, month (default: auto)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved event details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventDetailResponse"}}}},"400":{"description":"Invalid parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/event-entries":{"get":{"tags":["Analytics"],"summary":"Get paginated list of raw occurrences of a specific event, including custom JSON properties","operationId":"get_event_entries","parameters":[{"name":"event_name","in":"query","description":"Event name to list occurrences for","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date (ISO 8601)","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date (ISO 8601)","required":true,"schema":{"type":"string"}},{"name":"page","in":"query","description":"Page number (1-based, default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Items per page (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Successfully retrieved event entries","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventEntriesResponse"}}}},"400":{"description":"Invalid parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/event-visitors":{"get":{"tags":["Analytics"],"summary":"Get paginated list of visitors who triggered a specific event","operationId":"get_event_visitors","parameters":[{"name":"event_name","in":"query","description":"Event name to list visitors for","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date (ISO 8601)","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date (ISO 8601)","required":true,"schema":{"type":"string"}},{"name":"page","in":"query","description":"Page number (1-based, default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Items per page (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Successfully retrieved event visitors","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventVisitorsResponse"}}}},"400":{"description":"Invalid parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/events":{"get":{"tags":["Analytics"],"operationId":"get_analytics_events_count","parameters":[{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"limit","in":"query","description":"Maximum number of results to return","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"custom_events_only","in":"query","description":"Only return custom events, excluding system events like page_view, page_leave, heartbeat (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"breakdown","in":"query","description":"Breakdown by geography: 'country', 'region', or 'city' (optional)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved event counts","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EventCount"}}}}},"400":{"description":"Invalid date format, missing required parameters, or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/general-stats":{"get":{"tags":["Analytics"],"summary":"Get general statistics across all projects for a time frame","operationId":"get_general_stats","parameters":[{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"project_ids","in":"query","description":"Optional: Filter by specific project IDs (comma-separated)","required":false,"schema":{"type":"array","items":{"type":"integer","format":"int32"}}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"include_project_breakdown","in":"query","description":"Whether to include per-project breakdown (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Successfully retrieved general statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GeneralStatsResponse"}}}},"400":{"description":"Invalid date format or parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/has-events":{"get":{"tags":["Analytics"],"operationId":"check_analytics_has_events","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Analytics events existence check","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HasAnalyticsEventsResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/live-visitors":{"get":{"tags":["Analytics"],"summary":"Get list of currently live visitors from visitor table","operationId":"get_live_visitors_list","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"window_minutes","in":"query","description":"Time window in minutes for live visitors (default: 5)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved live visitors list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LiveVisitorsListResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/page-flow":{"get":{"tags":["Analytics"],"summary":"Get page flow analytics: entry pages, exit pages, drop-off points, and page transitions","operationId":"get_page_flow","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max entry/exit pages to return (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"transitions_limit","in":"query","description":"Max page transitions to return (default: 50, max: 200)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"min_views_for_dropoff","in":"query","description":"Minimum views for drop-off analysis (default: 5)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved page flow analytics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PageFlowResponse"}}}},"400":{"description":"Invalid parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/page-hourly-sessions":{"get":{"tags":["Analytics"],"operationId":"get_page_hourly_sessions","parameters":[{"name":"page_path","in":"query","description":"The page path to get sessions for","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_time","in":"query","description":"Start time in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"bucket_interval","in":"query","description":"Bucket interval: 'hour', 'day', 'week', or 'month' (default: auto-determined based on range)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved page sessions with time buckets","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PageHourlySessionsResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/page-path-detail":{"get":{"tags":["Analytics"],"summary":"Get detailed analytics for a specific page path\nReturns visitors, page views, activity over time, geographic distribution, and referrers","operationId":"get_page_path_detail","parameters":[{"name":"page_path","in":"query","description":"The page path to get details for (URL-encoded)","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"bucket_interval","in":"query","description":"Bucket interval for time series: 'hour', 'day', 'week', 'month' (default: auto based on date range)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved page path detail analytics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PagePathDetailResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/page-path-visitors":{"get":{"tags":["Analytics"],"summary":"Get individual visitor sessions for a specific page path","operationId":"get_page_path_visitors","parameters":[{"name":"page_path","in":"query","description":"The page path to get visitors for (URL-encoded)","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"page","in":"query","description":"Page number (1-based, default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Items per page (default: 50, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Successfully retrieved page path visitors","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PagePathVisitorsResponse"}}}},"400":{"description":"Invalid parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/page-paths":{"get":{"tags":["Analytics"],"operationId":"get_page_paths","parameters":[{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS (optional)","required":false,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS (optional)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Maximum number of page paths to return (default: 100, max: 1000)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved page paths","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PagePathsResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/page-paths-sparklines":{"get":{"tags":["Analytics"],"operationId":"get_page_paths_sparklines","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_time","in":"query","description":"Start time in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"page_paths","in":"query","description":"Comma-separated list of page paths","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sparkline data for all requested page paths","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PagePathsSparklineResponse"}}}},"400":{"description":"Invalid parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/recent-activity":{"get":{"tags":["Analytics"],"summary":"Get recent activity events for real-time activity feed","operationId":"get_recent_activity","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"since_id","in":"query","description":"Return events with ID greater than this (cursor-based polling)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"limit","in":"query","description":"Max events to return (default: 50, max: 100)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved recent activity events","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecentActivityResponse"}}}},"400":{"description":"Invalid parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/sessions/{session_id}":{"get":{"tags":["Analytics"],"summary":"Get detailed information about a specific session including events and request logs","operationId":"get_session_details","parameters":[{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved session details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionDetails"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Session not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/sessions/{session_id}/events":{"get":{"tags":["Analytics"],"operationId":"get_analytics_session_events","parameters":[{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS","required":false,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Number of results to return (default: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"offset","in":"query","description":"Number of results to skip (default: 0)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved session events","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionEventsResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Session not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/sessions/{session_id}/logs":{"get":{"tags":["Analytics"],"operationId":"get_session_logs","parameters":[{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS","required":false,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Number of results to return (default: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"offset","in":"query","description":"Number of results to skip (default: 0)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved session logs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionLogsResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Session not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitor-facets":{"get":{"tags":["Analytics"],"summary":"Get filter dropdown contents for the visitors page. Returns the top\nvalues per dimension with distinct visitor counts so the UI can render\n\"Country — 1,234 visitors\" rows. Each dimension is computed against the\nsegment minus its own filter, so a selected value never collapses its\nown dropdown.","operationId":"get_visitor_facets","parameters":[{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"include_crawlers","in":"query","description":"Include crawlers (default: false)","required":false,"schema":{"type":"boolean"}},{"name":"has_activity_only","in":"query","description":"Hide ghost visitors (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"per_facet_limit","in":"query","description":"Top N values per dimension (default: 50, max: 200)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"filter_country","in":"query","description":"Geolocation country","required":false,"schema":{"type":"string"}},{"name":"filter_region","in":"query","description":"Geolocation region","required":false,"schema":{"type":"string"}},{"name":"filter_city","in":"query","description":"Geolocation city","required":false,"schema":{"type":"string"}},{"name":"filter_channel","in":"query","description":"First-touch channel","required":false,"schema":{"type":"string"}},{"name":"filter_referrer","in":"query","description":"First-touch referrer hostname (use 'Direct' for null)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Top values per dimension","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorFacets"}}}},"400":{"description":"Invalid date format or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors":{"get":{"tags":["Analytics"],"summary":"Get list of visitors with summary information","operationId":"get_visitors","parameters":[{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"include_crawlers","in":"query","description":"Include crawlers (default: false)","required":false,"schema":{"type":"boolean"}},{"name":"limit","in":"query","description":"Maximum number of visitors to return (default: 50)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"offset","in":"query","description":"Number of visitors to skip (default: 0)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"has_activity_only","in":"query","description":"Filter to only include visitors with recorded activity (events/sessions). When true, excludes ghost visitors (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"filter_country","in":"query","description":"Geolocation country","required":false,"schema":{"type":"string"}},{"name":"filter_region","in":"query","description":"Geolocation region","required":false,"schema":{"type":"string"}},{"name":"filter_city","in":"query","description":"Geolocation city","required":false,"schema":{"type":"string"}},{"name":"filter_channel","in":"query","description":"First-touch channel","required":false,"schema":{"type":"string"}},{"name":"filter_referrer","in":"query","description":"First-touch referrer hostname (use 'Direct' for null)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved visitors","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorsResponse"}}}},"400":{"description":"Invalid date format, missing required parameters, or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/guid/{visitor_id}":{"get":{"tags":["Analytics"],"summary":"Get visitor by GUID with geolocation data","operationId":"get_visitor_by_guid","parameters":[{"name":"visitor_id","in":"path","description":"Visitor GUID (supports enc_ prefix for encrypted IDs)","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved visitor with geolocation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorWithGeolocation"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/id/{id}":{"get":{"tags":["Analytics"],"summary":"Get visitor by numeric ID with geolocation data","operationId":"get_visitor_by_id","parameters":[{"name":"id","in":"path","description":"Visitor numeric ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved visitor with geolocation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorWithGeolocation"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/{visitor_id}":{"get":{"tags":["Analytics"],"summary":"Get detailed information about a specific visitor by numeric ID","operationId":"get_visitor_details","parameters":[{"name":"visitor_id","in":"path","description":"Visitor numeric ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved visitor details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorDetails"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/{visitor_id}/enrich":{"put":{"tags":["Analytics"],"operationId":"enrich_visitor","parameters":[{"name":"visitor_id","in":"path","description":"Visitor ID - can be numeric ID, GUID, or encrypted GUID (enc_xxx)","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnrichVisitorRequest"}}},"required":true},"responses":{"200":{"description":"Successfully enriched visitor data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnrichVisitorResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/{visitor_id}/info":{"get":{"tags":["Analytics"],"summary":"Get visitor record from database","operationId":"get_visitor_info","parameters":[{"name":"visitor_id","in":"path","description":"Visitor numeric ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved visitor info","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorRecord"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/{visitor_id}/journey":{"get":{"tags":["Analytics"],"summary":"Get the complete visitor journey: all events across all sessions, grouped by session","operationId":"get_visitor_journey","parameters":[{"name":"visitor_id","in":"path","description":"Visitor numeric ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"limit_sessions","in":"query","description":"Maximum number of sessions to return (default: 50)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved visitor journey","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorJourneyResponse"}}}},"400":{"description":"Invalid parameters"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/{visitor_id}/sessions":{"get":{"tags":["Analytics"],"summary":"Get all sessions for a specific visitor by numeric ID","operationId":"get_analytics_visitor_sessions","parameters":[{"name":"visitor_id","in":"path","description":"Visitor numeric ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"limit","in":"query","description":"Maximum number of sessions to return (default: 100)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved visitor sessions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorSessionsResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/{visitor_id}/stats":{"get":{"tags":["Analytics"],"summary":"Get visitor statistics","operationId":"get_visitor_stats","parameters":[{"name":"visitor_id","in":"path","description":"Visitor numeric ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved visitor statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorStats"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/api-keys":{"get":{"tags":["API Keys"],"operationId":"list_api_keys","parameters":[{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page (default: 20)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"API keys retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["API Keys"],"operationId":"create_api_key","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateApiKeyRequest"}}},"required":true},"responses":{"201":{"description":"API key created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateApiKeyResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"409":{"description":"Conflict - API key name already exists"},"428":{"description":"Recent MFA verification required"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/api-keys/permissions":{"get":{"tags":["API Keys"],"operationId":"get_api_key_permissions","responses":{"200":{"description":"Available permissions and roles retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AvailablePermissions"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/api-keys/{id}":{"get":{"tags":["API Keys"],"operationId":"get_api_key","parameters":[{"name":"id","in":"path","description":"API key ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"API key retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["API Keys"],"operationId":"update_api_key","parameters":[{"name":"id","in":"path","description":"API key ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateApiKeyRequest"}}},"required":true},"responses":{"200":{"description":"API key updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"409":{"description":"Conflict - API key name already exists"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["API Keys"],"operationId":"delete_api_key","parameters":[{"name":"id","in":"path","description":"API key ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"API key deleted successfully"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/api-keys/{id}/activate":{"post":{"tags":["API Keys"],"operationId":"activate_api_key","parameters":[{"name":"id","in":"path","description":"API key ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"API key activated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/api-keys/{id}/deactivate":{"post":{"tags":["API Keys"],"operationId":"deactivate_api_key","parameters":[{"name":"id","in":"path","description":"API key ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"API key deactivated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/api-keys/{id}/rotate":{"post":{"tags":["API Keys"],"operationId":"rotate_api_key","parameters":[{"name":"id","in":"path","description":"API key ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"API key rotated successfully; the response contains the new plaintext secret, shown only once","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateApiKeyResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"428":{"description":"Recent MFA verification required"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/auth/cli/device/approve":{"post":{"tags":["Authentication"],"operationId":"cli_device_approve","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDeviceApproveRequest"}}},"required":true},"responses":{"200":{"description":"Session approved; CLI can now claim the API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDeviceApproveResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Browser session required"},"404":{"description":"Unknown user_code"},"409":{"description":"Already resolved"},"410":{"description":"Session expired"},"428":{"description":"Recent MFA verification required"},"500":{"description":"Internal server error"}},"security":[{"session_token":[]}]}},"/auth/cli/device/deny":{"post":{"tags":["Authentication"],"operationId":"cli_device_deny","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDeviceApproveRequest"}}},"required":true},"responses":{"200":{"description":"Session denied","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDeviceApproveResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Unknown user_code"},"409":{"description":"Already resolved"},"410":{"description":"Session expired"},"500":{"description":"Internal server error"}},"security":[{"session_token":[]}]}},"/auth/cli/device/lookup":{"get":{"tags":["Authentication"],"operationId":"cli_device_lookup","parameters":[{"name":"user_code","in":"query","description":"`user_code` as displayed in the CLI / pasted into the URL.","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Device session metadata","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDeviceLookupResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Unknown user_code"},"410":{"description":"Device session expired"},"500":{"description":"Internal server error"}},"security":[{"session_token":[]}]}},"/auth/cli/device/poll":{"post":{"tags":["Authentication"],"operationId":"cli_device_poll","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDevicePollRequest"}}},"required":true},"responses":{"200":{"description":"Poll result; check `status` field","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDevicePollResponse"}}}},"404":{"description":"Unknown device_code"},"500":{"description":"Internal server error"}}}},"/auth/cli/device/start":{"post":{"tags":["Authentication"],"operationId":"cli_device_start","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDeviceStartRequest"}}},"required":true},"responses":{"200":{"description":"Device session created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDeviceStartResponse"}}}},"500":{"description":"Internal server error"}}}},"/auth/cli/logout":{"post":{"tags":["Authentication"],"operationId":"cli_logout","responses":{"204":{"description":"API key revoked"},"401":{"description":"Not authenticated"},"403":{"description":"Endpoint requires API key authentication"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/auth/email-status":{"get":{"tags":["Authentication"],"operationId":"email_status","responses":{"200":{"description":"Email configuration status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailStatusResponse"}}}},"500":{"description":"Internal server error"}}}},"/auth/login":{"post":{"tags":["Authentication"],"operationId":"login","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginRequest"}}},"required":true},"responses":{"200":{"description":"Login successful, session cookie set","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthResponse"}}}},"401":{"description":"Invalid credentials, or the account's role requires MFA enrollment that has not been completed"},"500":{"description":"Internal server error"}}}},"/auth/oidc/callback":{"get":{"tags":["Authentication"],"operationId":"oidc_callback","parameters":[{"name":"code","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"state","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"error","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"error_description","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"302":{"description":"Redirect to app with session cookie or login error"}}}},"/auth/oidc/login/{slug}":{"get":{"tags":["Authentication"],"operationId":"start_oidc_login_by_slug","parameters":[{"name":"slug","in":"path","description":"OIDC provider slug (from /email-status or /auth/oidc/providers)","required":true,"schema":{"type":"string"}},{"name":"return_to","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"302":{"description":"Redirect to IdP authorize URL"},"404":{"description":"Provider not found"},"503":{"description":"OIDC provider unreachable"}}}},"/auth/oidc/providers":{"get":{"tags":["Authentication"],"operationId":"list_public_providers","responses":{"200":{"description":"Enabled OIDC providers for login page","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OidcProvidersListResponse"}}}}}}},"/auth/password-reset/request":{"post":{"tags":["Authentication"],"operationId":"request_password_reset","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailRequest"}}},"required":true},"responses":{"200":{"description":"Reset email sent if account exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthResponse"}}}},"503":{"description":"Email service not configured"}}}},"/auth/password-reset/verify":{"post":{"tags":["Authentication"],"operationId":"reset_password","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResetPasswordRequest"}}},"required":true},"responses":{"200":{"description":"Password reset successful","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthResponse"}}}},"400":{"description":"Invalid or expired token"},"500":{"description":"Internal server error"}}}},"/auth/step-up":{"post":{"tags":["Authentication"],"operationId":"verify_step_up","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyStepUpRequest"}}},"required":true},"responses":{"200":{"description":"Session elevated for sensitive actions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StepUpResponse"}}}},"400":{"description":"Verification code is empty"},"401":{"description":"Invalid code or expired session"},"403":{"description":"Browser session required"},"428":{"description":"MFA setup required"},"429":{"description":"Too many verification attempts"},"500":{"description":"Verification infrastructure failed"}},"security":[{"session_token":[]}]}},"/auth/verify-email":{"get":{"tags":["Authentication"],"operationId":"verify_email","parameters":[{"name":"token","in":"query","description":"Email verification token","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Email verified successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthResponse"}}}},"400":{"description":"Invalid or expired token"},"500":{"description":"Internal server error"}}}},"/auth/verify-mfa":{"post":{"tags":["Authentication"],"operationId":"verify_mfa_challenge","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MfaVerificationRequest"}}},"required":true},"responses":{"204":{"description":"MFA verification successful"},"400":{"description":"Invalid request"},"401":{"description":"Invalid MFA code"},"500":{"description":"Internal server error"}}}},"/backups/alerts":{"get":{"tags":["Backups"],"summary":"List open backup alerts.","description":"Returns all alerts that have not yet been resolved, ordered by `opened_at`\ndescending (newest first). The UI renders these as a banner above the\nBackups page content. Alerts are auto-opened by the watcher and\nauto-resolved when the triggering condition clears.\n\n**Schedule overdue** — the backup scheduler did not enqueue a job within\nthe expected window (1 hour past `next_run`). Usually means the scheduler\ntask is dead or wedged.\n\n**Job stalled** — a `backup_jobs` row has been in `state='pending'` for\nmore than 1 hour. The runner never claimed the job. Usually means the\nrunner task is dead or the runner concurrency cap is too low.","operationId":"list_backup_alerts","responses":{"200":{"description":"List of open backup alerts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupAlertListResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/cleanup":{"post":{"tags":["Backups"],"summary":"Preview or run retention using each selected schedule's configured retention days.","operationId":"cleanup_expired_backups","parameters":[{"name":"dry_run","in":"query","description":"Return the backups selected by retention without deleting anything.","required":false,"schema":{"type":"boolean"}},{"name":"schedule_id","in":"query","description":"Limit cleanup to one backup schedule.","required":false,"schema":{"type":["integer","null"],"format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CleanupExpiredBackupsRequest"}}},"required":true},"responses":{"200":{"description":"Retention cleanup completed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RetentionCleanupReport"}}}},"400":{"description":"Missing or invalid preview candidate list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Schedule or backup not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"409":{"description":"Cleanup preview is stale","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Cleanup could not be started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/external-services/{id}/run":{"post":{"tags":["Backups"],"summary":"Run a backup for an external service manually.","description":"Enqueues the backup for asynchronous execution via the `BackupRunner`\n(ADR-014). Returns `202 Accepted` immediately: pending parent and child\nrows are inserted, and a `backup_jobs` row is enqueued for the resolved\nengine. Poll `GET /backups/{id}` to observe `pending → running → completed`.","operationId":"run_external_service_backup","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RunExternalServiceBackupRequest"}}},"required":true},"responses":{"202":{"description":"Backup enqueued for async execution","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceBackupResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"External service or S3 source not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/external-services/{service_id}/backups":{"get":{"tags":["Backups"],"summary":"List all backups for a specific external service (DB-only, no S3 scan).","description":"Returns a paginated list of backups that belong to this service.\nCompletes in <100 ms regardless of S3 endpoint latency because it\nnever touches S3.","operationId":"list_external_service_backups","parameters":[{"name":"service_id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-based). Defaults to 1.","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"page_size","in":"query","description":"Items per page. Defaults to 20, max 100.","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Paginated list of backups for this service","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceBackupListResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/external-services/{service_id}/schedules":{"get":{"tags":["Backups"],"summary":"List the schedules that target a specific external service. Useful for\nthe service detail page (\"which schedules back this DB up?\").","operationId":"list_service_schedules","parameters":[{"name":"service_id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Schedules backing up this service","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BackupScheduleResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Service not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/s3-sources":{"get":{"tags":["Backups"],"summary":"List all S3 sources","operationId":"list_s3_sources","responses":{"200":{"description":"List of S3 sources","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/S3SourceResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Backups"],"summary":"Create a new S3 source","operationId":"create_s3_source","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateS3SourceRequest"}}},"required":true},"responses":{"201":{"description":"S3 source created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/S3SourceResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/s3-sources/test":{"post":{"tags":["Backups"],"summary":"Test S3 connectivity against a prospective source configuration (before creating it).\nThe credentials are NOT persisted. Useful for validating the form in the UI.","operationId":"test_s3_connection_preview","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateS3SourceRequest"}}},"required":true},"responses":{"200":{"description":"Connection test result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/S3ConnectionTestResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/s3-sources/{id}":{"get":{"tags":["Backups"],"summary":"Get an S3 source by ID","operationId":"get_s3_source","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"S3 source details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/S3SourceResponse"}}}},"404":{"description":"S3 source not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Backups"],"summary":"Delete an S3 source","operationId":"delete_s3_source","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"S3 source deleted"},"404":{"description":"S3 source not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Backups"],"summary":"Update an S3 source","operationId":"update_s3_source","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateS3SourceRequest"}}},"required":true},"responses":{"200":{"description":"S3 source updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/S3SourceResponse"}}}},"404":{"description":"S3 source not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/s3-sources/{id}/backups":{"get":{"tags":["Backups"],"summary":"List all backups in an S3 source","operationId":"list_source_backups","parameters":[{"name":"include_s3_scan","in":"query","description":"When `true`, scan the S3 bucket for backups not tracked in the\nlocal database (useful after disaster-recovery from another Temps\ninstance). Defaults to `false` — the fast DB-only path.","required":false,"schema":{"type":"boolean"}},{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of all backups in the source","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceBackupIndexResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"S3 source not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/backups/s3-sources/{id}/run":{"post":{"tags":["Backups"],"summary":"Run a backup immediately for an S3 source.","description":"Enqueues the backup for asynchronous execution via the `BackupRunner`\n(ADR-014). Returns `202 Accepted` immediately: a `backups` row is inserted\nwith `state='pending'` and a `backup_jobs` row is enqueued for the\n`ControlPlaneEngine`. Poll `GET /backups/{id}` to observe\n`pending → running → completed`.","operationId":"run_backup_for_source","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RunBackupRequest"}}},"required":true},"responses":{"202":{"description":"Backup enqueued for async execution","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"S3 source not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/s3-sources/{id}/set-default":{"post":{"tags":["Backups"],"summary":"Mark an S3 source as the default. All new backups/schedules/services that do not\nexplicitly reference a source will use the default. Returns the updated source.","operationId":"set_default_s3_source","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"S3 source marked as default","content":{"application/json":{"schema":{"$ref":"#/components/schemas/S3SourceResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"S3 source not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/s3-sources/{id}/test":{"post":{"tags":["Backups"],"summary":"Test connectivity to an existing S3 source using its stored credentials.","operationId":"test_s3_source_connection","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Connection test result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/S3ConnectionTestResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"S3 source not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedule-runs/{id}/cancel":{"post":{"tags":["Backups"],"summary":"Cancel every non-terminal child backup belonging to a schedule run.","description":"Loops over `state IN ('pending','running')` children and flips each via\nthe same path as the per-backup cancel endpoint. The parent\n`schedule_runs.finished_at` is stamped automatically once no live\nchildren remain. Idempotent: cancelling a run with no live children is\na 200 with `cancelled = 0`.","operationId":"cancel_schedule_run","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Cancel processed (idempotent)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CancelBackupResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Schedule run not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedule-runs/{id}/jobs":{"get":{"tags":["Backups"],"summary":"List the individual backup jobs for a single scheduler run.","description":"Returns each child `backups` row joined with its external service name and\nthe most-recent `backup_jobs` engine key. Used by the schedule detail\naccordion to show per-job detail on row expand.\n\n`page_size` defaults to 50 and is capped at 200.","operationId":"list_schedule_run_jobs","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Jobs for this scheduler run","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ScheduleRunJobEntry"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedules":{"get":{"tags":["Backups"],"summary":"List all backup schedules","operationId":"list_backup_schedules","responses":{"200":{"description":"List of backup schedules","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BackupScheduleResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Backups"],"summary":"Create a new backup schedule","operationId":"create_backup_schedule","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateBackupScheduleRequest"}}},"required":true},"responses":{"201":{"description":"Backup schedule created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupScheduleResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}":{"get":{"tags":["Backups"],"summary":"Get a backup schedule by ID","operationId":"get_backup_schedule","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Backup schedule details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupScheduleResponse"}}}},"404":{"description":"Backup schedule not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Backups"],"summary":"Delete a backup schedule","operationId":"delete_backup_schedule","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Backup schedule deleted"},"404":{"description":"Backup schedule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Backups"],"summary":"Update a backup schedule (partial update).","description":"All request fields are optional; only fields that are present in the\nJSON body are updated. Absent fields leave the corresponding column\nunchanged. If `schedule_expression` is changed, `next_run` is\nrecomputed automatically.","operationId":"update_backup_schedule","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateBackupScheduleRequest"}}},"required":true},"responses":{"200":{"description":"Schedule updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupScheduleResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Schedule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}/backups":{"get":{"tags":["Backups"],"summary":"List backups for a schedule","operationId":"list_backups_for_schedule","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of backups for the schedule","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BackupResponse"}}}}},"404":{"description":"Backup schedule not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}/disable":{"patch":{"tags":["Backups"],"summary":"Disable a backup schedule","operationId":"disable_backup_schedule","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Backup schedule disabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupScheduleResponse"}}}},"404":{"description":"Backup schedule not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}/enable":{"patch":{"tags":["Backups"],"summary":"Enable a backup schedule","operationId":"enable_backup_schedule","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Backup schedule enabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupScheduleResponse"}}}},"404":{"description":"Backup schedule not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}/run":{"post":{"tags":["Backups"],"summary":"Immediately fan-out a run for the given schedule (Run Now).","description":"Creates one `schedule_runs` row, one control-plane backup job, and one\nbackup job per supported external service — all in a single transaction.\nReturns `202 Accepted` with a [`ScheduleRunResponse`] containing the new\n`schedule_run_id` and the list of enqueued jobs. Returns `409 Conflict` if\na run for this schedule is already in flight or if the schedule is disabled.","operationId":"run_schedule_now","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"202":{"description":"Fan-out run enqueued for async execution","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScheduleRunResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Schedule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"409":{"description":"Run already in flight or schedule disabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}/runs":{"get":{"tags":["Backups"],"summary":"Paginated run history for a backup schedule (one row per scheduler tick).","description":"Returns one [`ScheduleRunSummary`] per scheduler tick, with child backup\ncounts aggregated in a single SQL round-trip. Legacy `backups` rows (pre-\nfan-out) are surfaced as synthetic single-job runs so history does not\ndisappear. Ordered by `started_at DESC` (newest first).\n\nUse `GET /backups/schedule-runs/{run_id}/jobs` to drill into a single run.","operationId":"list_schedule_runs","parameters":[{"name":"page","in":"query","description":"Page number (1-based, defaults to 1, clamped to 1 if < 1).","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"page_size","in":"query","description":"Items per page (defaults to 20, clamped to 100 if > 100).","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Paginated run history for the schedule","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScheduleRunSummaryList"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Schedule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}/services":{"get":{"tags":["Backups"],"summary":"List the external services attached to a backup schedule.","operationId":"list_schedule_services","parameters":[{"name":"id","in":"path","description":"Schedule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Services attached to this schedule","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ExternalServiceSummary"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Schedule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Backups"],"summary":"Attach one or more external services to a backup schedule. Idempotent —\nservices that are already attached are silently skipped (`ON CONFLICT\nDO NOTHING`). Returns the count of newly inserted rows + the total\nmembership after the operation.","operationId":"attach_schedule_services","parameters":[{"name":"id","in":"path","description":"Schedule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttachScheduleServicesRequest"}}},"required":true},"responses":{"200":{"description":"Services attached","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttachScheduleServicesResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Schedule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}/services/{service_id}":{"delete":{"tags":["Backups"],"summary":"Detach a single external service from a backup schedule. Idempotent —\nreturns `204` whether or not a row was actually removed.","operationId":"detach_schedule_service","parameters":[{"name":"id","in":"path","description":"Schedule ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"service_id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Service detached (or was not attached)"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/{id}":{"get":{"tags":["Backups"],"summary":"Get a backup by ID","operationId":"get_backup","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Backup details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Backup not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Backups"],"summary":"Permanently delete one terminal backup from object storage and the database.","operationId":"delete_backup","parameters":[{"name":"id","in":"path","description":"Backup UUID","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Backup deleted"},"400":{"description":"Backup artifact cannot be safely attributed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Backup not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"409":{"description":"Backup is running, referenced, or lacks safe artifact identity","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Object storage or database error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/{id}/cancel":{"post":{"tags":["Backups"],"summary":"Cancel a single in-flight backup.","description":"Flips the parent `backups` row + its latest `backup_jobs` row to\n`failed` with reason `\"cancelled by user \"`. The in-process\n`CancellationToken` is observed on the next heartbeat tick (≤5s), so the\nengine exits cleanly and rollback reaps the sidecar. Idempotent: cancelling\nan already-terminal backup is a 200 with `cancelled = 0`.","operationId":"cancel_backup","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Cancel processed (idempotent)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CancelBackupResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Backup not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/{id}/children":{"get":{"tags":["Backups"],"summary":"List the external-service child backups that belong to a parent backup.","description":"Each entry in `children` corresponds to one `external_service_backups` row,\njoined with `external_services` so the caller receives the service name and\ntype without a second request.\n\nReturns an empty `{ \"children\": [] }` — **not 404** — when the parent\nbackup exists but has no children (e.g. control-plane backups).\nReturns 404 when the parent backup itself does not exist.","operationId":"list_backup_children","parameters":[{"name":"id","in":"path","description":"Integer row id of the parent backup","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Child backup list (may be empty)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChildBackupListResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Parent backup not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/blob":{"get":{"tags":["Blob"],"summary":"List blobs","operationId":"blob_list","parameters":[{"name":"limit","in":"query","description":"Maximum number of items to return","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"prefix","in":"query","description":"Prefix to filter by","required":false,"schema":{"type":"string"}},{"name":"cursor","in":"query","description":"Continuation token for pagination","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of blobs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListBlobsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Blob"],"summary":"Upload a blob","operationId":"blob_put","requestBody":{"description":"Binary blob data","content":{"application/octet-stream":{"schema":{"type":"string"}}},"required":true},"responses":{"201":{"description":"Blob uploaded successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlobResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Blob"],"summary":"Delete blobs","operationId":"blob_delete","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteBlobRequest"}}},"required":true},"responses":{"200":{"description":"Blobs deleted successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteBlobResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/blob/copy":{"post":{"tags":["Blob"],"summary":"Copy a blob to a new location","operationId":"blob_copy","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CopyBlobRequest"}}},"required":true},"responses":{"200":{"description":"Blob copied successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlobResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Source blob not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/blob/disable":{"delete":{"tags":["Blob Management"],"summary":"Disable Blob service","operationId":"blob_disable","responses":{"200":{"description":"Blob service disabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DisableBlobResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Blob service not enabled"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/blob/enable":{"post":{"tags":["Blob Management"],"summary":"Enable Blob service","operationId":"blob_enable","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnableBlobRequest"}}},"required":true},"responses":{"200":{"description":"Blob service enabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnableBlobResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/blob/status":{"get":{"tags":["Blob Management"],"summary":"Get Blob service status","operationId":"blob_status","responses":{"200":{"description":"Blob service status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlobStatusResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/blob/update":{"patch":{"tags":["Blob Management"],"summary":"Update Blob service configuration","operationId":"blob_update","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateBlobRequest"}}},"required":true},"responses":{"200":{"description":"Blob service updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateBlobResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Blob service not enabled"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/blob/{project_id}/{path}":{"get":{"tags":["Blob"],"summary":"Download a blob","operationId":"blob_download","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","description":"Blob path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Blob content"},"404":{"description":"Blob not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"head":{"tags":["Blob"],"summary":"Get blob metadata","operationId":"blob_head","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","description":"Blob path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Blob metadata in headers"},"404":{"description":"Blob not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/dashboard/projects-analytics":{"get":{"tags":["Events"],"summary":"Get dashboard analytics for multiple projects in a single batch request","description":"Returns unique visitor counts and hourly sparkline data for all requested projects\nusing only 2 SQL queries instead of 2×N per-project queries.","operationId":"get_dashboard_projects_analytics","parameters":[{"name":"project_ids","in":"query","description":"Comma-separated list of project IDs","required":true,"schema":{"type":"string"}},{"name":"start_date","in":"query","description":"Start date for filtering","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date for filtering","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved batch analytics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DashboardProjectsAnalyticsResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/deployments/activity-graph":{"get":{"tags":["Deployments"],"summary":"Get deployment activity graph showing daily deployment counts\nSimilar to GitHub's contribution graph","operationId":"get_activity_graph","parameters":[{"name":"project_id","in":"query","description":"Filter by project ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"days","in":"query","description":"Number of days to include (default: 365)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved activity graph","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivityGraphResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/deployments/{deployment_id}/vulnerability-scan":{"get":{"tags":["Vulnerability Scans"],"operationId":"get_scan_by_deployment","parameters":[{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Scan for the specified deployment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScanResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"No scan found for deployment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/deployments/{id}/metrics":{"get":{"tags":["Metrics"],"summary":"Fetch a time-series range for a single metric on a deployment.","operationId":"DeploymentMetricsGetRange","parameters":[{"name":"id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"metric","in":"query","description":"Metric name, e.g. `\"pg.connections_active\"`.","required":true,"schema":{"type":"string"}},{"name":"range","in":"query","description":"Time window: `\"1h\"` | `\"6h\"` | `\"24h\"` | `\"7d\"`.","required":false,"schema":{"type":"string"}},{"name":"percentile","in":"query","description":"Optional histogram percentile (0–100). When provided, the endpoint\nfetches histogram buckets and computes the requested quantile.","required":false,"schema":{"type":["number","null"],"format":"double"}}],"responses":{"200":{"description":"Metric time series data points","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MetricDataPoint"}}}}},"400":{"description":"Invalid query parameters"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"},"503":{"description":"Metrics store not available"}},"security":[{"bearer_auth":[]}]}},"/deployments/{id}/metrics/enable":{"patch":{"tags":["Metrics"],"summary":"Enable or disable OTLP metric ingestion for a deployment.","description":"When `enabled=true`, seeds the default container alert rules for the\ndeployment via [`temps_monitoring::seed_default_container_rules`] (idempotent).","operationId":"DeploymentMetricsToggle","parameters":[{"name":"id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToggleDeploymentMetricsRequest"}}},"required":true},"responses":{"200":{"description":"Metrics toggle applied"},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/deployments/{id}/metrics/latest":{"get":{"tags":["Metrics"],"summary":"Fetch the most-recent metric values for a deployment.","operationId":"DeploymentMetricsGetLatest","parameters":[{"name":"id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Map of metric name to latest value","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"number","format":"double"},"propertyNames":{"type":"string"}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"},"503":{"description":"Metrics store not available"}},"security":[{"bearer_auth":[]}]}},"/dns-providers":{"get":{"tags":["DNS Providers"],"summary":"List all DNS providers","operationId":"list_dns_providers","responses":{"200":{"description":"List of DNS providers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/DnsProviderResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["DNS Providers"],"summary":"Create a new DNS provider","description":"The provider's credentials will be tested before creation.\nIf the connection test fails, the provider will not be created.","operationId":"create_dns_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDnsProviderRequest"}}},"required":true},"responses":{"201":{"description":"DNS provider created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsProviderResponse"}}}},"400":{"description":"Invalid request or connection test failed"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{id}":{"get":{"tags":["DNS Providers"],"summary":"Get a DNS provider by ID","operationId":"get_dns_provider","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"DNS provider details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsProviderResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["DNS Providers"],"summary":"Update a DNS provider","description":"If new credentials are supplied, they are tested before the update is\npersisted (same as creation) -- otherwise a provider's credentials (and,\nfor Pebble, its target URL) could be swapped for something invalid or\nunsafe without ever going through validation.","operationId":"update_provider","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDnsProviderRequest"}}},"required":true},"responses":{"200":{"description":"DNS provider updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsProviderResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["DNS Providers"],"summary":"Delete a DNS provider","operationId":"delete_dns_provider","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"DNS provider deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{id}/domains":{"get":{"tags":["DNS Providers"],"summary":"List managed domains for a provider","operationId":"list_managed_domains","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of managed domains","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ManagedDomainResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["DNS Providers"],"summary":"Add a managed domain to a provider","operationId":"add_managed_domain","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddManagedDomainApiRequest"}}},"required":true},"responses":{"201":{"description":"Managed domain added","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagedDomainResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{id}/test":{"post":{"tags":["DNS Providers"],"summary":"Test provider connection","operationId":"test_provider_connection","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Connection test result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectionTestResult"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{id}/zones":{"get":{"tags":["DNS Providers"],"summary":"List zones available in a provider","operationId":"list_provider_zones","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of zones","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ZoneListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{provider_id}/domains/{domain}":{"delete":{"tags":["DNS Providers"],"summary":"Remove a managed domain","operationId":"remove_managed_domain","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Managed domain removed"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["DNS Providers"],"summary":"Update a managed domain's settings (hostname mode, sync opt-in, auto-manage).","operationId":"update_managed_domain","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateManagedDomainApiRequest"}}},"required":true},"responses":{"200":{"description":"Managed domain updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagedDomainResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{provider_id}/domains/{domain}/apply-hostname-mode":{"post":{"tags":["DNS Providers"],"summary":"Apply a hostname mode to a managed domain (persist + optional DNS sync +\nroute reload).","operationId":"apply_hostname_mode","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApplyHostnameModeRequest"}}},"required":true},"responses":{"200":{"description":"Hostname mode applied","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HostnamePreviewResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions or token lacks zone access"},"404":{"description":"Domain not found"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{provider_id}/domains/{domain}/hostname-preview":{"get":{"tags":["DNS Providers"],"summary":"Preview the impact of switching a managed domain's hostname mode.","operationId":"preview_hostname_mode","parameters":[{"name":"mode","in":"query","description":"Target mode: standard|flat","required":true,"schema":{"type":"string"}},{"name":"sync","in":"query","description":"Include DNS record changes","required":false,"schema":{"type":"boolean"}},{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Hostname mode preview","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HostnamePreviewResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{provider_id}/domains/{domain}/verify":{"post":{"tags":["DNS Providers"],"summary":"Verify a managed domain","operationId":"verify_managed_domain","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Domain verification result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagedDomainResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"}},"security":[{"bearer_auth":[]}]}},"/dns/lookup":{"get":{"tags":["DNS"],"summary":"Lookup DNS A records for a domain","operationId":"lookup_dns_a_records","parameters":[{"name":"domain","in":"query","description":"Domain name to lookup","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved DNS A records","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsLookupResponse"}}}},"400":{"description":"Invalid domain name or lookup failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsLookupError"}}}}}}},"/domains":{"get":{"tags":["Domains"],"summary":"List all domains","operationId":"list_domains","parameters":[{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20},{"name":"search","in":"query","description":"Search domains by name (substring match)","required":false,"schema":{"type":["string","null"]},"example":"example.com"}],"responses":{"200":{"description":"Domains retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListDomainsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Domains"],"summary":"Create a new domain","description":"Creates a new domain and automatically requests a Let's Encrypt challenge.\nYou can specify the challenge type (HTTP-01 or DNS-01) in the request.\n\n- **HTTP-01**: Validates domain ownership by placing a file on your web server at `/.well-known/acme-challenge/`\n- **DNS-01**: Validates domain ownership by adding a TXT record to your DNS (required for wildcard domains)","operationId":"create_domain","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDomainRequest"}}},"required":true},"responses":{"201":{"description":"Domain created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainResponse"}}}},"400":{"description":"Invalid input"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/by-host/{hostname}":{"get":{"tags":["Domains"],"summary":"Get domain details by hostname","operationId":"get_domain_by_host","parameters":[{"name":"hostname","in":"path","description":"Domain hostname","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Domain details retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/by-host/{hostname}/cert-status":{"get":{"tags":["Domains"],"summary":"Get on-demand TLS certificate status for a hostname","description":"Returns the current cert lifecycle state for a single hostname (from the\n`domains` row) plus the most recent on-demand issuance attempt (from the\n`on_demand_cert_attempts` audit log). This is the operator's first-line\ndiagnostic, surfaced by `temps domain cert-status` (ADR-018 §5). Returns the\nhostname with `None` fields when no on-demand activity exists for it (never a\n404, so the CLI can render \"no attempts recorded\").","operationId":"get_on_demand_cert_status","parameters":[{"name":"hostname","in":"path","description":"Domain hostname","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"On-demand cert status retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CertStatusResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/on-demand-certs":{"get":{"tags":["Domains"],"summary":"List on-demand TLS certificate attempts","description":"Returns rows from the append-only `on_demand_cert_attempts` audit log\n(ADR-018 §5), newest first, each joined with the current authoritative cert\nstate (`status`, `expiration_time`, `backoff_until`) from the `domains` row.\nThis backs the console \"Certificates\" surface. No certificate or private-key\nmaterial is returned — only audit metadata.","operationId":"list_on_demand_certs","parameters":[{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20}],"responses":{"200":{"description":"On-demand cert attempts retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListOnDemandCertsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain_id}/order":{"get":{"tags":["Domains"],"summary":"Get ACME order for a domain","operationId":"get_domain_order","parameters":[{"name":"domain_id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Order retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AcmeOrderResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Order not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Domains"],"summary":"Create or recreate ACME order for a domain","description":"Creates a new ACME order with Let's Encrypt for the specified domain.\nIf an order already exists, you should cancel it first using the cancel-order endpoint.\nReturns the challenge details that need to be fulfilled (DNS record or HTTP token).","operationId":"create_or_recreate_order","parameters":[{"name":"domain_id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Order created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainChallengeResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Domains"],"summary":"Cancel ACME order for a domain","description":"Cancels the current ACME order for a domain and clears all challenge data.\nThis allows you to start over with a new order if the previous one failed or got stuck.","operationId":"cancel_domain_order","parameters":[{"name":"domain_id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Order cancelled successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain_id}/order/finalize":{"post":{"tags":["Domains"],"summary":"Finalize ACME order for a domain","description":"Finalizes the ACME order by completing the challenge validation and requesting the certificate.\nThis should be called after the challenge has been set up (DNS record added or HTTP token served).","operationId":"finalize_order","parameters":[{"name":"domain_id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Order finalized successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain or order not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain_id}/setup-dns":{"post":{"tags":["Domains"],"summary":"Setup DNS challenge records automatically using a DNS provider","description":"This endpoint automatically creates the required DNS TXT records for ACME DNS-01 challenge\nvalidation using a configured DNS provider. The domain must have an active DNS challenge\npending (created via POST /domains/{id}/order with dns-01 challenge type).\n\nThis is similar to how email domain DNS records are auto-provisioned.","operationId":"setup_dns_challenge","parameters":[{"name":"domain_id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetupDnsChallengeRequest"}}},"required":true},"responses":{"200":{"description":"DNS records created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetupDnsChallengeResponse"}}}},"400":{"description":"Bad request - DNS provider not configured or no challenge pending"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain or DNS provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain}":{"get":{"tags":["Domains"],"summary":"Get domain by ID","operationId":"get_domain_by_id","parameters":[{"name":"domain","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Domain retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Domains"],"summary":"Delete a domain","operationId":"delete_domain","parameters":[{"name":"domain","in":"path","description":"Domain name","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Domain deleted successfully"},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain}/challenge-token":{"get":{"tags":["Domains"],"summary":"Get challenge token for a domain (returns plain text token)","operationId":"get_challenge_token","parameters":[{"name":"domain","in":"path","description":"Domain name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Challenge token retrieved successfully","content":{"text/plain":{"schema":{"type":"string"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Challenge not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain}/http-challenge-debug":{"get":{"tags":["Domains"],"summary":"Get HTTP challenge debug information","description":"Returns detailed debug information for HTTP-01 challenge including:\n- Whether a challenge exists for the domain\n- The challenge token and URL that Let's Encrypt will access\n- DNS resolution information showing where the domain currently points\n\nThis is useful for debugging why HTTP-01 challenges fail.","operationId":"get_http_challenge_debug","parameters":[{"name":"domain","in":"path","description":"Domain name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Debug information retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpChallengeDebugResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain}/provision":{"post":{"tags":["Domains"],"summary":"Provision a domain certificate","operationId":"provision_domain","parameters":[{"name":"domain","in":"path","description":"Domain name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Certificate provisioning initiated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProvisionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain}/renew":{"post":{"tags":["Domains"],"summary":"Renew domain certificate","description":"For HTTP-01 domains: Automatically renews the certificate\nFor DNS-01 domains (wildcards): Creates a new ACME order and returns challenge data","operationId":"renew_domain","parameters":[{"name":"domain","in":"path","description":"Domain name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Certificate renewal initiated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProvisionResponse"}}}},"202":{"description":"DNS challenge created - manual action required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainChallengeResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain}/status":{"get":{"tags":["Domains"],"summary":"Check domain status","operationId":"check_domain_status","parameters":[{"name":"domain","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Domain status retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/drop/inspect":{"post":{"tags":["Projects"],"summary":"Inspect a source ZIP without creating a project or retaining the upload.","operationId":"inspect_drop_archive","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/DropArchiveUpload"}}},"required":true},"responses":{"200":{"description":"Detected deployable project roots","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DropInspectionResponse"}}}},"400":{"description":"Invalid or unsupported archive"}},"security":[{"bearer_auth":[]}]}},"/email-domains":{"get":{"tags":["Email Domains"],"summary":"List all email domains","operationId":"list_email_domains","parameters":[{"name":"provider_id","in":"query","description":"Only return domains belonging to this provider","required":false,"schema":{"type":["integer","null"],"format":"int32"}}],"responses":{"200":{"description":"List of email domains","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EmailDomainResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Email Domains"],"summary":"Create a new email domain","operationId":"create_email_domain","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEmailDomainRequest"}}},"required":true},"responses":{"201":{"description":"Domain created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailDomainWithDnsResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-domains/by-domain/{domain}":{"get":{"tags":["Email Domains"],"summary":"Get an email domain by domain name with DNS records","operationId":"get_domain_by_name","parameters":[{"name":"domain","in":"path","description":"Domain name (e.g., 'mail.example.com')","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Email domain details with DNS records","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailDomainWithDnsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-domains/{id}":{"get":{"tags":["Email Domains"],"summary":"Get an email domain by ID with DNS records","operationId":"get_domain","parameters":[{"name":"id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Email domain details with DNS records","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailDomainWithDnsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Email Domains"],"summary":"Delete an email domain","operationId":"delete_email_domain","parameters":[{"name":"id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Domain deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-domains/{id}/dns-records":{"get":{"tags":["Email Domains"],"summary":"Get DNS records for an email domain","operationId":"get_domain_dns_records","parameters":[{"name":"id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"DNS records for the domain","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/DnsRecordResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-domains/{id}/setup-dns":{"post":{"tags":["Email Domains"],"summary":"Setup DNS records for an email domain using a configured DNS provider","operationId":"setup_dns","parameters":[{"name":"id","in":"path","description":"Email Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetupDnsRequest"}}},"required":true},"responses":{"200":{"description":"DNS records setup result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetupDnsResponse"}}}},"400":{"description":"Invalid request or DNS provider not configured"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-domains/{id}/verify":{"post":{"tags":["Email Domains"],"summary":"Verify an email domain's DNS configuration","operationId":"verify_domain","parameters":[{"name":"id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Domain verification result with DNS records","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailDomainWithDnsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-providers":{"get":{"tags":["Email Providers"],"summary":"List all email providers","operationId":"list_email_providers","responses":{"200":{"description":"List of email providers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EmailProviderResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Email Providers"],"summary":"Create a new email provider","operationId":"create_email_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEmailProviderRequest"}}},"required":true},"responses":{"201":{"description":"Provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailProviderResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-providers/{id}":{"get":{"tags":["Email Providers"],"summary":"Get an email provider by ID","operationId":"get_email_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Email provider details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailProviderResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Email Providers"],"summary":"Delete an email provider","operationId":"delete_email_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Provider deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Email Providers"],"summary":"Update an email provider","description":"Partial update — any field left out keeps its current value. Most importantly,\nomitting the credential block (`ses_credentials`/`scaleway_credentials`/`smtp_credentials`)\npreserves the stored secret, so operators can rename a provider without re-typing\npasswords. `provider_type` is immutable; to switch providers, delete and recreate.","operationId":"update_email_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEmailProviderRequest"}}},"required":true},"responses":{"200":{"description":"Provider updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailProviderResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"},"409":{"description":"Provider type mismatch"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-providers/{id}/test":{"post":{"tags":["Email Providers"],"summary":"Test an email provider by sending a test email to the logged-in user","operationId":"test_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestEmailRequest"}}},"required":true},"responses":{"200":{"description":"Test email result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestEmailResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-providers/{id}/tracking/setup":{"post":{"tags":["Email Providers"],"summary":"One-click AWS-side setup of SES event tracking (SNS topic + webhook\nsubscription + SESv2 event destination), using the provider's stored\ncredentials.","operationId":"setup_email_tracking","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Setup completed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailTrackingSetupResponse"}}}},"400":{"description":"Provider does not support event tracking"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"},"502":{"description":"An AWS call failed — the response detail names the failed step"}},"security":[{"bearer_auth":[]}]}},"/email-providers/{id}/tracking/status":{"get":{"tags":["Email Providers"],"summary":"Live status of SES event tracking for a provider","operationId":"get_email_tracking_status","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Event tracking status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailTrackingStatusResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]}},"/emails":{"get":{"tags":["Emails"],"summary":"List emails with optional filtering","operationId":"list_emails","parameters":[{"name":"domain_id","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"project_id","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"status","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"from_address","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"page","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"page_size","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}}],"responses":{"200":{"description":"List of emails","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedEmailsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Emails"],"summary":"Send an email","operationId":"send_email","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendEmailRequestBody"}}},"required":true},"responses":{"201":{"description":"Email sent successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendEmailResponseBody"}}}},"400":{"description":"Invalid request or domain not verified"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/emails/events":{"get":{"tags":["Email Tracking"],"summary":"GET /emails/events","operationId":"get_global_events","parameters":[{"name":"event_type","in":"query","description":"Filter by event type (open, click)","required":false,"schema":{"type":"string"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Paginated tracking events","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedEventsResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/emails/events/stats":{"get":{"tags":["Email Tracking"],"summary":"GET /emails/events/stats","operationId":"get_global_event_stats","responses":{"200":{"description":"Global tracking statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GlobalEventStatsResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/emails/stats":{"get":{"tags":["Emails"],"summary":"Get email statistics","operationId":"get_email_stats","parameters":[{"name":"domain_id","in":"query","description":"Optional domain ID to filter stats","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Email statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailStatsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/emails/validate":{"post":{"tags":["Email Validation"],"summary":"Validate an email address","operationId":"validate_email","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateEmailRequest"}}},"required":true},"responses":{"200":{"description":"Email validation result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateEmailResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/emails/{email_id}/track/click/{link_index}":{"get":{"tags":["Email Tracking"],"summary":"Track email link click - redirects to original URL","description":"This endpoint replaces original links in tracked emails.\nNo authentication required - it's called when the recipient clicks a link.","operationId":"track_click","parameters":[{"name":"email_id","in":"path","description":"Email ID (UUID)","required":true,"schema":{"type":"string"}},{"name":"link_index","in":"path","description":"Link index","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"302":{"description":"Redirect to original URL"},"404":{"description":"Link not found"}}}},"/emails/{email_id}/track/open":{"get":{"tags":["Email Tracking"],"summary":"Track email open - returns a 1x1 transparent GIF","description":"This endpoint is embedded as an tag in emails.\nNo authentication required - it's called by the email client.","operationId":"track_open","parameters":[{"name":"email_id","in":"path","description":"Email ID (UUID)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"1x1 transparent tracking pixel"},"404":{"description":"Email not found"}}}},"/emails/{id}":{"get":{"tags":["Emails"],"summary":"Get an email by ID","operationId":"get_email","parameters":[{"name":"id","in":"path","description":"Email ID (UUID)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Email details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Email not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/emails/{id}/tracking":{"get":{"tags":["Email Tracking"],"summary":"Get email tracking summary","operationId":"get_email_tracking","parameters":[{"name":"id","in":"path","description":"Email ID (UUID)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Tracking summary","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailTrackingResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Email not found"}},"security":[{"bearer_auth":[]}]}},"/emails/{id}/tracking/events":{"get":{"tags":["Email Tracking"],"summary":"Get email tracking events","operationId":"get_email_events","parameters":[{"name":"id","in":"path","description":"Email ID (UUID)","required":true,"schema":{"type":"string"}},{"name":"event_type","in":"query","description":"Filter by event type (open, click)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Tracking events","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TrackingEventResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Email not found"}},"security":[{"bearer_auth":[]}]}},"/emails/{id}/tracking/links":{"get":{"tags":["Email Tracking"],"summary":"Get tracked links for an email","operationId":"get_email_links","parameters":[{"name":"id","in":"path","description":"Email ID (UUID)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Tracked links","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TrackedLinkResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Email not found"}},"security":[{"bearer_auth":[]}]}},"/external-services":{"get":{"tags":["External Services"],"summary":"Get all external services","operationId":"list_services","parameters":[{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20},{"name":"sort_by","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"List of external services","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}}},"500":{"description":"Internal server error"}}},"post":{"tags":["External Services"],"summary":"Create new external service","operationId":"create_service","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateExternalServiceRequest"}}},"required":true},"responses":{"201":{"description":"Service created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}},"400":{"description":"Invalid request"},"500":{"description":"Internal server error"}}}},"/external-services/available-containers":{"get":{"tags":["External Services"],"summary":"List available Docker containers that can be imported as services","operationId":"list_available_containers","responses":{"200":{"description":"List of available containers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AvailableContainerInfo"}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/by-slug/{slug}":{"get":{"tags":["External Services"],"summary":"Get external service details by slug","operationId":"get_service_by_slug","parameters":[{"name":"slug","in":"path","description":"External service slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"External service details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceDetails"}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/health-status-batch":{"get":{"tags":["External Services"],"summary":"Current health status for many services at once","description":"Powers the status dot on the Storage list page. Pass a comma-separated\nlist of service IDs via `?ids=1,2,3`. Omit to get every service.","operationId":"list_service_health_statuses","parameters":[{"name":"ids","in":"query","description":"Comma-separated service IDs. Omit for all services.","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Batch of current health statuses","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceHealthStatusBatchResponse"}}}},"500":{"description":"Internal server error"}}}},"/external-services/import":{"post":{"tags":["External Services"],"summary":"Import an existing Docker container as a managed external service","operationId":"import_external_service","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportExternalServiceRequest"}}},"required":true},"responses":{"201":{"description":"Service imported successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/projects/{project_id}":{"get":{"tags":["External Services"],"summary":"List services linked to a project","operationId":"list_project_services","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20},{"name":"sort_by","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"List of services linked to project","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProjectServiceInfo"}}}}},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}}},"/external-services/projects/{project_id}/environment":{"get":{"tags":["External Services"],"summary":"Get all environment variables for all services linked to a project","operationId":"get_project_service_environment_variables","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Map of service IDs to their environment variables","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"object","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"propertyNames":{"type":"integer","format":"int32"}}}}},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}}},"/external-services/providers/metadata":{"get":{"tags":["External Services"],"summary":"Get provider metadata (display names, icons, descriptions)","operationId":"get_providers_metadata","responses":{"200":{"description":"List of provider metadata","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProviderMetadata"}}}}},"500":{"description":"Internal server error"}}}},"/external-services/providers/metadata/{service_type}":{"get":{"tags":["External Services"],"summary":"Get metadata for a specific provider","operationId":"get_provider_metadata","parameters":[{"name":"service_type","in":"path","description":"Service type (mongodb, postgres, redis, s3)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Provider metadata","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderMetadata"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}}}},"/external-services/types":{"get":{"tags":["External Services"],"summary":"Get available service types","operationId":"get_service_types","responses":{"200":{"description":"List of available service types","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ServiceTypeRoute"}}}}},"500":{"description":"Internal server error"}}}},"/external-services/types/{service_type}/parameters":{"get":{"tags":["External Services"],"summary":"Get parameter schema for a specific service type","operationId":"get_service_type_parameters","parameters":[{"name":"service_type","in":"path","description":"Service type","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Service type parameter schema"},"404":{"description":"Service type not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}":{"get":{"tags":["External Services"],"summary":"Get external service details","operationId":"get_service","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"External service details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceDetails"}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}},"put":{"tags":["External Services"],"summary":"Update external service","operationId":"update_service","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateExternalServiceRequest"}}},"required":true},"responses":{"200":{"description":"Service updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}},"400":{"description":"Invalid request"},"404":{"description":"Service not found"},"409":{"description":"A major upgrade is in progress for this service"},"500":{"description":"Internal server error"}}},"delete":{"tags":["External Services"],"summary":"Delete external service","operationId":"delete_service","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Service deleted successfully"},"400":{"description":"Cannot delete: service is still linked to projects"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/cluster-health":{"get":{"tags":["External Services"],"summary":"Per-member health for a Postgres HA cluster.","description":"Reads pg_auto_failover's `pgautofailover.node` table from the cluster's\nmonitor (TLS, autoctl_node) and joins each member with its\n`pg_stat_replication` row from the current primary. Returns one row per\ndata member with role/state, sync state, and replay lag.\n\nReturns `200` with `monitor_error` set when the monitor is briefly\nunreachable (UI surfaces it as a banner above the table); the table\nitself is empty in that case. Returns `400` for non-cluster services.","operationId":"get_cluster_health","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Per-member cluster health report","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClusterHealthReportResponse"}}}},"400":{"description":"Service is not a cluster"},"401":{"description":"Unauthorized"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/health-check":{"post":{"tags":["External Services"],"summary":"Run a health check for one service right now","description":"Triggers the same engine-specific probe as the background monitor, writes\na history row, updates the denormalized fields on `external_services`, and\nfires alerts on the Nth consecutive failure (so consecutive-failure state\nstays honest). Returns the fresh snapshot the UI can display immediately.","operationId":"trigger_service_health_check","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Fresh health snapshot after probing","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceHealthResponse"}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"},"503":{"description":"Health monitor not running on this node"}}}},"/external-services/{id}/health-status":{"get":{"tags":["External Services"],"summary":"Persisted health status for an external service","description":"Returns the latest health probe result recorded by\n`ExternalServiceHealthMonitor`, plus recent check history for sparklines\nand a 24-hour uptime percentage. Safe to poll from the UI every 30s.","operationId":"get_service_health_status","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"limit","in":"query","description":"Max number of recent checks (default 50, max 200)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Current health + recent history","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceHealthResponse"}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/members":{"post":{"tags":["External Services"],"summary":"Begin adding a single new member to a running cluster.","description":"Currently only `replica` members can be added at runtime. The\nresponse is **202 Accepted** as soon as the validation passes and\nthe placeholder `service_members` row is inserted. The actual\ncontainer provisioning + DNS registration runs in the background;\npoll `GET /external-services/{id}/members/{member_id}` to watch\n`provisioning_step` advance through the phases.","operationId":"add_cluster_member","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddClusterMemberRequest"}}},"required":true},"responses":{"202":{"description":"Cluster member provisioning started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceMemberInfo"}}}},"400":{"description":"Validation failed (wrong topology, status, or role)"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/members/{member_id}":{"get":{"tags":["External Services"],"summary":"Get a single cluster member's current state.","description":"Used by the add-member page to poll the row every second while the\nbackground provisioning task walks through its phases. The\n`provisioning_step` field advances through `inserting_row` →\n`provisioning_container` → `registering_dns` → `done` (or `failed`\nwith `provisioning_error` set).","operationId":"get_cluster_member","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"member_id","in":"path","description":"Cluster member ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Cluster member details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceMemberInfo"}}}},"404":{"description":"Service or member not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["External Services"],"summary":"Remove a single member from a running cluster.","description":"Refuses to remove the monitor (singleton), the current primary\n(failover first), or any member if the cluster would drop below the\n2-data-member quorum required for HA. Stops + removes the container,\ndeletes the row, and drops the Tier-2 DNS record.","operationId":"remove_cluster_member","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"member_id","in":"path","description":"Cluster member ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Cluster member removed"},"400":{"description":"Validation failed (monitor, primary, or quorum violation)"},"404":{"description":"Service or member not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/members/{member_id}/promote":{"post":{"tags":["External Services"],"summary":"Promote a replica to primary by triggering a pg_auto_failover\nfailover. The monitor demotes the current primary and the chosen\nreplica transitions to primary; the role reconciler then refreshes\nthe role-aliased VIPs (≤30s).","operationId":"promote_cluster_member","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"member_id","in":"path","description":"Cluster member ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"202":{"description":"Promotion initiated"},"400":{"description":"Validation failed (monitor, already primary, not running, etc.)"},"404":{"description":"Service or member not found"},"500":{"description":"pg_autoctl perform promotion failed"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/metrics":{"get":{"tags":["Metrics"],"summary":"Fetch a time-series range for a single metric on an external service.","description":"Pass `percentile` to compute a histogram quantile instead of a plain\ngauge/counter average.","operationId":"ExternalServiceMetricsGetRange","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"metric","in":"query","description":"Metric name, e.g. `\"pg.connections_active\"`.","required":true,"schema":{"type":"string"}},{"name":"range","in":"query","description":"Time window: `\"1h\"` | `\"6h\"` | `\"24h\"` | `\"7d\"`.","required":false,"schema":{"type":"string"}},{"name":"percentile","in":"query","description":"Optional histogram percentile (0–100). When provided, the endpoint\nfetches histogram buckets and computes the requested quantile.","required":false,"schema":{"type":["number","null"],"format":"double"}}],"responses":{"200":{"description":"Metric time series data points","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MetricDataPoint"}}}}},"400":{"description":"Invalid query parameters"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"},"503":{"description":"Metrics store not available"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/metrics/alert-rules":{"get":{"tags":["Metrics"],"summary":"List all monitoring alert rules for an external service.","operationId":"ExternalServiceMetricsGetAlertRules","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of alert rules","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ServiceAlertRuleResponse"}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Metrics"],"summary":"Create a monitoring alert rule for an external service.","description":"If metric collection is enabled and the service engine has default rules,\nseeding is idempotent (ON CONFLICT DO NOTHING).","operationId":"ExternalServiceMetricsCreateAlertRule","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceCreateAlertRuleRequest"}}},"required":true},"responses":{"201":{"description":"Alert rule created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceAlertRuleResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/metrics/alert-rules/{rule_id}":{"put":{"tags":["Metrics"],"summary":"Update an existing monitoring alert rule for an external service.","operationId":"ExternalServiceMetricsUpdateAlertRule","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"rule_id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceUpdateAlertRuleRequest"}}},"required":true},"responses":{"200":{"description":"Updated alert rule","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceAlertRuleResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Alert rule not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Metrics"],"summary":"Delete a monitoring alert rule for an external service.","operationId":"ExternalServiceMetricsDeleteAlertRule","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"rule_id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Alert rule deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Alert rule not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/metrics/by-database":{"get":{"tags":["Metrics"],"summary":"Return the latest per-database metric values for a Postgres service.","description":"Groups `pg_stat_database` / size metrics by `datname` so the UI can show a\nbreakdown table (each database with its own size, cache-hit ratio, etc.)\nrather than collapsing every database into one value.","operationId":"ExternalServiceMetricsByDatabase","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Per-database metric breakdown","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DatabaseMetricsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"},"503":{"description":"Metrics not available"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/metrics/enable":{"patch":{"tags":["Metrics"],"summary":"Enable or disable metric collection for an external service.","description":"When `enabled=true`, seeds the default alert rules for the service's engine\nvia [`temps_monitoring::seed_default_rules`] (idempotent).","operationId":"ExternalServiceMetricsToggle","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToggleServiceMetricsRequest"}}},"required":true},"responses":{"200":{"description":"Metrics toggle applied"},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/metrics/latest":{"get":{"tags":["Metrics"],"summary":"Fetch the most-recent value for every tracked metric on an external service.","operationId":"ExternalServiceMetricsGetLatest","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Map of metric name to latest value","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"number","format":"double"},"propertyNames":{"type":"string"}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"},"503":{"description":"Metrics store not available"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/metrics/status":{"get":{"tags":["Metrics"],"summary":"Return the freshness status (last-received timestamp) for a service.","description":"Cheap O(1) lookup against `service_metrics_status` — used by the UI to show\n\"last received at …\" without scanning the metrics hypertable.","operationId":"ExternalServiceMetricsStatus","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Metrics freshness status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MetricsStatusResponse"}}}},"503":{"description":"Metrics not available"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/parameters/{param_name}":{"get":{"tags":["External Services"],"summary":"Reveal one sensitive service parameter. Service detail responses never\ncontain plaintext values; every successful reveal is recorded separately.","operationId":"reveal_service_parameter","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"param_name","in":"path","description":"Sensitive parameter name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sensitive parameter value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SensitiveValueResponse"}}}},"400":{"description":"Parameter is not sensitive"},"403":{"description":"Caller cannot access a project linked to this service"},"404":{"description":"Service or parameter not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/preview-environment-masked":{"get":{"tags":["External Services"],"summary":"Get environment variables preview with masked sensitive values","operationId":"get_service_preview_environment_variables_masked","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Preview of environment variables with sensitive values masked as ***","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/preview-environment-names":{"get":{"tags":["External Services"],"summary":"Get environment variable names preview (safe - no sensitive values)","operationId":"get_service_preview_environment_variable_names","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of environment variable names that would be provided","content":{"application/json":{"schema":{"type":"array","items":{"type":"string"}}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/projects":{"get":{"tags":["External Services"],"summary":"List projects linked to service","operationId":"list_service_projects","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20},{"name":"sort_by","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"List of linked projects","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProjectServiceInfo"}}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}},"post":{"tags":["External Services"],"summary":"Link service to project","operationId":"link_service_to_project","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LinkServiceRequest"}}},"required":true},"responses":{"201":{"description":"Service linked to project successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectServiceInfo"}}}},"404":{"description":"Service or project not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/projects/{project_id}":{"delete":{"tags":["External Services"],"summary":"Unlink service from project","operationId":"unlink_service_from_project","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Service unlinked from project successfully"},"404":{"description":"Service link not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/projects/{project_id}/environment":{"get":{"tags":["External Services"],"summary":"Get all environment variables for a service-project pair","operationId":"get_service_environment_variables","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of environment variables","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EnvironmentVariableInfo"}}}}},"404":{"description":"Service or project not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/projects/{project_id}/environment/{var_name}":{"get":{"tags":["External Services"],"summary":"Get specific environment variable for a service-project pair","operationId":"get_service_environment_variable","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"var_name","in":"path","description":"Environment variable name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Environment variable value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentVariableInfo"}}}},"403":{"description":"Plaintext secret access is not permitted"},"404":{"description":"Service, project, or variable not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/resources":{"patch":{"tags":["External Services"],"summary":"Update a service's resource limits (memory, CPU caps).","description":"Persists the new caps to the encrypted config AND live-applies them\nvia Docker's update API. Memory and CPU can be hot-changed without a\nrestart on running containers; stopped containers also accept the\nupdate and pick up the new caps on next start.\n\nPass `null` (or omit) any field to leave it unlimited. A request where\nevery field is `null` removes any existing limits.\n\nThe response includes a per-container `applied[]` list so the caller\ncan tell which members got the update and which were skipped (e.g.,\ncontainer not yet created, or `docker update` rejected because the\nnew memory cap is below current usage).","operationId":"update_service_resources","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceResourceLimits"}}},"required":true},"responses":{"200":{"description":"Updated resource limits","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResourceLimitsUpdateResponse"}}}},"400":{"description":"Invalid resource limits"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/restore":{"post":{"tags":["Restore"],"operationId":"start_restore","parameters":[{"name":"id","in":"path","description":"External service id (source for the restore)","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartRestoreRequest"}}},"required":true},"responses":{"202":{"description":"Restore run started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RestoreRunView"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Backup or service not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/restore-capabilities":{"get":{"tags":["Restore"],"operationId":"get_restore_capabilities","parameters":[{"name":"id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Capabilities declared by the service","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RestoreCapabilitiesResponse"}}}},"404":{"description":"Service not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/restore-plan":{"post":{"tags":["Restore"],"operationId":"plan_restore","parameters":[{"name":"id","in":"path","description":"Target service id","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartRestoreRequest"}}},"required":true},"responses":{"200":{"description":"Preview of what the restore will do","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RestorePlan"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Backup or service not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/restore-runs":{"get":{"tags":["Restore"],"operationId":"list_restore_runs_for_service","parameters":[{"name":"id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Recent restore runs for the service","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RestoreRunView"}}}}}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/retry":{"post":{"tags":["External Services"],"summary":"Retry a failed cluster service initialization.","description":"Cleans up any leftover containers from the previous attempt and\nre-runs cluster initialization with the provided member specifications.","operationId":"retry_cluster","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RetryClusterRequest"}}},"required":true},"responses":{"200":{"description":"Cluster retry initiated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}},"400":{"description":"Service is not a failed cluster"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/runtime":{"get":{"tags":["External Services"],"summary":"Inspect a service's container(s): status, restart count, OOM-killed flag,\nexit code, and the cgroup limits actually applied.","operationId":"get_service_runtime","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Container runtime snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceRuntimeReport"}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/start":{"post":{"tags":["External Services"],"summary":"Start an external service","operationId":"start_service","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Service started successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}},"404":{"description":"Service not found"},"409":{"description":"A Postgres major upgrade is in progress for this service"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/stats":{"get":{"tags":["External Services"],"summary":"Sample current CPU/memory usage from each of a service's containers.\nOne-shot sample, no streaming. Cheap to call (single Docker round-trip\nper member) so the UI can poll on a 5–10s interval.","operationId":"get_service_stats","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Container stats snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceStatsReport"}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/stop":{"post":{"tags":["External Services"],"summary":"Stop an external service","operationId":"stop_service","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Service stopped successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/upgrade":{"post":{"tags":["External Services"],"summary":"Upgrade external service to new Docker image with data migration\nThis endpoint uses service-specific upgrade procedures (e.g., pg_upgrade for PostgreSQL)","operationId":"upgrade_service","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpgradeExternalServiceRequest"}}},"required":true},"responses":{"200":{"description":"Service upgraded successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}},"400":{"description":"Invalid request or upgrade not supported"},"404":{"description":"Service not found"},"409":{"description":"A major upgrade is already in progress for this service"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/wal-health":{"get":{"tags":["External Services"],"summary":"Postgres WAL & archive health snapshot","description":"Returns the latest WAL/archive health snapshot recorded by the background\nhealth monitor for a Postgres external service. Powers the warning banner\non the service detail page when the disk is filling up due to stale\nreplication slots, archive backlog, or misconfigured `archive_command`.\n\nReturns 404 when no snapshot exists yet (probe hasn't run, or the service\nisn't Postgres).","operationId":"getPostgresWalHealth","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Latest WAL health snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PostgresWalHealth"}}}},"404":{"description":"Service not found, or no WAL snapshot available"},"500":{"description":"Internal server error"}}}},"/external-services/{service_id}/pg-stat-statements/enable":{"post":{"tags":["External Services"],"summary":"Enable `pg_stat_statements` on a standalone Postgres service.","description":"Stops the container and restarts it so that the\n`shared_preload_libraries=pg_stat_statements` CMD flag (baked into every\nnew standalone Postgres container) takes effect. The named data volume is\nreused unchanged — no data is lost.\n\n**Clustered (HA) services are rejected** with 422 — a blind single-container\nrestart bypasses controlled failover. For clustered services the response\nbody describes the manual rolling-restart steps.\n\nConfirmation is the caller's responsibility (UI dialog / CLI `--yes` flag)\nbefore invoking this endpoint.","operationId":"ExternalServiceEnablePgStatStatements","parameters":[{"name":"service_id","in":"path","description":"ID of the provisioned standalone Postgres service","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Container restarted; pg_stat_statements now active","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnablePgStatStatementsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions (requires external_services:write)"},"404":{"description":"Service not found"},"422":{"description":"Service is not standalone Postgres (cluster or wrong type)"},"500":{"description":"Restart failed"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/pg-stat-statements/reset":{"post":{"tags":["External Services"],"summary":"Reset all statistics accumulated by `pg_stat_statements` for a Postgres\nservice. This affects every user, database, and normalized query tracked by\nthe target Postgres instance and cannot be undone.","operationId":"ExternalServiceResetPgStatStatements","parameters":[{"name":"service_id","in":"path","description":"ID of the provisioned Postgres service","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"Explicit confirmation of the global, irreversible reset","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResetPgStatStatementsRequest"}}},"required":true},"responses":{"200":{"description":"All accumulated pg_stat_statements statistics cleared","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResetPgStatStatementsResponse"}}}},"400":{"description":"Missing or invalid reset confirmation"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions (requires external_services:write)"},"404":{"description":"Service not found"},"422":{"description":"Service is not Postgres"},"502":{"description":"Target Postgres rejected or failed the reset operation"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/pg-stat-statements/slow-queries":{"get":{"tags":["External Services"],"operationId":"get_slow_queries","parameters":[{"name":"service_id","in":"path","description":"ID of the provisioned Postgres service","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-based). Defaults to 1.","required":false,"schema":{"type":["integer","null"],"format":"int32","minimum":0}},{"name":"page_size","in":"query","description":"Number of rows per page (1–100). Defaults to 20.","required":false,"schema":{"type":["integer","null"],"format":"int32","minimum":0}},{"name":"sort_by","in":"query","description":"Column to sort by: one of `calls`, `total_exec_time_ms`,\n`mean_exec_time_ms`, `rows`, `cache_hit_ratio`. Defaults to\n`mean_exec_time_ms`. Applied server-side so ordering stays\nconsistent across pages.","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","description":"Sort direction: `asc` or `desc`. Defaults to `desc`.","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"Paginated slow queries from pg_stat_statements","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SlowQueriesResponse"}}}},"400":{"description":"Invalid pagination or sort parameters"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions (requires external_services:read)"},"404":{"description":"Service not found"},"422":{"description":"Service is not a Postgres service"},"503":{"description":"pg_stat_statements extension not available (container restart required)"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/containers":{"get":{"tags":["External Services - Query"],"summary":"List containers at the root level (databases, keyspaces, etc.)","operationId":"list_root_containers","parameters":[{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of root containers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ContainerResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/containers/{path}":{"get":{"tags":["External Services - Query"],"summary":"List containers at a specific path\nPath segments are separated by forward slashes\nExample: /external-services/1/query/containers/mydb lists schemas in database \"mydb\"","operationId":"list_containers_at_path","parameters":[{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of containers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ContainerResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service or container not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/containers/{path}/entities":{"get":{"tags":["External Services - Query"],"summary":"List entities (tables, collections, etc.) in a container\nExample: /external-services/1/query/containers/mydb/public/entities lists tables in the public schema","operationId":"list_entities","parameters":[{"name":"limit","in":"query","description":"Maximum number of entities to return (default: 100, max: 1000)","required":false,"schema":{"type":"integer","minimum":0}},{"name":"token","in":"query","description":"Continuation token for pagination","required":false,"schema":{"type":"string"}},{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Paginated list of entities","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedEntitiesResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service or container not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/containers/{path}/entities/{entity}":{"get":{"tags":["External Services - Query"],"summary":"Get detailed information about an entity (table schema)","operationId":"get_entity_info","parameters":[{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","required":true,"schema":{"type":"string"}},{"name":"entity","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Entity details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EntityInfoResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service, container, or entity not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/containers/{path}/entities/{entity}/data":{"post":{"tags":["External Services - Query"],"summary":"Query data from an entity with optional filters, pagination, and sorting","operationId":"query_data","parameters":[{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","required":true,"schema":{"type":"string"}},{"name":"entity","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QueryDataRequest"}}},"required":true},"responses":{"200":{"description":"Query results","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QueryDataResponse"}}}},"400":{"description":"Invalid query"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service, container, or entity not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/containers/{path}/entities/{entity}/download":{"get":{"tags":["External Services - Query"],"summary":"Download an object (S3 only) as a streaming response","operationId":"download_object","parameters":[{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","required":true,"schema":{"type":"string"}},{"name":"entity","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Object data stream","content":{"application/octet-stream":{}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Object not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/containers/{path}/info":{"get":{"tags":["External Services - Query"],"summary":"Get information about a specific container","operationId":"get_container_info","parameters":[{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Container information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service or container not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/explorer-support":{"get":{"tags":["External Services - Query"],"summary":"Check if a service supports query explorer functionality","operationId":"check_explorer_support","parameters":[{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Explorer support information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExplorerSupportResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/upgrades":{"get":{"tags":["Postgres Upgrades"],"summary":"List recent upgrades for a single service (newest first, page size 50).","operationId":"list_pg_upgrades","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Recent upgrades","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PgUpgradeResponse"}}}}},"500":{"description":"Internal error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Postgres Upgrades"],"summary":"Start a new PostgreSQL major-version upgrade for a service.","operationId":"start_pg_upgrade","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartPgUpgradeRequest"}}},"required":true},"responses":{"201":{"description":"Upgrade started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PgUpgradeResponse"}}}},"400":{"description":"Invalid request"},"409":{"description":"An upgrade is already running for this service"},"412":{"description":"No default S3 source configured"},"500":{"description":"Internal error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/upgrades/{id}":{"get":{"tags":["Postgres Upgrades"],"summary":"Get a single upgrade by id, scoped to a service.","operationId":"get_pg_upgrade","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"id","in":"path","description":"Upgrade id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Upgrade","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PgUpgradeResponse"}}}},"404":{"description":"Not found"},"500":{"description":"Internal error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/upgrades/{id}/cancel":{"post":{"tags":["Postgres Upgrades"],"summary":"Cancel an in-flight upgrade. The orchestrator stops at its next phase\nboundary; already-terminal upgrades return 409.","operationId":"cancel_pg_upgrade","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"id","in":"path","description":"Upgrade id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Cancellation requested","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PgUpgradeResponse"}}}},"404":{"description":"Not found"},"409":{"description":"Upgrade already terminal"},"500":{"description":"Internal error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/upgrades/{id}/logs":{"get":{"tags":["Postgres Upgrades"],"summary":"Get the accumulated JSONL log content for an upgrade (for dashboard display).","operationId":"get_pg_upgrade_logs","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"id","in":"path","description":"Upgrade id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Log content","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PgUpgradeLogResponse"}}}},"404":{"description":"Not found"},"500":{"description":"Internal error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/upgrades/{id}/retry":{"post":{"tags":["Postgres Upgrades"],"summary":"Retry a failed upgrade. The phase is preserved, so the state machine\nresumes from where it failed.","operationId":"retry_pg_upgrade","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"id","in":"path","description":"Upgrade id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Retry scheduled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PgUpgradeResponse"}}}},"400":{"description":"Upgrade is not in a retriable state"},"404":{"description":"Not found"},"500":{"description":"Internal error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/upgrades/{id}/rollback":{"post":{"tags":["Postgres Upgrades"],"summary":"Roll a completed upgrade back to its pre-upgrade PGDATA volume and old image.\nOnly valid while the rollback retention window is still open (see\n`ROLLBACK_RETENTION_DAYS`) and the rollback volume has not been swept.","operationId":"rollback_pg_upgrade","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"id","in":"path","description":"Upgrade id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Rollback complete","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PgUpgradeResponse"}}}},"404":{"description":"Not found"},"409":{"description":"Upgrade is not in a rollbackable state (not completed, volume swept, or retention expired)"},"500":{"description":"Internal error"}},"security":[{"bearer_auth":[]}]}},"/files/{file_path}":{"get":{"tags":["Files"],"operationId":"get_file","parameters":[{"name":"file_path","in":"path","description":"Relative path to the file from static directory","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"File content retrieved successfully","content":{"application/octet-stream":{}}},"401":{"description":"Authentication required"},"403":{"description":"Access denied - path outside static directory or insufficient permissions"},"404":{"description":"File not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/flags/exposure":{"post":{"tags":["Feature Flags"],"summary":"Record which flags a running app actually evaluated.","description":"This is what makes `last_evaluated_at` mean something. The snapshot\nendpoint hands the SDK every flag in the environment and evaluation then\nhappens locally, so the control plane cannot otherwise tell a flag that is\nreferenced by live code from one nothing has called in a year. Stamping on\nsnapshot fetch would mark every flag as freshly used and defeat the point.\n\nScope comes from the deployment token, never the body. The endpoint writes\nonly `last_evaluated_at` — never a flag's value — so \"a deployment token\ncannot change what a flag serves\" still holds despite this being a write.","operationId":"record_flag_exposure","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecordExposureRequest"}}},"required":true},"responses":{"200":{"description":"Exposure recorded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecordExposureResponse"}}}},"400":{"description":"Deployment token required"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/flags/snapshot":{"get":{"tags":["Feature Flags"],"summary":"Every flag for the caller's environment, collapsed to what the evaluator\nneeds.","description":"Scope comes from the deployment token, never from the URL: a container's\nbaked-in `TEMPS_API_TOKEN` identifies exactly one project (and usually one\nenvironment), so a compromised app cannot read another tenant's flags by\nchanging a path parameter.\n\nSupports `If-None-Match`, so the SDK's background poll is a 304 in the\ncommon case.","operationId":"get_flag_snapshot","parameters":[{"name":"environment_id","in":"query","description":"Required only when the calling token is project-wide rather than scoped\nto a single environment.","required":false,"schema":{"type":["integer","null"],"format":"int32"}}],"responses":{"200":{"description":"Snapshot for the environment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagSnapshotResponse"}}}},"304":{"description":"Snapshot unchanged"},"400":{"description":"Environment could not be determined"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/geo/{ip}":{"get":{"tags":["geo"],"summary":"Get geolocation information for an IP address","operationId":"get_ip_geolocation","parameters":[{"name":"ip","in":"path","description":"IP address to geolocate (IPv4 or IPv6)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Geolocation information retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GeoLocationResponse"}}}},"400":{"description":"Invalid IP address","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"IP address not found in database","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/git-connections":{"get":{"tags":["Git Providers"],"summary":"List user's git provider connections","operationId":"list_connections","parameters":[{"name":"page","in":"query","description":"Page number for pagination (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Number of items per page (default: 30, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"sort","in":"query","description":"Sort field (created_at, updated_at, account_name)","required":false,"schema":{"type":"string"}},{"name":"direction","in":"query","description":"Sort direction (asc, desc), default: desc","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of connections","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectionListResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}":{"delete":{"tags":["Git Providers"],"summary":"Permanently delete a git provider connection","operationId":"delete_connection","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Connection deleted successfully"},"400":{"description":"Connection is in use by projects and cannot be deleted"},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}/activate":{"post":{"tags":["Git Providers"],"summary":"Activate a git provider connection","operationId":"activate_connection","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Connection activated successfully"},"400":{"description":"Provider is deactivated and connection cannot be activated"},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}/deactivate":{"post":{"tags":["Git Providers"],"summary":"Deactivate a git provider connection","operationId":"deactivate_connection","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Connection deactivated successfully"},"400":{"description":"Connection is in use by projects and cannot be deactivated"},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}/health-check":{"post":{"tags":["Git Provider Connections"],"summary":"Run an on-demand health check for a git connection.","description":"Probes the upstream (GitHub App, PAT, or OAuth token), persists the result,\nand fires admin notifications on status transitions. Returns the updated\nconnection.","operationId":"run_connection_health_check","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Health check completed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}/repositories":{"get":{"tags":["Git Providers"],"summary":"List repositories for a specific connection","description":"Fetches repositories from the connected git provider with support for pagination, search, and filtering.\nThis endpoint calls the provider's API directly to get the most up-to-date repository list.","operationId":"list_repositories_by_connection","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"sort","in":"query","description":"Sort field (name, created_at, updated_at, stars, etc.)","required":false,"schema":{"type":"string"}},{"name":"direction","in":"query","description":"Sort direction (asc, desc)","required":false,"schema":{"type":"string"}},{"name":"search","in":"query","description":"Search term to filter repositories","required":false,"schema":{"type":"string"}},{"name":"owner","in":"query","description":"Filter by repository owner","required":false,"schema":{"type":"string"}},{"name":"language","in":"query","description":"Filter by programming language","required":false,"schema":{"type":"string"}},{"name":"private","in":"query","description":"Filter by private status (true/false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of repositories","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositoryListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}/sync":{"post":{"tags":["Git Providers"],"summary":"Start a repository sync for a connection","description":"Kicks off a background sync of the connection's repositories from the\nprovider. Returns `202 Accepted` immediately — the caller should poll\nthe connection endpoint for `syncing` / `synced_repository_count`\nupdates rather than waiting on this response. The sync is guarded by\na hard deadline and always releases the `syncing` flag on exit, so a\nclient that disconnects mid-sync will not leave the connection stuck.","operationId":"sync_repositories","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"202":{"description":"Repository sync started in background","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositorySyncStartedResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"409":{"description":"Sync already in progress"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}/update-token":{"post":{"tags":["Git Provider Connections"],"summary":"Update access token for a connection (when tokens expire or are rotated)","operationId":"update_connection_token","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTokenRequest"}}},"required":true},"responses":{"200":{"description":"Token updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTokenResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}/validate":{"get":{"tags":["Git Provider Connections"],"summary":"Validate a connection by testing the access token","operationId":"validate_connection","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Connection validation result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers":{"get":{"tags":["Git Providers"],"summary":"List all git providers","operationId":"list_git_providers","responses":{"200":{"description":"List of providers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProviderResponse"}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Git Providers"],"summary":"Create a new git provider configuration","operationId":"create_git_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProviderRequest"}}},"required":true},"responses":{"201":{"description":"Provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/bitbucket":{"post":{"tags":["Git Providers"],"summary":"Create a Bitbucket Cloud provider with access token or app password authentication","operationId":"create_bitbucket_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateBitbucketRequest"}}},"required":true},"responses":{"201":{"description":"Bitbucket provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request — missing or invalid auth fields"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/generic":{"post":{"tags":["Git Providers"],"summary":"Create a Generic git provider for self-hosted or arbitrary HTTPS git hosts.\nSupports public repositories (no token) and private repositories (token-based).","operationId":"create_generic_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGenericRequest"}}},"required":true},"responses":{"201":{"description":"Generic git provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request — invalid clone URL or missing fields"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/gitea/pat":{"post":{"tags":["Git Providers"],"summary":"Create a Gitea Personal Access Token provider","operationId":"create_gitea_pat_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGiteaPATRequest"}}},"required":true},"responses":{"201":{"description":"Gitea PAT provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request — invalid URL or missing fields"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/github/pat":{"post":{"tags":["Git Providers"],"summary":"Create a GitHub Personal Access Token provider","operationId":"create_github_pat_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGitHubPATRequest"}}},"required":true},"responses":{"201":{"description":"GitHub PAT provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/gitlab/oauth":{"post":{"tags":["Git Providers"],"summary":"Create a GitLab OAuth provider","operationId":"create_gitlab_oauth_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGitLabOAuthRequest"}}},"required":true},"responses":{"201":{"description":"GitLab OAuth provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/gitlab/pat":{"post":{"tags":["Git Providers"],"summary":"Create a GitLab PAT provider","operationId":"create_gitlab_pat_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGitLabPATRequest"}}},"required":true},"responses":{"201":{"description":"GitLab PAT provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}":{"get":{"tags":["Git Providers"],"summary":"Get a specific git provider","operationId":"get_git_provider","parameters":[{"name":"provider_id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Provider details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Git Providers"],"summary":"Permanently delete a git provider","operationId":"delete_git_provider","parameters":[{"name":"provider_id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Provider deleted successfully"},"400":{"description":"Provider has connections and cannot be deleted"},"401":{"description":"Unauthorized"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/activate":{"post":{"tags":["Git Providers"],"summary":"Activate a git provider","operationId":"activate_provider","parameters":[{"name":"provider_id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Provider activated successfully"},"401":{"description":"Unauthorized"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/callback":{"get":{"tags":["Git Providers"],"summary":"Handle OAuth callback for a git provider","operationId":"handle_git_provider_oauth_callback","parameters":[{"name":"provider_id","in":"path","description":"Git provider ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"code","in":"query","description":"OAuth authorization code","required":true,"schema":{"type":"string"}},{"name":"state","in":"query","description":"CSRF state token","required":true,"schema":{"type":"string"}}],"responses":{"302":{"description":"Redirect to success page"},"400":{"description":"Bad request"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}}}},"/git-providers/{provider_id}/connections":{"get":{"tags":["Git Providers"],"summary":"Get connections for a specific git provider","operationId":"get_provider_connections","parameters":[{"name":"provider_id","in":"path","description":"Provider ID to get connections for","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of connections for the provider","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ConnectionResponse"}}}}},"401":{"description":"Unauthorized"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/credentials":{"patch":{"tags":["Git Providers"],"summary":"Partially update credentials for an existing git provider. Only the fields\nyou send are replaced; omitted fields keep their stored values. Fields that\ndon't apply to the provider's auth method are ignored on the service side.","operationId":"update_git_provider_credentials","parameters":[{"name":"provider_id","in":"path","description":"Git provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProviderCredentialsRequest"}}},"required":true},"responses":{"200":{"description":"Credentials updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/deactivate":{"post":{"tags":["Git Providers"],"summary":"Deactivate a git provider","operationId":"deactivate_provider","parameters":[{"name":"provider_id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Provider deactivated successfully"},"401":{"description":"Unauthorized"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/deletion-check":{"get":{"tags":["Git Providers"],"summary":"Check if a git provider can be safely deleted","operationId":"check_provider_deletion_safety","parameters":[{"name":"provider_id","in":"path","description":"Git provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deletion check result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderDeletionCheckResponse"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/oauth/authorize":{"get":{"tags":["Git Providers"],"summary":"Start OAuth flow for a git provider","operationId":"start_git_provider_oauth","parameters":[{"name":"provider_id","in":"path","description":"Git provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"302":{"description":"Redirect to OAuth provider"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/repositories":{"get":{"tags":["Git Providers"],"summary":"List all repositories for a specific provider","description":"Lists repositories synced to the database across every connection under\nthis provider, with the same pagination/filtering as `/repositories`.","operationId":"list_repositories_by_provider","parameters":[{"name":"provider_id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"sort","in":"query","description":"Sort field (name, created_at, updated_at, stars, watchers, size, issues)","required":false,"schema":{"type":"string"}},{"name":"direction","in":"query","description":"Sort direction (asc, desc)","required":false,"schema":{"type":"string"}},{"name":"search","in":"query","description":"Search term to filter repositories","required":false,"schema":{"type":"string"}},{"name":"owner","in":"query","description":"Filter by repository owner","required":false,"schema":{"type":"string"}},{"name":"language","in":"query","description":"Filter by programming language","required":false,"schema":{"type":"string"}},{"name":"private","in":"query","description":"Filter by private status (true/false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of repositories","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositoryListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/safe-delete":{"delete":{"tags":["Git Providers"],"summary":"Safely delete a git provider (only if no projects are using it)","operationId":"delete_provider_safely","parameters":[{"name":"provider_id","in":"path","description":"Git provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Provider successfully deleted"},"400":{"description":"Cannot delete provider because it's in use"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git/public/{provider}/{owner}/{repo}":{"get":{"tags":["Public Repositories"],"summary":"Get information about a public repository (supports GitHub and GitLab)","operationId":"get_public_repository","parameters":[{"name":"provider","in":"path","description":"Git provider (github or gitlab)","required":true,"schema":{"type":"string"}},{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"repo","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Repository information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicRepositoryInfo"}}}},"400":{"description":"Provider not supported"},"404":{"description":"Repository not found"},"429":{"description":"API rate limit exceeded"},"500":{"description":"Internal server error"}}}},"/git/public/{provider}/{owner}/{repo}/branches":{"get":{"tags":["Public Repositories"],"summary":"Get branches for a public repository (supports GitHub and GitLab)","operationId":"get_public_branches","parameters":[{"name":"provider","in":"path","description":"Git provider (github or gitlab)","required":true,"schema":{"type":"string"}},{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"repo","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}},{"name":"fresh","in":"query","description":"Force fetch fresh data, bypassing cache (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of branches","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BranchListResponse"}}}},"400":{"description":"Provider not supported"},"404":{"description":"Repository not found"},"429":{"description":"API rate limit exceeded"},"500":{"description":"Internal server error"}}}},"/git/public/{provider}/{owner}/{repo}/presets":{"get":{"tags":["Public Repositories"],"summary":"Detect presets for a public repository (supports GitHub and GitLab)","operationId":"detect_public_presets","parameters":[{"name":"provider","in":"path","description":"Git provider (github or gitlab)","required":true,"schema":{"type":"string"}},{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"repo","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}},{"name":"branch","in":"query","description":"Branch name to detect presets for (default: repository's default branch)","required":false,"schema":{"type":["string","null"]}},{"name":"fresh","in":"query","description":"Force fetch fresh data, bypassing cache (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Detected presets","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicPresetResponse"}}}},"400":{"description":"Provider not supported"},"404":{"description":"Repository or branch not found"},"429":{"description":"API rate limit exceeded"},"500":{"description":"Internal server error"}}}},"/imports/discover":{"post":{"tags":["Imports"],"summary":"Discover workloads from a source","operationId":"discover_workloads","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiscoverRequest"}}},"required":true},"responses":{"200":{"description":"List of discovered workloads","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiscoverResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/imports/execute":{"post":{"tags":["Imports"],"summary":"Execute an import","operationId":"execute_import","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecuteImportRequest"}}},"required":true},"responses":{"202":{"description":"Import execution started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecuteImportResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/imports/plan":{"post":{"tags":["Imports"],"summary":"Create an import plan","operationId":"create_plan","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePlanRequest"}}},"required":true},"responses":{"200":{"description":"Import plan created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePlanResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/imports/sources":{"get":{"tags":["Imports"],"summary":"List available import sources","operationId":"list_sources","responses":{"200":{"description":"List of available import sources","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ImportSourceInfo"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/imports/{session_id}":{"get":{"tags":["Imports"],"summary":"Get import status","operationId":"get_import_status","parameters":[{"name":"session_id","in":"path","description":"Import session ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Import status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportStatusResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Import session not found"}},"security":[{"bearer_auth":[]}]}},"/incidents/{incident_id}":{"get":{"tags":["Status Page"],"summary":"Get an incident by ID","operationId":"get_incident","parameters":[{"name":"incident_id","in":"path","description":"Incident ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved incident","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncidentResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Incident not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/incidents/{incident_id}/status":{"patch":{"tags":["Status Page"],"summary":"Update incident status","operationId":"update_incident_status","parameters":[{"name":"incident_id","in":"path","description":"Incident ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateIncidentStatusRequest"}}},"required":true},"responses":{"200":{"description":"Incident status updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncidentResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Incident not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/incidents/{incident_id}/updates":{"get":{"tags":["Status Page"],"summary":"Get incident updates","operationId":"get_incident_updates","parameters":[{"name":"incident_id","in":"path","description":"Incident ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved incident updates","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/IncidentUpdateResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Incident not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/internal/nodes":{"get":{"tags":["Nodes"],"summary":"List all registered nodes (admin — session auth via RequireAuth)","operationId":"admin_list_nodes","responses":{"200":{"description":"List of nodes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NodeListResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/internal/nodes/register":{"post":{"tags":["Nodes"],"summary":"Register a new worker node or reconnect an existing one","operationId":"register_node","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterNodeApiRequest"}}},"required":true},"responses":{"200":{"description":"Node reconnected successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterNodeResponse"}}}},"201":{"description":"Node registered successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterNodeResponse"}}}},"400":{"description":"Validation error"},"500":{"description":"Internal server error"}}}},"/internal/nodes/{node_id}":{"get":{"tags":["Nodes"],"summary":"Get a specific node by ID (admin — session auth via RequireAuth)","operationId":"admin_get_node","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Node details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NodeInfoResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Nodes"],"summary":"Remove a node from the cluster entirely. The node should be drained first\nto ensure containers have been rescheduled. If the node still has active\ncontainers, it will be drained automatically before removal.","operationId":"admin_remove_node","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Node removed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RemoveNodeResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Node not found"},"409":{"description":"Node still has active containers"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/internal/nodes/{node_id}/containers":{"get":{"tags":["Nodes"],"summary":"List all containers running on a specific node","operationId":"admin_list_node_containers","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Containers on this node","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NodeContainerListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/internal/nodes/{node_id}/dns/ack":{"post":{"tags":["Internal DNS"],"summary":"`POST /internal/nodes/{node_id}/dns/ack`","operationId":"post_dns_ack","parameters":[{"name":"node_id","in":"path","description":"Node id, must match the bearer token's node","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsAckRequest"}}},"required":true},"responses":{"200":{"description":"ACK accepted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsAckResponse"}}}},"400":{"description":"ACK higher than server generation"},"401":{"description":"Missing or invalid bearer token"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}}}},"/internal/nodes/{node_id}/dns/changes":{"get":{"tags":["Internal DNS"],"summary":"`GET /internal/nodes/{node_id}/dns/changes?since=N`","operationId":"get_dns_changes","parameters":[{"name":"node_id","in":"path","description":"Node id, must match the bearer token's node","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"since","in":"query","description":"Highest generation the agent has already applied. Pass `0` to\nrequest a full zone snapshot. Defaults to `0` if omitted.","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Diff or full snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsChangesResponse"}}}},"401":{"description":"Missing or invalid bearer token"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}}}},"/internal/nodes/{node_id}/drain":{"get":{"tags":["Nodes"],"summary":"Get the drain status for a node, including migration progress.","description":"Returns container counts and whether the drain is complete.\nCan be polled to track drain progress.","operationId":"admin_drain_status","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Drain status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DrainStatusResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Nodes"],"summary":"Drain a node: mark it as \"draining\" so no new replicas are scheduled on it,\nand trigger redeployment of all affected environments so their containers\nare rescheduled to healthy nodes.","operationId":"admin_drain_node","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Node drain initiated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DrainNodeResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Nodes"],"summary":"Undrain (reactivate) a node so it can accept new deployments again.\nOnly works for nodes in \"draining\" or \"drained\" status.","operationId":"admin_undrain_node","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Node reactivated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UndrainNodeResponse"}}}},"400":{"description":"Node not in drainable state"},"401":{"description":"Unauthorized"},"404":{"description":"Node not found"}},"security":[{"bearer_auth":[]}]}},"/internal/nodes/{node_id}/heartbeat":{"post":{"tags":["Nodes"],"summary":"Receive a heartbeat from a worker node","operationId":"node_heartbeat","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HeartbeatApiRequest"}}},"required":true},"responses":{"200":{"description":"Heartbeat received","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HeartbeatResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}}}},"/internal/nodes/{node_id}/network/peers":{"get":{"tags":["Nodes"],"summary":"`GET /internal/nodes/{node_id}/network/peers`","operationId":"list_peers","parameters":[{"name":"node_id","in":"path","description":"Node id, must match the bearer token's node","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Peer list and self-allocation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PeerListResponse"}}}},"401":{"description":"Missing or invalid bearer token"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}}}},"/internal/nodes/{node_id}/s3-credentials/{s3_source_id}":{"get":{"tags":["Nodes"],"summary":"Get decrypted S3 credentials for a backup/restore operation.","description":"Agents call this endpoint to receive the S3 credentials they need to upload\nor download backups. The credentials are decrypted from the stored S3 source\nand returned over the authenticated TLS/WireGuard channel.","operationId":"get_s3_credentials","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"s3_source_id","in":"path","description":"S3 source ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"S3 credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/S3CredentialsResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"S3 source not found"},"500":{"description":"Internal server error"}}}},"/ip-access-control":{"get":{"tags":["IP Access Control"],"summary":"List all IP access control rules","operationId":"list_ip_access_control","parameters":[{"name":"action","in":"query","description":"Filter by action (\"block\" or \"allow\")","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"List of IP access control rules","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/IpAccessControlResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["IP Access Control"],"summary":"Create a new IP access control rule","operationId":"create_ip_access_control","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateIpAccessControlRequest"}}},"required":true},"responses":{"201":{"description":"IP access control rule created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IpAccessControlResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"409":{"description":"Duplicate IP address","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ip-access-control/check/{ip}":{"get":{"tags":["IP Access Control"],"summary":"Check if an IP address is blocked","operationId":"check_ip_blocked","parameters":[{"name":"ip","in":"path","description":"IP address to check","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"IP block status"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ip-access-control/{id}":{"get":{"tags":["IP Access Control"],"summary":"Get a single IP access control rule by ID","operationId":"get_ip_access_control","parameters":[{"name":"id","in":"path","description":"IP access control rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"IP access control rule details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IpAccessControlResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"IP access control rule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["IP Access Control"],"summary":"Delete an IP access control rule","operationId":"delete_ip_access_control","parameters":[{"name":"id","in":"path","description":"IP access control rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"IP access control rule deleted"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"IP access control rule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["IP Access Control"],"summary":"Update an IP access control rule","operationId":"update_ip_access_control","parameters":[{"name":"id","in":"path","description":"IP access control rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateIpAccessControlRequest"}}},"required":true},"responses":{"200":{"description":"IP access control rule updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IpAccessControlResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"IP access control rule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/kv/del":{"post":{"tags":["KV Store"],"summary":"Delete one or more keys","operationId":"kv_del","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DelRequest"}}},"required":true},"responses":{"200":{"description":"Keys deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DelResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/disable":{"delete":{"tags":["KV Management"],"summary":"Disable KV service","operationId":"kv_disable","responses":{"200":{"description":"KV service disabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DisableKvResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"KV service not enabled"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/enable":{"post":{"tags":["KV Management"],"summary":"Enable KV service","operationId":"kv_enable","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnableKvRequest"}}},"required":true},"responses":{"200":{"description":"KV service enabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnableKvResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/expire":{"post":{"tags":["KV Store"],"summary":"Set expiration on a key","operationId":"kv_expire","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExpireRequest"}}},"required":true},"responses":{"200":{"description":"Expiration set","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExpireResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/get":{"post":{"tags":["KV Store"],"summary":"Get a value by key","operationId":"kv_get","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetRequest"}}},"required":true},"responses":{"200":{"description":"Value retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/incr":{"post":{"tags":["KV Store"],"summary":"Increment a numeric value","operationId":"kv_incr","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncrRequest"}}},"required":true},"responses":{"200":{"description":"Value incremented","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncrResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/keys":{"post":{"tags":["KV Store"],"summary":"Get keys matching a pattern","operationId":"kv_keys","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KeysRequest"}}},"required":true},"responses":{"200":{"description":"Keys retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KeysResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/set":{"post":{"tags":["KV Store"],"summary":"Set a value with optional expiration","operationId":"kv_set","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetRequest"}}},"required":true},"responses":{"200":{"description":"Value set","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/status":{"get":{"tags":["KV Management"],"summary":"Get KV service status","operationId":"kv_status","responses":{"200":{"description":"KV service status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KvStatusResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/ttl":{"post":{"tags":["KV Store"],"summary":"Get time-to-live for a key","operationId":"kv_ttl","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TtlRequest"}}},"required":true},"responses":{"200":{"description":"TTL retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TtlResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/update":{"patch":{"tags":["KV Management"],"summary":"Update KV service configuration","operationId":"kv_update","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateKvRequest"}}},"required":true},"responses":{"200":{"description":"KV service updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateKvResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"KV service not enabled"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/lb/routes":{"get":{"tags":["Load Balancer"],"operationId":"list_routes","responses":{"200":{"description":"List of routes","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RouteResponse"}}}}},"500":{"description":"Internal server error"}}},"post":{"tags":["Load Balancer"],"operationId":"create_route","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRouteRequest"}}},"required":true},"responses":{"201":{"description":"Route created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteResponse"}}}},"400":{"description":"Invalid request"}}}},"/lb/routes/{domain}":{"get":{"tags":["Load Balancer"],"operationId":"get_route","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Route found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteResponse"}}}},"404":{"description":"Route not found"}}},"put":{"tags":["Load Balancer"],"operationId":"update_route","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateRouteRequest"}}},"required":true},"responses":{"200":{"description":"Route updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteResponse"}}}},"404":{"description":"Route not found"}}},"delete":{"tags":["Load Balancer"],"operationId":"delete_route","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Route deleted successfully"},"404":{"description":"Route not found"}}}},"/logout":{"post":{"tags":["Authentication"],"operationId":"logout","responses":{"200":{"description":"Successfully logged out"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"session_token":[]}]}},"/logs/context":{"get":{"tags":["Logs"],"summary":"Get context lines surrounding a specific log line","operationId":"get_log_context","parameters":[{"name":"chunk_id","in":"query","description":"Chunk ID","required":true,"schema":{"type":"string"}},{"name":"line_offset","in":"query","description":"Line offset within the chunk","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"lines","in":"query","description":"Context lines before and after (default: 25)","required":false,"schema":{"type":"integer","format":"int32","minimum":0}}],"responses":{"200":{"description":"Context lines","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContextLogsResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Chunk not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/logs/search":{"post":{"tags":["Logs"],"summary":"Search logs with structured filters and full text search","operationId":"search_logs","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchLogsRequest"}}},"required":true},"responses":{"200":{"description":"Search results","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchLogsResponse"}}}},"400":{"description":"Invalid search parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/logs/tail":{"get":{"tags":["Logs"],"summary":"Live tail logs via Server-Sent Events","operationId":"tail_logs","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"string"}},{"name":"service","in":"query","description":"Service name","required":true,"schema":{"type":"string"}},{"name":"env","in":"query","description":"Environment","required":true,"schema":{"type":"string"}},{"name":"levels","in":"query","description":"Optional level filters","required":true,"schema":{"type":"array","items":{"type":"string"}}},{"name":"text","in":"query","description":"Optional text filter","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"SSE stream of log lines"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/monitors-health/projects":{"get":{"tags":["Status Page"],"summary":"Get monitor-based health summaries for multiple projects in a single query","operationId":"get_projects_monitor_health","parameters":[{"name":"project_ids","in":"query","description":"Comma-separated list of project IDs","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Health summaries per project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectsMonitorHealthResponse"}}}},"400":{"description":"Invalid parameters"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/monitors/{monitor_id}":{"get":{"tags":["Status Page"],"summary":"Get a monitor by ID","operationId":"get_monitor","parameters":[{"name":"monitor_id","in":"path","description":"Monitor ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved monitor","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MonitorResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Monitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Status Page"],"summary":"Delete a monitor","operationId":"delete_monitor","parameters":[{"name":"monitor_id","in":"path","description":"Monitor ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Monitor deleted successfully"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Monitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/monitors/{monitor_id}/bucketed":{"get":{"tags":["Status Page"],"summary":"Get bucketed status data for a monitor using TimescaleDB","operationId":"get_bucketed_status","parameters":[{"name":"monitor_id","in":"path","description":"Monitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"interval","in":"query","description":"Bucket interval: '5min', 'hourly', or 'daily' (default: hourly)","required":false,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601) (default: 24 hours ago)","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (ISO 8601) (default: now)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved bucketed status data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatusBucketedResponse"}}}},"400":{"description":"Invalid parameters"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Monitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/monitors/{monitor_id}/current-status":{"get":{"tags":["Status Page"],"summary":"Get current status and uptime metrics for a monitor","operationId":"get_current_monitor_status","parameters":[{"name":"monitor_id","in":"path","description":"Monitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_time","in":"query","description":"Custom start time (ISO 8601) - overrides timeframe","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"Custom end time (ISO 8601)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved current status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CurrentStatusResponse"}}}},"400":{"description":"Invalid time parameters"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Monitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/monitors/{monitor_id}/uptime":{"get":{"tags":["Status Page"],"summary":"Get uptime history for a monitor","operationId":"get_uptime_history","parameters":[{"name":"monitor_id","in":"path","description":"Monitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"days","in":"query","description":"Number of days of history (default: 60) - ignored if start_time/end_time provided","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601) - overrides days parameter","required":true,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (ISO 8601) - defaults to now","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved uptime history","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UptimeHistoryResponse"}}}},"400":{"description":"Invalid time parameters"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Monitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/nodes/{id}/metrics":{"get":{"tags":["Metrics"],"summary":"Fetch a time-series range for a single metric on a node.","operationId":"NodeMetricsGetRange","parameters":[{"name":"id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"metric","in":"query","description":"Metric name, e.g. `\"pg.connections_active\"`.","required":true,"schema":{"type":"string"}},{"name":"range","in":"query","description":"Time window: `\"1h\"` | `\"6h\"` | `\"24h\"` | `\"7d\"`.","required":false,"schema":{"type":"string"}},{"name":"percentile","in":"query","description":"Optional histogram percentile (0–100). When provided, the endpoint\nfetches histogram buckets and computes the requested quantile.","required":false,"schema":{"type":["number","null"],"format":"double"}}],"responses":{"200":{"description":"Metric time series data points","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MetricDataPoint"}}}}},"400":{"description":"Invalid query parameters"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"},"503":{"description":"Metrics store not available"}},"security":[{"bearer_auth":[]}]}},"/notification-preferences":{"get":{"tags":["Notification Preferences"],"summary":"Get notification preferences","operationId":"get_preferences","responses":{"200":{"description":"Successfully retrieved preferences","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationPreferencesResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Notification Preferences"],"summary":"Update notification preferences","operationId":"update_preferences","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePreferencesRequest"}}},"required":true},"responses":{"200":{"description":"Successfully updated preferences","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationPreferencesResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Notification Preferences"],"summary":"Delete notification preferences","operationId":"delete_preferences","responses":{"204":{"description":"Successfully deleted preferences"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers":{"get":{"tags":["Notification Providers"],"summary":"List all notification providers","operationId":"list_notification_providers","parameters":[{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20},{"name":"sort_by","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"Successfully retrieved providers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}}},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Notification Providers"],"summary":"Create a new notification provider","operationId":"create_notification_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProviderRequest"}}},"required":true},"responses":{"201":{"description":"Successfully created provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"400":{"description":"Invalid request"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/cloudflare":{"post":{"tags":["Notification Providers"],"summary":"Create a new Cloudflare Email Sending notification provider","operationId":"create_cloudflare_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCloudflareProviderRequest"}}},"required":true},"responses":{"201":{"description":"Successfully created Cloudflare provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"400":{"description":"Invalid request"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/cloudflare/{id}":{"put":{"tags":["Notification Providers"],"summary":"Update a Cloudflare Email Sending notification provider","operationId":"update_cloudflare_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCloudflareProviderRequest"}}},"required":true},"responses":{"200":{"description":"Successfully updated Cloudflare provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/email":{"post":{"tags":["Notification Providers"],"summary":"Create a new Email notification provider","operationId":"create_notification_email_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateNotificationEmailProviderRequest"}}},"required":true},"responses":{"201":{"description":"Successfully created Email provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"400":{"description":"Invalid request"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/email/{id}":{"put":{"tags":["Notification Providers"],"summary":"Update an Email notification provider","operationId":"update_notification_email_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateNotificationEmailProviderRequest"}}},"required":true},"responses":{"200":{"description":"Successfully updated Email provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/slack":{"post":{"tags":["Notification Providers"],"summary":"Create a new Slack notification provider","operationId":"create_slack_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSlackProviderRequest"}}},"required":true},"responses":{"201":{"description":"Successfully created Slack provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"400":{"description":"Invalid request"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/slack/{id}":{"put":{"tags":["Notification Providers"],"summary":"Update a Slack notification provider","operationId":"update_slack_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSlackProviderRequest"}}},"required":true},"responses":{"200":{"description":"Successfully updated Slack provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/webhook":{"post":{"tags":["Notification Providers"],"summary":"Create a new Webhook notification provider","description":"Webhook providers send notifications as JSON payloads to any HTTP endpoint.\nYou can configure custom headers for authentication (Bearer tokens, API keys, etc.).\nThe webhook will receive a JSON payload with notification details including:\nid, title, message, type, priority, severity, timestamp, and metadata.","operationId":"create_webhook_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWebhookProviderRequest"}}},"required":true},"responses":{"201":{"description":"Successfully created Webhook provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"400":{"description":"Invalid request"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/webhook/{id}":{"put":{"tags":["Notification Providers"],"summary":"Update a Webhook notification provider","operationId":"update_webhook_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWebhookProviderRequest"}}},"required":true},"responses":{"200":{"description":"Successfully updated Webhook provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/{id}":{"get":{"tags":["Notification Providers"],"summary":"Get a single notification provider","operationId":"get_notification_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Notification Providers"],"summary":"Update a notification provider","operationId":"update_notification_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProviderRequest"}}},"required":true},"responses":{"200":{"description":"Successfully updated provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"400":{"description":"Invalid masked provider configuration"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Notification Providers"],"summary":"Delete a notification provider","operationId":"delete_notification_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Successfully deleted provider"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/{id}/config/{field}":{"get":{"tags":["Notification Providers"],"operationId":"reveal_notification_provider_config","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"field","in":"path","description":"Sensitive field, such as password or headers.Authorization","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sensitive provider configuration value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SensitiveConfigValueResponse"}}}},"400":{"description":"Field is not revealable"},"403":{"description":"Missing secrets:read permission"},"404":{"description":"Provider or field not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/{id}/test":{"post":{"tags":["Notification Providers"],"summary":"Test a notification provider","operationId":"test_notification_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Test result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestProviderResponse"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/orders":{"get":{"tags":["Domains"],"summary":"List all ACME orders","operationId":"list_orders","parameters":[{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20},{"name":"sort_by","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"Orders retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListOrdersResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/otel/alerts":{"get":{"tags":["Alerts"],"summary":"List alert rules for a project (newest first, paginated).","operationId":"list_alerts","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Alert rules for the project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricAlertsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Alerts"],"summary":"Create a new alert rule for a project.","operationId":"create_alert","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMetricAlertRequest"}}},"required":true},"responses":{"201":{"description":"Alert rule created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricAlertRuleResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/alerts/preview":{"post":{"tags":["Alerts"],"summary":"Backtest an anomaly detector over a time range without saving a rule.","description":"Replays the metric against the same band the evaluator would use, returning\nthe per-bucket band + which points would have fired. Powers the form's\n\"would this have fired?\" preview and the explorer band overlay. Read-only.","operationId":"preview_alert","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnomalyPreviewRequest"}}},"required":true},"responses":{"200":{"description":"Per-bucket band + breach points","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnomalyPreviewResponse"}}}},"400":{"description":"Not an anomaly detector / bad input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/alerts/{id}":{"get":{"tags":["Alerts"],"summary":"Fetch a single alert rule by id.","operationId":"get_alert","parameters":[{"name":"id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Owning project ID (scopes the lookup)","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Alert rule","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricAlertRuleResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Alert rule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Alerts"],"summary":"Delete an alert rule.","operationId":"delete_alert","parameters":[{"name":"id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Owning project ID (scopes the delete)","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Alert rule deleted"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Alert rule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Alerts"],"summary":"Update an alert rule's fields.","operationId":"update_alert","parameters":[{"name":"id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Owning project ID (scopes the update)","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMetricAlertRequest"}}},"required":true},"responses":{"200":{"description":"Alert rule updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricAlertRuleResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Alert rule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/dashboards":{"get":{"tags":["Dashboards"],"summary":"List dashboards for a project (newest first, paginated).","operationId":"list_dashboards","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Dashboards for the project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelDashboardsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Dashboards"],"summary":"Create a new dashboard for a project.","operationId":"create_dashboard","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDashboardRequest"}}},"required":true},"responses":{"201":{"description":"Dashboard created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelDashboardResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/dashboards/{id}":{"get":{"tags":["Dashboards"],"summary":"Fetch a single dashboard by id.","operationId":"get_dashboard","parameters":[{"name":"id","in":"path","description":"Dashboard ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Owning project ID (scopes the lookup)","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Dashboard","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelDashboardResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Dashboard not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Dashboards"],"summary":"Delete a dashboard.","operationId":"delete_dashboard","parameters":[{"name":"id","in":"path","description":"Dashboard ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Owning project ID (scopes the delete)","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Dashboard deleted"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Dashboard not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Dashboards"],"summary":"Update a dashboard's name and/or layout.","operationId":"update_dashboard","parameters":[{"name":"id","in":"path","description":"Dashboard ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Owning project ID (scopes the update)","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDashboardRequest"}}},"required":true},"responses":{"200":{"description":"Dashboard updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelDashboardResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Dashboard not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/genai/traces":{"get":{"tags":["GenAI"],"summary":"Query GenAI trace summaries — traces containing spans with `gen_ai.*` attributes.","description":"`duration_ms` is the only field guaranteed to be milliseconds. `gen_ai.*`\nspan attributes (e.g. time-to-first-token, token latency) often follow the\nOTel GenAI semantic conventions, which use **seconds** (a fractional\ndouble), not milliseconds — do not read them as ms without converting.","operationId":"query_genai_traces","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"service_name","in":"query","description":"Filter by service name","required":false,"schema":{"type":"string"}},{"name":"gen_ai_system","in":"query","description":"Filter by AI system (openai, anthropic, etc.)","required":false,"schema":{"type":"string"}},{"name":"gen_ai_model","in":"query","description":"Filter by model (gpt-4, claude-sonnet-4-20250514, etc.)","required":false,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Start time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max traces to return (default: 50, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"offset","in":"query","description":"Offset for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"GenAI trace summaries","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenAiTraceSummariesResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/genai/traces/{project_id}/{trace_id}":{"get":{"tags":["GenAI"],"summary":"Get GenAI span details for a specific trace.","description":"`duration_ms` is the only field guaranteed to be milliseconds. `gen_ai.*`\nspan attributes (e.g. time-to-first-token, token latency) often follow the\nOTel GenAI semantic conventions, which use **seconds** (a fractional\ndouble), not milliseconds — do not read them as ms without converting.","operationId":"get_genai_trace","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"trace_id","in":"path","description":"Trace ID (hex)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"GenAI trace span details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenAiTraceDetailResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/global/traces/{trace_id}":{"get":{"tags":["Traces"],"summary":"Assemble a unified cross-project span waterfall (Phase 2).","description":"Fans out to every project that holds spans for `trace_id` (up to 20\nprojects, 10,000 total spans). Spans are annotated with\n`project_id`/`project_name` and sorted by `start_time ASC`.\n`truncated: true` signals a hit on either cap; `truncated_projects`\nlists the dropped project IDs. See ADR-027 §4 for the full design.","operationId":"getUnifiedTrace","parameters":[{"name":"trace_id","in":"path","description":"Trace ID (32 lowercase hex characters)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Unified cross-project trace waterfall","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnifiedTrace"}}}},"400":{"description":"trace_id is not 32 lowercase hex characters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions or deployment token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/health/{project_id}":{"get":{"tags":["OTel"],"summary":"Get health summaries for a project.","operationId":"get_health","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Health summaries","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/insights/{project_id}":{"get":{"tags":["Insights"],"summary":"List anomaly insights for a project.","operationId":"list_insights","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"status","in":"query","description":"Filter by status (active, resolved)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max insights to return (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"offset","in":"query","description":"Offset for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Insights list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InsightsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/logs":{"get":{"tags":["Telemetry Logs"],"summary":"Query log records with optional filters.","operationId":"query_logs","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"severity","in":"query","description":"Filter by severity (TRACE, DEBUG, INFO, WARN, ERROR, FATAL)","required":false,"schema":{"type":"string"}},{"name":"service_name","in":"query","description":"Filter by service name","required":false,"schema":{"type":"string"}},{"name":"search","in":"query","description":"Full-text search in log body (ILIKE)","required":false,"schema":{"type":"string"}},{"name":"trace_id","in":"query","description":"Filter by correlated trace ID","required":false,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Start time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max logs to return (default: 100, max: 1000)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"offset","in":"query","description":"Offset for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Log records","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LogsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/metric-label-keys":{"get":{"tags":["Telemetry Metrics"],"summary":"List the attribute (label) keys observed on a metric — powers the\nlabel-filter key autocomplete.","operationId":"list_metric_label_keys","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"metric_name","in":"query","description":"Metric to inspect","required":true,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Window start (RFC 3339); defaults to 24h before end","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"Window end (RFC 3339); defaults to now","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Distinct label keys","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricLabelKeysResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/metric-label-values":{"get":{"tags":["Telemetry Metrics"],"summary":"List the distinct values seen for a label key on a metric — powers value\nautocomplete once a key is chosen.","operationId":"list_metric_label_values","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"metric_name","in":"query","description":"Metric to inspect","required":true,"schema":{"type":"string"}},{"name":"label_key","in":"query","description":"Label key whose values to list (must match [a-zA-Z0-9_.:-])","required":true,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Window start (RFC 3339); defaults to 24h before end","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"Window end (RFC 3339); defaults to now","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Distinct label values","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricLabelValuesResponse"}}}},"400":{"description":"Invalid label key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/metric-names/{project_id}":{"get":{"tags":["Telemetry Metrics"],"summary":"List distinct metric names for a project.","operationId":"list_metric_names","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of metric names","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricNamesResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/metrics":{"get":{"tags":["Telemetry Metrics"],"summary":"Query metrics with time bucketing.","operationId":"query_metrics","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"metric_name","in":"query","description":"Filter by metric name","required":false,"schema":{"type":"string"}},{"name":"service_name","in":"query","description":"Filter by service name","required":false,"schema":{"type":"string"}},{"name":"environment","in":"query","description":"Filter by deployment environment","required":false,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Start time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"bucket_interval","in":"query","description":"Bucket interval (e.g. '1 hour', '5 minutes')","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max buckets to return (default: 1000)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"metric_type","in":"query","description":"Filter by metric type (gauge, sum, histogram, exponential_histogram, summary)","required":false,"schema":{"type":"string"}},{"name":"aggregation","in":"query","description":"Per-bucket aggregation: avg (default), sum, min, max, count, rate, p50/p95/p99, quantile:0.95","required":false,"schema":{"type":"string"}},{"name":"label_filters","in":"query","description":"Comma-separated key=value data-point label filters (keys must match [a-zA-Z0-9_.:-])","required":false,"schema":{"type":"string"}},{"name":"group_by","in":"query","description":"Comma-separated label keys to group series by","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Metrics data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricsResponse"}}}},"400":{"description":"Invalid label key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/pipeline-stats":{"get":{"tags":["OTel"],"summary":"Get OTel pipeline statistics (admin/system view).","operationId":"get_pipeline_stats","responses":{"200":{"description":"Pipeline statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PipelineStatsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/quota/{project_id}":{"get":{"tags":["OTel"],"summary":"Get storage quota for a project.","operationId":"get_quota","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Storage quota","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuotaResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/trace-summaries":{"get":{"tags":["Traces"],"summary":"Query trace summaries — one row per trace with span count, error count,\nroot span info, and proper trace-level pagination.","operationId":"query_trace_summaries","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"trace_id","in":"query","description":"Filter by trace ID","required":false,"schema":{"type":"string"}},{"name":"service_name","in":"query","description":"Filter by service name","required":false,"schema":{"type":"string"}},{"name":"status","in":"query","description":"Filter by status (OK, ERROR)","required":false,"schema":{"type":"string"}},{"name":"min_duration_ms","in":"query","description":"Minimum trace duration in ms","required":false,"schema":{"type":"number","format":"double"}},{"name":"start_time","in":"query","description":"Start time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"name_pattern","in":"query","description":"Filter by span name pattern (ILIKE)","required":false,"schema":{"type":"string"}},{"name":"sort_by","in":"query","description":"Sort field: 'start_time' (default) or 'duration'","required":false,"schema":{"type":"string"}},{"name":"sort_order","in":"query","description":"Sort direction: 'asc' or 'desc' (default)","required":false,"schema":{"type":"string"}},{"name":"include_total","in":"query","description":"Compute the `total` count (default: true). Set false to skip the second aggregation when only the page is needed","required":false,"schema":{"type":"boolean"}},{"name":"limit","in":"query","description":"Max traces to return (default: 50, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"offset","in":"query","description":"Offset for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Trace summaries","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TraceSummariesResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/traces":{"get":{"tags":["Traces"],"summary":"Query trace spans with optional filters.","description":"Each returned span has a `duration_ms` field (float, milliseconds) — this is\nthe ONLY field guaranteed to be in milliseconds. Spans also carry an\n`attributes` map of raw key/value pairs exactly as reported by the\ninstrumenting library: numeric attribute values may be seconds, milliseconds,\nmicroseconds, or nanoseconds depending on that library's convention, and\nnothing in this response labels the unit. Never assume an attribute's\nnumeric value shares `duration_ms`'s unit, and never state a duration in\nmilliseconds unless it came from a `duration_ms` field.","operationId":"query_traces","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"trace_id","in":"query","description":"Filter by trace ID","required":false,"schema":{"type":"string"}},{"name":"service_name","in":"query","description":"Filter by service name","required":false,"schema":{"type":"string"}},{"name":"status","in":"query","description":"Filter by status (OK, ERROR, UNSET)","required":false,"schema":{"type":"string"}},{"name":"min_duration_ms","in":"query","description":"Minimum span duration in ms","required":false,"schema":{"type":"number","format":"double"}},{"name":"start_time","in":"query","description":"Start time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"limit","in":"query","description":"Max spans to return (default: 100, max: 1000)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"offset","in":"query","description":"Offset for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Trace spans","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TracesResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/traces/cross-project/{trace_id}":{"get":{"tags":["Traces"],"summary":"Discover sibling projects that share the same `trace_id` (Phase 1 banner).","description":"Returns an empty `siblings` list when the trace is single-project — never\n404. Project names are included so the UI can render navigation links\nwithout a second round-trip. See ADR-027 §3 for the full auth model and\ntopology-disclosure trade-offs.","operationId":"getCrossProjectTraceSiblings","parameters":[{"name":"trace_id","in":"path","description":"Trace ID (32 lowercase hex characters)","required":true,"schema":{"type":"string"}},{"name":"exclude_project_id","in":"query","description":"Project ID to exclude (the caller's own project) so the UI does not render a self-link","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Sibling projects sharing this trace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CrossProjectTraceResponse"}}}},"400":{"description":"trace_id is not 32 lowercase hex characters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions or deployment token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/traces/{project_id}/{trace_id}":{"get":{"tags":["Traces"],"summary":"Get all spans for a specific trace.","description":"Each span has a `duration_ms` field (float, milliseconds) — the ONLY field\nguaranteed to be in milliseconds — plus an `attributes` map of raw\nkey/value pairs exactly as the instrumenting library reported them.\nNumeric attribute values (e.g. connection-pool wait times, queue delays)\nmay be in seconds, milliseconds, microseconds, or nanoseconds depending on\nthat library's own convention; this response never labels the unit. When\nexplaining what a span spent time on, only quote milliseconds from\n`duration_ms` (or from `start_time`/`end_time` deltas) — never assume a raw\nattribute number is already in milliseconds.","operationId":"get_trace","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"trace_id","in":"path","description":"Trace ID (hex)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Trace spans tree","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TracesResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/v1/logs":{"post":{"tags":["OTel Ingest"],"summary":"Ingest log records via OTLP/HTTP protobuf.","description":"Authenticates via API key in header, decompresses, decodes protobuf,\nchecks rate limit and storage quota, routes high-severity logs\nto DB and all logs to S3.","operationId":"ingest_logs","requestBody":{"description":"OTLP ExportLogsServiceRequest (protobuf, optionally gzip/zstd compressed)","content":{"application/x-protobuf":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"Logs accepted (OTLP protobuf response)"},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"413":{"description":"Storage quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"api_key":[]}]}},"/otel/v1/metrics":{"post":{"tags":["OTel Ingest"],"summary":"Ingest metrics via OTLP/HTTP protobuf.","description":"Authenticates via API key in header, decompresses, decodes protobuf,\nchecks rate limit and storage quota, then stores.","operationId":"ingest_metrics","requestBody":{"description":"OTLP ExportMetricsServiceRequest (protobuf, optionally gzip/zstd compressed)","content":{"application/x-protobuf":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"Metrics accepted (OTLP protobuf response)"},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"413":{"description":"Storage quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"api_key":[]}]}},"/otel/v1/traces":{"post":{"tags":["OTel Ingest"],"summary":"Ingest trace spans via OTLP/HTTP protobuf.","description":"Authenticates via API key in header, decompresses, decodes protobuf,\nchecks rate limit and storage quota, then stores spans.","operationId":"ingest_traces","requestBody":{"description":"OTLP ExportTraceServiceRequest (protobuf, optionally gzip/zstd compressed)","content":{"application/x-protobuf":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"Traces accepted (OTLP protobuf response)"},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"413":{"description":"Storage quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"api_key":[]}]}},"/otel/v1/{project_id}/{environment_id}/{deployment_id}/logs":{"post":{"tags":["OTel Ingest"],"summary":"Ingest log records with project/environment/deployment in the URL path.","operationId":"ingest_logs_by_path","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"OTLP ExportLogsServiceRequest (protobuf, optionally gzip/zstd compressed)","content":{"application/x-protobuf":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"Logs accepted (OTLP protobuf response)"},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"413":{"description":"Storage quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"api_key":[]}]}},"/otel/v1/{project_id}/{environment_id}/{deployment_id}/metrics":{"post":{"tags":["OTel Ingest"],"summary":"Ingest metrics with project/environment/deployment in the URL path.","operationId":"ingest_metrics_by_path","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"OTLP ExportMetricsServiceRequest (protobuf, optionally gzip/zstd compressed)","content":{"application/x-protobuf":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"Metrics accepted (OTLP protobuf response)"},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"413":{"description":"Storage quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"api_key":[]}]}},"/otel/v1/{project_id}/{environment_id}/{deployment_id}/traces":{"post":{"tags":["OTel Ingest"],"summary":"Ingest trace spans with project/environment/deployment in the URL path.","operationId":"ingest_traces_by_path","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"OTLP ExportTraceServiceRequest (protobuf, optionally gzip/zstd compressed)","content":{"application/x-protobuf":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"Traces accepted (OTLP protobuf response)"},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"413":{"description":"Storage quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"api_key":[]}]}},"/performance/has-metrics":{"get":{"tags":["Performance"],"summary":"Check if performance metrics exist for a project","operationId":"has_performance_metrics","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully checked performance metrics availability","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HasMetricsResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/performance/metrics":{"get":{"tags":["Performance"],"summary":"Get performance metrics","operationId":"get_performance_metrics","parameters":[{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Deployment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"device_type","in":"query","description":"Device type filter: desktop or mobile (optional)","required":false,"schema":{"type":"string"}},{"name":"include_bots","in":"query","description":"Include crawler/datacenter bot samples (default false)","required":false,"schema":{"type":"boolean"}},{"name":"filter_path","in":"query","description":"Filter to one page pathname (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_country","in":"query","description":"Filter to one country (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_region","in":"query","description":"Filter to one region (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_city","in":"query","description":"Filter to one city (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_browser","in":"query","description":"Filter to one browser (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_operating_system","in":"query","description":"Filter to one operating system (optional)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved performance metrics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PerformanceMetricsResponse"}}}},"400":{"description":"Invalid date format or missing parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/performance/metrics-over-time":{"get":{"tags":["Performance"],"summary":"Get metrics over time","operationId":"get_metrics_over_time","parameters":[{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DDTHH:MM:SSZ","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DDTHH:MM:SSZ","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Deployment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"device_type","in":"query","description":"Device type filter: desktop or mobile (optional)","required":false,"schema":{"type":"string"}},{"name":"include_bots","in":"query","description":"Include crawler/datacenter bot samples (default false)","required":false,"schema":{"type":"boolean"}},{"name":"filter_path","in":"query","description":"Filter to one page pathname (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_country","in":"query","description":"Filter to one country (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_region","in":"query","description":"Filter to one region (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_city","in":"query","description":"Filter to one city (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_browser","in":"query","description":"Filter to one browser (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_operating_system","in":"query","description":"Filter to one operating system (optional)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved metrics over time","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MetricsOverTimeResponse"}}}},"400":{"description":"Invalid date format or missing parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/performance/page-metrics":{"get":{"tags":["Performance"],"summary":"Get grouped page metrics","operationId":"get_grouped_page_metrics","parameters":[{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DDTHH:MM:SSZ","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DDTHH:MM:SSZ","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Deployment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"group_by","in":"query","description":"Group by: path, country, region, city, device_type, browser, operating_system","required":true,"schema":{"type":"string"}},{"name":"device_type","in":"query","description":"Device type filter: desktop or mobile (optional)","required":false,"schema":{"type":"string"}},{"name":"include_bots","in":"query","description":"Include crawler/datacenter bot samples (default false)","required":false,"schema":{"type":"boolean"}},{"name":"filter_path","in":"query","description":"Filter to one page pathname (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_country","in":"query","description":"Filter to one country (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_region","in":"query","description":"Filter to one region (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_city","in":"query","description":"Filter to one city (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_browser","in":"query","description":"Filter to one browser (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_operating_system","in":"query","description":"Filter to one operating system (optional)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved grouped page metrics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GroupedPageMetricsResponse"}}}},"400":{"description":"Invalid date format, missing parameters, or invalid group_by value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/platform/access-info":{"get":{"tags":["Platform"],"summary":"Get information about how the service is being accessed","description":"Returns details about the server's access mode, public IP address, private IP address,\nand domain creation capabilities. Both IP addresses are always included when available.","operationId":"get_access_info","responses":{"200":{"description":"Service access information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceAccessInfo"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/platform/private-ip":{"get":{"tags":["Platform"],"summary":"Get private/local IP address of the server","operationId":"get_private_ip","responses":{"200":{"description":"Successfully retrieved private IP address"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/platform/public-ip":{"get":{"tags":["Platform"],"summary":"Get public IP address of the server","operationId":"get_public_ip","responses":{"200":{"description":"Successfully retrieved public IP address"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/presets":{"get":{"tags":["Presets"],"summary":"List all available presets","operationId":"list_presets","responses":{"200":{"description":"List of available presets","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListPresetsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/presets/{slug}/dockerfile":{"post":{"tags":["Presets"],"summary":"Generate a Dockerfile from a preset","description":"Returns the Dockerfile content and build arguments for a given preset slug.\nThe CLI can use this to build Docker images locally without needing a Dockerfile\nin the project directory, enabling zero-config deployments.","operationId":"generate_preset_dockerfile","parameters":[{"name":"slug","in":"path","description":"Preset slug (e.g., nextjs, vite, python)","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateDockerfileRequest"}}},"required":true},"responses":{"200":{"description":"Generated Dockerfile","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateDockerfileResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Preset not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/preview-gateway/logs":{"get":{"tags":["Preview Gateway"],"operationId":"get_preview_gateway_logs","parameters":[{"name":"tail","in":"query","description":"Lines to tail (default 200, max 2000)","required":false,"schema":{"type":"integer","minimum":0}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LogsResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/preview-gateway/restart":{"post":{"tags":["Preview Gateway"],"operationId":"restart_preview_gateway","responses":{"204":{"description":"Gateway restarted"}},"security":[{"bearer_auth":[]}]}},"/preview-gateway/settings":{"get":{"tags":["Preview Gateway"],"operationId":"get_preview_gateway_settings","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreviewGatewaySettingsResponse"}}}}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Preview Gateway"],"operationId":"patch_preview_gateway_settings","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PatchSettingsRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreviewGatewaySettingsResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/preview-gateway/status":{"get":{"tags":["Preview Gateway"],"operationId":"get_preview_gateway_status","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayStatus"}}}}},"security":[{"bearer_auth":[]}]}},"/preview-gateway/upgrade":{"post":{"tags":["Preview Gateway"],"operationId":"upgrade_preview_gateway","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpgradeRequest"}}},"required":true},"responses":{"204":{"description":"Gateway upgraded"}},"security":[{"bearer_auth":[]}]}},"/projects":{"get":{"tags":["Projects"],"summary":"Get a list of all projects","operationId":"get_projects","parameters":[{"name":"page","in":"query","description":"Page number (1-based)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"per_page","in":"query","description":"Number of items per page","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"List of projects","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedProjectList"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Projects"],"summary":"Create a new project","operationId":"create_project","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectRequest"}}},"required":true},"responses":{"200":{"description":"Project created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"400":{"description":"Invalid input"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/by-slug/{slug}":{"get":{"tags":["Projects"],"summary":"Get details of a specific project by slug","operationId":"get_project_by_slug","parameters":[{"name":"slug","in":"path","description":"Project slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Project details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"404":{"description":"Project not found"}},"security":[{"bearer_auth":[]}]}},"/projects/from-template":{"post":{"tags":["Projects"],"summary":"Create a new project from a template","description":"Creates a new repository from a template and sets up the project with the\nspecified configuration. The template is cloned to a new repository under\nthe authenticated user's account or specified organization.","operationId":"create_project_from_template","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectFromTemplateRequest"}}},"required":true},"responses":{"201":{"description":"Project created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectFromTemplateResponse"}}}},"400":{"description":"Invalid input"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Template not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/statistics":{"get":{"tags":["Projects"],"summary":"Get project statistics","operationId":"get_project_statistics","responses":{"200":{"description":"Project statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectStatisticsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{id}":{"get":{"tags":["Projects"],"summary":"Get details of a specific project","operationId":"get_project","parameters":[{"name":"id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Project details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"404":{"description":"Project not found"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Projects"],"operationId":"update_project","parameters":[{"name":"id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectRequest"}}},"required":true},"responses":{"200":{"description":"Project updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Projects"],"operationId":"delete_project","parameters":[{"name":"id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Project deleted successfully"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{id}/deployments":{"get":{"tags":["Projects"],"operationId":"get_project_deployments","parameters":[{"name":"id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"per_page","in":"query","description":"Items per page","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"environment_id","in":"query","description":"Environment ID filter","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of deployments","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentListResponse"}}}},"404":{"description":"Project not found"}}}},"/projects/{id}/last-deployment":{"get":{"tags":["Deployments"],"summary":"Get the last deployment for a specific project","operationId":"get_last_deployment","parameters":[{"name":"id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Last deployment details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentResponse"}}}},"404":{"description":"Project not found or no deployments"},"500":{"description":"Internal server error"}}}},"/projects/{id}/source":{"patch":{"tags":["Projects"],"summary":"Change a project's source type to a Git-less type (docker_image /\nstatic_files / manual). Switching TO Git is done via the Git settings\nendpoint (`POST /projects/{id}/git`), which also supplies the repository and\nprovider connection.","operationId":"change_project_source","parameters":[{"name":"id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeProjectSourceRequest"}}},"required":true},"responses":{"200":{"description":"Source type changed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"400":{"description":"Invalid source type change (e.g. switching to Git here)"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{id}/trigger-pipeline":{"post":{"tags":["Projects"],"summary":"Trigger pipeline for a specific project","operationId":"trigger_project_pipeline","parameters":[{"name":"id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerPipelinePayload"}}},"required":true},"responses":{"200":{"description":"Pipeline triggered successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerPipelineResponse"}}}},"400":{"description":"Invalid request"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/access":{"get":{"tags":["Teams"],"operationId":"list_project_access","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Access grants","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProjectAccessResponse"}}}}},"403":{"description":"Insufficient permissions or no access to this project"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Teams"],"operationId":"grant_project_access","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectAccessRequest"}}},"required":true},"responses":{"201":{"description":"Access granted (idempotent upsert)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectAccessResponse"}}}},"403":{"description":"Insufficient permissions or no access to this project"},"404":{"description":"Team not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/access/{team_id}":{"delete":{"tags":["Teams"],"operationId":"revoke_project_access","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"team_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Access revoked"},"403":{"description":"Insufficient permissions or no access to this project"},"404":{"description":"Grant not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/active-visitors":{"get":{"tags":["Events"],"summary":"Get active visitors count","operationId":"get_active_visitors","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved active visitors count","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActiveVisitorsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents":{"get":{"tags":["Agents"],"operationId":"list_agents","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of agents for project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListAgentsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Agents"],"operationId":"create_agent","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertAgentRequest"}}},"required":true},"responses":{"201":{"description":"Agent created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentConfigResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/cli-status":{"get":{"tags":["Agents"],"operationId":"get_cli_status","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"provider","in":"query","description":"AI provider: claude_cli or codex_cli","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"CLI status"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/runs":{"get":{"tags":["Agents"],"operationId":"list_all_runs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-based)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (max 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List of all agent runs for a project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListRunsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/runs/latest-for-source":{"get":{"tags":["Agents"],"operationId":"latest_run_for_source","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"trigger_source_type","in":"query","description":"Trigger source type, e.g. 'error_group'","required":true,"schema":{"type":"string"}},{"name":"trigger_source_id","in":"query","description":"Trigger source ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Latest matching run, or null if none","content":{"application/json":{"schema":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AgentRunResponse"}]}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/runs/{run_id}":{"get":{"tags":["Agents"],"operationId":"get_run_with_logs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Run with logs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRunWithLogsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/runs/{run_id}/cancel":{"post":{"tags":["Agents"],"operationId":"cancel_run","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Agent run ID to cancel","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Run cancelled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRunResponse"}}}},"400":{"description":"Run is already in a terminal state"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/runs/{run_id}/retry":{"post":{"tags":["Agents"],"summary":"Retry a completed, failed, cancelled, or no_fix run with the same trigger context.\nCreates a new run record and spawns the executor.","operationId":"retry_run","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID to retry","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"202":{"description":"New run created from retry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRunResponse"}}}},"400":{"description":"Run is still active"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/runs/{run_id}/stream":{"get":{"tags":["Agents"],"summary":"SSE endpoint for real-time streaming of run events.\nPolls the agent_run_logs table every 500ms for new entries and streams them.\nCloses when the run reaches a terminal status.","operationId":"stream_run_events","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Agent run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Server-Sent Events stream of run log events and terminal status","content":{"text/event-stream":{}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/sandbox-status":{"get":{"tags":["Agents"],"operationId":"get_sandbox_status","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Project-scoped sandbox readiness (Docker + agent image)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxStatusResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/smoke-test":{"post":{"tags":["Agents"],"summary":"Run a smoke test to verify the selected AI CLI works in the environment\nwhere agents will actually execute (host or sandbox container). If no\n`provider_id` is supplied the globally active provider is tested.","operationId":"smoke_test_agent","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"provider_id","in":"query","description":"Provider id to test; defaults to the globally active provider","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Smoke test result for the AI CLI in the agent's execution environment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SmokeTestResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/{slug}":{"get":{"tags":["Agents"],"operationId":"get_agent","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Agent slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Agent config","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentConfigResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Agent not found"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Agents"],"operationId":"update_agent","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Agent slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertAgentRequest"}}},"required":true},"responses":{"200":{"description":"Agent updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentConfigResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Agent not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Agents"],"operationId":"delete_agent","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Agent slug","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Agent deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Agent not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/{slug}/runs":{"get":{"tags":["Agents"],"operationId":"list_agent_runs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Agent slug","required":true,"schema":{"type":"string"}},{"name":"page","in":"query","description":"Page number (1-based)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (max 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List of runs for a specific agent","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListRunsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Agent not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/{slug}/trigger":{"post":{"tags":["Agents"],"operationId":"trigger_agent","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Agent slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerAgentRequest"}}},"required":true},"responses":{"202":{"description":"Agent run created and queued","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRunResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"402":{"description":"Daily budget exceeded"},"403":{"description":"Insufficient permissions"},"404":{"description":"Agent not found"},"422":{"description":"AI CLI not installed"},"429":{"description":"Cooldown active"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/aggregated-buckets":{"get":{"tags":["Events"],"summary":"Get aggregated metrics by time bucket","operationId":"get_aggregated_buckets","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date for the query range","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date for the query range","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Optional environment filter","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Optional deployment filter","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"aggregation_level","in":"query","description":"Aggregation level: events, sessions, or visitors (default: events)","required":false,"schema":{"type":"string"}},{"name":"bucket_size","in":"query","description":"Time bucket size: '1 hour', '1 day', '1 week', etc. (default: '1 hour')","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved aggregated buckets","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AggregatedBucketsResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/conversations":{"get":{"tags":["AI Chat"],"summary":"Find the existing chat for a context (returns `null` if none yet). Requires\nthe per-project `ai_debug_chat_enabled` toggle to be on; returns 403 when the\nfeature is disabled so revoking it consistently hides existing chat content.","operationId":"find_conversation","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"context_type","in":"query","required":true,"schema":{"type":"string"}},{"name":"context_id","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ConversationResponse"}]}}}},"401":{"description":""},"403":{"description":""}},"security":[{"bearer_auth":[]}]},"post":{"tags":["AI Chat"],"summary":"Get-or-create the chat for a context (seeds it on first open).","operationId":"create_conversation","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateConversationRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversationResponse"}}}},"401":{"description":""},"403":{"description":""},"404":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/conversations/list":{"get":{"tags":["AI Chat"],"summary":"List all active conversations for a project, most-recently-active first.\nPowers the conversation switcher in the AI assistant sidebar.","operationId":"list_conversations","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ConversationResponse"}}}}},"401":{"description":""},"403":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/conversations/{public_id}":{"get":{"tags":["AI Chat"],"summary":"Full conversation history (excluding the internal system seed).","operationId":"get_conversation","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"public_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversationDetailResponse"}}}},"401":{"description":""},"403":{"description":""},"404":{"description":""}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["AI Chat"],"summary":"Rename a conversation (set its human-facing title).","operationId":"rename_conversation","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"public_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RenameConversationRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversationResponse"}}}},"400":{"description":""},"401":{"description":""},"403":{"description":""},"404":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/conversations/{public_id}/archive":{"post":{"tags":["AI Chat"],"summary":"Archive (soft-delete) a conversation.","operationId":"archive_conversation","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"public_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":""},"401":{"description":""},"403":{"description":""},"404":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/conversations/{public_id}/messages":{"post":{"tags":["AI Chat"],"summary":"Send a user message; stream the assistant reply as Server-Sent Events.","operationId":"send_message","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"public_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendMessageRequest"}}},"required":true},"responses":{"200":{"description":"SSE stream of assistant text deltas","content":{"text/event-stream":{}}},"401":{"description":""},"403":{"description":""},"404":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/conversations/{public_id}/pending-actions":{"get":{"tags":["AI Chat"],"summary":"List all pending actions for a conversation (most-recently-proposed first).","operationId":"list_pending_actions","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"public_id","in":"path","description":"Conversation public id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PendingActionResponse"}}}}},"401":{"description":""},"403":{"description":""},"404":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/pending-actions/{action_public_id}":{"get":{"tags":["AI Chat"],"summary":"Get a single pending action by its public id (scoped to the project).","operationId":"get_pending_action","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"action_public_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PendingActionResponse"}}}},"401":{"description":""},"403":{"description":""},"404":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/pending-actions/{action_public_id}/confirm":{"post":{"tags":["AI Chat"],"summary":"Confirm a proposed AI action: validate permission, atomically claim, execute,\npersist outcome. The execution uses the CONFIRMING user's auth — never the model's.","operationId":"confirm_pending_action","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"action_public_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PendingActionResponse"}}}},"401":{"description":""},"403":{"description":""},"404":{"description":""},"409":{"description":""},"503":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/pending-actions/{action_public_id}/reject":{"post":{"tags":["AI Chat"],"summary":"Reject a proposed AI action (no execution). Status transitions to \"rejected\".","operationId":"reject_pending_action","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"action_public_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PendingActionResponse"}}}},"401":{"description":""},"403":{"description":""},"404":{"description":""},"409":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/readiness":{"get":{"tags":["AI Chat"],"summary":"Report which AI prerequisites this project satisfies.","description":"Read-only and cheap, so the UI can decide up front whether to show a working\nentry point, an onboarding path, or nothing — instead of letting the user\nclick something that fails with a 409 they can't act on.","operationId":"get_chat_readiness","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Which AI prerequisites are met","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatReadinessResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/alarms":{"get":{"tags":["Alarms"],"summary":"List alarms for a project with optional filters.","operationId":"listProjectAlarms","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"alarm_type","in":"query","description":"Filter by alarm type (e.g. `container_restart`, `outage`).","required":false,"schema":{"type":["string","null"]}},{"name":"status","in":"query","description":"Filter by status: `firing`, `acknowledged`, or `resolved`.","required":false,"schema":{"type":["string","null"]}},{"name":"severity","in":"query","description":"Filter by severity: `info`, `warning`, or `critical`.","required":false,"schema":{"type":["string","null"]}},{"name":"environment_id","in":"query","description":"Filter by environment ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"service_id","in":"query","description":"Filter by external service ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"page","in":"query","description":"Page number (1-based, default 1).","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page (default 20, max 100).","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}}],"responses":{"200":{"description":"Paginated list of alarms","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlarmListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/alarms/summary":{"get":{"tags":["Alarms"],"summary":"Get alarm counts by status/severity/type for a project (dashboard summary widget).","operationId":"getProjectAlarmsSummary","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Alarm summary counts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlarmSummaryResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/alarms/{alarm_id}/acknowledge":{"post":{"tags":["Alarms"],"summary":"Acknowledge a firing alarm (marks it as seen but not resolved).","operationId":"acknowledgeAlarm","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"alarm_id","in":"path","description":"Alarm ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Alarm acknowledged"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Alarm not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/alarms/{alarm_id}/resolve":{"post":{"tags":["Alarms"],"summary":"Resolve an alarm.","operationId":"resolveAlarm","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"alarm_id","in":"path","description":"Alarm ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Alarm resolved"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Alarm not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/analyze":{"post":{"tags":["Autofixer"],"summary":"Start an autofixer analysis run for the given error group.\nCreates the run record immediately and spawns analysis in the background.","operationId":"start_analysis","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartAnalysisRequest"}}},"required":true},"responses":{"202":{"description":"Analysis started; returns run_id for streaming","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutofixerRunResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/runs/{run_id}":{"get":{"tags":["Autofixer"],"summary":"Get a single autofixer run with its logs.","operationId":"get_run","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Run with logs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutofixerRunWithLogsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/runs/{run_id}/add-context":{"post":{"tags":["Autofixer"],"summary":"Append a user message to the run's context field.","operationId":"add_context","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddContextRequest"}}},"required":true},"responses":{"200":{"description":"Context appended"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/runs/{run_id}/cancel":{"post":{"tags":["Autofixer"],"summary":"Cancel an autofixer run and clean up the work directory.","operationId":"cancel","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Run cancelled"},"400":{"description":"Run is already in a terminal state"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/runs/{run_id}/create-pr":{"post":{"tags":["Autofixer"],"summary":"Push the fix branch and create a pull request.\nRequires phase == \"fix_ready\".","operationId":"create_pr","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"201":{"description":"PR created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePrResponse"}}}},"400":{"description":"Run not in fix_ready phase"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/runs/{run_id}/fix":{"post":{"tags":["Autofixer"],"summary":"Transition from analysis to fix phase.\nRequires phase == \"analyzed\".","operationId":"start_fix","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"202":{"description":"Fix generation started"},"400":{"description":"Run not in analyzed phase"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/runs/{run_id}/re-analyze":{"post":{"tags":["Autofixer"],"summary":"Continue the conversation with user feedback.\nUses the same Claude session (--continue) in the existing work directory.\nRequires phase == \"analyzed\".","operationId":"re_analyze","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"202":{"description":"Conversation continued with feedback"},"400":{"description":"Run not in analyzed phase"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/runs/{run_id}/stream":{"get":{"tags":["Agents"],"summary":"SSE endpoint: streams run log events in real-time.\nPolls every 500 ms. Keeps the connection open through \"analyzed\" and \"fix_ready\"\nwaiting states; closes only on terminal statuses.","operationId":"stream_events","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Autofixer run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Server-Sent Events stream of autofixer run logs and status updates","content":{"text/event-stream":{}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/automatic-deploy":{"post":{"tags":["Projects"],"summary":"Update automatic deployment setting for a project","operationId":"update_automatic_deploy","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAutomaticDeployRequest"}}},"required":true},"responses":{"200":{"description":"Automatic deployment setting updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/custom-domains":{"get":{"tags":["Custom Domains"],"summary":"List all custom domains for a project","operationId":"list_custom_domains_for_project","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Custom domains retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListCustomDomainsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Custom Domains"],"summary":"Create a custom domain for a project","operationId":"create_custom_domain","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomDomainRequest"}}},"required":true},"responses":{"201":{"description":"Custom domain created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomDomainResponse"}}}},"400":{"description":"Invalid input"},"401":{"description":"Unauthorized"},"409":{"description":"Domain already exists"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/custom-domains/{domain_id}":{"get":{"tags":["Custom Domains"],"summary":"Get a custom domain by ID","operationId":"get_custom_domain","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain_id","in":"path","description":"Custom domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Custom domain retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomDomainResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Custom domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Custom Domains"],"summary":"Update a custom domain","operationId":"update_custom_domain","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain_id","in":"path","description":"Custom domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCustomDomainRequest"}}},"required":true},"responses":{"200":{"description":"Custom domain updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomDomainResponse"}}}},"400":{"description":"Invalid input"},"401":{"description":"Unauthorized"},"404":{"description":"Custom domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Custom Domains"],"summary":"Delete a custom domain","operationId":"delete_custom_domain","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain_id","in":"path","description":"Custom domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Custom domain deleted successfully"},"401":{"description":"Unauthorized"},"404":{"description":"Custom domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/custom-domains/{domain_id}/link-certificate/{certificate_id}":{"post":{"tags":["Custom Domains"],"summary":"Link a custom domain to a certificate","operationId":"link_custom_domain_to_certificate","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain_id","in":"path","description":"Custom domain ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"certificate_id","in":"path","description":"Certificate ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Custom domain linked to certificate successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomDomainResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Custom domain or certificate not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/deployment-config":{"patch":{"tags":["Projects"],"summary":"Update deployment configuration for a project","operationId":"update_project_deployment_config","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDeploymentConfigRequest"}}},"required":true},"responses":{"200":{"description":"Deployment configuration updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"400":{"description":"Invalid deployment configuration"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/deployment-tokens":{"get":{"tags":["Deployment Tokens"],"summary":"List all deployment tokens for a project","operationId":"list_deployment_tokens","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List of deployment tokens","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentTokenListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Deployment Tokens"],"summary":"Create a new deployment token for a project","operationId":"create_deployment_token","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDeploymentTokenRequest"}}},"required":true},"responses":{"201":{"description":"Deployment token created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDeploymentTokenResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"409":{"description":"Token with this name already exists"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/deployment-tokens/{token_id}":{"get":{"tags":["Deployment Tokens"],"summary":"Get a specific deployment token","operationId":"get_deployment_token","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"token_id","in":"path","description":"Deployment token ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deployment token details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentTokenResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Deployment token not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Deployment Tokens"],"summary":"Delete a deployment token","operationId":"delete_deployment_token","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"token_id","in":"path","description":"Deployment token ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Deployment token deleted successfully"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Deployment token not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Deployment Tokens"],"summary":"Update a deployment token","operationId":"update_deployment_token","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"token_id","in":"path","description":"Deployment token ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDeploymentTokenRequest"}}},"required":true},"responses":{"200":{"description":"Deployment token updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentTokenResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Deployment token not found"},"409":{"description":"Token with this name already exists"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/deployment-tokens/{token_id}/rotate":{"post":{"tags":["Deployment Tokens"],"summary":"Rotate a deployment token, invalidating its old secret and issuing a new one","operationId":"rotate_deployment_token","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"token_id","in":"path","description":"Deployment token ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deployment token rotated successfully; the response contains the new plaintext token, shown only once","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDeploymentTokenResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Deployment token not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/deployments/{deployment_id}":{"get":{"tags":["Deployments"],"summary":"Get a specific deployment by ID for a project (identified by ID or slug)","operationId":"get_deployment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deployment details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentResponse"}}}},"404":{"description":"Project or deployment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/deployments/{deployment_id}/cancel":{"post":{"tags":["Projects"],"summary":"Cancel a deployment","operationId":"cancel_deployment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deployment cancelled successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentStateResponse"}}}},"400":{"description":"Deployment cannot be cancelled (already completed, failed, or cancelled)"},"404":{"description":"Project or deployment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/deployments/{deployment_id}/container-logs":{"get":{"tags":["Deployments"],"summary":"List the captured (historical) container-log dumps for a deployment.","description":"Container runtime logs are normally only available live from the running\ncontainer. When a deployment is superseded its containers are torn down and\nthose logs would be lost — so just before teardown we capture each\ncontainer's logs to durable storage. This endpoint lists what was captured\nfor a given (often older) deployment, so a user can read the logs of a\ncontainer that no longer exists.","operationId":"list_deployment_container_logs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Captured container logs for the deployment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentContainerLogsListResponse"}}}},"404":{"description":"Deployment not found in this project"},"500":{"description":"Internal server error"}},"security":[{"bearer_token":[]}]}},"/projects/{project_id}/deployments/{deployment_id}/container-logs/{log_id}":{"get":{"tags":["Deployments"],"summary":"Get the captured text content of a single historical container-log dump.","operationId":"get_deployment_container_log_content","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"log_id","in":"path","description":"Captured log ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Captured container log content","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentContainerLogContentResponse"}}}},"404":{"description":"Captured log not found in this project"},"500":{"description":"Internal server error"}},"security":[{"bearer_token":[]}]}},"/projects/{project_id}/deployments/{deployment_id}/jobs":{"get":{"tags":["Deployments"],"summary":"Get jobs for a specific deployment","description":"Returns all jobs (workflow tasks) for a deployment, ordered by execution order.\nThis replaces the old deployment stages endpoint.","operationId":"get_deployment_jobs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Jobs retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentJobsResponse"}}}},"404":{"description":"Deployment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/deployments/{deployment_id}/jobs/{job_id}/logs":{"get":{"tags":["Deployments"],"summary":"Get logs for a specific deployment job","operationId":"get_deployment_job_logs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"job_id","in":"path","description":"Job ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Job logs retrieved successfully","content":{"text/plain":{"schema":{"type":"string"}}}},"404":{"description":"Job or logs not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_token":[]}]}},"/projects/{project_id}/deployments/{deployment_id}/jobs/{job_id}/logs/tail":{"get":{"tags":["Deployments"],"summary":"Tail logs for a specific deployment job in real-time via WebSocket","description":"**WebSocket Streaming**: Logs are sent as raw text, one line per WebSocket message.\n\n**Authentication**: Requires authentication via session cookie (browser clients)\nor API key (API clients). For browser-based WebSocket connections, ensure the user\nis logged in - the browser automatically includes session cookies in the WebSocket\nupgrade request.\n\n**API Client Authentication**: Include API key in Authorization header:\n```text\nAuthorization: Bearer tk_your_api_key_here\n```","operationId":"tail_deployment_job_logs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"job_id","in":"path","description":"Job ID","required":true,"schema":{"type":"string"}}],"responses":{"101":{"description":"WebSocket connection established for streaming deployment job logs"},"404":{"description":"Job or logs not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_token":[]}]}},"/projects/{project_id}/deployments/{deployment_id}/operations":{"get":{"tags":["Deployments"],"summary":"Get all operations for a deployment","operationId":"get_deployment_operations","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of operations","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperationResultsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Deployment not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Deployments"],"summary":"Execute a deployment operation (deploy, mark_complete, take_screenshot)","operationId":"execute_deployment_operation","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecuteOperationRequest"}}},"required":true},"responses":{"202":{"description":"Operation executed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperationResultResponse"}}}},"400":{"description":"Invalid operation"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Deployment not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/deployments/{deployment_id}/operations/{operation_type}":{"get":{"tags":["Deployments"],"summary":"Get the status of a specific operation type","operationId":"get_deployment_operation_status","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","required":true,"schema":{"type":"string"}},{"name":"operation_type","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Operation status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperationResultResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Operation not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/deployments/{deployment_id}/pause":{"post":{"tags":["Projects"],"summary":"Pause a deployment","operationId":"pause_deployment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deployment paused successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentStateResponse"}}}},"404":{"description":"Project or deployment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/deployments/{deployment_id}/promote":{"post":{"tags":["Deployments"],"summary":"Promote a deployment to another environment","description":"Creates a new deployment in the target environment using the source deployment's\nDocker image. Useful for promoting a validated preview/staging deployment to production.","operationId":"promote_deployment","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Source deployment ID to promote","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PromoteDeploymentRequest"}}},"required":true},"responses":{"200":{"description":"Promotion initiated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentResponse"}}}},"400":{"description":"Invalid deployment state for promotion"},"404":{"description":"Project, deployment, or target environment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/deployments/{deployment_id}/resume":{"post":{"tags":["Projects"],"summary":"Resume a deployment","operationId":"resume_deployment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deployment resumed successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentStateResponse"}}}},"404":{"description":"Project or deployment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/deployments/{deployment_id}/rollback":{"post":{"tags":["Projects"],"operationId":"rollback_to_deployment","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID to rollback to","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Rollback initiated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentResponse"}}}},"404":{"description":"Project or deployment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/deployments/{deployment_id}/teardown":{"delete":{"tags":["Projects"],"summary":"Teardown a specific deployment","operationId":"teardown_deployment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Deployment torn down successfully"},"404":{"description":"Project or deployment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/dsns":{"get":{"tags":[],"summary":"List all DSNs for a project","operationId":"list_dsns","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of DSNs","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProjectDSNResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"post":{"tags":[],"summary":"Create a new DSN for a project","operationId":"create_dsn","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDSNRequest"}}},"required":true},"responses":{"201":{"description":"DSN created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectDSNResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/dsns/get-or-create":{"post":{"tags":[],"summary":"Get or create DSN for a project/environment/deployment combination","operationId":"get_or_create_dsn","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetOrCreateDSNRequest"}}},"required":true},"responses":{"200":{"description":"DSN retrieved or created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectDSNResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/dsns/{dsn_id}/regenerate":{"post":{"tags":[],"summary":"Regenerate DSN keys (rotate keys)","operationId":"regenerate_dsn","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"dsn_id","in":"path","description":"DSN ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegenerateDSNRequest"}}},"required":true},"responses":{"200":{"description":"DSN keys regenerated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectDSNResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"DSN not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/dsns/{dsn_id}/revoke":{"post":{"tags":[],"summary":"Revoke (deactivate) a DSN","operationId":"revoke_dsn","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"dsn_id","in":"path","description":"DSN ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"DSN revoked"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"DSN not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/env-vars":{"get":{"tags":["Projects"],"summary":"Get environment variables for a project, optionally filtered by environment","operationId":"get_environment_variables","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Optional environment ID to filter by","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of environment variables","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EnvironmentVariableResponse"}}}}},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}},"post":{"tags":["Projects"],"summary":"Create a new environment variable","operationId":"create_environment_variable","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEnvironmentVariableRequest"}}},"required":true},"responses":{"201":{"description":"Environment variables created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentVariableResponse"}}}},"400":{"description":"Invalid input"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/env-vars/resolved":{"get":{"tags":["Projects"],"summary":"Resolved env vars for a project (manual + integration-sourced, merged).","description":"Returns the effective set of environment variables a deployment would see,\ncombining manually-defined vars with those contributed by linked external\nservices (Postgres, Redis, S3, etc.). Each entry is tagged with its source\nso the UI can render an integration icon, and manual entries that shadow an\nintegration key carry a reference to the integration they override.\n\nValues are always returned as a masked preview. Use the per-key reveal\nendpoint for plaintext (audit-logged).","operationId":"get_resolved_environment_variables","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Optional environment ID to filter manual vars by","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Resolved environment variables","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ResolvedEnvVarResponse"}}}}},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/env-vars/resolved/{key}/value":{"get":{"tags":["Projects"],"summary":"Reveal the plaintext value of a resolved environment variable.","description":"Mirrors `GET /projects/{id}/env-vars/{key}/value` but handles keys sourced\nfrom linked integrations (which are not stored in the `env_vars` table).\nResolution order mirrors the merged view:\n\n1. Manual env var with this key — this endpoint reads the manual store when\n the key exists there, then writes its own reveal audit event so callers\n can safely use one endpoint regardless of source.\n2. Integration env var supplied by a linked external service.\n\nReturns 404 when neither a manual var nor an integration produces the key.","operationId":"get_resolved_environment_variable_value","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"key","in":"path","description":"Environment variable key","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Optional environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"var_id","in":"query","description":"Exact manual environment-variable row ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"service_id","in":"query","description":"Integration service ID shown by the resolved list","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Resolved environment variable value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentVariableValueResponse"}}}},"403":{"description":"Plaintext secret access is not permitted"},"404":{"description":"Project, key, or integration not found"},"409":{"description":"Environment variable key is ambiguous"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/env-vars/{key}/value":{"get":{"tags":["Projects"],"summary":"Get environment variable value by key","operationId":"get_environment_variable_value","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"key","in":"path","description":"Environment variable key","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Optional environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"var_id","in":"query","description":"Exact environment-variable row ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Environment variable value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentVariableValueResponse"}}}},"403":{"description":"Plaintext secret access is not permitted"},"404":{"description":"Project or variable not found"},"409":{"description":"Environment variable key is ambiguous"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/env-vars/{var_id}":{"put":{"tags":["Projects"],"summary":"Update an environment variable","operationId":"update_environment_variable","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"var_id","in":"path","description":"Environment variable ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEnvironmentVariableRequest"}}},"required":true},"responses":{"200":{"description":"Environment variables updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentVariableResponse"}}}},"400":{"description":"Invalid input"},"404":{"description":"Project or variable not found"},"500":{"description":"Internal server error"}}},"delete":{"tags":["Projects"],"summary":"Delete an environment variable","operationId":"delete_environment_variable","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"var_id","in":"path","description":"Environment variable ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Environment variable deleted successfully"},"404":{"description":"Project or variable not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments":{"get":{"tags":["Projects"],"summary":"Get all environments for a project","operationId":"get_environments","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of environments","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EnvironmentResponse"}}}}},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}},"post":{"tags":["Projects"],"summary":"Create a new environment for a project","operationId":"create_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEnvironmentRequest"}}},"required":true},"responses":{"201":{"description":"Environment created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentResponse"}}}},"400":{"description":"Invalid input"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}":{"get":{"tags":["Projects"],"summary":"Get a specific environment by ID or slug","operationId":"get_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Environment details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentResponse"}}}},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}}},"delete":{"tags":["Projects"],"summary":"Delete an environment permanently","description":"Permanently deletes an environment and all related data. Cannot delete:\n- Production environments (name = \"Production\")\n\nWarning: This action is permanent and cannot be undone.\nActive deployments are automatically cancelled before deletion.","operationId":"delete_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Environment permanently deleted"},"400":{"description":"Cannot delete production environment"},"404":{"description":"Project or environment not found"},"428":{"description":"Recent MFA verification required"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/crons":{"get":{"tags":["Crons"],"operationId":"get_environment_crons","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of cron jobs","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CronInfo"}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/crons/{cron_id}":{"get":{"tags":["Crons"],"operationId":"get_cron_by_id","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"cron_id","in":"path","description":"Cron Job ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Cron job details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CronInfo"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Cron job not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/crons/{cron_id}/executions":{"get":{"tags":["Crons"],"operationId":"get_cron_executions","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"cron_id","in":"path","description":"Cron Job ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"per_page","in":"query","description":"Items per page (default: 20)","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"List of cron job executions","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CronExecutionInfo"}}}}},"401":{"description":"Unauthorized"},"404":{"description":"Cron job not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/domains":{"get":{"tags":["Projects"],"summary":"Get all environment domains for a specific environment","operationId":"get_environment_domains","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of environment domains","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EnvironmentDomainResponse"}}}}},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}}},"post":{"tags":["Projects"],"summary":"Add a new environment domain","operationId":"add_environment_domain","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddEnvironmentDomainRequest"}}},"required":true},"responses":{"201":{"description":"Domain added successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentDomainResponse"}}}},"400":{"description":"Invalid input"},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/domains/{domain_id}":{"delete":{"tags":["Projects"],"summary":"Delete an environment domain","operationId":"delete_environment_domain","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain_id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Domain deleted successfully"},"404":{"description":"Project, environment, or domain not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/settings":{"put":{"tags":["Projects"],"summary":"Update environment settings","operationId":"update_environment_settings","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEnvironmentSettingsRequest"}}},"required":true},"responses":{"200":{"description":"Environment settings updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentResponse"}}}},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/sleep":{"post":{"tags":["Environments"],"summary":"Sleep an on-demand environment","description":"Manually put an on-demand environment to sleep. Stops containers and sets\n`sleeping = true`. If no OnDemandWaker is available, falls back to DB flag only.","operationId":"sleep_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Environment put to sleep","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentResponse"}}}},"400":{"description":"On-demand not enabled for this environment"},"404":{"description":"Environment not found"},"429":{"description":"Too many state transitions, retry after cooldown"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/subdomain":{"patch":{"tags":["Projects"],"summary":"Rename the auto-managed subdomain for an environment.","description":"Replaces the environment's previous subdomain entirely — the old\nhostname stops resolving once the proxy reloads its route table.\nCustom domains attached to the environment are unaffected.","operationId":"update_environment_subdomain","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEnvironmentSubdomainRequest"}}},"required":true},"responses":{"200":{"description":"Subdomain updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentResponse"}}}},"400":{"description":"Invalid subdomain or conflict with another environment"},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/teardown":{"delete":{"tags":["Projects"],"summary":"Teardown an environment and all its active deployments","operationId":"teardown_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Environment torn down successfully"},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/wake":{"post":{"tags":["Environments"],"summary":"Wake a sleeping on-demand environment","description":"Manually wake an environment that has been put to sleep by the on-demand\nidle timeout. Starts containers, waits for health checks, then sets\n`sleeping = false`. If no OnDemandWaker is available (proxy not running\nin same process), falls back to setting the DB flag only.","operationId":"wake_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Environment woken up","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentResponse"}}}},"400":{"description":"On-demand not enabled for this environment"},"404":{"description":"Environment not found"},"429":{"description":"Too many state transitions, retry after cooldown"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{environment_id}/container-logs":{"get":{"tags":["Deployments"],"summary":"Get logs for a container in an environment via WebSocket","operationId":"get_container_logs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date for logs","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"end_date","in":"query","description":"End date for logs","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"tail","in":"query","description":"Number of lines to tail (or 'all')","required":false,"schema":{"type":"string"}},{"name":"container_name","in":"query","description":"Optional container name (defaults to first/primary container)","required":false,"schema":{"type":"string"}},{"name":"timestamps","in":"query","description":"Include timestamps in log output (default: false)","required":false,"schema":{"type":"boolean"}},{"name":"follow","in":"query","description":"Follow log output in real-time (default: true)","required":false,"schema":{"type":"boolean"}}],"responses":{"101":{"description":"WebSocket connection established for streaming container logs"},"400":{"description":"Not a server-type project"},"404":{"description":"Project, deployment, or container not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/containers":{"get":{"tags":["Deployments"],"summary":"List all containers for an environment","operationId":"list_containers","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of containers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerListResponse"}}}},"400":{"description":"Not a server-type project"},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}":{"get":{"tags":["Containers"],"summary":"Get detailed information about a specific container","operationId":"get_container_detail","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Container details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerDetailResponse"}}}},"404":{"description":"Container not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/environment/{variable_name}":{"get":{"tags":["Containers"],"operationId":"get_container_environment_variable","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}},{"name":"variable_name","in":"path","description":"Environment variable name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Environment variable value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerEnvironmentVariableValueResponse"}}}},"403":{"description":"Plaintext secret access is not permitted"},"404":{"description":"Container or environment variable not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/logs":{"get":{"tags":["Deployments"],"summary":"Get logs for a specific container by container ID via WebSocket","operationId":"get_container_logs_by_id","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}},{"name":"start_date","in":"query","description":"Start date for logs","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"end_date","in":"query","description":"End date for logs","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"tail","in":"query","description":"Number of lines to tail (or 'all')","required":false,"schema":{"type":"string"}},{"name":"timestamps","in":"query","description":"Include timestamps in log output (default: false)","required":false,"schema":{"type":"boolean"}},{"name":"follow","in":"query","description":"Follow log output in real-time (default: true)","required":false,"schema":{"type":"boolean"}}],"responses":{"101":{"description":"WebSocket connection established for streaming container logs"},"400":{"description":"Not a server-type project"},"404":{"description":"Project, environment, or container not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/metrics":{"get":{"tags":["Containers"],"summary":"Get metrics/stats for a specific container","operationId":"get_container_metrics","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Container metrics retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerMetricsResponse"}}}},"404":{"description":"Container not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/metrics/history":{"get":{"tags":["Containers"],"summary":"Fetch a time-series range for a single container resource metric\n(recorded by the container health monitor every ~30s).","description":"Useful metric names: `container.cpu_percent`,\n`container.cpu_utilization_percent`, `container.memory_used_bytes`,\n`container.memory_percent`, `container.network_rx_bytes_delta`,\n`container.network_tx_bytes_delta`.","operationId":"ContainerMetricsGetHistory","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}},{"name":"metric","in":"query","description":"Dotted metric name, e.g. `container.cpu_percent` or\n`container.memory_used_bytes`.","required":true,"schema":{"type":"string"}},{"name":"range","in":"query","description":"Time window: `1h`, `6h`, `24h`, or `7d` (defaults to `1h`).","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Metric time series data points","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ContainerMetricHistoryPoint"}}}}},"401":{"description":"Unauthorized"},"404":{"description":"Container not found"},"500":{"description":"Internal server error"},"503":{"description":"Metrics store not available"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/metrics/stream":{"get":{"tags":["Containers"],"summary":"Stream container metrics via Server-Sent Events (SSE)","operationId":"stream_container_metrics","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}},{"name":"interval","in":"query","description":"Update interval in milliseconds (default: 1000)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Metrics stream established (Server-Sent Events)"},"404":{"description":"Container not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/restart":{"post":{"tags":["Containers"],"summary":"Restart a container","operationId":"restart_container","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Container restarted successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerActionResponse"}}}},"404":{"description":"Container not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/start":{"post":{"tags":["Containers"],"summary":"Start a container","operationId":"start_container","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Container started successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerActionResponse"}}}},"404":{"description":"Container not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/stop":{"post":{"tags":["Containers"],"summary":"Stop a specific container","operationId":"stop_container","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Container stopped successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerActionResponse"}}}},"404":{"description":"Container not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{environment_id}/deploy/image":{"post":{"tags":["Deployments"],"summary":"Deploy from an external Docker image","description":"Triggers a deployment using a pre-built Docker image from an external registry.\nThe image will be pulled and deployed to the specified environment.","operationId":"deploy_from_image","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeployFromImageRequest"}}},"required":true},"responses":{"202":{"description":"Deployment started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RemoteDeploymentResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/deploy/image-upload":{"post":{"tags":["Deployments"],"summary":"Deploy from an uploaded Docker image tarball","description":"Uploads a Docker image tarball (from `docker save`) and deploys it directly.\nThe image is imported using `docker load` and then deployed to the specified environment.\nThis is useful when you want to deploy an image without pushing to a registry first.\n\nThe uploaded file should be a tarball created by `docker save myimage:tag > image.tar`\nor `docker save myimage:tag | gzip > image.tar.gz` (gzip compressed tarballs are also supported).","operationId":"deploy_from_image_upload","parameters":[{"name":"tag","in":"query","description":"Tag to apply to the imported image (e.g., \"myapp:v1.0\")\nIf not provided, a unique tag will be generated","required":false,"schema":{"type":["string","null"]}},{"name":"health_check_path","in":"query","description":"Optional HTTP health-check path override (e.g. \"/api/healthz\").\nMust start with '/'. When omitted, defaults to \"/\".","required":false,"schema":{"type":["string","null"]}},{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"202":{"description":"Image imported and deployment started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RemoteDeploymentResponse"}}}},"400":{"description":"Invalid request or unsupported format"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project or environment not found"},"413":{"description":"Image tarball too large"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/deploy/source":{"post":{"tags":["Deployments"],"summary":"Upload source code and immediately start a preset-based deployment.","operationId":"deploy_from_uploaded_source","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/SourceArchiveUpload"}}},"required":true},"responses":{"202":{"description":"Source deployment started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RemoteDeploymentResponse"}}}},"400":{"description":"Invalid source archive"},"404":{"description":"Project or environment not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/deploy/static":{"post":{"tags":["Deployments"],"summary":"Deploy from an uploaded static bundle","description":"Triggers a deployment using a previously uploaded static file bundle.","operationId":"deploy_from_static","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeployFromStaticRequest"}}},"required":true},"responses":{"202":{"description":"Deployment started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RemoteDeploymentResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project, environment, or bundle not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/error-alert-rules":{"get":{"tags":["error-alert-rules"],"summary":"List all alert rules for a project","operationId":"list_alert_rules","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of alert rules","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AlertRuleResponse"}}}}},"500":{"description":"Internal server error"}}},"post":{"tags":["error-alert-rules"],"summary":"Create a new alert rule","operationId":"create_alert_rule","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAlertRuleRequest"}}},"required":true},"responses":{"201":{"description":"Alert rule created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlertRuleResponse"}}}},"400":{"description":"Validation error"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-alert-rules/{rule_id}":{"get":{"tags":["error-alert-rules"],"summary":"Get a specific alert rule","operationId":"get_alert_rule","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"rule_id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Alert rule details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlertRuleResponse"}}}},"404":{"description":"Alert rule not found"},"500":{"description":"Internal server error"}}},"put":{"tags":["error-alert-rules"],"summary":"Update an existing alert rule","operationId":"update_alert_rule","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"rule_id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAlertRuleRequest"}}},"required":true},"responses":{"200":{"description":"Alert rule updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlertRuleResponse"}}}},"400":{"description":"Validation error"},"404":{"description":"Alert rule not found"},"500":{"description":"Internal server error"}}},"delete":{"tags":["error-alert-rules"],"summary":"Delete an alert rule","operationId":"delete_alert_rule","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"rule_id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Alert rule deleted"},"404":{"description":"Alert rule not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-dashboard-stats":{"get":{"tags":["error-tracking"],"summary":"Get error dashboard statistics","operationId":"get_error_dashboard_stats","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_time","in":"query","required":true,"schema":{"type":"string","format":"date-time"}},{"name":"end_time","in":"query","required":true,"schema":{"type":"string","format":"date-time"}},{"name":"environment_id","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"compare_to_previous","in":"query","required":false,"schema":{"type":["boolean","null"]}}],"responses":{"200":{"description":"Error dashboard statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDashboardStatsResponse"}}}},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-groups":{"get":{"tags":["error-tracking"],"summary":"List error groups for a project","operationId":"list_error_groups","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"status","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"environment_id","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"start_date","in":"query","required":false,"schema":{"type":["string","null"],"format":"date-time"}},{"name":"end_date","in":"query","required":false,"schema":{"type":["string","null"],"format":"date-time"}},{"name":"sort_by","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Paginated list of error groups","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedErrorGroupsResponse"}}}},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-groups/{group_id}":{"get":{"tags":["error-tracking"],"summary":"Get a specific error group","operationId":"get_error_group","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"group_id","in":"path","description":"Error group ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Error group details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorGroupResponse"}}}},"404":{"description":"Error group not found"},"500":{"description":"Internal server error"}}},"put":{"tags":["error-tracking"],"summary":"Update error group status","operationId":"update_error_group","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"group_id","in":"path","description":"Error group ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateErrorGroupRequest"}}},"required":true},"responses":{"200":{"description":"Error group updated successfully"},"404":{"description":"Error group not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-groups/{group_id}/events":{"get":{"tags":["error-tracking"],"summary":"List error events for a specific group","operationId":"list_error_events","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"group_id","in":"path","description":"Error group ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Paginated list of error events","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedErrorEventsResponse"}}}},"404":{"description":"Error group not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-groups/{group_id}/events/{event_id}":{"get":{"tags":["error-tracking"],"summary":"Get a specific error event","operationId":"get_error_event","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"group_id","in":"path","description":"Error group ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"event_id","in":"path","description":"Error event ID","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Error event details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEventResponse"}}}},"404":{"description":"Event not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-stats":{"get":{"tags":["error-tracking"],"summary":"Get error statistics for a project","operationId":"get_error_stats","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Error statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorGroupStatsResponse"}}}},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-time-series":{"get":{"tags":["error-tracking"],"summary":"Get error time series data for charts","operationId":"get_error_time_series","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_time","in":"query","required":true,"schema":{"type":"string","format":"date-time"}},{"name":"end_time","in":"query","required":true,"schema":{"type":"string","format":"date-time"}},{"name":"bucket","in":"query","description":"Time bucket size (e.g., \"1h\", \"15m\", \"1d\", \"1 hour\", \"30 minutes\")","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Error time series data","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ErrorTimeSeriesDataResponse"}}}}},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/events":{"get":{"tags":["Events"],"summary":"Get event counts with filtering","operationId":"get_events_count","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date for filtering events","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date for filtering events","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"limit","in":"query","description":"Maximum number of events to return (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"custom_events_only","in":"query","description":"Only return custom events, excluding system events like page_view, page_leave, heartbeat (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"aggregation_level","in":"query","description":"Aggregation level: events, sessions, or visitors (default: events)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved event counts","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EventCount"}}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/events/breakdown":{"get":{"tags":["Events"],"summary":"Get event type breakdown","operationId":"get_event_type_breakdown","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date for filtering events","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date for filtering events","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"aggregation_level","in":"query","description":"Aggregation level: events, sessions, or visitors (default: events)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved event type breakdown","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EventTypeBreakdown"}}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/events/ingest":{"post":{"tags":["Events"],"summary":"Record an analytics event via the console API with explicit project ID.","description":"The app backend forwards the user's encrypted Temps cookies, so visitor/session\nidentity is resolved automatically by middleware. No geolocation or user-agent\nenrichment is performed — this is a lightweight server-side ingestion path.","operationId":"record_console_event","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConsoleEventPayload"}}},"required":true},"responses":{"200":{"description":"Event recorded successfully"},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/events/properties/breakdown":{"get":{"tags":["Events"],"summary":"Get property breakdown by grouping events by a column","operationId":"get_property_breakdown","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in '%Y-%m-%d %H:%M:%S' format","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in '%Y-%m-%d %H:%M:%S' format","required":true,"schema":{"type":"string"}},{"name":"group_by","in":"query","description":"Column to group by (channel, device_type, browser, etc.)","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"event_name","in":"query","description":"Filter by event name","required":false,"schema":{"type":"string"}},{"name":"aggregation_level","in":"query","description":"Aggregation level: events, sessions, or visitors - default: events","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Maximum number of results (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"filter_country","in":"query","description":"Filter by country (for region/city drill-downs)","required":false,"schema":{"type":"string"}},{"name":"filter_region","in":"query","description":"Filter by region (for city drill-downs)","required":false,"schema":{"type":"string"}},{"name":"filter_browser","in":"query","description":"Filter by browser name (for version drill-downs)","required":false,"schema":{"type":"string"}},{"name":"filter_os","in":"query","description":"Filter by OS name (for version drill-downs)","required":false,"schema":{"type":"string"}},{"name":"filter_channel","in":"query","description":"Filter by channel name (for channel drill-downs)","required":false,"schema":{"type":"string"}},{"name":"filter_referrer","in":"query","description":"Filter by referrer hostname (for referrer drill-downs)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved property breakdown","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PropertyBreakdownResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/events/properties/timeline":{"get":{"tags":["Events"],"summary":"Get property timeline by grouping events by a column over time","operationId":"get_property_timeline","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in '%Y-%m-%d %H:%M:%S' format","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in '%Y-%m-%d %H:%M:%S' format","required":true,"schema":{"type":"string"}},{"name":"group_by","in":"query","description":"Column to group by (channel, device_type, browser, etc.)","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"event_name","in":"query","description":"Filter by event name","required":false,"schema":{"type":"string"}},{"name":"aggregation_level","in":"query","description":"Aggregation level: events, sessions, or visitors - default: events","required":false,"schema":{"type":"string"}},{"name":"bucket_size","in":"query","description":"Time bucket: hour, day, week, month (default: auto-detect)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved property timeline","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PropertyTimelineResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/events/timeline":{"get":{"tags":["Events"],"summary":"Get events timeline","operationId":"get_events_timeline","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date for filtering events","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date for filtering events","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"event_name","in":"query","description":"Filter by specific event name","required":false,"schema":{"type":"string"}},{"name":"bucket_size","in":"query","description":"Bucket size: hour, day, or week (auto-detected if not specified)","required":false,"schema":{"type":"string"}},{"name":"aggregation_level","in":"query","description":"Aggregation level: events, sessions, or visitors (default: events)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved events timeline","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EventTimeline"}}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/events/unique":{"get":{"tags":["Funnels"],"summary":"Get all unique/distinct event types for a project (paginated)","operationId":"get_unique_events","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page (default: 50, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Unique event types retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventTypesResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/external-images":{"get":{"tags":["External Images"],"summary":"List external images for a project","operationId":"list_remote_external_images","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page (default: 20)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List of external images","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedExternalImagesResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["External Images"],"summary":"Register an external Docker image","description":"Registers an external Docker image reference without triggering a deployment.\nThe image can be deployed later using the deploy/image endpoint.","operationId":"register_external_image","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterImageRequest"}}},"required":true},"responses":{"201":{"description":"Image registered successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalImageResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/external-images/{image_id}":{"get":{"tags":["External Images"],"summary":"Get details of a specific external image","operationId":"get_remote_external_image","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"image_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Image details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalImageResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Image not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["External Images"],"summary":"Delete an external image","operationId":"delete_external_image","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"image_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Image deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Image not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/flags":{"get":{"tags":["Feature Flags"],"operationId":"list_flags","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"include_archived","in":"query","description":"Include archived flags. Defaults to false.","required":false,"schema":{"type":"boolean"}},{"name":"page","in":"query","description":"1-indexed page number. Defaults to 1.","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page. Defaults to 20, capped at 100.","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}}],"responses":{"200":{"description":"Flags listed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Feature Flags"],"operationId":"create_flag","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFlagRequest"}}},"required":true},"responses":{"201":{"description":"Flag created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"409":{"description":"Flag key already exists"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/flags/{key}":{"get":{"tags":["Feature Flags"],"operationId":"get_flag","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"key","in":"path","description":"Flag key","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Flag retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Flag not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Feature Flags"],"operationId":"archive_flag","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"key","in":"path","description":"Flag key","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Flag archived","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArchiveFlagResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Flag not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Feature Flags"],"operationId":"update_flag","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"key","in":"path","description":"Flag key","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateFlagRequest"}}},"required":true},"responses":{"200":{"description":"Flag updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Flag not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/flags/{key}/environments/{environment_id}":{"put":{"tags":["Feature Flags"],"summary":"Set a flag's value in one environment, and/or flip its kill switch.","operationId":"set_flag_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"key","in":"path","description":"Flag key","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetFlagEnvironmentRequest"}}},"required":true},"responses":{"200":{"description":"Environment value set","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagEnvironmentResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Flag or environment not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/flags/{key}/restore":{"post":{"tags":["Feature Flags"],"summary":"Bring an archived flag back.","description":"Archiving is otherwise one-way: the key stays reserved so the flag cannot\neven be re-created under the same name, which makes an accidental archive\nunrecoverable through the API.","operationId":"restore_flag","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"key","in":"path","description":"Flag key","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Flag restored","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Flag not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/funnels":{"get":{"tags":["Funnels"],"summary":"List all funnels for a project","operationId":"list_funnels","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Funnels retrieved successfully","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/FunnelResponse"}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Funnels"],"summary":"Create a new funnel","operationId":"create_funnel","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFunnelRequest"}}},"required":true},"responses":{"201":{"description":"Funnel created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFunnelResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/funnels/preview":{"post":{"tags":["Funnels"],"summary":"Preview funnel metrics without creating the funnel","operationId":"preview_funnel_metrics","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFunnelRequest"}}},"required":true},"responses":{"200":{"description":"Funnel metrics preview","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FunnelMetricsResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/funnels/{funnel_id}":{"put":{"tags":["Funnels"],"summary":"Update a funnel","operationId":"update_funnel","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"funnel_id","in":"path","description":"Funnel ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFunnelRequest"}}},"required":true},"responses":{"200":{"description":"Funnel updated successfully"},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"404":{"description":"Funnel not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Funnels"],"summary":"Delete a funnel","operationId":"delete_funnel","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"funnel_id","in":"path","description":"Funnel ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Funnel deleted successfully"},"401":{"description":"Unauthorized"},"404":{"description":"Funnel not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/funnels/{funnel_id}/metrics":{"get":{"tags":["Funnels"],"summary":"Get funnel metrics","operationId":"get_funnel_metrics","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"funnel_id","in":"path","description":"Funnel ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID filter","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"country_code","in":"query","description":"Country code filter","required":false,"schema":{"type":"string"}},{"name":"start_date","in":"query","description":"Start date filter (ISO 8601)","required":false,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date filter (ISO 8601)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Funnel metrics retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FunnelMetricsResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"404":{"description":"Funnel not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/git":{"post":{"tags":["Projects"],"summary":"Update git settings for a project","operationId":"update_git_settings","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateGitSettingsRequest"}}},"required":true},"responses":{"200":{"description":"Git settings updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"400":{"description":"Invalid git configuration or branch does not exist"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/gitlab/reinstall-webhook":{"post":{"tags":["Projects"],"summary":"Reinstall the GitLab webhook for a project","description":"Removes the existing webhook (if any) and installs a fresh one.\nUse this when a webhook has been manually deleted on the GitLab side\nand automatic deployments have stopped working.","operationId":"reinstall_gitlab_webhook","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Webhook reinstalled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReinstallWebhookResponse"}}}},"400":{"description":"Project is not connected to a GitLab repository"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/has-error-groups":{"get":{"tags":["error-tracking"],"summary":"Check if project has any error groups","operationId":"has_error_groups","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Error groups existence check","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HasErrorGroupsResponse"}}}},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/has-events":{"get":{"tags":["Events"],"summary":"Check if project has any analytics events","operationId":"has_analytics_events","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully checked for events","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HasEventsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/hourly-visits":{"get":{"tags":["Events"],"summary":"Get hourly visits","operationId":"get_hourly_visits","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date for filtering visits","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date for filtering visits","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"aggregation_level","in":"query","description":"Aggregation level: events (page views), sessions (unique sessions), or visitors (unique visitors) - default: events","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved hourly visits","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EventTimeline"}}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/images":{"get":{"tags":["External Images"],"summary":"List all external images for a project","operationId":"list_external_images","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of external images","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PushedExternalImageResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/images/push":{"post":{"tags":["External Images"],"summary":"Push an external Docker image","operationId":"push_external_image","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PushImageRequest"}}},"required":true},"responses":{"201":{"description":"Image pushed successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PushedExternalImageResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/images/{image_id}":{"get":{"tags":["External Images"],"summary":"Get details of a specific external image","operationId":"get_external_image","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"image_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Image details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PushedExternalImageResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Image not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/incidents":{"get":{"tags":["Status Page"],"summary":"List incidents for a project","operationId":"list_incidents","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"status","in":"query","description":"Filter by status","required":false,"schema":{"type":"string"}},{"name":"page","in":"query","description":"Page number","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Successfully retrieved incidents"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Status Page"],"summary":"Create a new incident","operationId":"create_incident","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateIncidentRequest"}}},"required":true},"responses":{"201":{"description":"Incident created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncidentResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/incidents/bucketed":{"get":{"tags":["Status Page"],"summary":"Get bucketed incident data for a project","operationId":"get_bucketed_incidents","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"interval","in":"query","description":"Bucket interval: '5min', 'hourly', or 'daily' (default: hourly)","required":false,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601) (default: 7 days ago)","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (ISO 8601) (default: now)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved bucketed incident data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncidentBucketedResponse"}}}},"400":{"description":"Invalid parameters"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/logs":{"delete":{"tags":["Logs"],"summary":"Purge all logs for a project before a given timestamp","operationId":"purge_project_logs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PurgeLogsRequest"}}},"required":true},"responses":{"200":{"description":"Purge completed"},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/mcp-servers":{"get":{"tags":["Agents"],"operationId":"list_mcps","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListMcpsResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Agents"],"operationId":"create_mcp","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMcpRequest"}}},"required":true},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpDefinitionResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/mcp-servers/{slug}":{"get":{"tags":["Agents"],"operationId":"get_mcp","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"MCP server not found"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Agents"],"operationId":"update_mcp","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMcpRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"MCP server not found"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Agents"],"operationId":"delete_mcp","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"MCP server deleted"},"401":{"description":"Unauthorized"},"404":{"description":"MCP server not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/mcp-servers/{slug}/config/{field}":{"get":{"tags":["Agents"],"operationId":"reveal_mcp_config","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}},{"name":"field","in":"path","description":"Sensitive field path, such as url or env.API_TOKEN","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SensitiveMcpConfigValueResponse"}}}},"400":{"description":"Field is not revealable"},"401":{"description":"Unauthorized"},"403":{"description":"Missing secrets:read permission"},"404":{"description":"MCP server or field not found"},"500":{"description":"Configuration read or audit failed"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/monitors":{"get":{"tags":["Status Page"],"summary":"List monitors for a project","operationId":"list_monitors","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved monitors","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MonitorResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Status Page"],"summary":"Create a new monitor","operationId":"create_monitor","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMonitorRequest"}}},"required":true},"responses":{"201":{"description":"Monitor created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MonitorResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/observe/events":{"get":{"tags":["Observability"],"summary":"List a merged page of observability events for a project.","description":"Each row carries everything the side panel needs to render — no\nfollow-up fetch is required for the common case. Heavy fields\n(stacktraces, headers, span attributes) are truncated server-side and\nexpose a `*_truncated` flag; clients fetch the full row from the\n`/full` endpoint only when the user explicitly clicks \"Show full\".","operationId":"observability_list_events","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"kinds","in":"query","description":"Comma-separated kinds: `log,request,span,error,revenue`. Empty or\nmissing returns every kind.","required":false,"schema":{"type":"string"}},{"name":"from","in":"query","description":"Inclusive lower bound on event timestamp (ISO 8601, `Z` suffix).","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","description":"Inclusive upper bound on event timestamp.","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"deployment_id","in":"query","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"search","in":"query","description":"Free-text substring matched against per-kind summary fields\n(request path / error class / revenue event_type).","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Page size (default 50, max 200).","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"hide_bots","in":"query","description":"When `true`, exclude bot/crawler request rows. When `false`, only\ninclude bot rows. Omitted means \"include everything\" (default).\nOnly affects the `Request` kind.","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Merged event page","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventsResponse"}}}},"400":{"description":"Invalid filter (kinds, time range, …)","content":{"text/plain":{"schema":{"type":"string"}}}},"401":{"description":"Unauthorized","content":{"text/plain":{"schema":{"type":"string"}}}},"403":{"description":"Insufficient permissions","content":{"text/plain":{"schema":{"type":"string"}}}},"500":{"description":"Internal server error","content":{"text/plain":{"schema":{"type":"string"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/observe/events/{kind}/{event_id}/full":{"get":{"tags":["Observability"],"summary":"Fetch the un-truncated form of one event by `(kind, id)`. Side panel\n\"Show full\" action calls this — the list response carries truncated\npreviews + a `*_truncated` flag to let the UI decide whether to fetch.","operationId":"observability_full_event","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"kind","in":"path","description":"Event kind discriminator","required":true,"schema":{"$ref":"#/components/schemas/EventKind"}},{"name":"event_id","in":"path","description":"Per-kind identity: request_id for requests, `{trace_id}:{span_id}` for spans, serial id for errors/revenue","required":true,"schema":{"type":"string"}},{"name":"ts","in":"query","description":"The row's event timestamp as returned by the list endpoint. Optional,\nbut strongly recommended: it bounds the lookup to the storage\npartitions/chunks around that instant instead of scanning the whole\nretention window.","required":false,"schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"Full row","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FullEvent"}}}},"401":{"description":"Unauthorized","content":{"text/plain":{"schema":{"type":"string"}}}},"403":{"description":"Insufficient permissions","content":{"text/plain":{"schema":{"type":"string"}}}},"404":{"description":"Event not found in project","content":{"text/plain":{"schema":{"type":"string"}}}},"500":{"description":"Internal server error","content":{"text/plain":{"schema":{"type":"string"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/releases/{release}/source-files":{"get":{"tags":["source-maps"],"summary":"List uploaded source files for a release (metadata only).","operationId":"list_source_files","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"release","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of source files","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceFileListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["source-maps"],"summary":"Upload a raw source file for a release (native symbolication).","description":"Accepts a multipart form with:\n- `file`: the source file bytes (required)\n- `file_path`: the path of the file as it appears in stack frames (required;\n derived from the uploaded filename if omitted). Normalized with the `~`\n prefix convention, matching source-map storage.\n\nRequires the project's `error_source_context_enabled` toggle to be on.\nUpserts on (project, release, file_path).","operationId":"upload_source_file","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"release","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"201":{"description":"Source file uploaded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceFileResponse"}}}},"400":{"description":"Missing fields"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"409":{"description":"Source context disabled for project"},"413":{"description":"Source file too large"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["source-maps"],"summary":"Delete all uploaded source files for a release.","operationId":"delete_release_source_files","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"release","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Source files deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/releases/{release}/source-maps":{"get":{"tags":["source-maps"],"summary":"List all source maps for a specific release","operationId":"list_source_maps","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"release","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of source maps","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceMapListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["source-maps"],"summary":"Upload a source map for a release.","description":"Accepts a multipart form with:\n- `file`: The .map file (required)\n- `file_path`: The URL path of the minified file as it appears in stack traces (required).\n Uses the ~ prefix convention (e.g., \"~/assets/main.js\").\n If a full URL is provided, it will be normalized automatically.\n- `dist`: Optional distribution identifier\n\nIf a source map already exists for the same (project, release, file_path), it is replaced.","operationId":"upload_source_map","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"release","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"201":{"description":"Source map uploaded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceMapResponse"}}}},"400":{"description":"Invalid source map or missing fields"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"413":{"description":"Source map too large"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["source-maps"],"summary":"Delete all source maps for a specific release","operationId":"delete_release_source_maps","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"release","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Source maps deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/events":{"get":{"tags":["Revenue"],"summary":"Recent ingested events for the activity feed.","operationId":"revenue_recent_events","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RecentEventResponse"}}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/integrations":{"get":{"tags":["Revenue"],"summary":"List revenue integrations for a project.","operationId":"revenue_list_integrations","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/IntegrationResponse"}}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Revenue"],"summary":"Create a new revenue integration. Response contains the generated\nwebhook path that the user must paste into their provider's dashboard.","operationId":"revenue_create_integration","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateIntegrationBody"}}},"required":true},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntegrationResponse"}}}},"400":{"description":"Validation error"},"409":{"description":"Already connected"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/integrations/{integration_id}":{"delete":{"tags":["Revenue"],"summary":"Delete a revenue integration (permanent — use rotate_token to refresh\ncredentials without breaking history).","operationId":"revenue_delete_integration","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"integration_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/integrations/{integration_id}/config":{"post":{"tags":["Revenue"],"summary":"Replace the typed provider config on an integration. Passing `null`\nclears the config back to the accept-everything default. The config's\nprovider tag must match the integration's provider.","operationId":"revenue_update_config","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"integration_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateConfigBody"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntegrationResponse"}}}},"400":{"description":"Validation error"},"404":{"description":"Integration not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/integrations/{integration_id}/import/invoices":{"post":{"tags":["Revenue"],"summary":"Import a Stripe invoices CSV export. Each paid invoice becomes an\n`invoice.paid` event so historical MRR/charge totals populate the\ntimeseries. Ingestion is idempotent: re-uploading the same file is a\nno-op.","operationId":"revenue_import_invoices_csv","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"integration_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportOutcomeResponse"}}}},"400":{"description":"Malformed CSV or wrong provider"},"404":{"description":"Integration not found"},"413":{"description":"CSV too large"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/integrations/{integration_id}/import/subscriptions":{"post":{"tags":["Revenue"],"summary":"Import a Stripe subscriptions CSV export. Use this to backfill MRR /\nactive subscriptions when migrating from Stripe without providing\nAPI keys. Webhooks remain the source of truth for live updates —\nCSV rows never overwrite newer webhook state.","operationId":"revenue_import_subscriptions_csv","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"integration_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportOutcomeResponse"}}}},"400":{"description":"Malformed CSV or wrong provider"},"404":{"description":"Integration not found"},"413":{"description":"CSV too large"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/integrations/{integration_id}/rotate-token":{"post":{"tags":["Revenue"],"summary":"Rotate the webhook path token. Returns the new integration state —\nthe user must paste the new URL into their provider's dashboard.","operationId":"revenue_rotate_token","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"integration_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntegrationResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/integrations/{integration_id}/update-secret":{"post":{"tags":["Revenue"],"summary":"Replace the stored signing secret without rotating the webhook URL.\nUse this after rotating the secret in the provider's dashboard.","operationId":"revenue_update_secret","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"integration_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSecretBody"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntegrationResponse"}}}},"400":{"description":"Validation error"},"404":{"description":"Integration not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/metrics/customers":{"get":{"tags":["Revenue"],"summary":"New + churned customers per bucket.","operationId":"revenue_metrics_customers","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CustomerMovementResponse"}}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/metrics/mrr":{"get":{"tags":["Revenue"],"summary":"Bucketed MRR timeseries for the revenue chart.","operationId":"revenue_metrics_mrr","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MrrBucketResponse"}}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/metrics/summary":{"get":{"tags":["Revenue"],"summary":"Current MRR / ARR / churn / ARPU for a project, in one currency.","operationId":"revenue_metrics_summary","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MetricsSummaryResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/secrets":{"get":{"tags":["Secrets"],"summary":"List project secrets (metadata only — values never returned).","operationId":"listProjectSecrets","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Optional environment filter","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of secrets (metadata only, no values)","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProjectSecretResponse"}}}}},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}},"post":{"tags":["Secrets"],"summary":"Create a new secret. The value is encrypted before storage and will be\nmounted as a file at `/run/secrets/` on the next deployment.\nThe plaintext value is NOT returned — the response carries only metadata.","operationId":"createProjectSecret","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectSecretRequest"}}},"required":true},"responses":{"201":{"description":"Secret created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectSecretResponse"}}}},"400":{"description":"Invalid key or value too large"},"409":{"description":"Key already exists in project"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/secrets/{secret_id}":{"put":{"tags":["Secrets"],"summary":"Update a project secret. Value rotation requires a redeploy to take effect —\nrunning containers keep their currently-mounted values until the next\ndeployment.","operationId":"updateProjectSecret","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"secret_id","in":"path","description":"Secret ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProjectSecretRequest"}}},"required":true},"responses":{"200":{"description":"Secret updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectSecretResponse"}}}},"400":{"description":"Value too large"},"404":{"description":"Secret not found"},"500":{"description":"Internal server error"}}},"delete":{"tags":["Secrets"],"summary":"Delete a project secret. Running containers keep their mounted secret files\nuntil they are redeployed.","operationId":"deleteProjectSecret","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"secret_id","in":"path","description":"Secret ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Secret deleted"},"404":{"description":"Secret not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/settings":{"post":{"tags":["Projects"],"summary":"Update project settings","operationId":"update_project_settings","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProjectSettingsRequest"}}},"required":true},"responses":{"200":{"description":"Project settings updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/skills":{"get":{"tags":["Agents"],"operationId":"list_skills","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListSkillsResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Agents"],"operationId":"create_skill","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSkillRequest"}}},"required":true},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/skills/upload":{"post":{"tags":["Agents"],"summary":"Upload a skill with an archive (tar.gz) — project-scoped.","operationId":"upload_skill","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"type":"string"}}},"required":true},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/skills/{slug}":{"get":{"tags":["Agents"],"operationId":"get_skill","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Agents"],"operationId":"update_skill","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSkillRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Agents"],"operationId":"delete_skill","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Skill deleted"},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/skills/{slug}/archive":{"get":{"tags":["Agents"],"summary":"Download a skill's archive (tar.gz) — project-scoped.","operationId":"download_skill_archive","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Skill archive tar.gz","content":{"application/gzip":{}}},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found or has no archive"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/source-map-releases":{"get":{"tags":["source-maps"],"summary":"List all releases that have source maps for a project","operationId":"list_releases","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of releases","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReleaseListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/source-maps/{source_map_id}":{"delete":{"tags":["source-maps"],"summary":"Delete a specific source map by ID","operationId":"delete_source_map","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"source_map_id","in":"path","description":"Source map ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Source map deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Source map not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/static-bundles":{"get":{"tags":["Static Bundles"],"summary":"List static bundles for a project","operationId":"list_static_bundles","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page (default: 20)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List of static bundles","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedStaticBundlesResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/static-bundles/{bundle_id}":{"get":{"tags":["Static Bundles"],"summary":"Get details of a specific static bundle","operationId":"get_static_bundle","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"bundle_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Bundle details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StaticBundleResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Bundle not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Static Bundles"],"summary":"Delete a static bundle","operationId":"delete_static_bundle","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"bundle_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Bundle deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Bundle not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/status":{"get":{"tags":["Status Page"],"summary":"Get status page overview","operationId":"get_status_overview","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved status overview","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatusPageOverview"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/unique-counts":{"get":{"tags":["Events"],"summary":"Get unique counts over time frame","operationId":"get_unique_counts","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in '%Y-%m-%d %H:%M:%S' format","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in '%Y-%m-%d %H:%M:%S' format","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"metric","in":"query","description":"Metric to count: 'sessions' (unique sessions), 'visitors' (unique visitors), 'returning_visitors' (visitors seen before the range), or 'page_views' (total page views) (default: 'sessions')","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved count","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UniqueCountsResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/upload/static":{"post":{"tags":["Static Bundles"],"summary":"Upload a static bundle for later deployment","description":"Uploads a tar.gz or zip file containing static assets. The bundle can be\ndeployed later using the deploy/static endpoint.","operationId":"upload_static_bundle","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"201":{"description":"Bundle uploaded successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StaticBundleResponse"}}}},"400":{"description":"Invalid request or unsupported format"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project not found"},"413":{"description":"Bundle too large"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/vulnerability-scans":{"get":{"tags":["Vulnerability Scans"],"operationId":"list_project_scans","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List of vulnerability scans","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ScanResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Vulnerability Scans"],"operationId":"trigger_scan","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerScanRequest"}}},"required":true},"responses":{"202":{"description":"Scan triggered successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerScanResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/vulnerability-scans/environments":{"get":{"tags":["Vulnerability Scans"],"operationId":"get_latest_scans_per_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Latest scans per environment for current deployments","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ScanResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/vulnerability-scans/latest":{"get":{"tags":["Vulnerability Scans"],"operationId":"get_latest_scan","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Latest scan for project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScanResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"No scans found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/webhooks":{"get":{"tags":["Webhooks"],"summary":"List all webhooks for a project","operationId":"list_webhooks","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20},{"name":"sort_by","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"List of webhooks","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/WebhookResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Webhooks"],"summary":"Create a new webhook","operationId":"create_webhook","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWebhookRequestBody"}}},"required":true},"responses":{"201":{"description":"Webhook created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/webhooks/{webhook_id}":{"get":{"tags":["Webhooks"],"summary":"Get a specific webhook","operationId":"get_webhook","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"webhook_id","in":"path","description":"Webhook ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Webhook details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Webhook not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Webhooks"],"summary":"Update a webhook","operationId":"update_webhook","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"webhook_id","in":"path","description":"Webhook ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWebhookRequestBody"}}},"required":true},"responses":{"200":{"description":"Webhook updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Webhook not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Webhooks"],"summary":"Delete a webhook","operationId":"delete_webhook","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"webhook_id","in":"path","description":"Webhook ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Webhook deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Webhook not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/webhooks/{webhook_id}/deliveries":{"get":{"tags":["Webhook Deliveries"],"summary":"List webhook deliveries","operationId":"list_deliveries","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"webhook_id","in":"path","description":"Webhook ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"limit","in":"query","description":"Number of deliveries to return (default: 50)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List of deliveries","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/WebhookDeliveryResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/webhooks/{webhook_id}/deliveries/{delivery_id}":{"get":{"tags":["Webhook Deliveries"],"summary":"Get a specific webhook delivery by ID","operationId":"get_delivery","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"webhook_id","in":"path","description":"Webhook ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"delivery_id","in":"path","description":"Delivery ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Delivery details including full payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDeliveryResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Delivery not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/webhooks/{webhook_id}/deliveries/{delivery_id}/retry":{"post":{"tags":["Webhook Deliveries"],"summary":"Retry a failed delivery","operationId":"retry_delivery","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"webhook_id","in":"path","description":"Webhook ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"delivery_id","in":"path","description":"Delivery ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Delivery retried","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDeliveryResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Delivery not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/workflows/dry-run":{"post":{"tags":["Workflows"],"operationId":"workflow_dry_run","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkflowDryRunRequest"}}},"required":true},"responses":{"202":{"description":"Ephemeral run created and queued","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRunResponse"}}}},"400":{"description":"Validation error (bad YAML, oversized payload, capped limits exceeded)"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/proxy-logs":{"get":{"tags":["Proxy Logs"],"summary":"Get proxy logs with optional filters and pagination","operationId":"get_proxy_logs","parameters":[{"name":"project_id","in":"query","description":"Filter by project ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"session_id","in":"query","description":"Filter by session ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"visitor_id","in":"query","description":"Filter by visitor ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"start_date","in":"query","description":"Start date for filtering (ISO 8601 format).\n\n**Defaults to 1 hour before `end_date` (or before now) when omitted.**\nThe listing is always time-bounded: an unbounded query would have to\nconsider the entire retention window — 100M+ rows on a busy deployment —\nto return a single page. Pass an explicit `start_date` to widen the\nwindow, up to the configured retention horizon.\n\nThe maximum span between `start_date` and `end_date` is 7 days when\n`project_id` is omitted, or 30 days when a single `project_id` is set —\na project-scoped query is bounded by that project's own row count\nrather than the whole deployment's. A wider request is rejected with a\n400 naming the applicable cap.","required":false,"schema":{"type":["string","null"],"format":"date-time"}},{"name":"end_date","in":"query","description":"End date for filtering (ISO 8601 format). Defaults to now.","required":false,"schema":{"type":["string","null"],"format":"date-time"}},{"name":"method","in":"query","description":"Filter by HTTP method (GET, POST, etc.)","required":false,"schema":{"type":["string","null"]}},{"name":"host","in":"query","description":"Filter by host header","required":false,"schema":{"type":["string","null"]}},{"name":"path","in":"query","description":"Filter by path (supports partial match)","required":false,"schema":{"type":["string","null"]}},{"name":"client_ip","in":"query","description":"Filter by client IP address","required":false,"schema":{"type":["string","null"]}},{"name":"status_code","in":"query","description":"Filter by HTTP status code","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"response_time_min","in":"query","description":"Filter by minimum response time in ms","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"response_time_max","in":"query","description":"Filter by maximum response time in ms","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"routing_status","in":"query","description":"Filter by routing status (routed, no_project, error, pending)","required":false,"schema":{"type":["string","null"]}},{"name":"request_source","in":"query","description":"Filter by request source (proxy, api, console, cli)","required":false,"schema":{"type":["string","null"]}},{"name":"is_system_request","in":"query","description":"Filter by system request flag","required":false,"schema":{"type":["boolean","null"]}},{"name":"user_agent","in":"query","description":"Filter by user agent string (partial match)","required":false,"schema":{"type":["string","null"]}},{"name":"browser","in":"query","description":"Filter by browser name","required":false,"schema":{"type":["string","null"]}},{"name":"operating_system","in":"query","description":"Filter by operating system","required":false,"schema":{"type":["string","null"]}},{"name":"device_type","in":"query","description":"Filter by device type (mobile, desktop, tablet)","required":false,"schema":{"type":["string","null"]}},{"name":"is_bot","in":"query","description":"Filter by bot detection","required":false,"schema":{"type":["boolean","null"]}},{"name":"exclude_bots","in":"query","description":"When `true`, exclude rows flagged as bots while KEEPING rows whose\n`is_bot` is NULL (older rows without detection metadata). This is the\ntri-state complement of `is_bot=false`, which matches only rows\nexplicitly detected as non-bots. `false`/omitted is a no-op.","required":false,"schema":{"type":["boolean","null"]}},{"name":"bot_name","in":"query","description":"Filter by bot name","required":false,"schema":{"type":["string","null"]}},{"name":"ai_provider","in":"query","description":"Filter by AI provider (e.g. `OpenAI`, `Anthropic`, `Perplexity`). Matches\nthe canonical provider returned by the AI agent detector.","required":false,"schema":{"type":["string","null"]}},{"name":"ai_agent","in":"query","description":"Filter by AI agent name (e.g. `GPTBot`, `ChatGPT-User`). Equivalent to\nfiltering `bot_name` against a known AI taxonomy.","required":false,"schema":{"type":["string","null"]}},{"name":"is_ai_agent","in":"query","description":"When `true`, only return requests classified as known AI agents\n(regardless of provider/agent). Mutually compatible with the above.","required":false,"schema":{"type":["boolean","null"]}},{"name":"request_size_min","in":"query","description":"Filter by minimum request size in bytes","required":false,"schema":{"type":["integer","null"],"format":"int64"}},{"name":"request_size_max","in":"query","description":"Filter by maximum request size in bytes","required":false,"schema":{"type":["integer","null"],"format":"int64"}},{"name":"response_size_min","in":"query","description":"Filter by minimum response size in bytes","required":false,"schema":{"type":["integer","null"],"format":"int64"}},{"name":"response_size_max","in":"query","description":"Filter by maximum response size in bytes","required":false,"schema":{"type":["integer","null"],"format":"int64"}},{"name":"cache_status","in":"query","description":"Filter by cache status","required":false,"schema":{"type":["string","null"]}},{"name":"container_id","in":"query","description":"Filter by container ID","required":false,"schema":{"type":["string","null"]}},{"name":"upstream_host","in":"query","description":"Filter by upstream host","required":false,"schema":{"type":["string","null"]}},{"name":"has_error","in":"query","description":"Filter by presence of error message","required":false,"schema":{"type":["boolean","null"]}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (default: 20, max: 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"sort_by","in":"query","description":"Sort by field (default: timestamp)","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","description":"Sort order (asc or desc, default: desc)","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"List of proxy logs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProxyLogsPaginatedResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/ai-agents/known":{"get":{"tags":["Proxy Logs"],"summary":"List every AI agent the detector knows how to classify.","description":"Returned in the same order as the internal taxonomy so the UI can use it as\na stable dropdown.","operationId":"list_known_ai_agents","responses":{"200":{"description":"Known AI agents","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KnownAiAgentsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/request/{request_id}":{"get":{"tags":["Proxy Logs"],"summary":"Get a proxy log by request ID (for tracing)","operationId":"get_proxy_log_by_request_id","parameters":[{"name":"request_id","in":"path","description":"Request ID from pingora","required":true,"schema":{"type":"string"}},{"name":"timestamp","in":"query","description":"Event time of the log row (ISO 8601). When provided, the lookup is\nbounded to the hypertable chunks around this instant instead of\nscanning (and decompressing) the whole retention window. The list\nendpoint already returns this value per row — always pass it when\nnavigating from a list.","required":false,"schema":{"type":["string","null"],"format":"date-time"}}],"responses":{"200":{"description":"Proxy log found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProxyLogResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Proxy log not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/ai-agent-pages":{"get":{"tags":["Proxy Logs"],"summary":"Get the top pages accessed by a specific AI agent over a time window.","description":"Returns page paths ranked by request count, scoped to a single canonical\nagent name (e.g. `ChatGPT-User`). Use `GET /proxy-logs/ai-agents/known` to\nlist all valid agent names. Unknown agent names return an empty items array.","operationId":"get_ai_agent_pages","parameters":[{"name":"agent","in":"query","description":"Canonical agent name to filter by (e.g. `ChatGPT-User`, `ClaudeBot`).\nMust be a name returned by `GET /proxy-logs/ai-agents/known`.","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Filter by project ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601). Defaults to `end_time - 7d`.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-22T00:00:00Z"},{"name":"end_time","in":"query","description":"End time (ISO 8601). Defaults to now.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-29T00:00:00Z"},{"name":"limit","in":"query","description":"Maximum rows to return. Capped at 100 server-side.","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}}],"responses":{"200":{"description":"Pages breakdown for the requested agent","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiAgentPagesResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/ai-agents":{"get":{"tags":["Proxy Logs"],"summary":"Get the per-AI-agent breakdown for a project over a time window.","operationId":"get_ai_agent_breakdown","parameters":[{"name":"project_id","in":"query","description":"Filter by project ID (recommended for per-project analytics).","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601). Defaults to `end_time - 7d`.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-22T00:00:00Z"},{"name":"end_time","in":"query","description":"End time (ISO 8601). Defaults to now.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-29T00:00:00Z"},{"name":"limit","in":"query","description":"Maximum rows to return. Capped at 100 server-side.","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"path","in":"query","description":"Optional exact path filter. Only used by the AI pages breakdown — when\nset, returns the single matching page so callers can ask \"how many AI\nagents hit this page?\".","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"AI agent breakdown","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiAgentBreakdownResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/ai-agents/timeline":{"get":{"tags":["Proxy Logs"],"summary":"Time-bucketed AI-agent request volume, split by provider or agent.","description":"Powers the \"AI agents over time\" stacked chart. Same data source as the AI\nagent breakdown (request logs), just bucketed.","operationId":"get_ai_agent_timeline","parameters":[{"name":"project_id","in":"query","description":"Filter by project ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601). Defaults to `end_time - 7d`.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-22T00:00:00Z"},{"name":"end_time","in":"query","description":"End time (ISO 8601). Defaults to now.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-29T00:00:00Z"},{"name":"group_by","in":"query","description":"Grouping dimension: `provider` (default) or `agent`.","required":false,"schema":{"type":["string","null"]},"example":"provider"},{"name":"bucket","in":"query","description":"Bucket interval override (e.g. `1 hour`, `1 day`). Auto-selected from the\nwindow width when omitted.","required":false,"schema":{"type":["string","null"]},"example":"1 hour"}],"responses":{"200":{"description":"AI agent timeline","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiAgentTimelineResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/ai-pages":{"get":{"tags":["Proxy Logs"],"summary":"Get the top pages crawled by AI agents over a time window.","operationId":"get_ai_page_breakdown","parameters":[{"name":"project_id","in":"query","description":"Filter by project ID (recommended for per-project analytics).","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601). Defaults to `end_time - 7d`.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-22T00:00:00Z"},{"name":"end_time","in":"query","description":"End time (ISO 8601). Defaults to now.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-29T00:00:00Z"},{"name":"limit","in":"query","description":"Maximum rows to return. Capped at 100 server-side.","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"path","in":"query","description":"Optional exact path filter. Only used by the AI pages breakdown — when\nset, returns the single matching page so callers can ask \"how many AI\nagents hit this page?\".","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"AI page breakdown","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiPageBreakdownResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/ai-status":{"get":{"tags":["Proxy Logs"],"summary":"HTTP status-class breakdown for AI-agent traffic — are bots being served\n(2xx) or hitting broken/blocked pages (4xx/5xx)?","operationId":"get_ai_status_breakdown","parameters":[{"name":"project_id","in":"query","description":"Filter by project ID (recommended for per-project analytics).","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601). Defaults to `end_time - 7d`.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-22T00:00:00Z"},{"name":"end_time","in":"query","description":"End time (ISO 8601). Defaults to now.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-29T00:00:00Z"},{"name":"limit","in":"query","description":"Maximum rows to return. Capped at 100 server-side.","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"path","in":"query","description":"Optional exact path filter. Only used by the AI pages breakdown — when\nset, returns the single matching page so callers can ask \"how many AI\nagents hit this page?\".","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"AI status breakdown","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiStatusBreakdownResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/projects-health":{"get":{"tags":["Proxy Logs"],"summary":"Get health summaries for multiple projects (last 1 hour)","operationId":"get_projects_health","parameters":[{"name":"project_ids","in":"query","description":"Comma-separated list of project IDs","required":true,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Optional start time (ISO 8601). Defaults to `end_time - 1h`.","required":false,"schema":{"type":["string","null"]},"example":"2025-10-23T00:00:00Z"},{"name":"end_time","in":"query","description":"Optional end time (ISO 8601). Defaults to now.","required":false,"schema":{"type":["string","null"]},"example":"2025-10-23T23:59:59Z"},{"name":"is_bot","in":"query","description":"Filter by bot detection. Pass `false` to exclude bots, `true` for bots only.","required":false,"schema":{"type":["boolean","null"]}}],"responses":{"200":{"description":"Health summaries per project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectsHealthResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/time-buckets":{"get":{"tags":["Proxy Logs"],"summary":"Get time-bucketed statistics with optional filters","operationId":"get_time_bucket_stats","parameters":[{"name":"start_time","in":"query","description":"Start time (ISO 8601 format)","required":true,"schema":{"type":"string"},"example":"2025-10-23T00:00:00Z"},{"name":"end_time","in":"query","description":"End time (ISO 8601 format)","required":true,"schema":{"type":"string"},"example":"2025-10-23T23:59:59Z"},{"name":"bucket_interval","in":"query","description":"Bucket interval (e.g., \"1 hour\", \"1 day\", \"5 minutes\")","required":false,"schema":{"type":"string"}},{"name":"method","in":"query","description":"Filter by HTTP method","required":false,"schema":{"type":"string"}},{"name":"client_ip","in":"query","description":"Filter by client IP","required":false,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Filter by project ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"host","in":"query","description":"Filter by host","required":false,"schema":{"type":"string"}},{"name":"status_code","in":"query","description":"Filter by status code","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"status_code_class","in":"query","description":"Filter by status code class (e.g. \"2xx\", \"3xx\", \"4xx\", \"5xx\")","required":false,"schema":{"type":"string"}},{"name":"routing_status","in":"query","description":"Filter by routing status","required":false,"schema":{"type":"string"}},{"name":"request_source","in":"query","description":"Filter by request source","required":false,"schema":{"type":"string"}},{"name":"is_bot","in":"query","description":"Filter by bot detection","required":false,"schema":{"type":"boolean"}},{"name":"device_type","in":"query","description":"Filter by device type","required":false,"schema":{"type":"string"}},{"name":"has_project","in":"query","description":"When true, only count requests that matched a project\n(project_id IS NOT NULL). Makes chart totals line up with the\nper-project health cards.","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Time-bucketed statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TimeBucketStatsResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/today":{"get":{"tags":["Proxy Logs"],"summary":"Get today's request count with optional filters","operationId":"get_today_stats","parameters":[{"name":"method","in":"query","description":"Filter by HTTP method","required":false,"schema":{"type":["string","null"]}},{"name":"client_ip","in":"query","description":"Filter by client IP","required":false,"schema":{"type":["string","null"]}},{"name":"project_id","in":"query","description":"Filter by project ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"host","in":"query","description":"Filter by host","required":false,"schema":{"type":["string","null"]}},{"name":"status_code","in":"query","description":"Filter by status code","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"status_code_class","in":"query","description":"Filter by status code class (e.g. \"2xx\", \"3xx\", \"4xx\", \"5xx\")","required":false,"schema":{"type":["string","null"]}},{"name":"routing_status","in":"query","description":"Filter by routing status","required":false,"schema":{"type":["string","null"]}},{"name":"request_source","in":"query","description":"Filter by request source","required":false,"schema":{"type":["string","null"]}},{"name":"is_bot","in":"query","description":"Filter by bot detection","required":false,"schema":{"type":["boolean","null"]}},{"name":"device_type","in":"query","description":"Filter by device type","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"Today's request count","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TodayStatsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/{id}":{"get":{"tags":["Proxy Logs"],"summary":"Get a single proxy log by ID","operationId":"get_proxy_log_by_id","parameters":[{"name":"id","in":"path","description":"Proxy log ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"timestamp","in":"query","description":"Event time of the log row (ISO 8601). When provided, the lookup is\nbounded to the hypertable chunks around this instant instead of\nscanning (and decompressing) the whole retention window. The list\nendpoint already returns this value per row — always pass it when\nnavigating from a list.","required":false,"schema":{"type":["string","null"],"format":"date-time"}}],"responses":{"200":{"description":"Proxy log found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProxyLogResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Proxy log not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/repositories":{"get":{"tags":["Git Providers"],"summary":"List synced repositories with advanced filtering","description":"Lists repositories that have been synced to the database with filtering options.\nThis provides fast access to repository metadata with filtering by connection, search, and other criteria.","operationId":"list_synced_repositories","parameters":[{"name":"page","in":"query","description":"Page number for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"sort","in":"query","description":"Sort field (name, created_at, updated_at, stars, watchers, size, issues)","required":false,"schema":{"type":"string"}},{"name":"direction","in":"query","description":"Sort direction (asc, desc)","required":false,"schema":{"type":"string"}},{"name":"search","in":"query","description":"Search term to filter repositories","required":false,"schema":{"type":"string"}},{"name":"owner","in":"query","description":"Filter by repository owner","required":false,"schema":{"type":"string"}},{"name":"language","in":"query","description":"Filter by programming language","required":false,"schema":{"type":"string"}},{"name":"private","in":"query","description":"Filter by private status (true/false)","required":false,"schema":{"type":"boolean"}},{"name":"git_provider_connection_id","in":"query","description":"Filter by git provider connection ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of synced repositories","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositoryListResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repositories/{owner}/{name}":{"get":{"tags":["Git Providers"],"summary":"Get repository by owner and name from any connection","operationId":"get_repository_by_name","parameters":[{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}},{"name":"connection_id","in":"query","description":"Optional specific connection ID to search","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Repository found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositoryResponse"}}}},"404":{"description":"Repository not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repositories/{owner}/{name}/all":{"get":{"tags":["Git Providers"],"summary":"Get all repositories with same owner/name from all git providers","operationId":"get_all_repositories_by_name","parameters":[{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Repositories found from all providers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RepositoryResponse"}}}}},"404":{"description":"No repositories found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repositories/{owner}/{name}/preset":{"get":{"tags":["Git Providers"],"summary":"Get repository preset by owner and name","operationId":"get_repository_preset_by_name","parameters":[{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}},{"name":"branch","in":"query","description":"Git branch to check (defaults to repository's default branch)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Repository preset calculated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositoryPresetResponse"}}}},"404":{"description":"Repository not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repositories/{owner}/{repo}/branches":{"get":{"tags":["Repositories"],"summary":"Get repository branches","operationId":"get_repository_branches","parameters":[{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"repo","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}},{"name":"connection_id","in":"query","description":"Git provider connection ID (required when multiple connections have the same repo)","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"fresh","in":"query","description":"Force fetch fresh data, bypassing cache (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of branches","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BranchListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Repository not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repositories/{owner}/{repo}/tags":{"get":{"tags":["Repositories"],"summary":"Get repository tags","operationId":"get_repository_tags","parameters":[{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"repo","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}},{"name":"connection_id","in":"query","description":"Git provider connection ID (required when multiple connections have the same repo)","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"fresh","in":"query","description":"Force fetch fresh data, bypassing cache (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of tags","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TagListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Repository not found"},"429":{"description":"Fresh tag lookup rate limit exceeded"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repositories/{repository_id}/preset/live":{"get":{"tags":["Git Providers"],"operationId":"get_repository_preset_live","parameters":[{"name":"repository_id","in":"path","description":"Repository ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"branch","in":"query","description":"Git branch to check (defaults to repository's default branch)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Repository presets calculated successfully - includes root preset and projects in subdirectories","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositoryPresetResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"The git provider rejected the stored credential - the connection must be re-authorized"},"404":{"description":"Repository not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repository/{repository_id}":{"get":{"tags":["Git Providers"],"summary":"Get repository by ID","operationId":"get_repository_by_id","parameters":[{"name":"repository_id","in":"path","description":"Repository ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Repository found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositoryResponse"}}}},"404":{"description":"Repository not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repository/{repository_id}/branches":{"get":{"tags":["Repositories"],"summary":"Get repository branches by repository ID","operationId":"get_branches_by_repository_id","parameters":[{"name":"repository_id","in":"path","description":"Repository ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"fresh","in":"query","description":"Force fetch fresh data, bypassing cache (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of branches","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BranchListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Repository not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repository/{repository_id}/commits":{"get":{"tags":["Repositories"],"summary":"List recent commits for a repository branch","operationId":"list_commits_by_repository_id","parameters":[{"name":"repository_id","in":"path","description":"Repository ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"branch","in":"query","description":"Branch name to list commits for","required":true,"schema":{"type":"string"}},{"name":"per_page","in":"query","description":"Number of commits to return (default: 20, max: 100)","required":false,"schema":{"type":["integer","null"],"format":"int32","minimum":0}}],"responses":{"200":{"description":"List of commits","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommitListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Repository not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repository/{repository_id}/commits/{commit_sha}":{"get":{"tags":["Repositories"],"summary":"Check if a commit exists in a repository","operationId":"check_commit_exists","parameters":[{"name":"repository_id","in":"path","description":"Repository ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"commit_sha","in":"path","description":"Commit SHA to check","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Commit existence check result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommitExistsResponse"}}}},"400":{"description":"Invalid commit SHA"},"401":{"description":"Unauthorized"},"404":{"description":"Repository not found"},"429":{"description":"Commit lookup rate limit exceeded"},"500":{"description":"Internal server error"},"502":{"description":"Git provider request failed"}},"security":[{"bearer_auth":[]}]}},"/repository/{repository_id}/tags":{"get":{"tags":["Repositories"],"summary":"Get repository tags by repository ID","operationId":"get_tags_by_repository_id","parameters":[{"name":"repository_id","in":"path","description":"Repository ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"fresh","in":"query","description":"Force fetch fresh data, bypassing cache (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of tags","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TagListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Repository not found"},"429":{"description":"Fresh tag lookup rate limit exceeded"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/restore-runs/{id}":{"get":{"tags":["Restore"],"operationId":"get_restore_run","parameters":[{"name":"id","in":"path","description":"Restore run id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Restore run progress","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RestoreRunView"}}}},"404":{"description":"Restore run not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/revenue/events":{"get":{"tags":["Revenue"],"summary":"Org-wide revenue events across every project. Powers the revenue\ntransactions page. Supports filtering by project, date range, and\nevent type.","operationId":"revenue_global_events","parameters":[{"name":"project_id","in":"query","description":"Filter to a single project","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"from","in":"query","description":"Lower bound (inclusive), ISO-8601","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","description":"Upper bound (inclusive), ISO-8601","required":false,"schema":{"type":"string"}},{"name":"event_types","in":"query","description":"Comma-separated event types (e.g. `invoice.paid,charge.succeeded`)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max rows, default 100, max 500","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GlobalRecentEventResponse"}}}}}},"security":[{"bearer_auth":[]}]}},"/revenue/metrics/global-mrr":{"get":{"tags":["Revenue"],"summary":"Org-wide MRR total, summed across every project in the install.\nPowers the single-number MRR card on the main dashboard.","operationId":"revenue_metrics_global_mrr","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GlobalMrrResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/revenue/metrics/global-summary":{"get":{"tags":["Revenue"],"summary":"Org-wide revenue summary: MRR, paid cash (30d + all-time), refunds,\nactive subscriptions/customers, and transaction count. Powers the\nheader on the Revenue transactions page.","operationId":"revenue_metrics_global_summary","parameters":[{"name":"currency","in":"query","description":"ISO-4217 currency code, default USD","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GlobalRevenueSummaryResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/revenue/providers":{"get":{"tags":["Revenue"],"summary":"List registered providers (what the UI needs to render the \"Connect\"\ndropdown + its wizard instructions).","operationId":"revenue_list_providers","responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProviderDescriptor"}}}}}},"security":[{"bearer_auth":[]}]}},"/session-replays":{"get":{"tags":["Analytics"],"summary":"Get session replays for a project","operationId":"get_project_session_replays","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-based)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Items per page","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Session replays retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetProjectSessionReplaysResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/sessions/{session_id}/events":{"get":{"tags":["Events"],"summary":"Get events for a specific session","operationId":"get_session_events","parameters":[{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved session events","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalyticsSessionEventsResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Session not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings":{"get":{"tags":["Settings"],"summary":"Get application settings","operationId":"get_settings","responses":{"200":{"description":"Application settings with masked sensitive fields","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppSettingsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Settings"],"summary":"Update application settings","operationId":"update_settings","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppSettings"}}},"required":true},"responses":{"200":{"description":"Settings updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SettingsUpdateResponse"}}}},"400":{"description":"Bad request - invalid settings"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/agent-token":{"post":{"tags":["Agents"],"summary":"Save an encrypted AI provider token for use in sandbox containers.","operationId":"save_agent_token","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveAgentTokenRequest"}}},"required":true},"responses":{"200":{"description":"Token encrypted and persisted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveAgentTokenResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Encryption or database error"}},"security":[{"bearer_auth":[]}]}},"/settings/ai-providers":{"get":{"tags":["Agents"],"summary":"List the AI provider catalog. Includes per-provider \"is a credential\nconfigured?\" so the settings UI can render configured/not-configured\nbadges without leaking the encrypted credential.","operationId":"list_ai_providers","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderCatalogResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/settings/ai-providers/{provider_id}":{"patch":{"tags":["Agents"],"summary":"Update provider-scoped settings without touching the saved credential.\nToday that means just `default_model`; future per-provider settings\n(base URL overrides, request headers, etc.) can land here too without\nchanging the shape of `save_credential`.","operationId":"update_ai_provider","parameters":[{"name":"provider_id","in":"path","description":"AI provider ID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAiProviderRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAiProviderResponse"}}}},"400":{"description":"Unknown provider"},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/settings/ai-providers/{provider_id}/activate":{"post":{"tags":["Agents"],"summary":"Activate a provider as the platform-wide default. Refuses to activate a\nprovider that doesn't have a credential saved yet — the UI enforces the\nsame rule on the button, but we re-check server-side so a stale tab\ncan't bypass it.","operationId":"activate_ai_provider","parameters":[{"name":"provider_id","in":"path","description":"AI provider ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivateProviderResponse"}}}},"400":{"description":"Provider not configured"},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/settings/ai-providers/{provider_id}/credential":{"post":{"tags":["Agents"],"summary":"Save (or replace) a provider's credential. The credential is encrypted\nwith `EncryptionService` and stored inside\n`agent_sandbox.providers[provider_id].credentials_encrypted`.","description":"The plaintext shape depends on the flavor's `credential_format`:\n - `ApiKey` / `OauthToken`: the key/token string.\n - `ConfigFile`: the full file body (e.g. OpenCode's `auth.json`).","operationId":"save_ai_provider_credential","parameters":[{"name":"provider_id","in":"path","description":"AI provider ID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveCredentialRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveCredentialResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/settings/disk-status":{"get":{"tags":["Settings"],"summary":"Get current disk usage for the control-plane server","description":"Returns live disk usage for the monitored path along with any disks that\nmeet or exceed the configured alert threshold. Read-only — does not send\nnotifications. Used by the dashboard to surface a low-disk-space warning.","operationId":"get_disk_status","responses":{"200":{"description":"Current disk usage and threshold alerts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiskSpaceCheckResult"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/enrollment-tokens":{"get":{"tags":["Settings"],"summary":"List currently-valid node enrollment tokens (hashes elided).","operationId":"list_enrollment_tokens","responses":{"200":{"description":"Active enrollment tokens","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnrollmentTokenListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Settings"],"summary":"Mint a short-lived, single-use node enrollment token.","operationId":"mint_enrollment_token","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MintEnrollmentTokenRequest"}}},"required":true},"responses":{"200":{"description":"Enrollment token minted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MintEnrollmentTokenResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/enrollment-tokens/{id}":{"delete":{"tags":["Settings"],"summary":"Revoke a node enrollment token by id.","operationId":"revoke_enrollment_token","parameters":[{"name":"id","in":"path","description":"Enrollment token id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Enrollment token revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SettingsUpdateResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Enrollment token not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/join-token":{"delete":{"tags":["Settings"],"summary":"Revoke the current join token","description":"Removes the stored join token hash, allowing any node to register\n(if no other authentication is in place).","operationId":"revoke_join_token","responses":{"200":{"description":"Join token revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SettingsUpdateResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/join-token/generate":{"post":{"tags":["Settings"],"summary":"Generate a new join token for multi-node cluster registration","description":"Creates a random 32-byte hex token, stores the SHA-256 hash in settings,\nand returns the plaintext exactly once. If a token already exists, it is replaced.","operationId":"generate_join_token","responses":{"200":{"description":"Join token generated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateJoinTokenResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/join-token/status":{"get":{"tags":["Settings"],"summary":"Check whether a join token is currently configured","operationId":"get_join_token_status","responses":{"200":{"description":"Join token status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JoinTokenStatusResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/mcp-servers":{"get":{"tags":["Agents"],"operationId":"list_global_mcps","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListMcpsResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Agents"],"operationId":"create_global_mcp","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMcpRequest"}}},"required":true},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpDefinitionResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/settings/mcp-servers/{slug}":{"get":{"tags":["Agents"],"operationId":"get_global_mcp","parameters":[{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"MCP server not found"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Agents"],"operationId":"update_global_mcp","parameters":[{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMcpRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"MCP server not found"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Agents"],"operationId":"delete_global_mcp","parameters":[{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"MCP server deleted"},"401":{"description":"Unauthorized"},"404":{"description":"MCP server not found"}},"security":[{"bearer_auth":[]}]}},"/settings/mcp-servers/{slug}/config/{field}":{"get":{"tags":["Agents"],"operationId":"reveal_global_mcp_config","parameters":[{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}},{"name":"field","in":"path","description":"Sensitive field path, such as url or env.API_TOKEN","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SensitiveMcpConfigValueResponse"}}}},"400":{"description":"Field is not revealable"},"401":{"description":"Unauthorized"},"403":{"description":"Missing secrets:read permission"},"404":{"description":"MCP server or field not found"},"500":{"description":"Configuration read or audit failed"}},"security":[{"bearer_auth":[]}]}},"/settings/routes/refresh":{"post":{"tags":["Settings"],"summary":"Manually refresh the proxy route table","description":"Reloads all routes from the database into the in-memory proxy cache.\nUseful as a workaround when routes are out of sync.","operationId":"refresh_route_table","responses":{"200":{"description":"Route table refreshed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteRefreshResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/sandbox-rebuild":{"post":{"tags":["Agents"],"operationId":"rebuild_sandbox_image","responses":{"200":{"description":"Server-Sent Events stream of rebuild progress; final event `{\"type\":\"done\",\"success\":bool,...}`","content":{"text/event-stream":{}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/settings/sandbox-status":{"get":{"tags":["Agents"],"operationId":"get_global_sandbox_status","responses":{"200":{"description":"Global sandbox readiness for the settings page","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxStatusResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/settings/secrets":{"get":{"tags":["Secrets"],"operationId":"list_secrets","responses":{"200":{"description":"List of global agent secrets","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListSecretsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Secrets"],"operationId":"upsert_secret","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertSecretRequest"}}},"required":true},"responses":{"201":{"description":"Secret created/updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SecretResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/settings/secrets/{name}":{"delete":{"tags":["Secrets"],"operationId":"delete_secret","parameters":[{"name":"name","in":"path","description":"Secret name","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Secret deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Secret not found"}},"security":[{"bearer_auth":[]}]}},"/settings/skills":{"get":{"tags":["Agents"],"operationId":"list_global_skills","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListSkillsResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Agents"],"operationId":"create_global_skill","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSkillRequest"}}},"required":true},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/settings/skills/upload":{"post":{"tags":["Agents"],"summary":"Upload a skill with an archive (tar.gz) — global.","operationId":"upload_global_skill","requestBody":{"content":{"multipart/form-data":{"schema":{"type":"string"}}},"required":true},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/settings/skills/{slug}":{"get":{"tags":["Agents"],"operationId":"get_global_skill","parameters":[{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Agents"],"operationId":"update_global_skill","parameters":[{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSkillRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Agents"],"operationId":"delete_global_skill","parameters":[{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Skill deleted"},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found"}},"security":[{"bearer_auth":[]}]}},"/settings/skills/{slug}/archive":{"get":{"tags":["Agents"],"summary":"Download a skill's archive (tar.gz) — global.","operationId":"download_global_skill_archive","parameters":[{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Skill archive tar.gz","content":{"application/gzip":{}}},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found or has no archive"}},"security":[{"bearer_auth":[]}]}},"/settings/update-status":{"get":{"tags":["Settings"],"summary":"Report whether a newer temps release is available for this install.","operationId":"get_update_status","responses":{"200":{"description":"Release update status for this install","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateStatusResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/teams":{"get":{"tags":["Teams"],"operationId":"list_teams","parameters":[{"name":"page","in":"query","description":"1-indexed page","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"default 20, max 100","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Paginated teams","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Teams"],"operationId":"create_team","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTeamRequest"}}},"required":true},"responses":{"201":{"description":"Team created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamResponse"}}}},"400":{"description":"Validation error"},"403":{"description":"Insufficient permissions"},"409":{"description":"Slug already taken"}},"security":[{"bearer_auth":[]}]}},"/teams/{team_id}":{"get":{"tags":["Teams"],"operationId":"get_team","parameters":[{"name":"team_id","in":"path","description":"Team id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Team","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamResponse"}}}},"403":{"description":"Insufficient permissions"},"404":{"description":"Team not found"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Teams"],"operationId":"delete_team","parameters":[{"name":"team_id","in":"path","description":"Team id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Team deleted"},"403":{"description":"Insufficient permissions"},"404":{"description":"Team not found"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Teams"],"operationId":"update_team","parameters":[{"name":"team_id","in":"path","description":"Team id","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTeamRequest"}}},"required":true},"responses":{"200":{"description":"Updated team","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamResponse"}}}},"400":{"description":"Validation error"},"403":{"description":"Insufficient permissions"},"404":{"description":"Team not found"}},"security":[{"bearer_auth":[]}]}},"/teams/{team_id}/members":{"get":{"tags":["Teams"],"operationId":"list_team_members","parameters":[{"name":"team_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Members","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TeamMemberResponse"}}}}},"403":{"description":"Insufficient permissions"},"404":{"description":"Team not found"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Teams"],"operationId":"add_team_member","parameters":[{"name":"team_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTeamMemberRequest"}}},"required":true},"responses":{"201":{"description":"Member added","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamMemberResponse"}}}},"403":{"description":"Insufficient permissions"},"404":{"description":"Team not found"},"409":{"description":"User already a member"}},"security":[{"bearer_auth":[]}]}},"/teams/{team_id}/members/{user_id}":{"delete":{"tags":["Teams"],"operationId":"remove_team_member","parameters":[{"name":"team_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"user_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Member removed"},"403":{"description":"Insufficient permissions"},"404":{"description":"Member not found"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Teams"],"operationId":"update_team_member_role","parameters":[{"name":"team_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"user_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMemberRoleRequest"}}},"required":true},"responses":{"200":{"description":"Updated membership","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamMemberResponse"}}}},"403":{"description":"Insufficient permissions"},"404":{"description":"Member not found"}},"security":[{"bearer_auth":[]}]}},"/teams/{team_id}/projects":{"get":{"tags":["Teams"],"operationId":"list_team_projects","parameters":[{"name":"team_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Projects this team has access to","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProjectAccessResponse"}}}}},"403":{"description":"Insufficient permissions"},"404":{"description":"Team not found"}},"security":[{"bearer_auth":[]}]}},"/templates":{"get":{"tags":["Templates"],"summary":"List all available templates","description":"Returns a list of all public templates, optionally filtered by tag or featured status.","operationId":"list_project_templates","parameters":[{"name":"tag","in":"query","description":"Filter templates by tag","required":false,"schema":{"type":"string"}},{"name":"featured","in":"query","description":"Only return featured templates","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of templates","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListTemplatesResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/templates/tags":{"get":{"tags":["Templates"],"summary":"List all available template tags","description":"Returns a list of all unique tags used by public templates.","operationId":"list_project_template_tags","responses":{"200":{"description":"List of tags","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListTagsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/templates/{slug}":{"get":{"tags":["Templates"],"summary":"Get a specific template by slug","description":"Returns detailed information about a single template.","operationId":"get_project_template","parameters":[{"name":"slug","in":"path","description":"Template slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Template details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TemplateResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Template not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/user/me":{"get":{"tags":["Authentication"],"operationId":"get_current_user","responses":{"200":{"description":"Successfully retrieved user information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"session_token":[]}]}},"/users":{"get":{"tags":["Users"],"operationId":"list_users","parameters":[{"name":"include_deleted","in":"query","description":"Include deleted users in the response","required":true,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List all users with their roles","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RouteUserWithRoles"}}}}},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Users"],"summary":"Create a new user with roles","operationId":"create_user","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUserRequest"}}},"required":true},"responses":{"201":{"description":"User created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteUserWithRoles"}}}},"400":{"description":"Invalid input"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/me":{"patch":{"tags":["Users"],"summary":"Update current user's information","operationId":"update_self","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSelfRequest"}}},"required":true},"responses":{"200":{"description":"User updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteUserWithRoles"}}}},"400":{"description":"Invalid input"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/me/mfa":{"delete":{"tags":["Users"],"operationId":"disable_mfa","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DisableMfaRequest"}}},"required":true},"responses":{"204":{"description":"MFA disabled"},"400":{"description":"Invalid verification code"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/me/mfa/setup":{"post":{"tags":["Users"],"operationId":"setup_mfa","responses":{"200":{"description":"MFA setup data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MfaSetupResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/me/mfa/verify":{"post":{"tags":["Users"],"operationId":"verify_and_enable_mfa","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyMfaRequest"}}},"required":true},"responses":{"204":{"description":"MFA verified and enabled"},"400":{"description":"Invalid code"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/me/password":{"post":{"tags":["Users"],"operationId":"change_password_self","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangePasswordRequest"}}},"required":true},"responses":{"204":{"description":"Password updated"},"400":{"description":"Validation error (weak password, same as current, MFA missing)"},"401":{"description":"Current password incorrect or MFA code invalid"},"403":{"description":"Account has no password set (SSO only)"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/{user_id}":{"delete":{"tags":["Users"],"summary":"Delete a user","operationId":"delete_user","parameters":[{"name":"user_id","in":"path","description":"User ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"User deleted successfully"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden - Cannot delete yourself or non-admin attempt"},"404":{"description":"User not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Users"],"summary":"Update user information (admin only)","operationId":"update_user","parameters":[{"name":"user_id","in":"path","description":"User ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUserRequest"}}},"required":true},"responses":{"200":{"description":"User updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteUserWithRoles"}}}},"400":{"description":"Invalid input"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden - Non-admin attempt"},"404":{"description":"User not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/{user_id}/restore":{"post":{"tags":["Users"],"operationId":"restore_user","parameters":[{"name":"user_id","in":"path","description":"User ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"User restored successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteUserWithRoles"}}}},"400":{"description":"User is not deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden - Non-admin attempt"},"404":{"description":"User not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/{user_id}/roles":{"post":{"tags":["Users"],"operationId":"assign_role","parameters":[{"name":"user_id","in":"path","description":"User ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssignRoleRequest"}}},"required":true},"responses":{"200":{"description":"Role assigned successfully"},"400":{"description":"Invalid role type"},"401":{"description":"Unauthorized"},"403":{"description":"Admin role required or self-modification forbidden"},"404":{"description":"User or role not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/{user_id}/roles/{role_type}":{"delete":{"tags":["Users"],"operationId":"remove_role","parameters":[{"name":"user_id","in":"path","description":"User ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"role_type","in":"path","description":"Role type to remove","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Role removed successfully"},"400":{"description":"Invalid role type"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden - Cannot modify own roles or non-admin attempt"},"404":{"description":"User or role not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes":{"get":{"tags":["Sandboxes"],"operationId":"list_sandboxes","parameters":[{"name":"page","in":"query","description":"Page (1-indexed)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page (default 20, max 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List sandboxes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListSandboxesResponse"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Sandboxes"],"operationId":"create_sandbox","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSandboxBody"}}},"required":true},"responses":{"201":{"description":"Sandbox created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/rootfs":{"get":{"tags":["Sandboxes"],"summary":"Inspect rootfs storage: the Firecracker digest-keyed cache (with which\nsandboxes reference each entry) and per-VM disks. Empty on Docker-only\nhosts. Admin/read scope — this exposes host storage layout.","operationId":"rootfs_report","responses":{"200":{"description":"Rootfs storage report"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/rootfs/gc":{"post":{"tags":["Sandboxes"],"summary":"Reclaim rootfs cache entries not backing any live sandbox. Idempotent;\nsafe to call any time (live VMs hold their own per-VM disks).","operationId":"rootfs_gc","responses":{"200":{"description":"Reclaimed cache entries"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}":{"get":{"tags":["Sandboxes"],"operationId":"get_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sandbox details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"404":{"description":"Not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/cmd":{"post":{"tags":["Sandboxes"],"summary":"Run a command inside the sandbox (`@vercel/sandbox`-compatible).","description":"`wait=false` (default) returns `{ command: {..., exitCode: null} }`\nimmediately once the background task is spawned.\n\n`wait=true` streams `application/x-ndjson`: the first line is the\nrunning envelope, the second is the finished envelope with `exitCode`.","operationId":"cmd","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CmdBody"}}},"required":true},"responses":{"200":{"description":"Command started (wait=false) or finished (wait=true)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CmdResponse"}}}},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/cmd/{cmd_id}":{"get":{"tags":["Sandboxes"],"operationId":"get_cmd","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"cmd_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Command snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CmdResponse"}}}},"404":{"description":"Sandbox or command not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/cmd/{cmd_id}/logs":{"get":{"tags":["Sandboxes"],"summary":"Stream a command's stdout/stderr as `application/x-ndjson`\n(`@vercel/sandbox`-compatible). Each line is either\n`{stream:\"stdout\"|\"stderr\", data:\"...\"}` or\n`{stream:\"error\", data:{code, message}}`.","operationId":"cmd_logs","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"cmd_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"NDJSON stream of log events"},"404":{"description":"Sandbox or command not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/destroy":{"post":{"tags":["Sandboxes"],"operationId":"destroy_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Sandbox destroyed (alias for `/stop` with an explicit verb)"},"404":{"description":"Not found"},"409":{"description":"Sandbox belongs to an active agent run — stop the run instead"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/domain":{"get":{"tags":["Sandboxes"],"operationId":"domain","parameters":[{"name":"port","in":"query","description":"Port inside the sandbox (1..=65535)","required":true,"schema":{"type":"integer","format":"int32","minimum":0}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Preview URL for the port","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxDomainResponse"}}}},"400":{"description":"Invalid port"},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/events":{"get":{"tags":["Sandboxes"],"summary":"The operations timeline for a sandbox (lifecycle events only — never\nshell/exec activity), newest first.","operationId":"list_events","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Operations timeline","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxEventsResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/exec":{"post":{"tags":["Sandboxes"],"operationId":"exec","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecBody"}}},"required":true},"responses":{"200":{"description":"Command finished (non-zero exit is NOT an error)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecResponse"}}}},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/exec-detached":{"post":{"tags":["Sandboxes"],"operationId":"exec_detached","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecBody"}}},"required":true},"responses":{"202":{"description":"Command accepted; poll /jobs/{job_id}","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecDetachedResponse"}}}},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/extend-timeout":{"post":{"tags":["Sandboxes"],"operationId":"extend_timeout","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExtendTimeoutBody"}}},"required":true},"responses":{"200":{"description":"Timeout extended","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"400":{"description":"Validation error"},"404":{"description":"Not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/fs/mkdir":{"post":{"tags":["Sandboxes"],"operationId":"mkdir","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MkdirBody"}}},"required":true},"responses":{"204":{"description":"Directory created (or already existed)"},"400":{"description":"Validation error"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/fs/read":{"get":{"tags":["Sandboxes"],"operationId":"read_file","parameters":[{"name":"path","in":"query","description":"Absolute file path inside the sandbox","required":true,"schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"File contents (base64)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReadFileResponse"}}}},"400":{"description":"Validation error"},"404":{"description":"Sandbox or file not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/fs/stat":{"get":{"tags":["Sandboxes"],"operationId":"stat_path","parameters":[{"name":"path","in":"query","description":"Absolute path inside the sandbox","required":true,"schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Stat info (exists=false when missing — not an error)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatResponse"}}}},"400":{"description":"Validation error"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/fs/write":{"post":{"tags":["Sandboxes"],"summary":"Write a file into the sandbox. Accepts two body shapes — the SDK\npicks one based on `Content-Type`:","description":"- **`application/json`** (temps-native): `{path, contents_b64, mode}`\n — one file, base64-encoded.\n- **`application/gzip`** (`@vercel/sandbox`): a gzipped tarball of\n one-or-more entries, with the target extract dir carried in the\n `x-cwd` header. The SDK's `writeFile` and `writeFiles` both post\n here; they differ only in how many entries the tarball contains.\n\nWhy merge them on one route: the SDK is hardcoded to\n`POST /fs/write`, so splitting tar uploads onto a separate path would\nforce us to break SDK compat. Instead we dispatch on Content-Type,\npreserve JSON for native callers, and add tar for SDK callers.","operationId":"write_file","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WriteFileBody"}}},"required":true},"responses":{"204":{"description":"File(s) written"},"400":{"description":"Validation error or invalid base64"},"404":{"description":"Sandbox not found"},"415":{"description":"Unsupported Content-Type (expected application/json or application/gzip)"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/fs/write-batch":{"post":{"tags":["Sandboxes"],"summary":"Batch-write multiple files in a single request. Mirrors\n`@vercel/sandbox` `writeFiles()`. Semantics are fail-fast: if any\nfile errors, previously-written entries are left in place and the\nerror describes which file broke.","operationId":"write_files","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WriteFilesBody"}}},"required":true},"responses":{"200":{"description":"All files written","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WriteFilesResponse"}}}},"400":{"description":"Validation error or invalid base64"},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/jobs":{"get":{"tags":["Sandboxes"],"operationId":"list_jobs","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Detached jobs for this sandbox","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListJobsResponse"}}}},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/jobs/{job_id}":{"get":{"tags":["Sandboxes"],"operationId":"job_status","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"job_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Job status snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobStatusResponse"}}}},"404":{"description":"Sandbox or job not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/jobs/{job_id}/kill":{"post":{"tags":["Sandboxes"],"summary":"Terminate a detached job. Aborts the server-side tracking task and\nsends SIGTERM (or SIGKILL if `force=true`) to any matching processes\ninside the sandbox container. Returns 204 on success; 404 if the\nsandbox or job is unknown.","operationId":"kill_job","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"job_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KillJobBody"}}},"required":true},"responses":{"204":{"description":"Job killed"},"404":{"description":"Sandbox or job not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/jobs/{job_id}/logs":{"get":{"tags":["Sandboxes"],"summary":"SSE endpoint streaming each stdout/stderr line from a detached job\nas it's produced. Mirrors the `Command.logs()` async iterator shape\non `@vercel/sandbox` — events carry `{ stream, data }`.","description":"Late subscribers only see events produced after they connect. The\nJobState snapshot (`GET /jobs/{job_id}`) covers the history.\n\nA \"done\" sentinel event fires when the broadcast channel closes\n(the exec task has exited and dropped the sender), signalling\ncallers they can stop reading.","operationId":"job_logs","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"job_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"SSE stream of log events"},"404":{"description":"Sandbox or job not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/pause":{"post":{"tags":["Sandboxes"],"operationId":"pause_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sandbox paused (container stopped, state preserved)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"404":{"description":"Not found"},"409":{"description":"Sandbox is in an incompatible state (e.g. already destroyed)"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/preview-link":{"post":{"tags":["Sandboxes"],"summary":"Mint a shareable link to a sandbox preview.","description":"`GET /domain` returns the bare preview URL, which is useless to anyone who\ndoes not already hold the sandbox's preview password — so sharing a\nprotected preview meant sharing that password, which is the same secret for\nevery recipient and can only be withdrawn by rotating it for all of them.\n\nThis returns the same URL carrying a short-lived, sandbox-scoped grant. The\nrecipient's browser exchanges it for the ordinary preview cookie and lands\non `path`. The grant never reaches the sandbox, so preview application code\ncannot read it and re-share it.\n\nAnyone holding the returned URL can view the preview until it expires;\nthere is no per-link revocation short of rotating the preview password.","operationId":"sandbox_create_preview_link","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreviewShareLinkBody"}}},"required":true},"responses":{"200":{"description":"Shareable preview link","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreviewShareLinkResponse"}}}},"400":{"description":"Invalid port"},"404":{"description":"Sandbox not found"},"409":{"description":"Sandbox has no preview password"},"500":{"description":"Preview grant minting failed"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/preview-password":{"put":{"tags":["Sandboxes"],"operationId":"set_preview_password","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetPreviewPasswordBody"}}},"required":true},"responses":{"200":{"description":"Preview password set or rotated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetPreviewPasswordResponse"}}}},"400":{"description":"Password too short or too long"},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Sandboxes"],"operationId":"clear_preview_password","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Preview password removed (sandbox is now URL-only protected)"},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/resize":{"post":{"tags":["Sandboxes"],"summary":"Grow a Firecracker sandbox's root disk. Offline resize — the VM reboots\n(filesystem/data persist) rather than resizing fully live.","operationId":"resize_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResizeSandboxBody"}}},"required":true},"responses":{"200":{"description":"Resized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"400":{"description":"Invalid size or unsupported backend"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/restart":{"post":{"tags":["Sandboxes"],"operationId":"restart_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sandbox container restarted in place","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"404":{"description":"Not found"},"409":{"description":"Sandbox is stopped (use /resume) or already destroyed"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/resume":{"post":{"tags":["Sandboxes"],"operationId":"resume_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sandbox resumed; expires_at refreshed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"404":{"description":"Not found"},"409":{"description":"Sandbox is not in a resumable state"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/source":{"post":{"tags":["Sandboxes"],"operationId":"source_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceBody"}}},"required":true},"responses":{"200":{"description":"Source content seeded into the sandbox work dir","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"400":{"description":"Validation error (embedded creds, conflicting fields, etc.)"},"404":{"description":"Sandbox not found"},"409":{"description":"Sandbox is not running"},"500":{"description":"Source seed failed inside sandbox"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/stop":{"post":{"tags":["Sandboxes"],"operationId":"stop_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Sandbox stopped and destroyed"},"404":{"description":"Not found"},"409":{"description":"Sandbox belongs to an active agent run — stop the run instead"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/{cmd_id}/kill":{"post":{"tags":["Sandboxes"],"summary":"Kill a running command (`@vercel/sandbox`-compatible). The SDK\ncalls `POST /v1/sandboxes/{id}/{cmdId}/kill` — note the path has the\ncommand ID directly under the sandbox, NOT under `/jobs/` or `/cmd/`.","operationId":"cmd_kill","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"cmd_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CmdKillBody"}}}},"responses":{"200":{"description":"Command killed; returns final snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CmdResponse"}}}},"404":{"description":"Sandbox or command not found"}},"security":[{"bearer_auth":[]}]}},"/visitors/{visitor_id}/session-replays":{"get":{"tags":["Analytics"],"summary":"Get session replays for a visitor","operationId":"get_visitor_sessions","parameters":[{"name":"visitor_id","in":"path","description":"Visitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-based)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Items per page","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Session replays retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetVisitorSessionsResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/visitors/{visitor_id}/session-replays/{session_id}":{"get":{"tags":["Analytics"],"summary":"Get session replay data with visitor info (without events)","operationId":"get_session_replay","parameters":[{"name":"visitor_id","in":"path","description":"Visitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Session replay retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetSessionReplayResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Session not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Analytics"],"summary":"Delete a session replay","operationId":"delete_session_replay","parameters":[{"name":"visitor_id","in":"path","description":"Visitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Session replay deleted successfully"},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Session not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/visitors/{visitor_id}/session-replays/{session_id}/duration":{"put":{"tags":["Analytics"],"summary":"Update session duration","operationId":"update_session_duration","parameters":[{"name":"visitor_id","in":"path","description":"Visitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSessionDurationRequest"}}},"required":true},"responses":{"200":{"description":"Session duration updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSessionDurationResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Session not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/visitors/{visitor_id}/session-replays/{session_id}/events":{"get":{"tags":["Analytics"],"summary":"Get session replay events (with session and visitor metadata)","operationId":"get_session_replay_events","parameters":[{"name":"visitor_id","in":"path","description":"Visitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Session replay with events retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionReplayWithEventsDto"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Session not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Analytics"],"summary":"Add events to an existing session","operationId":"add_events","parameters":[{"name":"visitor_id","in":"path","description":"Visitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddEventsRequest"}}},"required":true},"responses":{"200":{"description":"Events added successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddEventsResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Session not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/vulnerability-scans/{scan_id}":{"get":{"tags":["Vulnerability Scans"],"operationId":"get_scan","parameters":[{"name":"scan_id","in":"path","description":"Scan ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Scan details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScanResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Scan not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Vulnerability Scans"],"operationId":"delete_scan","parameters":[{"name":"scan_id","in":"path","description":"Scan ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Scan deleted"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Scan not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/vulnerability-scans/{scan_id}/vulnerabilities":{"get":{"tags":["Vulnerability Scans"],"operationId":"get_scan_vulnerabilities","parameters":[{"name":"scan_id","in":"path","description":"Scan ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"severity","in":"query","description":"Filter by severity (CRITICAL, HIGH, MEDIUM, LOW)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of vulnerabilities","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/VulnerabilityResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Scan not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/webhook-event-types":{"get":{"tags":["Webhooks"],"summary":"List available event types","operationId":"list_event_types","responses":{"200":{"description":"List of available event types","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EventTypeResponse"}}}}}}}},"/weekly-digest/trigger":{"post":{"tags":["Notification Preferences"],"summary":"Trigger weekly digest generation manually","operationId":"trigger_weekly_digest","responses":{"200":{"description":"Weekly digest triggered successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerDigestResponse"}}}},"500":{"description":"Failed to generate digest"}},"security":[{"bearer_auth":[]}]}},"/x/plugins":{"get":{"tags":["External Plugins"],"summary":"List all running external plugins and their manifests.","description":"Requires only a valid session/token (no specific permission) since the\nmanifest drives sidebar navigation rendering for every authenticated\nuser, not just admins.","operationId":"list_external_plugins","responses":{"200":{"description":"List of all running external plugins","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PluginManifest"}}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/x/plugins/reload":{"post":{"tags":["External Plugins"],"summary":"Reload all external plugins.","description":"Stops all running plugin processes, re-scans the plugins directory,\nstarts any discovered binaries, and hot-swaps the proxy router so new\nand removed plugins take effect immediately without a server restart.\n\nRequires `SystemAdmin` permission.","operationId":"reload_plugins","responses":{"200":{"description":"Plugins reloaded successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReloadResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/{project_id}/envelope/":{"post":{"tags":["sentry-ingestor"],"summary":"Ingest a Sentry envelope (binary payload)","operationId":"ingest_sentry_envelope","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"Sentry envelope as binary data","content":{"application/octet-stream":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"Envelope ingested"},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"413":{"description":"Request body too large (exceeds 2 MiB)"}}}},"/{project_id}/store/":{"post":{"tags":["sentry-ingestor"],"summary":"Ingest a Sentry event (JSON payload)","operationId":"ingest_sentry_event","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryEventRequest"}}},"required":true},"responses":{"200":{"description":"Event ingested","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryEventResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"413":{"description":"Request body too large (exceeds 2 MiB)"}}}},"audit/logs":{"get":{"tags":["Audit Logs"],"summary":"List audit logs with optional filtering","operationId":"list_audit_logs","parameters":[{"name":"operation_type","in":"query","description":"Filter logs by operation type (omit for all)","required":false,"schema":{"type":"string"},"example":"user.login"},{"name":"user_id","in":"query","description":"Filter logs by user ID (omit for all users)","required":false,"schema":{"type":"integer","format":"int32"},"example":1},{"name":"from","in":"query","description":"Start timestamp (milliseconds since epoch)","required":false,"schema":{"type":"string","format":"date-time"},"example":1},{"name":"to","in":"query","description":"End timestamp (milliseconds since epoch)","required":false,"schema":{"type":"string","format":"date-time"},"example":1},{"name":"limit","in":"query","description":"Maximum number of logs to return","required":false,"schema":{"type":"integer","format":"int32"},"example":100},{"name":"offset","in":"query","description":"Number of logs to skip","required":false,"schema":{"type":"integer","format":"int32"},"example":0}],"responses":{"200":{"description":"List of audit logs","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AuditLogResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"api_key":[]}]}},"audit/logs/{id}":{"get":{"tags":["Audit Logs"],"summary":"Get a specific audit log entry by ID","operationId":"get_audit_log","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Audit log details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuditLogResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Audit log not found"},"500":{"description":"Internal server error"}},"security":[{"api_key":[]}]}}},"components":{"schemas":{"AcmeOrderResponse":{"type":"object","required":["id","order_url","domain_id","email","status","identifiers","created_at","updated_at"],"properties":{"authorizations":{},"certificate_url":{"type":["string","null"]},"challenge_validation":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ChallengeValidationStatus","description":"Live challenge validation status fetched from Let's Encrypt"}]},"created_at":{"type":"integer","format":"int64"},"domain_id":{"type":"integer","format":"int32"},"email":{"type":"string"},"error":{"type":["string","null"]},"error_type":{"type":["string","null"]},"expires_at":{"type":["integer","null"],"format":"int64"},"finalize_url":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"identifiers":{},"order_url":{"type":"string"},"status":{"type":"string"},"updated_at":{"type":"integer","format":"int64"}}},"ActivateProviderResponse":{"type":"object","required":["default_provider"],"properties":{"default_provider":{"type":"string"}}},"ActiveVisitor":{"type":"object","required":["session_id","session_start","last_activity","page_count","event_count","duration_seconds","is_active"],"properties":{"current_page":{"type":["string","null"]},"duration_seconds":{"type":"integer","format":"int64"},"event_count":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"last_activity":{"type":"string"},"page_count":{"type":"integer","format":"int32"},"session_id":{"type":"string"},"session_start":{"type":"string"},"visitor_id":{"type":["string","null"]}}},"ActiveVisitorsQuery":{"type":"object","properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"}}},"ActiveVisitorsResponse":{"type":"object","required":["active_visitors","window_minutes"],"properties":{"active_visitors":{"type":"integer","format":"int64"},"window_minutes":{"type":"integer","format":"int32"}}},"ActivityDay":{"type":"object","description":"Daily activity count for a single day","required":["date","count","level"],"properties":{"count":{"type":"integer","format":"int64","description":"Number of deployments on this day"},"date":{"type":"string","description":"Date in YYYY-MM-DD format","example":"2024-06-15"},"level":{"type":"integer","format":"int32","description":"Intensity level (0-4) for visualization\n0: No activity, 1: Low (1-2), 2: Medium (3-5), 3: High (6-10), 4: Very High (11+)","example":2}}},"ActivityEvent":{"type":"object","description":"A single activity event for the real-time activity feed","required":["id","timestamp","event_type","page_path","is_crawler"],"properties":{"browser":{"type":["string","null"],"description":"Browser"},"city":{"type":["string","null"],"description":"Visitor's city (from ip_geolocations)"},"country":{"type":["string","null"],"description":"Visitor's country (from ip_geolocations)"},"country_code":{"type":["string","null"],"description":"Visitor's country code (from ip_geolocations)"},"device_type":{"type":["string","null"],"description":"Device type"},"event_name":{"type":["string","null"],"description":"Event name (for custom events)"},"event_type":{"type":"string","description":"Event type: \"page_view\", \"custom\", etc."},"id":{"type":"integer","format":"int64","description":"Event ID"},"is_crawler":{"type":"boolean","description":"Whether this event was from a crawler"},"latitude":{"type":["number","null"],"format":"double","description":"Latitude"},"longitude":{"type":["number","null"],"format":"double","description":"Longitude"},"operating_system":{"type":["string","null"],"description":"Operating system"},"page_path":{"type":"string","description":"Page path where the event happened"},"page_title":{"type":["string","null"],"description":"Page title"},"referrer":{"type":["string","null"],"description":"Referrer"},"timestamp":{"type":"string","format":"date-time","description":"When the event occurred"},"visitor_id":{"type":["integer","null"],"format":"int32","description":"Visitor numeric ID"}}},"ActivityGraphQuery":{"type":"object","description":"Query parameters for activity graph endpoint","properties":{"days":{"type":"integer","format":"int32","description":"Number of days to include (default: 365 for last year)"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Optional environment ID to filter activity"},"project_id":{"type":["integer","null"],"format":"int32","description":"Optional project ID to filter activity"}}},"ActivityGraphResponse":{"type":"object","description":"Response for activity graph showing daily deployment activity","required":["days","total_count","start_date","end_date"],"properties":{"days":{"type":"array","items":{"$ref":"#/components/schemas/ActivityDay"},"description":"Array of daily activity counts"},"end_date":{"type":"string","description":"Date range end (YYYY-MM-DD)","example":"2024-12-31"},"start_date":{"type":"string","description":"Date range start (YYYY-MM-DD)","example":"2024-01-01"},"total_count":{"type":"integer","format":"int64","description":"Total count of activities across all days"}}},"AddClusterMemberRequest":{"type":"object","description":"Request body for adding a single member to a running cluster.","required":["role"],"properties":{"node_id":{"type":["integer","null"],"format":"int32","description":"Target worker node ID. Omit or null to run on the control plane."},"role":{"type":"string","description":"Member role. Currently only `replica` is accepted at runtime —\nmonitor is a singleton, primary is elected by pg_auto_failover.","example":"replica"}}},"AddContextRequest":{"type":"object","required":["message"],"properties":{"message":{"type":"string"}}},"AddEnvironmentDomainRequest":{"type":"object","required":["domain","is_primary"],"properties":{"domain":{"type":"string"},"is_primary":{"type":"boolean"}}},"AddEventsRequest":{"type":"object","required":["events"],"properties":{"events":{"type":"string"}}},"AddEventsResponse":{"type":"object","required":["event_count","message"],"properties":{"event_count":{"type":"integer","minimum":0},"message":{"type":"string"}}},"AddManagedDomainApiRequest":{"type":"object","description":"Request to add a managed domain","required":["domain"],"properties":{"auto_manage":{"type":"boolean"},"domain":{"type":"string","example":"example.com"},"generated_hostname_mode":{"type":["string","null"],"description":"Generated hostname layout: `\"standard\"` (default) or `\"flat\"`."},"sync_generated_records":{"type":"boolean","description":"Opt in to reconciling generated hostnames into this domain's DNS zone."}}},"AdminGateResponse":{"type":"object","required":["allowed_ips","allowed_hosts","trust_forwarded_for","source","editable"],"properties":{"allowed_hosts":{"type":"array","items":{"type":"string"},"description":"`Host` header values allowed. Empty = any host."},"allowed_ips":{"type":"array","items":{"type":"string"},"description":"IPs / CIDRs allowed to reach the admin listener. Empty = any source."},"editable":{"type":"boolean","description":"True when the config is writable through this API. False when env\nvars are dictating the active config."},"source":{"$ref":"#/components/schemas/AdminGateSource","description":"Where the active config came from."},"trust_forwarded_for":{"type":"boolean","description":"When true, the gate trusts `X-Forwarded-For` from loopback peers."}}},"AdminGateSource":{"type":"string","description":"Where the active gate configuration came from. Env-supplied configs are\nfrozen at the process level — the UI shows them read-only and refuses to\npersist DB writes. DB-supplied configs are editable at runtime.","enum":["default","db","env"]},"AgentConfigResponse":{"type":"object","description":"Response DTO for a single agent — masks the encrypted API key.","required":["id","project_id","slug","name","source","enabled","trigger_config","ai_provider","api_key_set","max_turns","timeout_seconds","daily_budget_cents","cooldown_minutes","branch_prefix","deliverable","created_at","updated_at"],"properties":{"ai_model":{"type":["string","null"],"description":"Preferred model for the CLI (e.g. \"sonnet\", \"gpt-5-codex\"). `None` means default."},"ai_provider":{"type":"string"},"ai_provider_key_id":{"type":["integer","null"],"format":"int32"},"api_key_set":{"type":"boolean","description":"`true` if an API key is set; `false` otherwise."},"branch_prefix":{"type":"string"},"config_repo_branch":{"type":["string","null"],"description":"Branch of the config repo to use."},"config_repo_url":{"type":["string","null"],"description":"Private config repo containing .claude/ directory (skills, MCP, plugins)."},"cooldown_minutes":{"type":"integer","format":"int32"},"created_at":{"type":"string"},"daily_budget_cents":{"type":"integer","format":"int32"},"deliverable":{"type":"string"},"description":{"type":["string","null"]},"enabled":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"max_turns":{"type":"integer","format":"int32"},"mcp_servers_config":{"description":"MCP servers config (Claude Code settings.json mcpServers format).\nCredential-bearing legacy inline values are write-only and appear as\n`***`. Omit this field on update to preserve their stored values."},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"prompt":{"type":["string","null"]},"sandbox_enabled":{"type":["boolean","null"],"description":"None = use global sandbox setting, true = force on, false = force off"},"skills_config":{"description":"Skills config as JSON array."},"slug":{"type":"string"},"source":{"type":"string"},"timeout_seconds":{"type":"integer","format":"int32"},"tools_config":{"description":"Tools config as JSON array. Legacy custom-tool webhook URLs and headers\nare write-only and appear as `***`. Omit this field on update to\npreserve their stored values."},"trigger_config":{},"updated_at":{"type":"string"},"webhook_token":{"type":["string","null"],"description":"Secret token for the `X-Webhook-Token` header. Shown once when created,\nmasked with `***` prefix in subsequent reads."},"webhook_url":{"type":["string","null"],"description":"Public webhook URL for triggering this agent externally.\nOnly set when `on: { webhook: true }` is configured.\nUsage: `POST {webhook_url}` with header `X-Webhook-Token: {webhook_token}`"}}},"AgentRunLogResponse":{"type":"object","required":["id","run_id","level","message","created_at"],"properties":{"created_at":{"type":"string"},"id":{"type":"integer","format":"int64"},"level":{"type":"string"},"message":{"type":"string"},"metadata":{},"run_id":{"type":"integer","format":"int32"}}},"AgentRunResponse":{"type":"object","required":["id","project_id","source","trigger_type","status","tokens_input","tokens_output","estimated_cost_cents","files_changed","created_at","sandbox_enabled"],"properties":{"agent_name":{"type":["string","null"],"description":"Name of the agent that created this run, if available."},"agent_slug":{"type":["string","null"],"description":"Slug of the agent that created this run, if available."},"ai_model":{"type":["string","null"]},"ai_output":{"type":["string","null"]},"ai_provider":{"type":["string","null"],"description":"AI provider slug that executed this run (e.g. claude_cli, codex_cli, opencode)."},"ai_reasoning":{"type":["string","null"]},"ai_session_id":{"type":["string","null"],"description":"Claude CLI session UUID for resuming conversations via `--resume`."},"analysis":{"type":["string","null"],"description":"Report / analysis text produced by the agent (used for report/notification deliverables)."},"branch_name":{"type":["string","null"]},"commit_sha":{"type":["string","null"]},"completed_at":{"type":["string","null"]},"config_id":{"type":["integer","null"],"format":"int32","description":"Optional. NULL for ephemeral CLI runs (`source = \"cli_ephemeral\"`) and\nhistorical autofixer runs that pre-date the agent_id column."},"created_at":{"type":"string"},"ephemeral_yaml":{"type":["string","null"],"description":"Full WorkflowYamlConfig as YAML text. Populated only when\n`source = \"cli_ephemeral\"`. Used by the web UI to show a \"View YAML\"\nmodal so the user can see exactly what the executor ran."},"error_message":{"type":["string","null"]},"estimated_cost_cents":{"type":"integer","format":"int32"},"files_changed":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"phase":{"type":["string","null"],"description":"Autofixer phase: \"analyzing\", \"analyzed\", \"fixing\", \"fix_ready\", \"no_fix\",\n\"pr_created\", or NULL for non-autofixer runs."},"pr_number":{"type":["integer","null"],"format":"int32"},"pr_url":{"type":["string","null"]},"preview_url":{"type":["string","null"]},"project_id":{"type":"integer","format":"int32"},"prompt_text":{"type":["string","null"],"description":"Final assembled prompt the AI CLI actually saw (trigger context block +\nYAML prompt, with error-group fields interpolated). Captured once per\nrun. `None` for pre-migration rows."},"run_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AutofixRunConfig","description":"Per-run AI options the user chose when starting an autofixer run\n(provider, model, max_turns, branch). NULL for generic agent runs\nand historical rows. Used to prefill the retry dialog."}]},"sandbox_enabled":{"type":"boolean","description":"Legacy field — all runs now execute in a sandbox. Kept for\nbackwards-compatible JSON shape; always `true`."},"source":{"type":"string","description":"`committed` (the run's config lives in `project_agents`) or\n`cli_ephemeral` (the config was uploaded via the CLI for a one-off\ndry run; see `ephemeral_yaml`)."},"started_at":{"type":["string","null"]},"status":{"type":"string"},"tokens_input":{"type":"integer","format":"int32"},"tokens_output":{"type":"integer","format":"int32"},"trigger_source_id":{"type":["integer","null"],"format":"int32"},"trigger_source_type":{"type":["string","null"]},"trigger_type":{"type":"string"},"user_context":{"type":["string","null"],"description":"User-provided context for this run (e.g. webhook payload, manual instructions)."}}},"AgentRunWithLogsResponse":{"type":"object","required":["run","logs"],"properties":{"logs":{"type":"array","items":{"$ref":"#/components/schemas/AgentRunLogResponse"}},"run":{"$ref":"#/components/schemas/AgentRunResponse"}}},"AgentSandboxSettings":{"type":"object","description":"Global agent sandbox settings. Controls whether agent runs are isolated\ninside Docker containers by default. Individual agents can override this.","properties":{"api_key_encrypted":{"type":["string","null"],"description":"DEPRECATED: use `providers[default_provider].credentials_encrypted` instead.","default":null},"auth_type":{"type":"string","description":"DEPRECATED: use `providers[default_provider].auth_type` instead.","default":"subscription"},"cpu_limit":{"type":"number","format":"double","description":"CPU limit in cores for sandbox containers","default":4.0,"example":4.0},"custom_image":{"type":"string","description":"Custom Docker image (only used when runtime is \"custom\").\nMust have git and claude CLI installed.","default":"","example":""},"default_provider":{"type":"string","description":"Default AI provider for agents: \"claude_cli\", \"opencode\", or \"codex_cli\".\nWorkspaces always use this provider — no per-session override.","default":"claude_cli","example":"claude_cli"},"enabled":{"type":"boolean","description":"Sandbox is always enabled — the executor refuses to run any agent\noutside a sandboxed container. Field is retained so existing settings\nrows still deserialize, but it is ignored at runtime.","default":true},"memory_limit_mb":{"type":"integer","format":"int64","description":"Memory limit in MB for sandbox containers","default":8192,"example":8192,"minimum":0},"network_mode":{"type":"string","description":"Network access level: \"full\" (unrestricted), \"restricted\" (Temps network only), \"none\" (no network)","default":"full","example":"full"},"providers":{"type":"object","description":"Per-provider auth + config. Keyed by provider id (e.g. `claude_cli`,\n`codex_cli`, `opencode`). Adding a new provider only requires a new\ncatalog entry on the Rust side — the JSON column stays migration-free.","default":{},"additionalProperties":{"$ref":"#/components/schemas/ProviderConfig"},"propertyNames":{"type":"string"}},"runtime":{"type":"string","description":"Runtime preset: \"node\", \"bun\", \"python\", \"rust\", \"go\", \"full\", or \"custom\"","default":"node","example":"node"},"sandbox_backend":{"type":["string","null"],"description":"Default isolation backend for sandboxes: \"docker\" (default) or\n\"firecracker\" (ADR-029; requires `temps firecracker setup`). Only\nconsulted when the Firecracker backend probes available — otherwise\nDocker is used regardless.","default":null,"example":"docker"}}},"AgentSandboxSettingsMasked":{"type":"object","description":"Agent sandbox settings with masked per-provider credentials.\nEach provider entry reports only whether a credential is saved, not\nthe encrypted blob itself. Non-sensitive fields (auth_type, default_model,\nextra) are passed through so the UI can render provider-specific state.","required":["default_provider","providers","api_key_saved","auth_type","enabled","runtime","custom_image","cpu_limit","memory_limit_mb","network_mode","sandbox_backend"],"properties":{"api_key_saved":{"type":"boolean"},"auth_type":{"type":"string"},"cpu_limit":{"type":"number","format":"double"},"custom_image":{"type":"string"},"default_provider":{"type":"string"},"enabled":{"type":"boolean"},"memory_limit_mb":{"type":"integer","format":"int64","minimum":0},"network_mode":{"type":"string"},"providers":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/ProviderConfigMasked"},"propertyNames":{"type":"string"}},"runtime":{"type":"string"},"sandbox_backend":{"type":"string"}}},"AggregatedBucketItem":{"type":"object","required":["timestamp","count"],"properties":{"count":{"type":"integer","format":"int64"},"timestamp":{"type":"string"}}},"AggregatedBucketsQuery":{"type":"object","description":"Query parameters for aggregated metrics by time bucket","required":["start_date","end_date"],"properties":{"aggregation_level":{"$ref":"#/components/schemas/AggregationLevel","description":"Aggregation level: events, sessions, or visitors"},"bucket_size":{"type":"string","description":"Time bucket size: \"1 hour\", \"1 day\", \"1 week\", etc. (default: \"1 hour\")"},"deployment_id":{"type":["integer","null"],"format":"int32","description":"Optional deployment filter"},"end_date":{"type":"string","format":"date-time","description":"End date for the query range"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Optional environment filter"},"start_date":{"type":"string","format":"date-time","description":"Start date for the query range"}}},"AggregatedBucketsResponse":{"type":"object","required":["bucket_size","aggregation_level","items","total"],"properties":{"aggregation_level":{"type":"string"},"bucket_size":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/AggregatedBucketItem"}},"total":{"type":"integer","format":"int64"}}},"AggregationLevel":{"type":"string","enum":["events","sessions","visitors"]},"AggregationTemporality":{"type":"string","description":"The aggregation temporality of a Sum/Histogram/ExponentialHistogram metric.\n\nMirrors OTel's `AggregationTemporality` proto enum: whether reported values\nare cumulative since the start of the series (Cumulative) or only the delta\nsince the previous report (Delta).","enum":["unspecified","delta","cumulative"]},"AiAgentBreakdownResponse":{"type":"object","description":"Response wrapping the AI agent breakdown rows.","required":["items","start_time","end_time"],"properties":{"end_time":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/AiAgentBreakdownRow"}},"start_time":{"type":"string"}}},"AiAgentBreakdownRow":{"type":"object","description":"One row in the AI-agent analytics breakdown. `agent` is the canonical\ncrawler name (e.g. `GPTBot`, `Claude-User`), `provider` is the vendor used\nfor grouping + logos. The UI mirrors the browsers card and ranks by\n`request_count`.","required":["provider","agent","purpose","request_count","unique_ips"],"properties":{"agent":{"type":"string"},"last_seen":{"type":["string","null"],"description":"Last-seen timestamp in RFC3339 format, or `None` if no rows matched.","example":"2026-05-29T12:00:00Z"},"provider":{"type":"string"},"purpose":{"type":"string"},"request_count":{"type":"integer","format":"int64"},"unique_ips":{"type":"integer","format":"int64"}}},"AiAgentDescriptor":{"type":"object","description":"Static descriptor for one entry in the known-AI-agents taxonomy.","required":["provider","agent","purpose"],"properties":{"agent":{"type":"string"},"provider":{"type":"string"},"purpose":{"type":"string"}}},"AiAgentPageRow":{"type":"object","description":"One row in the pages-by-agent breakdown. Returned by\n[`ProxyLogService::get_ai_agent_pages`] for a single named agent.\n`unique_ips` counts distinct client IPs that hit this path via that agent\n(same definition as the per-agent unique-IPs in [`AiAgentBreakdownRow`]).","required":["path","request_count","unique_ips"],"properties":{"last_seen":{"type":["string","null"],"description":"Last-seen timestamp in RFC3339 format, or `None` if no rows matched.","example":"2026-05-29T12:00:00Z"},"path":{"type":"string"},"request_count":{"type":"integer","format":"int64"},"unique_ips":{"type":"integer","format":"int64"}}},"AiAgentPagesResponse":{"type":"object","description":"Response wrapping the per-agent pages breakdown rows.","required":["agent","items","start_time","end_time"],"properties":{"agent":{"type":"string","description":"The agent name this breakdown is scoped to."},"end_time":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/AiAgentPageRow"}},"start_time":{"type":"string"}}},"AiAgentTimelineResponse":{"type":"object","description":"Response wrapping the AI agent timeline rows.","required":["items","start_time","end_time","bucket","group_by"],"properties":{"bucket":{"type":"string","description":"Bucket interval used for the buckets (so the UI can label the x-axis).","example":"1 hour"},"end_time":{"type":"string"},"group_by":{"type":"string","description":"Echoes the grouping dimension actually applied.","example":"provider"},"items":{"type":"array","items":{"$ref":"#/components/schemas/AiAgentTimelineRow"}},"start_time":{"type":"string"}}},"AiAgentTimelineRow":{"type":"object","description":"One point in the AI-agent timeline: the request count for a single\n(`bucket`, `key`) pair, where `key` is a provider or agent name depending on\nthe requested grouping. The UI pivots these into one stacked series per\n`key` across the shared bucket x-axis.","required":["bucket","key","request_count"],"properties":{"bucket":{"type":"string","description":"Bucket start in RFC3339 format.","example":"2026-05-29T12:00:00Z"},"key":{"type":"string","description":"Provider or agent name this count belongs to.","example":"OpenAI"},"request_count":{"type":"integer","format":"int64"}}},"AiChatLimitsSettings":{"type":"object","description":"Bounds on one AI chat turn.\n\nA turn is bounded by TIME rather than by a number of steps. A step count\nsays nothing about cost or about how long someone has been watching a\nspinner, and it cuts short exactly the long, productive turns the chat\nexists for. The user can already see each tool call and press Stop; the\ndeadline is what guarantees an *unattended* turn still ends.\n\nThe right value is a property of the model, which is why it is configurable\nrather than compiled in: a full alert-suggestion turn takes ~10 minutes\nagainst a slow local model and seconds against a hosted one.","properties":{"turn_timeout_secs":{"type":"integer","format":"int32","description":"How long one turn may run before it is stopped and the partial answer\nreturned, in seconds. The user is told the turn was cut short.\n\nChecked between steps, not mid-call: a model round already in flight\nfinishes, so a turn can overrun by up to one round. Against a slow\nself-hosted model that is a minute or two. Aborting mid-stream would cut\nthe answer off in the middle of a sentence and throw away work already\npaid for, which is worse than a late stop.","default":900,"example":900,"maximum":3600,"minimum":30}}},"AiConfigSettings":{"type":"object","description":"Global AI configuration settings. Controls the default config repo\ncontaining `.claude/` directory (skills, MCP servers, plugins) that\ngets overlaid into every agent sandbox.","properties":{"config_repo":{"type":"string","description":"Global config repo URL in \"owner/repo\" format (e.g. \"myorg/claude-config\").\nCloned at agent run time and overlaid into the sandbox's `.claude/` directory.","default":"","example":""},"config_repo_branch":{"type":"string","description":"Branch of the config repo to use.","default":"main","example":"main"}}},"AiPageBreakdownResponse":{"type":"object","description":"Response wrapping the AI page breakdown rows.","required":["items","start_time","end_time"],"properties":{"end_time":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/AiPageBreakdownRow"}},"start_time":{"type":"string"}}},"AiPageBreakdownRow":{"type":"object","description":"One row in the AI-crawled-pages breakdown. `agent_count` is the number of\n*distinct* AI agents that hit this path, so the UI can show both how heavily\nand how broadly a page is being crawled.","required":["path","request_count","agent_count"],"properties":{"agent_count":{"type":"integer","format":"int64"},"last_seen":{"type":["string","null"],"description":"Last-seen timestamp in RFC3339 format, or `None` if no rows matched.","example":"2026-05-29T12:00:00Z"},"path":{"type":"string"},"request_count":{"type":"integer","format":"int64"}}},"AiStatusBreakdownResponse":{"type":"object","description":"Response wrapping the AI status breakdown rows.","required":["items","start_time","end_time"],"properties":{"end_time":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/AiStatusBreakdownRow"}},"start_time":{"type":"string"}}},"AiStatusBreakdownRow":{"type":"object","description":"One row in the AI-agent HTTP status breakdown: the request count for a\nstatus class (`2xx`/`3xx`/`4xx`/`5xx`/`other`) across crawler traffic.","required":["status_class","request_count"],"properties":{"request_count":{"type":"integer","format":"int64"},"status_class":{"type":"string","description":"Status class label.","example":"2xx"}}},"AlarmListResponse":{"type":"object","description":"Paginated list of alarms.","required":["items","total","page","page_size"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AlarmResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"AlarmResponse":{"type":"object","description":"Full alarm representation returned by list/summary endpoints.","required":["id","project_id","alarm_type","severity","status","title","fired_at","created_at","updated_at"],"properties":{"acknowledged_at":{"type":["string","null"],"description":"ISO-8601 UTC timestamp when the alarm was acknowledged, if any."},"acknowledged_by":{"type":["integer","null"],"format":"int32","description":"User ID who acknowledged the alarm, if any."},"alarm_type":{"type":"string"},"container_id":{"type":["integer","null"],"format":"int32"},"created_at":{"type":"string","description":"ISO-8601 UTC timestamp when the row was created."},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"fired_at":{"type":"string","description":"ISO-8601 UTC timestamp when the alarm fired."},"id":{"type":"integer","format":"int32"},"message":{"type":["string","null"]},"metadata":{"description":"Arbitrary JSON metadata attached by the alarm source."},"project_id":{"type":"integer","format":"int32"},"resolved_at":{"type":["string","null"],"description":"ISO-8601 UTC timestamp when the alarm was resolved, if any."},"service_id":{"type":["integer","null"],"format":"int32"},"severity":{"type":"string"},"status":{"type":"string"},"title":{"type":"string"},"updated_at":{"type":"string","description":"ISO-8601 UTC timestamp when the row was last updated."}}},"AlarmSummaryResponse":{"type":"object","description":"Re-export AlarmSummary for the OpenAPI schema.","required":["total_active","firing","acknowledged","critical","warning","by_type"],"properties":{"acknowledged":{"type":"integer","format":"int32","minimum":0},"by_type":{"type":"object","additionalProperties":{"type":"integer","format":"int32","minimum":0},"propertyNames":{"type":"string"}},"critical":{"type":"integer","format":"int32","minimum":0},"firing":{"type":"integer","format":"int32","minimum":0},"total_active":{"type":"integer","format":"int32","minimum":0},"warning":{"type":"integer","format":"int32","minimum":0}}},"AlertRuleResponse":{"type":"object","required":["id","project_id","name","trigger_type","trigger_config","notification_priority","cooldown_minutes","enabled","created_at","updated_at"],"properties":{"cooldown_minutes":{"type":"integer","format":"int32"},"created_at":{"type":"string"},"enabled":{"type":"boolean"},"environment_filter":{"type":["integer","null"],"format":"int32"},"error_level_filter":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"notification_priority":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"trigger_config":{},"trigger_type":{"type":"string"},"updated_at":{"type":"string"}}},"AllocEntry":{"type":"object","description":"Wire-format allocation. `null` in the JSON when the node hasn't been\nallocated yet — workers should treat that as \"single-host mode, do\nnot bring up the overlay\".","required":["node_id","compute_cidr","bridge_address","underlay_address"],"properties":{"bridge_address":{"type":"string"},"compute_cidr":{"type":"string"},"node_id":{"type":"string","description":"Stable v5 UUID derived from the database node id."},"underlay_address":{"type":"string"}}},"AnalyticsSessionEventsResponse":{"type":"object","required":["session_id","events","total_events"],"properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/SessionEvent"}},"session_id":{"type":"string"},"total_events":{"type":"integer","minimum":0}}},"AnnotatedSpan":{"type":"object","description":"A single span annotated with the project that originally stored it.\nUsed in `UnifiedTrace` to let the UI colour-code spans by project.","required":["project_id","project_name","span"],"properties":{"project_id":{"type":"integer","format":"int32","description":"The project that stored this span (same as `span.project_id`)."},"project_name":{"type":"string","description":"Human-readable project name for waterfall colour-coding and legend."},"span":{"$ref":"#/components/schemas/SpanRecord","description":"Original span data verbatim from storage."}}},"AnomalyAlgorithm":{"type":"string","description":"Anomaly baseline algorithm. Adding one (e.g. a new robust variant) is a\ncode-only enum addition — no migration, since it lives inside the blob.","enum":["robust","basic","agile","ewma"]},"AnomalyParams":{"type":"object","description":"Seasonal anomaly-band detector parameters (stub — not yet evaluated).","properties":{"algorithm":{"$ref":"#/components/schemas/AnomalyAlgorithm","description":"Baseline model. `robust` is the default (seasonal, stable, flags level\nshifts); `ewma`/`agile` adopt level shifts; `basic` is non-seasonal."},"baseline_lookback_days":{"type":["integer","null"],"format":"int32","description":"How far back to build the baseline. `None` = an evaluator default."},"deviations":{"type":"number","format":"double","description":"Band width in robust standard deviations (Datadog's `bounds`)."},"direction":{"$ref":"#/components/schemas/Direction","description":"Which side(s) of the band a deviation must be on to count."},"pct_anomalous":{"type":"number","format":"double","description":"Fraction (0..=1) of points in the window that must be anomalous to fire."},"seasonality":{"$ref":"#/components/schemas/Seasonality","description":"Seasonality model for the baseline."}}},"AnomalyPreviewPointResponse":{"type":"object","required":["bucket","value","lower","upper","breaching"],"properties":{"breaching":{"type":"boolean"},"bucket":{"type":"string","example":"2025-10-12T12:15:47Z"},"lower":{"type":"number","format":"double","description":"Lower edge of the expected band at this point."},"upper":{"type":"number","format":"double","description":"Upper edge of the expected band at this point."},"value":{"type":"number","format":"double"}}},"AnomalyPreviewRequest":{"type":"object","required":["project_id","metric_name","aggregation","window_secs","detection_config"],"properties":{"aggregation":{"type":"string","description":"One of `avg|sum|min|max|count|rate|p50|p90|p95|p99`."},"detection_config":{"$ref":"#/components/schemas/DetectionConfig","description":"The detector to backtest. `static` and `anomaly` are supported — the\nkinds the evaluator actually runs."},"end_time":{"type":["string","null"],"description":"RFC 3339; defaults to now.","example":"2025-10-12T12:15:47Z"},"metric_name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"start_time":{"type":["string","null"],"description":"RFC 3339; defaults to 7 days before `end_time`.","example":"2025-10-12T12:15:47Z"},"window_secs":{"type":"integer","format":"int32"}}},"AnomalyPreviewResponse":{"type":"object","required":["points","breach_count","baseline_samples","sufficient"],"properties":{"baseline_samples":{"type":"integer","format":"int64","description":"Baseline sample count (drives the `sufficient` flag)."},"breach_count":{"type":"integer","format":"int64","description":"How many points in the range would have fired."},"points":{"type":"array","items":{"$ref":"#/components/schemas/AnomalyPreviewPointResponse"}},"sufficient":{"type":"boolean","description":"Whether the baseline had enough history for a trustworthy band."}}},"ApiKeyListResponse":{"type":"object","required":["api_keys","total"],"properties":{"api_keys":{"type":"array","items":{"$ref":"#/components/schemas/ApiKeyResponse"}},"total":{"type":"integer","format":"int64","minimum":0}}},"ApiKeyResponse":{"type":"object","required":["id","name","key_prefix","role_type","is_active","created_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00Z"},"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"key_prefix":{"type":"string"},"last_used_at":{"type":["string","null"],"format":"date-time","example":"2024-01-01T00:00:00Z"},"name":{"type":"string"},"permissions":{"type":["array","null"],"items":{"type":"string"}},"role_type":{"type":"string"}}},"AppSettings":{"type":"object","description":"Application settings stored in the database\nAll fields have sensible defaults for easy onboarding","properties":{"agent_sandbox":{"oneOf":[{"$ref":"#/components/schemas/AgentSandboxSettings"}],"default":{"default_provider":"claude_cli","providers":{},"auth_type":"subscription","api_key_encrypted":null,"enabled":true,"runtime":"node","custom_image":"","cpu_limit":4.0,"memory_limit_mb":8192,"network_mode":"full","sandbox_backend":null}},"ai_chat_limits":{"oneOf":[{"$ref":"#/components/schemas/AiChatLimitsSettings","description":"Limits on a single AI chat turn. Operator-tunable because the right\nvalue depends on the model: a turn against a slow self-hosted model can\nlegitimately take ten minutes, while a hosted one finishes in seconds\nand a shorter ceiling keeps costs predictable."}],"default":{"turn_timeout_secs":900}},"ai_config":{"oneOf":[{"$ref":"#/components/schemas/AiConfigSettings"}],"default":{"config_repo":"","config_repo_branch":"main"}},"build_limits":{"oneOf":[{"$ref":"#/components/schemas/BuildLimitsSettings","description":"Build-time resource limits applied on the control plane to prevent\n`docker build` from saturating host CPU/RAM. Worker nodes are\nintentionally NOT subject to these limits (each worker is dedicated\nhardware that already has its own per-host headroom)."}],"default":{"max_concurrent":2,"cpu_limit_cores":0.0,"memory_limit_mb":0}},"cluster_dns":{"oneOf":[{"$ref":"#/components/schemas/ClusterDnsSettings","description":"Cluster-DNS resolver settings (ADR-024, experimental beta). Off by\ndefault — see `ClusterDnsSettings` for the incident background and\ntrade-offs. Must be explicitly enabled by operators who need\n`*.temps.local` service-to-service resolution inside containers."}],"default":{"enabled":false}},"console_version":{"type":["string","null"],"description":"Binary version tag (e.g. \"v0.1.0\") of the *console* process\n(`temps serve`, role=all or role=console) that last started. Written\non console startup; read by the standalone `temps proxy` to detect\nversion skew during a rolling upgrade (ADR-017 Phase 3). `None` on\ninstalls that never ran a console build carrying this field.\n\nThis is informational state written by the binary itself — NOT an\noperator-tunable setting. It is intentionally absent from\n`AppSettingsResponse` and the PATCH path so an operator cannot\naccidentally overwrite the self-recorded value.","default":null},"container_logs":{"oneOf":[{"$ref":"#/components/schemas/ContainerLogSettings"}],"default":{"max_size":"50m","max_file":3,"service_max_size":"20m","service_max_file":3}},"disk_space_alert":{"oneOf":[{"$ref":"#/components/schemas/DiskSpaceAlertSettings"}],"default":{"enabled":true,"threshold_percent":80,"check_interval_seconds":300,"monitor_path":null}},"dns_provider":{"oneOf":[{"$ref":"#/components/schemas/DnsProviderSettings"}],"default":{"provider":"manual","cloudflare_api_key":null}},"docker_registry":{"oneOf":[{"$ref":"#/components/schemas/DockerRegistrySettings"}],"default":{"enabled":false,"registry_url":null,"username":null,"password":null,"tls_verify":true,"ca_certificate":null}},"edge_target":{"type":["string","null"],"description":"Public edge target that generated DNS records point at when a managed\ndomain opts into automatic record sync. An IPv4/IPv6 address produces an\n`A`/`AAAA` record; anything else is treated as a `CNAME` target. `None`\ndisables DNS record sync regardless of per-domain opt-in.","default":null},"external_url":{"type":["string","null"],"default":null},"insecure_tls":{"type":"boolean","description":"Skip TLS certificate verification on outbound HTTP clients built by the\nserver (deployer, agent, remote service client). Strictly opt-in for\noperators running self-signed control plane / worker certs on a trusted\ninternal network. Worker→control-plane traffic that traverses the public\ninternet must keep this `false` — otherwise a MitM steals the join token.","default":false},"internal_url":{"type":["string","null"],"description":"URL that service containers use to reach the Temps API from *inside*\nthe Docker network (OTLP metrics ingest, agent callbacks, etc.). On\nDocker Desktop this defaults to `http://host.docker.internal:`;\non Linux it requires the `host.docker.internal:host-gateway` host\nmapping (which Temps adds to provisioned containers). Distinct from\n`external_url`, which is the public-facing address.","default":null},"letsencrypt":{"oneOf":[{"$ref":"#/components/schemas/LetsEncryptSettings"}],"default":{"email":null,"environment":"production"}},"monitoring":{"oneOf":[{"$ref":"#/components/schemas/MonitoringSettings","description":"Metrics observability settings. Controls the MetricsStore backend,\nscrape interval, and tiered retention windows."}],"default":{"enabled":false,"store":"timescale_db","scrape_interval_secs":30,"retention_raw_days":7,"retention_hourly_days":90,"retention_daily_years":2,"clickhouse_url":null}},"multi_node":{"oneOf":[{"$ref":"#/components/schemas/MultiNodeSettings"}],"default":{"join_token_hash":null,"private_address":null,"legacy_shared_token_enabled":true,"cluster_ca_cert_pem":null,"cluster_ca_key_encrypted":null,"require_mtls":false,"node_cpu_alert_percent":90.0,"node_memory_alert_percent":90.0,"node_disk_alert_percent":90.0}},"observability_compression":{"oneOf":[{"$ref":"#/components/schemas/ObservabilityCompressionSettings","description":"TimescaleDB compression delays for immutable observability data.\nChanges are applied at runtime by the Settings API."}],"default":{"proxy_logs_after_hours":24,"otel_spans_after_hours":24}},"observability_retention":{"oneOf":[{"$ref":"#/components/schemas/ObservabilityRetentionSettings","description":"Retention windows for raw proxy and OpenTelemetry telemetry.\nTimescaleDB policies are updated at runtime by the Settings API."}],"default":{"proxy_logs_days":30,"otel_spans_days":90,"otel_logs_days":90,"otel_metrics_days":90}},"on_demand_tls":{"oneOf":[{"$ref":"#/components/schemas/OnDemandTlsSettings"}],"default":{"enabled":false,"zone":null,"max_concurrent":3,"hourly_cap":10,"deployment_url_mode":"http"}},"preview_domain":{"type":"string","default":"localho.st"},"preview_gateway":{"oneOf":[{"$ref":"#/components/schemas/PreviewGatewaySettings"}],"default":{"image":"ghcr.io/gotempsh/temps-preview-gateway:latest","host_port":8090,"auto_upgrade":true}},"rate_limiting":{"oneOf":[{"$ref":"#/components/schemas/RateLimitSettings"}],"default":{"enabled":false,"max_requests_per_minute":60,"max_requests_per_hour":1000,"whitelist_ips":[],"blacklist_ips":[]}},"require_mfa_for_admins":{"type":"boolean","description":"When `true`, any user holding the `Admin` role must have MFA enrolled\n(`users.mfa_enabled = true`) to complete a **password** login. Users\nwithout MFA enrolled are rejected with a typed error instructing them\nto enroll before retrying. This only gates the password-login path\n(`AuthService::login`) -- SSO/OIDC logins are handled by a separate\ncode path (`OidcService::resolve_user` + `oidc_handler`) and are\nintentionally unaffected, since federating identity to a\nproperly-hardened IdP is itself an acceptable alternative to local\nTOTP MFA. Modeled as a settings row (not an env var) per CLAUDE.md so\nan operator can flip it at runtime via the Settings API without\nrestarting the binary.","default":false},"screenshots":{"oneOf":[{"$ref":"#/components/schemas/ScreenshotSettings"}],"default":{"enabled":false,"provider":"local","url":""}},"security_headers":{"oneOf":[{"$ref":"#/components/schemas/SecurityHeadersSettings"}],"default":{"enabled":false,"preset":"moderate","content_security_policy":"default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self'; frame-ancestors 'self'","x_frame_options":"SAMEORIGIN","x_content_type_options":"nosniff","x_xss_protection":"1; mode=block","strict_transport_security":"max-age=31536000; includeSubDomains","referrer_policy":"strict-origin-when-cross-origin","permissions_policy":"geolocation=(), microphone=(), camera=()"}},"setup_complete":{"type":"boolean","description":"Set to `true` by `temps setup` (all modes) once initial configuration\nhas been applied. The web onboarding wizard reads this from the server\nand skips itself when true, preventing the \"Configure Base Domain\" wall\nfrom appearing on installs that were already configured via the CLI.","default":false}}},"AppSettingsResponse":{"type":"object","description":"Safe response for application settings that masks sensitive fields","required":["preview_domain","screenshots","letsencrypt","dns_provider","security_headers","rate_limiting","docker_registry","disk_space_alert","container_logs","agent_sandbox","ai_config","preview_gateway","multi_node","monitoring","observability_compression","observability_retention","effective_metrics_store","effective_observability_store","insecure_tls","setup_complete","require_mfa_for_admins","cluster_dns","build_limits","ai_chat_limits"],"properties":{"agent_sandbox":{"$ref":"#/components/schemas/AgentSandboxSettingsMasked"},"ai_chat_limits":{"$ref":"#/components/schemas/AiChatLimitsSettings","description":"Per-turn limits for the AI chat. No sensitive content."},"ai_config":{"$ref":"#/components/schemas/AiConfigSettings"},"build_limits":{"$ref":"#/components/schemas/BuildLimitsSettings","description":"Build-time resource limits (control-plane only). No sensitive content,\npassed through as-is."},"cluster_dns":{"$ref":"#/components/schemas/ClusterDnsSettings","description":"Cluster-DNS resolver settings (ADR-024, experimental beta). No masking\nneeded — `enabled` is a plain bool with no sensitive content. Passed\nthrough as-is so the settings UI can read and toggle the flag."},"container_logs":{"$ref":"#/components/schemas/ContainerLogSettings"},"disk_space_alert":{"$ref":"#/components/schemas/DiskSpaceAlertSettings"},"dns_provider":{"$ref":"#/components/schemas/DnsProviderSettingsMasked"},"docker_registry":{"$ref":"#/components/schemas/DockerRegistrySettingsMasked"},"edge_target":{"type":["string","null"],"description":"Public edge target that synced DNS records point at (IP → A/AAAA, else CNAME)."},"effective_metrics_store":{"$ref":"#/components/schemas/MetricsStoreKind","description":"The storage backend the runtime is **actually** using for metrics,\nafter reconciling the `monitoring.store` toggle with the server's\n`TEMPS_CLICKHOUSE_*` configuration. When `monitoring.store` is\n`click_house` but those env vars are not fully set, the runtime falls\nback to TimescaleDB — in that case this reports `timescale_db` even\nthough `monitoring.store` says `click_house`. The UI shows this as the\neffective backend and warns when it diverges from the configured store."},"effective_observability_store":{"$ref":"#/components/schemas/MetricsStoreKind","description":"Storage backend actually used for proxy logs, OTel spans, and OTel\nmetrics. OTel logs remain TimescaleDB-backed. Unlike resource metrics,\nthese domains switch to ClickHouse whenever the server-level ClickHouse\nconnection is configured; they do not use the monitoring store toggle."},"external_url":{"type":["string","null"]},"insecure_tls":{"type":"boolean"},"internal_url":{"type":["string","null"]},"letsencrypt":{"$ref":"#/components/schemas/LetsEncryptSettings"},"monitored_services_count":{"type":["integer","null"],"format":"int64","description":"Number of enabled, running services the MetricsScraper currently\nincludes. Used for the lightweight storage estimate in the UI.","minimum":0},"monitoring":{"$ref":"#/components/schemas/MonitoringSettingsMasked"},"multi_node":{"$ref":"#/components/schemas/MultiNodeSettingsMasked"},"observability_compression":{"$ref":"#/components/schemas/ObservabilityCompressionSettings","description":"TimescaleDB compression delays for immutable proxy logs and OTel spans."},"observability_retention":{"$ref":"#/components/schemas/ObservabilityRetentionSettings","description":"Retention windows for raw proxy logs and OpenTelemetry data."},"preview_domain":{"type":"string"},"preview_gateway":{"$ref":"#/components/schemas/PreviewGatewaySettingsMasked"},"rate_limiting":{"$ref":"#/components/schemas/RateLimitSettings"},"require_mfa_for_admins":{"type":"boolean","description":"When enabled, Admin-role accounts without MFA enrolled are rejected\nat password login (bherila/temps#32). SSO/OIDC logins are unaffected."},"screenshots":{"$ref":"#/components/schemas/ScreenshotSettings"},"security_headers":{"$ref":"#/components/schemas/SecurityHeadersSettings"},"setup_complete":{"type":"boolean","description":"Whether `temps setup` has been run at least once. The web onboarding\nwizard checks this field on load and skips itself when true."}}},"ApplyHostnameModeRequest":{"type":"object","description":"Request to apply a hostname mode (recompute + optional DNS sync).","required":["mode"],"properties":{"mode":{"type":"string","description":"Target mode to apply: `\"standard\"` or `\"flat\"`."},"sync_dns":{"type":"boolean","description":"Also reconcile the provider's DNS zone for the affected hostnames."}}},"ArchiveFlagResponse":{"type":"object","required":["key"],"properties":{"archived_at":{"type":["string","null"]},"key":{"type":"string"}}},"ArchiveMode":{"type":"string","enum":["off","on","always","unknown"]},"AssignRoleRequest":{"type":"object","required":["user_id","role_type"],"properties":{"role_type":{"type":"string"},"user_id":{"type":"integer","format":"int32"}}},"AttachScheduleServicesRequest":{"type":"object","description":"Body for `POST /api/backups/schedules/{id}/services` — attach external\nservices to a backup schedule. Idempotent.","required":["service_ids"],"properties":{"service_ids":{"type":"array","items":{"type":"integer","format":"int32"},"description":"External service ids to attach. Duplicates are de-duplicated server-side."}}},"AttachScheduleServicesResponse":{"type":"object","description":"Response for `POST /api/backups/schedules/{id}/services`.","required":["inserted","total_attached"],"properties":{"inserted":{"type":"integer","format":"int64","description":"Number of rows actually inserted (excludes rows skipped by\n`ON CONFLICT DO NOTHING`).","minimum":0},"total_attached":{"type":"integer","description":"Total number of services now attached to the schedule.","minimum":0}}},"AuditLogIpInfo":{"type":"object","description":"IP address information in audit log","required":["ip"],"properties":{"city":{"type":["string","null"],"description":"City name","example":"San Francisco"},"country":{"type":["string","null"],"description":"Country code","example":"US"},"ip":{"type":"string","description":"IP address","example":"192.168.1.1"},"latitude":{"type":["number","null"],"format":"double","description":"Latitude","example":37.7749},"longitude":{"type":["number","null"],"format":"double","description":"Longitude","example":122.4194}}},"AuditLogResponse":{"type":"object","description":"Response type for audit log entries","required":["id","operation_type","audit_date"],"properties":{"audit_date":{"type":"integer","format":"int64","description":"When the action occurred","example":11932193},"data":{"description":"Additional context about the action"},"id":{"type":"integer","format":"int32","description":"Unique identifier for the audit log entry"},"ip_address":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AuditLogIpInfo","description":"IP address details"}]},"operation_type":{"type":"string","description":"The type of action that was performed","example":"USER_LOGIN"},"user":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AuditLogUserInfo","description":"User details who performed the action"}]},"user_id":{"type":["integer","null"],"format":"int32","description":"The user who performed the action (`null` when that account has\nsince been deleted; `data` retains the original actor context)"}}},"AuditLogUserInfo":{"type":"object","description":"User information in audit log","required":["id","name","email"],"properties":{"email":{"type":"string","description":"User's email","example":"john.doe@example.com"},"id":{"type":"integer","format":"int32","description":"User ID"},"name":{"type":"string","description":"User's name","example":"John Doe"}}},"AuthFlavorDto":{"type":"object","description":"One auth flavor surfaced to the UI. Mirrors `AuthFlavor` in the catalog\nbut without the seed-path / env-var fields the frontend doesn't need\n(those are server-side only — exposing them just bloats the response).","required":["id","label","description","format"],"properties":{"description":{"type":"string"},"env_var":{"type":["string","null"],"description":"For `api_key` format: the env var name that will be set inside the\nsandbox. Useful for showing the user \"we'll set OPENAI_API_KEY\" so\nthey know what their key controls."},"format":{"type":"string","description":"`api_key`, `oauth_token`, or `config_file` — drives which input UI\nthe settings page renders (single-line vs. multi-line textarea)."},"id":{"type":"string"},"label":{"type":"string"}}},"AuthResponse":{"type":"object","required":["success","message","mfa_required"],"properties":{"message":{"type":"string"},"mfa_required":{"type":"boolean"},"success":{"type":"boolean"},"user_id":{"type":["integer","null"],"format":"int32"}}},"AuthStatusResponse":{"type":"object","required":["status"],"properties":{"cli_token":{"type":["string","null"]},"status":{"type":"string"}}},"AuthTokenResponse":{"type":"object","required":["access_token","refresh_token","expires_at"],"properties":{"access_token":{"type":"string"},"expires_at":{"type":"integer","format":"int64"},"refresh_token":{"type":"string"}}},"AutoWatchParams":{"type":"object","description":"Auto-watch (Watchdog-style) detector parameters (stub — not evaluated).","properties":{"direction":{"$ref":"#/components/schemas/Direction","description":"The engine self-tunes the band; the user supplies only the direction."}}},"AutofixRunConfig":{"type":"object","description":"User-chosen per-run options, persisted as JSON in `agent_runs.run_config`.\nEvery field is optional — unset fields fall back to the provider defaults\nin settings, then to built-in defaults.","properties":{"branch":{"type":["string","null"],"description":"Branch to clone instead of the project's main branch.","default":null},"max_turns":{"type":["integer","null"],"format":"int32","description":"Per-run turn cap applied to every phase of this run. Only enforced\nfor CLIs with a turn flag (Claude Code); Codex/OpenCode run to\ncompletion. `None` uses the provider's per-phase defaults.","default":null},"model":{"type":["string","null"],"description":"Model id for the chosen provider. `None` uses the provider's saved\ndefault model, or the CLI's own default.","default":null},"provider":{"type":["string","null"],"description":"AI provider id (\"claude_cli\", \"codex_cli\", \"opencode\"). `None` uses\nthe platform default provider from agent sandbox settings.","default":null}}},"AutofixerRunResponse":{"type":"object","required":["id","project_id","status","tokens_input","tokens_output","files_changed","created_at"],"properties":{"ai_model":{"type":["string","null"]},"ai_output":{"type":["string","null"]},"ai_provider":{"type":["string","null"],"description":"AI provider slug this run executes with (e.g. claude_cli, codex_cli)."},"analysis":{"type":["string","null"]},"branch_name":{"type":["string","null"]},"completed_at":{"type":["string","null"]},"created_at":{"type":"string"},"error_message":{"type":["string","null"]},"files_changed":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"phase":{"type":["string","null"]},"pr_number":{"type":["integer","null"],"format":"int32"},"pr_url":{"type":["string","null"]},"project_id":{"type":"integer","format":"int32"},"run_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AutofixRunConfig","description":"Per-run options the run was started with; used to prefill the\nretry / start-over dialog."}]},"started_at":{"type":["string","null"]},"status":{"type":"string"},"tokens_input":{"type":"integer","format":"int32"},"tokens_output":{"type":"integer","format":"int32"},"trigger_source_id":{"type":["integer","null"],"format":"int32"},"user_context":{"type":["string","null"]}}},"AutofixerRunWithLogsResponse":{"type":"object","required":["run","logs"],"properties":{"logs":{"type":"array","items":{"$ref":"#/components/schemas/AgentRunLogResponse"}},"run":{"$ref":"#/components/schemas/AutofixerRunResponse"}}},"AvailableContainerInfo":{"type":"object","description":"Available Docker container that can be imported as a service","required":["container_id","container_name","image","version","service_type","is_running"],"properties":{"container_id":{"type":"string","description":"Container ID or name","example":"abc123def456"},"container_name":{"type":"string","description":"Container display name","example":"my-postgres"},"exposed_ports":{"type":"array","items":{"type":"integer","format":"int32","minimum":0},"description":"Exposed ports (e.g., [5432] for PostgreSQL, [6379] for Redis)"},"image":{"type":"string","description":"Docker image name (e.g., \"gotempsh/postgres-walg:18-bookworm\")","example":"gotempsh/postgres-walg:18-bookworm"},"is_running":{"type":"boolean","description":"Whether the container is currently running","example":true},"service_type":{"$ref":"#/components/schemas/ServiceTypeRoute","description":"Service type this container represents"},"version":{"type":"string","description":"Extracted version from image","example":"18"}}},"AvailablePermissions":{"type":"object","description":"Response containing all available permissions for frontend validation","required":["permissions","roles"],"properties":{"permissions":{"type":"array","items":{"$ref":"#/components/schemas/PermissionInfo"},"description":"All available permissions in the system"},"roles":{"type":"array","items":{"$ref":"#/components/schemas/RoleInfo"},"description":"All available roles"}}},"BackupAlertListResponse":{"type":"object","description":"Response body for the list-backup-alerts endpoint.","required":["alerts"],"properties":{"alerts":{"type":"array","items":{"$ref":"#/components/schemas/BackupAlertResponse"},"description":"All currently open (unresolved) alerts, newest first."}}},"BackupAlertResponse":{"type":"object","description":"A single open backup alert surfaced in the UI banner.\n\nAlerts are auto-opened by the watcher and auto-resolved when the triggering\ncondition clears. No manual dismiss is required or supported.\n\nThe optional `schedule_s3_source_id` field is included so the UI can\ndeep-link an `overdue_schedule` alert to the S3 source detail page that\nhosts the schedule. `stalled_job` alerts no longer carry a deep-link\ntarget — the alert message text contains the backup id for display.","required":["id","kind","severity","message","opened_at"],"properties":{"id":{"type":"integer","format":"int64","description":"Database id of the alert row."},"kind":{"type":"string","description":"`\"overdue_schedule\"` or `\"stalled_job\"`."},"message":{"type":"string","description":"Human-readable description of the alert condition."},"opened_at":{"type":"string","description":"RFC 3339 timestamp when the alert was opened.","example":"2026-05-15T10:00:00Z"},"schedule_id":{"type":["integer","null"],"format":"int32","description":"FK to `backup_schedules.id`. Set for `overdue_schedule` alerts."},"schedule_name":{"type":["string","null"],"description":"Human-readable name of the linked schedule, if applicable."},"schedule_s3_source_id":{"type":["integer","null"],"format":"int32","description":"FK to `backup_schedules.s3_source_id`. The UI uses this to deep-link\nthe alert to the S3 source detail page that hosts the schedule.\nSet for `overdue_schedule` alerts."},"severity":{"type":"string","description":"`\"warning\"` or `\"critical\"`."}}},"BackupResponse":{"type":"object","description":"Response type for backup","required":["id","name","backup_id","backup_type","state","started_at","s3_source_id","s3_location","metadata","compression_type","created_by","tags"],"properties":{"attempts":{"type":["integer","null"],"format":"int32","description":"How many times this job has been claimed and run. `null` for legacy\nbackups with no `backup_jobs` row."},"backup_id":{"type":"string"},"backup_type":{"type":"string"},"checksum":{"type":["string","null"]},"completed_at":{"type":["integer","null"],"format":"int64"},"compression_type":{"type":"string"},"created_by":{"type":"integer","format":"int32"},"current_step":{"type":["string","null"],"description":"Name of the engine step currently executing (e.g., `\"walg_push\"`).\n`null` when no `backup_jobs` row exists for this backup (legacy rows\npre-dating ADR-014), or when the job has not yet completed its first step."},"error_message":{"type":["string","null"]},"expires_at":{"type":["integer","null"],"format":"int64"},"external_service":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ExternalServiceSummary","description":"External service that owns this backup (Redis, Postgres, etc.).\n`null` for control-plane backups (the Temps server's own database)."}]},"file_count":{"type":["integer","null"],"format":"int32"},"id":{"type":"integer","format":"int32"},"live_size_bytes":{"type":["integer","null"],"format":"int64","description":"Best-effort partial size while a backup is still running, computed\nby listing the S3 prefix. Null when the backup is finished\n(`size_bytes` is authoritative in that case)."},"max_attempts":{"type":["integer","null"],"format":"int32","description":"Maximum attempts before the job is permanently failed. `null` for\nlegacy backups."},"max_runtime_secs":{"type":["integer","null"],"format":"int64","description":"Resolved wall-clock timeout for this backup job (seconds). `null` for\nlegacy backups. Derived from the three-tier resolution order:\ncaller override → schedule override → engine default."},"metadata":{},"name":{"type":"string"},"s3_location":{"type":"string"},"s3_source_id":{"type":"integer","format":"int32"},"schedule_id":{"type":["integer","null"],"format":"int32"},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Final size of the backup once completed. Null while running."},"started_at":{"type":"integer","format":"int64"},"state":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}}}},"BackupScheduleResponse":{"type":"object","description":"Response type for backup schedule","required":["id","name","backup_type","retention_period","s3_source_id","schedule_expression","enabled","created_at","updated_at","tags","target_all_services","include_control_plane"],"properties":{"backup_type":{"type":"string"},"created_at":{"type":"integer","format":"int64"},"description":{"type":["string","null"]},"enabled":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"include_control_plane":{"type":"boolean","description":"When `true`, every run also produces a `control_plane` backup\n(Temps's own Postgres). When `false`, only the external service\nfan-out happens."},"last_run":{"type":["integer","null"],"format":"int64"},"max_runtime_secs":{"type":["integer","null"],"format":"int64","description":"Per-schedule wall-clock timeout override for backup jobs (seconds).\n`null` means the engine-family default is used. See\n`temps_backup_core::timeouts::default_max_runtime_secs`."},"name":{"type":"string"},"next_run":{"type":["integer","null"],"format":"int64"},"retention_period":{"type":"integer","format":"int32"},"s3_source_id":{"type":"integer","format":"int32"},"schedule_expression":{"type":"string","example":"0 0 * * *"},"tags":{"type":"array","items":{"type":"string"}},"target_all_services":{"type":"boolean","description":"When `true`, the schedule auto-includes every external service on\nthe host (and any future ones). When `false`, the schedule only\ntargets services attached via `backup_schedule_services`."},"updated_at":{"type":"integer","format":"int64"}}},"BitbucketAuthInput":{"oneOf":[{"type":"object","description":"Personal / Workspace / Repository Access Token.","required":["token","type"],"properties":{"token":{"type":"string","description":"The Bitbucket access token value."},"type":{"type":"string","enum":["access_token"]}}},{"type":"object","description":"HTTP Basic / App Password authentication.","required":["username","password","type"],"properties":{"password":{"type":"string","description":"App password generated in Bitbucket security settings."},"type":{"type":"string","enum":["app_password"]},"username":{"type":"string","description":"Bitbucket account username."}}}],"description":"Authentication input for a Bitbucket Cloud provider. Use `access_token` for\na Repository or Workspace Access Token (PAT), or `username` + `app_password`\nfor App Password (HTTP Basic) authentication."},"BlobResponse":{"type":"object","description":"Response after uploading a blob","required":["url","pathname","contentType","size","uploadedAt"],"properties":{"contentType":{"type":"string","description":"Content type of the blob","example":"image/png"},"pathname":{"type":"string","description":"Original pathname","example":"images/avatar-abc123.png"},"size":{"type":"integer","format":"int64","description":"Size in bytes","example":12345},"uploadedAt":{"type":"string","format":"date-time","description":"Upload timestamp","example":"2025-01-03T12:00:00Z"},"url":{"type":"string","description":"URL path to access the blob","example":"/api/blob/123/images/avatar-abc123.png"}}},"BlobStatusResponse":{"type":"object","description":"Response for Blob service status","required":["enabled","healthy"],"properties":{"docker_image":{"type":["string","null"],"description":"Docker image being used","example":"ghcr.io/rustfs/rustfs:0.5.0"},"enabled":{"type":"boolean","description":"Whether the Blob service is enabled","example":true},"healthy":{"type":"boolean","description":"Whether the service is healthy","example":true},"version":{"type":["string","null"],"description":"Current version (if running)","example":"0.5.0"}}},"BranchInfo":{"type":"object","required":["name","commit_sha","protected"],"properties":{"commit_sha":{"type":"string"},"name":{"type":"string"},"protected":{"type":"boolean"}}},"BranchListResponse":{"type":"object","required":["branches"],"properties":{"branches":{"type":"array","items":{"$ref":"#/components/schemas/BranchInfo"}}}},"BrowserCount":{"type":"object","required":["browser","count","percentage"],"properties":{"browser":{"type":"string"},"count":{"type":"integer","format":"int64"},"percentage":{"type":"number","format":"double"}}},"BrowsersQuery":{"type":"object","required":["start_date","end_date","project_id"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"BuildConfiguration":{"type":"object","description":"Build configuration (for building images from source)","required":["context","args"],"properties":{"args":{"type":"object","description":"Build arguments","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"context":{"type":"string","description":"Build context (Dockerfile path or buildpack)"},"dockerfile":{"type":["string","null"],"description":"Dockerfile path (relative to context)"},"target":{"type":["string","null"],"description":"Target stage (for multi-stage builds)"}}},"BuildLimitsSettings":{"type":"object","description":"Control-plane build resource limits.\n\nCaps how many builds run concurrently AND how much CPU/memory each build\nis allowed to consume. A single global semaphore in the deployer crate\ngates every `DockerRuntime::build_image` call to `max_concurrent`. When\nthe semaphore is full, additional builds queue and wait — they do not\nfail. Per-build CPU/memory caps are forwarded to Docker via\n`BuildImageOptions { memory, cpuquota, cpuperiod }`.\n\n`cpu_limit_cores = 0.0` or `memory_limit_mb = 0` means \"no explicit cap\"\n— fall back to the legacy 50%-of-host heuristic for backwards\ncompatibility with operators who never visit the settings page.","properties":{"cpu_limit_cores":{"type":"number","format":"float","description":"CPU cores allowed per build (float, e.g. 2.0 = 2 cores, 0.5 = half\na core). 0 means \"use the legacy 50%-of-host default\".","default":0.0,"example":2.0,"minimum":0},"max_concurrent":{"type":"integer","format":"int32","description":"Maximum number of `docker build` operations allowed to run at the\nsame time on the control plane. Additional builds queue. Min 1.","default":2,"example":2,"minimum":1},"memory_limit_mb":{"type":"integer","format":"int32","description":"Memory allowed per build, in megabytes. 0 means \"use the legacy\n50%-of-host default\". Docker enforces this as a hard cap — builds\nthat exceed it OOM-kill.","default":0,"example":2048,"minimum":0}}},"CancelBackupResponse":{"type":"object","description":"Response body for cancel endpoints.","required":["cancelled"],"properties":{"cancelled":{"type":"integer","format":"int64","description":"Number of rows that were actually flipped to `failed`. `0` is a valid\nsuccess and means the backup was already terminal — the call is\nidempotent.","minimum":0}}},"CertStatusResponse":{"type":"object","description":"Current on-demand cert status for a single hostname (ADR-018 §5). Backs\n`GET /domains/by-host/{hostname}/cert-status`.","required":["hostname"],"properties":{"backoff_until":{"type":["integer","null"],"format":"int64","description":"On-demand negative-cache deadline (epoch millis), when in backoff."},"hostname":{"type":"string","description":"SNI hostname."},"last_attempt":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/OnDemandCertAttemptResponse","description":"The most recent on-demand issuance attempt for this hostname, if any."}]},"status":{"type":["string","null"],"description":"Current cert lifecycle status from the `domains` row, when one exists."}}},"ChallengeConfig":{"type":"object","description":"Challenge configuration (future feature)\nFor CAPTCHA, JS challenges, proof-of-work, etc.","required":["challengeType","difficulty"],"properties":{"challengeType":{"type":"string","description":"Challenge type: \"captcha\", \"js_challenge\", \"proof_of_work\""},"difficulty":{"type":"integer","format":"int32","description":"Challenge difficulty level (1-10)","minimum":0},"protectedPaths":{"type":"array","items":{"type":"string"},"description":"Paths that require challenges"}}},"ChallengeError":{"type":"object","required":["type","detail","status"],"properties":{"detail":{"type":"string","description":"Human-readable error description"},"status":{"type":"integer","format":"int32","description":"HTTP status code"},"type":{"type":"string","description":"Error type (e.g., \"urn:ietf:params:acme:error:unauthorized\")"}}},"ChallengeValidationStatus":{"type":"object","required":["type","url","status","token"],"properties":{"error":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ChallengeError","description":"Error details if validation failed"}]},"status":{"type":"string","description":"Challenge status (e.g., \"pending\", \"valid\", \"invalid\")"},"token":{"type":"string","description":"Challenge token"},"type":{"type":"string","description":"Challenge type (e.g., \"dns-01\", \"http-01\")"},"url":{"type":"string","description":"Challenge validation URL"},"validated":{"type":["string","null"],"description":"When the challenge was validated (if successful)"}}},"ChangePasswordRequest":{"type":"object","required":["current_password","new_password"],"properties":{"current_password":{"type":"string","example":"current_password_value"},"mfa_code":{"type":["string","null"],"description":"TOTP code (or recovery code). Required iff the user has MFA enabled.","example":"123456"},"new_password":{"type":"string","example":"new_password_value"},"revoke_other_sessions":{"type":"boolean","description":"When true, every session OTHER than the one making this request is\nrevoked. Defaults to false; the UI surfaces this as a checkbox."}}},"ChangeProjectSourceRequest":{"type":"object","description":"Change a project's source type to a Git-less type (docker_image /\nstatic_files / manual). Switching TO `git` is done via the Git settings\nendpoint (which also supplies the repository + provider connection).","required":["source_type"],"properties":{"source_type":{"$ref":"#/components/schemas/SourceType"}}},"ChatCompletionChoice":{"type":"object","required":["index","message"],"properties":{"finish_reason":{"type":["string","null"]},"index":{"type":"integer","format":"int32"},"message":{"$ref":"#/components/schemas/ChatMessage"}}},"ChatCompletionRequest":{"allOf":[{"type":["object","null"],"description":"Tolerates extra SDK fields (stream_options, logprobs, etc.)","additionalProperties":{},"propertyNames":{"type":"string"}},{"type":"object","required":["model","messages"],"properties":{"frequency_penalty":{"type":["number","null"],"format":"double"},"max_tokens":{"type":["integer","null"],"format":"int64"},"messages":{"type":"array","items":{"$ref":"#/components/schemas/ChatMessage"}},"model":{"type":"string"},"n":{"type":["integer","null"],"format":"int32"},"presence_penalty":{"type":["number","null"],"format":"double"},"response_format":{},"seed":{"type":["integer","null"],"format":"int64"},"stop":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/StopSequence"}]},"stream":{"type":"boolean"},"temperature":{"type":["number","null"],"format":"double"},"tool_choice":{},"tools":{"type":["array","null"],"items":{}},"top_p":{"type":["number","null"],"format":"double"},"user":{"type":["string","null"]}}}],"description":"OpenAI-compatible chat completion request.\nUses `deny_unknown_fields = false` (serde default) so that SDK-specific\nfields like `stream_options`, `logprobs`, `top_logprobs`, `logit_bias`,\n`parallel_tool_calls`, etc. are silently accepted without breaking."},"ChatCompletionResponse":{"type":"object","required":["id","object","created","model","choices"],"properties":{"choices":{"type":"array","items":{"$ref":"#/components/schemas/ChatCompletionChoice"}},"created":{"type":"integer","format":"int64"},"id":{"type":"string"},"model":{"type":"string"},"object":{"type":"string"},"usage":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/UsageInfo"}]}}},"ChatMessage":{"type":"object","required":["role"],"properties":{"content":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/MessageContent"}]},"name":{"type":["string","null"]},"role":{"type":"string"},"tool_call_id":{"type":["string","null"]},"tool_calls":{"type":["array","null"],"items":{}}}},"ChatReadinessResponse":{"type":"object","description":"What still has to be true before an AI chat can run a turn in this project.\n\nThe three gates are independent and fail for different reasons with different\nfixes, so they are reported separately rather than collapsed into one boolean:\nan instance admin configures a provider (instance-wide), while the two toggles\nare per-project. Collapsing them would leave the user with \"AI unavailable\"\nand no idea which of three places to go.","required":["ai_configured","chat_enabled","write_actions_enabled"],"properties":{"ai_configured":{"type":"boolean","description":"An AI provider is configured on this instance. Fixed in\nSettings → AI Providers; instance-wide, not per project."},"chat_enabled":{"type":"boolean","description":"The per-project read-only chat toggle is on (the default)."},"write_actions_enabled":{"type":"boolean","description":"The per-project write-actions opt-in is on. Required for any flow where\nthe assistant *proposes* changes; irrelevant for read-only questions."}}},"ChildBackupEntryResponse":{"type":"object","description":"A single child backup entry in the `GET /backups/{id}/children` response.\n\nEach entry corresponds to one `external_service_backups` row joined with\n`external_services`, providing service metadata without a second request.","required":["id","service_id","service_name","service_type","state","backup_type","started_at","s3_location","compression_type"],"properties":{"backup_type":{"type":"string","description":"Backup variant (e.g. \"full\", \"incremental\")."},"compression_type":{"type":"string","description":"Compression algorithm used (e.g. \"gzip\", \"lz4\")."},"error_message":{"type":["string","null"],"description":"Engine-reported error message when `state = \"failed\"`."},"finished_at":{"type":["string","null"],"description":"When the child backup finished, if known.","example":"2025-01-15T14:35:00.456Z"},"id":{"type":"integer","format":"int32","description":"Row ID from `external_service_backups`."},"s3_location":{"type":"string","description":"Object key or `s3://` URL where the backup data lives."},"service_id":{"type":"integer","format":"int32","description":"FK to `external_services.id`."},"service_name":{"type":"string","description":"Human-readable name of the external service (e.g. \"redis-prod\")."},"service_type":{"type":"string","description":"Service type string (e.g. \"postgres\", \"redis\", \"mongodb\", \"s3\").","example":"postgres"},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Size of the child backup in bytes, if available."},"started_at":{"type":"string","description":"When the child backup started (RFC 3339).","example":"2025-01-15T14:30:00.123Z"},"state":{"type":"string","description":"Current state: \"pending\" | \"running\" | \"completed\" | \"failed\"."}}},"ChildBackupListResponse":{"type":"object","description":"Response body for `GET /backups/{id}/children`.\n\nReturns an empty `children` list (not 404) when the parent backup has no\nchild records (e.g. control-plane backups).","required":["children"],"properties":{"children":{"type":"array","items":{"$ref":"#/components/schemas/ChildBackupEntryResponse"},"description":"Zero or more child backup entries ordered by `external_service_backups.id` ASC."}}},"CleanupExpiredBackupsRequest":{"type":"object","properties":{"expected_backup_ids":{"type":["array","null"],"items":{"type":"string"},"description":"Exact candidates returned by the dry run. Execution fails if the\nretention selection has changed since preview."}}},"CliDeviceApproveRequest":{"type":"object","required":["user_code"],"properties":{"user_code":{"type":"string"}}},"CliDeviceApproveResponse":{"type":"object","required":["user_code","status"],"properties":{"status":{"type":"string"},"user_code":{"type":"string"}}},"CliDeviceLookupResponse":{"type":"object","required":["user_code","status","expires_at"],"properties":{"client_name":{"type":["string","null"]},"expires_at":{"type":"string","format":"date-time"},"requested_ip":{"type":["string","null"]},"status":{"type":"string","description":"`pending` | `approved` | `denied` | `expired`."},"user_code":{"type":"string"}}},"CliDevicePollRequest":{"type":"object","required":["device_code"],"properties":{"device_code":{"type":"string"}}},"CliDevicePollResponse":{"oneOf":[{"type":"object","description":"Still waiting on the user to approve in the browser.","required":["status"],"properties":{"status":{"type":"string","enum":["authorization_pending"]}}},{"type":"object","description":"CLI is polling faster than the server-suggested interval.","required":["status"],"properties":{"status":{"type":"string","enum":["slow_down"]}}},{"type":"object","description":"User denied the request in the browser.","required":["status"],"properties":{"status":{"type":"string","enum":["access_denied"]}}},{"type":"object","description":"The session has expired without approval.","required":["status"],"properties":{"status":{"type":"string","enum":["expired_token"]}}},{"type":"object","description":"The session was approved; this is the only response that carries\nthe API key. The key is returned exactly once and then cleared\nfrom the session row.","required":["user_id","email","role","api_key","key_prefix","status"],"properties":{"api_key":{"type":"string"},"email":{"type":"string"},"expires_at":{"type":["string","null"],"format":"date-time"},"key_prefix":{"type":"string"},"role":{"type":"string"},"status":{"type":"string","enum":["approved"]},"user_id":{"type":"integer","format":"int32"}}}]},"CliDeviceStartRequest":{"type":"object","properties":{"client_name":{"type":["string","null"],"description":"Friendly hostname / client identifier shown in the browser approval\nscreen. Sanitized before display.","example":"dviejo-mac.local"}}},"CliDeviceStartResponse":{"type":"object","required":["device_code","user_code","verification_uri","verification_uri_complete","expires_in","interval"],"properties":{"device_code":{"type":"string","description":"Opaque secret the CLI polls with. Never display to a human."},"expires_in":{"type":"integer","format":"int64","description":"Seconds until the device_code expires."},"interval":{"type":"integer","format":"int64","description":"Suggested polling interval, in seconds."},"user_code":{"type":"string","description":"Short human-readable code the user types into the browser.","example":"ABCD-1234"},"verification_uri":{"type":"string","description":"Base verification URL — the CLI may display this when the\npre-filled URL is too long to be useful.","example":"https://temps.example.com/cli-login"},"verification_uri_complete":{"type":"string","description":"`verification_uri` with `user_code` pre-filled. Open this directly.","example":"https://temps.example.com/cli-login/ABCD-1234"}}},"CliLoginRequest":{"type":"object","required":["username","password"],"properties":{"password":{"type":"string"},"username":{"type":"string"}}},"CloudProvider":{"type":"string","description":"Cloud provider detected from node metadata","enum":["aws","gcp","azure","hetzner","digitalocean","other"]},"CloudflareConfig":{"type":"object","description":"Configuration for a Cloudflare Email Sending notification provider.\n\nNotifications are delivered through Cloudflare's transactional Email Sending\nAPI. Only the account, token, sender and recipients are configured here —\nsubject and body are derived from each notification.","required":["account_id","api_token","from_address","to_addresses"],"properties":{"account_id":{"type":"string","description":"Cloudflare account id that owns the Email Sending configuration.","example":"023e105f4ecef8ad9ca31a8372d0c353"},"api_token":{"type":"string","description":"Cloudflare API token with the Email Sending permission. Encrypted at\nrest and masked in normal API responses."},"from_address":{"type":"string","description":"Verified sender address (must belong to a domain enabled for Cloudflare\nEmail Sending).","example":"welcome@infracf.example.com"},"from_name":{"type":["string","null"],"description":"Optional human-friendly sender name shown in the recipient's inbox."},"to_addresses":{"type":"array","items":{"type":"string"},"description":"Recipients that should receive the notification."}}},"ClusterCapacity":{"type":"object","description":"Total cluster capacity (sum of node allocatable resources)","required":["node_count","cpu_millis","memory_mb"],"properties":{"cpu_millis":{"type":"integer","format":"int64","description":"Total allocatable CPU in millicores"},"memory_mb":{"type":"integer","format":"int64","description":"Total allocatable memory in MB"},"node_count":{"type":"integer","description":"Number of nodes","minimum":0}}},"ClusterDnsSettings":{"type":"object","description":"Cluster-DNS resolver settings (ADR-024, experimental beta).\n\nWhen `enabled`, the Temps control plane starts a Hickory DNS resolver and\ninjects it as the first nameserver into every deployed container via\n`HostConfig.Dns` — giving containers the ability to resolve `*.temps.local`\nFQDNs for service-to-service communication. Worker nodes pick this flag up\nfrom the `/api/internal/nodes/{id}/network/peers` wire response and gate\ntheir own per-node resolver the same way.\n\n**Default: `false` (disabled).**\n\nWhy disabled by default: a production incident showed that when the injected\nHickory resolver was slow or transiently unresponsive for a non-`*.temps.local`\n(external) hostname, glibc's resolver cycled through all three nameservers\n(`172.20.0.1`, `1.1.1.1`, `8.8.8.8`) at ~5 s timeout × 2 attempts each,\ncausing 22–27 s delays for outbound TCP connections. Disabling the injection\nrestores Docker's embedded DNS as the sole resolver, eliminating that failure\nmode. Operators running single/multi-node installs that depend on\n`*.temps.local` resolution must explicitly opt in by setting `enabled: true`.\n\n`bool` defaults to `false` in Rust and JSON (`#[serde(default)]`), so the\nsafe-off behaviour is automatic for new installs and legacy settings rows.","properties":{"enabled":{"type":"boolean","description":"Master switch. When `false` (default), no custom DNS is injected into\ncontainers — they use Docker's embedded DNS which forwards to the host's\nown `resolv.conf`. When `true`, the control-plane Hickory resolver is\nstarted and its bridge IP is injected as the first nameserver so\n`*.temps.local` FQDNs resolve inside containers.","default":false,"example":false}}},"ClusterHealthReportResponse":{"type":"object","description":"Response body for `GET /external-services/{id}/cluster-health`.","required":["checked_at","monitor_response_ms","members"],"properties":{"checked_at":{"type":"string","description":"ISO-8601 wall-clock when the report was generated.","example":"2025-10-12T12:15:47.609192Z"},"members":{"type":"array","items":{"$ref":"#/components/schemas/ClusterMemberHealthResponse"}},"monitor_error":{"type":["string","null"],"description":"Set when the monitor itself was unreachable. UI shows a banner."},"monitor_response_ms":{"type":"integer","format":"int64","description":"Round-trip to query the monitor (ms)."}}},"ClusterMemberHealthResponse":{"type":"object","description":"One row in the cluster Members table — see `GET /external-services/{id}/cluster-health`.","required":["nodename","nodehost","nodeport","reported_state","goal_state","health","seconds_since_report","candidate_priority","replication_quorum"],"properties":{"candidate_priority":{"type":"integer","format":"int32"},"goal_state":{"type":"string","description":"What the monitor *wants* the node to be. Differs from\n`reported_state` mid-transition (failover, demotion, etc.)."},"health":{"type":"integer","format":"int32","description":"pg_auto_failover liveness signal: `1` healthy, `0` unknown\n(no recent report), `-1` unhealthy."},"nodehost":{"type":"string"},"nodename":{"type":"string"},"nodeport":{"type":"integer","format":"int32"},"replay_lag_ms":{"type":["integer","null"],"format":"int64","description":"`replay_lag` from `pg_stat_replication`, in milliseconds."},"replication_quorum":{"type":"boolean"},"reported_state":{"type":"string","description":"What the node *last told the monitor* it was. Stale during outages."},"seconds_since_report":{"type":"integer","format":"int64","description":"Wall-clock seconds since the node last reported in."},"sync_state":{"type":["string","null"],"description":"`sync` / `quorum` / `async` for secondaries; `null` for the primary."}}},"ClusterMemberRequest":{"type":"object","description":"Request spec for a single cluster member.","required":["role"],"properties":{"node_id":{"type":["integer","null"],"format":"int32","description":"Target worker node ID. Omit or null to run on the control plane."},"role":{"type":"string","description":"Service-type-specific role (e.g., \"monitor\", \"primary\", \"replica\")","example":"primary"}}},"CmdBody":{"type":"object","required":["command"],"properties":{"args":{"type":"array","items":{"type":"string"},"description":"Arguments to pass to the binary. Defaults to empty."},"command":{"type":"string","description":"Binary name (argv[0]) — e.g. `\"ls\"`, `\"node\"`. The SDK sends this\nseparately from `args`."},"cwd":{"type":["string","null"],"description":"Working directory override."},"env":{"type":"object","description":"Extra env vars.","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"sudo":{"type":"boolean","description":"When true, the SDK runs the command privileged. We ignore it today\n— the underlying provider always runs as the sandbox's own user."},"wait":{"type":"boolean","description":"When true, the response is an `application/x-ndjson` stream where\nthe first line is the running-command envelope and the second line\nis the finished-command envelope with `exitCode`."}}},"CmdInner":{"type":"object","description":"Inner `command` object — matches the SDK's zod validator exactly.\n`exitCode` is `null` until the command terminates; `startedAt` is Unix\nepoch milliseconds.","required":["id","name","args","cwd","sandboxId","startedAt"],"properties":{"args":{"type":"array","items":{"type":"string"}},"cwd":{"type":"string"},"exitCode":{"type":["integer","null"],"format":"int32"},"id":{"type":"string"},"name":{"type":"string"},"sandboxId":{"type":"string"},"startedAt":{"type":"integer","format":"int64"}}},"CmdKillBody":{"type":"object","description":"SDK-shaped kill body. The SDK sends `{signal: AbortSignal}` but only\nuses the signal for HTTP request abortion client-side; there's no\nsignal name on the wire.","properties":{"force":{"type":"boolean","description":"Optional: when true, SIGKILL instead of SIGTERM."}}},"CmdResponse":{"type":"object","description":"`@vercel/sandbox` envelope: `{ command: {...} }`.","required":["command"],"properties":{"command":{"$ref":"#/components/schemas/CmdInner"}}},"CommitExistsResponse":{"type":"object","required":["exists"],"properties":{"commit":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/CommitInfo","description":"Commit metadata when the requested SHA exists."}]},"commit_sha":{"type":["string","null"]},"exists":{"type":"boolean"}}},"CommitInfo":{"type":"object","required":["sha","message","author","author_email","date"],"properties":{"author":{"type":"string","description":"Author name"},"author_email":{"type":"string","description":"Author email"},"date":{"type":"string","format":"date-time","description":"Commit date in ISO 8601 format","example":"2025-10-12T12:15:47.609192Z"},"message":{"type":"string","description":"Commit message"},"sha":{"type":"string","description":"Commit SHA hash"}}},"CommitListResponse":{"type":"object","required":["commits"],"properties":{"commits":{"type":"array","items":{"$ref":"#/components/schemas/CommitInfo"}}}},"Comparator":{"type":"string","description":"Comparator for static/forecast threshold detectors. Serializes to the\nkeyword forms `gt|gte|lt|lte` (NOT the SQL operators used by\n`temps-monitoring::compare`).","enum":["gt","gte","lt","lte"]},"ComposePublicPort":{"type":"object","description":"A port that should be exposed publicly through the proxy for a compose service.","required":["service","port"],"properties":{"port":{"type":"integer","format":"int32","description":"Container port to expose (e.g. 8123)","minimum":0},"service":{"type":"string","description":"Compose service name (e.g. \"web\", \"clickhouse\")"}}},"ConnectionListQuery":{"type":"object","properties":{"direction":{"type":["string","null"]},"page":{"type":["integer","null"],"format":"int64","minimum":0},"per_page":{"type":["integer","null"],"format":"int64","minimum":0},"sort":{"type":["string","null"]}}},"ConnectionListResponse":{"type":"object","required":["connections","total_count","page","per_page"],"properties":{"connections":{"type":"array","items":{"$ref":"#/components/schemas/ConnectionResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"per_page":{"type":"integer","format":"int64","minimum":0},"total_count":{"type":"integer","minimum":0}}},"ConnectionResponse":{"type":"object","required":["id","provider_id","account_name","account_type","is_active","is_expired","syncing","synced_repository_count","health_status","consecutive_health_failures","created_at","updated_at"],"properties":{"account_name":{"type":"string"},"account_type":{"type":"string"},"consecutive_health_failures":{"type":"integer","format":"int32"},"created_at":{"type":"string","format":"date-time"},"health_message":{"type":["string","null"],"description":"Human-readable reason when health_status is \"unhealthy\"; null otherwise."},"health_status":{"type":"string","description":"Current health status: \"healthy\", \"unhealthy\", or \"unknown\"."},"id":{"type":"integer","format":"int32"},"installation_id":{"type":["string","null"]},"is_active":{"type":"boolean"},"is_expired":{"type":"boolean"},"last_health_check_at":{"type":["string","null"],"format":"date-time"},"last_synced_at":{"type":["string","null"],"format":"date-time"},"provider_id":{"type":"integer","format":"int32"},"synced_repository_count":{"type":"integer","format":"int32","description":"Running count of repositories persisted by the current (or most\nrecent) sync. Resets to 0 when a new sync begins; useful for showing\nlive progress on large syncs."},"syncing":{"type":"boolean"},"updated_at":{"type":"string","format":"date-time"},"user_id":{"type":["integer","null"],"format":"int32"}}},"ConnectionTestResult":{"type":"object","description":"Connection test result","required":["success","message"],"properties":{"message":{"type":"string"},"success":{"type":"boolean"}}},"ConsoleEventPayload":{"type":"object","description":"Payload for server-side event ingestion via the console API.\n\nThe app backend reads the encrypted `_temps_visitor_id` and `_temps_sid`\ncookie values from the user's request and forwards them here.\nTemps decrypts them server-side to resolve visitor/session identity.","required":["event_name","environment_id","deployment_id"],"properties":{"deployment_id":{"type":"integer","format":"int32","description":"Deployment ID to attribute the event to"},"environment_id":{"type":"integer","format":"int32","description":"Environment ID to attribute the event to"},"event_data":{"description":"Arbitrary JSON event data"},"event_name":{"type":"string","description":"Event name (e.g. \"purchase\", \"signup\", custom event names)"},"request_path":{"type":"string","description":"Page path context (defaults to \"/\")"},"request_query":{"type":"string","description":"Query string context"},"session_id":{"type":["string","null"],"description":"Encrypted `_temps_sid` cookie value from the user's browser"},"visitor_id":{"type":["string","null"],"description":"Encrypted `_temps_visitor_id` cookie value from the user's browser"}}},"ContainerActionResponse":{"type":"object","description":"Response indicating success of container state change","required":["container_id","container_name","action","status","message"],"properties":{"action":{"type":"string"},"container_id":{"type":"string"},"container_name":{"type":"string"},"message":{"type":"string"},"status":{"type":"string"}}},"ContainerDetailResponse":{"type":"object","description":"Detailed container information with environment variables and metrics","required":["id","container_id","container_name","image_name","status","deployment_id","created_at","deployed_at","container_port","environment_variables"],"properties":{"container_id":{"type":"string"},"container_name":{"type":"string"},"container_port":{"type":"integer","format":"int32","description":"Port inside the container"},"cpu_limit_cores":{"type":["number","null"],"format":"double","description":"CPU limit in whole cores (e.g. 1.0). None when no limit is configured."},"created_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"deployed_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"deployment_id":{"type":"integer","format":"int32"},"environment_variables":{"type":"array","items":{"$ref":"#/components/schemas/EnvVarResponse"},"description":"Environment variables (sensitive values masked)"},"error_message":{"type":["string","null"],"description":"Free-form error string from Docker's container state on exit."},"exit_code":{"type":["integer","null"],"format":"int32","description":"Process exit code reported by Docker. None while still running."},"exit_reason":{"type":["string","null"],"description":"Human-readable reason the container exited."},"finished_at":{"type":["string","null"],"description":"When the container exited (Docker's FinishedAt). None while running.","example":"2025-10-12T12:16:47.609192Z"},"host_port":{"type":["integer","null"],"format":"int32","description":"Port on the host machine"},"id":{"type":"integer","format":"int32"},"image_name":{"type":"string"},"oom_killed":{"type":["boolean","null"],"description":"True when Docker's OOM killer terminated the container."},"ready_at":{"type":["string","null"],"example":"2025-10-12T12:16:47.609192Z"},"resource_limits":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ResourceLimitsResponse","description":"Resource limits"}]},"restart_count":{"type":["integer","null"],"format":"int64","description":"Container restart count from Docker"},"service_name":{"type":["string","null"],"description":"Compose service name (e.g. \"web\", \"redis\"). None for single-container deployments."},"service_url":{"type":["string","null"],"description":"Per-service URL for compose deployments"},"started_at":{"type":["string","null"],"description":"When the container's main process most recently started.","example":"2025-10-12T12:15:50.000000Z"},"status":{"type":"string"}}},"ContainerEnvironmentVariableValueResponse":{"type":"object","required":["value"],"properties":{"value":{"type":"string"}}},"ContainerInfoResponse":{"type":"object","required":["container_id","container_name","image_name","status","created_at"],"properties":{"container_id":{"type":"string"},"container_name":{"type":"string"},"cpu_limit_cores":{"type":["number","null"],"format":"double","description":"CPU limit in whole cores (e.g. 1.0). None when no limit is configured."},"created_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"error_message":{"type":["string","null"],"description":"Free-form error string from Docker's container state on exit."},"exit_code":{"type":["integer","null"],"format":"int32","description":"Process exit code reported by Docker. None while still running."},"exit_reason":{"type":["string","null"],"description":"Human-readable reason the container exited (e.g. \"OOMKilled\",\n\"Killed by SIGKILL (exit code 137)\", \"Exit code 1\"). None while running."},"finished_at":{"type":["string","null"],"description":"When the container exited (Docker's FinishedAt). None while running.","example":"2025-10-12T12:16:47.609192Z"},"image_name":{"type":"string"},"node_name":{"type":["string","null"],"description":"Node name where this container is running. None for local (single-node) deployments."},"oom_killed":{"type":["boolean","null"],"description":"True when Docker's OOM killer terminated the container."},"restart_count":{"type":["integer","null"],"format":"int64","description":"Container restart count from Docker. The UI shows a chip when this is\n> 0 so a crash loop is visible without opening detail."},"service_name":{"type":["string","null"],"description":"Compose service name (e.g. \"web\", \"redis\"). None for single-container deployments."},"service_url":{"type":["string","null"],"description":"Per-service URL for compose deployments (e.g. \"https://web-myapp.localho.st\")"},"started_at":{"type":["string","null"],"description":"When the container's main process most recently started. The UI uses\nthis for the uptime label so the count resets when a container is\nrestarted in place. None for containers that never started.","example":"2025-10-12T12:15:50.000000Z"},"status":{"type":"string"}}},"ContainerInventoryItem":{"type":"object","description":"A container reported by the agent during heartbeat reconciliation.","required":["container_id","container_name"],"properties":{"container_id":{"type":"string","description":"Docker container ID"},"container_name":{"type":"string","description":"Docker container name"}}},"ContainerListResponse":{"type":"object","required":["containers","total"],"properties":{"containers":{"type":"array","items":{"$ref":"#/components/schemas/ContainerInfoResponse"}},"total":{"type":"integer","minimum":0}}},"ContainerLogSettings":{"type":"object","description":"Docker container log rotation settings\nControls the `--log-opt max-size` and `--log-opt max-file` for containers","properties":{"max_file":{"type":"integer","format":"int32","description":"Maximum number of rotated log files to keep (e.g., 3 means up to 3 x max_size total)","default":3,"example":3,"minimum":0},"max_size":{"type":"string","description":"Maximum size of each log file (e.g., \"50m\", \"100m\", \"1g\")\nDocker default is unlimited; we default to \"50m\" to prevent disk exhaustion","default":"50m","example":"50m"},"service_max_file":{"type":"integer","format":"int32","description":"Maximum rotated log files for external service containers","default":3,"example":3,"minimum":0},"service_max_size":{"type":"string","description":"Maximum size for external service container logs (postgres, redis, etc.)\nDefaults to \"20m\" since services are typically less verbose than app containers","default":"20m","example":"20m"}}},"ContainerLogsQuery":{"type":"object","properties":{"container_name":{"type":["string","null"],"description":"Optional container name to get logs from (if deployment has multiple containers)"},"end_date":{"type":["integer","null"],"format":"int64"},"follow":{"type":"boolean","description":"Follow log output in real-time (default: true for backward compatibility)"},"start_date":{"type":["integer","null"],"format":"int64"},"tail":{"type":["string","null"]},"timestamps":{"type":"boolean","description":"Include timestamps in log output (default: false)"}}},"ContainerMetricHistoryPoint":{"type":"object","description":"One bucketed data point of a container resource metric time series.","required":["time","value"],"properties":{"time":{"type":"string","description":"Bucket timestamp (ISO 8601 with `Z` suffix).","example":"2025-10-12T12:15:00+00:00"},"value":{"type":"number","format":"double","description":"Averaged metric value for the bucket."}}},"ContainerMetricsHistoryQuery":{"type":"object","description":"Query parameters for the container metrics history endpoint.","required":["metric"],"properties":{"metric":{"type":"string","description":"Dotted metric name, e.g. `container.cpu_percent` or\n`container.memory_used_bytes`."},"range":{"type":"string","description":"Time window: `1h`, `6h`, `24h`, or `7d` (defaults to `1h`)."}}},"ContainerMetricsResponse":{"type":"object","description":"Container resource metrics (CPU, memory usage)","required":["container_id","container_name","cpu_percent","memory_bytes","network_rx_bytes","network_tx_bytes","timestamp"],"properties":{"container_id":{"type":"string"},"container_name":{"type":"string"},"cpu_limit_cores":{"type":["number","null"],"format":"double","description":"CPU limit in whole cores (e.g. 1.0). None = no limit."},"cpu_percent":{"type":"number","format":"double","description":"CPU usage as a multi-core percentage (Docker convention: 200 = 2 cores\nfully pinned). Divide by 100 to get cores used."},"memory_bytes":{"type":"integer","format":"int64","description":"Memory usage in bytes","minimum":0},"memory_limit_bytes":{"type":["integer","null"],"format":"int64","description":"Memory limit in bytes (if set)","minimum":0},"memory_percent":{"type":["number","null"],"format":"double","description":"Memory usage percentage (0-100) if limit is set"},"network_rx_bytes":{"type":"integer","format":"int64","description":"Network bytes received","minimum":0},"network_tx_bytes":{"type":"integer","format":"int64","description":"Network bytes transmitted","minimum":0},"timestamp":{"type":"string","description":"Timestamp of metrics collection","example":"2025-10-12T12:15:47.609192Z"}}},"ContainerResponse":{"type":"object","required":["name","container_type","can_contain_containers","can_contain_entities","metadata"],"properties":{"can_contain_containers":{"type":"boolean","description":"Can this container hold other containers?","example":true},"can_contain_entities":{"type":"boolean","description":"Can this container hold entities (tables, collections, etc.)?","example":false},"child_container_type":{"type":["string","null"],"description":"Type of child containers (if can_contain_containers is true)","example":"schema"},"container_type":{"type":"string","description":"Container type (database, schema, keyspace, bucket, etc.)","example":"database"},"entity_count_hint":{"type":["string","null"],"description":"Hint for UI on expected entity count (small = sidebar, large = pagination)","example":"large"},"entity_type_label":{"type":["string","null"],"description":"Label for entity type (if can_contain_entities is true)","example":"table"},"metadata":{"description":"Additional metadata"},"name":{"type":"string","description":"Container name","example":"mydb"}}},"ContainerRuntimeInfo":{"type":"object","description":"Snapshot of a container's lifecycle state from `docker inspect`.\n`restart_count` and `oom_killed` are the load-bearing fields when\ndiagnosing crash loops — the kernel OOM killer never reaches the\napplication's logs, so seeing `oom_killed=true` is the only signal\nthat a memory limit was the cause.","required":["role","container_name","resource_limits"],"properties":{"container_id":{"type":["string","null"],"description":"Container Docker id, when present. None = container does not exist\n(was never created or was removed externally)."},"container_name":{"type":"string","description":"Stable name of the Docker container (e.g. `postgres-mydb`)."},"exit_code":{"type":["integer","null"],"format":"int64","description":"Last container exit code, when known. Non-zero = unclean stop."},"finished_at":{"type":["string","null"],"description":"ISO-8601 timestamp of the most recent termination, when known."},"image":{"type":["string","null"],"description":"Currently-effective Docker image (e.g. `gotempsh/postgres-walg:18-bookworm`)."},"oom_killed":{"type":["boolean","null"],"description":"True when the container's last termination was caused by the\nkernel OOM killer. Set if the user enabled hard memory limits\nand the working set exceeded them."},"resource_limits":{"$ref":"#/components/schemas/ServiceResourceLimits","description":"Currently-applied resource limits read off the container's\n`HostConfig`. Compare this against the user-configured limits to\ndetect drift (an old container that never picked up new caps)."},"restart_count":{"type":["integer","null"],"format":"int64","description":"Total restarts since the container was created. Useful for\ndetecting crash loops — a steady stream means something is killing\nthe container repeatedly (frequently OOM)."},"role":{"type":"string","description":"`service_members.role` for cluster members; \"standalone\" otherwise."},"started_at":{"type":["string","null"],"description":"ISO-8601 timestamp of when the container last started. None when\nit has never started (i.e. created but never run)."},"status":{"type":["string","null"],"description":"Bollard container state (\"running\", \"exited\", \"dead\", etc.). None\nwhen the container does not exist."}}},"ContainerStatsSample":{"type":"object","description":"Live resource usage sample for a single container.\n\n`cpu_percent` is computed by Docker's standard formula:\n ((cpu_delta / system_delta) * online_cpus) * 100\n`memory_percent` is `(memory_usage / memory_limit) * 100` — when no\nmemory limit is set the limit reported by Docker is the host's total\nRAM, so a 5% reading means \"5% of host RAM\", not \"5% of allocated\".","required":["role","container_name"],"properties":{"container_name":{"type":"string"},"cpu_percent":{"type":["number","null"],"format":"double","description":"CPU usage as a percentage. `None` when the container is not running\n(Docker returns no usable counters)."},"memory_limit_bytes":{"type":["integer","null"],"format":"int64","description":"Memory limit in bytes (host RAM if no limit set).","minimum":0},"memory_percent":{"type":["number","null"],"format":"double","description":"Memory usage as a percentage of `memory_limit_bytes`."},"memory_usage_bytes":{"type":["integer","null"],"format":"int64","description":"Resident memory usage in bytes.","minimum":0},"online_cpus":{"type":["integer","null"],"format":"int32","description":"Number of cores Docker observed at sample time. Used by the UI\nto label \"x/y cores\" instead of just a percent.","minimum":0},"role":{"type":"string"}}},"ContentPart":{"type":"object","required":["type"],"properties":{"image_url":{},"text":{"type":["string","null"]},"type":{"type":"string"}}},"ContextLine":{"type":"object","description":"A line in context response","required":["timestamp","level","message","line_offset","is_match"],"properties":{"fields":{},"is_match":{"type":"boolean","description":"Whether this line matched the original search"},"level":{"$ref":"#/components/schemas/LogLevel"},"line_offset":{"type":"integer","format":"int32"},"message":{"type":"string"},"timestamp":{"type":"string"}}},"ContextLogsRequest":{"type":"object","required":["chunk_id","line_offset"],"properties":{"chunk_id":{"type":"string"},"line_offset":{"type":"integer","format":"int32"},"lines":{"type":["integer","null"],"format":"int32","description":"Number of context lines before and after (default: 25)","minimum":0}}},"ContextLogsResponse":{"type":"object","required":["lines","target_index"],"properties":{"lines":{"type":"array","items":{"$ref":"#/components/schemas/ContextLine"}},"target_index":{"type":"integer","minimum":0}}},"ConversationDetailResponse":{"allOf":[{"$ref":"#/components/schemas/ConversationResponse"},{"type":"object","required":["messages"],"properties":{"messages":{"type":"array","items":{"$ref":"#/components/schemas/MessageResponse"},"description":"Turns oldest-first. The `system` seed message is omitted (internal)."}}}]},"ConversationResponse":{"type":"object","required":["public_id","context_type","context_id","status","created_at","last_activity_at"],"properties":{"context_id":{"type":"string"},"context_type":{"type":"string"},"created_at":{"type":"string"},"last_activity_at":{"type":"string"},"public_id":{"type":"string"},"status":{"type":"string"},"title":{"type":["string","null"]}}},"ConversationSummary":{"type":"object","description":"A conversation summary grouping related AI invocations.","required":["conversation_id","message_count","total_input_tokens","total_output_tokens","total_tokens","total_cost_microcents","avg_latency_ms","models_used","first_at","last_at"],"properties":{"avg_latency_ms":{"type":"number","format":"double"},"conversation_id":{"type":"string"},"first_at":{"type":"string"},"last_at":{"type":"string"},"message_count":{"type":"integer","format":"int64"},"models_used":{"type":"array","items":{"type":"string"}},"total_cost_microcents":{"type":"integer","format":"int64"},"total_input_tokens":{"type":"integer","format":"int64"},"total_output_tokens":{"type":"integer","format":"int64"},"total_tokens":{"type":"integer","format":"int64"}}},"ConversationsQueryParams":{"type":"object","properties":{"from":{"type":["string","null"],"description":"ISO 8601 start time (defaults to 24h ago)"},"limit":{"type":["integer","null"],"format":"int64","description":"Max results (defaults to 50, max 100)","minimum":0},"model":{"type":["string","null"],"description":"Filter by model name"},"tags":{"type":["string","null"],"description":"Filter by tags (comma-separated, AND logic)"},"to":{"type":["string","null"],"description":"ISO 8601 end time (defaults to now)"},"user_id":{"type":["integer","null"],"format":"int32","description":"Filter by user ID"}}},"CopyBlobRequest":{"type":"object","description":"Request to copy a blob","required":["fromUrl","toPathname"],"properties":{"fromUrl":{"type":"string","description":"Source blob URL or pathname","example":"/api/blob/10/images/avatar.png"},"projectId":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1},"toPathname":{"type":"string","description":"Destination pathname","example":"images/avatar-copy.png"}}},"CostAnalysis":{"type":"object","description":"Full cluster cost + rightsizing analysis attached to an import plan.","required":["nodes","capacity","requested","usage_source","overprovisioning","recommendation","notes"],"properties":{"actual_usage":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ResourceFootprint","description":"Measured usage from the metrics API (`metrics.k8s.io`).\n`None` when metrics-server is not installed."}]},"capacity":{"$ref":"#/components/schemas/ClusterCapacity","description":"Total cluster capacity (sum of node allocatable resources)"},"control_plane_monthly_usd":{"type":["number","null"],"format":"double","description":"Managed control-plane fee included in `current_monthly_usd` (EKS/GKE\ncharge ~$73/mo per cluster). `None` when not applicable/unknown."},"current_monthly_usd":{"type":["number","null"],"format":"double","description":"Estimated total infrastructure cost per month in USD (compute nodes +\ncontrol-plane fee). `None` when no node could be priced."},"nodes":{"type":"array","items":{"$ref":"#/components/schemas/NodeCostInfo"},"description":"Per-node inventory with price estimates where the instance type is known"},"notes":{"type":"array","items":{"type":"string"},"description":"Honesty notes: what could not be measured, which numbers are\nestimates, and any assumptions made. Always shown to the user."},"overprovisioning":{"$ref":"#/components/schemas/OverprovisioningAssessment","description":"Requests-vs-capacity-vs-usage assessment"},"provider":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/CloudProvider","description":"Detected cloud provider (from node `providerID` prefixes)"}]},"recommendation":{"$ref":"#/components/schemas/TargetRecommendation","description":"The temps/Hetzner target sizing and savings estimate"},"requested":{"$ref":"#/components/schemas/ResourceFootprint","description":"Sum of pod resource *requests* across running pods — what the\nscheduler has reserved, i.e. what the cluster is sized for."},"usage_source":{"$ref":"#/components/schemas/UsageSource","description":"How the usage numbers were obtained (drives UI wording)"}}},"CreateAlertRuleRequest":{"type":"object","required":["name","trigger_type"],"properties":{"cooldown_minutes":{"type":"integer","format":"int32","description":"Minimum minutes between notifications for same rule+group"},"enabled":{"type":"boolean"},"environment_filter":{"type":["integer","null"],"format":"int32","description":"Optional environment ID to filter alerts"},"error_level_filter":{"type":["string","null"],"description":"Optional error type/level filter"},"name":{"type":"string"},"notification_priority":{"type":"string","description":"Notification priority: Low, Normal, High, Critical"},"trigger_config":{"description":"Trigger-specific configuration (e.g., {\"count\": 100, \"window_minutes\": 60} for frequency)"},"trigger_type":{"type":"string","description":"Trigger type: new_issue, regression, frequency, new_user, user_count, status_change"}}},"CreateApiKeyRequest":{"type":"object","required":["name","role_type"],"properties":{"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"name":{"type":"string"},"permissions":{"type":["array","null"],"items":{"type":"string"},"example":["projects:read","deployments:read"]},"role_type":{"type":"string","example":"admin"}}},"CreateApiKeyResponse":{"type":"object","required":["id","name","key_prefix","role_type","api_key","created_at"],"properties":{"api_key":{"type":"string"},"created_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00Z"},"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"id":{"type":"integer","format":"int32"},"key_prefix":{"type":"string"},"name":{"type":"string"},"permissions":{"type":["array","null"],"items":{"type":"string"}},"role_type":{"type":"string"}}},"CreateBackupScheduleRequest":{"type":"object","required":["name","backup_type","retention_period","schedule_expression","enabled","tags"],"properties":{"backup_type":{"type":"string"},"description":{"type":["string","null"]},"enabled":{"type":"boolean"},"include_control_plane":{"type":["boolean","null"],"description":"When `true` (default), every run also produces a `control_plane`\nbackup of Temps's own database. Operators who use Temps purely as\na backup orchestrator for external DBs can set this to `false` to\nkeep the run history focused on those services."},"max_runtime_secs":{"type":["integer","null"],"format":"int64","description":"Optional wall-clock timeout override for jobs created by this schedule\n(seconds). When set, overrides the engine-family default. `null` means\n\"use engine default.\" The per-job `max_runtime_secs` in\n`EnqueueJobParams` can still override this for ad-hoc triggers."},"name":{"type":"string"},"retention_period":{"type":"integer","format":"int32"},"s3_source_id":{"type":["integer","null"],"format":"int32","description":"Optional S3 source. If omitted, the current default S3 source is used."},"schedule_expression":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"target_all_services":{"type":["boolean","null"],"description":"When `true` (default), the schedule backs up every external service\non the host — including databases created in the future. When\n`false`, the schedule backs up only the services explicitly attached\nvia `POST /backups/schedules/{id}/services`. Omit to use the default."}}},"CreateBitbucketRequest":{"type":"object","required":["name","auth"],"properties":{"auth":{"$ref":"#/components/schemas/BitbucketAuthInput","description":"Authentication credentials — either an access token or an app password."},"name":{"type":"string","description":"Display name for this provider."}}},"CreateCloudflareProviderRequest":{"type":"object","required":["name","config"],"properties":{"config":{"$ref":"#/components/schemas/CloudflareConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":"string"}}},"CreateConversationRequest":{"type":"object","required":["context_type","context_id"],"properties":{"context_id":{"type":"string","description":"The entity id (ints stringified)."},"context_type":{"type":"string","description":"e.g. `\"deployment\"`."}}},"CreateDSNRequest":{"type":"object","properties":{"base_url":{"type":["string","null"]},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"name":{"type":["string","null"]}}},"CreateDashboardRequest":{"type":"object","required":["project_id","name","layout"],"properties":{"layout":{"$ref":"#/components/schemas/DashboardLayout"},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"}}},"CreateDeploymentTokenRequest":{"type":"object","required":["name"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32","description":"Optional deployment ID - if set, token is scoped to a specific deployment"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Optional environment ID - if not set, token applies to all environments"},"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"name":{"type":"string"},"permissions":{"type":["array","null"],"items":{"type":"string"},"description":"List of permissions (e.g., [\"visitors:enrich\", \"emails:send\"])\nIf not provided, defaults to full access","example":["visitors:enrich","emails:send"]}}},"CreateDeploymentTokenResponse":{"type":"object","required":["id","project_id","name","token_prefix","token","created_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00Z"},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"permissions":{"type":["array","null"],"items":{"type":"string"}},"project_id":{"type":"integer","format":"int32"},"token":{"type":"string","description":"The full token value - only returned on creation"},"token_prefix":{"type":"string"}}},"CreateDnsProviderRequest":{"type":"object","description":"Request to create a new DNS provider","required":["name","provider_type","credentials"],"properties":{"credentials":{"$ref":"#/components/schemas/DnsProviderCredentials","description":"Provider credentials"},"description":{"type":["string","null"],"description":"Optional description"},"name":{"type":"string","description":"User-friendly name","example":"My Cloudflare"},"provider_type":{"$ref":"#/components/schemas/DnsProviderType","description":"Provider type"}}},"CreateDomainRequest":{"type":"object","required":["domain"],"properties":{"challenge_type":{"type":"string","description":"Challenge type for Let's Encrypt validation. Options: \"http-01\" (default) or \"dns-01\""},"domain":{"type":"string"}}},"CreateEmailDomainRequest":{"type":"object","required":["provider_id","domain"],"properties":{"domain":{"type":"string","description":"Domain name (e.g., \"updates.example.com\")","example":"updates.example.com"},"provider_id":{"type":"integer","format":"int32","description":"Provider ID to use for this domain"}}},"CreateEmailProviderRequest":{"type":"object","required":["name","provider_type","region"],"properties":{"name":{"type":"string","description":"User-friendly name for the provider","example":"My AWS SES"},"provider_type":{"$ref":"#/components/schemas/EmailProviderTypeRoute","description":"Provider type"},"region":{"type":"string","description":"Cloud region. For SMTP this is informational only — the host/port carry the real routing.","example":"us-east-1"},"scaleway_credentials":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ScalewayCredentialsRequest","description":"Scaleway credentials (required if provider_type is scaleway)"}]},"ses_credentials":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SesCredentialsRequest","description":"AWS SES credentials (required if provider_type is ses)"}]},"smtp_credentials":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SmtpCredentialsRequest","description":"Generic SMTP credentials (required if provider_type is smtp). Use when\nyou only have SMTP creds and want to import an already-set-up domain."}]},"sns_topic_arn":{"type":["string","null"],"description":"Exact SNS topic allowed to deliver SES events for this provider."}}},"CreateEnvironmentRequest":{"type":"object","required":["name","branch"],"properties":{"branch":{"type":"string"},"name":{"type":"string"},"set_as_preview":{"type":"boolean","description":"If true, set this environment as the preview environment for the project"}}},"CreateEnvironmentVariableRequest":{"type":"object","required":["key","value","environment_ids"],"properties":{"environment_ids":{"type":"array","items":{"type":"integer","format":"int32"}},"include_in_preview":{"type":"boolean","description":"Include this environment variable in preview environments (default: true)"},"is_secret":{"type":"boolean","description":"When true the variable is treated as write-only: never returned in\nplaintext from the API, masked in the UI, and updates that omit the\nvalue preserve the existing ciphertext. The flag is one-way — secret\nvars cannot be demoted back to regular vars."},"key":{"type":"string"},"value":{"type":"string"}}},"CreateExternalServiceRequest":{"type":"object","required":["name","service_type","parameters"],"properties":{"members":{"type":"array","items":{"$ref":"#/components/schemas/ClusterMemberRequest"},"description":"Cluster member specifications. Required when topology is \"cluster\"."},"name":{"type":"string"},"node_id":{"type":["integer","null"],"format":"int32","description":"Target node ID for the service. Omit or null to run on the control plane."},"parameters":{"type":"object","additionalProperties":{},"propertyNames":{"type":"string"}},"service_type":{"$ref":"#/components/schemas/ServiceTypeRoute"},"topology":{"type":"string","description":"Service topology: \"standalone\" (default) or \"cluster\" (HA multi-member).","example":"standalone"},"version":{"type":["string","null"]}}},"CreateFlagRequest":{"type":"object","required":["key","value_type","default_value"],"properties":{"client_visible":{"type":"boolean","description":"Whether the flag may be exposed on the unauthenticated same-origin\nevaluation endpoint. Defaults to `false`: flags are server-only unless\nexplicitly opted in, because targeting rules can encode business logic."},"default_value":{"description":"Served whenever evaluation cannot do better. Must match `value_type`.\n\nLeft unannotated so utoipa emits a free-form schema: a bool flag's\ndefault is `false`, not an object, and `value_type = Object` would tell\nevery generated client otherwise."},"description":{"type":["string","null"]},"key":{"type":"string","description":"Stable key used in application code. Immutable after create.","example":"checkout.v2"},"value_type":{"$ref":"#/components/schemas/FlagValueType","description":"Fixed at create: retyping would invalidate every stored value and every\ncall site."}}},"CreateFunnelRequest":{"type":"object","required":["name","steps"],"properties":{"description":{"type":["string","null"]},"name":{"type":"string"},"steps":{"type":"array","items":{"$ref":"#/components/schemas/CreateFunnelStep"}}}},"CreateFunnelResponse":{"type":"object","required":["funnel_id","message"],"properties":{"funnel_id":{"type":"integer","format":"int32"},"message":{"type":"string"}}},"CreateFunnelStep":{"type":"object","required":["event_name"],"properties":{"event_filter":{"type":"array","items":{"$ref":"#/components/schemas/SmartFilter"}},"event_name":{"type":"string"}}},"CreateGenericRequest":{"type":"object","required":["name","clone_url"],"properties":{"base_url":{"type":["string","null"],"description":"Optional base URL of the git host for display purposes (no API is called)."},"clone_url":{"type":"string","description":"HTTPS clone URL for the repository, e.g. `https://git.example.com/org/repo.git`."},"name":{"type":"string","description":"Display name for this provider."},"token":{"type":["string","null"],"description":"Access token or password. Omit (or set to `null`) for public repositories."},"token_username":{"type":["string","null"],"description":"HTTP Basic username used with the token. Defaults to `x-access-token` when\nabsent or empty. Ignored for public (unauthenticated) repositories."}}},"CreateGitHubPATRequest":{"type":"object","required":["name","token"],"properties":{"name":{"type":"string"},"token":{"type":"string"}}},"CreateGitLabOAuthRequest":{"type":"object","required":["name","client_id","client_secret","redirect_uri"],"properties":{"base_url":{"type":["string","null"]},"client_id":{"type":"string"},"client_secret":{"type":"string"},"name":{"type":"string"},"redirect_uri":{"type":"string"}}},"CreateGitLabPATRequest":{"type":"object","required":["name","token"],"properties":{"base_url":{"type":["string","null"]},"name":{"type":"string"},"token":{"type":"string"}}},"CreateGiteaPATRequest":{"type":"object","required":["name","token","base_url"],"properties":{"base_url":{"type":"string","description":"HTTPS base URL of the Gitea instance, e.g. `https://git.example.com`."},"name":{"type":"string","description":"Display name for this provider."},"token":{"type":"string","description":"Personal access token issued by the Gitea instance."}}},"CreateIncidentRequest":{"type":"object","required":["title","severity"],"properties":{"description":{"type":["string","null"]},"environment_id":{"type":["integer","null"],"format":"int32"},"monitor_id":{"type":["integer","null"],"format":"int32"},"severity":{"type":"string"},"title":{"type":"string"}}},"CreateIntegrationBody":{"type":"object","required":["provider","signing_secret"],"properties":{"provider":{"type":"string","description":"Registered provider name, e.g. \"stripe\"."},"signing_secret":{"type":"string","description":"Signing secret from the provider's dashboard."}}},"CreateIpAccessControlRequest":{"type":"object","description":"Request to create an IP access control rule","required":["ip_address","action"],"properties":{"action":{"type":"string","description":"Action to take: \"block\" or \"allow\"","example":"block"},"ip_address":{"type":"string","description":"IP address in CIDR notation (e.g., \"192.168.1.1\" or \"10.0.0.0/24\")","example":"192.168.1.100"},"reason":{"type":["string","null"],"description":"Optional reason for the action","example":"Malicious activity detected"}}},"CreateMcpRequest":{"type":"object","required":["slug","name","config"],"properties":{"config":{"type":"object"},"description":{"type":["string","null"]},"name":{"type":"string"},"slug":{"type":"string"}}},"CreateMetricAlertRequest":{"type":"object","required":["project_id","name","metric_name","aggregation","detection_config","window_secs","for_duration_secs","severity","enabled"],"properties":{"aggregation":{"type":"string","description":"One of `avg|sum|min|max|count|rate|p50|p90|p95|p99`."},"detection_config":{"$ref":"#/components/schemas/DetectionConfig","description":"The detector: a discriminated union keyed by `kind`. Today only\n`{ \"kind\": \"static\", \"comparator\": \"gt\", \"threshold\": 500 }` is evaluable."},"dynamic_alerts":{"type":"boolean","description":"When true (and `group_by` is set) fire one independent alarm per breaching\nseries. Static detectors only. Default false."},"enabled":{"type":"boolean"},"for_duration_secs":{"type":"integer","format":"int32"},"group_by":{"type":"array","items":{"type":"string"},"description":"Label keys to break the metric down by, e.g. `[\"endpoint\",\"region\"]`. Empty\n(the default) = one aggregate stream. Max 2 keys; keys must match\n`[a-zA-Z0-9_.:-]`."},"grouped_notification_threshold":{"type":"integer","format":"int32","description":"When more than this many series transition to firing in the same tick, only\nthe first gets the expensive chart/AI enrichment. Range 1–1000, default 5."},"label_filters":{"type":"array","items":{"type":"array","items":false,"prefixItems":[{"type":"string"},{"type":"string"}]},"description":"AND-combined label equality filters: `[[\"key\",\"value\"],…]`. Empty = no\nfiltering (the default). Max 10 pairs; keys must match `[a-zA-Z0-9_.:-]`;\nvalues capped at 500 characters."},"max_series":{"type":"integer","format":"int32","description":"Cardinality cap for dynamic alerting: at most this many series (top by\n`|value|`). Range 1–100, default 20."},"metric_name":{"type":"string"},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"severity":{"type":"string","description":"One of `info|warning|critical`."},"window_secs":{"type":"integer","format":"int32"}}},"CreateMonitorRequest":{"type":"object","required":["name","monitor_type","environment_id"],"properties":{"check_interval_seconds":{"type":["integer","null"],"format":"int32"},"check_path":{"type":["string","null"]},"environment_id":{"type":"integer","format":"int32"},"monitor_type":{"type":"string"},"name":{"type":"string"}}},"CreateNotificationEmailProviderRequest":{"type":"object","required":["name","config"],"properties":{"config":{"$ref":"#/components/schemas/EmailConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":"string"}}},"CreateOidcProviderRequest":{"type":"object","required":["name","issuer_url","client_id","client_secret"],"properties":{"client_id":{"type":"string"},"client_secret":{"type":"string"},"default_role":{"type":"string"},"enabled":{"type":"boolean"},"group_claim":{"type":"string"},"issuer_url":{"type":"string"},"jit_provisioning":{"type":"boolean"},"name":{"type":"string"},"role_claim":{"type":"string"},"scopes":{"type":"string"},"template":{"type":"string"},"trust_idp_email":{"type":"boolean","description":"Defaults false. Set to true only for IdPs where an admin\ncontrols user provisioning (corporate Okta, Azure AD) and\nself-signup of arbitrary emails is not possible — see the\n`trust_idp_email` field on `oidc_providers::Model` for the\nsecurity tradeoff this enables."}}},"CreateOidcRoleMappingRequest":{"type":"object","required":["priority","idp_group","role"],"properties":{"idp_group":{"type":"string"},"priority":{"type":"integer","format":"int32"},"role":{"type":"string"}}},"CreatePlanRequest":{"type":"object","description":"Request to create an import plan","required":["source","workload_id"],"properties":{"credentials":{"$ref":"#/components/schemas/ImportCredentials","description":"Platform credentials (required for cloud platforms like Vercel, Railway)"},"repository_id":{"type":["integer","null"],"format":"int32","description":"Optional repository ID to associate with the import\nIf provided, preset will be detected from the repository"},"source":{"$ref":"#/components/schemas/ImportSource","description":"Source to import from"},"workload_id":{"$ref":"#/components/schemas/WorkloadId","description":"Workload ID to import"}}},"CreatePlanResponse":{"type":"object","description":"Response with created plan","required":["session_id","plan","validation","can_execute"],"properties":{"can_execute":{"type":"boolean","description":"Whether the plan can be executed"},"plan":{"$ref":"#/components/schemas/ImportPlan","description":"Generated import plan"},"session_id":{"type":"string","description":"Session ID for tracking"},"validation":{"$ref":"#/components/schemas/ValidationReport","description":"Validation report"}}},"CreatePrResponse":{"type":"object","required":["run","pr_url","pr_number","branch_name"],"properties":{"branch_name":{"type":"string"},"pr_number":{"type":"integer","format":"int32"},"pr_url":{"type":"string"},"run":{"$ref":"#/components/schemas/AutofixerRunResponse"}}},"CreateProjectAccessRequest":{"type":"object","required":["team_id","role"],"properties":{"role":{"$ref":"#/components/schemas/TeamRole"},"team_id":{"type":"integer","format":"int32"}}},"CreateProjectFromTemplateRequest":{"type":"object","description":"Request to create a project from a template\n\nSupports two deploy modes:\n * **Fork mode** — when `git_provider_connection_id` is set, the template\n repo is cloned into a new repository under the user's Git account and the\n project tracks that fork (git-push deploys, automatic deploy on push).\n * **One-click public-repo mode** — when `git_provider_connection_id` is\n omitted, the project deploys directly from the template's public source\n repository (no fork, no Git account required). This is the activation\n path: a brand-new user with no Git provider connected can still deploy a\n demo in one click. `repository_name` / `repository_owner` are ignored in\n this mode, and automatic-deploy-on-push is unavailable (there is no fork\n to receive webhooks).","required":["template_slug","project_name"],"properties":{"automatic_deploy":{"type":"boolean","description":"Enable automatic deployment on push (defaults to true). Only honoured in\nfork mode; public-repo deploys cannot receive push webhooks."},"environment_variables":{"type":"array","items":{"$ref":"#/components/schemas/EnvVarInput"},"description":"Environment variables to set (key-value pairs)"},"git_provider_connection_id":{"type":["integer","null"],"format":"int32","description":"Git provider connection ID. When omitted, the project deploys directly\nfrom the template's public source repository instead of forking it."},"private":{"type":"boolean","description":"Whether to make the repository private (defaults to true)"},"project_name":{"type":"string","description":"Name for the new project"},"repository_name":{"type":["string","null"],"description":"Name for the new repository to create. Required in fork mode; ignored in\none-click public-repo mode."},"repository_owner":{"type":["string","null"],"description":"Owner/organization for the new repository (defaults to authenticated user)"},"storage_service_ids":{"type":"array","items":{"type":"integer","format":"int32"},"description":"External storage service IDs to attach to the project"},"template_slug":{"type":"string","description":"Template slug to use as the base"}}},"CreateProjectFromTemplateResponse":{"type":"object","description":"Response after creating a project from template","required":["project_id","project_slug","project_name","repository_url","template_slug","message"],"properties":{"message":{"type":"string","description":"Message with additional info"},"project_id":{"type":"integer","format":"int32","description":"ID of the created project"},"project_name":{"type":"string","description":"Name of the created project"},"project_slug":{"type":"string","description":"Slug of the created project"},"repository_url":{"type":"string","description":"URL of the created repository"},"template_slug":{"type":"string","description":"Template that was used"}}},"CreateProjectRequest":{"type":"object","required":["name","directory","main_branch","preset","storage_service_ids"],"properties":{"automatic_deploy":{"type":["boolean","null"]},"build_command":{"type":["string","null"]},"custom_domain":{"type":["string","null"]},"directory":{"type":"string"},"environment_variables":{"type":["array","null"],"items":{"type":"array","items":false,"prefixItems":[{"type":"string"},{"type":"string"}]}},"exposed_port":{"type":["integer","null"],"format":"int32","description":"Port exposed by the container (fallback when image has no EXPOSE directive)\n\nPriority order for port resolution:\n1. Image EXPOSE directive (auto-detected from built image)\n2. Environment-level exposed_port (overrides this value per environment)\n3. This project-level exposed_port (fallback)\n4. Default: 3000\n\nOnly set this if your image doesn't use EXPOSE directive.","example":8080},"git_provider_connection_id":{"type":["integer","null"],"format":"int32"},"git_url":{"type":["string","null"]},"install_command":{"type":["string","null"]},"is_on_demand":{"type":["boolean","null"]},"is_public_repo":{"type":["boolean","null"]},"is_web_app":{"type":["boolean","null"]},"main_branch":{"type":"string"},"name":{"type":"string"},"output_dir":{"type":["string","null"]},"performance_metrics_enabled":{"type":"boolean"},"preset":{"type":"string"},"preset_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PresetConfigSchema","description":"Preset-specific configuration\n\nDifferent presets accept different configuration options:\n- **Dockerfile preset**: Accepts `DockerfilePresetConfig` with `dockerfile_path` and `build_context`\n- **Nixpacks preset**: Accepts ordered `providers` (for example `[\"...\", \"python\"]`)\n and optional inline `nixpacksConfig` TOML\n- **Static presets** (Vite, Next.js, etc.): Accept `StaticPresetConfig` with build commands and output dir\n\nExample for Dockerfile preset:\n```json\n{\n \"dockerfilePath\": \"docker/Dockerfile\",\n \"buildContext\": \"./api\"\n}\n```"}]},"project_type":{"type":["string","null"]},"repo_name":{"type":["string","null"]},"repo_owner":{"type":["string","null"]},"source_type":{"$ref":"#/components/schemas/SourceType","description":"Source type for deployments\n\nDetermines how the project is deployed:\n- **git** (default): Traditional Git-based deployments - source code is pulled, built, and deployed\n- **docker_image**: Deploy pre-built Docker images from external registries (DockerHub, GHCR, etc.)\n- **static_files**: Deploy pre-built static files uploaded as tar.gz or zip bundles\n\nFor `docker_image` and `static_files` source types, `repo_name` and `repo_owner` are optional."},"storage_service_ids":{"type":"array","items":{"type":"integer","format":"int32"}},"use_default_wildcard":{"type":["boolean","null"]}}},"CreateProjectSecretRequest":{"type":"object","description":"Request to create a new project secret.\n\nProject secrets are mounted into the container as files under\n`/run/secrets/` (mode 0400, tmpfs) instead of as environment variables.\nValues are always encrypted at rest and never returned in plaintext from\nthe API after create. Distinct from agent secrets (global `/settings/secrets`).","required":["key","value"],"properties":{"environment_ids":{"type":"array","items":{"type":"integer","format":"int32"}},"include_in_preview":{"type":"boolean","description":"Include this secret in preview environments."},"key":{"type":"string","description":"Identifier for the secret. Becomes the filename at `/run/secrets/`.\nMust start with a letter or underscore and contain only A-Z, a-z, 0-9, _."},"value":{"type":"string","description":"Plaintext value, <= 1 MiB."}}},"CreateProviderKeyRequest":{"type":"object","required":["provider","display_name","api_key"],"properties":{"api_key":{"type":"string"},"base_url":{"type":["string","null"]},"default_model":{"type":["string","null"],"description":"Optional model id to pin for this provider (e.g. \"gpt-4o-mini\")."},"display_name":{"type":"string"},"provider":{"type":"string"}}},"CreateProviderRequest":{"type":"object","required":["name","provider_type","config"],"properties":{"config":{},"enabled":{"type":["boolean","null"]},"name":{"type":"string"},"provider_type":{"type":"string"}}},"CreateRouteRequest":{"type":"object","required":["domain","host","port"],"properties":{"domain":{"type":"string"},"host":{"type":"string"},"port":{"type":"integer","format":"int32"},"route_type":{"type":["string","null"],"description":"Route type: \"http\" (default) matches on HTTP Host header,\n\"tls\" matches on TLS SNI hostname for TCP passthrough"}}},"CreateS3SourceRequest":{"type":"object","required":["name","bucket_name","bucket_path","access_key_id","secret_key","region"],"properties":{"access_key_id":{"type":"string"},"bucket_name":{"type":"string"},"bucket_path":{"type":"string"},"endpoint":{"type":["string","null"],"description":"Optional endpoint URL for S3-compatible services like MinIO","example":"http://minio.example.com:9000"},"force_path_style":{"type":["boolean","null"],"description":"Whether to use path-style addressing (default: true)","example":true},"is_default":{"type":["boolean","null"],"description":"When true, make this the default source (will swap out any existing default).\nThe very first S3 source is always created as default regardless of this flag.","example":false},"name":{"type":"string"},"region":{"type":"string"},"secret_key":{"type":"string"}}},"CreateSandboxBody":{"type":"object","properties":{"_runtime":{"type":["string","null"]},"backend":{"type":["string","null"],"description":"Isolation backend: `\"docker\"` (default) or `\"firecracker\"` (ADR-029,\nhardware-virtualized microVM — requires a host provisioned with\n`temps firecracker setup`). Omit for the platform default; existing\nclients are unaffected. Requesting an unavailable backend fails with\n400 rather than silently downgrading isolation."},"cpu_limit":{"type":["number","null"],"format":"double"},"disk_size_mb":{"type":["integer","null"],"format":"int64","description":"Root disk size in MB (Firecracker only; Docker ignores it). Omit for\nthe platform default (1 GiB).","minimum":0},"env":{"type":"object","description":"Extra env vars baked into the container on create.","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"image":{"type":["string","null"],"description":"Docker image override. `null` uses the platform default."},"memory_limit_mb":{"type":["integer","null"],"format":"int64","minimum":0},"name":{"type":["string","null"]},"networkPolicy":{},"pids_limit":{"type":["integer","null"],"format":"int64"},"ports":{"type":"array","items":{"type":"integer","format":"int32","minimum":0},"description":"Ports the sandbox will listen on. Each port becomes a `routes[]`\nentry in the create/get response so `@vercel/sandbox`'s\n`sandbox.domain(port)` can resolve it client-side without an\nextra round-trip."},"preview_password":{"type":["string","null"],"description":"Optional preview-URL password. When set, every preview URL served\nfor this sandbox is gated behind a login form. 8–256 characters.\nOmit to leave preview URLs open (the sandbox ID remains the only\ngate). The plaintext is never returned; only the last-4 hint is\nsurfaced in `SandboxResponse.preview_password_hint`."},"projectId":{"type":["string","null"]},"resources":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ResourcesBody","description":"`@vercel/sandbox`'s nested resources object. When present, its\n`memory` / `vcpus` populate `memory_limit_mb` / `cpu_limit` if those\nweren't sent directly."}]},"source":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SourceBody","description":"Optional initial content to seed into the work dir. Clones a\nrepo or extracts a tarball after the sandbox is created."}]},"timeout":{"type":["integer","null"],"format":"int64","description":"Idle timeout as sent by `@vercel/sandbox` (milliseconds). Converted\nto seconds when `timeout_secs` is absent.","minimum":0},"timeout_secs":{"type":["integer","null"],"format":"int64","description":"Idle timeout in seconds (temps-native). Clamped to `[60, 86400]`.","minimum":0}}},"CreateSkillRequest":{"type":"object","required":["slug","name","content"],"properties":{"content":{"type":"string"},"description":{"type":["string","null"]},"name":{"type":"string"},"slug":{"type":"string"}}},"CreateSlackProviderRequest":{"type":"object","required":["name","config"],"properties":{"config":{"$ref":"#/components/schemas/SlackConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":"string"}}},"CreateTeamMemberRequest":{"type":"object","required":["user_id","role"],"properties":{"role":{"$ref":"#/components/schemas/TeamRole"},"user_id":{"type":"integer","format":"int32"}}},"CreateTeamRequest":{"type":"object","required":["name","slug"],"properties":{"description":{"type":["string","null"]},"name":{"type":"string"},"slug":{"type":"string"}}},"CreateUserRequest":{"type":"object","required":["username","roles"],"properties":{"email":{"type":["string","null"]},"password":{"type":["string","null"]},"roles":{"type":"array","items":{"type":"string"}},"username":{"type":"string"}}},"CreateWebhookProviderRequest":{"type":"object","required":["name","config"],"properties":{"config":{"$ref":"#/components/schemas/WebhookConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":"string"}}},"CreateWebhookRequestBody":{"type":"object","required":["url","events"],"properties":{"enabled":{"type":["boolean","null"],"description":"Whether the webhook is enabled","default":true},"events":{"type":"array","items":{"type":"string"},"description":"Event types to subscribe to","example":["deployment.created","deployment.succeeded"]},"secret":{"type":["string","null"],"description":"Secret for HMAC signature verification (optional)"},"url":{"type":"string","description":"Target URL for webhook delivery","example":"https://example.com/webhook"}}},"CreatedResource":{"type":"object","description":"Resource created during import (for rollback / audit)","required":["resource_type","resource_id","resource_name"],"properties":{"resource_id":{"type":"integer","format":"int32","description":"Resource ID"},"resource_name":{"type":"string","description":"Resource name"},"resource_type":{"type":"string","description":"Resource type (project, environment, deployment, service, domain, etc.)"}}},"CronExecutionInfo":{"type":"object","required":["id","cron_id","executed_at","url","status_code","headers","response_time_ms"],"properties":{"cron_id":{"type":"integer","format":"int32"},"error_message":{"type":["string","null"]},"executed_at":{"type":"string"},"headers":{"type":"string"},"id":{"type":"integer","format":"int32"},"response_time_ms":{"type":"integer","format":"int32"},"status_code":{"type":"integer","format":"int32"},"url":{"type":"string"}}},"CronInfo":{"type":"object","required":["id","project_id","environment_id","path","schedule","created_at","updated_at"],"properties":{"created_at":{"type":"string"},"deleted_at":{"type":["string","null"]},"environment_id":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"next_run":{"type":["string","null"]},"path":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"schedule":{"type":"string"},"updated_at":{"type":"string"}}},"CrossProjectSiblingRef":{"type":"object","description":"A sibling project that shares the same `trace_id`, returned by the\nPhase 1 cross-project banner endpoint.","required":["project_id","project_name","project_slug","first_seen"],"properties":{"first_seen":{"type":"string","format":"date-time","description":"ISO 8601 timestamp (UTC, `Z` suffix) of first span ingest for this\n`(trace_id, project_id)` pair."},"project_id":{"type":"integer","format":"int32"},"project_name":{"type":"string"},"project_slug":{"type":"string","description":"URL slug used to link into the sibling project's single-project trace view."}}},"CrossProjectTraceResponse":{"type":"object","description":"Response body for `GET /otel/traces/cross-project/{trace_id}`.\n\nAn empty `siblings` vec is the normal single-project case — never 404.","required":["trace_id","siblings"],"properties":{"siblings":{"type":"array","items":{"$ref":"#/components/schemas/CrossProjectSiblingRef"},"description":"Projects other than the caller's that hold spans for this trace,\nordered by `first_seen ASC`."},"trace_id":{"type":"string","description":"The trace_id that was queried (echoed back for client convenience)."}}},"CurrentStatusResponse":{"type":"object","required":["monitor_id","current_status","uptime_percentage"],"properties":{"avg_response_time_ms":{"type":["number","null"],"format":"double"},"current_status":{"type":"string"},"last_check_at":{"type":["string","null"],"format":"date-time"},"monitor_id":{"type":"integer","format":"int32"},"uptime_percentage":{"type":"number","format":"double"}}},"CustomDomainRequest":{"type":"object","required":["domain","environment_id"],"properties":{"branch":{"type":["string","null"]},"domain":{"type":"string"},"environment_id":{"type":"integer","format":"int32"},"redirect_to":{"type":["string","null"]},"service_name":{"type":["string","null"],"description":"Docker Compose service name this domain routes to (only for docker-compose projects)"},"status_code":{"type":["integer","null"],"format":"int32"}}},"CustomDomainResponse":{"type":"object","required":["id","project_id","domain","status","created_at","updated_at"],"properties":{"branch":{"type":["string","null"]},"created_at":{"type":"integer","format":"int64"},"domain":{"type":"string"},"domain_id":{"type":["integer","null"],"format":"int32"},"environment":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DomainEnvironmentResponse"}]},"expiration_time":{"type":["integer","null"],"format":"int64"},"id":{"type":"integer","format":"int32"},"last_renewed":{"type":["integer","null"],"format":"int64"},"message":{"type":["string","null"]},"project_id":{"type":"integer","format":"int32"},"redirect_to":{"type":["string","null"]},"service_name":{"type":["string","null"],"description":"Docker Compose service name this domain routes to"},"status":{"type":"string"},"status_code":{"type":["integer","null"],"format":"int32"},"updated_at":{"type":"integer","format":"int64"}}},"CustomerMovementResponse":{"type":"object","required":["bucket","new_customers","churned_customers"],"properties":{"bucket":{"type":"string","format":"date-time"},"churned_customers":{"type":"integer","format":"int64"},"new_customers":{"type":"integer","format":"int64"}}},"DashboardLayout":{"type":"object","description":"The typed layout persisted (as JSONB) in `metric_dashboards.layout`.","required":["sections"],"properties":{"sections":{"type":"array","items":{"$ref":"#/components/schemas/DashboardSection"},"description":"Ordered sections that make up the dashboard."}}},"DashboardProjectsAnalyticsQuery":{"type":"object","description":"Query parameters for batch dashboard analytics","required":["project_ids","start_date","end_date"],"properties":{"end_date":{"type":"string","format":"date-time","description":"End date for the query range"},"project_ids":{"type":"string","description":"Comma-separated list of project IDs"},"start_date":{"type":"string","format":"date-time","description":"Start date for the query range"}}},"DashboardProjectsAnalyticsResponse":{"type":"object","description":"Batch response for dashboard project analytics","required":["projects"],"properties":{"projects":{"type":"object","description":"Map of project_id -> analytics data","additionalProperties":{"$ref":"#/components/schemas/ProjectDashboardAnalytics"},"propertyNames":{"type":"string"}}}},"DashboardSection":{"type":"object","description":"A titled group of tiles within a dashboard.","required":["id","title","tiles"],"properties":{"id":{"type":"string","description":"Stable client-generated section id."},"tiles":{"type":"array","items":{"$ref":"#/components/schemas/DashboardTile"},"description":"Tiles rendered within this section."},"title":{"type":"string","description":"Section heading."}}},"DashboardTile":{"type":"object","description":"A single metric tile within a dashboard section.","required":["id","metric_name","aggregation"],"properties":{"aggregation":{"type":"string","description":"Aggregation applied per bucket: one of\n`avg|sum|min|max|count|rate|p50|p90|p95|p99`."},"group_by":{"type":"array","items":{"type":"string"},"description":"Label keys to break the metric down by (group-by / multi-series view).\nEmpty = single aggregated series (current behavior). Max 2 keys — more\ndimensions are unreadable in a chart (ADR-026 Phase 2). Each key must\nmatch `[a-zA-Z0-9_.:-]`. Wired directly to `MetricQuery.group_by` by\nthe tile query path (separate frontend task)."},"id":{"type":"string","description":"Stable client-generated tile id (used as a React key / for reordering)."},"label_filters":{"type":"array","items":{"type":"array","items":false,"prefixItems":[{"type":"string"},{"type":"string"}]},"description":"AND-combined label equality filters: `[[\"key\",\"value\"],…]`. Empty = no\nfiltering. Max 10 pairs; keys must match `[a-zA-Z0-9_.:-]`; values\ncapped at 500 characters. Not yet wired into the tile query path\n(Phase 1 ADR-026 — field round-trips and validates; query wiring is\na separate frontend task)."},"metric_name":{"type":"string","description":"The metric name to chart (e.g. `http.server.duration`)."},"title":{"type":["string","null"],"description":"Optional display title; falls back to the metric name in the UI."}}},"DataImplication":{"type":"object","description":"A specific data implication the user needs to understand","required":["severity","message"],"properties":{"message":{"type":"string","description":"Human-readable description of what could happen"},"recommended_action":{"type":["string","null"],"description":"What the user should do about it (if anything)"},"severity":{"$ref":"#/components/schemas/DataImplicationSeverity","description":"Severity of this implication"}}},"DataImplicationSeverity":{"type":"string","description":"Severity of a data implication","enum":["info","warning","data-not-migrated","potential-data-loss"]},"DatabaseMetricsResponse":{"type":"object","description":"Response for the per-database metrics breakdown.","required":["databases"],"properties":{"databases":{"type":"array","items":{"$ref":"#/components/schemas/DatabaseMetricsRow"},"description":"One entry per database, sorted by the first metric descending\n(largest first) so the biggest database leads the table."}}},"DatabaseMetricsRow":{"type":"object","description":"Per-database metric values for a Postgres service.\n\nA Postgres instance can host many databases (some unrelated to this\nservice). The collector records per-`datname` series; this groups the\nlatest value of each requested metric by database so the UI can render a\n\"Databases\" breakdown table instead of one collapsed number.","required":["database","metrics"],"properties":{"database":{"type":"string","description":"Database name (`datname`)."},"metrics":{"type":"object","description":"Latest value of each requested metric for this database\n(e.g. `{\"pg.database_size_bytes\": 7943871, \"pg.cache_hit_ratio\": 0.99}`).","additionalProperties":{"type":"number","format":"double"},"propertyNames":{"type":"string"}}}},"DelRequest":{"type":"object","description":"Request to delete keys","required":["keys"],"properties":{"keys":{"type":"array","items":{"type":"string"},"description":"The key(s) to delete","example":["user:123","user:456"]},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1}}},"DelResponse":{"type":"object","description":"Response for delete operation","required":["deleted"],"properties":{"deleted":{"type":"integer","format":"int64","description":"Number of keys deleted","example":2}}},"DeleteBlobRequest":{"type":"object","description":"Request to delete blobs","required":["pathnames"],"properties":{"pathnames":{"type":"array","items":{"type":"string"},"description":"Pathnames to delete (relative to project)","example":["images/avatar.png","documents/file.pdf"]},"projectId":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1}}},"DeleteBlobResponse":{"type":"object","description":"Response after deleting blobs","required":["deleted"],"properties":{"deleted":{"type":"integer","format":"int64","description":"Number of blobs deleted","example":2}}},"DeleteResponse":{"type":"object","required":["deleted"],"properties":{"deleted":{"type":"integer","format":"int64","minimum":0}}},"DeployFromImageRequest":{"type":"object","properties":{"external_image_id":{"type":["integer","null"],"format":"int32","description":"External image ID (if already registered). If provided without image_ref,\nthe image reference will be fetched from the registered external image."},"health_check_path":{"type":["string","null"],"description":"Optional HTTP health-check path override (e.g. \"/api/healthz\").\nImage deploys can't read `.temps.yaml`, so this sets the path the deployer\nprobes after the container starts and the path the environment's uptime\nmonitor checks. Must start with '/'. When omitted, defaults to \"/\".","example":"/api/healthz"},"image_ref":{"type":["string","null"],"description":"Docker image reference (e.g., \"ghcr.io/org/app:v1.0\")\nRequired if external_image_id is not provided","example":"ghcr.io/myorg/myapp:v1.0"},"metadata":{"description":"Optional deployment metadata"}}},"DeployFromImageUploadQuery":{"type":"object","description":"Query parameters for deploying from an uploaded image tarball","properties":{"health_check_path":{"type":["string","null"],"description":"Optional HTTP health-check path override (e.g. \"/api/healthz\").\nMust start with '/'. When omitted, defaults to \"/\".","example":"/api/healthz"},"tag":{"type":["string","null"],"description":"Tag to apply to the imported image (e.g., \"myapp:v1.0\")\nIf not provided, a unique tag will be generated","example":"myapp:v1.0"}}},"DeployFromStaticRequest":{"type":"object","required":["static_bundle_id"],"properties":{"health_check_path":{"type":["string","null"],"description":"Optional HTTP health-check path override (e.g. \"/api/healthz\").\nStatic deploys can't read `.temps.yaml`, so this sets the path the deployer\nprobes after the container starts and the path the environment's uptime\nmonitor checks. Must start with '/'. When omitted, defaults to \"/\".","example":"/api/healthz"},"metadata":{"description":"Optional deployment metadata"},"static_bundle_id":{"type":"integer","format":"int32","description":"Static bundle ID (required)"}}},"DeploymentConfig":{"type":"object","description":"Deployment configuration shared between projects and environments\n\nThis configuration can be set at the project level (as defaults) and\noverridden at the environment level for specific deployments.\n\nNote: Environment variables are managed separately and are not part of this config.","properties":{"antiAffinity":{"type":"boolean","description":"Anti-affinity: spread replicas across different nodes.\n\nWhen enabled, the scheduler avoids placing two replicas of the same\nenvironment on the same node. If there are fewer eligible nodes than\nreplicas, remaining replicas wrap around (best-effort spreading).\n\nDefaults to `true` — replicas spread by default."},"automaticDeploy":{"type":["boolean","null"],"description":"Enable automatic deployments on git push.\n`None` = inherit from project config; `Some(true/false)` = explicit override.\nStored as JSONB so absent key → `None` (inherit), never silently defaults to false."},"containerExecEnabled":{"type":"boolean","description":"Enable container exec/shell access (disabled by default for security)"},"cpuLimit":{"type":["integer","null"],"format":"int32","description":"CPU limit in microcores, where 1_000_000 = 1 full CPU core\n(e.g., 2_000_000 = 2 CPUs). NOT millicores. `None` = uncapped."},"cpuRequest":{"type":["integer","null"],"format":"int32","description":"CPU request in microcores, where 1_000_000 = 1 full CPU core\n(e.g., 100_000 = 0.1 CPU, 500_000 = 0.5 CPU, 2_000_000 = 2 CPUs).\nNOT millicores — the deployer formats this as `{n}u` and converts\n`n / 1_000_000` cores into Docker nano_cpus."},"crossArchitectureBuilds":{"type":["boolean","null"],"description":"Build one image per architecture the eligible nodes run.\n\n`None`/`false` (the default) builds exactly once, on the control\nplane's native platform — byte-for-byte the behaviour of a\nsingle-architecture cluster. When enabled and the nodes this\ndeployment could land on span more than one architecture, the build\njob produces one image per architecture; the non-native ones go\nthrough the daemon's `platform` option, which requires QEMU binfmt\nhandlers registered on the control plane.\n\n**Opt-in on purpose.** Cross-architecture builds are emulated and\nsubstantially slower, and deriving them from cluster topology would\nmean a single node joining silently changes build behaviour for every\ndeployment in the cluster. It also keeps the decision on operator\nconfig rather than on a value each node reports about itself.\n\n`Option` so an environment inherits the project's setting\n(`None`) or overrides it, matching `automatic_deploy`."},"exposedPort":{"type":["integer","null"],"format":"int32","description":"Port exposed by the container\nIf not specified, will be auto-detected from Docker image or default to 3000"},"idleTimeoutSeconds":{"type":"integer","format":"int32","description":"Seconds of inactivity before containers are stopped in on-demand mode.\nOnly used when `on_demand` is true. Min: 60, Max: 86400 (24h).\nDefault: 300 (5 minutes)."},"memoryLimit":{"type":["integer","null"],"format":"int32","description":"Memory limit in megabytes. Three-state semantics:\n- `None` → inherit the parent layer (env inherits project, project\n inherits the seeded default); used by the settings UI's \"Use default\".\n- `Some(0)` → explicit **uncapped**: stop inheriting and run with no\n memory limit. This is the deliberate escape hatch for dedicated\n workloads, distinct from `None`.\n- `Some(n)` → hard cap of `n` MB.\n\n`merge`/resolution keep `Some(0)` as a present value (it wins precedence\nover a parent cap), and the deployer collapses it to \"no limit\" before\ntalking to Docker."},"memoryRequest":{"type":["integer","null"],"format":"int32","description":"Memory request in megabytes (e.g., 128 = 128MB)"},"onDemand":{"type":"boolean","description":"Enable on-demand mode (scale-to-zero).\nWhen enabled, containers are stopped after `idle_timeout_seconds` of no traffic\nand automatically started when a new request arrives."},"performanceMetricsEnabled":{"type":"boolean","description":"Enable performance metrics collection (speed insights)"},"replicas":{"type":"integer","format":"int32","description":"Number of replicas/instances to run\nDefaults to 1 replica"},"security":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SecurityConfig","description":"Security configuration (headers, rate limiting, attack mode, etc.)\nThese settings inherit and override from parent level (Environment > Project > Global)"}]},"sessionRecordingEnabled":{"type":"boolean","description":"Enable session recording for analytics"},"targetLabels":{"description":"Label selector for node-based scheduling. Replicas are only deployed to\nnodes whose labels match the selector.\n\nMatching rules:\n- **Same key, array value** → OR: node must match any value\n- **Different keys** → AND: node must satisfy all keys\n\nExample: `{\"region\": [\"us\", \"asia\"], \"gpu\": \"true\"}`\n→ (region=us OR region=asia) AND gpu=true\n\nApplied after `target_nodes` filtering (they stack)."},"targetNodes":{"type":["array","null"],"items":{"type":"integer","format":"int32"},"description":"Optional list of node IDs to deploy to. When set, replicas are distributed\nonly across these nodes (round-robin). When None, the scheduler distributes\nacross all active nodes (or deploys locally if no nodes exist)."},"wakeTimeoutSeconds":{"type":"integer","format":"int32","description":"Max seconds to wait for containers to start when waking from on-demand sleep.\nRequests return 503 if exceeded. Default: 30."}}},"DeploymentConfigSnapshot":{"type":"object","description":"Deployment configuration snapshot for deployments\n\nThis extends DeploymentConfig with environment variables to capture\nthe complete state of a deployment at the time it was created.","properties":{"automaticDeploy":{"type":"boolean","description":"Enable automatic deployments on git push"},"containerExecEnabled":{"type":"boolean","description":"Enable container exec/shell access"},"cpuLimit":{"type":["integer","null"],"format":"int32","description":"CPU limit in millicores"},"cpuRequest":{"type":["integer","null"],"format":"int32","description":"CPU request in millicores"},"environmentVariables":{"type":"object","description":"Environment variables used for this deployment","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"exposedPort":{"type":["integer","null"],"format":"int32","description":"Port exposed by the container"},"memoryLimit":{"type":["integer","null"],"format":"int32","description":"Memory limit in megabytes"},"memoryRequest":{"type":["integer","null"],"format":"int32","description":"Memory request in megabytes"},"performanceMetricsEnabled":{"type":"boolean","description":"Enable performance metrics collection"},"replicas":{"type":"integer","format":"int32","description":"Number of replicas"},"sessionRecordingEnabled":{"type":"boolean","description":"Enable session recording"}}},"DeploymentConfiguration":{"type":"object","description":"Deployment-level configuration","required":["image","strategy","env_vars","ports","volumes","network","resources"],"properties":{"build":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/BuildConfiguration","description":"Build configuration (if building from source)"}]},"command":{"type":["array","null"],"items":{"type":"string"},"description":"Command override"},"entrypoint":{"type":["array","null"],"items":{"type":"string"},"description":"Entrypoint override"},"env_vars":{"type":"array","items":{"$ref":"#/components/schemas/EnvironmentVariable"},"description":"Environment variables"},"git":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/GitSourcePlan","description":"Where the application's source code lives, when the source platform\nbuilds from a git repository. Execution uses this to link the temps\nproject to the same repository so the real deployment pipeline can\nclone and build it."}]},"health_check":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/HealthCheckConfiguration","description":"Health check configuration"}]},"image":{"type":"string","description":"Image to deploy"},"network":{"$ref":"#/components/schemas/NetworkConfiguration","description":"Network configuration"},"ports":{"type":"array","items":{"$ref":"#/components/schemas/PortMapping"},"description":"Port mappings"},"resources":{"$ref":"#/components/schemas/ResourceLimits","description":"Resource limits"},"strategy":{"$ref":"#/components/schemas/DeploymentStrategy","description":"Deployment strategy"},"volumes":{"type":"array","items":{"$ref":"#/components/schemas/VolumeMount"},"description":"Volume mounts"},"working_dir":{"type":["string","null"],"description":"Working directory"}}},"DeploymentContainerLogContentResponse":{"type":"object","description":"A single captured container-log dump, including its full text content.","required":["id","container_name","size_bytes","truncated","captured_at","content"],"properties":{"captured_at":{"type":"integer","format":"int64"},"container_name":{"type":"string"},"content":{"type":"string","description":"The captured plain-text log content."},"id":{"type":"integer","format":"int32"},"service_name":{"type":["string","null"]},"size_bytes":{"type":"integer","format":"int64"},"truncated":{"type":"boolean"}}},"DeploymentContainerLogResponse":{"type":"object","description":"Metadata for one captured (historical) container-log dump. Listed on the\ndeployment detail page so a user can pick which past container's logs to read.","required":["id","deployment_id","container_id","container_name","size_bytes","truncated","captured_at"],"properties":{"captured_at":{"type":"integer","format":"int64","description":"Unix epoch milliseconds of when the logs were captured (just before\nteardown). Matches the timestamp convention used by `DeploymentResponse`."},"container_id":{"type":"string"},"container_name":{"type":"string"},"deployment_id":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"node_id":{"type":["integer","null"],"format":"int32"},"service_name":{"type":["string","null"]},"size_bytes":{"type":"integer","format":"int64"},"truncated":{"type":"boolean"}}},"DeploymentContainerLogsListResponse":{"type":"object","description":"The list of captured container-log dumps for a deployment.","required":["logs"],"properties":{"logs":{"type":"array","items":{"$ref":"#/components/schemas/DeploymentContainerLogResponse"}}}},"DeploymentEnvironmentResponse":{"type":"object","required":["id","name","slug","domains"],"properties":{"domains":{"type":"array","items":{"type":"string"}},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"slug":{"type":"string"}}},"DeploymentJobResponse":{"type":"object","required":["id","deployment_id","job_id","job_type","name","status","created_at","updated_at","log_id"],"properties":{"created_at":{"type":"integer","format":"int64"},"dependencies":{},"deployment_id":{"type":"integer","format":"int32"},"description":{"type":["string","null"]},"error_message":{"type":["string","null"]},"execution_order":{"type":["integer","null"],"format":"int32"},"finished_at":{"type":["integer","null"],"format":"int64"},"id":{"type":"integer","format":"int32"},"job_config":{"description":"Internal workflow configuration is intentionally redacted. It can\ncontain legacy plaintext secrets or encrypted secret envelopes."},"job_id":{"type":"string"},"job_type":{"type":"string"},"log_id":{"type":"string"},"name":{"type":"string"},"outputs":{},"started_at":{"type":["integer","null"],"format":"int64"},"status":{"type":"string"},"updated_at":{"type":"integer","format":"int64"}}},"DeploymentJobsResponse":{"type":"object","required":["jobs","total"],"properties":{"jobs":{"type":"array","items":{"$ref":"#/components/schemas/DeploymentJobResponse"}},"total":{"type":"integer","minimum":0}}},"DeploymentListResponse":{"type":"object","required":["deployments","total","page","per_page"],"properties":{"deployments":{"type":"array","items":{"$ref":"#/components/schemas/DeploymentResponse"}},"page":{"type":"integer","format":"int64"},"per_page":{"type":"integer","format":"int64"},"total":{"type":"integer","format":"int64"}}},"DeploymentMetadata":{"type":"object","description":"Deployment metadata - typed information about the deployment","properties":{"buildDurationMs":{"type":["integer","null"],"format":"int64","description":"Build duration in milliseconds"},"builder":{"type":["string","null"],"description":"Docker builder used (e.g., \"nixpacks\", \"dockerfile\")"},"deploymentDurationMs":{"type":["integer","null"],"format":"int64","description":"Deployment duration in milliseconds"},"deploymentSourceType":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SourceType","description":"Source type for THIS specific deployment (for Manual/flexible projects)\nThis allows Manual projects to have deployments via different methods\n(docker_image, static_files, or git) while keeping per-deployment tracking"}]},"dockerfilePath":{"type":["string","null"],"description":"Dockerfile path if using Dockerfile builder"},"externalImageId":{"type":["integer","null"],"format":"int32","description":"External image ID (reference to external_images table)"},"externalImageRef":{"type":["string","null"],"description":"External Docker image reference (for docker_image source type)\ne.g., \"ghcr.io/org/app:v1.0\" or \"docker.io/myapp:sha-abc123\""},"fileCount":{"type":["integer","null"],"format":"int32","description":"Number of files in the build output"},"gitPushEvent":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/GitPushEvent","description":"Git push event that triggered this deployment (if from webhook)"}]},"healthCheckPath":{"type":["string","null"],"description":"Explicit deploy-time HTTP health-check path override.\nImage/static deploys can't read `.temps.yaml`, so this lets the deploy\nrequest set a custom path (e.g. \"/api/healthz\"). When present it takes\npriority over any `.temps.yaml` `health.path` value. Always starts with '/'."},"imageSizeBytes":{"type":["integer","null"],"format":"int64","description":"Total size of the built image in bytes"},"imageUploadedLocally":{"type":"boolean","description":"Whether the image was uploaded directly (via docker save/load) rather than pulled from registry\nWhen true, the PullExternalImageJob is skipped since the image is already loaded locally"},"isRollback":{"type":"boolean","description":"Whether this is a rollback deployment"},"labels":{"type":"array","items":{"type":"string"},"description":"Custom labels/tags for the deployment"},"rolledBackFromId":{"type":["integer","null"],"format":"int32","description":"ID of the deployment this was rolled back from (if applicable)"},"staticBundleContentType":{"type":["string","null"],"description":"Static bundle content type (for proper extraction: application/gzip or application/zip)"},"staticBundleId":{"type":["integer","null"],"format":"int32","description":"Static bundle ID (reference to static_bundles table, for static_files source type)"},"staticBundlePath":{"type":["string","null"],"description":"Static bundle path in blob storage (for static_files source type)"},"uploadedImageId":{"type":["string","null"],"description":"Docker image ID of the locally uploaded image (sha256:...)\nUsed to verify the image exists before deployment"}}},"DeploymentResponse":{"type":"object","required":["id","project_id","environment_id","environment","status","url","created_at","is_current"],"properties":{"branch":{"type":["string","null"]},"cancelled_reason":{"type":["string","null"]},"commit_author":{"type":["string","null"]},"commit_date":{"type":["integer","null"],"format":"int64"},"commit_hash":{"type":["string","null"]},"commit_message":{"type":["string","null"]},"created_at":{"type":"integer","format":"int64"},"deployment_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DeploymentConfigSnapshot","description":"Deployment configuration snapshot (CPU, memory, replicas, environment variables, etc.)"}]},"environment":{"$ref":"#/components/schemas/DeploymentEnvironmentResponse"},"environment_id":{"type":"integer","format":"int32"},"finished_at":{"type":["integer","null"],"format":"int64"},"id":{"type":"integer","format":"int32"},"is_current":{"type":"boolean"},"metadata":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DeploymentMetadata","description":"Deployment metadata (build info, git event, etc.)"}]},"project_id":{"type":"integer","format":"int32"},"screenshot_location":{"type":["string","null"]},"started_at":{"type":["integer","null"],"format":"int64"},"status":{"type":"string"},"tag":{"type":["string","null"]},"url":{"type":"string"}}},"DeploymentStateResponse":{"type":"object","required":["id","state","message"],"properties":{"id":{"type":"integer","format":"int32"},"message":{"type":"string"},"state":{"type":"string"}}},"DeploymentStrategy":{"type":"string","description":"Deployment strategy","enum":["replace","blue-green","rolling"]},"DeploymentTokenListResponse":{"type":"object","required":["tokens","total"],"properties":{"tokens":{"type":"array","items":{"$ref":"#/components/schemas/DeploymentTokenResponse"}},"total":{"type":"integer","format":"int64","minimum":0}}},"DeploymentTokenResponse":{"type":"object","required":["id","project_id","name","token_prefix","is_active","created_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00Z"},"created_by":{"type":["integer","null"],"format":"int32"},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"last_used_at":{"type":["string","null"],"format":"date-time","example":"2024-01-01T00:00:00Z"},"name":{"type":"string"},"permissions":{"type":["array","null"],"items":{"type":"string"}},"project_id":{"type":"integer","format":"int32"},"token_prefix":{"type":"string"}}},"DetectionConfig":{"oneOf":[{"allOf":[{"$ref":"#/components/schemas/StaticParams","description":"v0 (shipping): static threshold comparison of the aggregated value."},{"type":"object","required":["kind"],"properties":{"kind":{"type":"string","enum":["static"]}}}],"description":"v0 (shipping): static threshold comparison of the aggregated value."},{"allOf":[{"$ref":"#/components/schemas/AnomalyParams","description":"Seasonal anomaly band (basic/agile/robust/ewma share this variant — the\nalgorithm is a field, not a new kind). Creation rejected until evaluated."},{"type":"object","required":["kind"],"properties":{"kind":{"type":"string","enum":["anomaly"]}}}],"description":"Seasonal anomaly band (basic/agile/robust/ewma share this variant — the\nalgorithm is a field, not a new kind). Creation rejected until evaluated."},{"allOf":[{"$ref":"#/components/schemas/ForecastParams","description":"Predict a future threshold breach (capacity planning). Stub."},{"type":"object","required":["kind"],"properties":{"kind":{"type":"string","enum":["forecast"]}}}],"description":"Predict a future threshold breach (capacity planning). Stub."},{"allOf":[{"$ref":"#/components/schemas/OutlierParams","description":"Cross-series population outlier (one host misbehaving vs its peers). Stub."},{"type":"object","required":["kind"],"properties":{"kind":{"type":"string","enum":["outlier"]}}}],"description":"Cross-series population outlier (one host misbehaving vs its peers). Stub."},{"allOf":[{"$ref":"#/components/schemas/AutoWatchParams","description":"Watchdog-style self-tuning auto-watch (engine picks bounds). Stub."},{"type":"object","required":["kind"],"properties":{"kind":{"type":"string","enum":["auto_watch"]}}}],"description":"Watchdog-style self-tuning auto-watch (engine picks bounds). Stub."}],"description":"The typed detector definition stored (as jsonb) in\n`metric_alert_rules.detection_config`.\n\nToday only [`DetectionConfig::Static`] is evaluable; the other variants are\nschema-present (so the SDK/UI and storage are already future-shaped) but\nrejected by [`DetectionConfig::validate`] until their evaluator lands. Each is\nthen enabled code-only, with no schema migration."},"DeviceCount":{"type":"object","required":["device_type","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"device_type":{"type":"string"},"percentage":{"type":"number","format":"double"}}},"DigestSections":{"type":"object","description":"Sections that can be included in the weekly digest\nNote: `#[serde(default)]` allows backward compatibility when deserializing\nold data that may have `security` and `resources` fields instead of `projects`","properties":{"deployments":{"type":"boolean","default":true},"errors":{"type":"boolean","default":true},"funnels":{"type":"boolean","default":true},"performance":{"type":"boolean","default":true},"projects":{"type":"boolean","default":true}}},"Direction":{"type":"string","description":"Which side(s) of an anomaly band count as a deviation.","enum":["both","above","below"]},"DisableBlobResponse":{"type":"object","description":"Response after disabling Blob service","required":["success","message"],"properties":{"message":{"type":"string","description":"Human-readable message","example":"Blob service disabled successfully"},"success":{"type":"boolean","description":"Whether the operation succeeded","example":true}}},"DisableKvResponse":{"type":"object","description":"Response after disabling KV service","required":["success","message"],"properties":{"message":{"type":"string","description":"Status message","example":"KV service disabled successfully"},"success":{"type":"boolean","description":"Whether the service was successfully disabled"}}},"DisableMfaRequest":{"type":"object","required":["code"],"properties":{"code":{"type":"string"}}},"DiscoverRequest":{"type":"object","description":"Request to discover workloads","required":["source"],"properties":{"credentials":{"$ref":"#/components/schemas/ImportCredentials","description":"Platform credentials (required for cloud platforms like Vercel, Railway)"},"selector":{"$ref":"#/components/schemas/ImportSelector","description":"Optional selector to filter workloads"},"source":{"$ref":"#/components/schemas/ImportSource","description":"Source to discover from"}}},"DiscoverResponse":{"type":"object","description":"Response with discovered workloads","required":["workloads"],"properties":{"workloads":{"type":"array","items":{"$ref":"#/components/schemas/WorkloadDescriptor"},"description":"Discovered workloads"}}},"DiskInfo":{"type":"object","description":"Disk space information for a single disk/partition","required":["mount_point","total_bytes","used_bytes","available_bytes","usage_percent","file_system"],"properties":{"available_bytes":{"type":"integer","format":"int64","description":"Available space in bytes","minimum":0},"file_system":{"type":"string","description":"File system type (e.g., \"ext4\", \"apfs\")"},"mount_point":{"type":"string","description":"Mount point of the disk"},"total_bytes":{"type":"integer","format":"int64","description":"Total space in bytes","minimum":0},"usage_percent":{"type":"number","format":"double","description":"Usage percentage (0-100)"},"used_bytes":{"type":"integer","format":"int64","description":"Used space in bytes","minimum":0}}},"DiskSpaceAlert":{"type":"object","description":"Alert for a disk that exceeds the threshold","required":["mount_point","usage_percent","threshold_percent","available_bytes","available_human"],"properties":{"available_bytes":{"type":"integer","format":"int64","description":"Available space in bytes","minimum":0},"available_human":{"type":"string","description":"Human-readable available space"},"mount_point":{"type":"string","description":"Mount point of the disk"},"threshold_percent":{"type":"integer","format":"int32","description":"Configured threshold percentage","minimum":0},"usage_percent":{"type":"number","format":"double","description":"Current usage percentage"}}},"DiskSpaceAlertSettings":{"type":"object","description":"Disk space alert settings for monitoring disk usage","properties":{"check_interval_seconds":{"type":"integer","format":"int64","description":"Interval in seconds between disk space checks","default":300,"example":300,"minimum":60},"enabled":{"type":"boolean","description":"Whether disk space alerts are enabled","default":true},"monitor_path":{"type":["string","null"],"description":"Restrict monitoring to the disk backing this path. When unset (the\ndefault), every mounted writable volume is monitored — including\ndedicated volumes such as `/var/lib/docker`.","default":null},"threshold_percent":{"type":"integer","format":"int32","description":"Threshold percentage (0-100) at which to trigger alerts","default":80,"example":80,"maximum":100,"minimum":0}}},"DiskSpaceCheckResult":{"type":"object","description":"Result of a disk space check","required":["checked_at","enabled","threshold_percent","disks","alerts"],"properties":{"alerts":{"type":"array","items":{"$ref":"#/components/schemas/DiskSpaceAlert"},"description":"Disks that meet or exceed the threshold"},"checked_at":{"type":"string","format":"date-time","description":"Timestamp of the check (ISO 8601, UTC)","example":"2026-05-28T12:15:47.609192Z"},"disks":{"type":"array","items":{"$ref":"#/components/schemas/DiskInfo"},"description":"List of all monitored disks"},"enabled":{"type":"boolean","description":"Whether disk space monitoring is enabled in settings"},"threshold_percent":{"type":"integer","format":"int32","description":"Configured alert threshold percentage (0-100)","minimum":0}}},"DnsAckRequest":{"type":"object","required":["applied_generation"],"properties":{"applied_generation":{"type":"integer","format":"int64","description":"Highest generation the agent has actually applied locally."}}},"DnsAckResponse":{"type":"object","required":["node_id","applied_generation","server_generation"],"properties":{"applied_generation":{"type":"integer","format":"int64"},"node_id":{"type":"integer","format":"int32"},"server_generation":{"type":"integer","format":"int64"}}},"DnsChallengeRecordResult":{"type":"object","description":"Result of a single DNS TXT record creation for ACME challenge","required":["name","value","success","message"],"properties":{"message":{"type":"string","description":"Human-readable message about the operation"},"name":{"type":"string","description":"TXT record name (e.g., \"_acme-challenge.example.com\")","example":"_acme-challenge.example.com"},"success":{"type":"boolean","description":"Whether the record was created successfully"},"value":{"type":"string","description":"TXT record value (the ACME challenge token)","example":"abc123..."}}},"DnsChangesResponse":{"type":"object","required":["generation","full_snapshot","records","removed_ids"],"properties":{"full_snapshot":{"type":"boolean","description":"`true` ⇒ replace the local zone with `records`. `false` ⇒ merge\n`records` into the existing zone (and remove `removed_ids`)."},"generation":{"type":"integer","format":"int64","description":"Highest generation included in this response. Agent ACKs this back."},"records":{"type":"array","items":{"$ref":"#/components/schemas/EndpointDto"}},"removed_ids":{"type":"array","items":{"type":"integer","format":"int64"},"description":"IDs the agent should remove from its zone. Always empty in the v1\nprotocol — the resolver reconciles by name on snapshot mode. Kept\nin the wire format so a future tombstone-based protocol doesn't\nrequire a breaking change."}}},"DnsCompletionResponse":{"type":"object","required":["domain","status"],"properties":{"domain":{"type":"string"},"status":{"type":"string"}}},"DnsLookupError":{"type":"object","description":"Error response for DNS lookup failures","required":["error","domain"],"properties":{"domain":{"type":"string","description":"Domain name that failed","example":"nonexistent.com"},"error":{"type":"string","description":"Error message","example":"DNS lookup failed: domain not found"}}},"DnsLookupRequest":{"type":"object","description":"Request to lookup DNS A records for a domain","required":["domain"],"properties":{"domain":{"type":"string","description":"Domain name to lookup","example":"example.com"}}},"DnsLookupResponse":{"type":"object","description":"Response containing DNS A records","required":["domain","records","count","dns_servers"],"properties":{"count":{"type":"integer","description":"Number of records found","example":1,"minimum":0},"dns_servers":{"type":"array","items":{"type":"string"},"description":"DNS servers used for the lookup","example":["8.8.8.8","8.8.4.4"]},"domain":{"type":"string","description":"Domain name that was queried","example":"example.com"},"records":{"type":"array","items":{"type":"string"},"description":"List of A record IP addresses","example":["93.184.216.34"]}}},"DnsProviderCredentials":{"oneOf":[{"type":"object","required":["api_token","type"],"properties":{"account_id":{"type":["string","null"]},"api_token":{"type":"string","example":"your-api-token"},"type":{"type":"string","enum":["cloudflare"]}}},{"type":"object","required":["api_user","api_key","type"],"properties":{"api_key":{"type":"string","example":"your-api-key"},"api_user":{"type":"string","example":"your-username"},"client_ip":{"type":["string","null"]},"sandbox":{"type":"boolean"},"type":{"type":"string","enum":["namecheap"]}}},{"type":"object","required":["access_key_id","secret_access_key","type"],"properties":{"access_key_id":{"type":"string","example":"AKIAIOSFODNN7EXAMPLE"},"region":{"type":["string","null"],"example":"us-east-1"},"secret_access_key":{"type":"string","example":"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"},"session_token":{"type":["string","null"]},"type":{"type":"string","enum":["route53"]}}},{"type":"object","required":["api_token","type"],"properties":{"api_token":{"type":"string","example":"dop_v1_your-token"},"type":{"type":"string","enum":["digitalocean"]}}},{"type":"object","required":["service_account_email","private_key","project_id","type"],"properties":{"private_key":{"type":"string","example":"-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----"},"project_id":{"type":"string","example":"my-gcp-project"},"service_account_email":{"type":"string","example":"dns-admin@myproject.iam.gserviceaccount.com"},"type":{"type":"string","enum":["gcp"]}}},{"type":"object","required":["tenant_id","client_id","client_secret","subscription_id","resource_group","type"],"properties":{"client_id":{"type":"string","example":"00000000-0000-0000-0000-000000000000"},"client_secret":{"type":"string"},"resource_group":{"type":"string","example":"my-resource-group"},"subscription_id":{"type":"string","example":"00000000-0000-0000-0000-000000000000"},"tenant_id":{"type":"string","example":"00000000-0000-0000-0000-000000000000"},"type":{"type":"string","enum":["azure"]}}},{"type":"object","description":"Pebble challtestsrv mock DNS (LOCAL DEV/TEST ONLY)","required":["management_url","type"],"properties":{"management_url":{"type":"string","example":"http://localhost:8055"},"type":{"type":"string","enum":["pebble"]}}}],"description":"DNS provider credentials (API-facing)"},"DnsProviderResponse":{"type":"object","description":"DNS provider response","required":["id","name","provider_type","credentials","is_active","flat_hostnames_supported","created_at","updated_at"],"properties":{"created_at":{"type":"string"},"credentials":{"description":"Masked credentials for display"},"description":{"type":["string","null"]},"flat_hostnames_supported":{"type":"boolean","description":"Whether this provider benefits from the flat hostname mode (e.g. Cloudflare\nUniversal SSL). The UI surfaces/recommends the Flat toggle when true."},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"last_error":{"type":["string","null"]},"last_used_at":{"type":["string","null"]},"name":{"type":"string"},"provider_type":{"type":"string"},"updated_at":{"type":"string"}}},"DnsProviderSettings":{"type":"object","properties":{"cloudflare_api_key":{"type":["string","null"],"default":null},"provider":{"type":"string","default":"manual"}}},"DnsProviderSettingsMasked":{"type":"object","description":"DNS provider settings with masked sensitive fields","required":["provider"],"properties":{"cloudflare_api_key":{"type":["string","null"]},"provider":{"type":"string"}}},"DnsProviderType":{"type":"string","description":"Supported DNS provider types","enum":["cloudflare","namecheap","route53","digitalocean","gcp","azure","manual","pebble"]},"DnsRecord":{"type":"object","description":"A DNS record","required":["zone","name","fqdn","content","ttl"],"properties":{"content":{"$ref":"#/components/schemas/DnsRecordContent","description":"Record content"},"fqdn":{"type":"string","description":"Fully qualified domain name","example":"www.example.com"},"id":{"type":["string","null"],"description":"Provider-specific record ID (if exists)","example":"abc123"},"metadata":{"type":"object","description":"Provider-specific metadata","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"name":{"type":"string","description":"Record name (without zone, e.g., \"www\" or \"@\" for root)","example":"www"},"proxied":{"type":"boolean","description":"Whether this record is proxied (Cloudflare-specific)"},"ttl":{"type":"integer","format":"int32","description":"Time to live in seconds","example":300,"minimum":0},"zone":{"type":"string","description":"Zone/domain this record belongs to","example":"example.com"}}},"DnsRecordChange":{"type":"object","description":"A single DNS record change the Cloudflare sync would make.","required":["action","name","record_type","value"],"properties":{"action":{"type":"string","description":"`\"create\"`, `\"update\"`, or `\"delete\"`."},"name":{"type":"string"},"record_type":{"type":"string","description":"Record type, e.g. `\"A\"` or `\"CNAME\"`."},"value":{"type":"string"}}},"DnsRecordContent":{"oneOf":[{"type":"object","description":"A record - IPv4 address (as string, e.g., \"192.0.2.1\")","required":["value","type"],"properties":{"type":{"type":"string","enum":["A"]},"value":{"type":"object","description":"A record - IPv4 address (as string, e.g., \"192.0.2.1\")","required":["address"],"properties":{"address":{"type":"string","example":"192.0.2.1"}}}}},{"type":"object","description":"AAAA record - IPv6 address (as string, e.g., \"2001:db8::1\")","required":["value","type"],"properties":{"type":{"type":"string","enum":["AAAA"]},"value":{"type":"object","description":"AAAA record - IPv6 address (as string, e.g., \"2001:db8::1\")","required":["address"],"properties":{"address":{"type":"string","example":"2001:db8::1"}}}}},{"type":"object","description":"CNAME record - canonical name","required":["value","type"],"properties":{"type":{"type":"string","enum":["CNAME"]},"value":{"type":"object","description":"CNAME record - canonical name","required":["target"],"properties":{"target":{"type":"string"}}}}},{"type":"object","description":"TXT record - text content","required":["value","type"],"properties":{"type":{"type":"string","enum":["TXT"]},"value":{"type":"object","description":"TXT record - text content","required":["content"],"properties":{"content":{"type":"string"}}}}},{"type":"object","description":"MX record - mail exchange","required":["value","type"],"properties":{"type":{"type":"string","enum":["MX"]},"value":{"type":"object","description":"MX record - mail exchange","required":["priority","target"],"properties":{"priority":{"type":"integer","format":"int32","minimum":0},"target":{"type":"string"}}}}},{"type":"object","description":"NS record - nameserver","required":["value","type"],"properties":{"type":{"type":"string","enum":["NS"]},"value":{"type":"object","description":"NS record - nameserver","required":["nameserver"],"properties":{"nameserver":{"type":"string"}}}}},{"type":"object","description":"SRV record - service","required":["value","type"],"properties":{"type":{"type":"string","enum":["SRV"]},"value":{"type":"object","description":"SRV record - service","required":["priority","weight","port","target"],"properties":{"port":{"type":"integer","format":"int32","minimum":0},"priority":{"type":"integer","format":"int32","minimum":0},"target":{"type":"string"},"weight":{"type":"integer","format":"int32","minimum":0}}}}},{"type":"object","description":"CAA record - certification authority authorization","required":["value","type"],"properties":{"type":{"type":"string","enum":["CAA"]},"value":{"type":"object","description":"CAA record - certification authority authorization","required":["flags","tag","value"],"properties":{"flags":{"type":"integer","format":"int32","minimum":0},"tag":{"type":"string"},"value":{"type":"string"}}}}},{"type":"object","description":"PTR record - pointer","required":["value","type"],"properties":{"type":{"type":"string","enum":["PTR"]},"value":{"type":"object","description":"PTR record - pointer","required":["target"],"properties":{"target":{"type":"string"}}}}}],"description":"DNS record content - varies by record type"},"DnsRecordResponse":{"type":"object","required":["record_type","name","value","status"],"properties":{"name":{"type":"string","description":"DNS record name (host)","example":"temps._domainkey.example.com"},"priority":{"type":["integer","null"],"format":"int32","description":"Priority (for MX records)","example":"10","minimum":0},"record_type":{"type":"string","description":"Record type: TXT, CNAME, MX","example":"TXT"},"status":{"$ref":"#/components/schemas/DnsRecordStatusResponse","description":"Verification status: unknown, verified, pending, failed"},"value":{"type":"string","description":"DNS record value","example":"v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3..."}}},"DnsRecordSetupResult":{"type":"object","description":"Result of a single DNS record creation","required":["record_type","name","success","automatic","message"],"properties":{"automatic":{"type":"boolean","description":"Whether the operation was automatic or manual"},"message":{"type":"string","description":"Human-readable message"},"name":{"type":"string","description":"Record name"},"record_type":{"type":"string","description":"Record type (TXT, CNAME, MX)"},"success":{"type":"boolean","description":"Whether the record was created successfully"}}},"DnsRecordStatusResponse":{"type":"string","description":"DNS record verification status","enum":["unknown","verified","pending","failed"]},"DnsZone":{"type":"object","description":"A DNS zone (domain managed by the provider)","required":["id","name","status","nameservers"],"properties":{"id":{"type":"string","description":"Provider-specific zone ID","example":"zone123"},"metadata":{"type":"object","description":"Provider-specific metadata","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"name":{"type":"string","description":"Zone name (domain)","example":"example.com"},"nameservers":{"type":"array","items":{"type":"string"},"description":"Nameservers for this zone"},"status":{"type":"string","description":"Zone status","example":"active"}}},"DockerComposePresetConfig":{"type":"object","description":"Configuration for Docker Compose deployments.","properties":{"composeOverride":{"type":["string","null"],"description":"User-provided docker-compose.override.yml content."},"composePath":{"type":["string","null"],"description":"Path to the Compose file relative to the project directory."},"publicPorts":{"type":"array","items":{"$ref":"#/components/schemas/ComposePublicPort"},"description":"Compose service ports that should be publicly routed."}}},"DockerRegistrySettings":{"type":"object","properties":{"ca_certificate":{"type":["string","null"],"default":null},"enabled":{"type":"boolean","default":false},"password":{"type":["string","null"],"default":null},"registry_url":{"type":["string","null"],"default":null},"tls_verify":{"type":"boolean","default":true},"username":{"type":["string","null"],"default":null}}},"DockerRegistrySettingsMasked":{"type":"object","description":"Docker registry settings with masked sensitive fields","required":["enabled","tls_verify"],"properties":{"ca_certificate":{"type":["string","null"]},"enabled":{"type":"boolean"},"password":{"type":["string","null"]},"registry_url":{"type":["string","null"]},"tls_verify":{"type":"boolean"},"username":{"type":["string","null"]}}},"DockerfilePresetConfig":{"type":"object","description":"Configuration for Dockerfile preset\nAllows customizing the Dockerfile path and build context for Docker-based deployments","properties":{"buildContext":{"type":["string","null"],"description":"Custom build context path (relative to repository root)\nIf not specified, uses the project's directory setting","example":"./api"},"dockerfilePath":{"type":["string","null"],"description":"Custom Dockerfile path (relative to build context)\nIf not specified, defaults to \"Dockerfile\" in the build context","example":"docker/Dockerfile"},"variant":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DockerfileVariant","description":"Catalog variant. Normally omitted; `custom` selects the generated\nDockerfile compatibility preset."}]}}},"DockerfileVariant":{"type":"string","description":"Catalog variant persisted under the canonical Dockerfile preset.\n\nExisting rows predate this discriminator and therefore deserialize as\n[`DockerfileVariant::File`].","enum":["file","custom"]},"DomainAction":{"type":"string","description":"What to do with a domain during migration","enum":["import","skip"]},"DomainChallengeResponse":{"type":"object","required":["domain","txt_records","status"],"properties":{"domain":{"type":"string"},"status":{"type":"string"},"txt_records":{"type":"array","items":{"$ref":"#/components/schemas/TxtRecord"},"description":"Array of TXT records to add to DNS. For wildcards, multiple records are required."}}},"DomainEnvironmentResponse":{"type":"object","required":["id","name","slug"],"properties":{"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"slug":{"type":"string"}}},"DomainError":{"type":"object","required":["message","code"],"properties":{"code":{"type":"string"},"details":{"type":["string","null"]},"message":{"type":"string"}}},"DomainPlan":{"type":"object","description":"Plan for migrating a single custom domain","required":["domain","environment","action","action_description"],"properties":{"action":{"$ref":"#/components/schemas/DomainAction","description":"What to do with this domain"},"action_description":{"type":"string","description":"Human-readable explanation"},"domain":{"type":"string","description":"Full domain name"},"environment":{"type":"string","description":"Which environment to associate with (\"production\")"},"redirect_to":{"type":["string","null"],"description":"Redirect target (if this is a redirect domain)"},"replacement":{"type":["string","null"],"description":"The temps-side address that replaces this domain when it is skipped.\n\nSource-generated domains (sslip.io / traefik.me / platform subdomains)\nembed the source server's IP and would keep pointing at the old\nmachine — this tells the user where the app will be reachable on\ntemps instead."},"status_code":{"type":["integer","null"],"format":"int32","description":"Redirect status code"}}},"DomainResponse":{"type":"object","required":["id","domain","status","is_wildcard","verification_method","created_at","updated_at"],"properties":{"certificate":{"type":["string","null"],"description":"The PEM-encoded certificate chain (can be displayed in browser or downloaded)"},"created_at":{"type":"integer","format":"int64"},"dns_challenge_token":{"type":["string","null"]},"dns_challenge_value":{"type":["string","null"]},"domain":{"type":"string"},"expiration_time":{"type":["integer","null"],"format":"int64"},"id":{"type":"integer","format":"int32"},"is_wildcard":{"type":"boolean"},"last_error":{"type":["string","null"]},"last_error_type":{"type":["string","null"]},"last_renewed":{"type":["integer","null"],"format":"int64"},"on_demand_backoff_until":{"type":["integer","null"],"format":"int64","description":"On-demand TLS negative-cache deadline (epoch millis), when this hostname's\non-demand HTTP-01 issuance is in backoff after a failure (ADR-018 §4).\n`None` means no active backoff."},"status":{"type":"string"},"updated_at":{"type":"integer","format":"int64"},"verification_method":{"type":"string"}}},"DrainNodeResponse":{"type":"object","required":["id","name","status","affected_environments","message"],"properties":{"affected_environments":{"type":"integer","minimum":0},"id":{"type":"integer","format":"int32"},"message":{"type":"string"},"name":{"type":"string"},"status":{"type":"string"}}},"DrainStatusResponse":{"type":"object","description":"Progress of a node drain operation.","required":["node_id","node_name","status","remaining_containers","drain_complete","can_remove","message"],"properties":{"can_remove":{"type":"boolean","description":"Can the node be safely removed?"},"drain_complete":{"type":"boolean","description":"Whether the drain is complete (all containers migrated)"},"message":{"type":"string"},"node_id":{"type":"integer","format":"int32"},"node_name":{"type":"string"},"remaining_containers":{"type":"integer","description":"Number of containers still on this node","minimum":0},"status":{"type":"string"}}},"DropArchiveUpload":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary"}}},"DropInspectionResponse":{"type":"object","required":["suggestedName","candidates"],"properties":{"candidates":{"type":"array","items":{"$ref":"#/components/schemas/DropPresetCandidate"}},"suggestedName":{"type":"string"}}},"DropOffPoint":{"type":"object","description":"Drop-off point: pages where visitors leave the site","required":["page_path","exit_count","total_views","exit_rate"],"properties":{"exit_count":{"type":"integer","format":"int64","description":"Number of exits from this page"},"exit_rate":{"type":"number","format":"double","description":"Exit rate for this page (exit_count / total_views)"},"page_path":{"type":"string","description":"The page path where visitors drop off"},"total_views":{"type":"integer","format":"int64","description":"Total views of this page"}}},"DropPresetCandidate":{"type":"object","required":["directory","preset","label","confidence","reason","isStatic"],"properties":{"confidence":{"type":"string"},"directory":{"type":"string"},"isStatic":{"type":"boolean"},"label":{"type":"string"},"preset":{"type":"string"},"reason":{"type":"string"}}},"EmailConfig":{"type":"object","required":["smtp_host","smtp_port","username","password","from_address","to_addresses"],"properties":{"accept_invalid_certs":{"type":"boolean"},"from_address":{"type":"string"},"from_name":{"type":["string","null"]},"password":{"type":"string"},"smtp_host":{"type":"string"},"smtp_port":{"type":"integer","format":"int32","minimum":0},"starttls_required":{"type":"boolean"},"tls_mode":{"$ref":"#/components/schemas/TlsMode"},"to_addresses":{"type":"array","items":{"type":"string"}},"username":{"type":"string"}}},"EmailDomainResponse":{"type":"object","required":["id","provider_id","domain","status","created_at","updated_at"],"properties":{"created_at":{"type":"string","example":"2025-12-03T10:30:00Z"},"domain":{"type":"string","example":"updates.example.com"},"id":{"type":"integer","format":"int32"},"last_verified_at":{"type":["string","null"]},"provider_id":{"type":"integer","format":"int32"},"status":{"type":"string","example":"verified"},"updated_at":{"type":"string","example":"2025-12-03T10:30:00Z"},"verification_error":{"type":["string","null"]}}},"EmailDomainWithDnsResponse":{"type":"object","required":["domain","dns_records"],"properties":{"dns_records":{"type":"array","items":{"$ref":"#/components/schemas/DnsRecordResponse"}},"domain":{"$ref":"#/components/schemas/EmailDomainResponse"}}},"EmailProviderResponse":{"type":"object","required":["id","name","provider_type","region","is_active","credentials","created_at","updated_at"],"properties":{"created_at":{"type":"string","example":"2025-12-03T10:30:00Z"},"credentials":{"description":"Masked credentials for display"},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"name":{"type":"string","example":"My AWS SES"},"provider_type":{"$ref":"#/components/schemas/EmailProviderTypeRoute"},"region":{"type":"string","example":"us-east-1"},"sns_topic_arn":{"type":["string","null"]},"updated_at":{"type":"string","example":"2025-12-03T10:30:00Z"}}},"EmailProviderTypeRoute":{"type":"string","enum":["ses","scaleway","smtp"]},"EmailRequest":{"type":"object","description":"Request body carrying just an email address (password-reset request).","required":["email"],"properties":{"email":{"type":"string"}}},"EmailResponse":{"type":"object","required":["id","from_address","to_addresses","subject","status","created_at","track_opens","track_clicks","open_count","click_count"],"properties":{"bcc_addresses":{"type":["array","null"],"items":{"type":"string"}},"cc_addresses":{"type":["array","null"],"items":{"type":"string"}},"click_count":{"type":"integer","format":"int32","description":"Number of times links in the email were clicked"},"created_at":{"type":"string","example":"2025-12-03T10:30:00Z"},"domain_id":{"type":["integer","null"],"format":"int32"},"error_message":{"type":["string","null"]},"first_clicked_at":{"type":["string","null"],"description":"When a link was first clicked"},"first_opened_at":{"type":["string","null"],"description":"When the email was first opened"},"from_address":{"type":"string","example":"hello@updates.example.com"},"from_name":{"type":["string","null"]},"headers":{"type":["object","null"],"additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"html_body":{"type":["string","null"]},"id":{"type":"string","example":"550e8400-e29b-41d4-a716-446655440000"},"open_count":{"type":"integer","format":"int32","description":"Number of times the email was opened"},"project_id":{"type":["integer","null"],"format":"int32"},"provider_message_id":{"type":["string","null"]},"reply_to":{"type":["string","null"]},"sent_at":{"type":["string","null"]},"status":{"type":"string","example":"sent"},"subject":{"type":"string"},"tags":{"type":["array","null"],"items":{"type":"string"}},"text_body":{"type":["string","null"]},"to_addresses":{"type":"array","items":{"type":"string"}},"track_clicks":{"type":"boolean","description":"Whether click tracking is enabled"},"track_opens":{"type":"boolean","description":"Whether open tracking is enabled"},"tracked_html_body":{"type":["string","null"],"description":"The final HTML sent to the provider (with tracking pixel and rewritten links)"}}},"EmailStatsResponse":{"type":"object","required":["total","sent","failed","queued","captured"],"properties":{"captured":{"type":"integer","format":"int64","description":"Emails captured without sending (Mailhog mode - no provider configured)","minimum":0},"failed":{"type":"integer","format":"int64","minimum":0},"queued":{"type":"integer","format":"int64","minimum":0},"sent":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"EmailStatusResponse":{"type":"object","required":["email_configured","password_reset_available","oidc_providers"],"properties":{"email_configured":{"type":"boolean"},"oidc_providers":{"type":"array","items":{"$ref":"#/components/schemas/OidcProviderSummary"}},"password_reset_available":{"type":"boolean"}}},"EmailTrackingResponse":{"type":"object","description":"Email tracking summary","required":["email_id","track_opens","track_clicks","open_count","click_count","unique_opens","unique_clicks","links"],"properties":{"click_count":{"type":"integer","format":"int32"},"email_id":{"type":"string"},"first_clicked_at":{"type":["string","null"]},"first_opened_at":{"type":["string","null"]},"links":{"type":"array","items":{"$ref":"#/components/schemas/TrackedLinkResponse"}},"open_count":{"type":"integer","format":"int32"},"track_clicks":{"type":"boolean"},"track_opens":{"type":"boolean"},"unique_clicks":{"type":"integer","format":"int64","minimum":0},"unique_opens":{"type":"integer","format":"int64","minimum":0}}},"EmailTrackingSetupResponse":{"type":"object","description":"Result of the one-click AWS-side event-tracking setup.","required":["topic_arn","webhook_url","subscription_requested","event_destination_attached"],"properties":{"event_destination_attached":{"type":"boolean","description":"The SESv2 event destination (bounce/complaint/delivery) is attached\nto the `temps-tracking` configuration set."},"subscription_requested":{"type":"boolean","description":"The webhook subscription was requested; SNS confirms it\nasynchronously through the webhook itself."},"topic_arn":{"type":"string","example":"arn:aws:sns:us-east-1:123456789012:temps-email-events-1"},"webhook_url":{"type":"string"}}},"EmailTrackingStatusResponse":{"type":"object","description":"Live status of the SES event-tracking pipeline for one provider.","required":["webhook_url","supports_event_tracking"],"properties":{"last_event_at":{"type":["string","null"],"description":"Most recent delivered/bounced/complained event recorded for an email\nsent through this provider. `null` means no provider feedback has\narrived yet.","example":"2026-07-18T10:31:00Z"},"sns_topic_arn":{"type":["string","null"]},"subscription_confirmed_at":{"type":["string","null"],"description":"When the SNS subscription for the current topic was confirmed.\n`null` with a topic set usually means the subscription is still\npending — most often because the endpoint was subscribed before the\ntopic ARN was saved here.","example":"2026-07-18T10:30:00Z"},"supports_event_tracking":{"type":"boolean","description":"Only SES providers support SNS event tracking."},"webhook_url":{"type":"string","description":"Public webhook endpoint SNS must deliver events to.","example":"https://temps.example.com/api/t/webhook/ses"}}},"EmbeddingData":{"type":"object","required":["object","embedding","index"],"properties":{"embedding":{"type":"array","items":{"type":"number","format":"double"}},"index":{"type":"integer","format":"int32"},"object":{"type":"string"}}},"EmbeddingInput":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]},"EmbeddingRequest":{"type":"object","required":["model","input"],"properties":{"dimensions":{"type":["integer","null"],"format":"int32"},"encoding_format":{"type":["string","null"]},"input":{"$ref":"#/components/schemas/EmbeddingInput"},"model":{"type":"string"}}},"EmbeddingResponse":{"type":"object","required":["object","data","model","usage"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/EmbeddingData"}},"model":{"type":"string"},"object":{"type":"string"},"usage":{"$ref":"#/components/schemas/EmbeddingUsage"}}},"EmbeddingUsage":{"type":"object","required":["prompt_tokens","total_tokens"],"properties":{"prompt_tokens":{"type":"integer","format":"int64"},"total_tokens":{"type":"integer","format":"int64"}}},"EnableBlobRequest":{"type":"object","description":"Request to enable Blob service","properties":{"docker_image":{"type":["string","null"],"description":"Docker image to use (optional, defaults to RustFS)","example":"ghcr.io/rustfs/rustfs:0.5.0"},"root_password":{"type":["string","null"],"description":"Root password for S3 access"},"root_user":{"type":["string","null"],"description":"Root user for S3 access"}}},"EnableBlobResponse":{"type":"object","description":"Response after enabling Blob service","required":["success","message","status"],"properties":{"message":{"type":"string","description":"Human-readable message","example":"Blob service enabled successfully"},"status":{"$ref":"#/components/schemas/BlobStatusResponse","description":"Current status"},"success":{"type":"boolean","description":"Whether the operation succeeded","example":true}}},"EnableKvRequest":{"type":"object","description":"Request to enable the KV service","properties":{"docker_image":{"type":["string","null"],"description":"Docker image to use (optional, uses default if not provided)","example":"gotempsh/redis-walg:8-bookworm"},"max_memory":{"type":["string","null"],"description":"Maximum memory allocation (e.g., \"256mb\", \"1gb\")","example":"256mb"},"persistence":{"type":"boolean","description":"Enable data persistence"}}},"EnableKvResponse":{"type":"object","description":"Response after enabling KV service","required":["success","message","status"],"properties":{"message":{"type":"string","description":"Status message","example":"KV service enabled successfully"},"status":{"$ref":"#/components/schemas/KvStatusResponse","description":"Current service status"},"success":{"type":"boolean","description":"Whether the service was successfully enabled"}}},"EnablePgStatStatementsResponse":{"type":"object","description":"Response for the enable pg_stat_statements endpoint.","required":["message"],"properties":{"message":{"type":"string","description":"Human-readable message confirming the action."}}},"EndpointDto":{"type":"object","description":"One DNS record on the wire. Mirrors `service_endpoints::Model` but\nkeeps the API stable across entity evolution. `target_ip` is a string\n(v4 or v6 literal, or CNAME target hostname) parsed by the resolver.","required":["id","fqdn","record_type","ttl","owner_kind","owner_id","generation"],"properties":{"fqdn":{"type":"string"},"generation":{"type":"integer","format":"int64"},"id":{"type":"integer","format":"int64"},"node_id":{"type":["integer","null"],"format":"int32"},"owner_id":{"type":"integer","format":"int64"},"owner_kind":{"type":"string"},"record_type":{"type":"string"},"target_ip":{"type":["string","null"]},"target_port":{"type":["integer","null"],"format":"int32"},"ttl":{"type":"integer","format":"int32"}}},"EnqueuedJob":{"type":"object","description":"A single job that was successfully enqueued during a fan-out run.","required":["backup_id","job_id","engine"],"properties":{"backup_id":{"type":"integer","format":"int32","description":"FK to `backups.id` for this job."},"engine":{"type":"string","description":"Engine key (e.g. `\"control_plane\"`, `\"redis\"`, `\"postgres_pgdump\"`)."},"job_id":{"type":"integer","format":"int64","description":"FK to `backup_jobs.id` for this job."},"target_service_id":{"type":["integer","null"],"format":"int32","description":"FK to `external_services.id` when this is an external-service job.\n`None` for the control-plane job."}}},"EnrichVisitorRequest":{"type":"object","required":["custom_data"],"properties":{"custom_data":{"type":"object"}}},"EnrichVisitorResponse":{"type":"object","required":["success","visitor_id","message"],"properties":{"message":{"type":"string"},"success":{"type":"boolean"},"visitor_id":{"type":"string"}}},"EnrollmentTokenInfo":{"type":"object","required":["id","expires_at","used_count","max_uses","created_at"],"properties":{"bound_node_name":{"type":["string","null"]},"created_at":{"type":"string"},"expires_at":{"type":"string"},"id":{"type":"integer","format":"int32"},"max_uses":{"type":"integer","format":"int32"},"used_count":{"type":"integer","format":"int32"}}},"EnrollmentTokenListResponse":{"type":"object","required":["tokens"],"properties":{"tokens":{"type":"array","items":{"$ref":"#/components/schemas/EnrollmentTokenInfo"}}}},"EntityInfoResponse":{"type":"object","required":["container_path","entity","entity_type","fields"],"properties":{"container_path":{"type":"array","items":{"type":"string"},"description":"Full container path","example":["mydb","public"]},"entity":{"type":"string","description":"Entity name","example":"users"},"entity_type":{"type":"string","description":"Entity type","example":"table"},"fields":{"type":"array","items":{"$ref":"#/components/schemas/FieldResponse"},"description":"Field definitions"},"metadata":{"description":"Additional metadata (content_type, last_modified, etag, etc.)"},"row_count":{"type":["integer","null"],"description":"Approximate row count (for tables/collections)","example":1234,"minimum":0},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Size in bytes (for objects/files)","example":1048576,"minimum":0},"sort_schema":{"description":"JSON Schema for sort options (if supported)"}}},"EntityResponse":{"type":"object","required":["name","entity_type"],"properties":{"entity_type":{"type":"string","description":"Entity type (table, view, collection, etc.)","example":"table"},"name":{"type":"string","description":"Entity name (table/collection)","example":"users"},"row_count":{"type":["integer","null"],"description":"Approximate row count","example":1234,"minimum":0},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Size in bytes (for files/objects)","example":1048576,"minimum":0}}},"EnvVarInput":{"type":"object","description":"Input for environment variable","required":["name","value"],"properties":{"name":{"type":"string","description":"Variable name"},"value":{"type":"string","description":"Variable value"}}},"EnvVarIntegrationInfo":{"type":"object","required":["service_id","service_name","service_type","service_updated_at"],"properties":{"service_id":{"type":"integer","format":"int32"},"service_name":{"type":"string"},"service_slug":{"type":["string","null"]},"service_type":{"type":"string"},"service_updated_at":{"type":"string"}}},"EnvVarResponse":{"type":"object","description":"Environment variable with masked sensitive values","required":["key","value","is_masked"],"properties":{"is_masked":{"type":"boolean","description":"Whether this is a sensitive/masked value"},"key":{"type":"string"},"value":{"type":"string"}}},"EnvVarTemplateResponse":{"type":"object","description":"Environment variable template response","required":["name","required"],"properties":{"default":{"type":["string","null"],"description":"Default value if not provided by user"},"default_generator":{"type":["string","null"],"description":"Frontend-side generator hint for the default value\n(e.g. `app_url`, `random_secret`, `random_hex_32`)"},"description":{"type":["string","null"],"description":"Description of what this variable is used for"},"example":{"type":["string","null"],"description":"Example value for documentation"},"name":{"type":"string","description":"Name of the environment variable"},"required":{"type":"boolean","description":"Whether this variable is required"}}},"EnvironmentConfiguration":{"type":"object","description":"Environment-level configuration","required":["name","subdomain","resources"],"properties":{"name":{"type":"string","description":"Environment name"},"resources":{"$ref":"#/components/schemas/ResourceLimits","description":"Resource limits for environment"},"subdomain":{"type":"string","description":"Proposed subdomain"}}},"EnvironmentDomainResponse":{"type":"object","required":["id","environment_id","domain","created_at","url"],"properties":{"created_at":{"type":"integer","format":"int64"},"domain":{"type":"string"},"environment_id":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"url":{"type":"string","description":"Full URL for this domain (e.g., https://buildtolearndev-production.example.com)","example":"https://buildtolearndev-production.example.com"}}},"EnvironmentInfo":{"type":"object","required":["id","name","main_url"],"properties":{"current_deployment_id":{"type":["integer","null"],"format":"int32"},"id":{"type":"integer","format":"int32"},"main_url":{"type":"string"},"name":{"type":"string"}}},"EnvironmentResponse":{"type":"object","required":["id","project_id","name","slug","main_url","subdomain","created_at","updated_at","is_preview","protected","sleeping"],"properties":{"attack_mode":{"type":["boolean","null"],"description":"Per-environment CAPTCHA attack-mode override.\n`null` means inherit the project-level `attack_mode`; `true`/`false`\nexplicitly enable/disable the challenge for this environment. Always\nserialized (NOT skipped) so the UI can distinguish `null` from `false`."},"branch":{"type":["string","null"]},"created_at":{"type":"integer","format":"int64"},"current_deployment_id":{"type":["integer","null"],"format":"int32"},"deployment_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DeploymentConfig","description":"Deployment configuration for this environment (overrides project-level config)"}]},"estimated_sleep_at":{"type":["integer","null"],"format":"int64","description":"Estimated time (epoch millis) when the environment will go to sleep\nbased on last activity + idle timeout. NULL when sleeping or on-demand disabled."},"force_https":{"type":["boolean","null"],"description":"Per-environment HTTP→HTTPS redirect override.\n`null` means inherit the proxy default (redirect only when the host has\nan active TLS certificate); `true` always redirects plain HTTP for this\nenvironment, `false` never does. Always serialized (NOT skipped) so the\nUI can distinguish `null` from `false`."},"id":{"type":"integer","format":"int32"},"is_preview":{"type":"boolean","description":"Indicates if this is a preview environment (auto-created per branch)\nFor preview environments, 'branch' contains the feature branch name"},"last_activity_at":{"type":["integer","null"],"format":"int64","description":"Last proxied request timestamp (epoch millis) for on-demand environments.\nNULL when on-demand is disabled or no traffic has been received yet."},"main_url":{"type":"string"},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"protected":{"type":"boolean","description":"When true, git pushes do NOT auto-deploy to this environment.\nDeployments must be promoted from another environment."},"sleeping":{"type":"boolean","description":"When true, the environment's containers are currently stopped due to\ninactivity (on-demand mode) and will start on the next request."},"slug":{"type":"string"},"subdomain":{"type":"string","description":"The host label stored for this environment (e.g.\n`myproject-production`). This is the prefix that is combined with the\nplatform's preview domain at request time to produce `main_url`. Edit\nthis via the rename-subdomain endpoint, not the full URL."},"updated_at":{"type":"integer","format":"int64"}}},"EnvironmentVariable":{"type":"object","description":"Environment variable","required":["key","value","is_secret"],"properties":{"is_secret":{"type":"boolean","description":"Whether this is a secret (should be encrypted)"},"key":{"type":"string","description":"Variable name"},"source_description":{"type":["string","null"],"description":"Where this env var originates from (for traceability)"},"value":{"type":"string","description":"Variable value (may be redacted for secrets)"}}},"EnvironmentVariableInfo":{"type":"object","required":["name","value","sensitive"],"properties":{"name":{"type":"string"},"sensitive":{"type":"boolean","description":"Whether this variable contains sensitive data (passwords, keys, tokens)","example":false},"value":{"type":"string"}}},"EnvironmentVariableResponse":{"type":"object","required":["id","key","created_at","updated_at","environments","include_in_preview","is_secret"],"properties":{"created_at":{"type":"integer","format":"int64"},"environments":{"type":"array","items":{"$ref":"#/components/schemas/EnvironmentInfo"}},"id":{"type":"integer","format":"int32"},"include_in_preview":{"type":"boolean","description":"Include this environment variable in preview environments"},"is_secret":{"type":"boolean","description":"Whether the variable is a write-only secret. Secrets always have\n`value: None` in responses."},"key":{"type":"string"},"updated_at":{"type":"integer","format":"int64"},"value":{"type":["string","null"],"description":"Plaintext value for non-secret vars (or `\"***\"` mask for list responses).\n`None` for secret vars — secrets are write-only."}}},"EnvironmentVariableValueResponse":{"type":"object","required":["value"],"properties":{"value":{"type":"string"}}},"ErrorDashboardStatsQuery":{"type":"object","required":["start_time","end_time"],"properties":{"compare_to_previous":{"type":["boolean","null"]},"end_time":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"start_time":{"type":"string","format":"date-time"}}},"ErrorDashboardStatsResponse":{"type":"object","required":["total_errors","total_errors_previous_period","total_errors_change_percent","error_groups","error_groups_previous_period","start_time","end_time"],"properties":{"comparison_end_time":{"type":["string","null"],"format":"date-time"},"comparison_start_time":{"type":["string","null"],"format":"date-time"},"end_time":{"type":"string","format":"date-time"},"error_groups":{"type":"integer","format":"int64"},"error_groups_previous_period":{"type":"integer","format":"int64"},"start_time":{"type":"string","format":"date-time"},"total_errors":{"type":"integer","format":"int64"},"total_errors_change_percent":{"type":"number","format":"double"},"total_errors_previous_period":{"type":"integer","format":"int64"}}},"ErrorEventResponse":{"type":"object","required":["id","error_group_id","timestamp","created_at"],"properties":{"created_at":{"type":"string"},"data":{"description":"Full error event data (contains raw Sentry event or custom error data)"},"error_group_id":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int64"},"source":{"type":["string","null"],"description":"Source of the error event (e.g., \"sentry\", \"custom\", \"bugsnag\")"},"timestamp":{"type":"string"}}},"ErrorGroupResponse":{"type":"object","required":["id","title","error_type","first_seen","last_seen","total_count","status","project_id","created_at","updated_at"],"properties":{"assigned_to":{"type":["string","null"]},"created_at":{"type":"string"},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"error_type":{"type":"string"},"first_seen":{"type":"string"},"id":{"type":"integer","format":"int32"},"last_seen":{"type":"string"},"message_template":{"type":["string","null"]},"project_id":{"type":"integer","format":"int32"},"status":{"type":"string"},"title":{"type":"string"},"total_count":{"type":"integer","format":"int32"},"updated_at":{"type":"string"},"visitor_id":{"type":["integer","null"],"format":"int32"}}},"ErrorGroupStatsResponse":{"type":"object","required":["total_groups","unresolved_groups","resolved_groups","ignored_groups"],"properties":{"ignored_groups":{"type":"integer","format":"int64"},"resolved_groups":{"type":"integer","format":"int64"},"total_groups":{"type":"integer","format":"int64"},"unresolved_groups":{"type":"integer","format":"int64"}}},"ErrorResponse":{"type":"object","required":["error"],"properties":{"details":{"type":["string","null"]},"error":{"type":"string"}}},"ErrorRow":{"type":"object","required":["id","ts","error_group_id","fingerprint","error_class","stacktrace_preview","stacktrace_truncated"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"error_class":{"type":"string"},"error_group_id":{"type":"integer","format":"int32"},"fingerprint":{"type":"string"},"id":{"type":"integer","format":"int64"},"message":{"type":["string","null"]},"stacktrace_preview":{},"stacktrace_truncated":{"type":"boolean"},"trace_id":{"type":["string","null"]},"ts":{"type":"string","format":"date-time"}}},"ErrorTimeSeriesDataResponse":{"type":"object","required":["timestamp","count"],"properties":{"count":{"type":"integer","format":"int64"},"timestamp":{"type":"string"}}},"ErrorTimeSeriesQuery":{"type":"object","required":["start_time","end_time"],"properties":{"bucket":{"type":"string","description":"Time bucket size (e.g., \"1h\", \"15m\", \"1d\", \"1 hour\", \"30 minutes\")","example":"1h"},"end_time":{"type":"string","format":"date-time"},"start_time":{"type":"string","format":"date-time"}}},"EventActivityBucket":{"type":"object","description":"Time bucket data point for event activity graph","required":["timestamp","count","unique_visitors"],"properties":{"count":{"type":"integer","format":"int64","description":"Number of event occurrences in this bucket"},"timestamp":{"type":"string","description":"Timestamp for this bucket (ISO 8601)"},"unique_visitors":{"type":"integer","format":"int64","description":"Number of unique visitors in this bucket"}}},"EventBreakdown":{"type":"string","enum":["country","region","city"]},"EventBrowserStats":{"type":"object","description":"Browser stats for an event","required":["browser","count","percentage"],"properties":{"browser":{"type":"string","description":"Browser name"},"count":{"type":"integer","format":"int64","description":"Number of event occurrences from this browser"},"percentage":{"type":"number","format":"double","description":"Percentage of total events"}}},"EventCount":{"type":"object","required":["event_name","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"event_name":{"type":"string"},"percentage":{"type":"number","format":"double"}}},"EventCountryStats":{"type":"object","description":"Country stats for an event","required":["country","count","percentage"],"properties":{"count":{"type":"integer","format":"int64","description":"Number of event occurrences from this country"},"country":{"type":"string","description":"Country name"},"country_code":{"type":["string","null"],"description":"ISO country code (2-letter)"},"percentage":{"type":"number","format":"double","description":"Percentage of total events"}}},"EventDetailQuery":{"type":"object","description":"Query parameters for event detail analytics","required":["event_name","project_id","start_date","end_date"],"properties":{"bucket_interval":{"type":["string","null"],"description":"Bucket interval for time series: 'hour', 'day', 'week', 'month' (default: auto)"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"event_name":{"type":"string","description":"The specific event name to get details for"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"EventDetailResponse":{"type":"object","description":"Summary response for a specific event's analytics","required":["event_name","total_count","unique_visitors","unique_sessions","activity_over_time","referrers","countries","browsers","bucket_interval"],"properties":{"activity_over_time":{"type":"array","items":{"$ref":"#/components/schemas/EventActivityBucket"},"description":"Time series data for event activity graph"},"browsers":{"type":"array","items":{"$ref":"#/components/schemas/EventBrowserStats"},"description":"Browser distribution of visitors who triggered this event"},"bucket_interval":{"type":"string","description":"Bucket interval used for time series ('hour', 'day', etc.)"},"countries":{"type":"array","items":{"$ref":"#/components/schemas/EventCountryStats"},"description":"Geographic distribution of visitors who triggered this event"},"event_name":{"type":"string","description":"The event name being analyzed"},"referrers":{"type":"array","items":{"$ref":"#/components/schemas/EventReferrerStats"},"description":"Top referrer hostnames for visitors who triggered this event"},"total_count":{"type":"integer","format":"int64","description":"Total number of times this event was triggered in the date range"},"unique_sessions":{"type":"integer","format":"int64","description":"Number of unique sessions where this event occurred"},"unique_visitors":{"type":"integer","format":"int64","description":"Number of unique visitors who triggered this event"}}},"EventEntriesQuery":{"type":"object","description":"Query parameters for the raw event entries list","required":["event_name","project_id","start_date","end_date"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"event_name":{"type":"string","description":"The specific event name to list occurrences for"},"page":{"type":["integer","null"],"format":"int64","description":"Page number (1-based, default: 1)","minimum":0},"per_page":{"type":["integer","null"],"format":"int64","description":"Items per page (default: 20, max: 100)","minimum":0},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"EventEntriesResponse":{"type":"object","description":"Paginated response for raw event entries","required":["event_name","total_count","page","per_page","entries"],"properties":{"entries":{"type":"array","items":{"$ref":"#/components/schemas/EventEntryInfo"},"description":"Individual event occurrences, most recent first"},"event_name":{"type":"string","description":"The event name"},"page":{"type":"integer","format":"int64","description":"Current page number","minimum":0},"per_page":{"type":"integer","format":"int64","description":"Items per page","minimum":0},"total_count":{"type":"integer","format":"int64","description":"Total number of occurrences of this event in the date range"}}},"EventEntryInfo":{"type":"object","description":"A single raw occurrence of an event, including its custom JSON properties","required":["id","timestamp","page_path","href"],"properties":{"browser":{"type":["string","null"],"description":"Browser name"},"city":{"type":["string","null"],"description":"City of the visitor at the time of the event"},"country":{"type":["string","null"],"description":"Country of the visitor at the time of the event"},"country_code":{"type":["string","null"],"description":"ISO country code (2-letter)"},"device_type":{"type":["string","null"],"description":"Device type (Desktop, Mobile, Tablet)"},"href":{"type":"string","description":"Full URL where the event was triggered"},"id":{"type":"integer","format":"int64","description":"Event row ID"},"page_path":{"type":"string","description":"Page path where the event was triggered"},"props":{"type":["object","null"],"description":"Custom event properties as JSON (null when the event carried no data)"},"session_id":{"type":["string","null"],"description":"Session ID the event belongs to (if any)"},"timestamp":{"type":"string","format":"date-time","description":"When the event occurred"},"visitor_id":{"type":["integer","null"],"format":"int32","description":"Visitor numeric ID (if known)"},"visitor_uuid":{"type":["string","null"],"description":"Visitor UUID (if known)"}}},"EventKind":{"type":"string","description":"Tag enum for filter parameters and routing. Matches the variant\ndiscriminator used by `ObservabilityEvent`.","enum":["request","span","error","revenue"]},"EventMetricsPayload":{"type":"object","required":["event_name","event_data","request_path","request_query"],"properties":{"cls":{"type":["number","null"],"format":"float","description":"Cumulative Layout Shift (score)"},"event_data":{},"event_name":{"type":"string"},"fcp":{"type":["number","null"],"format":"float","description":"First Contentful Paint (milliseconds)"},"fid":{"type":["number","null"],"format":"float","description":"First Input Delay (milliseconds)"},"inp":{"type":["number","null"],"format":"float","description":"Interaction to Next Paint (milliseconds)"},"language":{"type":["string","null"]},"lcp":{"type":["number","null"],"format":"float","description":"Largest Contentful Paint (milliseconds)"},"page_title":{"type":["string","null"]},"referrer":{"type":["string","null"],"description":"Referrer URL (falls back to Referer header if not provided)"},"request_path":{"type":"string"},"request_query":{"type":"string"},"screen_height":{"type":["integer","null"],"format":"int32","minimum":0},"screen_width":{"type":["integer","null"],"format":"int32","minimum":0},"ttfb":{"type":["number","null"],"format":"float","description":"Time to First Byte (milliseconds)"},"viewport_height":{"type":["integer","null"],"format":"int32","minimum":0},"viewport_width":{"type":["integer","null"],"format":"int32","minimum":0}}},"EventReferrerStats":{"type":"object","description":"Referrer stats for an event","required":["referrer","count","percentage"],"properties":{"count":{"type":"integer","format":"int64","description":"Number of event occurrences from this referrer"},"percentage":{"type":"number","format":"double","description":"Percentage of total events"},"referrer":{"type":"string","description":"Referrer hostname or \"Direct\""}}},"EventTimeline":{"type":"object","required":["date","count"],"properties":{"count":{"type":"integer","format":"int64"},"date":{"type":"string","format":"date-time"}}},"EventTimelineQuery":{"type":"object","required":["start_date","end_date"],"properties":{"aggregation_level":{"$ref":"#/components/schemas/AggregationLevel","description":"Aggregation level: events (raw count), sessions (unique sessions), or visitors (unique visitors)"},"bucket_size":{"type":["string","null"],"description":"Bucket size: hour, day, or week (auto-detected if not specified)"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"event_name":{"type":["string","null"]},"start_date":{"type":"string","format":"date-time"}}},"EventType":{"type":"object","required":["name","count"],"properties":{"count":{"type":"integer","format":"int64"},"name":{"type":"string"}}},"EventTypeBreakdown":{"type":"object","required":["event_type","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"event_type":{"type":"string"},"percentage":{"type":"number","format":"double"}}},"EventTypeBreakdownQuery":{"type":"object","required":["start_date","end_date"],"properties":{"aggregation_level":{"$ref":"#/components/schemas/AggregationLevel","description":"Aggregation level: events (raw count), sessions (unique sessions), or visitors (unique visitors)"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"EventTypeResponse":{"type":"object","required":["event_type","description","category"],"properties":{"category":{"type":"string"},"description":{"type":"string"},"event_type":{"type":"string"}}},"EventTypesResponse":{"type":"object","required":["events","total","page","page_size"],"properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/EventType"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"EventVisitorInfo":{"type":"object","description":"A visitor who triggered a specific event","required":["visitor_id","visitor_uuid","event_count","first_triggered","last_triggered"],"properties":{"browser":{"type":["string","null"],"description":"Browser name"},"city":{"type":["string","null"],"description":"Visitor's city"},"country":{"type":["string","null"],"description":"Visitor's country"},"country_code":{"type":["string","null"],"description":"Visitor's country code"},"device_type":{"type":["string","null"],"description":"Device type (Desktop, Mobile, Tablet)"},"event_count":{"type":"integer","format":"int64","description":"Number of times this visitor triggered the event"},"first_triggered":{"type":"string","format":"date-time","description":"When the visitor first triggered the event in the date range"},"last_triggered":{"type":"string","format":"date-time","description":"When the visitor last triggered the event in the date range"},"referrer_hostname":{"type":["string","null"],"description":"Referrer hostname for the event"},"visitor_id":{"type":"integer","format":"int32","description":"Visitor numeric ID"},"visitor_uuid":{"type":"string","description":"Visitor UUID"}}},"EventVisitorsQuery":{"type":"object","description":"Query parameters for event visitors list","required":["event_name","project_id","start_date","end_date"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"event_name":{"type":"string","description":"The specific event name to list visitors for"},"page":{"type":["integer","null"],"format":"int64","description":"Page number (1-based, default: 1)","minimum":0},"per_page":{"type":["integer","null"],"format":"int64","description":"Items per page (default: 20, max: 100)","minimum":0},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"EventVisitorsResponse":{"type":"object","description":"Paginated response for event visitors","required":["event_name","total_count","page","per_page","visitors"],"properties":{"event_name":{"type":"string","description":"The event name"},"page":{"type":"integer","format":"int64","description":"Current page number","minimum":0},"per_page":{"type":"integer","format":"int64","description":"Items per page","minimum":0},"total_count":{"type":"integer","format":"int64","description":"Total number of unique visitors who triggered this event"},"visitors":{"type":"array","items":{"$ref":"#/components/schemas/EventVisitorInfo"},"description":"Individual visitors who triggered this event"}}},"EventsCountQuery":{"type":"object","required":["start_date","end_date"],"properties":{"aggregation_level":{"$ref":"#/components/schemas/AggregationLevel","description":"Aggregation level: events (raw count), sessions (unique sessions), or visitors (unique visitors)"},"custom_events_only":{"type":["boolean","null"],"description":"Only return custom events, excluding system events like page_view, page_leave, heartbeat (default: true)"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"EventsResponse":{"type":"object","required":["events","applied_kinds"],"properties":{"applied_kinds":{"type":"array","items":{"$ref":"#/components/schemas/EventKind"},"description":"Echo of the kinds filter actually applied (server-resolved). Useful\nfor clients that pass `kinds=` empty and want to know what they got."},"events":{"type":"array","items":{"$ref":"#/components/schemas/ObservabilityEvent"}}}},"ExecBody":{"type":"object","required":["cmd"],"properties":{"cmd":{"type":"array","items":{"type":"string"}},"cwd":{"type":["string","null"]},"env":{"type":"object","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}}},"additionalProperties":false},"ExecDetachedResponse":{"type":"object","required":["job_id"],"properties":{"job_id":{"type":"string"}}},"ExecResponse":{"type":"object","required":["exit_code","stdout","stderr"],"properties":{"exit_code":{"type":"integer","format":"int32"},"stderr":{"type":"string"},"stdout":{"type":"string"}}},"ExecuteImportRequest":{"type":"object","description":"Request to execute an import","required":["session_id","project_name","preset","directory","main_branch"],"properties":{"directory":{"type":"string","description":"Project directory","example":"."},"dry_run":{"type":["boolean","null"],"description":"Dry run mode (don't create resources)"},"main_branch":{"type":"string","description":"Main branch name","example":"main"},"preset":{"type":"string","description":"Preset to use for the project (e.g., \"nextjs\", \"express\", \"docker\")"},"project_name":{"type":"string","description":"Project name to use (overrides the name from the plan)","example":"my-app"},"session_id":{"type":"string","description":"Session ID from plan creation"}}},"ExecuteImportResponse":{"type":"object","description":"Response from import execution","required":["session_id","status","step_results"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32","description":"Created deployment ID (if completed)"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Created environment ID (if completed)"},"project_id":{"type":["integer","null"],"format":"int32","description":"Created project ID (if completed)"},"session_id":{"type":"string","description":"Session ID"},"status":{"$ref":"#/components/schemas/ImportExecutionStatus","description":"Execution status"},"step_results":{"type":"array","items":{"$ref":"#/components/schemas/StepResult"},"description":"Per-step results (in execution order)"}}},"ExecuteOperationRequest":{"type":"object","required":["operation"],"properties":{"operation":{"type":"string"}}},"ExpireRequest":{"type":"object","description":"Request to set expiration on a key","required":["key","seconds"],"properties":{"key":{"type":"string","description":"The key to set expiration on","example":"session:abc"},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1},"seconds":{"type":"integer","format":"int64","description":"Expiration time in seconds","example":3600}}},"ExpireResponse":{"type":"object","description":"Response for expire operation","required":["success"],"properties":{"success":{"type":"boolean","description":"True if expiration was set, false if key doesn't exist"}}},"ExplorerSupportResponse":{"type":"object","required":["supported","service_type","capabilities","hierarchy"],"properties":{"capabilities":{"type":"array","items":{"type":"string"},"description":"Capabilities supported by this service","example":["sql"]},"filter_schema":{"description":"JSON Schema for filter format with embedded UI hints (if supported)"},"hierarchy":{"type":"array","items":{"$ref":"#/components/schemas/HierarchyLevel"},"description":"Hierarchy levels (describes the navigation structure)"},"reason":{"type":["string","null"],"description":"Reason why explorer is not supported (if applicable)"},"service_type":{"type":"string","description":"Service type","example":"postgres"},"supported":{"type":"boolean","description":"Whether the service supports query explorer functionality","example":true}}},"ExtendTimeoutBody":{"type":"object","properties":{"duration":{"type":["integer","null"],"format":"int64","description":"`@vercel/sandbox`-compatible alternative — duration in milliseconds.\nUsed when `extra_secs` is absent.","minimum":0},"extra_secs":{"type":["integer","null"],"format":"int64","description":"Extra seconds to add to the existing `expires_at` (temps-native).","minimum":0}}},"ExternalImageResponse":{"type":"object","required":["id","project_id","image_ref","pushed_at","created_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"digest":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"image_ref":{"type":"string"},"metadata":{},"project_id":{"type":"integer","format":"int32"},"pushed_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"size_bytes":{"type":["integer","null"],"format":"int64"},"tag":{"type":["string","null"]}}},"ExternalServiceBackupResponse":{"type":"object","description":"Response type for external service backup","required":["id","service_id","backup_id","backup_type","state","started_at","s3_location","metadata","compression_type","created_by"],"properties":{"backup_id":{"type":"integer","format":"int32"},"backup_type":{"type":"string"},"checksum":{"type":["string","null"]},"compression_type":{"type":"string"},"created_by":{"type":"integer","format":"int32"},"error_message":{"type":["string","null"]},"expires_at":{"type":["string","null"],"example":"2025-02-15T14:30:00.123Z"},"finished_at":{"type":["string","null"],"example":"2025-01-15T14:35:00.456Z"},"id":{"type":"integer","format":"int32"},"metadata":{},"s3_location":{"type":"string"},"service_id":{"type":"integer","format":"int32"},"size_bytes":{"type":["integer","null"],"format":"int64"},"started_at":{"type":"string","example":"2025-01-15T14:30:00.123Z"},"state":{"type":"string"}}},"ExternalServiceDetails":{"type":"object","required":["service","sensitive_parameters"],"properties":{"current_parameters":{"type":["object","null"],"additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"parameter_schema":{},"sensitive_parameters":{"type":"array","items":{"type":"string"},"description":"Parameter names whose values are masked in `current_parameters` and\nmay be fetched only through the audited reveal endpoint."},"service":{"$ref":"#/components/schemas/ExternalServiceInfo"}}},"ExternalServiceInfo":{"type":"object","required":["id","name","service_type","status","created_at","updated_at","topology"],"properties":{"connection_info":{"type":["string","null"]},"created_at":{"type":"string"},"error_message":{"type":["string","null"],"description":"Error message from failed initialization."},"id":{"type":"integer","format":"int32"},"members":{"type":"array","items":{"$ref":"#/components/schemas/ServiceMemberInfo"},"description":"Cluster members (empty for standalone services)."},"metrics_enabled":{"type":"boolean","description":"Whether metric collection is enabled for this service. The UI uses this\nto decide whether to poll the monitoring endpoints."},"name":{"type":"string"},"node_id":{"type":["integer","null"],"format":"int32","description":"Node ID where the service runs. Null means control plane (local)."},"service_type":{"$ref":"#/components/schemas/ServiceTypeRoute"},"status":{"type":"string"},"topology":{"type":"string","description":"Service topology: \"standalone\" (single container) or \"cluster\" (HA multi-member).","example":"standalone"},"updated_at":{"type":"string"},"version":{"type":["string","null"]}}},"ExternalServiceSummary":{"type":"object","description":"Summary of the external service that owns a backup. Only populated for\nexternal-service backups (Redis, Postgres, etc.); absent for control-plane\nbackups.","required":["id","name","service_type"],"properties":{"id":{"type":"integer","format":"int32","description":"Database id of the external service."},"name":{"type":"string","description":"Human-readable service name (e.g. \"redis-prod\")."},"service_type":{"type":"string","description":"Service type string (e.g. \"postgres\", \"redis\", \"mongodb\").","example":"postgres"}}},"FieldResponse":{"type":"object","required":["name","field_type","nullable"],"properties":{"field_type":{"type":"string","description":"Field type (Int32, String, Timestamp, etc.)","example":"Int64"},"name":{"type":"string","description":"Field name","example":"id"},"nullable":{"type":"boolean","description":"Whether the field is nullable","example":false}}},"FiringSeriesEntry":{"type":"object","description":"A single currently-firing series for a dynamic alert rule, snapshotted from\nthe evaluator's in-memory per-series firing map at read time (ADR-026 Phase 3).","required":["series_key","series_label"],"properties":{"alarm_id":{"type":["integer","null"],"format":"int32","description":"The open alarm's id, when one was created (absent if suppressed)."},"series_key":{"type":"array","items":{"type":"array","items":false,"prefixItems":[{"type":"string"},{"type":"string"}]},"description":"The series' label pairs, e.g. `[[\"endpoint\",\"/checkout\"],[\"region\",\"eu-west\"]]`."},"series_label":{"type":"string","description":"The human-readable joined label, e.g. `endpoint=/checkout, region=eu-west`."}}},"FlagEnvironmentResponse":{"type":"object","required":["environment_id","enabled"],"properties":{"enabled":{"type":"boolean"},"environment_id":{"type":"integer","format":"int32"},"value":{}}},"FlagListResponse":{"type":"object","description":"Note the absence of `salt`: it is never exposed. Publishing the bucketing\nsalt would let a client predict, and self-select into, a rollout cohort.","required":["flags","total","page","page_size","total_pages"],"properties":{"flags":{"type":"array","items":{"$ref":"#/components/schemas/FlagResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","description":"Total flags matching the filter, across all pages.","minimum":0},"total_pages":{"type":"integer","format":"int64","minimum":0}}},"FlagResponse":{"type":"object","required":["id","key","value_type","default_value","client_visible","created_at","updated_at","environments"],"properties":{"archived_at":{"type":["string","null"]},"client_visible":{"type":"boolean"},"created_at":{"type":"string"},"default_value":{},"description":{"type":["string","null"]},"environments":{"type":"array","items":{"$ref":"#/components/schemas/FlagEnvironmentResponse"},"description":"Per-environment overrides. Empty means the flag inherits its default\neverywhere."},"id":{"type":"integer","format":"int32"},"key":{"type":"string"},"last_evaluated_at":{"type":["string","null"],"description":"When an app last actually evaluated this flag. `None` means never seen,\nwhich is a real answer rather than missing data."},"updated_at":{"type":"string"},"value_type":{"type":"string"}}},"FlagSnapshot":{"type":"object","description":"A single flag, already resolved down to one environment. This is what the\nevaluator sees and what the SDK caches in memory.","required":["key","value_type","default_value","enabled"],"properties":{"default_value":{"description":"Served whenever evaluation cannot do better. Genuinely polymorphic by\ndesign — the surrounding struct carries the type."},"enabled":{"type":"boolean","description":"False means the kill switch is engaged for this environment."},"environment_value":{"description":"`None` means \"inherit `default_value`\"."},"key":{"type":"string"},"value_type":{"$ref":"#/components/schemas/FlagValueType"}}},"FlagSnapshotResponse":{"type":"object","required":["environment_id","flags"],"properties":{"environment_id":{"type":"integer","format":"int32"},"flags":{"type":"array","items":{"$ref":"#/components/schemas/FlagSnapshot"},"description":"Flags collapsed to what the evaluator needs, sorted by key so the\nserialized form — and therefore the ETag — is stable."}}},"FlagValueType":{"type":"string","description":"The declared type of a flag's value. Fixed at create time.","enum":["bool","string","number","json"]},"ForecastAlgorithm":{"type":"string","description":"Forecast model family.","enum":["linear","seasonal"]},"ForecastParams":{"type":"object","description":"Forecast detector parameters (stub — not yet evaluated).","required":["forecast_horizon_secs","comparator","threshold"],"properties":{"algorithm":{"$ref":"#/components/schemas/ForecastAlgorithm"},"comparator":{"$ref":"#/components/schemas/Comparator","description":"Comparator + threshold the *forecast* is checked against."},"deviations":{"type":"number","format":"double"},"forecast_horizon_secs":{"type":"integer","format":"int32","description":"How far ahead to project before checking the breach condition."},"threshold":{"type":"number","format":"double"}}},"FullError":{"type":"object","required":["id","ts","error_group_id","fingerprint","error_class"],"properties":{"data":{"description":"Full JSONB blob from `error_events.data` — stack trace, breadcrumbs,\nrequest context, everything. Schema is documented per source SDK."},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"error_class":{"type":"string"},"error_group_id":{"type":"integer","format":"int32"},"fingerprint":{"type":"string"},"id":{"type":"integer","format":"int64"},"message":{"type":["string","null"]},"trace_id":{"type":["string","null"]},"ts":{"type":"string","format":"date-time"}}},"FullEvent":{"oneOf":[{"allOf":[{"$ref":"#/components/schemas/FullRequest"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["request"]}}}]},{"allOf":[{"$ref":"#/components/schemas/FullError"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["error"]}}}]},{"allOf":[{"$ref":"#/components/schemas/RevenueRow"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["revenue"]}}}]},{"allOf":[{"$ref":"#/components/schemas/SpanRow","description":"`SpanRow.attributes` is the truncated form; re-fetching returns\nthe same shape so the panel has a stable contract."},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["span"]}}}],"description":"`SpanRow.attributes` is the truncated form; re-fetching returns\nthe same shape so the panel has a stable contract."}],"description":"One un-truncated row, returned by the `/full/{type}/{id}` endpoint when\nthe user clicks \"Show full\". Same shape as the list rows, but with the\nraw heavy fields restored (no truncation flags) so the side panel can\nrender the long form."},"FullRequest":{"type":"object","required":["id","ts","method","host","path","status"],"properties":{"client_ip":{"type":["string","null"]},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"error_group_id":{"type":["integer","null"],"format":"int32"},"host":{"type":"string"},"id":{"type":"string","description":"The request's unique `request_id` — same identity the list rows carry\n(backend-agnostic; ClickHouse rows have no serial PK)."},"latency_ms":{"type":["integer","null"],"format":"int32"},"method":{"type":"string"},"path":{"type":"string"},"referrer":{"type":["string","null"]},"request_headers":{},"response_headers":{},"status":{"type":"integer","format":"int32"},"trace_id":{"type":["string","null"]},"ts":{"type":"string","format":"date-time"},"user_agent":{"type":["string","null"]}}},"FunnelMetricsResponse":{"type":"object","required":["funnel_id","funnel_name","total_entries","step_conversions","overall_conversion_rate","average_completion_time_seconds"],"properties":{"average_completion_time_seconds":{"type":"number","format":"double"},"funnel_id":{"type":"integer","format":"int32"},"funnel_name":{"type":"string"},"overall_conversion_rate":{"type":"number","format":"double"},"step_conversions":{"type":"array","items":{"$ref":"#/components/schemas/StepConversionResponse"}},"total_entries":{"type":"integer","format":"int64","minimum":0}}},"FunnelResponse":{"type":"object","required":["id","name","is_active","created_at","updated_at"],"properties":{"created_at":{"type":"string"},"description":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"name":{"type":"string"},"updated_at":{"type":"string"}}},"GatewayStatus":{"type":"object","description":"Detailed gateway container status surfaced to the settings UI.","required":["present","running","health","container_name","expected_image","drift","auto_upgrade"],"properties":{"auto_upgrade":{"type":"boolean","description":"True if `auto_upgrade` is enabled in settings."},"container_name":{"type":"string","description":"Container name."},"drift":{"type":"boolean","description":"True when `image != expected_image` and the container is present."},"expected_image":{"type":"string","description":"The image the supervisor *expects* (from settings/constant). If this\ndiffers from `image`, the UI shows a \"drift\" badge."},"health":{"type":"string","description":"Higher-level health label: \"running\" | \"restarting\" | \"crash_looping\"\n| \"stopped\" | \"missing\". UI should prefer this over `running`."},"host_port":{"type":["integer","null"],"format":"int32","description":"Host port that the container's :8080 is published on.","minimum":0},"image":{"type":["string","null"],"description":"Image reference the container was created with (e.g.\n`ghcr.io/gotempsh/temps-preview-gateway:latest`)."},"image_digest":{"type":["string","null"],"description":"Image digest if available (e.g. `sha256:…`)."},"last_error":{"type":["string","null"],"description":"Error string Docker recorded for the container (e.g. startup failure)."},"last_exit_code":{"type":["integer","null"],"format":"int64","description":"Exit code of the last run, if the container is not currently running."},"network":{"type":["string","null"],"description":"Network the container is attached to (should be `temps-sandbox-net`)."},"present":{"type":"boolean","description":"Whether the container exists at all."},"restart_count":{"type":["integer","null"],"format":"int64","description":"Number of times Docker has restarted the container."},"running":{"type":"boolean","description":"Whether the container is currently running."},"started_at":{"type":["string","null"],"description":"ISO 8601 timestamp the container was started at, if running."}}},"GenAiEvent":{"type":"object","description":"A GenAI-related event extracted from span events.\n\nCovers `gen_ai.client.inference.operation.details` and `gen_ai.evaluation.result`\nevents per the OTel GenAI semantic conventions.","required":["span_id","trace_id","event_name","timestamp","attributes"],"properties":{"attributes":{"type":"object","description":"All event attributes.","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"event_name":{"type":"string"},"span_id":{"type":"string"},"timestamp":{"type":"string","format":"date-time"},"trace_id":{"type":"string"}}},"GenAiSpanDetail":{"type":"object","description":"A single GenAI span with extracted semantic convention fields.\n\nFields are aligned with the OpenTelemetry GenAI Semantic Conventions spec:\n","required":["span_id","name","kind","start_time","duration_ms","status_code","attributes"],"properties":{"agent_description":{"type":["string","null"],"description":"Agent description from `gen_ai.agent.description`."},"agent_id":{"type":["string","null"],"description":"Agent identifier from `gen_ai.agent.id`."},"agent_name":{"type":["string","null"],"description":"Agent name from `gen_ai.agent.name`."},"agent_version":{"type":["string","null"],"description":"Agent version from `gen_ai.agent.version`."},"attributes":{"type":"object","description":"All span attributes for extensibility.","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"aws_bedrock_guardrail_id":{"type":["string","null"],"description":"AWS Bedrock guardrail ID from `aws.bedrock.guardrail.id`."},"aws_bedrock_knowledge_base_id":{"type":["string","null"],"description":"AWS Bedrock knowledge base ID from `aws.bedrock.knowledge_base.id`."},"azure_resource_provider_namespace":{"type":["string","null"],"description":"Azure resource provider namespace from `azure.resource_provider.namespace`."},"cache_creation_input_tokens":{"type":["integer","null"],"format":"int64","description":"Tokens written to provider cache from `gen_ai.usage.cache_creation.input_tokens`."},"cache_read_input_tokens":{"type":["integer","null"],"format":"int64","description":"Tokens served from provider cache from `gen_ai.usage.cache_read.input_tokens`."},"conversation_id":{"type":["string","null"],"description":"Unique conversation/session/thread ID from `gen_ai.conversation.id`."},"data_source_id":{"type":["string","null"],"description":"Data source identifier from `gen_ai.data_source.id`."},"duration_ms":{"type":"number","format":"double"},"embeddings_dimension_count":{"type":["integer","null"],"format":"int64","description":"Output embedding dimensions from `gen_ai.embeddings.dimension.count`."},"error_type":{"type":["string","null"],"description":"Error type from `error.type` when the span status is ERROR."},"gen_ai_model":{"type":["string","null"],"description":"The requested model from `gen_ai.request.model`."},"gen_ai_operation":{"type":["string","null"],"description":"The operation type from `gen_ai.operation.name` (e.g. \"chat\", \"embeddings\", \"execute_tool\")."},"gen_ai_response_model":{"type":["string","null"],"description":"The model that actually generated the response from `gen_ai.response.model`."},"gen_ai_system":{"type":["string","null"],"description":"The GenAI provider from `gen_ai.provider.name` (falls back to deprecated `gen_ai.system`)."},"input_messages":{"type":["string","null"],"description":"Chat history input from `gen_ai.input.messages` (opt-in, JSON string)."},"input_tokens":{"type":["integer","null"],"format":"int64"},"kind":{"$ref":"#/components/schemas/SpanKind"},"name":{"type":"string"},"openai_api_type":{"type":["string","null"],"description":"OpenAI API type from `openai.api.type` (chat_completions, responses)."},"openai_request_service_tier":{"type":["string","null"],"description":"Requested service tier from `openai.request.service_tier`."},"openai_response_service_tier":{"type":["string","null"],"description":"Actual service tier from `openai.response.service_tier`."},"openai_system_fingerprint":{"type":["string","null"],"description":"System fingerprint from `openai.response.system_fingerprint`."},"output_messages":{"type":["string","null"],"description":"Model output from `gen_ai.output.messages` (opt-in, JSON string)."},"output_tokens":{"type":["integer","null"],"format":"int64"},"output_type":{"type":["string","null"],"description":"Output content type from `gen_ai.output.type` (text, json, image, speech)."},"parent_span_id":{"type":["string","null"]},"request_choice_count":{"type":["integer","null"],"format":"int64","description":"Number of choices requested from `gen_ai.request.choice.count`."},"request_encoding_formats":{"type":["array","null"],"items":{"type":"string"},"description":"Requested encoding formats from `gen_ai.request.encoding_formats`."},"request_frequency_penalty":{"type":["number","null"],"format":"double","description":"Frequency penalty from `gen_ai.request.frequency_penalty`."},"request_max_tokens":{"type":["integer","null"],"format":"int64","description":"Max tokens from `gen_ai.request.max_tokens`."},"request_presence_penalty":{"type":["number","null"],"format":"double","description":"Presence penalty from `gen_ai.request.presence_penalty`."},"request_seed":{"type":["integer","null"],"format":"int64","description":"Seed for reproducibility from `gen_ai.request.seed`."},"request_stop_sequences":{"type":["array","null"],"items":{"type":"string"},"description":"Stop sequences from `gen_ai.request.stop_sequences`."},"request_temperature":{"type":["number","null"],"format":"double","description":"Temperature setting from `gen_ai.request.temperature`."},"request_top_k":{"type":["number","null"],"format":"double","description":"Top-k setting from `gen_ai.request.top_k`."},"request_top_p":{"type":["number","null"],"format":"double","description":"Top-p setting from `gen_ai.request.top_p`."},"response_finish_reasons":{"type":["array","null"],"items":{"type":"string"},"description":"Reasons the model stopped from `gen_ai.response.finish_reasons` (e.g. [\"stop\"])."},"response_id":{"type":["string","null"],"description":"Unique completion ID from `gen_ai.response.id` (e.g. \"chatcmpl-123\")."},"retrieval_documents":{"type":["string","null"],"description":"Retrieved documents from `gen_ai.retrieval.documents` (opt-in, JSON string)."},"retrieval_query_text":{"type":["string","null"],"description":"Retrieval query text from `gen_ai.retrieval.query.text` (opt-in)."},"server_address":{"type":["string","null"],"description":"GenAI server address from `server.address`."},"server_port":{"type":["integer","null"],"format":"int64","description":"GenAI server port from `server.port`."},"span_id":{"type":"string"},"start_time":{"type":"string","format":"date-time"},"status_code":{"$ref":"#/components/schemas/SpanStatusCode"},"system_instructions":{"type":["string","null"],"description":"System instructions from `gen_ai.system_instructions` (opt-in, JSON string)."},"tool_call_arguments":{"type":["string","null"],"description":"Tool call arguments from `gen_ai.tool.call.arguments` (opt-in, JSON string)."},"tool_call_id":{"type":["string","null"],"description":"Tool call ID from `gen_ai.tool.call.id`."},"tool_call_result":{"type":["string","null"],"description":"Tool call result from `gen_ai.tool.call.result` (opt-in, JSON string)."},"tool_definitions":{"type":["string","null"],"description":"Tool definitions from `gen_ai.tool.definitions` (opt-in, JSON string)."},"tool_description":{"type":["string","null"],"description":"Tool description from `gen_ai.tool.description`."},"tool_name":{"type":["string","null"],"description":"Tool name from `gen_ai.tool.name`."},"tool_type":{"type":["string","null"],"description":"Tool type from `gen_ai.tool.type` (function, extension, datastore)."}}},"GenAiTraceDetailResponse":{"type":"object","required":["trace_id","spans","span_count","events","event_count"],"properties":{"event_count":{"type":"integer","minimum":0},"events":{"type":"array","items":{"$ref":"#/components/schemas/GenAiEvent"}},"span_count":{"type":"integer","minimum":0},"spans":{"type":"array","items":{"$ref":"#/components/schemas/GenAiSpanDetail"}},"trace_id":{"type":"string"}}},"GenAiTraceSummariesResponse":{"type":"object","required":["data","total"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/GenAiTraceSummary"}},"total":{"type":"integer","format":"int64","minimum":0}}},"GenAiTraceSummary":{"type":"object","description":"Summary of a GenAI conversation — aggregated from OTel spans with `gen_ai.*` attributes.","required":["trace_id","root_span_name","service_name","start_time","duration_ms","span_count","error_count"],"properties":{"duration_ms":{"type":"number","format":"double"},"error_count":{"type":"integer","format":"int64"},"gen_ai_model":{"type":["string","null"],"description":"The requested model from `gen_ai.request.model`."},"gen_ai_operation":{"type":["string","null"],"description":"The operation type from `gen_ai.operation.name` (e.g. \"chat\", \"embeddings\")."},"gen_ai_system":{"type":["string","null"],"description":"The GenAI provider (e.g. \"openai\", \"anthropic\") from `gen_ai.provider.name`."},"root_span_name":{"type":"string"},"service_name":{"type":"string"},"span_count":{"type":"integer","format":"int64"},"start_time":{"type":"string","format":"date-time"},"total_cache_creation_input_tokens":{"type":["integer","null"],"format":"int64","description":"Total cache-creation input tokens across all spans."},"total_cache_read_input_tokens":{"type":["integer","null"],"format":"int64","description":"Total cache-read input tokens across all spans."},"total_input_tokens":{"type":["integer","null"],"format":"int64","description":"Total input tokens across all spans in this trace."},"total_output_tokens":{"type":["integer","null"],"format":"int64","description":"Total output tokens across all spans in this trace."},"trace_id":{"type":"string"}}},"GeneralStatsQuery":{"type":"object","required":["start_date","end_date"],"properties":{"end_date":{"type":"string","format":"date-time"},"start_date":{"type":"string","format":"date-time"}}},"GeneralStatsResponse":{"type":"object","required":["total_unique_visitors","total_visits","total_page_views","total_events","total_projects","avg_bounce_rate","avg_engagement_rate","project_breakdown"],"properties":{"avg_bounce_rate":{"type":"number","format":"double"},"avg_engagement_rate":{"type":"number","format":"double"},"page_views_trend_percentage":{"type":["number","null"],"format":"double","description":"Percentage change in page views vs previous period"},"previous_page_views":{"type":["integer","null"],"format":"int64","description":"Previous period page views"},"previous_unique_visitors":{"type":["integer","null"],"format":"int64","description":"Previous period unique visitors (same duration, shifted back)"},"project_breakdown":{"type":"array","items":{"$ref":"#/components/schemas/ProjectStatsBreakdown"}},"total_events":{"type":"integer","format":"int64"},"total_page_views":{"type":"integer","format":"int64"},"total_projects":{"type":"integer","format":"int64"},"total_unique_visitors":{"type":"integer","format":"int64"},"total_visits":{"type":"integer","format":"int64"},"visitors_trend_percentage":{"type":["number","null"],"format":"double","description":"Percentage change in unique visitors vs previous period"}}},"GenerateDockerfileRequest":{"type":"object","description":"Request body for generating a Dockerfile from a preset","properties":{"build_command":{"type":["string","null"],"description":"Custom build command (overrides preset default)","example":"npm run build"},"install_command":{"type":["string","null"],"description":"Custom install command (overrides preset default)","example":"npm ci"},"output_dir":{"type":["string","null"],"description":"Output directory for static builds","example":"dist"},"package_manager":{"type":["string","null"],"description":"Package manager used by the project (npm, yarn, pnpm, bun)\nIf not provided, defaults to npm","example":"npm"},"project_name":{"type":["string","null"],"description":"Project name/slug used for container naming","example":"my-app"},"use_buildkit":{"type":"boolean","description":"Whether to use BuildKit cache mounts for faster builds"}}},"GenerateDockerfileResponse":{"type":"object","description":"Response containing a generated Dockerfile and build arguments","required":["dockerfile","build_args","preset"],"properties":{"build_args":{"type":"object","description":"Build arguments to pass to `docker build --build-arg KEY=VALUE`","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"dockerfile":{"type":"string","description":"The generated Dockerfile content"},"preset":{"type":"string","description":"The preset slug used for generation"}}},"GenerateJoinTokenResponse":{"type":"object","description":"Response returned when a join token is generated (plaintext shown once)","required":["token","message"],"properties":{"message":{"type":"string"},"token":{"type":"string","description":"The plaintext join token — shown only once, save it now"}}},"GeoLocationResponse":{"type":"object","description":"Response containing geolocation information for an IP address","required":["ip","is_eu"],"properties":{"city":{"type":["string","null"],"description":"City name","example":"Mountain View"},"country":{"type":["string","null"],"description":"Country name","example":"United States"},"country_code":{"type":["string","null"],"description":"ISO country code (2 letters)","example":"US"},"ip":{"type":"string","description":"IP address that was geolocated","example":"8.8.8.8"},"is_eu":{"type":"boolean","description":"Whether the IP is in the European Union","example":false},"latitude":{"type":["number","null"],"format":"double","description":"Latitude coordinate","example":37.386},"longitude":{"type":["number","null"],"format":"double","description":"Longitude coordinate","example":-122.0838},"region":{"type":["string","null"],"description":"Region/state name","example":"California"},"timezone":{"type":["string","null"],"description":"Timezone identifier","example":"America/Los_Angeles"}}},"GeoRestrictionsConfig":{"type":"object","description":"Geographic restrictions configuration (future feature)","properties":{"allowedCountries":{"type":"array","items":{"type":"string"},"description":"Allow traffic only from specific countries"},"blockedCountries":{"type":"array","items":{"type":"string"},"description":"Block traffic from specific countries (ISO 3166-1 alpha-2 codes)"}}},"GetDeploymentsParams":{"type":"object","properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"page":{"type":["integer","null"],"format":"int64"},"per_page":{"type":["integer","null"],"format":"int64"}}},"GetEnvironmentVariablesQuery":{"type":"object","properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"service_id":{"type":["integer","null"],"format":"int32","description":"Required by integration-value reveals to bind the plaintext response to\nthe exact service displayed by the client."},"var_id":{"type":["integer","null"],"format":"int32","description":"Exact manual env-var row to reveal. Required by the dashboard so\nduplicate keys on disjoint environments cannot cross-reveal."}}},"GetFunnelMetricsQuery":{"type":"object","properties":{"country_code":{"type":["string","null"]},"end_date":{"type":["string","null"],"format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"start_date":{"type":["string","null"],"format":"date-time"}}},"GetOrCreateDSNRequest":{"type":"object","properties":{"base_url":{"type":["string","null"]},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"}}},"GetProjectSecretsQuery":{"type":"object","properties":{"environment_id":{"type":["integer","null"],"format":"int32"}}},"GetProjectSessionReplaysQuery":{"type":"object","required":["project_id"],"properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"page":{"type":["integer","null"],"format":"int64","minimum":0},"per_page":{"type":["integer","null"],"format":"int64","minimum":0},"project_id":{"type":"integer","format":"int32"}}},"GetProjectSessionReplaysResponse":{"type":"object","required":["sessions","page","per_page","total_count"],"properties":{"page":{"type":"integer","format":"int64","minimum":0},"per_page":{"type":"integer","format":"int64","minimum":0},"sessions":{"type":"array","items":{"$ref":"#/components/schemas/SessionReplayWithVisitorDto"}},"total_count":{"type":"integer","format":"int64","minimum":0}}},"GetRequest":{"type":"object","description":"Request to get a value by key","required":["key"],"properties":{"key":{"type":"string","description":"The key to retrieve","example":"user:123"},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1}}},"GetResponse":{"type":"object","description":"Response for get operation","properties":{"value":{"description":"The value, or null if not found"}}},"GetSessionReplayResponse":{"type":"object","required":["session"],"properties":{"session":{"$ref":"#/components/schemas/SessionReplayWithVisitorDto"}}},"GetUniqueEventsQuery":{"type":"object","properties":{"page":{"type":["integer","null"],"format":"int64","minimum":0},"page_size":{"type":["integer","null"],"format":"int64","minimum":0}}},"GetVisitorSessionsQuery":{"type":"object","properties":{"page":{"type":["integer","null"],"format":"int64","minimum":0},"per_page":{"type":["integer","null"],"format":"int64","minimum":0}}},"GetVisitorSessionsResponse":{"type":"object","required":["sessions","page","per_page","total_count"],"properties":{"page":{"type":"integer","format":"int64","minimum":0},"per_page":{"type":"integer","format":"int64","minimum":0},"sessions":{"type":"array","items":{"$ref":"#/components/schemas/SessionReplayWithVisitorDto"}},"total_count":{"type":"integer","minimum":0}}},"GitPushEvent":{"type":"object","description":"Git push event information that triggered the deployment","required":["repo","owner","branch","commit"],"properties":{"branch":{"type":"string","description":"Branch that was pushed"},"commit":{"type":"string","description":"Commit SHA"},"owner":{"type":"string","description":"Repository owner/organization"},"repo":{"type":"string","description":"Repository name"}}},"GitRefResponse":{"type":"object","description":"Git repository reference response","required":["url","ref"],"properties":{"path":{"type":["string","null"],"description":"Path within the repository (for monorepos)"},"ref":{"type":"string","description":"Git reference (branch, tag, or commit)"},"url":{"type":"string","description":"Git repository URL"}}},"GitSourcePlan":{"type":"object","description":"Git repository the source platform deploys from","required":["owner","repo","branch","is_public"],"properties":{"branch":{"type":"string","description":"Branch the source platform deploys"},"clone_url":{"type":["string","null"],"description":"Full clone URL, e.g. `https://github.com/owner/repo.git`"},"is_public":{"type":"boolean","description":"True when the repository is public (no credentials on the source\nplatform) — the project can then build without a git provider\nconnection."},"owner":{"type":"string","description":"Repository owner (organization or user)"},"repo":{"type":"string","description":"Repository name"}}},"GlobalConversationResponse":{"type":"object","description":"A conversation in the unified cross-project switcher: carries the project it\nbelongs to (name/slug) so the UI can show where the chat was started and\nlink back to the source.","required":["public_id","project_id","context_type","context_id","status","created_at","last_activity_at"],"properties":{"context_id":{"type":"string"},"context_type":{"type":"string"},"created_at":{"type":"string"},"last_activity_at":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"project_name":{"type":["string","null"]},"project_slug":{"type":["string","null"]},"public_id":{"type":"string"},"status":{"type":"string"},"title":{"type":["string","null"]}}},"GlobalEventStatsResponse":{"type":"object","required":["delivered","opened","clicked","bounced","complained"],"properties":{"bounce_rate":{"type":["number","null"],"format":"double"},"bounced":{"type":"integer","format":"int64","minimum":0},"click_rate":{"type":["number","null"],"format":"double"},"clicked":{"type":"integer","format":"int64","minimum":0},"complained":{"type":"integer","format":"int64","minimum":0},"delivered":{"type":"integer","format":"int64","minimum":0},"open_rate":{"type":["number","null"],"format":"double"},"opened":{"type":"integer","format":"int64","minimum":0}}},"GlobalMrrResponse":{"type":"object","required":["currency","current_mrr_minor","previous_mrr_minor"],"properties":{"change_percentage":{"type":["number","null"],"format":"double","description":"Percentage change vs 24h ago. Null when previous MRR is zero\n(no baseline to compare against)."},"currency":{"type":"string"},"current_mrr_minor":{"type":"integer","format":"int64"},"previous_mrr_minor":{"type":"integer","format":"int64","description":"MRR 24h before now, reconstructed from the event log."}}},"GlobalRecentEventResponse":{"type":"object","required":["id","project_id","project_name","occurred_at","event_type"],"properties":{"amount_minor":{"type":["integer","null"],"format":"int64"},"currency":{"type":["string","null"]},"customer_ref":{"type":["string","null"]},"event_type":{"type":"string"},"id":{"type":"integer","format":"int64"},"mrr_minor":{"type":["integer","null"],"format":"int64"},"occurred_at":{"type":"string","format":"date-time"},"project_id":{"type":"integer","format":"int32"},"project_name":{"type":"string"}}},"GlobalRevenueSummaryResponse":{"type":"object","required":["currency","current_mrr_minor","paid_last_30d_minor","refunded_last_30d_minor","paid_all_time_minor","refunded_all_time_minor","active_subscriptions","active_customers","transactions_last_30d"],"properties":{"active_customers":{"type":"integer","format":"int64"},"active_subscriptions":{"type":"integer","format":"int64"},"currency":{"type":"string"},"current_mrr_minor":{"type":"integer","format":"int64"},"paid_all_time_minor":{"type":"integer","format":"int64"},"paid_last_30d_minor":{"type":"integer","format":"int64"},"refunded_all_time_minor":{"type":"integer","format":"int64"},"refunded_last_30d_minor":{"type":"integer","format":"int64"},"transactions_last_30d":{"type":"integer","format":"int64"}}},"GroupedPageMetric":{"type":"object","required":["group_key","events"],"properties":{"cls":{"type":["number","null"],"format":"float"},"country_code":{"type":["string","null"],"description":"ISO 3166-1 alpha-2 code of the group's country. Populated for the\ngeographic dimensions (country/region/city) so clients can match map\ngeometries without name-based lookups; null otherwise."},"events":{"type":"integer","format":"int64"},"fcp":{"type":["number","null"],"format":"float"},"group_key":{"type":"string"},"inp":{"type":["number","null"],"format":"float"},"lcp":{"type":["number","null"],"format":"float"},"ttfb":{"type":["number","null"],"format":"float"}}},"GroupedPageMetricsQuery":{"allOf":[{"$ref":"#/components/schemas/SpeedSegmentFilters","description":"Segment filters — same shape as `PerformanceMetricsQuery`."},{"type":"object","required":["start_date","end_date","project_id","group_by"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"device_type":{"type":["string","null"],"description":"Device type filter: \"desktop\" or \"mobile\""},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"group_by":{"type":"string"},"include_bots":{"type":["boolean","null"],"description":"Include crawler/datacenter (bot) samples. Defaults to false."},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}}]},"GroupedPageMetricsResponse":{"type":"object","required":["groups","total_events","grouped_by"],"properties":{"grouped_by":{"type":"string"},"groups":{"type":"array","items":{"$ref":"#/components/schemas/GroupedPageMetric"}},"total_events":{"type":"integer","format":"int64"}}},"HasAnalyticsEventsResponse":{"type":"object","required":["has_events"],"properties":{"has_events":{"type":"boolean"}}},"HasErrorGroupsResponse":{"type":"object","required":["has_error_groups"],"properties":{"has_error_groups":{"type":"boolean"}}},"HasEventsQuery":{"type":"object","required":["project_id"],"properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"}}},"HasEventsResponse":{"type":"object","required":["has_events"],"properties":{"has_events":{"type":"boolean"}}},"HasMetricsQuery":{"type":"object","required":["project_id"],"properties":{"project_id":{"type":"integer","format":"int32"}}},"HasMetricsResponse":{"type":"object","required":["has_metrics"],"properties":{"has_metrics":{"type":"boolean"}}},"HealthCheckConfiguration":{"type":"object","description":"Health check configuration","required":["port","interval","timeout","retries"],"properties":{"http_path":{"type":["string","null"],"description":"HTTP path to check (if applicable)"},"interval":{"type":"integer","format":"int32","description":"Interval between checks (seconds)","minimum":0},"port":{"type":"integer","format":"int32","description":"Port to check","minimum":0},"retries":{"type":"integer","format":"int32","description":"Number of retries before marking unhealthy","minimum":0},"timeout":{"type":"integer","format":"int32","description":"Timeout for each check (seconds)","minimum":0}}},"HealthCheckEntryResponse":{"type":"object","required":["checked_at","status"],"properties":{"checked_at":{"type":"string","description":"ISO 8601 timestamp of when the probe ran.","example":"2026-04-22T11:30:00Z"},"error_message":{"type":["string","null"],"description":"Present only when the probe failed or was degraded."},"response_time_ms":{"type":["integer","null"],"format":"int32","description":"TCP connect latency in milliseconds."},"status":{"type":"string","description":"\"operational\" | \"degraded\" | \"down\"","example":"operational"}}},"HealthResponse":{"type":"object","required":["summaries"],"properties":{"summaries":{"type":"array","items":{"$ref":"#/components/schemas/HealthSummary"}}}},"HealthStatus":{"type":"string","description":"Overall health status.","enum":["healthy","degraded","down","unknown"]},"HealthSummary":{"type":"object","description":"Pre-computed health summary for a project environment.","required":["project_id","service_name","status","uptime_pct","error_rate","p95_latency_ms","cpu_usage_pct","memory_usage_pct","computed_at"],"properties":{"computed_at":{"type":"string","format":"date-time"},"cpu_usage_pct":{"type":"number","format":"double"},"environment_id":{"type":["integer","null"],"format":"int32"},"error_rate":{"type":"number","format":"double"},"last_deploy_at":{"type":["string","null"],"format":"date-time"},"last_deploy_id":{"type":["integer","null"],"format":"int32"},"memory_usage_pct":{"type":"number","format":"double"},"p95_latency_ms":{"type":"number","format":"double"},"project_id":{"type":"integer","format":"int32"},"service_name":{"type":"string"},"status":{"$ref":"#/components/schemas/HealthStatus"},"uptime_pct":{"type":"number","format":"double"}}},"HeartbeatApiRequest":{"type":"object","properties":{"architecture":{"type":["string","null"],"description":"Container platform of this node's Docker daemon (`linux/amd64`,\n`linux/arm64`), read from `docker info` by the agent. Absent from\npre-multi-arch agents; the stored value is then left untouched."},"capacity":{"description":"Resource capacity/usage info as JSON (cpu_usage, memory_usage, etc.)"},"containers":{"type":["array","null"],"items":{"$ref":"#/components/schemas/ContainerInventoryItem"},"description":"Container inventory for reconciliation (sent on first heartbeat after agent startup).\nEach entry has `container_id` and `container_name` of temps-managed containers."},"labels":{"description":"Updated node labels for scheduling (allows runtime label changes)."}}},"HeartbeatResponse":{"type":"object","required":["status","message"],"properties":{"message":{"type":"string"},"status":{"type":"string"}}},"HierarchyLevel":{"type":"object","description":"Describes a level in the data source hierarchy","required":["level","name","container_type","can_list_containers","can_list_entities"],"properties":{"can_list_containers":{"type":"boolean","description":"Can list containers at this level?","example":true},"can_list_entities":{"type":"boolean","description":"Can list entities at this level?","example":false},"container_type":{"type":"string","description":"Type of container at this level","example":"database"},"level":{"type":"integer","format":"int32","description":"Level number (0 = root)","example":0,"minimum":0},"name":{"type":"string","description":"Human-readable name for this level","example":"root"}}},"HistogramSummary":{"type":"object","description":"An explicit-bucket histogram aggregated over a time bucket.\n\nCarries the reduced scalars (count/sum/min/max) plus the explicit bucket\nlayout — `bounds` (the upper bounds) and `bucket_counts` (observation counts,\nsummed element-wise across the window; length is `bounds.len() + 1`, the last\nentry being the +Inf overflow bucket). With these, a caller can reconstruct\nany quantile (e.g. p95) via cumulative-count interpolation.","required":["count","sum","bounds","bucket_counts"],"properties":{"bounds":{"type":"array","items":{"type":"number","format":"double"},"description":"Explicit bucket upper bounds (OTLP `explicit_bounds`), ascending."},"bucket_counts":{"type":"array","items":{"type":"integer","format":"int64","minimum":0},"description":"Per-bucket observation counts summed element-wise across the window.\nLength is `bounds.len() + 1` (the trailing element is the +Inf bucket)."},"count":{"type":"integer","format":"int64","description":"Total observation count summed across the bucket window.","minimum":0},"max":{"type":["number","null"],"format":"double","description":"Maximum observed value, when reported by the producer."},"min":{"type":["number","null"],"format":"double","description":"Minimum observed value, when reported by the producer."},"sum":{"type":"number","format":"double","description":"Sum of observed values across the bucket window."}}},"HostnameChange":{"type":"object","description":"A single generated-hostname change in a flatten preview/apply.","required":["kind","id","old","new"],"properties":{"id":{"type":"integer","format":"int32","description":"Row id of the affected record."},"kind":{"type":"string","description":"`\"deployment\"` or `\"environment\"`."},"new":{"type":"string"},"old":{"type":"string"}}},"HostnamePreviewResponse":{"type":"object","description":"Combined preview of a hostname-mode change.","required":["hostname_changes","dns_changes","total"],"properties":{"dns_changes":{"type":"array","items":{"$ref":"#/components/schemas/DnsRecordChange"}},"hostname_changes":{"type":"array","items":{"$ref":"#/components/schemas/HostnameChange"}},"total":{"type":"integer","minimum":0},"zone_access_ok":{"type":["boolean","null"],"description":"Whether the provider token can manage this zone (None if not checked)."}}},"HourlyPageSessions":{"type":"object","required":["timestamp","session_count","event_count","avg_duration_seconds"],"properties":{"avg_duration_seconds":{"type":"number","format":"double"},"event_count":{"type":"integer","format":"int64"},"session_count":{"type":"integer","format":"int64"},"timestamp":{"type":"string"}}},"HourlyVisitsQuery":{"type":"object","required":["start_date","end_date"],"properties":{"aggregation_level":{"$ref":"#/components/schemas/AggregationLevel","description":"Aggregation level: events (page views), sessions (unique sessions), or visitors (unique visitors)"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"HttpChallengeDebugResponse":{"type":"object","required":["domain","challenge_exists","dns_a_records","dns_aaaa_records"],"properties":{"challenge_exists":{"type":"boolean"},"challenge_token":{"type":["string","null"]},"challenge_url":{"type":["string","null"],"description":"The full URL that Let's Encrypt will try to access to validate the challenge"},"dns_a_records":{"type":"array","items":{"type":"string"},"description":"IPv4 addresses the domain points to"},"dns_aaaa_records":{"type":"array","items":{"type":"string"},"description":"IPv6 addresses the domain points to"},"dns_error":{"type":["string","null"],"description":"Any DNS resolution errors"},"domain":{"type":"string"},"validation_url":{"type":["string","null"],"description":"The ACME validation URL (internal to ACME protocol)"}}},"ImportCredentials":{"type":"object","description":"Platform-specific credentials for accessing the source system.\n\nFor platforms like Vercel and Railway, this contains the API token.\nFor self-hosted platforms like Coolify and Dokploy, this also contains\nthe `base_url` of the instance.\n\nLocal importers (Docker) can use `ImportCredentials::none()`.","properties":{"base_url":{"type":["string","null"],"description":"Base URL override (for self-hosted platforms like Coolify, Dokploy)\n\nExample: `https://coolify.example.com`"},"extra":{"type":"object","description":"Additional platform-specific parameters","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"team_id":{"type":["string","null"],"description":"Team or organization ID (for platforms with team scoping like Vercel)"},"token":{"type":["string","null"],"description":"API token / bearer token for the source platform"}}},"ImportExecutionStatus":{"type":"string","description":"Import execution status","enum":["pending","inprogress","completed","failed"]},"ImportExternalServiceRequest":{"type":"object","description":"Request to import a Docker container as a managed service","required":["name","service_type","parameters","container_id"],"properties":{"container_id":{"type":"string","description":"Container ID or name to import","example":"abc123def456"},"name":{"type":"string","description":"Name to register the service as in Temps","example":"production-database"},"parameters":{"type":"object","description":"Service configuration parameters","additionalProperties":{},"propertyNames":{"type":"string"}},"service_type":{"$ref":"#/components/schemas/ServiceTypeRoute","description":"Service type"},"version":{"type":["string","null"],"description":"Optional version override"}}},"ImportOutcomeResponse":{"type":"object","required":["rows_read","inserted","updated","skipped_stale","skipped_invalid","errors"],"properties":{"errors":{"type":"array","items":{"$ref":"#/components/schemas/ImportRowErrorResponse"}},"inserted":{"type":"integer","minimum":0},"rows_read":{"type":"integer","minimum":0},"skipped_invalid":{"type":"integer","minimum":0},"skipped_stale":{"type":"integer","minimum":0},"updated":{"type":"integer","minimum":0}}},"ImportPlan":{"type":"object","description":"Complete import plan describing all operations to onboard a workload.\n\nThe plan is generated from a snapshot and presented to the user for review\nbefore any resources are created. Users can modify individual items\n(skip services, change actions) before approving execution.","required":["version","source","source_id","project","environment","deployment","summary","metadata"],"properties":{"additional_deployments":{"type":"array","items":{"$ref":"#/components/schemas/DeploymentConfiguration"},"description":"Additional deployments (workers, cron jobs, etc.)"},"cost_analysis":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/CostAnalysis","description":"Cost, overprovisioning, and savings analysis. Populated by importers\nthat can observe the whole source cluster (currently Kubernetes);\n`None` for container/platform imports."}]},"deployment":{"$ref":"#/components/schemas/DeploymentConfiguration","description":"Primary deployment configuration"},"domains":{"type":"array","items":{"$ref":"#/components/schemas/DomainPlan"},"description":"Custom domains to migrate"},"environment":{"$ref":"#/components/schemas/EnvironmentConfiguration","description":"Environment configuration"},"metadata":{"$ref":"#/components/schemas/PlanMetadata","description":"Plan metadata"},"project":{"$ref":"#/components/schemas/ProjectConfiguration","description":"Project configuration"},"services":{"type":"array","items":{"$ref":"#/components/schemas/ServicePlan"},"description":"Services to migrate (databases, caches, blob stores)\n\nEach service has an `action` field the user can change before execution."},"source":{"type":"string","description":"Source system this plan was generated from"},"source_id":{"type":"string","description":"Source workload / project ID in the source system"},"steps":{"type":"array","items":{"$ref":"#/components/schemas/MigrationStep"},"description":"Ordered list of migration steps that will be executed.\n\nThis is the human-readable execution plan. Each step describes what\nwill happen, what risks are involved, and what the user should verify.\nSteps are executed in order. If a step fails, execution stops and\nalready-created resources are reported for manual cleanup."},"summary":{"$ref":"#/components/schemas/MigrationSummary","description":"Human-readable summary of the entire migration"},"version":{"type":"string","description":"Plan version for compatibility tracking"}}},"ImportRowErrorResponse":{"type":"object","required":["row","reason"],"properties":{"reason":{"type":"string"},"row":{"type":"integer","minimum":0}}},"ImportSelector":{"type":"object","description":"Selector for discovering workloads","properties":{"label_filter":{"type":["object","null"],"description":"Filter by labels/tags","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"limit":{"type":["integer","null"],"description":"Limit number of results","minimum":0},"name_pattern":{"type":["string","null"],"description":"Filter by name pattern (glob/regex)"},"status_filter":{"type":["array","null"],"items":{"type":"string"},"description":"Filter by status (running, stopped, deployed, etc.)"},"workload_type_filter":{"type":["array","null"],"items":{"type":"string"},"description":"Filter by workload type (container, function, static-site, etc.)"}}},"ImportSource":{"type":"string","description":"Import source identifier","enum":["docker","coolify","dokploy","vercel","netlify","railway","render","fly","kubernetes","caprover","portainer","kamal","custom"]},"ImportSourceCapabilities":{"type":"object","description":"Source capabilities","required":["supports_volumes","supports_networks","supports_health_checks","supports_resource_limits","supports_build","supports_services","supports_domains","supports_project_snapshot","supports_cost_analysis","requires_credentials"],"properties":{"requires_credentials":{"type":"boolean","description":"Whether this source requires API credentials (token, base URL)"},"supports_build":{"type":"boolean"},"supports_cost_analysis":{"type":"boolean","description":"Supports cluster cost + overprovisioning analysis in the plan"},"supports_domains":{"type":"boolean","description":"Supports custom domain migration"},"supports_health_checks":{"type":"boolean"},"supports_networks":{"type":"boolean"},"supports_project_snapshot":{"type":"boolean","description":"Supports full project-level snapshots"},"supports_resource_limits":{"type":"boolean"},"supports_services":{"type":"boolean","description":"Supports service migration (databases, caches, etc.)"},"supports_volumes":{"type":"boolean"}}},"ImportSourceInfo":{"type":"object","description":"Information about an import source","required":["source","name","version","available","capabilities"],"properties":{"available":{"type":"boolean","description":"Whether the source is currently available"},"capabilities":{"$ref":"#/components/schemas/ImportSourceCapabilities","description":"Capabilities"},"name":{"type":"string","description":"Human-readable name"},"source":{"$ref":"#/components/schemas/ImportSource","description":"Source identifier"},"version":{"type":"string","description":"Source version"}}},"ImportStatusResponse":{"type":"object","description":"Response with import status","required":["session_id","status","errors","warnings","created_at","updated_at"],"properties":{"created_at":{"type":"string","format":"date-time","description":"Created at timestamp"},"deployment_id":{"type":["integer","null"],"format":"int32","description":"Created deployment ID"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Created environment ID"},"errors":{"type":"array","items":{"type":"string"},"description":"Errors (if any)"},"plan":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ImportPlan","description":"Import plan"}]},"project_id":{"type":["integer","null"],"format":"int32","description":"Created project ID"},"session_id":{"type":"string","description":"Session ID"},"status":{"$ref":"#/components/schemas/ImportExecutionStatus","description":"Current status"},"updated_at":{"type":"string","format":"date-time","description":"Updated at timestamp"},"validation":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ValidationReport","description":"Validation report"}]},"warnings":{"type":"array","items":{"type":"string"},"description":"Warnings (if any)"}}},"IncidentBucket":{"type":"object","required":["bucket_start","total_incidents","minor_incidents","major_incidents","critical_incidents","resolved_incidents","active_incidents"],"properties":{"active_incidents":{"type":"integer","format":"int64"},"avg_resolution_time_minutes":{"type":["number","null"],"format":"double"},"bucket_start":{"type":"string","format":"date-time"},"critical_incidents":{"type":"integer","format":"int64"},"major_incidents":{"type":"integer","format":"int64"},"minor_incidents":{"type":"integer","format":"int64"},"resolved_incidents":{"type":"integer","format":"int64"},"total_incidents":{"type":"integer","format":"int64"}}},"IncidentBucketedResponse":{"type":"object","required":["project_id","interval","buckets"],"properties":{"buckets":{"type":"array","items":{"$ref":"#/components/schemas/IncidentBucket"}},"environment_id":{"type":["integer","null"],"format":"int32"},"interval":{"type":"string"},"project_id":{"type":"integer","format":"int32"}}},"IncidentResponse":{"type":"object","required":["id","project_id","title","severity","status","started_at","created_at","updated_at"],"properties":{"created_at":{"type":"string","format":"date-time"},"description":{"type":["string","null"]},"environment_id":{"type":["integer","null"],"format":"int32"},"id":{"type":"integer","format":"int32"},"monitor_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"resolved_at":{"type":["string","null"],"format":"date-time"},"severity":{"type":"string"},"started_at":{"type":"string","format":"date-time"},"status":{"type":"string"},"title":{"type":"string"},"updated_at":{"type":"string","format":"date-time"}}},"IncidentUpdateResponse":{"type":"object","required":["id","incident_id","status","message","created_at"],"properties":{"created_at":{"type":"string","format":"date-time"},"id":{"type":"integer","format":"int32"},"incident_id":{"type":"integer","format":"int32"},"message":{"type":"string"},"status":{"type":"string"}}},"IncrRequest":{"type":"object","description":"Request to increment a value","required":["key"],"properties":{"amount":{"type":["integer","null"],"format":"int64","description":"Amount to increment by (default: 1)"},"key":{"type":"string","description":"The key to increment","example":"counter"},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1}}},"IncrResponse":{"type":"object","description":"Response for increment operation","required":["value"],"properties":{"value":{"type":"integer","format":"int64","description":"New value after increment","example":42}}},"InitAuthResponse":{"type":"object","required":["auth_url","session_token"],"properties":{"auth_url":{"type":"string"},"session_token":{"type":"string"}}},"Insight":{"type":"object","description":"An anomaly insight.","required":["id","project_id","service_name","severity","status","title","description","anomaly_ids","started_at","created_at","updated_at"],"properties":{"anomaly_ids":{"type":"array","items":{"type":"integer","format":"int64"}},"correlated_deploy_id":{"type":["integer","null"],"format":"int32"},"created_at":{"type":"string","format":"date-time"},"description":{"type":"string"},"environment":{"type":["string","null"]},"id":{"type":"integer","format":"int64"},"metric_name":{"type":["string","null"]},"project_id":{"type":"integer","format":"int32"},"resolved_at":{"type":["string","null"],"format":"date-time"},"service_name":{"type":"string"},"severity":{"$ref":"#/components/schemas/InsightSeverity"},"started_at":{"type":"string","format":"date-time"},"status":{"$ref":"#/components/schemas/InsightStatus"},"title":{"type":"string"},"updated_at":{"type":"string","format":"date-time"}}},"InsightSeverity":{"type":"string","description":"Severity of an anomaly insight.","enum":["low","medium","high","critical"]},"InsightStatus":{"type":"string","description":"Status of an insight.","enum":["active","resolved"]},"InsightsResponse":{"type":"object","required":["data","count"],"properties":{"count":{"type":"integer","minimum":0},"data":{"type":"array","items":{"$ref":"#/components/schemas/Insight"}}}},"IntegrationResponse":{"type":"object","required":["id","project_id","provider","webhook_path_token","webhook_path","status","has_secret","created_at"],"properties":{"config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ProviderConfig","description":"Typed provider config — allowlist and metered-billing mode. Null\nwhen the operator hasn't configured one yet (accept everything)."}]},"created_at":{"type":"string","format":"date-time"},"has_secret":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"last_event_at":{"type":["string","null"],"format":"date-time"},"project_id":{"type":"integer","format":"int32"},"provider":{"type":"string"},"status":{"type":"string"},"webhook_path":{"type":"string","description":"Relative path the UI can display and copy. The frontend builds\nthe full URL by prefixing its own origin."},"webhook_path_token":{"type":"string","description":"Unguessable token embedded in the public webhook URL. The full\nURL is `{api_origin}/webhooks/revenue/{provider}/{webhook_path_token}`."}}},"IpAccessControlQuery":{"type":"object","description":"Query parameters for listing IP access control rules","properties":{"action":{"type":["string","null"],"description":"Filter by action (\"block\" or \"allow\")"}}},"IpAccessControlResponse":{"type":"object","description":"Response model for IP access control rules","required":["id","ip_address","action","created_at","updated_at"],"properties":{"action":{"type":"string"},"created_at":{"type":"string","example":"2025-10-12T12:15:47.609Z"},"created_by":{"type":["integer","null"],"format":"int32"},"id":{"type":"integer","format":"int32"},"ip_address":{"type":"string"},"reason":{"type":["string","null"]},"updated_at":{"type":"string","example":"2025-10-12T12:15:47.609Z"}}},"JobStatusResponse":{"type":"object","description":"Snapshot of a background job. `status` is one of \"running\" | \"exited\"\n| \"failed\"; `exit_code` is populated only when `status == \"exited\"`.","required":["status","stdout","stderr"],"properties":{"exit_code":{"type":["integer","null"],"format":"int32"},"reason":{"type":["string","null"]},"status":{"type":"string"},"stderr":{"type":"string"},"stdout":{"type":"string"}}},"JobSummaryResponse":{"type":"object","description":"Row in the jobs list. Omits stdout/stderr so a noisy dev server doesn't\nbloat the list payload — callers drill into `GET /jobs/{id}` for the\nfull buffer.","required":["id","status","cmd","started_at"],"properties":{"cmd":{"type":"string"},"exit_code":{"type":["integer","null"],"format":"int32"},"id":{"type":"string"},"reason":{"type":["string","null"]},"started_at":{"type":"string"},"status":{"type":"string"}}},"JoinTokenStatusResponse":{"type":"object","description":"Response for join token status check","required":["has_token"],"properties":{"has_token":{"type":"boolean","description":"Whether a join token has been configured"}}},"JourneyEvent":{"type":"object","description":"A single event in the visitor journey timeline","required":["id","event_type","event_name","occurred_at","is_entry","is_exit","is_bounce"],"properties":{"event_data":{"description":"Custom event properties (for custom events)"},"event_name":{"type":"string","description":"Resolved event name (event_name for custom events, event_type for system events)"},"event_type":{"type":"string","description":"Event type: \"page_view\", \"page_leave\", \"custom\", \"web_vitals\""},"id":{"type":"integer","format":"int64","description":"Event ID"},"is_bounce":{"type":"boolean","description":"Whether this was a bounce"},"is_entry":{"type":"boolean","description":"Whether this is the entry page of the session"},"is_exit":{"type":"boolean","description":"Whether this is the exit page of the session"},"occurred_at":{"type":"string","format":"date-time","description":"When the event occurred"},"page_path":{"type":["string","null"],"description":"Page path where the event happened"},"page_title":{"type":["string","null"],"description":"Page title (if available)"},"referrer":{"type":["string","null"],"description":"Referrer URL for this event"},"scroll_depth":{"type":["integer","null"],"format":"int32","description":"Scroll depth percentage (0-100)"},"session_page_number":{"type":["integer","null"],"format":"int32","description":"Page number within the session (1-indexed)"},"time_on_page":{"type":["integer","null"],"format":"int32","description":"Time spent on page in seconds (computed, not from column)"}}},"JourneySession":{"type":"object","description":"A session within the visitor journey, grouping events","required":["session_id","started_at","duration_seconds","page_views","events_count","is_bounced","is_engaged","events"],"properties":{"channel":{"type":["string","null"],"description":"Traffic source: channel (e.g. \"organic\", \"direct\", \"social\")"},"duration_seconds":{"type":"integer","format":"int64","description":"Session duration in seconds"},"ended_at":{"type":["string","null"],"format":"date-time","description":"When the session ended"},"entry_path":{"type":["string","null"],"description":"Entry page path"},"events":{"type":"array","items":{"$ref":"#/components/schemas/JourneyEvent"},"description":"Events within this session, ordered chronologically"},"events_count":{"type":"integer","format":"int64","description":"Total events in this session"},"exit_path":{"type":["string","null"],"description":"Exit page path"},"is_bounced":{"type":"boolean","description":"Whether the session was a bounce"},"is_engaged":{"type":"boolean","description":"Whether the visitor was engaged (had non-pageview events)"},"page_views":{"type":"integer","format":"int64","description":"Number of page views in this session"},"referrer":{"type":["string","null"],"description":"Traffic source: referrer URL"},"referrer_hostname":{"type":["string","null"],"description":"Traffic source: referrer hostname"},"session_id":{"type":"integer","format":"int32","description":"Session internal ID"},"started_at":{"type":"string","format":"date-time","description":"When the session started"},"utm_campaign":{"type":["string","null"],"description":"UTM campaign parameter"},"utm_medium":{"type":["string","null"],"description":"UTM medium parameter"},"utm_source":{"type":["string","null"],"description":"UTM source parameter"}}},"KeysRequest":{"type":"object","description":"Request to get keys matching a pattern","required":["pattern"],"properties":{"pattern":{"type":"string","description":"Pattern to match (supports * and ? wildcards)","example":"user:*"},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1}}},"KeysResponse":{"type":"object","description":"Response for keys operation","required":["keys"],"properties":{"keys":{"type":"array","items":{"type":"string"},"description":"List of matching keys","example":["user:1","user:2","user:3"]}}},"KillJobBody":{"type":"object","properties":{"force":{"type":"boolean","description":"When true, sends SIGKILL immediately. Defaults to SIGTERM so the\nprocess gets a chance to flush (mirrors `Command.kill()` in\n`@vercel/sandbox`, which also accepts a signal override)."}},"additionalProperties":false},"KnownAiAgentsResponse":{"type":"object","description":"Response listing every AI agent the detector knows about.","required":["items"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AiAgentDescriptor"}}}},"KvStatusResponse":{"type":"object","description":"Response for KV service status","required":["enabled","healthy"],"properties":{"docker_image":{"type":["string","null"],"description":"Docker image being used","example":"gotempsh/redis-walg:8-bookworm"},"enabled":{"type":"boolean","description":"Whether the KV service is enabled"},"healthy":{"type":"boolean","description":"Whether the underlying Redis service is healthy"},"version":{"type":["string","null"],"description":"Service version","example":"7.2"}}},"LemonSqueezyConfig":{"type":"object","properties":{"product_allowlist":{"type":"array","items":{"type":"string"}},"variant_allowlist":{"type":"array","items":{"type":"string"}}}},"LetsEncryptSettings":{"type":"object","properties":{"email":{"type":["string","null"],"default":null},"environment":{"type":"string","default":"production"}}},"LineContext":{"type":"object","description":"Raw surrounding lines for a single match (grep -C style).","required":["before","after"],"properties":{"after":{"type":"array","items":{"$ref":"#/components/schemas/ContextLine"},"description":"Lines immediately after the match, oldest-first."},"before":{"type":"array","items":{"$ref":"#/components/schemas/ContextLine"},"description":"Lines immediately before the match, oldest-first."}}},"LinkServiceRequest":{"type":"object","required":["project_id"],"properties":{"project_id":{"type":"integer","format":"int32"}}},"ListAgentsResponse":{"type":"object","required":["items","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AgentConfigResponse"}},"total":{"type":"integer","minimum":0}}},"ListApiKeysQuery":{"type":"object","properties":{"page":{"type":["integer","null"],"format":"int64","minimum":0},"page_size":{"type":["integer","null"],"format":"int64","minimum":0}}},"ListAuditLogsQuery":{"type":"object","description":"Query parameters for listing audit logs.\n\nEvery field is optional — omitting one means \"don't filter on it\". Deriving\n`IntoParams` makes utoipa render them as optional query params with the\ncorrect types; the previous hand-written `params((\"operation_type\", Query,\n…))` tuples defaulted every param to `required: true, type: string`, which\nmisled both API clients and the AI `describe_api`/`call_api` tools into\nthinking all filters were mandatory.","properties":{"from":{"type":["string","null"],"format":"date-time","description":"Start timestamp (milliseconds since epoch)"},"limit":{"type":["integer","null"],"format":"int32","description":"Maximum number of logs to return"},"offset":{"type":["integer","null"],"format":"int32","description":"Number of logs to skip"},"operation_type":{"type":["string","null"],"description":"Filter logs by operation type (omit for all)"},"to":{"type":["string","null"],"format":"date-time","description":"End timestamp (milliseconds since epoch)"},"user_id":{"type":["integer","null"],"format":"int32","description":"Filter logs by user ID (omit for all users)"}}},"ListBlobsQuery":{"type":"object","description":"Query parameters for listing blobs","properties":{"cursor":{"type":["string","null"],"description":"Continuation token for pagination"},"limit":{"type":["integer","null"],"format":"int32","description":"Maximum number of items to return","example":100},"prefix":{"type":["string","null"],"description":"Prefix to filter by","example":"images/"},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1}}},"ListBlobsResponse":{"type":"object","description":"Response for listing blobs","required":["blobs","hasMore"],"properties":{"blobs":{"type":"array","items":{"$ref":"#/components/schemas/BlobResponse"},"description":"List of blobs"},"cursor":{"type":["string","null"],"description":"Continuation token for next page"},"hasMore":{"type":"boolean","description":"Whether there are more results","example":false}}},"ListCustomDomainsResponse":{"type":"object","required":["domains","total"],"properties":{"domains":{"type":"array","items":{"$ref":"#/components/schemas/CustomDomainResponse"}},"total":{"type":"integer","minimum":0}}},"ListDeploymentTokensQuery":{"type":"object","properties":{"page":{"type":["integer","null"],"format":"int64","example":1,"minimum":0},"page_size":{"type":["integer","null"],"format":"int64","example":20,"minimum":0}}},"ListDomainsResponse":{"type":"object","required":["domains","total","page","page_size"],"properties":{"domains":{"type":"array","items":{"$ref":"#/components/schemas/DomainResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"ListEntitiesQuery":{"type":"object","properties":{"limit":{"type":"integer","description":"Maximum number of entities to return","example":100,"minimum":0},"token":{"type":["string","null"],"description":"Continuation token for pagination (backend-specific)"}}},"ListErrorEventsQuery":{"type":"object","properties":{"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0}}},"ListErrorGroupsQuery":{"type":"object","properties":{"end_date":{"type":["string","null"],"format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"sort_by":{"type":["string","null"]},"sort_order":{"type":"string"},"start_date":{"type":["string","null"],"format":"date-time"},"status":{"type":["string","null"]}}},"ListJobsResponse":{"type":"object","required":["items"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/JobSummaryResponse"}}}},"ListMcpsResponse":{"type":"object","description":"Concrete list wrapper for MCP server definitions (utoipa requires non-generic types).","required":["items","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/McpDefinitionResponse"}},"total":{"type":"integer","minimum":0}}},"ListOnDemandCertsResponse":{"type":"object","description":"Paginated list of on-demand cert attempts (ADR-018 §5 console \"Certificates\"\nsurface). Joined with current `domains.status`, newest first.","required":["certs","total","page","page_size"],"properties":{"certs":{"type":"array","items":{"$ref":"#/components/schemas/OnDemandCertRow"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"ListOrdersResponse":{"type":"object","required":["orders"],"properties":{"orders":{"type":"array","items":{"$ref":"#/components/schemas/AcmeOrderResponse"}}}},"ListPresetsResponse":{"type":"object","required":["presets","total"],"properties":{"presets":{"type":"array","items":{"$ref":"#/components/schemas/PresetResponse"}},"total":{"type":"integer","minimum":0}}},"ListRunsResponse":{"type":"object","required":["items","total","page","page_size"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AgentRunResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"ListSandboxesResponse":{"type":"object","description":"SDK list response: `{ sandboxes: [...], pagination: {...} }`.","required":["sandboxes","pagination"],"properties":{"pagination":{"$ref":"#/components/schemas/Pagination"},"sandboxes":{"type":"array","items":{"$ref":"#/components/schemas/SandboxInner"}}}},"ListScansQuery":{"type":"object","properties":{"page":{"type":["integer","null"],"format":"int64","example":1,"minimum":0},"page_size":{"type":["integer","null"],"format":"int64","example":20,"minimum":0}}},"ListSecretsResponse":{"type":"object","required":["items","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/SecretResponse"}},"total":{"type":"integer","minimum":0}}},"ListSkillsResponse":{"type":"object","description":"Concrete list wrapper for skill definitions (utoipa requires non-generic types).","required":["items","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/SkillDefinitionResponse"}},"total":{"type":"integer","minimum":0}}},"ListTagsResponse":{"type":"object","description":"Response for listing tags","required":["tags","total"],"properties":{"tags":{"type":"array","items":{"type":"string"},"description":"List of available tags"},"total":{"type":"integer","description":"Total number of tags","minimum":0}}},"ListTemplatesQuery":{"type":"object","description":"Query parameters for listing templates","properties":{"featured":{"type":["boolean","null"],"description":"Only return featured templates"},"tag":{"type":["string","null"],"description":"Filter templates by tag"}}},"ListTemplatesResponse":{"type":"object","description":"Response for listing templates","required":["templates","total"],"properties":{"templates":{"type":"array","items":{"$ref":"#/components/schemas/TemplateResponse"},"description":"List of templates"},"total":{"type":"integer","description":"Total number of templates","minimum":0}}},"ListVulnerabilitiesQuery":{"type":"object","properties":{"page":{"type":["integer","null"],"format":"int64","example":1,"minimum":0},"page_size":{"type":["integer","null"],"format":"int64","example":20,"minimum":0},"severity":{"type":["string","null"],"example":"CRITICAL"}}},"LiveVisitorInfo":{"type":"object","required":["id","visitor_id","project_id","environment_id","first_seen","last_seen","is_crawler"],"properties":{"city":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"crawler_name":{"type":["string","null"]},"current_page":{"type":["string","null"],"description":"Most recent page path visited by this visitor"},"custom_data":{},"environment_id":{"type":"integer","format":"int32"},"first_channel":{"type":["string","null"],"description":"Marketing channel from the first visit (e.g. \"Organic Search\", \"Direct\")"},"first_referrer":{"type":["string","null"],"description":"Full referrer URL from the visitor's first session"},"first_referrer_hostname":{"type":["string","null"],"description":"Hostname extracted from first_referrer"},"first_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"id":{"type":"integer","format":"int32"},"ip_address":{"type":["string","null"]},"ip_address_id":{"type":["integer","null"],"format":"int32"},"is_crawler":{"type":"boolean"},"is_eu":{"type":["boolean","null"]},"last_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"latitude":{"type":["number","null"],"format":"double"},"longitude":{"type":["number","null"],"format":"double"},"project_id":{"type":"integer","format":"int32"},"region":{"type":["string","null"]},"timezone":{"type":["string","null"]},"user_agent":{"type":["string","null"]},"visitor_id":{"type":"string"}}},"LiveVisitorsListResponse":{"type":"object","required":["total_count","visitors","window_minutes"],"properties":{"total_count":{"type":"integer","format":"int64"},"visitors":{"type":"array","items":{"$ref":"#/components/schemas/LiveVisitorInfo"}},"window_minutes":{"type":"integer","format":"int32"}}},"LocationCount":{"type":"object","required":["location","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"location":{"type":"string"},"percentage":{"type":"number","format":"double"}}},"LocationGranularity":{"type":"string","enum":["country","region","city"]},"LocationInfo":{"type":"object","properties":{"city":{"type":["string","null"]},"country":{"type":["string","null"]},"region":{"type":["string","null"]}}},"LogLevel":{"type":"string","description":"Normalized log level","enum":["TRACE","DEBUG","INFO","WARN","ERROR"]},"LogRecord":{"type":"object","description":"A single log record ready for storage.","required":["project_id","resource","timestamp","observed_timestamp","severity","severity_text","body","attributes"],"properties":{"attributes":{"type":"object","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"body":{"type":"string"},"deployment_id":{"type":["integer","null"],"format":"int32"},"observed_timestamp":{"type":"string","format":"date-time"},"project_id":{"type":"integer","format":"int32"},"resource":{"$ref":"#/components/schemas/ResourceInfo"},"severity":{"$ref":"#/components/schemas/LogSeverity"},"severity_text":{"type":"string"},"span_id":{"type":["string","null"]},"timestamp":{"type":"string","format":"date-time"},"trace_id":{"type":["string","null"]}}},"LogSearchLine":{"type":"object","description":"A single line in search results","required":["timestamp","level","service","message","chunk_id","line_offset"],"properties":{"chunk_id":{"type":"string"},"container_id":{"type":"string","description":"Container this line came from — lets the UI tag/group lines by container\nin a combined (\"show all\") multi-container view."},"context":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/LineContext","description":"Raw surrounding lines (grep -C). `None` unless `context_lines > 0` was\nrequested. Overlapping windows between nearby matches are merged: the\nshared neighbors appear on the earlier match only, so the frontend can\nrender one continuous block without duplicated lines."}]},"deploy_id":{"type":["integer","null"],"format":"int32"},"fields":{},"level":{"$ref":"#/components/schemas/LogLevel"},"line_offset":{"type":"integer","format":"int32"},"message":{"type":"string"},"node_id":{"type":["integer","null"],"format":"int32","description":"Worker node the line came from (`None` = control-plane-local)."},"node_name":{"type":["string","null"],"description":"Human-readable node name for display."},"service":{"type":"string"},"timestamp":{"type":"string"}}},"LogSeverity":{"type":"string","description":"Log severity level (simplified from OTel's 24 levels).","enum":["TRACE","DEBUG","INFO","WARN","ERROR","FATAL"]},"LogSource":{"type":"object","description":"A distinct log source (container) seen in the queried scope. Used to populate\nthe history filter dropdowns with the *full* set of containers/nodes for the\nproject + env + deployment + time window — independent of the active\ncontainer/node/service filter, so the user can switch between them.","required":["container_id","service"],"properties":{"container_id":{"type":"string"},"node_id":{"type":["integer","null"],"format":"int32"},"node_name":{"type":["string","null"]},"service":{"type":"string"}}},"LogStream":{"type":"string","description":"Log output stream","enum":["stdout","stderr"]},"LoginRequest":{"type":"object","required":["email","password"],"properties":{"email":{"type":"string"},"password":{"type":"string"}}},"LogsQuery":{"type":"object","properties":{"tail":{"type":["integer","null"],"description":"Number of lines to return from the tail. Defaults to 200, capped at 2000.","minimum":0}}},"LogsResponse":{"type":"object","required":["data","count"],"properties":{"count":{"type":"integer","minimum":0},"data":{"type":"array","items":{"$ref":"#/components/schemas/LogRecord"}}}},"ManagedDomainResponse":{"type":"object","description":"Managed domain response","required":["id","provider_id","domain","auto_manage","verified","generated_hostname_mode","sync_generated_records","created_at","updated_at"],"properties":{"auto_manage":{"type":"boolean"},"created_at":{"type":"string"},"domain":{"type":"string"},"generated_hostname_mode":{"type":"string","description":"Generated hostname layout: `\"standard\"` or `\"flat\"`."},"id":{"type":"integer","format":"int32"},"provider_id":{"type":"integer","format":"int32"},"sync_generated_records":{"type":"boolean","description":"Whether generated hostnames are reconciled into the provider's DNS zone."},"updated_at":{"type":"string"},"verification_error":{"type":["string","null"]},"verified":{"type":"boolean"},"verified_at":{"type":["string","null"]},"zone_access_error":{"type":["string","null"],"description":"Detail for a failed zone-access check."},"zone_access_ok":{"type":["boolean","null"],"description":"Last token zone-access check: `Some(true)`/`Some(false)`/`None` (unchecked)."},"zone_id":{"type":["string","null"]}}},"ManualAction":{"type":"object","description":"A manual action the user must perform outside of the automated migration","required":["timing","description","reason"],"properties":{"description":{"type":"string","description":"Human-readable description"},"reason":{"type":"string","description":"Why this can't be automated"},"timing":{"$ref":"#/components/schemas/ManualActionTiming","description":"When this action needs to happen"}}},"ManualActionTiming":{"type":"string","description":"When a manual action needs to happen relative to migration","enum":["before-migration","after-migration","within-hours"]},"McpDefinitionResponse":{"type":"object","required":["id","slug","name","config","created_at","updated_at"],"properties":{"config":{"type":"object"},"created_at":{"type":"string"},"description":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"project_id":{"type":["integer","null"],"format":"int32"},"slug":{"type":"string"},"updated_at":{"type":"string"}}},"MessageContent":{"oneOf":[{"type":"string"},{"type":"array","items":{"$ref":"#/components/schemas/ContentPart"}}]},"MessagePart":{"oneOf":[{"type":"object","required":["text","type"],"properties":{"text":{"type":"string"},"type":{"type":"string","enum":["text"]}}},{"type":"object","required":["tool","type"],"properties":{"tool":{"$ref":"#/components/schemas/ToolInfo"},"type":{"type":"string","enum":["tool"]}}}],"description":"One ordered segment of an assistant turn: a chunk of prose, or a tool\ninvocation. Mirrors the `metadata.parts` persisted by the chat service."},"MessageResponse":{"type":"object","required":["role","content","created_at"],"properties":{"content":{"type":"string"},"created_at":{"type":"string"},"parts":{"type":["array","null"],"items":{"$ref":"#/components/schemas/MessagePart"},"description":"Ordered render segments (text / tool, in the order they occurred) so a\nreloaded chat shows the same interleaving as the live stream. Absent for\nolder messages persisted before parts were tracked; the client then falls\nback to `tools` (rendered first) + `content`."},"role":{"type":"string"},"tools":{"type":["array","null"],"items":{"$ref":"#/components/schemas/ToolInfo"},"description":"Tools the assistant ran on this turn (persisted in message metadata), so\nthe chat replays its tool work after a reload. Absent for plain turns."}}},"MeteredMode":{"type":"string","description":"How to treat metered-billing subscriptions when computing MRR.\n\n* `DeriveFromInvoices` (default): ignore the subscription row's\n `mrr_minor` for metered items and rely on the per-invoice\n [`NormalizedEventType::MrrRealized`] events instead. Correct for\n pure-metered, hybrid, tiered, and flat — recommended.\n* `UseSubscription`: trust whatever MRR the subscription parser\n returns (0 for metered). Legacy behavior.\n* `Ignore`: drop metered subscriptions from MRR entirely.","enum":["derive_from_invoices","use_subscription","ignore"]},"MetricAggregation":{"oneOf":[{"type":"string","description":"Arithmetic mean of the scalar value in each bucket. The default.","enum":["avg"]},{"type":"string","description":"Sum of the scalar value in each bucket.","enum":["sum"]},{"type":"string","description":"Minimum scalar value in each bucket.","enum":["min"]},{"type":"string","description":"Maximum scalar value in each bucket.","enum":["max"]},{"type":"string","description":"Number of points in each bucket.","enum":["count"]},{"type":"string","description":"Per-second rate of change of a cumulative monotonic counter, computed as\n`(max - min) / window_seconds` within each bucket. Non-monotonic series\nfall back to a simple delta.","enum":["rate_per_sec"]},{"type":"object","description":"A quantile of the scalar value in each bucket. The carried `f64` is the\nrequested quantile in `[0.0, 1.0]`.","required":["quantile"],"properties":{"quantile":{"type":"number","format":"double","description":"A quantile of the scalar value in each bucket. The carried `f64` is the\nrequested quantile in `[0.0, 1.0]`."}}}],"description":"The aggregation applied when reducing raw metric points into a time bucket.\n\nStore-neutral: every storage backend (ClickHouse today, TimescaleDB later)\nmust be able to satisfy this contract. `Quantile(q)` carries the requested\nquantile in `[0.0, 1.0]` (e.g. `0.95` for p95)."},"MetricBucket":{"type":"object","description":"A time-bucketed metric aggregate for chart display.\n\nStore-neutral response contract. The legacy scalar fields\n(`avg_value`/`min_value`/`max_value`/`count`) are always populated for chart\nback-compat. The richer fields describe the explicitly-requested\n[`MetricAggregation`] (`value`), optional `quantiles`, an optional\n`histogram_summary`, and a `series_key` identifying the label-set when the\nquery used `group_by`.","required":["bucket","avg_value","min_value","max_value","count"],"properties":{"avg_value":{"type":"number","format":"double"},"bucket":{"type":"string","format":"date-time"},"count":{"type":"integer","format":"int64"},"histogram_summary":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/HistogramSummary","description":"A reduced histogram summary when the bucketed metric is a histogram."}]},"max_value":{"type":"number","format":"double"},"min_value":{"type":"number","format":"double"},"quantiles":{"type":"array","items":{"type":"array","items":false,"prefixItems":[{"type":"number","format":"double"},{"type":"number","format":"double"}]},"description":"Computed quantile/value pairs `(quantile, value)` when the query asked for\nquantile aggregation; otherwise empty."},"series_key":{"type":["array","null"],"items":{"type":"array","items":false,"prefixItems":[{"type":"string"},{"type":"string"}]},"description":"The label-set this bucket belongs to, as ordered `(key, value)` pairs,\nwhen the query grouped by labels. Empty/`None` = the single ungrouped\naggregate stream."},"value":{"type":"number","format":"double","description":"The value of the requested [`MetricAggregation`] for this bucket. For the\ndefault `Avg` aggregation this equals `avg_value`. `#[serde(default)]` so\npre-existing payloads (which only carried avg/min/max/count) still parse."}}},"MetricDataPoint":{"type":"object","description":"A single `(timestamp, value)` data point in a metric series.","required":["time","value"],"properties":{"time":{"type":"string","description":"ISO 8601 timestamp with `Z` suffix."},"value":{"type":"number","format":"double","description":"Metric value at this bucket."}}},"MetricType":{"type":"string","description":"The type of an OTel metric.","enum":["gauge","sum","histogram","exponential_histogram","summary"]},"MetricsOverTimeResponse":{"type":"object","required":["timestamps","ttfb","lcp","fid","fcp","cls","inp"],"properties":{"cls":{"type":"array","items":{"type":["number","null"],"format":"float"}},"cls_p75":{"type":["number","null"],"format":"float"},"cls_p90":{"type":["number","null"],"format":"float"},"cls_p95":{"type":["number","null"],"format":"float"},"cls_p99":{"type":["number","null"],"format":"float"},"fcp":{"type":"array","items":{"type":["number","null"],"format":"float"}},"fcp_p75":{"type":["number","null"],"format":"float"},"fcp_p90":{"type":["number","null"],"format":"float"},"fcp_p95":{"type":["number","null"],"format":"float"},"fcp_p99":{"type":["number","null"],"format":"float"},"fid":{"type":"array","items":{"type":["number","null"],"format":"float"}},"fid_p75":{"type":["number","null"],"format":"float"},"fid_p90":{"type":["number","null"],"format":"float"},"fid_p95":{"type":["number","null"],"format":"float"},"fid_p99":{"type":["number","null"],"format":"float"},"inp":{"type":"array","items":{"type":["number","null"],"format":"float"}},"inp_p75":{"type":["number","null"],"format":"float"},"inp_p90":{"type":["number","null"],"format":"float"},"inp_p95":{"type":["number","null"],"format":"float"},"inp_p99":{"type":["number","null"],"format":"float"},"lcp":{"type":"array","items":{"type":["number","null"],"format":"float"}},"lcp_p75":{"type":["number","null"],"format":"float"},"lcp_p90":{"type":["number","null"],"format":"float"},"lcp_p95":{"type":["number","null"],"format":"float"},"lcp_p99":{"type":["number","null"],"format":"float"},"timestamps":{"type":"array","items":{"type":"string"}},"ttfb":{"type":"array","items":{"type":["number","null"],"format":"float"}},"ttfb_p75":{"type":["number","null"],"format":"float"},"ttfb_p90":{"type":["number","null"],"format":"float"},"ttfb_p95":{"type":["number","null"],"format":"float"},"ttfb_p99":{"type":["number","null"],"format":"float"}}},"MetricsQuery":{"type":"object","required":["start_date","end_date","project_id"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"MetricsRangeQuery":{"type":"object","description":"Query params for range metric queries.","required":["metric"],"properties":{"metric":{"type":"string","description":"Metric name, e.g. `\"pg.connections_active\"`."},"percentile":{"type":["number","null"],"format":"double","description":"Optional histogram percentile (0–100). When provided, the endpoint\nfetches histogram buckets and computes the requested quantile."},"range":{"type":"string","description":"Time window: `\"1h\"` | `\"6h\"` | `\"24h\"` | `\"7d\"`."}}},"MetricsStatusResponse":{"type":"object","description":"Freshness status: when metrics were last received for this service.","properties":{"last_received_at":{"type":["string","null"],"description":"ISO 8601 timestamp of the most recent metric row, or null if none yet."}}},"MetricsStoreKind":{"type":"string","description":"Which storage backend to use for the MetricsStore.","enum":["timescale_db","click_house"]},"MetricsSummaryResponse":{"type":"object","required":["currency","current_mrr_minor","current_arr_minor","active_subscriptions","active_customers","churned_last_30d","arpu_minor"],"properties":{"active_customers":{"type":"integer","format":"int64"},"active_subscriptions":{"type":"integer","format":"int64"},"arpu_minor":{"type":"integer","format":"int64"},"churned_last_30d":{"type":"integer","format":"int64"},"currency":{"type":"string"},"current_arr_minor":{"type":"integer","format":"int64"},"current_mrr_minor":{"type":"integer","format":"int64"}}},"MfaRequiredResponse":{"type":"object","required":["requires_mfa","session_token"],"properties":{"requires_mfa":{"type":"boolean"},"session_token":{"type":"string"}}},"MfaSetupResponse":{"type":"object","required":["secret_key","qr_code","recovery_codes"],"properties":{"qr_code":{"type":"string"},"recovery_codes":{"type":"array","items":{"type":"string"}},"secret_key":{"type":"string"}}},"MfaVerificationRequest":{"type":"object","required":["code"],"properties":{"code":{"type":"string"}}},"MigrationStep":{"type":"object","description":"A single step in the migration execution plan.\n\nSteps are presented to the user before execution so they know exactly\nwhat will happen. During execution, each step runs in order and reports\nits outcome before proceeding to the next.","required":["order","id","title","description","resource_type","risk","skippable","reversible"],"properties":{"data_implications":{"type":"array","items":{"$ref":"#/components/schemas/DataImplication"},"description":"Data implications — what could go wrong or what the user needs to know"},"description":{"type":"string","description":"Detailed description of what this step does"},"estimated_duration":{"type":["string","null"],"description":"Estimated duration hint (e.g., \"< 1 second\", \"10-30 seconds\")"},"id":{"type":"string","description":"Machine-readable step identifier (e.g., \"create-project\", \"create-service-postgres\")"},"order":{"type":"integer","description":"Step number (1-based, for display)","minimum":0},"post_conditions":{"type":"array","items":{"type":"string"},"description":"Things the user should verify AFTER this step completes"},"pre_conditions":{"type":"array","items":{"type":"string"},"description":"Things the user should verify BEFORE this step runs"},"resource_type":{"$ref":"#/components/schemas/StepResourceType","description":"What kind of resource this step creates/modifies"},"reversible":{"type":"boolean","description":"Whether this step is reversible (can be cleaned up on failure)"},"risk":{"$ref":"#/components/schemas/RiskLevel","description":"Risk level for this step"},"skippable":{"type":"boolean","description":"Whether this step can be skipped by the user"},"skipped":{"type":"boolean","description":"Whether the user has chosen to skip this step (set during review)"},"title":{"type":"string","description":"Human-readable title (e.g., \"Create project 'my-app'\")"}}},"MigrationSummary":{"type":"object","description":"Human-readable summary of the entire migration plan","required":["headline","overall_risk","resource_counts"],"properties":{"critical_warnings":{"type":"array","items":{"type":"string"},"description":"Critical warnings that must be acknowledged before proceeding.\nThese are the most important things the user needs to know."},"headline":{"type":"string","description":"One-line summary (e.g., \"Migrate 'my-app' from Vercel with 1 database, 2 domains\")"},"manual_actions_required":{"type":"array","items":{"$ref":"#/components/schemas/ManualAction"},"description":"Manual actions the user must perform (before or after migration)"},"overall_risk":{"$ref":"#/components/schemas/RiskLevel","description":"Overall risk assessment for the migration"},"resource_counts":{"$ref":"#/components/schemas/ResourceCounts","description":"Resource counts for quick overview"},"unsupported_features":{"type":"array","items":{"$ref":"#/components/schemas/UnsupportedFeature"},"description":"Features from the source platform that cannot be migrated"}}},"MintEnrollmentTokenRequest":{"type":"object","properties":{"bound_node_name":{"type":["string","null"],"description":"Optional: restrict the token to register one specific node name."},"max_uses":{"type":["integer","null"],"format":"int32","description":"Maximum registrations this token may authorize (default 1)."},"ttl_secs":{"type":["integer","null"],"format":"int64","description":"Time-to-live in seconds (default 3600 = 1h)."}}},"MintEnrollmentTokenResponse":{"type":"object","required":["id","token","expires_at","max_uses","message"],"properties":{"ca_fingerprint":{"type":["string","null"],"description":"SHA-256 fingerprint of the cluster CA (if mTLS is set up). Pass it to the\nworker as `temps join --ca-fingerprint ` to verify the CA on join."},"expires_at":{"type":"string"},"id":{"type":"integer","format":"int32"},"max_uses":{"type":"integer","format":"int32"},"message":{"type":"string"},"token":{"type":"string","description":"The plaintext enrollment token — shown only once, save it now."}}},"MiscResult":{"type":"object","description":"Miscellaneous validation result","required":["is_disposable","is_role_account","is_b2c"],"properties":{"gravatar_url":{"type":["string","null"],"description":"Gravatar URL if available"},"is_b2c":{"type":"boolean","description":"Whether the email provider is a B2C (consumer) email provider"},"is_disposable":{"type":"boolean","description":"Whether the email is from a disposable email provider"},"is_role_account":{"type":"boolean","description":"Whether the email is a role-based account (e.g., admin@, info@)"}}},"MkdirBody":{"type":"object","required":["path"],"properties":{"path":{"type":"string"}},"additionalProperties":false},"ModelInfo":{"type":"object","required":["id","object","owned_by"],"properties":{"id":{"type":"string"},"object":{"type":"string"},"owned_by":{"type":"string"}}},"ModelListResponse":{"type":"object","required":["object","data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ModelInfo"}},"object":{"type":"string"}}},"ModelPricing":{"type":"object","description":"Pricing for a single model, all values in USD per 1M tokens.\nFields are optional because not every provider supports every pricing tier.","required":["model","display_name","provider","input_per_million","output_per_million"],"properties":{"batch_input_per_million":{"type":["number","null"],"format":"double","description":"Batch API input cost per 1M tokens (if provider offers batch pricing)"},"batch_output_per_million":{"type":["number","null"],"format":"double","description":"Batch API output cost per 1M tokens"},"cache_hit_per_million":{"type":["number","null"],"format":"double","description":"Cache hit / refresh cost per 1M tokens"},"cache_write_1h_per_million":{"type":["number","null"],"format":"double","description":"1-hour cache write cost per 1M tokens"},"cache_write_5m_per_million":{"type":["number","null"],"format":"double","description":"5-minute cache write cost per 1M tokens (Anthropic-style prompt caching)"},"deprecated":{"type":"boolean","description":"Whether the model is deprecated"},"display_name":{"type":"string","description":"Human-readable model name (e.g. \"Claude Sonnet 4.6\")"},"input_per_million":{"type":"number","format":"double","description":"Base input token cost per 1M tokens"},"model":{"type":"string","description":"Model identifier (e.g. \"gpt-5.4\", \"claude-sonnet-4-6\")"},"output_per_million":{"type":"number","format":"double","description":"Output token cost per 1M tokens"},"provider":{"type":"string","description":"Provider ID (e.g. \"openai\", \"anthropic\")"}}},"ModelUsage":{"type":"object","required":["model","provider","request_count","input_tokens","output_tokens","total_tokens","avg_latency_ms"],"properties":{"avg_latency_ms":{"type":"number","format":"double"},"input_tokens":{"type":"integer","format":"int64"},"model":{"type":"string"},"output_tokens":{"type":"integer","format":"int64"},"provider":{"type":"string"},"request_count":{"type":"integer","format":"int64"},"total_tokens":{"type":"integer","format":"int64"}}},"MonitorResponse":{"type":"object","required":["id","project_id","name","monitor_type","monitor_url","check_interval_seconds","is_active","created_at","updated_at"],"properties":{"check_interval_seconds":{"type":"integer","format":"int32"},"check_path":{"type":["string","null"]},"created_at":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"monitor_type":{"type":"string"},"monitor_url":{"type":"string"},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"updated_at":{"type":"string","format":"date-time"}}},"MonitorStatus":{"type":"object","required":["monitor","current_status","uptime_percentage"],"properties":{"avg_response_time_ms":{"type":["integer","null"],"format":"int32"},"current_status":{"type":"string"},"monitor":{"$ref":"#/components/schemas/MonitorResponse"},"uptime_percentage":{"type":"number","format":"double"}}},"MonitoringSettings":{"type":"object","description":"Global metrics observability configuration.\n\nControls whether the MetricsScraper and AlertEvaluator background tasks\nare active, which storage backend they write to, and how long data is kept\nat each retention tier.","properties":{"clickhouse_url":{"type":["string","null"],"description":"ClickHouse DSN (legacy, optional). The runtime metrics store is built\nfrom the `TEMPS_CLICKHOUSE_*` env vars, never from this field; it is\nretained for compatibility and operator reference only.\nExample: `\"http://localhost:8123\"`.","default":null},"enabled":{"type":"boolean","description":"Enable or disable all metrics collection (scraping + alerting).\nDefaults to `false` so new installs don't write to TimescaleDB until\nan operator explicitly enables the feature.","default":false},"retention_daily_years":{"type":"integer","format":"int32","description":"How many years of daily-aggregate data to keep (converted to days internally).","default":2,"example":2,"maximum":10,"minimum":1},"retention_hourly_days":{"type":"integer","format":"int32","description":"How many days of hourly-aggregate data to keep.","default":90,"example":90,"minimum":1},"retention_raw_days":{"type":"integer","format":"int32","description":"How many days of raw (30 s resolution) metric data to keep.","default":7,"example":7,"minimum":1},"scrape_interval_secs":{"type":"integer","format":"int64","description":"How often the MetricsScraper collects data from all sources, in seconds.\nMinimum effective value is 10 s; values below that are clamped at runtime.","default":30,"example":30,"minimum":10},"store":{"oneOf":[{"$ref":"#/components/schemas/MetricsStoreKind","description":"Storage backend for metric data."}],"default":"timescale_db"}}},"MonitoringSettingsMasked":{"type":"object","description":"Monitoring settings with the ClickHouse DSN masked.\n\n`clickhouse_url` can embed credentials (`http://user:pass@host`), so it is\nreported only as a boolean (`clickhouse_url_set`) rather than echoed back —\nconsistent with how the DNS API key and Docker registry password are masked.","required":["enabled","store","scrape_interval_secs","retention_raw_days","retention_hourly_days","retention_daily_years","clickhouse_url_set"],"properties":{"clickhouse_url_set":{"type":"boolean","description":"True when a ClickHouse DSN is configured. The DSN itself is never\nreturned over HTTP because it may contain credentials."},"enabled":{"type":"boolean"},"retention_daily_years":{"type":"integer","format":"int32","minimum":0},"retention_hourly_days":{"type":"integer","format":"int32","minimum":0},"retention_raw_days":{"type":"integer","format":"int32","minimum":0},"scrape_interval_secs":{"type":"integer","format":"int64","minimum":0},"store":{"$ref":"#/components/schemas/MetricsStoreKind"}}},"MrrBucketResponse":{"type":"object","required":["bucket","mrr_minor","charge_total_minor","refund_total_minor","charge_count"],"properties":{"bucket":{"type":"string","format":"date-time"},"charge_count":{"type":"integer","format":"int64"},"charge_total_minor":{"type":"integer","format":"int64"},"mrr_minor":{"type":"integer","format":"int64"},"refund_total_minor":{"type":"integer","format":"int64"}}},"MultiNodeSettings":{"type":"object","description":"Multi-node cluster settings","properties":{"cluster_ca_cert_pem":{"type":["string","null"],"description":"Per-cluster CA certificate (PEM) for multi-node mTLS (ADR-020 WS-2.1).\nPublic — distributed to nodes as the trust root and used by the control\nplane as the root for verifying agent server certs. Minted lazily on the\nfirst CSR-bearing registration.","default":null},"cluster_ca_key_encrypted":{"type":["string","null"],"description":"Per-cluster CA private key, AES-256-GCM ciphertext (EncryptionService).\nSECRET — never returned over HTTP (elided in the masked response).","default":null},"join_token_hash":{"type":["string","null"],"description":"SHA-256 hash of the join token (never store plaintext)","default":null},"legacy_shared_token_enabled":{"type":"boolean","description":"Whether the legacy single shared join token is still accepted for node\nregistration (ADR-020 WS-1.1). Defaults to `true` so existing clusters\nkeep working on upgrade; fresh installs should set it `false` and rely on\nshort-lived, single-use enrollment tokens instead.","default":true},"node_cpu_alert_percent":{"type":["number","null"],"format":"double","description":"CPU-usage percent above which a worker node raises a resource alert\n(ADR-020 / monitoring). `None` disables CPU alerting. Default 90.","default":90.0},"node_disk_alert_percent":{"type":["number","null"],"format":"double","description":"Disk-usage percent above which a worker node raises a resource alert.\n`None` disables disk alerting. Default 90.","default":90.0},"node_memory_alert_percent":{"type":["number","null"],"format":"double","description":"Memory-usage percent above which a worker node raises a resource alert.\n`None` disables memory alerting. Default 90.","default":90.0},"private_address":{"type":["string","null"],"description":"Private/WireGuard IP address of the control plane node.\nUsed by remote worker nodes to reach services (databases, etc.) running on the control plane.\nSet via `--private-address` or `TEMPS_PRIVATE_ADDRESS`.","default":null},"require_mtls":{"type":"boolean","description":"Whether to enforce multi-node mTLS (ADR-020 WS-2.1). When `false`\n(default), the control plane ignores join-time CSRs and nodes keep\nserving plaintext HTTP — zero behavior change. When `true`, the CP signs\nnode CSRs, nodes serve mutual TLS, and every CP→agent call uses the\ncluster client cert. Observe-then-enforce: flip this on only once all\nworkers have re-enrolled with certs.","default":false}}},"MultiNodeSettingsMasked":{"type":"object","description":"Multi-node settings with `join_token_hash` elided.","required":["has_join_token","require_mtls","legacy_shared_token_enabled"],"properties":{"cluster_ca_fingerprint":{"type":["string","null"],"description":"SHA-256 fingerprint of the cluster CA certificate (public — operators can\nverify it out of band; the CA private key is never exposed)."},"has_join_token":{"type":"boolean"},"legacy_shared_token_enabled":{"type":"boolean","description":"Whether the deprecated shared join token is still accepted."},"node_cpu_alert_percent":{"type":["number","null"],"format":"double","description":"Node resource-alert thresholds (percent); `None` = that alert disabled."},"node_disk_alert_percent":{"type":["number","null"],"format":"double"},"node_memory_alert_percent":{"type":["number","null"],"format":"double"},"private_address":{"type":["string","null"]},"require_mtls":{"type":"boolean","description":"Whether control-plane↔agent mutual TLS is enforced."}}},"MxResult":{"type":"object","description":"MX (Mail Exchange) validation result","required":["accepts_mail","records"],"properties":{"accepts_mail":{"type":"boolean","description":"Whether the domain accepts mail"},"error":{"type":["string","null"],"description":"Error message if MX lookup failed"},"records":{"type":"array","items":{"type":"string"},"description":"List of MX records for the domain","example":["alt1.gmail-smtp-in.l.google.com.","gmail-smtp-in.l.google.com."]}}},"NavEntry":{"type":"object","description":"A navigation entry that the plugin contributes to the Temps UI.","required":["label","icon","section","path","order"],"properties":{"icon":{"type":"string","description":"Lucide icon name (e.g., \"puzzle\", \"database\", \"activity\")"},"label":{"type":"string","description":"Display label in the sidebar"},"order":{"type":"integer","format":"int32","description":"Sort order within the section (lower = higher in list)","minimum":0},"path":{"type":"string","description":"Client-side route path (e.g., \"/my-plugin\")"},"section":{"$ref":"#/components/schemas/NavSection","description":"Which sidebar section this entry belongs to"}}},"NavSection":{"type":"string","description":"Where the plugin's nav entry appears in the Temps UI sidebar.","enum":["platform","settings","project"]},"NetworkConfiguration":{"type":"object","description":"Network configuration","required":["mode","dns_servers"],"properties":{"dns_servers":{"type":"array","items":{"type":"string"},"description":"DNS servers"},"hostname":{"type":["string","null"],"description":"Hostname"},"mode":{"$ref":"#/components/schemas/NetworkMode","description":"Network mode"}}},"NetworkMode":{"oneOf":[{"type":"string","enum":["bridge"]},{"type":"string","enum":["host"]},{"type":"string","enum":["none"]},{"type":"object","required":["custom"],"properties":{"custom":{"type":"string"}}}],"description":"Network mode"},"NixpacksPresetConfig":{"type":"object","description":"Configuration for Nixpacks preset\nNixpacks provider and inline build-plan configuration.","properties":{"nixpacksConfig":{"type":["string","null"],"description":"Optional inline nixpacks.toml contents."},"providers":{"type":"array","items":{"$ref":"#/components/schemas/NixpacksProvider"},"description":"Ordered Nixpacks providers. Empty means repository config or auto-detect;\ninclude `...` to combine auto-detection with explicit providers."}}},"NixpacksProvider":{"type":"string","description":"A Nixpacks build provider.\n\n`Auto` serializes as the native Nixpacks `...` marker, which includes the\nprovider detected from the project alongside any explicitly listed\nproviders.","enum":["...","node","python","rust","go","java","php","ruby","deno","elixir","csharp","fsharp","dart","swift","zig","scala","haskell","clojure","crystal","cobol","gleam","lunatic","scheme","static"]},"NodeContainerListResponse":{"type":"object","required":["containers","total"],"properties":{"containers":{"type":"array","items":{"$ref":"#/components/schemas/NodeContainerResponse"}},"total":{"type":"integer","minimum":0}}},"NodeContainerResponse":{"type":"object","description":"A container running on a specific node, enriched with project/environment context.","required":["container_id","container_name","image_name","status","created_at","deployment_id","project_id","project_name","environment_id","environment_name"],"properties":{"container_id":{"type":"string"},"container_name":{"type":"string"},"created_at":{"type":"string"},"deployment_id":{"type":"integer","format":"int32"},"environment_id":{"type":"integer","format":"int32"},"environment_name":{"type":"string"},"image_name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"project_name":{"type":"string"},"status":{"type":"string"}}},"NodeCostInfo":{"type":"object","description":"One cluster node with capacity and (when priceable) a cost estimate","required":["name","cpu_millis","memory_mb"],"properties":{"cpu_millis":{"type":"integer","format":"int64","description":"CPU capacity in millicores"},"instance_type":{"type":["string","null"],"description":"Instance type from `node.kubernetes.io/instance-type` (e.g. \"m5.xlarge\")"},"memory_mb":{"type":"integer","format":"int64","description":"Memory capacity in MB"},"monthly_usd":{"type":["number","null"],"format":"double","description":"Estimated on-demand monthly price in USD. `None` when the instance\ntype is unknown or not in the price table."},"name":{"type":"string","description":"Node name"},"region":{"type":["string","null"],"description":"Region from `topology.kubernetes.io/region`"}}},"NodeInfoResponse":{"type":"object","required":["id","name","address","private_address","role","status","labels","capacity","created_at"],"properties":{"address":{"type":"string"},"architecture":{"type":["string","null"],"description":"Container platform this node runs (`linux/amd64`, `linux/arm64`).\n`None` until an agent that reports it has heartbeated."},"capacity":{"description":"Resource capacity/usage metrics from the latest heartbeat"},"created_at":{"type":"string"},"id":{"type":"integer","format":"int32"},"labels":{},"last_heartbeat":{"type":["string","null"]},"name":{"type":"string"},"private_address":{"type":"string"},"role":{"type":"string"},"status":{"type":"string"}}},"NodeListResponse":{"type":"object","required":["nodes","total"],"properties":{"nodes":{"type":"array","items":{"$ref":"#/components/schemas/NodeInfoResponse"}},"total":{"type":"integer","minimum":0}}},"NotificationPreferencesResponse":{"type":"object","required":["email_enabled","slack_enabled","batch_similar_notifications","minimum_severity","deployment_failures_enabled","build_errors_enabled","runtime_errors_enabled","error_threshold","error_time_window","ssl_expiration_enabled","ssl_days_before_expiration","domain_expiration_enabled","dns_changes_enabled","backup_failures_enabled","backup_successes_enabled","s3_connection_issues_enabled","retention_policy_violations_enabled","route_downtime_enabled","load_balancer_issues_enabled","weekly_digest_enabled","digest_send_day","digest_send_time","digest_sections"],"properties":{"backup_failures_enabled":{"type":"boolean"},"backup_successes_enabled":{"type":"boolean"},"batch_similar_notifications":{"type":"boolean"},"build_errors_enabled":{"type":"boolean"},"deployment_failures_enabled":{"type":"boolean"},"digest_sections":{"$ref":"#/components/schemas/DigestSections"},"digest_send_day":{"type":"string"},"digest_send_time":{"type":"string"},"dns_changes_enabled":{"type":"boolean"},"domain_expiration_enabled":{"type":"boolean"},"email_enabled":{"type":"boolean"},"error_threshold":{"type":"integer","format":"int32"},"error_time_window":{"type":"integer","format":"int32"},"load_balancer_issues_enabled":{"type":"boolean"},"minimum_severity":{"type":"string"},"retention_policy_violations_enabled":{"type":"boolean"},"route_downtime_enabled":{"type":"boolean"},"runtime_errors_enabled":{"type":"boolean"},"s3_connection_issues_enabled":{"type":"boolean"},"slack_enabled":{"type":"boolean"},"ssl_days_before_expiration":{"type":"integer","format":"int32"},"ssl_expiration_enabled":{"type":"boolean"},"weekly_digest_enabled":{"type":"boolean"}}},"NotificationProviderResponse":{"type":"object","required":["id","name","provider_type","config","enabled","created_at","updated_at"],"properties":{"config":{},"created_at":{"type":"integer","format":"int64"},"enabled":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"provider_type":{"type":"string"},"updated_at":{"type":"integer","format":"int64"}}},"ObservabilityCompressionSettings":{"type":"object","description":"TimescaleDB compression policy configuration for append-only observability\ntables. Values are expressed in hours so operators can choose sub-day\nwindows while keeping the API representation unambiguous.","properties":{"otel_spans_after_hours":{"type":"integer","format":"int32","description":"Compress OpenTelemetry span chunks after this many hours. Defaults to\n24 hours.","default":24,"example":24,"maximum":2160,"minimum":1},"proxy_logs_after_hours":{"type":"integer","format":"int32","description":"Compress proxy-log chunks after this many hours. Defaults to 24 hours.","default":24,"example":24,"maximum":720,"minimum":1}}},"ObservabilityEvent":{"oneOf":[{"allOf":[{"$ref":"#/components/schemas/RequestRow"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["request"]}}}]},{"allOf":[{"$ref":"#/components/schemas/SpanRow"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["span"]}}}]},{"allOf":[{"$ref":"#/components/schemas/ErrorRow"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["error"]}}}]},{"allOf":[{"$ref":"#/components/schemas/RevenueRow"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["revenue"]}}}]}],"description":"Discriminated union of every row that can appear in the Observe list.\n\nSerializes to `{ \"type\": \"request\" | \"span\" | ... , ...rest }` so the UI\ncan switch on `event.type` without ambiguity.\n\n**No `Log` variant**: runtime stdout/stderr lines live on a dedicated\nLogs page rather than Observe. Logs are too high-volume to interleave\nwith business signals (requests, errors, revenue) without dominating\nthe timeline, and they have their own retention/storage constraints\n(TimescaleDB hypertable + chunked file/S3 store) that don't compose\nwith the merge service's per-kind LIMIT strategy."},"ObservabilityRetentionSettings":{"type":"object","description":"Retention policy configuration for raw observability tables. Values are in\ndays. The Settings API applies them to TimescaleDB; ClickHouse-backed proxy\nlogs and spans retain their storage-level per-row TTL behavior.","properties":{"otel_logs_days":{"type":"integer","format":"int32","description":"Retain OpenTelemetry log events for this many days.","default":90,"example":90,"maximum":3650,"minimum":1},"otel_metrics_days":{"type":"integer","format":"int32","description":"Retain OpenTelemetry metric points for this many days.","default":90,"example":90,"maximum":3650,"minimum":1},"otel_spans_days":{"type":"integer","format":"int32","description":"Retain OpenTelemetry spans (traces) for this many days.","default":90,"example":90,"maximum":3650,"minimum":1},"proxy_logs_days":{"type":"integer","format":"int32","description":"Retain proxy request logs for this many days.","default":30,"example":30,"maximum":3650,"minimum":1}}},"OidcProviderResponse":{"type":"object","required":["id","name","issuer_url","client_id","client_secret","scopes","jit_provisioning","enabled","template","group_claim","role_claim","default_role","trust_idp_email"],"properties":{"client_id":{"type":"string"},"client_secret":{"type":"string","description":"Always masked — the secret is never returned after creation."},"default_role":{"type":"string"},"enabled":{"type":"boolean"},"group_claim":{"type":"string"},"id":{"type":"integer","format":"int32"},"issuer_url":{"type":"string"},"jit_provisioning":{"type":"boolean"},"name":{"type":"string"},"role_claim":{"type":"string"},"scopes":{"type":"string"},"template":{"type":"string"},"trust_idp_email":{"type":"boolean","description":"When true, the resolver skips the `email_verified` claim gate\nduring SSO login. Only safe for IdPs where an admin controls\nuser provisioning — see `oidc_providers::Model::trust_idp_email`."}}},"OidcProviderSummary":{"type":"object","required":["slug","name","template"],"properties":{"name":{"type":"string"},"slug":{"type":"string","description":"Stable opaque slug — use this as the path parameter when initiating\nOIDC login (`/auth/oidc/login/{slug}`). The integer database ID is\nintentionally omitted from this public endpoint to prevent provider\nenumeration."},"template":{"type":"string","description":"The template the provider was created from — e.g. `keycloak`,\n`okta`, `auth0`, `google`, `azure-ad`, or `generic`. Surfaced on\nthe public login endpoint so the unauthenticated login page can\nrender the right brand logo on the \"Sign in with X\" button.\nNever sensitive — the template name is part of the provider's\npublic identity, not configuration."}}},"OidcProviderUserResponse":{"type":"object","description":"A user that has logged in via a given OIDC provider. Used by the\nadmin \"Users for provider\" panel — the `oidc_subject` is the\nIdP-side identifier we matched on, useful when diagnosing why a\nuser can or can't log in.","required":["id","name","email","email_verified","mfa_enabled","created_at","updated_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2024-01-15T14:30:00Z"},"email":{"type":"string"},"email_verified":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"mfa_enabled":{"type":"boolean"},"name":{"type":"string"},"oidc_subject":{"type":["string","null"]},"updated_at":{"type":"string","format":"date-time","example":"2024-01-15T14:30:00Z"}}},"OidcProvidersListResponse":{"type":"object","required":["providers"],"properties":{"providers":{"type":"array","items":{"$ref":"#/components/schemas/OidcProviderSummary"}}}},"OidcRoleMappingResponse":{"type":"object","required":["id","provider_id","priority","idp_group","role"],"properties":{"id":{"type":"integer","format":"int32"},"idp_group":{"type":"string"},"priority":{"type":"integer","format":"int32"},"provider_id":{"type":"integer","format":"int32"},"role":{"type":"string"}}},"OidcTestConnectionResponse":{"type":"object","required":["success","message"],"properties":{"message":{"type":"string"},"success":{"type":"boolean"}}},"OnDemandCertAttemptResponse":{"type":"object","description":"A single on-demand HTTP-01 issuance attempt from the append-only\n`on_demand_cert_attempts` audit log. Carries the full forensic detail for one\nattempt; the current cert state lives on the enclosing row's domain fields.\n\nContains no private-key or certificate material — only audit metadata — so it\nis safe to return without masking.","required":["id","hostname","trigger","outcome","created_at"],"properties":{"acme_request_sent":{"type":["boolean","null"],"description":"Did we reach the Let's Encrypt API?"},"acme_response_status":{"type":["string","null"],"description":"HTTP status or ACME error type returned by Let's Encrypt, when known."},"challenge_served":{"type":["boolean","null"],"description":"Did the proxy serve the `/.well-known/acme-challenge/` request?"},"created_at":{"type":"integer","format":"int64","description":"When the attempt was recorded (epoch millis)."},"duration_ms":{"type":["integer","null"],"format":"int32","description":"End-to-end issuance duration in milliseconds (0/None for skipped)."},"error_category":{"type":["string","null"],"description":"Coarse error category for UI labelling: `\"rate_limited\"`, `\"dns_failure\"`,\n`\"acme_order_expired\"`, `\"challenge_mismatch\"`, `\"timeout\"`, `\"internal\"`."},"error_chain":{"type":["string","null"],"description":"Full `Display` chain of the error (all `source()` levels), when failed."},"hostname":{"type":"string","description":"SNI hostname that triggered the attempt."},"id":{"type":"integer","format":"int32"},"outcome":{"type":"string","description":"Final outcome: `\"issued\"`, `\"failed\"`, `\"skipped_duplicate\"`,\n`\"skipped_gate\"`, `\"skipped_rate_limit\"`, or `\"skipped_no_route\"`."},"trigger":{"type":"string","description":"What triggered the attempt (always `\"tls_callback\"` today)."}}},"OnDemandCertRow":{"type":"object","description":"One row of the on-demand certificates list: the most-recent attempt for a\nhostname plus the current authoritative cert state from its `domains` row.","required":["hostname","attempt"],"properties":{"attempt":{"$ref":"#/components/schemas/OnDemandCertAttemptResponse","description":"The audit record for the attempt this row represents (newest first in\nthe list)."},"backoff_until":{"type":["integer","null"],"format":"int64","description":"On-demand negative-cache deadline (epoch millis), when in backoff."},"expiration_time":{"type":["integer","null"],"format":"int64","description":"Certificate expiration (epoch millis), when an active cert exists."},"hostname":{"type":"string","description":"SNI hostname."},"status":{"type":["string","null"],"description":"Current cert lifecycle status from the `domains` row, when one exists:\n`on_demand_pending`, `on_demand_issuing`, `active`, `on_demand_failed`,\netc. `None` when no `domains` row exists yet for this hostname."}}},"OnDemandTlsSettings":{"type":"object","description":"On-demand (lazy) HTTP-01 TLS issuance settings (ADR-018).\n\nWhen `enabled`, the proxy's `certificate_callback` triggers ACME HTTP-01\nissuance for allowlisted, STABLE hostnames (per-environment aliases and the\nconsole host) that have no active cert, rather than silently failing the\nhandshake. Ephemeral per-deployment hostnames are NEVER certed (ADR §2).\n\nOff by default — operators opt in explicitly, except QuickStart (`sslip.io`)\ninstalls where `temps setup` auto-enables it and derives `zone`.","properties":{"deployment_url_mode":{"type":"string","description":"How ephemeral per-deployment hostnames behave when they have no cert\n(they are NEVER certed — see ADR §2). One of:\n - `\"http\"` (default): serve plain HTTP on :80.\n - `\"redirect_to_env\"`: 308-redirect to the stable per-environment URL,\n which IS certed.","default":"http","example":"http"},"enabled":{"type":"boolean","description":"Master switch. When `false` (default) the proxy's on-demand cert gate\nrejects every SNI and no issuance is ever triggered.","default":false,"example":false},"hourly_cap":{"type":"integer","format":"int32","description":"Global cap on total on-demand issuances per hour across all hostnames\n(ADR §4 Layer 3). The operator's self-imposed safety net, separate from\nthe Let's Encrypt rate limit.","default":10,"example":10,"minimum":1},"max_concurrent":{"type":"integer","format":"int32","description":"Maximum number of ACME issuance flows allowed to run simultaneously\n(the concurrent-issuance semaphore, ADR §4 Layer 1). Min 1.","default":3,"example":3,"minimum":1},"zone":{"type":["string","null"],"description":"Zone suffix for the allowlist gate. A hostname passes the gate only if\nit is a direct subdomain of this zone (e.g. zone `1.2.3.4.sslip.io`\nadmits `myapp.1.2.3.4.sslip.io` but not `deep.sub.1.2.3.4.sslip.io`).\n`None` (default) means \"auto-derive from `external_url`\"; if no zone can\nbe derived the gate rejects all SNI, disabling the feature.","default":null,"example":"1.2.3.4.sslip.io"}}},"OpenAiError":{"type":"object","required":["message","type"],"properties":{"code":{"type":["string","null"]},"message":{"type":"string"},"type":{"type":"string"}}},"OpenAiErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"$ref":"#/components/schemas/OpenAiError"}}},"OperatingSystemCount":{"type":"object","required":["operating_system","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"operating_system":{"type":"string"},"percentage":{"type":"number","format":"double"}}},"OperationResultResponse":{"type":"object","required":["operation","success","message","executed_at"],"properties":{"data":{},"executed_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"message":{"type":"string"},"operation":{"type":"string"},"success":{"type":"boolean"}}},"OperationResultsResponse":{"type":"object","required":["deployment_id","operations"],"properties":{"deployment_id":{"type":"string"},"operations":{"type":"array","items":{"$ref":"#/components/schemas/OperationResultResponse"}}}},"OtelDashboardResponse":{"type":"object","required":["id","project_id","name","layout","created_at","updated_at"],"properties":{"created_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"id":{"type":"integer","format":"int32"},"layout":{"$ref":"#/components/schemas/DashboardLayout"},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"updated_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"}}},"OtelDashboardsResponse":{"type":"object","required":["data","total"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/OtelDashboardResponse"}},"total":{"type":"integer","format":"int64","minimum":0}}},"OtelMetricAlertRuleResponse":{"type":"object","required":["id","project_id","name","metric_name","aggregation","detection_kind","detection_config","window_secs","for_duration_secs","severity","enabled","last_state","label_filters","group_by","dynamic_alerts","max_series","grouped_notification_threshold","last_dropped_series_count","series_states","created_at","updated_at"],"properties":{"aggregation":{"type":"string"},"created_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"detection_config":{"$ref":"#/components/schemas/DetectionConfig","description":"The typed detector definition (discriminated union keyed by `kind`)."},"detection_kind":{"type":"string","description":"Coarse detector discriminator: `static|anomaly|forecast|outlier|auto_watch`."},"dynamic_alerts":{"type":"boolean","description":"Whether per-series (\"dynamic\") alerting is enabled for this rule."},"enabled":{"type":"boolean"},"firing_series":{"type":"array","items":{"$ref":"#/components/schemas/FiringSeriesEntry"},"description":"Currently-firing series for a dynamic rule, snapshotted from the evaluator's\nin-memory firing map at read time. Empty for static/aggregate rules or when\nnothing is firing."},"for_duration_secs":{"type":"integer","format":"int32"},"group_by":{"type":"array","items":{"type":"string"},"description":"Label keys the rule breaks the metric down by. Empty = one aggregate stream."},"grouped_notification_threshold":{"type":"integer","format":"int32","description":"Notification-grouping threshold: when more than this many series fire in the\nsame tick, only the first gets chart/AI enrichment (1–1000)."},"id":{"type":"integer","format":"int32"},"label_filters":{"type":"array","items":{"type":"array","items":false,"prefixItems":[{"type":"string"},{"type":"string"}]},"description":"AND-combined label equality filters applied when evaluating this rule.\nEmpty = no filtering (matches all series)."},"last_dropped_series_count":{"type":"integer","format":"int32","description":"Number of series dropped by the cardinality cap on the latest dynamic tick\n(0 when nothing was dropped or for static/aggregate rules). Lets a UI warn\n\"N series were dropped this tick\" without reading server logs."},"last_evaluated_at":{"type":["string","null"],"example":"2025-10-12T12:15:47.609192Z"},"last_state":{"type":"string","description":"One of `ok|firing|unknown`."},"last_value":{"type":["number","null"],"format":"double"},"max_series":{"type":"integer","format":"int32","description":"Cardinality cap for dynamic alerting (1–100)."},"metric_name":{"type":"string"},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"series_states":{"type":"object","description":"Full per-series state snapshot persisted after the latest dynamic-rule tick,\nkeyed by the human-readable series label (`endpoint=/checkout`). Empty for\nstatic/aggregate rules. Unlike `firing_series` (a live in-memory snapshot),\nthis is decoded from the persisted `series_states` jsonb column, so an\nexternal consumer that only reads the rule row still sees per-series detail.","additionalProperties":{"$ref":"#/components/schemas/SeriesStateEntry"},"propertyNames":{"type":"string"}},"severity":{"type":"string"},"updated_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"window_secs":{"type":"integer","format":"int32"}}},"OtelMetricAlertsResponse":{"type":"object","required":["data","total"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/OtelMetricAlertRuleResponse"}},"total":{"type":"integer","format":"int64","minimum":0}}},"OtelMetricLabelKeysResponse":{"type":"object","required":["keys"],"properties":{"keys":{"type":"array","items":{"type":"string"}}}},"OtelMetricLabelValuesResponse":{"type":"object","required":["values"],"properties":{"values":{"type":"array","items":{"type":"string"}}}},"OtelMetricNamesResponse":{"type":"object","required":["names"],"properties":{"names":{"type":"array","items":{"type":"string"}}}},"OtelMetricsResponse":{"type":"object","required":["data","count"],"properties":{"count":{"type":"integer","minimum":0},"data":{"type":"array","items":{"$ref":"#/components/schemas/MetricBucket"}}}},"OutlierAlgorithm":{"type":"string","description":"Outlier detection algorithm.","enum":["dbscan","scaled_dbscan","mad","scaled_mad"]},"OutlierParams":{"type":"object","description":"Outlier (cross-series population) detector parameters (stub — not evaluated).","required":["peer_group_key"],"properties":{"algorithm":{"$ref":"#/components/schemas/OutlierAlgorithm"},"peer_group_key":{"type":"string","description":"Label key defining the peer population compared across series (e.g. `host`)."},"tolerance":{"type":"number","format":"double","description":"Sensitivity; higher tolerates larger spread before flagging."}}},"OverprovisioningAssessment":{"type":"object","description":"Requests-vs-capacity-vs-usage assessment","required":["verdict","explanation"],"properties":{"cpu_request_inflation_ratio":{"type":["number","null"],"format":"double","description":"Ratio of requested CPU to measured CPU usage (e.g. 40.0 = requests\nreserve 40× what the workloads actually use). `None` without metrics."},"cpu_requested_pct":{"type":["number","null"],"format":"double","description":"Requested CPU as % of cluster capacity"},"cpu_utilization_pct":{"type":["number","null"],"format":"double","description":"Measured CPU usage as % of cluster capacity (`None` without metrics)"},"explanation":{"type":"string","description":"Human-readable explanation of the verdict, e.g. \"Cluster capacity is\n8 vCPU but measured usage is 0.3 vCPU (3.7%) — severely overprovisioned\""},"memory_request_inflation_ratio":{"type":["number","null"],"format":"double","description":"Ratio of requested memory to measured memory usage"},"memory_requested_pct":{"type":["number","null"],"format":"double","description":"Requested memory as % of cluster capacity"},"memory_utilization_pct":{"type":["number","null"],"format":"double","description":"Measured memory usage as % of cluster capacity (`None` without metrics)"},"verdict":{"$ref":"#/components/schemas/OverprovisioningVerdict","description":"Overall verdict"}}},"OverprovisioningVerdict":{"type":"string","description":"Overall overprovisioning verdict","enum":["severe","moderate","reasonable","unknown"]},"PageActivityBucket":{"type":"object","description":"Time bucket data point for page activity graph","required":["timestamp","visitors","page_views","avg_time_seconds"],"properties":{"avg_time_seconds":{"type":"number","format":"double","description":"Average time on page in seconds"},"page_views":{"type":"integer","format":"int64","description":"Number of page views in this bucket"},"timestamp":{"type":"string","description":"Timestamp for this bucket (ISO 8601)"},"visitors":{"type":"integer","format":"int64","description":"Number of unique visitors in this bucket"}}},"PageCountryStats":{"type":"object","description":"Geographic distribution of visitors for a page","required":["country","visitors","page_views","percentage"],"properties":{"country":{"type":"string","description":"Country name"},"country_code":{"type":["string","null"],"description":"ISO country code (2-letter)"},"page_views":{"type":"integer","format":"int64","description":"Number of page views from this country"},"percentage":{"type":"number","format":"double","description":"Percentage of total visitors"},"visitors":{"type":"integer","format":"int64","description":"Number of unique visitors from this country"}}},"PageFlowEntry":{"type":"object","description":"A single page with its entry/exit/bounce statistics","required":["page_path","entry_count","exit_count","bounce_count","total_views","entry_rate","exit_rate","bounce_rate"],"properties":{"avg_time_on_page":{"type":["number","null"],"format":"double","description":"Average time spent on this page in seconds"},"bounce_count":{"type":"integer","format":"int64","description":"Number of times visitors bounced on this page"},"bounce_rate":{"type":"number","format":"double","description":"Bounce rate: bounce_count / entry_count (only meaningful for entry pages)"},"entry_count":{"type":"integer","format":"int64","description":"Number of times this page was the entry page of a session"},"entry_rate":{"type":"number","format":"double","description":"Entry rate: entry_count / total_views"},"exit_count":{"type":"integer","format":"int64","description":"Number of times this page was the exit page of a session"},"exit_rate":{"type":"number","format":"double","description":"Exit rate: exit_count / total_views"},"page_path":{"type":"string","description":"The page path (e.g. \"/pricing\", \"/docs/getting-started\")"},"total_views":{"type":"integer","format":"int64","description":"Total page views for this page"}}},"PageFlowQuery":{"type":"object","description":"Query parameters for page flow analytics","required":["project_id","start_date","end_date"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32","description":"Maximum number of entry/exit pages to return (default: 20)"},"min_views_for_dropoff":{"type":["integer","null"],"format":"int32","description":"Minimum views for drop-off analysis (default: 5)"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"},"transitions_limit":{"type":["integer","null"],"format":"int32","description":"Maximum number of transitions to return (default: 50)"}}},"PageFlowResponse":{"type":"object","description":"Complete page flow analytics response","required":["top_entry_pages","top_exit_pages","drop_off_points","transitions","total_pages","total_sessions"],"properties":{"drop_off_points":{"type":"array","items":{"$ref":"#/components/schemas/DropOffPoint"},"description":"Top drop-off points (highest exit rates with meaningful traffic)"},"top_entry_pages":{"type":"array","items":{"$ref":"#/components/schemas/PageFlowEntry"},"description":"Top entry pages (where visitors land), sorted by entry_count DESC"},"top_exit_pages":{"type":"array","items":{"$ref":"#/components/schemas/PageFlowEntry"},"description":"Top exit pages (where visitors leave), sorted by exit_count DESC"},"total_pages":{"type":"integer","format":"int64","description":"Total unique pages seen in the period"},"total_sessions":{"type":"integer","format":"int64","description":"Total sessions in the period"},"transitions":{"type":"array","items":{"$ref":"#/components/schemas/PageTransition"},"description":"Page-to-page transitions (most common navigation paths)"}}},"PageHourlySessionsQuery":{"type":"object","description":"Query parameters for page hourly sessions endpoint","required":["page_path","project_id","start_time","end_time"],"properties":{"bucket_interval":{"type":["string","null"]},"end_time":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"page_path":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"start_time":{"type":"string","format":"date-time"}}},"PageHourlySessionsResponse":{"type":"object","required":["page_path","hourly_data","total_sessions","hours"],"properties":{"hourly_data":{"type":"array","items":{"$ref":"#/components/schemas/HourlyPageSessions"}},"hours":{"type":"integer","format":"int32"},"page_path":{"type":"string"},"total_sessions":{"type":"integer","format":"int64"}}},"PagePathDetailQuery":{"type":"object","description":"Query parameters for page path detail analytics","required":["page_path","project_id","start_date","end_date"],"properties":{"bucket_interval":{"type":["string","null"],"description":"Bucket interval for time series: 'hour', 'day', 'week', 'month' (default: auto)"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"page_path":{"type":"string","description":"The specific page path to get details for (URL-encoded)"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"PagePathDetailResponse":{"type":"object","description":"Detailed analytics response for a specific page path","required":["page_path","unique_visitors","total_page_views","avg_time_on_page","bounce_rate","entry_rate","exit_rate","activity_over_time","countries","referrers","bucket_interval"],"properties":{"activity_over_time":{"type":"array","items":{"$ref":"#/components/schemas/PageActivityBucket"},"description":"Time series data for activity graph"},"avg_time_on_page":{"type":"number","format":"double","description":"Average time on page in seconds"},"bounce_rate":{"type":"number","format":"double","description":"Bounce rate percentage (0-100)"},"bucket_interval":{"type":"string","description":"Bucket interval used for time series ('hour', 'day', etc.)"},"countries":{"type":"array","items":{"$ref":"#/components/schemas/PageCountryStats"},"description":"Geographic distribution of visitors"},"entry_rate":{"type":"number","format":"double","description":"Entry rate - percentage of sessions that started on this page"},"exit_rate":{"type":"number","format":"double","description":"Exit rate - percentage of sessions that ended on this page"},"page_path":{"type":"string","description":"The page path being analyzed"},"referrers":{"type":"array","items":{"$ref":"#/components/schemas/PageReferrerStats"},"description":"Top referrers to this page"},"total_page_views":{"type":"integer","format":"int64","description":"Total page views in the date range"},"unique_visitors":{"type":"integer","format":"int64","description":"Total unique visitors to this page in the date range"}}},"PagePathInfo":{"type":"object","required":["page_path","session_count","page_view_count","first_seen","last_seen"],"properties":{"avg_time_seconds":{"type":["number","null"],"format":"double"},"first_seen":{"type":"string"},"last_seen":{"type":"string"},"page_path":{"type":"string"},"page_view_count":{"type":"integer","format":"int64"},"session_count":{"type":"integer","format":"int64"}}},"PagePathSparkline":{"type":"object","required":["page_path","points"],"properties":{"page_path":{"type":"string"},"points":{"type":"array","items":{"$ref":"#/components/schemas/PagePathSparklinePoint"}}}},"PagePathSparklinePoint":{"type":"object","required":["timestamp","session_count"],"properties":{"session_count":{"type":"integer","format":"int64"},"timestamp":{"type":"string"}}},"PagePathVisitorsQuery":{"type":"object","description":"Query parameters for page path visitors","required":["page_path","project_id","start_date","end_date"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"page":{"type":["integer","null"],"format":"int64","description":"Page number (1-based, default: 1)","minimum":0},"page_path":{"type":"string","description":"The specific page path to get visitors for"},"per_page":{"type":["integer","null"],"format":"int64","description":"Items per page (default: 50, max: 100)","minimum":0},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"PagePathVisitorsResponse":{"type":"object","description":"Response for page path visitors endpoint","required":["page_path","total_count","page","per_page","sessions"],"properties":{"page":{"type":"integer","format":"int64","description":"Current page number","minimum":0},"page_path":{"type":"string","description":"The page path"},"per_page":{"type":"integer","format":"int64","description":"Items per page","minimum":0},"sessions":{"type":"array","items":{"$ref":"#/components/schemas/PageVisitorSession"},"description":"Individual visitor sessions"},"total_count":{"type":"integer","format":"int64","description":"Total number of visitor sessions matching the query"}}},"PagePathsQuery":{"type":"object","required":["project_id"],"properties":{"end_date":{"type":["string","null"],"format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":["string","null"],"format":"date-time"}}},"PagePathsResponse":{"type":"object","required":["page_paths","total_count"],"properties":{"page_paths":{"type":"array","items":{"$ref":"#/components/schemas/PagePathInfo"}},"total_count":{"type":"integer","minimum":0}}},"PagePathsSparklineQuery":{"type":"object","description":"Query parameters for batch page paths sparkline endpoint","required":["project_id","start_time","end_time","page_paths"],"properties":{"end_time":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"page_paths":{"type":"string","description":"Comma-separated list of page paths"},"project_id":{"type":"integer","format":"int32"},"start_time":{"type":"string","format":"date-time"}}},"PagePathsSparklineResponse":{"type":"object","required":["sparklines"],"properties":{"sparklines":{"type":"array","items":{"$ref":"#/components/schemas/PagePathSparkline"}}}},"PageReferrerStats":{"type":"object","description":"Referrer source for the page","required":["referrer","visits","percentage"],"properties":{"percentage":{"type":"number","format":"double","description":"Percentage of total visits"},"referrer":{"type":"string","description":"Referrer URL or domain"},"visits":{"type":"integer","format":"int64","description":"Number of visits from this referrer"}}},"PageSessionComparison":{"type":"object","required":["page_path","date","session_count","event_count","avg_duration_seconds"],"properties":{"avg_duration_seconds":{"type":"number","format":"double"},"date":{"type":"string"},"event_count":{"type":"integer","format":"int64"},"page_path":{"type":"string"},"session_count":{"type":"integer","format":"int64"}}},"PageSessionStats":{"type":"object","required":["page_path","total_sessions","avg_time_seconds","min_time_seconds","max_time_seconds","total_page_views","avg_page_views_per_session"],"properties":{"avg_page_views_per_session":{"type":"number","format":"double"},"avg_time_seconds":{"type":"number","format":"double"},"max_time_seconds":{"type":"number","format":"double"},"min_time_seconds":{"type":"number","format":"double"},"page_path":{"type":"string"},"total_page_views":{"type":"integer","format":"int64"},"total_sessions":{"type":"integer","format":"int64"}}},"PageSessionStatsQuery":{"type":"object","required":["page_path","project_id","start_date","end_date"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"page_path":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"PageTransition":{"type":"object","description":"A page-to-page transition with count","required":["from_page","to_page","transition_count","percentage"],"properties":{"from_page":{"type":"string","description":"The source page path"},"percentage":{"type":"number","format":"double","description":"Percentage of transitions from the source page that go to this destination"},"to_page":{"type":"string","description":"The destination page path"},"transition_count":{"type":"integer","format":"int64","description":"Number of times this transition occurred"}}},"PageVisit":{"type":"object","required":["path","visits"],"properties":{"path":{"type":"string"},"visits":{"type":"integer","format":"int64"}}},"PageVisitorSession":{"type":"object","description":"Individual visitor session that viewed a specific page","required":["visitor_id","visitor_uuid","viewed_at","is_entry","is_exit","is_bounce"],"properties":{"browser":{"type":["string","null"],"description":"Browser name"},"city":{"type":["string","null"],"description":"Visitor's city"},"country":{"type":["string","null"],"description":"Visitor's country"},"country_code":{"type":["string","null"],"description":"Visitor's country code"},"device_type":{"type":["string","null"],"description":"Device type (Desktop, Mobile, Tablet)"},"is_bounce":{"type":"boolean","description":"Whether this was a bounce"},"is_entry":{"type":"boolean","description":"Whether this was the entry page for the session"},"is_exit":{"type":"boolean","description":"Whether this was the exit page for the session"},"operating_system":{"type":["string","null"],"description":"Operating system"},"referrer":{"type":["string","null"],"description":"Referrer URL"},"session_id":{"type":["string","null"],"description":"Session ID"},"session_page_number":{"type":["integer","null"],"format":"int32","description":"Page number in session flow"},"time_on_page":{"type":["integer","null"],"format":"int32","description":"Time spent on this page in seconds"},"viewed_at":{"type":"string","format":"date-time","description":"When the page was viewed"},"visitor_id":{"type":"integer","format":"int32","description":"Visitor numeric ID"},"visitor_uuid":{"type":"string","description":"Visitor UUID"}}},"PagesComparisonResponse":{"type":"object","required":["comparisons","page_paths"],"properties":{"comparisons":{"type":"array","items":{"$ref":"#/components/schemas/PageSessionComparison"}},"page_paths":{"type":"array","items":{"type":"string"}}}},"PaginatedEmailsResponse":{"type":"object","required":["data","total","page","page_size"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/EmailResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"PaginatedEntitiesResponse":{"type":"object","required":["entities","count","limit","has_more"],"properties":{"count":{"type":"integer","description":"Number of entities returned","minimum":0},"entities":{"type":"array","items":{"$ref":"#/components/schemas/EntityResponse"},"description":"List of entities"},"has_more":{"type":"boolean","description":"Whether there are more entities available"},"limit":{"type":"integer","description":"Limit used for this request","minimum":0},"next_token":{"type":["string","null"],"description":"Continuation token for next page (S3, etc.)"},"total":{"type":["integer","null"],"description":"Total number of entities (if available)","minimum":0}}},"PaginatedErrorEventsResponse":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ErrorEventResponse"}},"pagination":{"$ref":"#/components/schemas/PaginationMeta"}}},"PaginatedErrorGroupsResponse":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ErrorGroupResponse"}},"pagination":{"$ref":"#/components/schemas/PaginationMeta"}}},"PaginatedEventsResponse":{"type":"object","required":["events","total","page","page_size"],"properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/TrackingEventResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"PaginatedExternalImagesResponse":{"type":"object","required":["data","total","page","page_size"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ExternalImageResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"PaginatedProjectList":{"type":"object","required":["projects","total","page","per_page"],"properties":{"page":{"type":"integer","format":"int64"},"per_page":{"type":"integer","format":"int64"},"projects":{"type":"array","items":{"$ref":"#/components/schemas/ProjectResponse"}},"total":{"type":"integer","format":"int64"}}},"PaginatedStaticBundlesResponse":{"type":"object","required":["data","total","page","page_size"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/StaticBundleResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"Pagination":{"type":"object","description":"SDK pagination cursor. We use opaque page numbers internally but\nexpose `count`/`next`/`prev` the way `@vercel/sandbox` expects.","required":["count"],"properties":{"count":{"type":"integer","format":"int64","minimum":0},"next":{"type":["integer","null"],"format":"int64","minimum":0},"prev":{"type":["integer","null"],"format":"int64","minimum":0}}},"PaginationMeta":{"type":"object","required":["page","page_size","total_count","total_pages"],"properties":{"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total_count":{"type":"integer","format":"int64","minimum":0},"total_pages":{"type":"integer","format":"int64","minimum":0}}},"PaginationParams":{"type":"object","properties":{"page":{"type":"integer","format":"int64"},"per_page":{"type":"integer","format":"int64"}}},"PasswordProtectionConfig":{"type":"object","description":"Password protection configuration\n\nWhen enabled, the proxy shows an HTML password form before allowing access.\nAfter the user enters the correct password, an HMAC-signed cookie is set\nso subsequent requests pass through without re-entering the password.","required":["enabled","passwordHash"],"properties":{"enabled":{"type":"boolean","description":"Whether password protection is enabled"},"passwordHash":{"type":"string","description":"The bcrypt-hashed password (never stored or returned in plaintext)"}}},"PatchSettingsRequest":{"type":"object","properties":{"auto_upgrade":{"type":["boolean","null"]},"host_port":{"type":["integer","null"],"format":"int32","minimum":0},"image":{"type":["string","null"]}}},"PathVisitors":{"type":"object","required":["name","visitors","percentage"],"properties":{"name":{"type":"string"},"percentage":{"type":"number","format":"double"},"visitors":{"type":"integer","format":"int64"}}},"PathVisitorsAnalyticsQuery":{"type":"object","required":["start_date","end_date","project_id"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"PathVisitorsResponse":{"type":"object","required":["results"],"properties":{"results":{"type":"array","items":{"$ref":"#/components/schemas/PathVisitors"}}}},"PeerEntry":{"type":"object","description":"Wire-format peer entry. Matches `temps_network::config::Peer` but\nuses strings on the wire to keep the API stable across underlying\ntype evolution.","required":["node_id","compute_cidr","underlay_address"],"properties":{"compute_cidr":{"type":"string","description":"Per-node CIDR (e.g. `\"172.20.5.0/24\"`)."},"node_id":{"type":"string","description":"Stable v5 UUID derived from the database node id. Workers use\nthis as the kernel-layer identifier when calling\n`NetworkManager::reconcile_peers`."},"underlay_address":{"type":"string","description":"Address the local node should use to reach this peer over the\nunderlay (private VPC IP for same-DC, public IP for cross-DC)."}}},"PeerListResponse":{"type":"object","description":"Response body for `GET /internal/nodes/{node_id}/network/peers`.","required":["peers","cluster_dns_enabled"],"properties":{"alloc":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AllocEntry","description":"Caller's own allocation, or `null` if multi-host networking has\nnot been enabled for this node yet."}]},"cluster_dns_enabled":{"type":"boolean","description":"Whether the cluster-DNS resolver is enabled on this control plane\n(`AppSettings.cluster_dns.enabled`). Workers should start their\nper-node resolver and write `overlay_bridge_address` only when this\nis `true`. Always serialized (never `skip_serializing_if`) so older\nand newer version skew degrades to the safe default of `false`."},"peers":{"type":"array","items":{"$ref":"#/components/schemas/PeerEntry"},"description":"All other nodes with a `compute_cidr` set, excluding the caller."}}},"PendingActionResponse":{"type":"object","description":"A proposed AI write action awaiting human confirmation.","required":["public_id","operation_id","method","summary","status","step_index","params","created_at"],"properties":{"confirmed_at":{"type":["string","null"]},"created_at":{"type":"string"},"error":{"type":["string","null"]},"executed_at":{"type":["string","null"]},"method":{"type":"string"},"operation_id":{"type":"string"},"params":{"description":"The flat params to be replayed at execute time (shown pre-execution for review)."},"plan_public_id":{"type":["string","null"],"description":"Set when this action is one step of a multi-step plan (chained actions);\nall steps of the plan share this id. Absent for standalone single actions."},"public_id":{"type":"string"},"required_permission":{"type":["string","null"]},"result":{},"status":{"type":"string"},"step_index":{"type":"integer","format":"int32","description":"0-based order of this step within its plan (0 for standalone actions)."},"summary":{"type":"string"}}},"PerformanceMetricsQuery":{"allOf":[{"$ref":"#/components/schemas/SpeedSegmentFilters","description":"Segment filters (filter_path, filter_country, filter_region,\nfilter_city, filter_browser, filter_operating_system) — flattened so\neach remains a top-level query string param."},{"type":"object","required":["start_date","end_date","project_id"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"device_type":{"type":["string","null"],"description":"Device type filter: \"desktop\" or \"mobile\""},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"include_bots":{"type":["boolean","null"],"description":"Include crawler/datacenter (bot) samples. Defaults to false — bots\nare excluded from the read view but always stored at ingest."},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}}]},"PerformanceMetricsResponse":{"type":"object","properties":{"cls":{"type":["number","null"],"format":"float"},"cls_p75":{"type":["number","null"],"format":"float"},"cls_p90":{"type":["number","null"],"format":"float"},"cls_p95":{"type":["number","null"],"format":"float"},"cls_p99":{"type":["number","null"],"format":"float"},"fcp":{"type":["number","null"],"format":"float"},"fcp_p75":{"type":["number","null"],"format":"float"},"fcp_p90":{"type":["number","null"],"format":"float"},"fcp_p95":{"type":["number","null"],"format":"float"},"fcp_p99":{"type":["number","null"],"format":"float"},"fid":{"type":["number","null"],"format":"float"},"fid_p75":{"type":["number","null"],"format":"float"},"fid_p90":{"type":["number","null"],"format":"float"},"fid_p95":{"type":["number","null"],"format":"float"},"fid_p99":{"type":["number","null"],"format":"float"},"inp":{"type":["number","null"],"format":"float"},"inp_p75":{"type":["number","null"],"format":"float"},"inp_p90":{"type":["number","null"],"format":"float"},"inp_p95":{"type":["number","null"],"format":"float"},"inp_p99":{"type":["number","null"],"format":"float"},"lcp":{"type":["number","null"],"format":"float"},"lcp_p75":{"type":["number","null"],"format":"float"},"lcp_p90":{"type":["number","null"],"format":"float"},"lcp_p95":{"type":["number","null"],"format":"float"},"lcp_p99":{"type":["number","null"],"format":"float"},"ttfb":{"type":["number","null"],"format":"float"},"ttfb_p75":{"type":["number","null"],"format":"float"},"ttfb_p90":{"type":["number","null"],"format":"float"},"ttfb_p95":{"type":["number","null"],"format":"float"},"ttfb_p99":{"type":["number","null"],"format":"float"}}},"PermissionInfo":{"type":"object","description":"Information about a single permission","required":["name","description","category"],"properties":{"category":{"type":"string","description":"Category of the permission (e.g., \"Projects\", \"Deployments\")"},"description":{"type":"string","description":"Human-readable description of the permission"},"name":{"type":"string","description":"The permission identifier (e.g., \"projects:read\")"}}},"PgUpgradeLogResponse":{"type":"object","required":["log_id","content"],"properties":{"content":{"type":"string"},"log_id":{"type":"string"}}},"PgUpgradeResponse":{"type":"object","required":["id","service_id","from_version","to_version","from_image","to_image","status","phase","log_id","attempt","created_at"],"properties":{"attempt":{"type":"integer","format":"int32"},"created_at":{"type":"string"},"error_message":{"type":["string","null"]},"finished_at":{"type":["string","null"]},"from_image":{"type":"string"},"from_version":{"type":"string"},"id":{"type":"integer","format":"int32"},"log_id":{"type":"string"},"phase":{"type":"string"},"pre_upgrade_backup_id":{"type":["integer","null"],"format":"int32"},"rollback_volume_name":{"type":["string","null"]},"service_id":{"type":"integer","format":"int32"},"started_at":{"type":["string","null"]},"status":{"type":"string"},"to_image":{"type":"string"},"to_version":{"type":"string"}}},"PipelineStats":{"type":"object","description":"Internal pipeline statistics for self-observability.","required":["metrics_received","metrics_stored","metrics_dropped","spans_received","spans_stored","spans_dropped","logs_received","logs_stored_db","logs_stored_s3","logs_dropped","ingest_errors"],"properties":{"ingest_errors":{"type":"integer","format":"int64","minimum":0},"logs_dropped":{"type":"integer","format":"int64","minimum":0},"logs_received":{"type":"integer","format":"int64","minimum":0},"logs_stored_db":{"type":"integer","format":"int64","minimum":0},"logs_stored_s3":{"type":"integer","format":"int64","minimum":0},"metrics_dropped":{"type":"integer","format":"int64","minimum":0},"metrics_received":{"type":"integer","format":"int64","minimum":0},"metrics_stored":{"type":"integer","format":"int64","minimum":0},"spans_dropped":{"type":"integer","format":"int64","minimum":0},"spans_received":{"type":"integer","format":"int64","minimum":0},"spans_stored":{"type":"integer","format":"int64","minimum":0}}},"PipelineStatsResponse":{"type":"object","required":["stats"],"properties":{"stats":{"$ref":"#/components/schemas/PipelineStats"}}},"PlanComplexity":{"type":"string","description":"Plan complexity indicator","enum":["low","medium","high"]},"PlanMetadata":{"type":"object","description":"Plan metadata","required":["generated_at","generator_version","complexity","warnings"],"properties":{"complexity":{"$ref":"#/components/schemas/PlanComplexity","description":"Estimated complexity (low, medium, high)"},"generated_at":{"type":"string","format":"date-time","description":"When the plan was generated"},"generator_version":{"type":"string","description":"Generator (importer) version"},"warnings":{"type":"array","items":{"type":"string"},"description":"Warnings detected during planning"}}},"PlanSourceBackup":{"type":"object","required":["location","location_was_resolved","format"],"properties":{"created_at":{"type":["string","null"]},"format":{"type":"string","description":"\"walg\", \"pg_dump\", \"unknown\"."},"id":{"type":["integer","null"],"format":"int32","description":"DB id, absent for orphan (S3-scan) backups."},"location":{"type":"string","description":"Resolved S3 location the orchestrator will actually use."},"location_was_resolved":{"type":"boolean","description":"True when the original row's `s3_location` was empty and we resolved\na location by probing S3. The UI shows this as a warning."},"origin_service_name":{"type":["string","null"],"description":"Service that originally produced the backup, if known."},"size_bytes":{"type":["integer","null"],"format":"int64"}}},"PlanTarget":{"type":"object","required":["id","name","container"],"properties":{"container":{"type":"string","description":"Expected Docker container name."},"id":{"type":"integer","format":"int32"},"name":{"type":"string"}}},"PlatformInfo":{"type":"object","description":"Platform compatibility information","required":["os_type","architecture","platforms"],"properties":{"architecture":{"type":"string","description":"System architecture (e.g., \"x86_64\", \"aarch64\")"},"os_type":{"type":"string","description":"Operating system type (e.g., \"linux\", \"windows\", \"darwin\")"},"platforms":{"type":"array","items":{"type":"string"},"description":"List of supported platforms in \"os/arch\" format (e.g., [\"linux/amd64\"])"}}},"PluginManifest":{"type":"object","description":"The complete plugin manifest — the handshake contract.","required":["name","version"],"properties":{"description":{"type":["string","null"],"description":"Short description of what the plugin does"},"display_name":{"type":["string","null"],"description":"Human-readable display name"},"events":{"type":"array","items":{"type":"string"},"description":"Platform event types the plugin subscribes to.\n\nWhen specified, Temps will POST matching events to the plugin's\n`/_events` endpoint. Uses dot-notation event names matching the\nwebhook event types (e.g., \"deployment.succeeded\", \"project.created\").\n\nAvailable events:\n- `deployment.created`, `deployment.succeeded`, `deployment.failed`,\n `deployment.cancelled`, `deployment.ready`\n- `project.created`, `project.deleted`\n- `domain.created`, `domain.provisioned`"},"health_path":{"type":"string","description":"Health check endpoint path (relative to plugin root)"},"name":{"type":"string","description":"Unique plugin identifier (kebab-case, e.g., \"backup-manager\")"},"nav":{"type":"array","items":{"$ref":"#/components/schemas/NavEntry"},"description":"Navigation entries for the UI sidebar"},"requires_db":{"type":"boolean","description":"Whether the plugin needs database access"},"ui":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/UiManifest","description":"UI bundle manifest (if the plugin has a UI)"}]},"version":{"type":"string","description":"SemVer version string"}}},"PortMapping":{"type":"object","description":"Port mapping","required":["container_port","protocol","is_primary"],"properties":{"container_port":{"type":"integer","format":"int32","description":"Container port","minimum":0},"host_port":{"type":["integer","null"],"format":"int32","description":"Host port (optional - can be assigned dynamically)","minimum":0},"is_primary":{"type":"boolean","description":"Whether this is the primary HTTP port"},"protocol":{"$ref":"#/components/schemas/Protocol","description":"Protocol (tcp, udp)"}}},"PostgresWalHealth":{"type":"object","required":["probed_at","pg_wal_bytes","max_wal_size_bytes","archive_mode","archive_backlog","stale_slots","oldest_wal_age_secs","warnings"],"properties":{"archive_backlog":{"type":"integer","format":"int64","description":"Number of `archive_status/*.ready` files — un-shipped WAL segments."},"archive_command":{"type":["string","null"],"description":"The literal `archive_command` setting. May be empty or `/bin/true`\nwhen archiving is effectively disabled despite `archive_mode = on`."},"archive_mode":{"$ref":"#/components/schemas/ArchiveMode"},"archiver_failed_count":{"type":["integer","null"],"format":"int64"},"archiver_last_failed_at":{"type":["string","null"],"format":"date-time"},"max_wal_size_bytes":{"type":"integer","format":"int64","description":"`max_wal_size` setting in bytes (parsed from `pg_settings`)."},"oldest_wal_age_secs":{"type":"integer","format":"int64","description":"Age of the oldest WAL file in `pg_wal/` (seconds)."},"pg_wal_bytes":{"type":"integer","format":"int64","description":"Total size of files under `pg_wal/`, from `pg_ls_waldir()`."},"probed_at":{"type":"string","format":"date-time","description":"When the snapshot was taken."},"stale_slots":{"type":"array","items":{"$ref":"#/components/schemas/StaleSlot"}},"warnings":{"type":"array","items":{"$ref":"#/components/schemas/WalWarning"},"description":"Computed warnings, ordered by severity (critical first)."}}},"PresetConfigSchema":{"oneOf":[{"$ref":"#/components/schemas/DockerfilePresetConfig","description":"Configuration for Dockerfile preset"},{"$ref":"#/components/schemas/DockerComposePresetConfig","description":"Configuration for Docker Compose"},{"$ref":"#/components/schemas/NixpacksPresetConfig","description":"Configuration for Nixpacks provider selection and inline build plan"},{"$ref":"#/components/schemas/StaticPresetConfig","description":"Configuration for static site presets (Vite, Next.js, etc.)"}],"description":"Union type for preset configurations\nUse the appropriate configuration type based on your preset"},"PresetInfo":{"type":"object","description":"Detected preset information","required":["path","preset","preset_label","project_type"],"properties":{"compose_files":{"type":["array","null"],"items":{"type":"string"},"description":"Compose file paths found in the repository (only for docker-compose preset)"},"exposed_port":{"type":["integer","null"],"format":"int32","description":"Default exposed port for this preset"},"icon_url":{"type":["string","null"],"description":"Icon URL for this preset"},"path":{"type":"string","description":"Path where preset was detected (empty for root)"},"preset":{"type":"string","description":"Preset slug (e.g., \"nextjs\", \"fastapi\")"},"preset_label":{"type":"string","description":"Human-readable preset label"},"project_type":{"type":"string","description":"Project type (e.g., \"frontend\", \"backend\", \"fullstack\")"}}},"PresetResponse":{"type":"object","required":["slug","label","icon_url","project_type","description"],"properties":{"default_port":{"type":["integer","null"],"format":"int32","description":"Default port the application listens on (None for static sites)","example":3000,"minimum":0},"description":{"type":"string","description":"Description of what this preset does"},"icon_url":{"type":"string","description":"Icon URL for the preset"},"label":{"type":"string","description":"Display name/label for the preset"},"project_type":{"type":"string","description":"Project type (server or static)"},"slug":{"type":"string","description":"Unique identifier slug for the preset"}}},"PreviewGatewaySettings":{"type":"object","description":"Workspace preview gateway settings.\n\nThe preview gateway is a single shared Docker container that lives on the\n`temps-sandbox-net` network and routes requests to workspace sandbox dev\nservers based on the `Host` header (`ws--.`).\n`temps serve` reconciles this container on startup; these settings let an\noperator override the image, host port, and auto-upgrade behavior.","properties":{"auto_upgrade":{"type":"boolean","description":"When true (default), the supervisor will pull and apply the image\npinned in the Temps binary on every startup. When false, the\ncurrently-running image is left alone — operators upgrade manually\nfrom the settings UI.","default":true,"example":true},"host_port":{"type":"integer","format":"int32","description":"Host port to publish the gateway on (always bound to 127.0.0.1).\nPingora forwards `ws-*` traffic to this port after authenticating.","default":8090,"example":8090,"minimum":0},"image":{"type":"string","description":"Docker image reference for the gateway. Pinned per Temps release.\nOperators can override this to test a custom build.","default":"ghcr.io/gotempsh/temps-preview-gateway:latest","example":"ghcr.io/gotempsh/temps-preview-gateway:latest"},"shared_secret":{"type":"string","description":"Shared secret the host-side Pingora sends on every forwarded preview\nrequest via `X-Temps-Preview-Token`; the gateway rejects requests\nwithout it. Auto-generated on first boot, persisted in DB so the\nsecret is stable across `temps serve` restarts regardless of cwd,\n`TEMPS_DATA_DIR`, or data-dir changes. MUST be masked (`***`) in any\nAPI response — never expose it over HTTP.","default":"","example":""}}},"PreviewGatewaySettingsMasked":{"type":"object","description":"Preview gateway settings with `shared_secret` elided.","required":["image","host_port","auto_upgrade","shared_secret_set"],"properties":{"auto_upgrade":{"type":"boolean"},"host_port":{"type":"integer","format":"int32","minimum":0},"image":{"type":"string"},"shared_secret_set":{"type":"boolean"}}},"PreviewGatewaySettingsResponse":{"type":"object","required":["image","host_port","auto_upgrade","default_image","default_host_port"],"properties":{"auto_upgrade":{"type":"boolean"},"default_host_port":{"type":"integer","format":"int32","description":"The compile-time default host port.","minimum":0},"default_image":{"type":"string","description":"The compile-time default image — exposed so the UI can offer a\n\"Reset to default\" link without round-tripping."},"host_port":{"type":"integer","format":"int32","minimum":0},"image":{"type":"string"}}},"PreviewShareLinkBody":{"type":"object","description":"Request body for minting a preview share link.","required":["port"],"properties":{"path":{"type":["string","null"],"description":"Path the recipient lands on. Must be same-origin (start with a single\n`/`); anything else is replaced with `/` so a share link can never be\nturned into an open redirect."},"port":{"type":"integer","format":"int32","description":"Port inside the sandbox the preview serves on.","minimum":0},"ttl_seconds":{"type":["integer","null"],"format":"int64","description":"How long the link stays usable, in seconds. Clamped to 24 hours.\nDefaults to one hour — long enough to send to a reviewer, short enough\nthat a link pasted in a ticket does not stay live indefinitely.","minimum":0}}},"PreviewShareLinkResponse":{"type":"object","required":["url","expires_at"],"properties":{"expires_at":{"type":"integer","format":"int64","description":"Unix seconds after which the link stops working.","minimum":0},"url":{"type":"string","description":"The full link. Its fragment contains the grant and must be treated as a\ncredential; URL fragments are not sent to servers or in Referer headers."}}},"PricingResponse":{"type":"object","required":["models"],"properties":{"models":{"type":"array","items":{"$ref":"#/components/schemas/ModelPricing"}}}},"ProblemDetails":{"type":"object","description":"Representation of a Problem error to return to the client.\nFollows RFC 7807 - Problem Details for HTTP APIs","required":["title","extensions"],"properties":{"detail":{"type":["string","null"],"description":"A human-readable explanation specific to this occurrence of the problem","example":"The server encountered an unexpected condition"},"extensions":{"type":"object","description":"Additional properties of the problem","additionalProperties":true},"instance":{"type":["string","null"],"description":"A URI reference that identifies the specific occurrence of the problem","example":"/account/12345/msgs/abc"},"title":{"type":"string","description":"A short, human-readable summary of the problem type","example":"Internal Server Error"},"type":{"type":["string","null"],"description":"A URI reference that identifies the problem type","example":"https://example.com/probs/out-of-memory"}},"example":{"type":"https://example.com/probs/out-of-memory","title":"Internal Server Error","detail":"The server encountered an unexpected condition","instance":"/account/12345/msgs/abc","additional_info":"Custom field with additional details"}},"ProjectAccessResponse":{"type":"object","required":["id","project_id","team_id","role","granted_by","created_at","updated_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2026-07-30T12:15:47.609192Z"},"granted_by":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"project_id":{"type":"integer","format":"int32"},"role":{"$ref":"#/components/schemas/TeamRole"},"team_id":{"type":"integer","format":"int32"},"updated_at":{"type":"string","format":"date-time","example":"2026-07-30T12:15:47.609192Z"}}},"ProjectConfiguration":{"type":"object","description":"Project-level configuration","required":["name","slug","project_type","is_web_app"],"properties":{"is_web_app":{"type":"boolean","description":"Whether this is a web application"},"name":{"type":"string","description":"Proposed project name"},"project_type":{"$ref":"#/components/schemas/ProjectType","description":"Project type"},"slug":{"type":"string","description":"Proposed slug (URL-safe identifier)"}}},"ProjectDSNResponse":{"type":"object","required":["id","project_id","name","public_key","dsn","created_at","is_active","event_count"],"properties":{"created_at":{"type":"string"},"deployment_id":{"type":["integer","null"],"format":"int32"},"dsn":{"type":"string"},"environment_id":{"type":["integer","null"],"format":"int32"},"event_count":{"type":"integer","format":"int64"},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"public_key":{"type":"string"}}},"ProjectDashboardAnalytics":{"type":"object","description":"Analytics data for a single project in the dashboard batch response","required":["project_id","unique_visitors","previous_unique_visitors","hourly_visits"],"properties":{"hourly_visits":{"type":"array","items":{"$ref":"#/components/schemas/EventTimeline"},"description":"Hourly sparkline data points"},"previous_unique_visitors":{"type":"integer","format":"int64","description":"Unique visitor count in the previous period (same duration, shifted back)"},"project_id":{"type":"integer","format":"int32"},"trend_percentage":{"type":["number","null"],"format":"double","description":"Percentage change from previous period (positive = growth, negative = decline)\nNull when previous period had zero visitors (no baseline to compare)"},"unique_visitors":{"type":"integer","format":"int64","description":"Unique visitor count in the current time range"}}},"ProjectHealthSummary":{"type":"object","description":"Health summary for a single project (last 1 hour)","required":["project_id","total_requests","total_errors","avg_response_time_ms","error_rate","status"],"properties":{"avg_response_time_ms":{"type":"number","format":"double","description":"Average response time in ms"},"error_rate":{"type":"number","format":"double","description":"Error rate as a percentage (0-100)"},"project_id":{"type":"integer","format":"int32"},"status":{"type":"string","description":"Health status: \"healthy\", \"degraded\", \"down\", \"unknown\""},"total_errors":{"type":"integer","format":"int64","description":"Total server errors (status >= 500) in the period"},"total_requests":{"type":"integer","format":"int64","description":"Total requests in the period"}}},"ProjectInfo":{"type":"object","required":["id","slug","created_at"],"properties":{"created_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"id":{"type":"integer","format":"int32"},"slug":{"type":"string"}}},"ProjectMonitorHealth":{"type":"object","description":"Health summary for a single project based on its production monitors","required":["project_id","status"],"properties":{"project_id":{"type":"integer","format":"int32"},"status":{"type":"string","description":"Overall status: \"operational\", \"degraded\", \"down\", or \"no_monitors\""}}},"ProjectPresetResponse":{"type":"object","required":["path","preset","presetLabel","projectType"],"properties":{"composeFiles":{"type":["array","null"],"items":{"type":"string"},"description":"Compose file paths found in the repository (only for docker-compose preset)"},"exposedPort":{"type":["integer","null"],"format":"int32","description":"Default exposed port for this preset (e.g., 3000 for Next.js, 8000 for FastAPI)"},"iconUrl":{"type":["string","null"],"description":"Icon URL for the preset"},"path":{"type":"string"},"preset":{"type":"string"},"presetLabel":{"type":"string"},"projectType":{"type":"string","description":"Project type category (e.g., \"frontend\", \"backend\", \"fullstack\")"}}},"ProjectQuery":{"type":"object","required":["project_id"],"properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"}}},"ProjectRef":{"type":"object","description":"A lightweight project descriptor included in `UnifiedTrace`.","required":["project_id","project_name","project_slug"],"properties":{"project_id":{"type":"integer","format":"int32"},"project_name":{"type":"string"},"project_slug":{"type":"string","description":"URL slug used to link a span back into its owning project's trace view."}}},"ProjectResponse":{"type":"object","required":["id","slug","name","directory","main_branch","created_at","updated_at","deployment_config","attack_mode","ai_write_actions_enabled","error_source_context_enabled","enable_preview_environments","preview_envs_on_demand","preview_envs_idle_timeout_seconds","preview_envs_wake_timeout_seconds","source_type","cross_project_trace_sharing"],"properties":{"ai_alert_summaries_enabled":{"type":["boolean","null"],"description":"Opt-in to AI summarization of metric alert notifications (NULL/false = off)."},"ai_debug_chat_enabled":{"type":["boolean","null"],"description":"Opt-in to AI debugging chat, e.g. on deployment failures (NULL/false = off)."},"ai_write_actions_enabled":{"type":"boolean","description":"Opt-in to AI propose-then-confirm write capability (false = off)."},"attack_mode":{"type":"boolean","description":"Attack mode - when enabled, requires CAPTCHA verification for all project environments"},"created_at":{"type":"integer","format":"int64"},"cross_project_trace_sharing":{"type":"boolean","description":"ADR-027 Phase 3 opt-out: when false, this project's traces are suppressed\nfrom cross-project discovery results. Default true (consistent with the\nOSS global-observability model where any OtelRead holder can query any\nproject's telemetry)."},"deployment_config":{"$ref":"#/components/schemas/DeploymentConfig","description":"Deployment configuration (resources, autoscaling, features)"},"directory":{"type":"string"},"enable_preview_environments":{"type":"boolean","description":"Enable automatic preview environment creation for each branch"},"error_source_context_enabled":{"type":"boolean","description":"Opt-in to native error-tracking source context (false = off). When on,\nTemps stores uploaded source files and shows source code in stack traces."},"error_source_root":{"type":["string","null"],"description":"Where auto-capture reads source from (relative to the checkout). Null =\nthe deployment's Docker build context."},"git_provider_connection_id":{"type":["integer","null"],"format":"int32"},"git_url":{"type":["string","null"],"description":"Git clone URL for the repository (used for public repos without a provider connection)"},"gitlab_webhook_id":{"type":["integer","null"],"format":"int32","description":"GitLab webhook ID installed on the connected repository.\n`null` when no GitLab webhook is installed (not connected to GitLab,\nor webhook was removed / never created).","example":42},"id":{"type":"integer","format":"int32"},"last_deployment":{"type":["integer","null"],"format":"int64"},"main_branch":{"type":"string"},"name":{"type":"string"},"preset":{"type":["string","null"]},"preset_config":{"description":"Preset-specific configuration (Dockerfile path, build context, etc.)"},"preview_envs_idle_timeout_seconds":{"type":"integer","format":"int32","description":"Idle timeout (seconds) for on-demand preview environments."},"preview_envs_on_demand":{"type":"boolean","description":"When true, newly-created preview environments default to on-demand mode\n(containers stop after the configured idle timeout to save resources)."},"preview_envs_wake_timeout_seconds":{"type":"integer","format":"int32","description":"Wake timeout (seconds) for on-demand preview environments."},"repo_name":{"type":["string","null"]},"repo_owner":{"type":["string","null"]},"slug":{"type":"string"},"source_type":{"$ref":"#/components/schemas/SourceType","description":"Source type for deployments (git, docker_image, or static_files)"},"updated_at":{"type":"integer","format":"int64"}}},"ProjectSecretEnvironmentInfo":{"type":"object","required":["id","name","main_url"],"properties":{"id":{"type":"integer","format":"int32"},"main_url":{"type":"string"},"name":{"type":"string"}}},"ProjectSecretResponse":{"type":"object","description":"Project secret metadata. There is deliberately no `value` field — secret\nplaintext is never returned after creation. Callers that need the value\nmust read it from the mounted file inside the container.","required":["id","project_id","key","include_in_preview","created_at","updated_at","environments"],"properties":{"created_at":{"type":"integer","format":"int64"},"environments":{"type":"array","items":{"$ref":"#/components/schemas/ProjectSecretEnvironmentInfo"}},"id":{"type":"integer","format":"int32"},"include_in_preview":{"type":"boolean"},"key":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"updated_at":{"type":"integer","format":"int64"}}},"ProjectServiceInfo":{"type":"object","required":["id","project","service"],"properties":{"id":{"type":"integer","format":"int32"},"project":{"$ref":"#/components/schemas/ProjectInfo"},"service":{"$ref":"#/components/schemas/ExternalServiceInfo"}}},"ProjectStatisticsResponse":{"type":"object","required":["total_count"],"properties":{"total_count":{"type":"integer","format":"int64"}}},"ProjectStatsBreakdown":{"type":"object","required":["project_id","unique_visitors","total_visits","total_page_views","bounce_rate","engagement_rate"],"properties":{"bounce_rate":{"type":"number","format":"double"},"engagement_rate":{"type":"number","format":"double"},"project_id":{"type":"integer","format":"int32"},"project_name":{"type":["string","null"]},"total_page_views":{"type":"integer","format":"int64"},"total_visits":{"type":"integer","format":"int64"},"unique_visitors":{"type":"integer","format":"int64"}}},"ProjectType":{"type":"string","description":"Project type enumeration","enum":["static","docker","buildpack","git"]},"ProjectUsageInfoResponse":{"type":"object","required":["id","name","slug","connection_id","connection_name"],"properties":{"connection_id":{"type":"integer","format":"int32"},"connection_name":{"type":"string"},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"slug":{"type":"string"}}},"ProjectsHealthResponse":{"type":"object","description":"Batch health summary response","required":["projects"],"properties":{"projects":{"type":"object","description":"Health summaries keyed by project ID","additionalProperties":{"$ref":"#/components/schemas/ProjectHealthSummary"},"propertyNames":{"type":"string"}}}},"ProjectsMonitorHealthResponse":{"type":"object","description":"Batch response for projects health","required":["projects"],"properties":{"projects":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/ProjectMonitorHealth"},"propertyNames":{"type":"string"}}}},"PromoteDeploymentRequest":{"type":"object","required":["target_environment_id"],"properties":{"target_environment_id":{"type":"integer","format":"int32","description":"Target environment ID to promote the deployment to"}}},"PropertyBreakdownItem":{"type":"object","required":["value","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"percentage":{"type":"number","format":"double"},"value":{"type":"string"}}},"PropertyBreakdownQuery":{"type":"object","description":"Query parameters for property breakdown (group by column)","required":["start_date","end_date","group_by"],"properties":{"aggregation_level":{"$ref":"#/components/schemas/AggregationLevel","description":"Aggregation level"},"deployment_id":{"type":["integer","null"],"format":"int32","description":"Optional deployment filter"},"end_date":{"type":"string","format":"date-time","description":"End date for the query range"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Optional environment filter"},"event_name":{"type":["string","null"],"description":"Optional event name filter (e.g., \"page_view\", \"click\")"},"filter_browser":{"type":["string","null"],"description":"Filter by browser name (for browser version drill-downs)"},"filter_channel":{"type":["string","null"],"description":"Filter by channel name (for channel -> referrer drill-downs)"},"filter_country":{"type":["string","null"],"description":"Filter by country (for region/city drill-downs). Requires geolocation join."},"filter_os":{"type":["string","null"],"description":"Filter by operating system name (for OS version drill-downs)"},"filter_referrer":{"type":["string","null"],"description":"Filter by referrer hostname (for referrer -> pages drill-downs)"},"filter_region":{"type":["string","null"],"description":"Filter by region (for city drill-downs). Requires geolocation join."},"group_by":{"$ref":"#/components/schemas/PropertyColumn","description":"Property column to group by"},"limit":{"type":["integer","null"],"format":"int32","description":"Maximum number of results to return (default: 20, max: 100)"},"start_date":{"type":"string","format":"date-time","description":"Start date for the query range"}}},"PropertyBreakdownResponse":{"type":"object","required":["property","items","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/PropertyBreakdownItem"}},"property":{"type":"string"},"total":{"type":"integer","format":"int64"}}},"PropertyColumn":{"type":"string","enum":["channel","device_type","browser","browser_version","operating_system","operating_system_version","utm_source","utm_medium","utm_campaign","utm_term","utm_content","referrer_hostname","language","event_type","event_name","page_path","pathname","country","region","city"]},"PropertyTimelineItem":{"type":"object","required":["timestamp","value","count"],"properties":{"count":{"type":"integer","format":"int64"},"timestamp":{"type":"string"},"value":{"type":"string"}}},"PropertyTimelineQuery":{"type":"object","description":"Query parameters for property timeline (group by column over time)","required":["start_date","end_date","group_by"],"properties":{"aggregation_level":{"$ref":"#/components/schemas/AggregationLevel","description":"Aggregation level"},"bucket_size":{"type":["string","null"],"description":"Time bucket size: \"hour\", \"day\", \"week\", \"month\" (default: auto-detect)"},"deployment_id":{"type":["integer","null"],"format":"int32","description":"Optional deployment filter"},"end_date":{"type":"string","format":"date-time","description":"End date for the query range"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Optional environment filter"},"event_name":{"type":["string","null"],"description":"Optional event name filter"},"group_by":{"$ref":"#/components/schemas/PropertyColumn","description":"Property column to group by"},"start_date":{"type":"string","format":"date-time","description":"Start date for the query range"}}},"PropertyTimelineResponse":{"type":"object","required":["property","bucket_size","items"],"properties":{"bucket_size":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/PropertyTimelineItem"}},"property":{"type":"string"}}},"Protocol":{"type":"string","description":"Network protocol","enum":["tcp","udp"]},"ProviderCatalogDto":{"type":"object","description":"One catalog entry rendered for the settings UI.","required":["id","name","install_command","auth_command","auth_flavors","models","credential_saved","supports_max_turns"],"properties":{"auth_command":{"type":"string"},"auth_flavors":{"type":"array","items":{"$ref":"#/components/schemas/AuthFlavorDto"}},"credential_saved":{"type":"boolean","description":"True when a credential is currently saved for this provider in the\nsettings JSON. Lets the UI render \"Configured\" badges without the\nfrontend having to inspect the encrypted blob."},"current_auth_type":{"type":["string","null"],"description":"Currently saved auth flavor id (when `credential_saved` is true).\n`None` when no credential is saved yet."},"default_model":{"type":["string","null"],"description":"Currently saved default model id for this provider, if one was\npicked. `None` means \"use the CLI's own default\" — the UI renders\nthat as \"Use provider default\"."},"id":{"type":"string"},"install_command":{"type":"string"},"max_turns_analysis":{"type":["integer","null"],"format":"int32","description":"Default max turns for the autofixer analysis phase. `None` = built-in\ndefault (10). Only enforced for CLIs with a turn flag (Claude Code)."},"max_turns_feedback":{"type":["integer","null"],"format":"int32","description":"Default max turns for autofixer feedback rounds. `None` = built-in\ndefault (10)."},"max_turns_fix":{"type":["integer","null"],"format":"int32","description":"Default max turns for the autofixer fix phase. `None` = built-in\ndefault (20)."},"models":{"type":"array","items":{"type":"string"},"description":"Model ids this provider accepts, in display order. The first entry is\nthe recommended default. Empty when the provider doesn't expose model\nselection (e.g. OpenCode), which the UI uses to hide the dropdown."},"name":{"type":"string"},"supports_max_turns":{"type":"boolean","description":"True when this provider's CLI supports enforcing a turn cap. False\nfor Codex/OpenCode, which run to completion — the UI labels their\nmax-turns inputs accordingly."}}},"ProviderCatalogResponse":{"type":"object","required":["default_provider","providers"],"properties":{"default_provider":{"type":"string","description":"Active provider id from `agent_sandbox.default_provider`. The settings\nUI uses this to highlight which card is the active one."},"providers":{"type":"array","items":{"$ref":"#/components/schemas/ProviderCatalogDto"}}}},"ProviderConfig":{"oneOf":[{"allOf":[{"$ref":"#/components/schemas/StripeConfig"},{"type":"object","required":["provider"],"properties":{"provider":{"type":"string","enum":["stripe"]}}}]},{"allOf":[{"$ref":"#/components/schemas/LemonSqueezyConfig"},{"type":"object","required":["provider"],"properties":{"provider":{"type":"string","enum":["lemon_squeezy"]}}}]}],"description":"Provider-specific integration settings persisted in\n`revenue_integrations.config`.\n\nThe tag is the lowercase provider name, so adding a new provider\nmeans adding a new variant and the existing rows are untouched.\nOld rows (pre-config) and rows with `NULL` config are treated as\n\"accept all events, no filtering\" via [`ProviderConfig::default_for`]."},"ProviderConfigMasked":{"type":"object","required":["auth_type","credential_saved","extra"],"properties":{"auth_type":{"type":"string"},"credential_saved":{"type":"boolean","description":"True if a credential is stored for this provider. The encrypted blob\nis never returned over HTTP."},"default_model":{"type":["string","null"]},"extra":{}}},"ProviderDeletionCheckResponse":{"type":"object","required":["can_delete","projects_in_use","message"],"properties":{"can_delete":{"type":"boolean"},"message":{"type":"string"},"projects_in_use":{"type":"array","items":{"$ref":"#/components/schemas/ProjectUsageInfoResponse"}}}},"ProviderDescriptor":{"type":"object","required":["name","display_name","recommended_events"],"properties":{"display_name":{"type":"string"},"name":{"type":"string"},"recommended_events":{"type":"array","items":{"type":"string"}}}},"ProviderKeyResponse":{"type":"object","required":["id","provider","display_name","api_key_masked","is_active","created_at","updated_at"],"properties":{"api_key_masked":{"type":"string","description":"Masked API key (only last 4 chars visible)"},"base_url":{"type":["string","null"]},"created_at":{"type":"string"},"default_model":{"type":["string","null"],"description":"Model id this provider serves (NULL → per-provider default)."},"display_name":{"type":"string"},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"provider":{"type":"string"},"updated_at":{"type":"string"}}},"ProviderMetadata":{"type":"object","required":["service_type","display_name","description","icon_url","color"],"properties":{"color":{"type":"string","example":"#336791"},"description":{"type":"string","example":"Relational database management system"},"display_name":{"type":"string","example":"PostgreSQL"},"icon_url":{"type":"string","example":"https://cdn.simpleicons.org/postgresql"},"service_type":{"$ref":"#/components/schemas/ServiceTypeRoute"}}},"ProviderResponse":{"type":"object","required":["id","name","provider_type","auth_method","is_active","is_default","created_at","updated_at"],"properties":{"auth_method":{"type":"string"},"base_url":{"type":["string","null"]},"created_at":{"type":"string","format":"date-time"},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"is_default":{"type":"boolean"},"name":{"type":"string"},"provider_type":{"type":"string"},"updated_at":{"type":"string","format":"date-time"}}},"ProviderUsage":{"type":"object","required":["provider","request_count","input_tokens","output_tokens","avg_latency_ms","error_count"],"properties":{"avg_latency_ms":{"type":"number","format":"double"},"error_count":{"type":"integer","format":"int64"},"input_tokens":{"type":"integer","format":"int64"},"output_tokens":{"type":"integer","format":"int64"},"provider":{"type":"string"},"request_count":{"type":"integer","format":"int64"}}},"ProvisionResponse":{"oneOf":[{"allOf":[{"$ref":"#/components/schemas/DomainError"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["error"]}}}]},{"allOf":[{"$ref":"#/components/schemas/DomainResponse"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["complete"]}}}]},{"allOf":[{"$ref":"#/components/schemas/DomainChallengeResponse"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["pending"]}}}]}]},"ProxyLogResponse":{"type":"object","description":"Response model for proxy logs","required":["id","timestamp","method","path","host","status_code","request_source","is_system_request","routing_status","request_id"],"properties":{"bot_name":{"type":["string","null"]},"browser":{"type":["string","null"]},"browser_version":{"type":["string","null"]},"cache_status":{"type":["string","null"]},"client_ip":{"type":["string","null"]},"container_id":{"type":["string","null"]},"deployment_id":{"type":["integer","null"],"format":"int32"},"device_type":{"type":["string","null"]},"environment_id":{"type":["integer","null"],"format":"int32"},"error_message":{"type":["string","null"]},"host":{"type":"string"},"id":{"type":"integer","format":"int32"},"ip_geolocation_id":{"type":["integer","null"],"format":"int32"},"is_bot":{"type":["boolean","null"]},"is_system_request":{"type":"boolean"},"method":{"type":"string"},"operating_system":{"type":["string","null"]},"path":{"type":"string"},"project_id":{"type":["integer","null"],"format":"int32"},"query_string":{"type":["string","null"]},"referrer":{"type":["string","null"]},"request_id":{"type":"string"},"request_size_bytes":{"type":["integer","null"],"format":"int64"},"request_source":{"type":"string"},"response_size_bytes":{"type":["integer","null"],"format":"int64"},"response_time_ms":{"type":["integer","null"],"format":"int32"},"routing_status":{"type":"string"},"session_id":{"type":["integer","null"],"format":"int32"},"status_code":{"type":"integer","format":"int32"},"timestamp":{"type":"string"},"upstream_host":{"type":["string","null"]},"user_agent":{"type":["string","null"]},"visitor_id":{"type":["integer","null"],"format":"int32"}}},"ProxyLogsPaginatedResponse":{"type":"object","description":"Paginated response for proxy logs","required":["logs","total","page","page_size","total_pages"],"properties":{"logs":{"type":"array","items":{"$ref":"#/components/schemas/ProxyLogResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0},"total_pages":{"type":"integer","format":"int64","minimum":0}}},"PublicHostnameStrategy":{"type":"string","description":"Public hostname generation mode for Temps-managed preview routes.\n\nThe mode is stored per managed domain (`dns_managed_domains.generated_hostname_mode`)\nrather than globally, so a provider such as Cloudflare can offer the flat layout\nrequired by its Universal SSL wildcard cert without changing every domain's behaviour.","enum":["standard","flat"]},"PublicPresetResponse":{"type":"object","description":"Response for preset detection","required":["branch","presets"],"properties":{"branch":{"type":"string","description":"Branch name where presets were detected"},"presets":{"type":"array","items":{"$ref":"#/components/schemas/PresetInfo"},"description":"List of detected presets"}}},"PublicRepositoryInfo":{"type":"object","description":"Public repository information","required":["owner","name","full_name","default_branch","stars","forks"],"properties":{"default_branch":{"type":"string","description":"Default branch name"},"description":{"type":["string","null"],"description":"Repository description"},"forks":{"type":"integer","format":"int32","description":"Fork count"},"full_name":{"type":"string","description":"Full repository name (owner/repo)"},"language":{"type":["string","null"],"description":"Primary programming language"},"name":{"type":"string","description":"Repository name"},"owner":{"type":"string","description":"Repository owner"},"stars":{"type":"integer","format":"int32","description":"Star count"}}},"PurgeLogsRequest":{"type":"object","required":["before"],"properties":{"before":{"type":"string","description":"Delete all logs before this timestamp (ISO 8601)"}}},"PushImageRequest":{"type":"object","description":"Request to push an external image","required":["image_ref"],"properties":{"image_ref":{"type":"string"},"metadata":{}}},"PushedExternalImageResponse":{"type":"object","description":"Response for in-memory external image operations (legacy push flow).\n\nRenamed to avoid shadowing the richer database-backed `ExternalImageResponse`\nin `handlers/remote_deployments.rs`. The two types serve different routes\n(`/images` ephemeral push vs `/external-images` registered images).","required":["id","image_ref","pushed_at"],"properties":{"digest":{"type":["string","null"]},"id":{"type":"string"},"image_ref":{"type":"string"},"pushed_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"size":{"type":["integer","null"],"format":"int64","minimum":0}}},"QueryDataRequest":{"type":"object","properties":{"filters":{"description":"JSON filters (backend-specific format)"},"limit":{"type":"integer","description":"Maximum number of rows to return","example":100,"minimum":0},"offset":{"type":"integer","description":"Number of rows to skip","example":0,"minimum":0},"sort_by":{"type":["string","null"],"description":"Sort by field name"},"sort_order":{"type":["string","null"],"description":"Sort order (asc/desc)"}}},"QueryDataResponse":{"type":"object","required":["fields","rows","total_count","returned_count","execution_time_ms"],"properties":{"execution_time_ms":{"type":"integer","format":"int64","description":"Query execution time in milliseconds","example":45,"minimum":0},"fields":{"type":"array","items":{"$ref":"#/components/schemas/FieldResponse"},"description":"Field definitions"},"returned_count":{"type":"integer","description":"Number of rows returned in this response","example":100,"minimum":0},"rows":{"type":"array","items":{},"description":"Data rows (array of JSON objects)"},"total_count":{"type":"integer","format":"int64","description":"Total number of rows matching the query (before limit/offset)","example":1234,"minimum":0}}},"QuotaResponse":{"type":"object","required":["quota"],"properties":{"quota":{"$ref":"#/components/schemas/StorageQuota"}}},"RateLimitConfig":{"type":"object","description":"Rate limiting configuration (subset of global RateLimitSettings)","properties":{"blacklistIps":{"type":"array","items":{"type":"string"},"description":"Blacklist specific IPs for this project/environment"},"maxRequestsPerHour":{"type":["integer","null"],"format":"int32","description":"Override rate limit per hour","minimum":0},"maxRequestsPerMinute":{"type":["integer","null"],"format":"int32","description":"Override rate limit per minute","minimum":0},"whitelistIps":{"type":"array","items":{"type":"string"},"description":"Whitelist specific IPs for this project/environment"}}},"RateLimitSettings":{"type":"object","properties":{"blacklist_ips":{"type":"array","items":{"type":"string"},"default":[]},"enabled":{"type":"boolean","default":false},"max_requests_per_hour":{"type":"integer","format":"int32","default":1000,"minimum":0},"max_requests_per_minute":{"type":"integer","format":"int32","default":60,"minimum":0},"whitelist_ips":{"type":"array","items":{"type":"string"},"default":[]}}},"ReachabilityStatus":{"type":"string","description":"Email reachability status","enum":["safe","risky","invalid","unknown"]},"ReadFileResponse":{"type":"object","required":["path","contents_b64","size"],"properties":{"contents_b64":{"type":"string","description":"File contents, base64-encoded. Symmetric with `WriteFileBody`."},"path":{"type":"string"},"size":{"type":"integer","format":"int64","minimum":0}}},"RecentActivityQuery":{"type":"object","description":"Query parameters for recent activity endpoint","required":["project_id"],"properties":{"environment_id":{"type":["integer","null"],"format":"int32","description":"Environment ID (optional)"},"limit":{"type":["integer","null"],"format":"int32","description":"Max number of events to return (default: 50, max: 100)"},"project_id":{"type":"integer","format":"int32","description":"Project ID"},"since_id":{"type":["integer","null"],"format":"int64","description":"Return events with ID greater than this (for cursor-based polling)"}}},"RecentActivityResponse":{"type":"object","description":"Response for recent activity events endpoint","required":["events","count"],"properties":{"count":{"type":"integer","description":"Total events returned","minimum":0},"events":{"type":"array","items":{"$ref":"#/components/schemas/ActivityEvent"},"description":"Recent events, newest first"}}},"RecentEventResponse":{"type":"object","required":["occurred_at","event_type"],"properties":{"amount_minor":{"type":["integer","null"],"format":"int64"},"currency":{"type":["string","null"]},"customer_ref":{"type":["string","null"]},"event_type":{"type":"string"},"mrr_minor":{"type":["integer","null"],"format":"int64"},"occurred_at":{"type":"string","format":"date-time"}}},"RecentQueryParams":{"type":"object","properties":{"conversation_id":{"type":["string","null"],"description":"Filter by conversation ID"},"cost_gt":{"type":["integer","null"],"format":"int64","description":"Cost strictly greater-than, in microcents"},"cost_gte":{"type":["integer","null"],"format":"int64","description":"Cost greater-than-or-equal, in microcents"},"cost_lt":{"type":["integer","null"],"format":"int64","description":"Cost strictly less-than, in microcents"},"cost_lte":{"type":["integer","null"],"format":"int64","description":"Cost less-than-or-equal, in microcents"},"limit":{"type":["integer","null"],"format":"int64","description":"Page size (defaults to 20, max 50)","minimum":0},"model":{"type":["string","null"],"description":"Filter by model name"},"offset":{"type":["integer","null"],"format":"int64","description":"Number of results to skip for pagination (defaults to 0)","minimum":0},"provider":{"type":["string","null"],"description":"Filter by provider name"},"status":{"type":["integer","null"],"format":"int32","description":"Filter by HTTP status code (exact match)"},"tags":{"type":["string","null"],"description":"Filter by tags (comma-separated, AND logic)"},"tokens_gt":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) strictly greater-than"},"tokens_gte":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) greater-than-or-equal"},"tokens_lt":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) strictly less-than"},"tokens_lte":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) less-than-or-equal"},"user_id":{"type":["integer","null"],"format":"int32","description":"Filter by user ID"}}},"RecordExposureRequest":{"type":"object","description":"Keys a running app actually evaluated since its last report.","required":["keys"],"properties":{"keys":{"type":"array","items":{"type":"string"},"description":"Flag keys evaluated since the last report. Unknown keys are ignored.","example":["checkout.v2","api.rate_limit"]}}},"RecordExposureResponse":{"type":"object","required":["recorded"],"properties":{"recorded":{"type":"integer","format":"int64","description":"How many keys were accepted for processing.\n\nDeliberately not the number of rows updated: echoing that back would\nlet a caller post a single candidate key and read the result as \"this\nflag exists\", turning the endpoint into an existence oracle.","minimum":0}}},"RecordListResponse":{"type":"object","description":"Record list response","required":["records"],"properties":{"records":{"type":"array","items":{"$ref":"#/components/schemas/DnsRecord"}}}},"RecoveryTarget":{"oneOf":[{"type":"object","description":"Recover to a specific timestamp.","required":["time","kind"],"properties":{"kind":{"type":"string","enum":["time"]},"time":{"type":"string","format":"date-time"}}},{"type":"object","description":"Recover to a specific transaction id (Postgres).","required":["xid","kind"],"properties":{"kind":{"type":"string","enum":["xid"]},"xid":{"type":"string"}}},{"type":"object","description":"Recover to a specific log sequence number (Postgres).","required":["lsn","kind"],"properties":{"kind":{"type":"string","enum":["lsn"]},"lsn":{"type":"string"}}},{"type":"object","description":"Recover to a named restore point created via `pg_create_restore_point` (Postgres).","required":["name","kind"],"properties":{"kind":{"type":"string","enum":["name"]},"name":{"type":"string"}}}],"description":"Engine-specific recovery target for PITR.\n\nPostgres honors all variants; Redis/Mongo/S3 will likely reject non-Time\nvariants or define their own semantics when they grow PITR support."},"ReferrerCount":{"type":"object","required":["referrer","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"percentage":{"type":"number","format":"double"},"referrer":{"type":"string"}}},"ReferrersAnalyticsQuery":{"type":"object","required":["start_date","end_date","project_id"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"RegenerateDSNRequest":{"type":"object","properties":{"base_url":{"type":["string","null"]}}},"RegisterImageRequest":{"type":"object","required":["image_ref"],"properties":{"digest":{"type":["string","null"],"description":"Image digest (sha256:...)","example":"sha256:abc123def456"},"image_ref":{"type":"string","description":"Docker image reference (e.g., \"ghcr.io/org/app:v1.0\")","example":"ghcr.io/myorg/myapp:v1.0"},"metadata":{"description":"Additional metadata"},"tag":{"type":["string","null"],"description":"Image tag","example":"v1.0"}}},"RegisterNodeApiRequest":{"type":"object","required":["name","token","address","private_address"],"properties":{"address":{"type":"string","description":"Node's reachable address (e.g., \"10.100.0.2\" or \"192.168.1.50\")"},"architecture":{"type":["string","null"],"description":"Container platform of this node's Docker daemon (`linux/amd64`,\n`linux/arm64`). Optional: agents older than multi-arch support omit it\nand the value is learned from the first heartbeat instead."},"csr_pem":{"type":["string","null"],"description":"Node-generated certificate signing request (PEM) for multi-node mTLS\n(ADR-020 WS-2.1). When present, the control plane signs it with the\ncluster CA and returns the leaf + CA cert. Optional — token-only nodes\n(legacy / edge) still register without one."},"edge_public_key":{"type":["string","null"],"description":"X25519 public key for ECIES certificate encryption (base64-encoded, edge nodes only)"},"join_token":{"type":["string","null"],"description":"Join token to authorize this registration (must match the token generated in Settings)"},"labels":{"description":"Labels for scheduling (e.g., {\"region\": \"us-east\", \"gpu\": \"true\"})"},"name":{"type":"string","description":"Unique name for this node"},"prior_token":{"type":["string","null"],"description":"The node's *current* token, supplied to prove possession when\nre-registering (changing the identity of) a node that already exists.\nOptional; only needed to rebind a still-live node. (ADR-020 WS-1.2.)"},"private_address":{"type":"string","description":"Private/WireGuard address for inter-node communication"},"public_endpoint":{"type":["string","null"],"description":"Public endpoint for WireGuard (e.g., \"203.0.113.1:51820\")"},"role":{"type":["string","null"],"description":"Node role (default: \"worker\")"},"token":{"type":"string","description":"Registration token (plaintext, will be hashed before storage)"},"wg_public_key":{"type":["string","null"],"description":"WireGuard public key"}}},"RegisterNodeResponse":{"type":"object","required":["id","name","status","message"],"properties":{"ca_cert_pem":{"type":["string","null"],"description":"The cluster CA certificate (PEM) the node pins as its trust root.\nPresent only when a `csr_pem` was supplied. (ADR-020 WS-2.1.)"},"cert_pem":{"type":["string","null"],"description":"The signed per-node leaf certificate (PEM) the agent serves as its TLS\nserver cert. Present only when a `csr_pem` was supplied. (ADR-020 WS-2.1.)"},"id":{"type":"integer","format":"int32"},"message":{"type":"string"},"name":{"type":"string"},"status":{"type":"string"}}},"RegisterRequest":{"type":"object","required":["email","password","name"],"properties":{"email":{"type":"string"},"name":{"type":"string"},"password":{"type":"string"}}},"ReinstallWebhookResponse":{"type":"object","description":"Response for `POST /projects/{project_id}/gitlab/reinstall-webhook`","required":["hook_id","message"],"properties":{"hook_id":{"type":"integer","format":"int32","description":"The new GitLab hook ID that was installed."},"message":{"type":"string","description":"Human-readable status message."}}},"ReleaseListResponse":{"type":"object","required":["releases"],"properties":{"releases":{"type":"array","items":{"type":"string"}}}},"ReloadResponse":{"type":"object","description":"Response from the reload endpoint.","required":["loaded","plugins","message"],"properties":{"loaded":{"type":"integer","description":"Number of plugins successfully loaded after reload","minimum":0},"message":{"type":"string","description":"Human-readable status message"},"plugins":{"type":"array","items":{"type":"string"},"description":"Names of loaded plugins"}}},"RemoteDeploymentResponse":{"type":"object","required":["id","project_id","environment_id","slug","state","source_type","created_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"environment_id":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"project_id":{"type":"integer","format":"int32"},"slug":{"type":"string"},"source_type":{"type":"string"},"state":{"type":"string"}}},"RemoveNodeResponse":{"type":"object","required":["id","message"],"properties":{"id":{"type":"integer","format":"int32"},"message":{"type":"string"}}},"RenameConversationRequest":{"type":"object","required":["title"],"properties":{"title":{"type":"string","description":"New human-facing title. Trimmed; must be non-empty after trimming."}}},"RepositoryListQuery":{"type":"object","properties":{"direction":{"type":["string","null"]},"language":{"type":["string","null"]},"owner":{"type":["string","null"]},"page":{"type":["integer","null"],"format":"int64","minimum":0},"per_page":{"type":["integer","null"],"format":"int64","minimum":0},"private":{"type":["boolean","null"]},"search":{"type":["string","null"]},"sort":{"type":["string","null"]}}},"RepositoryListResponse":{"type":"object","required":["repositories","total_count"],"properties":{"repositories":{"type":"array","items":{"$ref":"#/components/schemas/RepositoryResponse"}},"total_count":{"type":"integer","minimum":0}}},"RepositoryPresetResponse":{"type":"object","required":["repository_id","owner","name","presets","calculated_at"],"properties":{"calculated_at":{"type":"string","format":"date-time"},"name":{"type":"string"},"owner":{"type":"string"},"presets":{"type":"array","items":{"$ref":"#/components/schemas/ProjectPresetResponse"}},"repository_id":{"type":"integer","format":"int32"}}},"RepositoryResponse":{"type":"object","required":["id","owner","name","full_name","private","default_branch","created_at","updated_at","pushed_at","git_provider_connection_id"],"properties":{"clone_url":{"type":["string","null"],"description":"HTTPS clone URL (e.g., https://github.com/owner/repo.git)"},"created_at":{"type":"string","format":"date-time"},"default_branch":{"type":"string"},"description":{"type":["string","null"]},"full_name":{"type":"string"},"git_provider_connection_id":{"type":"integer","format":"int32","description":"ID of the git provider connection this repository was synced from."},"id":{"type":"integer","format":"int32"},"language":{"type":["string","null"]},"name":{"type":"string"},"owner":{"type":"string"},"preset":{"type":["array","null"],"items":{"$ref":"#/components/schemas/ProjectPresetResponse"}},"private":{"type":"boolean"},"pushed_at":{"type":"string","format":"date-time"},"ssh_url":{"type":["string","null"],"description":"SSH clone URL (e.g., git@github.com:owner/repo.git)"},"updated_at":{"type":"string","format":"date-time"}}},"RepositorySyncStartedResponse":{"type":"object","description":"Returned by `POST /git-connections/{id}/sync` to acknowledge that a\nsync has been kicked off in the background. Clients should poll the\nconnection's `syncing` and `synced_repository_count` fields to track\nprogress rather than waiting on this response.","required":["connection_id","syncing","started_at"],"properties":{"connection_id":{"type":"integer","format":"int32"},"started_at":{"type":"string","format":"date-time"},"syncing":{"type":"boolean"}}},"RequestRow":{"type":"object","required":["id","ts","method","host","path","status","request_headers","response_headers","headers_truncated"],"properties":{"client_ip":{"type":["string","null"]},"country":{"type":["string","null"]},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"error_group_id":{"type":["integer","null"],"format":"int32"},"headers_truncated":{"type":"boolean"},"host":{"type":"string"},"id":{"type":"string","description":"The request's unique `request_id` (assigned by the proxy). Used as the\nrow identity instead of the storage PK because the ClickHouse backend\nhas no serial id (rows come back with `id = 0`) while `request_id` is\nunique and present on both backends."},"latency_ms":{"type":["integer","null"],"format":"int32"},"method":{"type":"string"},"path":{"type":"string"},"query_string":{"type":["string","null"]},"referrer":{"type":["string","null"]},"request_headers":{},"response_headers":{},"status":{"type":"integer","format":"int32"},"trace_id":{"type":["string","null"]},"ts":{"type":"string","format":"date-time"},"user_agent":{"type":["string","null"]}}},"ResetPasswordRequest":{"type":"object","required":["token","new_password"],"properties":{"new_password":{"type":"string"},"token":{"type":"string"}}},"ResetPgStatStatementsRequest":{"type":"object","description":"Explicit confirmation required for the destructive statistics reset.\n\nRequiring JSON makes the endpoint non-simple for browsers, preventing a\ndeployed same-site application from triggering it with a plain HTML form.","required":["confirm"],"properties":{"confirm":{"type":"boolean","description":"Must be `true` to acknowledge the global, irreversible reset."}}},"ResetPgStatStatementsResponse":{"type":"object","description":"Response for the pg_stat_statements reset endpoint.","required":["message"],"properties":{"message":{"type":"string","description":"Human-readable message confirming the destructive action."}}},"ResizeSandboxBody":{"type":"object","required":["disk_size_mb"],"properties":{"disk_size_mb":{"type":"integer","format":"int64","description":"New root disk size in MB. Grow-only; must exceed the current size.","minimum":0}},"additionalProperties":false},"ResolvedEnvVarResponse":{"type":"object","description":"One entry in the computed env-var view that merges manual and integration\nsources and tags each result with its origin. `value_preview` is always\nmasked — plaintext must be fetched per-key via the existing reveal endpoint,\nwhich is audit-logged.","required":["key","value_preview","source","environments","include_in_preview"],"properties":{"environments":{"type":"array","items":{"$ref":"#/components/schemas/EnvironmentInfo"},"description":"Environments this var applies to. For integration-sourced vars this\nreflects every environment of the project (integrations are global)."},"include_in_preview":{"type":"boolean","description":"Whether the var would be auto-applied to preview environments.\nIntegration vars always surface in preview; manual vars follow the flag."},"key":{"type":"string"},"source":{"$ref":"#/components/schemas/ResolvedEnvVarSource"},"value_preview":{"type":"string","description":"Masked or truncated preview. Never the raw value."}}},"ResolvedEnvVarSource":{"oneOf":[{"type":"object","description":"Manually-defined env var. If `overrides_service` is set, this key would\notherwise have been supplied by an integration — the UI should show the\nintegration icon plus an \"overridden\" indicator.","required":["var_id","type"],"properties":{"overrides_service":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/EnvVarIntegrationInfo"}]},"type":{"type":"string","enum":["manual"]},"var_id":{"type":"integer","format":"int32"}}},{"type":"object","description":"Supplied by a linked external service (Postgres, Redis, S3, etc.).","required":["service","type"],"properties":{"service":{"$ref":"#/components/schemas/EnvVarIntegrationInfo"},"type":{"type":"string","enum":["integration"]}}}],"description":"Where a resolved env var comes from. Integration-sourced vars may be\n\"shadowed\" by a manual entry with the same key, in which case the response\ncarries `Manual` with `overrides_service` populated so the UI can still show\nthe integration icon."},"ResourceCounts":{"type":"object","description":"Quick count of resources involved in the migration","required":["projects","environments","deployments","environment_variables","services","domains"],"properties":{"deployments":{"type":"integer","minimum":0},"domains":{"type":"integer","minimum":0},"environment_variables":{"type":"integer","minimum":0},"environments":{"type":"integer","minimum":0},"projects":{"type":"integer","minimum":0},"services":{"type":"integer","minimum":0}}},"ResourceFootprint":{"type":"object","description":"A CPU + memory footprint (requests or measured usage)","required":["cpu_millis","memory_mb"],"properties":{"cpu_millis":{"type":"integer","format":"int64","description":"CPU in millicores"},"memory_mb":{"type":"integer","format":"int64","description":"Memory in MB"}}},"ResourceInfo":{"type":"object","description":"Resource attributes extracted from OTel resource descriptors.","required":["service_name","attributes"],"properties":{"attributes":{"type":"object"},"deployment_environment":{"type":["string","null"]},"service_name":{"type":"string"},"service_version":{"type":["string","null"]}}},"ResourceLimitApplyResult":{"type":"object","description":"Per-container outcome of a live `docker update` call. Surfaced from the\nPATCH /resources endpoint so the UI can tell the operator whether the\nnew caps are already in effect or whether they only apply on next\nrecreate (e.g., container was missing).","required":["role","container_name","outcome"],"properties":{"container_name":{"type":"string"},"error":{"type":["string","null"],"description":"Populated only when `outcome == \"failed\"`."},"outcome":{"type":"string","description":"One of:\n- \"applied\" — Docker accepted the update; caps are live now.\n- \"missing\" — container does not exist; caps stored, will apply on next start.\n- \"stopped\" — container exists but isn't running; Docker still\n accepts the update (the new caps apply on next start).\n- \"failed\" — `docker update` returned an error (see `error`)."},"role":{"type":"string","description":"`service_members.role` for cluster members; \"standalone\" otherwise."}}},"ResourceLimits":{"type":"object","description":"Resource limits and requests","properties":{"cpu_limit":{"type":["integer","null"],"format":"int32","description":"CPU limit (millicores)"},"cpu_request":{"type":["integer","null"],"format":"int32","description":"CPU request (millicores)"},"memory_limit":{"type":["integer","null"],"format":"int32","description":"Memory limit (MB)"},"memory_request":{"type":["integer","null"],"format":"int32","description":"Memory request (MB)"}}},"ResourceLimitsResponse":{"type":"object","description":"Container resource limits","properties":{"cpu_limit":{"type":["integer","null"],"format":"int32"},"cpu_request":{"type":["integer","null"],"format":"int32"},"memory_limit":{"type":["integer","null"],"format":"int32"},"memory_request":{"type":["integer","null"],"format":"int32"}}},"ResourceLimitsUpdateResponse":{"type":"object","description":"Response from PATCH /external-services/{id}/resources.","required":["limits","applied"],"properties":{"applied":{"type":"array","items":{"$ref":"#/components/schemas/ResourceLimitApplyResult"},"description":"Per-container result of trying to apply the limits live."},"limits":{"$ref":"#/components/schemas/ServiceResourceLimits","description":"The limits that were persisted to the encrypted config."}}},"ResourcesBody":{"type":"object","description":"Nested `resources: { memory, vcpus }` as sent by `@vercel/sandbox`.\n`memory` is in MB, `vcpus` is fractional CPU count.","properties":{"memory":{"type":["integer","null"],"format":"int64","minimum":0},"vcpus":{"type":["number","null"],"format":"double"}}},"RestoreCapabilities":{"type":"object","description":"Capabilities a service exposes for the generic restore framework.\n\nEach engine overrides `ExternalService::restore_capabilities` to declare\nwhat it supports. The handler layer uses this to validate requests and\nthe UI uses it to conditionally show options (e.g., PITR picker).","required":["restore_in_place","restore_to_new_service","pitr"],"properties":{"earliest_pitr_time":{"type":["string","null"],"format":"date-time","description":"Earliest recoverable timestamp, if `pitr` is true. Derived from\nengine-specific archive metadata (e.g., `pg_stat_archiver`)."},"latest_pitr_time":{"type":["string","null"],"format":"date-time","description":"Latest recoverable timestamp, if `pitr` is true."},"pitr":{"type":"boolean","description":"Point-in-time recovery using engine-specific continuous archives\n(WAL for Postgres, AOF for Redis, oplog for MongoDB, object versions for S3)."},"restore_in_place":{"type":"boolean","description":"Restore a backup onto the same running service (destructive)."},"restore_to_new_service":{"type":"boolean","description":"Restore a backup into a freshly provisioned service."}}},"RestoreCapabilitiesResponse":{"allOf":[{"$ref":"#/components/schemas/RestoreCapabilities","description":"Trait-declared capabilities."},{"type":"object","required":["suggested_new_service_name"],"properties":{"suggested_new_service_name":{"type":"string","description":"Suggested name for the new service when creating a clone. Safe to\npre-fill into the UI dialog; the user can edit before submitting."}}}]},"RestorePlan":{"type":"object","description":"Preview of a restore operation. Answers \"what will happen if I click\nstart?\" with engine-level specificity so the user can confirm before\ncommitting to a destructive action.","required":["engine","target_service","source_backup","strategy","steps","warnings","errors","destructive","mode"],"properties":{"destructive":{"type":"boolean","description":"Whether any step overwrites existing data on the target service."},"engine":{"type":"string","description":"Target engine (\"postgres\", etc.)."},"errors":{"type":"array","items":{"type":"string"},"description":"Blocking problems. The UI disables the Start button when non-empty."},"mode":{"type":"string","description":"Echo of the requested mode for the UI."},"source_backup":{"$ref":"#/components/schemas/PlanSourceBackup","description":"Backup we'll read from."},"steps":{"type":"array","items":{"type":"string"},"description":"Ordered list of human-readable actions the orchestrator will take."},"strategy":{"type":"string","description":"How the restore will be performed: \"walg_restore\", \"pg_dump_restore\",\nor \"unsupported\"."},"target_service":{"$ref":"#/components/schemas/PlanTarget","description":"Service we'll operate on (or provision a sibling of)."},"warnings":{"type":"array","items":{"type":"string"},"description":"Non-blocking caveats the user should see (cross-service, empty\nlocation that will be auto-resolved, missing engine metadata, ...)."}}},"RestoreRequestMode":{"oneOf":[{"type":"object","description":"Restore the backup onto the existing service (destructive).","required":["mode"],"properties":{"mode":{"type":"string","enum":["in_place"]}}},{"type":"object","description":"Provision a new service and restore into it.","required":["name","mode"],"properties":{"mode":{"type":"string","enum":["new_service"]},"name":{"type":"string","description":"Name for the new service. Orchestrator auto-suggests\n`{source}-restore-{yyyymmdd-hhmm}` if caller omits, but we require\nan explicit value at the API boundary."},"parameter_overrides":{"description":"Optional parameter overrides (port, docker_image, database)."}}},{"type":"object","description":"Point-in-time recovery. Only valid on WAL-G backups (Postgres).","required":["to_new_service","target","mode"],"properties":{"mode":{"type":"string","enum":["pitr"]},"new_service_name":{"type":["string","null"],"description":"Required when `to_new_service` is true."},"target":{"$ref":"#/components/schemas/RecoveryTarget","description":"Recovery target kind + value."},"to_new_service":{"type":"boolean","description":"Whether PITR restores in place or creates a new service."}}}],"description":"What the caller wants to do. Mirrors `externalsvc::RestoreMode` but\nflattened for JSON over the wire."},"RestoreRunView":{"type":"object","required":["id","source_backup_id","source_service_id","mode","status","phase","created_at"],"properties":{"created_at":{"type":"string"},"error_message":{"type":["string","null"]},"finished_at":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"mode":{"type":"string"},"phase":{"type":"string"},"recovery_target":{},"source_backup_id":{"type":"integer","format":"int32"},"source_service_id":{"type":"integer","format":"int32"},"started_at":{"type":["string","null"]},"status":{"type":"string"},"target_service_id":{"type":["integer","null"],"format":"int32"},"target_service_name":{"type":["string","null"]}}},"RetentionCleanupFailure":{"type":"object","required":["backup_id","reason","partial","deleted_objects"],"properties":{"backup_id":{"type":"string"},"deleted_objects":{"type":"integer","format":"int64","minimum":0},"partial":{"type":"boolean"},"reason":{"type":"string"}}},"RetentionCleanupReport":{"type":"object","required":["dry_run","expired","deleted","failed","failures","deleted_backup_ids","deleted_backup_ids_truncated","partially_deleted_backup_ids","partially_deleted_backup_ids_truncated","candidate_backup_ids","candidate_backup_ids_truncated"],"properties":{"candidate_backup_ids":{"type":"array","items":{"type":"string"},"description":"Capped sample of backups selected by the retention policy."},"candidate_backup_ids_truncated":{"type":"boolean"},"deleted":{"type":"integer","format":"int64","minimum":0},"deleted_backup_ids":{"type":"array","items":{"type":"string"},"description":"Capped sample of deleted backup UUIDs for audit attribution."},"deleted_backup_ids_truncated":{"type":"boolean"},"dry_run":{"type":"boolean","description":"True when this report is a non-destructive preview."},"expired":{"type":"integer","format":"int64","minimum":0},"failed":{"type":"integer","format":"int64","minimum":0},"failures":{"type":"array","items":{"$ref":"#/components/schemas/RetentionCleanupFailure"},"description":"Capped diagnostic sample; `failed` remains the authoritative total."},"partially_deleted_backup_ids":{"type":"array","items":{"type":"string"}},"partially_deleted_backup_ids_truncated":{"type":"boolean"},"schedule_id":{"type":["integer","null"],"format":"int32","description":"Schedule scope, or `None` when every schedule was considered."}}},"RetryClusterRequest":{"type":"object","description":"Request body for retrying a failed cluster initialization.","properties":{"members":{"type":"array","items":{"$ref":"#/components/schemas/ClusterMemberRequest"},"description":"Cluster member specifications (same format as create).\nIf omitted, the original member configuration is reconstructed from\nthe preserved service_members records."}}},"RevenueRow":{"type":"object","required":["id","ts","provider","event_type"],"properties":{"amount_minor":{"type":["integer","null"],"format":"int64"},"currency":{"type":["string","null"]},"customer_ref":{"type":["string","null"]},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"event_type":{"type":"string"},"id":{"type":"integer","format":"int64"},"provider":{"type":"string"},"trace_id":{"type":["string","null"]},"ts":{"type":"string","format":"date-time"}}},"RiskLevel":{"type":"string","description":"Risk level for a migration step","enum":["none","low","medium","high","critical"]},"RoleInfo":{"type":"object","description":"Information about a role","required":["name","description","permissions"],"properties":{"description":{"type":"string","description":"Human-readable description of the role"},"name":{"type":"string","description":"The role identifier (e.g., \"admin\")"},"permissions":{"type":"array","items":{"type":"string"},"description":"Permissions included in this role"}}},"RootfsCacheEntry":{"type":"object","description":"A cached rootfs image (Firecracker backend). Digest-keyed build artifact\nshared by all VMs created from the same image.","required":["digest","bytes","referenced_by"],"properties":{"bytes":{"type":"integer","format":"int64","description":"Actual on-disk size in bytes (sparse-aware).","minimum":0},"digest":{"type":"string","description":"Image digest this rootfs was built from (the cache key)."},"referenced_by":{"type":"array","items":{"type":"string"},"description":"IDs of live sandboxes whose per-VM disk was cloned from this entry.\nEmpty means the entry is reclaimable — no sandbox needs it."}}},"RootfsGcReport":{"type":"object","description":"Outcome of a rootfs garbage-collection pass.","required":["removed_digests","freed_bytes"],"properties":{"freed_bytes":{"type":"integer","format":"int64","minimum":0},"removed_digests":{"type":"array","items":{"type":"string"},"description":"Digests of cache entries removed because no sandbox referenced them."}}},"RootfsReport":{"type":"object","description":"Snapshot of a backend's rootfs storage for the management API. Backends\nwithout a rootfs concept (Docker, local) return an empty report.","required":["cache_bytes","cache","vm_bytes","vms"],"properties":{"cache":{"type":"array","items":{"$ref":"#/components/schemas/RootfsCacheEntry"}},"cache_bytes":{"type":"integer","format":"int64","minimum":0},"vm_bytes":{"type":"integer","format":"int64","minimum":0},"vms":{"type":"array","items":{"$ref":"#/components/schemas/RootfsVmEntry"}}}},"RootfsVmEntry":{"type":"object","description":"A per-sandbox rootfs disk (Firecracker backend). One per non-destroyed\nsandbox — the authoritative storage, independent of the cache.","required":["sandbox_name","bytes","running"],"properties":{"bytes":{"type":"integer","format":"int64","minimum":0},"running":{"type":"boolean"},"sandbox_name":{"type":"string"}}},"RouteRefreshResponse":{"type":"object","required":["route_count","message"],"properties":{"message":{"type":"string","description":"Human-readable message"},"route_count":{"type":"integer","description":"Number of routes loaded","minimum":0}}},"RouteResponse":{"type":"object","required":["id","domain","host","port","enabled","route_type","created_at","updated_at"],"properties":{"created_at":{"type":"integer","format":"int64"},"domain":{"type":"string"},"enabled":{"type":"boolean"},"host":{"type":"string"},"id":{"type":"integer","format":"int32"},"port":{"type":"integer","format":"int32"},"route_type":{"type":"string","description":"Route type: \"http\" or \"tls\""},"updated_at":{"type":"integer","format":"int64"}}},"RouteRole":{"type":"object","required":["id","name","created_at","updated_at"],"properties":{"created_at":{"type":"integer","format":"int64","example":"1683900000000"},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"updated_at":{"type":"integer","format":"int64","example":"1683900000000"}}},"RouteUser":{"type":"object","required":["id","name","username","email","image","mfa_enabled","email_verified","created_at","updated_at"],"properties":{"created_at":{"type":"integer","format":"int64","example":"1683900000000"},"deleted_at":{"type":["integer","null"],"format":"int64"},"email":{"type":"string"},"email_verified":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"image":{"type":"string"},"mfa_enabled":{"type":"boolean"},"name":{"type":"string"},"updated_at":{"type":"integer","format":"int64","example":"1683900000000"},"username":{"type":"string"}}},"RouteUserWithRoles":{"type":"object","required":["user","roles"],"properties":{"roles":{"type":"array","items":{"$ref":"#/components/schemas/RouteRole"}},"user":{"$ref":"#/components/schemas/RouteUser"}}},"RunBackupRequest":{"type":"object","required":["backup_type"],"properties":{"backup_type":{"type":"string","description":"Type of backup to perform","example":"full"}}},"RunExternalServiceBackupRequest":{"type":"object","properties":{"backup_type":{"type":["string","null"],"description":"Type of backup to perform (e.g., \"full\", \"incremental\")","example":"full"},"s3_source_id":{"type":["integer","null"],"format":"int32","description":"ID of the S3 source to store the backup. If omitted, the current default S3 source is used.","example":1}}},"S3ConnectionTestResponse":{"type":"object","description":"Response body for an S3 connection test.","required":["ok","message"],"properties":{"message":{"type":"string","description":"Human-readable message (success confirmation or error detail)."},"ok":{"type":"boolean","description":"Whether the connection and credentials worked."}}},"S3CredentialsResponse":{"type":"object","description":"S3 credentials distributed to agents for backup/restore operations.","required":["access_key_id","secret_key","region","bucket_name","force_path_style"],"properties":{"access_key_id":{"type":"string"},"bucket_name":{"type":"string"},"endpoint":{"type":["string","null"]},"force_path_style":{"type":"boolean"},"region":{"type":"string"},"secret_key":{"type":"string"}}},"S3SourceResponse":{"type":"object","description":"Response type for S3 source","required":["id","name","bucket_name","bucket_path","access_key_id","secret_key","region","is_default","created_at","updated_at"],"properties":{"access_key_id":{"type":"string","example":"AKIAXXXXXXXXXXXXXXXX"},"bucket_name":{"type":"string"},"bucket_path":{"type":"string"},"created_at":{"type":"integer","format":"int64"},"endpoint":{"type":["string","null"],"example":"http://minio.example.com:9000"},"force_path_style":{"type":["boolean","null"]},"id":{"type":"integer","format":"int32"},"is_default":{"type":"boolean"},"name":{"type":"string"},"region":{"type":"string"},"secret_key":{"type":"string","writeOnly":true},"updated_at":{"type":"integer","format":"int64"}}},"SandboxDomainResponse":{"type":"object","required":["url"],"properties":{"url":{"type":"string"}}},"SandboxEvent":{"type":"object","description":"One entry in a sandbox's operations timeline.","required":["event_type","at"],"properties":{"at":{"type":"integer","format":"int64","description":"Unix epoch milliseconds."},"detail":{"description":"Optional structured context (shape depends on `event_type`)."},"event_type":{"type":"string","description":"Machine-readable operation (`created`, `stopped`, `resumed`,\n`restarted`, `timeout_extended`, `resized`, `preview_password_set`,\n`preview_password_cleared`, `preview_share_link_created`, `source_seeded`,\n`destroyed`)."}}},"SandboxEventsResponse":{"type":"object","required":["events"],"properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/SandboxEvent"}}}},"SandboxInner":{"type":"object","description":"Inner `sandbox` object in `@vercel/sandbox` responses. Strict shape —\nthe SDK's zod validator rejects missing required fields.","required":["id","memory","vcpus","region","runtime","timeout","status","requestedAt","createdAt","updatedAt","cwd","name","preview_url_template"],"properties":{"agent_run_id":{"type":["integer","null"],"format":"int32","description":"Agent run this sandbox executes (autofixer / workflow agent).\n`None` for sandboxes created via this API."},"backend":{"type":["string","null"],"description":"Isolation backend: \"docker\" | \"firecracker\". `None` on legacy rows\ncreated before the backend was recorded."},"createdAt":{"type":"integer","format":"int64"},"cwd":{"type":"string"},"disk_size_mb":{"type":["integer","null"],"format":"int64","description":"Configured root disk size in MB (Firecracker). `None` when unknown or\nthe default.","minimum":0},"id":{"type":"string"},"image":{"type":["string","null"]},"memory":{"type":"integer","format":"int64","minimum":0},"name":{"type":"string"},"preview_password_hint":{"type":["string","null"]},"preview_url_template":{"type":"string"},"region":{"type":"string"},"requestedAt":{"type":"integer","format":"int64","description":"Creation time as Unix epoch milliseconds."},"runtime":{"type":"string"},"status":{"type":"string"},"timeout":{"type":"integer","format":"int64","description":"Idle timeout in milliseconds (SDK convention).","minimum":0},"updatedAt":{"type":"integer","format":"int64"},"vcpus":{"type":"number","format":"double"}}},"SandboxResponse":{"type":"object","description":"`@vercel/sandbox` wraps every single-sandbox response as\n`{ sandbox: {...}, routes: [...] }`. The SDK reads both.","required":["sandbox","routes"],"properties":{"routes":{"type":"array","items":{"$ref":"#/components/schemas/SandboxRoute"}},"sandbox":{"$ref":"#/components/schemas/SandboxInner"}}},"SandboxRoute":{"type":"object","description":"A single preview route, one per declared port. We don't know ports\nupfront, so we surface an empty array by default — SDK clients use\ntheir own port when calling `sandbox.domain(port)`.","required":["url","subdomain","port"],"properties":{"port":{"type":"integer","format":"int32","minimum":0},"subdomain":{"type":"string"},"url":{"type":"string"}}},"SandboxStatusResponse":{"type":"object","required":["docker_available","image_ready","image_name","firecracker_available"],"properties":{"docker_available":{"type":"boolean"},"error":{"type":["string","null"]},"firecracker_available":{"type":"boolean"},"image_name":{"type":"string"},"image_ready":{"type":"boolean"}}},"SaveAgentTokenRequest":{"type":"object","required":["token"],"properties":{"token":{"type":"string","description":"The OAuth token from `claude setup-token` or an API key.\nWill be encrypted before storage."}}},"SaveAgentTokenResponse":{"type":"object","required":["saved"],"properties":{"saved":{"type":"boolean"}}},"SaveCredentialRequest":{"type":"object","required":["auth_type","credential"],"properties":{"auth_type":{"type":"string","description":"Auth flavor id (must match one of the provider's catalog entries)."},"credential":{"type":"string","description":"Plaintext credential body (API key, OAuth token, or full config file\ncontents). Encrypted with `EncryptionService` before being persisted\ninside the `agent_sandbox.providers` JSON map."}}},"SaveCredentialResponse":{"type":"object","required":["saved","provider_id","auth_type"],"properties":{"auth_type":{"type":"string"},"provider_id":{"type":"string"},"saved":{"type":"boolean"}}},"ScalewayCredentialsRequest":{"type":"object","required":["api_key","project_id"],"properties":{"api_key":{"type":"string","example":"scw-secret-key-12345"},"project_id":{"type":"string","example":"12345678-1234-1234-1234-123456789012"}}},"ScanResponse":{"type":"object","required":["id","project_id","scanner_type","status","total_count","critical_count","high_count","medium_count","low_count","unknown_count","started_at","created_at","updated_at"],"properties":{"branch":{"type":["string","null"]},"commit_hash":{"type":["string","null"]},"completed_at":{"type":["string","null"],"example":"2025-12-08T12:15:47.609192Z"},"created_at":{"type":"string","example":"2025-12-08T12:15:47.609192Z"},"critical_count":{"type":"integer","format":"int32"},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"error_message":{"type":["string","null"]},"high_count":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"low_count":{"type":"integer","format":"int32"},"medium_count":{"type":"integer","format":"int32"},"project_id":{"type":"integer","format":"int32"},"scanner_type":{"type":"string"},"scanner_version":{"type":["string","null"]},"started_at":{"type":"string","example":"2025-12-08T12:15:47.609192Z"},"status":{"type":"string"},"total_count":{"type":"integer","format":"int32"},"unknown_count":{"type":"integer","format":"int32"},"updated_at":{"type":"string","example":"2025-12-08T12:15:47.609192Z"}}},"ScheduleRunEntry":{"type":"object","description":"A single run-history entry for the schedule detail page (deliverable 1).\n\nCombines one `backups` row with the most-recent `backup_jobs` row for that\nbackup via a lateral JOIN. Fields from `backup_jobs` are `None` for legacy\nbackup rows that pre-date ADR-014.","required":["backup_id","backup_uuid","state","started_at","s3_location"],"properties":{"attempts":{"type":["integer","null"],"format":"int32","description":"Number of claim-and-run attempts so far. `None` for legacy rows."},"backup_id":{"type":"integer","format":"int32","description":"DB id of the `backups` row."},"backup_uuid":{"type":"string","description":"UUID string (`backups.backup_id`)."},"current_step":{"type":["string","null"],"description":"Last completed step reported by the engine (e.g. `\"upload\"`).\n`None` when no step has been persisted yet."},"error_message":{"type":["string","null"],"description":"Engine-reported error message when `state = \"failed\"`."},"finished_at":{"type":["string","null"],"description":"When the backup finished, if known."},"job_id":{"type":["integer","null"],"format":"int64","description":"Most recent `backup_jobs.id` for this backup. `None` for legacy rows."},"s3_location":{"type":"string","description":"S3 object key or URL where the backup data lives."},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Final size in bytes once completed. `None` while running."},"started_at":{"type":"string","description":"When the backup was started (ISO 8601 / RFC 3339)."},"state":{"type":"string","description":"Current state: `\"pending\"`, `\"running\"`, `\"completed\"`, `\"failed\"`."}}},"ScheduleRunJobEntry":{"type":"object","description":"A single job entry inside an expanded schedule run, returned by\n[`BackupService::list_schedule_run_jobs`].","required":["backup_id","backup_uuid","engine","service_name","state","started_at","s3_source_id"],"properties":{"backup_id":{"type":"integer","format":"int32","description":"`backups.id` for this job."},"backup_uuid":{"type":"string","description":"`backups.backup_id` UUID string."},"engine":{"type":"string","description":"Engine key (e.g. `\"control_plane\"`, `\"redis\"`)."},"error_message":{"type":["string","null"],"description":"Engine-reported error message when `state = \"failed\"`."},"finished_at":{"type":["string","null"],"description":"When this child backup finished, if known."},"s3_source_id":{"type":"integer","format":"int32","description":"FK to `s3_sources.id` — needed for the backup detail link."},"service_id":{"type":["integer","null"],"format":"int32","description":"`external_services.id` — `NULL` for the control-plane job."},"service_name":{"type":"string","description":"Name of the external service, or `\"control plane\"` for the\ncontrol-plane job."},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Size in bytes once completed; `None` while running."},"started_at":{"type":"string","description":"When this child backup started (ISO 8601 / RFC 3339)."},"state":{"type":"string","description":"Current state of this child backup."}}},"ScheduleRunListResponse":{"type":"object","description":"Paginated run-history response for a backup schedule (deliverable 1).","required":["runs","total","page","page_size"],"properties":{"page":{"type":"integer","format":"int64","description":"Current page (1-based)."},"page_size":{"type":"integer","format":"int64","description":"Number of items per page (clamped to 1–100)."},"runs":{"type":"array","items":{"$ref":"#/components/schemas/ScheduleRunEntry"},"description":"Run entries, newest first."},"total":{"type":"integer","format":"int64","description":"Total number of runs across all pages."}}},"ScheduleRunResponse":{"type":"object","description":"HTTP response body for `POST /api/backups/schedules/{id}/run` (fan-out).","required":["schedule_run_id","jobs"],"properties":{"jobs":{"type":"array","items":{"$ref":"#/components/schemas/EnqueuedJob"},"description":"All jobs that were enqueued in this fan-out."},"schedule_run_id":{"type":"integer","format":"int64","description":"The `schedule_runs.id` of the newly created run."}}},"ScheduleRunSummary":{"type":"object","description":"Summary of one scheduler tick (or one \"Run now\" click), returned by\n[`BackupService::list_schedule_runs`].\n\nThe `aggregate_state` is computed at read time from child backup counts:\n- `\"running\"` — at least one child is `\"pending\"` or `\"running\"`.\n- `\"failed\"` — at least one child is `\"failed\"` and none are running.\n- `\"completed\"` — all children are `\"completed\"`.","required":["run_id","schedule_id","triggered_by","started_at","aggregate_state","total_jobs","completed_jobs","failed_jobs","running_jobs","pending_jobs"],"properties":{"aggregate_state":{"type":"string","description":"Aggregate state computed from child counts (see struct docs)."},"completed_jobs":{"type":"integer","format":"int64","description":"Number of children in `state = \"completed\"`."},"failed_jobs":{"type":"integer","format":"int64","description":"Number of children in `state = \"failed\"`."},"finished_at":{"type":["string","null"],"description":"When all children reached a terminal state. `None` while any child is\nstill `\"pending\"` or `\"running\"`."},"pending_jobs":{"type":"integer","format":"int64","description":"Number of children in `state = \"pending\"`."},"run_id":{"type":"integer","format":"int64","description":"`schedule_runs.id` for this tick."},"running_jobs":{"type":"integer","format":"int64","description":"Number of children in `state = \"running\"`."},"schedule_id":{"type":"integer","format":"int32","description":"FK to `backup_schedules.id`."},"started_at":{"type":"string","description":"When the fan-out started (ISO 8601 / RFC 3339)."},"total_jobs":{"type":"integer","format":"int64","description":"Total number of child backup jobs in this run."},"triggered_by":{"type":"string","description":"How the run was triggered: `\"cron\"` or `\"manual\"`."}}},"ScheduleRunSummaryList":{"type":"object","description":"Paginated list of schedule run summaries returned by the new\n[`BackupService::list_schedule_runs`].","required":["runs","total","page","page_size"],"properties":{"page":{"type":"integer","format":"int64","description":"Current page (1-based)."},"page_size":{"type":"integer","format":"int64","description":"Number of items per page."},"runs":{"type":"array","items":{"$ref":"#/components/schemas/ScheduleRunSummary"},"description":"Run summaries, newest first. Includes synthetic single-job rows for\nlegacy `backups` rows that have `schedule_id` set but no\n`schedule_run_id` (pre-fan-out history)."},"total":{"type":"integer","format":"int64","description":"Total number of run entries across all pages."}}},"ScreenshotSettings":{"type":"object","properties":{"enabled":{"type":"boolean","default":false},"provider":{"type":"string","default":"local"},"url":{"type":"string","default":""}}},"SearchLogsRequest":{"type":"object","required":["project_id"],"properties":{"container_ids":{"type":"array","items":{"type":"string"},"description":"Filter to specific containers (Docker container IDs). Empty = all\ncontainers. Drives \"filter by container / show all\" in a project's\nhistory, which spans multiple deployments and containers."},"context_lines":{"type":["integer","null"],"format":"int32","description":"grep -C: number of raw context lines to include before and after each\nmatch (0 = none, default). Clamped to 50 server-side. The surrounding\nlines ignore the level/text filters — they are the actual adjacent log\nlines, merged across overlapping matches.","minimum":0},"cursor":{"type":["string","null"],"description":"Pagination cursor"},"deploy_id":{"type":["integer","null"],"format":"int32","description":"Filter by deployment ID (deployments.id)"},"end_time":{"type":["string","null"],"description":"End of time range (ISO 8601). Defaults to now."},"envs":{"type":"array","items":{"type":"string"},"description":"Filter by environments"},"external_service_id":{"type":["integer","null"],"format":"int32","description":"When set, search an imported/managed external service's logs instead\nof a project's. `project_id` is ignored in this mode."},"levels":{"type":"array","items":{"type":"string"},"description":"Filter by log levels"},"node_ids":{"type":"array","items":{"type":"integer","format":"int32"},"description":"Filter to specific worker nodes (node_id). Empty = all nodes, including\ncontrol-plane-local logs."},"page_size":{"type":["integer","null"],"format":"int32","description":"Page size (default: 100, max: 500)","minimum":0},"project_id":{"type":"integer","format":"int32","description":"Project ID (integer, as used by the rest of the platform)"},"services":{"type":"array","items":{"type":"string"},"description":"Filter by services"},"start_time":{"type":["string","null"],"description":"Start of time range (ISO 8601). Defaults to 1 hour ago."},"text":{"type":["string","null"],"description":"Full text search query"}}},"SearchLogsResponse":{"type":"object","required":["lines","search_mode","total_scanned"],"properties":{"available_sources":{"type":"array","items":{"$ref":"#/components/schemas/LogSource"},"description":"Distinct containers/nodes/services available in the queried scope, for\nthe filter dropdowns. Populated on the first page (no cursor)."},"lines":{"type":"array","items":{"$ref":"#/components/schemas/LogSearchLine"}},"next_cursor":{"type":["string","null"]},"search_mode":{"$ref":"#/components/schemas/SearchMode"},"total_scanned":{"type":"integer","format":"int64","minimum":0}}},"SearchMode":{"type":"string","description":"Search execution mode","enum":["index","archive"]},"Seasonality":{"type":"string","description":"Seasonality model for an anomaly baseline.","enum":["none","hourly","daily","weekly"]},"SecretResponse":{"type":"object","required":["id","name","secret_type","value","created_at","updated_at"],"properties":{"created_at":{"type":"string"},"description":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"mount_path":{"type":["string","null"]},"name":{"type":"string"},"secret_type":{"type":"string"},"updated_at":{"type":"string"},"value":{"type":"string","description":"Always masked in responses"}}},"SecurityConfig":{"type":"object","description":"Security configuration for projects and environments\n\nThis configuration can be set at three levels:\n1. Global (in settings table) - applies to all projects\n2. Project level - overrides global settings for specific project\n3. Environment level - overrides project settings for specific environment\n\nThe inheritance chain: Environment > Project > Global","properties":{"attackMode":{"type":["string","null"],"description":"Attack mode configuration (future: \"off\", \"challenge\", \"block\")\nPlaceholder for DDoS protection, bot detection, etc."},"challengeConfig":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ChallengeConfig","description":"Challenge configuration (future: CAPTCHA, JS challenge, etc.)"}]},"enabled":{"type":["boolean","null"],"description":"Enable/disable security features at this level\nIf None, inherits from parent level"},"geoRestrictions":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/GeoRestrictionsConfig","description":"Geographic restrictions (future: country blocking, etc.)"}]},"headers":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SecurityHeadersConfig","description":"Security headers configuration"}]},"passwordProtection":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PasswordProtectionConfig","description":"Password protection: shows an HTML password form before allowing access"}]},"rateLimiting":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/RateLimitConfig","description":"Rate limiting configuration"}]}}},"SecurityHeadersConfig":{"type":"object","description":"Security headers configuration (subset of global SecurityHeadersSettings)","properties":{"contentSecurityPolicy":{"type":["string","null"],"description":"Custom CSP (only used if preset is \"custom\")"},"preset":{"type":["string","null"],"description":"Use a preset: \"strict\", \"moderate\", \"permissive\", \"disabled\", \"custom\""},"referrerPolicy":{"type":["string","null"],"description":"Referrer-Policy override"},"strictTransportSecurity":{"type":["string","null"],"description":"HSTS override"},"xFrameOptions":{"type":["string","null"],"description":"X-Frame-Options override"}}},"SecurityHeadersSettings":{"type":"object","properties":{"content_security_policy":{"type":["string","null"],"default":"default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self'; frame-ancestors 'self'"},"enabled":{"type":"boolean","default":false},"permissions_policy":{"type":["string","null"],"default":"geolocation=(), microphone=(), camera=()"},"preset":{"type":"string","default":"moderate"},"referrer_policy":{"type":"string","default":"strict-origin-when-cross-origin"},"strict_transport_security":{"type":"string","default":"max-age=31536000; includeSubDomains"},"x_content_type_options":{"type":"string","default":"nosniff"},"x_frame_options":{"type":"string","default":"SAMEORIGIN"},"x_xss_protection":{"type":"string","default":"1; mode=block"}}},"SendEmailRequestBody":{"type":"object","required":["from","to","subject"],"properties":{"bcc":{"type":["array","null"],"items":{"type":"string"},"description":"BCC recipients"},"cc":{"type":["array","null"],"items":{"type":"string"},"description":"CC recipients"},"from":{"type":"string","description":"Sender email address (domain will be auto-extracted for lookup)","example":"hello@updates.example.com"},"from_name":{"type":["string","null"],"description":"Sender display name","example":"My App"},"headers":{"type":["object","null"],"description":"Custom headers","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"html":{"type":["string","null"],"description":"HTML body content","example":"

Hello World

"},"reply_to":{"type":["string","null"],"description":"Reply-to address"},"subject":{"type":"string","description":"Email subject","example":"Welcome to our platform!"},"tags":{"type":["array","null"],"items":{"type":"string"},"description":"Tags for categorization","example":["welcome","onboarding"]},"text":{"type":["string","null"],"description":"Plain text body content","example":"Hello World"},"to":{"type":"array","items":{"type":"string"},"description":"Recipient email addresses","example":["user@example.com"]},"track_clicks":{"type":["boolean","null"],"description":"Enable click tracking (link rewriting). Defaults to false."},"track_opens":{"type":["boolean","null"],"description":"Enable open tracking (tracking pixel injection). Defaults to false."}}},"SendEmailResponseBody":{"type":"object","required":["id","status"],"properties":{"id":{"type":"string","description":"Email ID","example":"550e8400-e29b-41d4-a716-446655440000"},"provider_message_id":{"type":["string","null"],"description":"Provider message ID"},"status":{"type":"string","description":"Email status","example":"sent"}}},"SendMessageRequest":{"type":"object","required":["content"],"properties":{"content":{"type":"string"},"page_context":{"type":["string","null"],"description":"Optional, client-supplied description of the page/entity the user is\ncurrently viewing (e.g. a trace in a project). Injected into the model's\nview of this turn only — never stored or shown in history. Capped server\nside; oversized values are ignored rather than rejected."}}},"SensitiveConfigValueResponse":{"type":"object","required":["value"],"properties":{"value":{"type":"string"}}},"SensitiveMcpConfigValueResponse":{"type":"object","required":["value"],"properties":{"value":{"type":"string"}}},"SensitiveValueResponse":{"type":"object","required":["value"],"properties":{"value":{"type":"string"}}},"SentryChunkUploadResponse":{"type":"object","required":["url","chunkSize","chunksPerRequest","maxFileSize","maxRequestSize","concurrency","hashAlgorithm","compression","accept"],"properties":{"accept":{"type":"array","items":{"type":"string"}},"chunkSize":{"type":"integer","format":"int64","minimum":0},"chunksPerRequest":{"type":"integer","format":"int32","minimum":0},"compression":{"type":"array","items":{"type":"string"}},"concurrency":{"type":"integer","format":"int32","minimum":0},"hashAlgorithm":{"type":"string"},"maxFileSize":{"type":"integer","format":"int64","minimum":0},"maxRequestSize":{"type":"integer","format":"int64","minimum":0},"url":{"type":"string"}}},"SentryCreateReleaseRequest":{"type":"object","required":["version"],"properties":{"projects":{"type":"array","items":{"type":"string"},"description":"Project slugs this release belongs to"},"version":{"type":"string","description":"Release version identifier"}}},"SentryEventRequest":{"type":"object","properties":{"event_id":{"type":["string","null"]},"message":{"type":["string","null"]},"platform":{"type":["string","null"]},"timestamp":{"type":["string","null"]}}},"SentryEventResponse":{"type":"object","required":["id"],"properties":{"id":{"type":"string"}}},"SentryReleaseFileResponse":{"type":"object","required":["id","name","headers","size","sha1","dateCreated"],"properties":{"dateCreated":{"type":"string"},"dist":{"type":["string","null"]},"headers":{},"id":{"type":"string"},"name":{"type":"string"},"sha1":{"type":"string"},"size":{"type":"integer","format":"int64"}}},"SentryReleaseProjectRef":{"type":"object","required":["name","slug"],"properties":{"name":{"type":"string"},"slug":{"type":"string"}}},"SentryReleaseResponse":{"type":"object","required":["version","dateCreated","shortVersion","projects"],"properties":{"dateCreated":{"type":"string"},"dateReleased":{"type":["string","null"]},"projects":{"type":"array","items":{"$ref":"#/components/schemas/SentryReleaseProjectRef"}},"shortVersion":{"type":"string"},"version":{"type":"string"}}},"SeriesStateEntry":{"type":"object","description":"One series' persisted state snapshot for a dynamic rule (ADR-026 follow-up):\nthe state after the latest tick, the value evaluated this tick, and the open\nalarm id (when firing). Serialized into the `series_states` jsonb column keyed\nby the human-readable [`series_label`]; the alert response decodes it back.","required":["state","value"],"properties":{"alarm_id":{"type":["integer","null"],"format":"int32","description":"The open alarm's id when the series is firing; `null` when ok."},"state":{"type":"string","description":"`firing` or `ok` for this series after the latest tick."},"value":{"type":"number","format":"double","description":"The value the rule evaluated for this series this tick."}}},"ServiceAccessInfo":{"type":"object","description":"Response containing information about how the service is being accessed","required":["access_mode","can_create_domains"],"properties":{"access_mode":{"type":"string","description":"Mode of access: \"local\", \"direct\", \"nat\", or \"cloudflare_tunnel\""},"can_create_domains":{"type":"boolean","description":"Whether domain creation is allowed in this mode"},"domain_creation_error":{"type":["string","null"],"description":"Error message if domain creation is not allowed"},"private_ip":{"type":["string","null"],"description":"Server's private/local IP address (always returned if available)"},"public_ip":{"type":["string","null"],"description":"Server's public IP address (always returned if available)"}}},"ServiceAction":{"type":"string","description":"What to do with a service during migration","enum":["create","link-external","skip"]},"ServiceAlertRuleResponse":{"type":"object","description":"Wire representation of a monitoring alert rule.\n\nRegistered under a domain-prefixed OpenAPI schema name to avoid colliding\nwith `temps-error-tracking`'s unrelated `AlertRuleResponse` (utoipa keys\nschemas by their bare struct name, so without `as = ...` the last crate to\nregister would silently shadow this one in the merged spec / generated SDK).","required":["id","name","metric_name","threshold","comparator","severity","for_duration_secs","enabled"],"properties":{"comparator":{"type":"string"},"deployment_id":{"type":["integer","null"],"format":"int32"},"enabled":{"type":"boolean"},"for_duration_secs":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"metric_name":{"type":"string"},"name":{"type":"string"},"service_id":{"type":["integer","null"],"format":"int32"},"severity":{"type":"string"},"silenced_until":{"type":["string","null"]},"threshold":{"type":"number","format":"double"}}},"ServiceBackupEntryResponse":{"type":"object","description":"A single backup entry in the per-service backup list.","required":["id","backup_id","name","state","backup_type","started_at","s3_location","compression_type","s3_source_id","s3_source_name","external_service_backup_id"],"properties":{"backup_id":{"type":"string","description":"UUID string assigned at backup creation time."},"backup_type":{"type":"string","description":"Backup variant (e.g. \"full\", \"incremental\")."},"compression_type":{"type":"string","description":"Compression algorithm used (e.g. \"gzip\")."},"error_message":{"type":["string","null"],"description":"Engine-reported error message, populated when `state = \"failed\"`."},"external_service_backup_id":{"type":"integer","format":"int32","description":"Row ID from `external_service_backups`."},"finished_at":{"type":["string","null"],"description":"ISO 8601 timestamp when the backup finished, if known.","example":"2025-01-15T14:35:00Z"},"id":{"type":"integer","format":"int32","description":"Row ID from the `backups` table."},"name":{"type":"string","description":"Human-friendly display name."},"s3_location":{"type":"string","description":"Object key or `s3://` URL for the backup data."},"s3_source_id":{"type":"integer","format":"int32","description":"FK to `s3_sources.id`."},"s3_source_name":{"type":"string","description":"Human-readable name of the S3 source."},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Size of the backup in bytes, if available."},"started_at":{"type":"string","description":"ISO 8601 timestamp when the backup started.","example":"2025-01-15T14:30:00Z"},"state":{"type":"string","description":"Current state: \"completed\", \"running\", \"failed\"."}}},"ServiceBackupListResponse":{"type":"object","description":"Paginated list of backups for a specific external service.\n\nReturned by `GET /backups/external-services/{service_id}/backups`.","required":["backups","total","page","page_size"],"properties":{"backups":{"type":"array","items":{"$ref":"#/components/schemas/ServiceBackupEntryResponse"},"description":"Backups belonging to this service, newest first."},"page":{"type":"integer","format":"int64","description":"Current page (1-based)."},"page_size":{"type":"integer","format":"int64","description":"Number of items per page."},"total":{"type":"integer","format":"int64","description":"Total number of backups for this service across all pages."}}},"ServiceCreateAlertRuleRequest":{"type":"object","description":"Request body for creating an alert rule on an external service.\n\nDomain-prefixed schema name — see [`AlertRuleResponse`] for why.","required":["name","metric_name","threshold","comparator","severity"],"properties":{"comparator":{"type":"string","description":"One of `>`, `<`, `>=`, `<=`."},"enabled":{"type":"boolean"},"for_duration_secs":{"type":"integer","format":"int32","description":"Seconds the breach must persist before the alarm fires (0 = immediate)."},"metric_name":{"type":"string"},"name":{"type":"string"},"severity":{"type":"string","description":"`\"warning\"` or `\"critical\"`."},"threshold":{"type":"number","format":"double"}}},"ServiceHealthResponse":{"type":"object","required":["service_id","consecutive_failures","recent_checks"],"properties":{"consecutive_failures":{"type":"integer","format":"int32","description":"Consecutive failed probes. Alert fires at 3."},"last_checked_at":{"type":["string","null"]},"last_error":{"type":["string","null"]},"recent_checks":{"type":"array","items":{"$ref":"#/components/schemas/HealthCheckEntryResponse"},"description":"Most recent checks, newest-first (capped at `limit`)."},"response_time_ms":{"type":["integer","null"],"format":"int32"},"service_id":{"type":"integer","format":"int32"},"status":{"type":["string","null"],"description":"Current health. `null` if the service has not been probed yet.","example":"operational"},"uptime_24h_percent":{"type":["number","null"],"format":"double","description":"Uptime percentage over the last 24 hours (0.0 — 100.0).\n`null` when there is not enough history."}}},"ServiceHealthStatusBatchResponse":{"type":"object","required":["statuses"],"properties":{"statuses":{"type":"array","items":{"$ref":"#/components/schemas/ServiceHealthStatusEntryResponse"}}}},"ServiceHealthStatusEntryResponse":{"type":"object","required":["service_id","consecutive_failures"],"properties":{"consecutive_failures":{"type":"integer","format":"int32"},"last_checked_at":{"type":["string","null"]},"service_id":{"type":"integer","format":"int32"},"status":{"type":["string","null"],"description":"\"operational\" | \"degraded\" | \"down\". `null` when the service has not\nbeen probed yet.","example":"operational"}}},"ServiceMemberInfo":{"type":"object","description":"Public info about a cluster member.","required":["id","role","container_name","status","ordinal"],"properties":{"compute_ip":{"type":["string","null"],"description":"Container's IP on the `temps-overlay` multi-host network. Populated\nby the lifecycle hook (ADR-011 Phase 3); `None` on single-host\nclusters where the overlay isn't attached."},"container_name":{"type":"string"},"hostname":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"live_state":{"type":["string","null"],"description":"Live FSM state from the pg_auto_failover monitor (`primary`,\n`secondary`, `catchingup`, `report_lsn`, …). `None` when the\nmonitor is unreachable, the service is not a cluster, or the row\nis the monitor itself.\n\n**The UI must render the role badge from this field**, falling\nback to `role` only when `live_state` is null. `role` is now\nconfig-only (`monitor` or `replica`); flipping the badge to\n\"primary\" when the monitor elects a new one used to require a\nreconciler that lagged ~5s behind real failovers — and during\nthat window the UI showed two primaries. `live_state` is read\ndirectly from the monitor on every list, so it can never lag."},"node_id":{"type":["integer","null"],"format":"int32"},"ordinal":{"type":"integer","format":"int32"},"port":{"type":["integer","null"],"format":"int32"},"provisioning_error":{"type":["string","null"],"description":"Most recent provisioning failure message, when `status='failed'`.\nSet by the background task so the UI can show *why* the new\nreplica didn't come up."},"provisioning_step":{"type":["string","null"],"description":"Last-attempted phase of the async `add_cluster_member` background\ntask (e.g. `validating`, `provisioning_container`, `done`,\n`failed`). `None` for members not created through that flow —\nthe UI falls back to the `status` column for those."},"role":{"type":"string"},"status":{"type":"string"}}},"ServiceParameter":{"type":"object","required":["name","required","encrypted","description"],"properties":{"choices":{"type":["array","null"],"items":{"type":"string"}},"default_value":{"type":["string","null"]},"description":{"type":"string"},"encrypted":{"type":"boolean"},"name":{"type":"string"},"required":{"type":"boolean"},"validation_pattern":{"type":["string","null"]}}},"ServicePlan":{"type":"object","description":"Plan for migrating a single service (database, cache, etc.)","required":["name","service_type","action","action_description"],"properties":{"action":{"$ref":"#/components/schemas/ServiceAction","description":"What to do with this service"},"action_description":{"type":"string","description":"Human-readable explanation of what this action means"},"data_implications":{"type":"array","items":{"$ref":"#/components/schemas/DataImplication"},"description":"Data implications specific to this service"},"env_var_mappings":{"type":"object","description":"Environment variable key mappings: source_key -> temps_key\n\nFor example, Vercel's `POSTGRES_URL` might map to Temps' `DATABASE_URL`.\nBoth keys will be set during migration so the app works with either.","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"name":{"type":"string","description":"Human-readable service name"},"parameters":{"type":"object","description":"Parameters for creating the service in Temps","additionalProperties":{},"propertyNames":{"type":"string"}},"service_type":{"type":"string","description":"Service type (maps to temps-providers ServiceType)"},"version":{"type":["string","null"],"description":"Service version to create (e.g., \"16\" for Postgres 16)"}}},"ServiceResourceLimits":{"type":"object","description":"Optional cgroup resource limits applied to a service container.\n\nAll fields are `Option`: `None` means \"no limit\" (the kernel default),\nmatching Docker's behavior when the corresponding `HostConfig` field is\nleft at zero. Operators opt in to limits explicitly through the\n`PATCH /external-services/{id}/resources` endpoint or by writing the\n`resources` block into `ServiceConfig::parameters` at create time.\n\nThese map directly onto bollard fields:\n- `memory_mb` → `HostConfig.memory` (bytes)\n- `memory_swap_mb`→ `HostConfig.memory_swap` (bytes; ≥ memory)\n- `nano_cpus` → `HostConfig.nano_cpus` (1e9 = 1 full CPU)\n- `cpu_shares` → `HostConfig.cpu_shares` (relative weight, default 1024)\n- `shm_size_mb` → `HostConfig.shm_size` (bytes; default 64 MiB)\n\nIMPORTANT: enabling hard memory limits causes the kernel OOM killer to\nterminate the container when the working set exceeds the limit. The\ncontainer will restart (RestartPolicy::ALWAYS) but in-flight queries\nfail. Surface this clearly in any UI that lets users set limits.","properties":{"cpu_shares":{"type":["integer","null"],"format":"int64","description":"Relative CPU weight (default 1024). Only used when `nano_cpus` is None."},"memory_mb":{"type":["integer","null"],"format":"int64","description":"Hard memory limit in MiB. None = unlimited."},"memory_swap_mb":{"type":["integer","null"],"format":"int64","description":"Memory + swap limit in MiB. None = unlimited.\nMUST be >= memory_mb when both are set; Docker rejects the request otherwise.\nSet equal to `memory_mb` to disable swap entirely."},"nano_cpus":{"type":["integer","null"],"format":"int64","description":"CPU quota in nano-cpus. 1_000_000_000 = 1 full CPU core. None = unlimited."},"shm_size_mb":{"type":["integer","null"],"format":"int64","description":"Shared memory (/dev/shm) size in MiB. None = Docker default (64 MiB).\nMaps to HostConfig.shm_size (bytes). PostgreSQL uses /dev/shm for parallel\nquery workers and large work_mem; the 64 MiB default causes \"could not\nresize shared memory segment ... No space left on device\" under load.\nNOTE: shm_size is fixed at container-create time — Docker's live update\nAPI cannot change it, so changing this value recreates the container."}}},"ServiceRuntimeReport":{"type":"object","description":"Aggregate runtime info for an external service. For standalone services,\n`members` has exactly one entry. For clusters, one entry per member.","required":["service_id","topology","members"],"properties":{"members":{"type":"array","items":{"$ref":"#/components/schemas/ContainerRuntimeInfo"}},"service_id":{"type":"integer","format":"int32"},"topology":{"type":"string"}}},"ServiceStatsReport":{"type":"object","required":["service_id","topology","members"],"properties":{"members":{"type":"array","items":{"$ref":"#/components/schemas/ContainerStatsSample"}},"service_id":{"type":"integer","format":"int32"},"topology":{"type":"string"}}},"ServiceTypeInfo":{"type":"object","required":["service_type","parameters"],"properties":{"parameters":{"type":"array","items":{"$ref":"#/components/schemas/ServiceParameter"},"example":"[{\"name\": \"host\", \"required\": true, \"encrypted\": false, \"description\": \"Database host\"}]"},"service_type":{"$ref":"#/components/schemas/ServiceTypeRoute"}}},"ServiceTypeRoute":{"type":"string","enum":["mariadb","mongodb","postgres","redis","s3","kv","blob","rustfs","minio"]},"ServiceUpdateAlertRuleRequest":{"type":"object","description":"Request body for updating an existing alert rule.\n\nDomain-prefixed schema name — see [`AlertRuleResponse`] for why.","properties":{"comparator":{"type":["string","null"]},"enabled":{"type":["boolean","null"]},"for_duration_secs":{"type":["integer","null"],"format":"int32"},"metric_name":{"type":["string","null"]},"name":{"type":["string","null"]},"severity":{"type":["string","null"]},"threshold":{"type":["number","null"],"format":"double"}}},"SesCredentialsRequest":{"type":"object","required":["access_key_id","secret_access_key"],"properties":{"access_key_id":{"type":"string","example":"AKIAIOSFODNN7EXAMPLE"},"secret_access_key":{"type":"string","example":"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"}}},"SessionDetails":{"type":"object","required":["session_id","visitor_id","started_at","duration_seconds","is_bounced","is_engaged","page_views"],"properties":{"duration_seconds":{"type":"integer","format":"int64"},"ended_at":{"type":["string","null"],"format":"date-time","example":"2024-01-01T00:00:00"},"entry_path":{"type":["string","null"]},"exit_path":{"type":["string","null"]},"is_bounced":{"type":"boolean"},"is_engaged":{"type":"boolean"},"page_views":{"type":"integer","format":"int64"},"referrer":{"type":["string","null"]},"session_id":{"type":"integer","format":"int32"},"started_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"visitor_id":{"type":"string"}}},"SessionDetailsQuery":{"type":"object","required":["project_id"],"properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"}}},"SessionEvent":{"type":"object","required":["id","timestamp"],"properties":{"event_data":{},"event_name":{"type":["string","null"]},"event_type":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"page_title":{"type":["string","null"]},"page_url":{"type":["string","null"]},"timestamp":{"type":"string"}}},"SessionEventDto":{"type":"object","required":["id","session_id","data","timestamp"],"properties":{"data":{},"event_type":{"type":["integer","null"],"format":"int32"},"id":{"type":"integer","format":"int32"},"session_id":{"type":"integer","format":"int32"},"timestamp":{"type":"integer","format":"int64"}}},"SessionEventsQuery":{"type":"object","required":["project_id"],"properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"}}},"SessionEventsResponse":{"type":"object","required":["session_id","events","total_count","offset","limit"],"properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/SessionEvent"}},"limit":{"type":"integer","format":"int32"},"offset":{"type":"integer","format":"int32"},"session_id":{"type":"integer","format":"int32"},"total_count":{"type":"integer","format":"int64"}}},"SessionLogsQuery":{"type":"object","required":["project_id"],"properties":{"end_date":{"type":["string","null"],"format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32"},"offset":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"sort_order":{"type":["string","null"]},"start_date":{"type":["string","null"],"format":"date-time"},"visitor_id":{"type":["integer","null"],"format":"int32"}}},"SessionLogsResponse":{"type":"object","required":["session_id","logs","total_count","offset","limit"],"properties":{"limit":{"type":"integer","format":"int32"},"logs":{"type":"array","items":{"$ref":"#/components/schemas/SessionRequestLog"}},"offset":{"type":"integer","format":"int32"},"session_id":{"type":"integer","format":"int32"},"total_count":{"type":"integer","format":"int64"}}},"SessionReplayEventsRequest":{"type":"object","required":["sessionId","events"],"properties":{"events":{"type":"string"},"sessionId":{"type":"string"}}},"SessionReplayInfoDto":{"type":"object","required":["id","visitor_id"],"properties":{"created_at":{"type":["string","null"]},"duration":{"type":["integer","null"],"format":"int32"},"id":{"type":"string"},"language":{"type":["string","null"]},"screen_height":{"type":["integer","null"],"format":"int32"},"screen_width":{"type":["integer","null"],"format":"int32"},"timezone":{"type":["string","null"]},"url":{"type":["string","null"]},"user_agent":{"type":["string","null"]},"viewport_height":{"type":["integer","null"],"format":"int32"},"viewport_width":{"type":["integer","null"],"format":"int32"},"visitor_id":{"type":"integer","format":"int32"}}},"SessionReplayInitRequest":{"type":"object","required":["sessionId"],"properties":{"colorDepth":{"type":["integer","null"],"format":"int32","minimum":0},"language":{"type":["string","null"]},"screenHeight":{"type":["integer","null"],"format":"int32","minimum":0},"screenWidth":{"type":["integer","null"],"format":"int32","minimum":0},"sessionId":{"type":"string"},"timestamp":{"type":["string","null"]},"timezone":{"type":["string","null"]},"url":{"type":["string","null"]},"userAgent":{"type":["string","null"]},"viewportHeight":{"type":["integer","null"],"format":"int32","minimum":0},"viewportWidth":{"type":["integer","null"],"format":"int32","minimum":0}}},"SessionReplayInitResponse":{"type":"object","required":["session_id","message"],"properties":{"message":{"type":"string"},"session_id":{"type":"string"}}},"SessionReplayWithEventsDto":{"type":"object","required":["session","events"],"properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/SessionEventDto"}},"session":{"$ref":"#/components/schemas/SessionReplayWithVisitorDto"}}},"SessionReplayWithVisitorDto":{"type":"object","required":["id","session_replay_id","visitor_id","visitor_uuid","visitor_project_id","visitor_environment_id","visitor_first_seen","visitor_last_seen","visitor_is_crawler"],"properties":{"browser":{"type":["string","null"]},"browser_version":{"type":["string","null"]},"created_at":{"type":["string","null"]},"device_type":{"type":["string","null"]},"duration":{"type":["integer","null"],"format":"int32"},"id":{"type":"integer","format":"int32"},"language":{"type":["string","null"]},"operating_system":{"type":["string","null"]},"operating_system_version":{"type":["string","null"]},"screen_height":{"type":["integer","null"],"format":"int32"},"screen_width":{"type":["integer","null"],"format":"int32"},"session_replay_id":{"type":"string"},"timezone":{"type":["string","null"]},"url":{"type":["string","null"]},"user_agent":{"type":["string","null"]},"viewport_height":{"type":["integer","null"],"format":"int32"},"viewport_width":{"type":["integer","null"],"format":"int32"},"visitor_city":{"type":["string","null"]},"visitor_country":{"type":["string","null"]},"visitor_country_code":{"type":["string","null"]},"visitor_crawler_name":{"type":["string","null"]},"visitor_custom_data":{},"visitor_environment_id":{"type":"integer","format":"int32"},"visitor_first_seen":{"type":"string"},"visitor_id":{"type":"integer","format":"int32"},"visitor_is_crawler":{"type":"boolean"},"visitor_last_seen":{"type":"string"},"visitor_project_id":{"type":"integer","format":"int32"},"visitor_region":{"type":["string","null"]},"visitor_uuid":{"type":"string"}}},"SessionRequestLog":{"type":"object","required":["id","method","path","status_code","created_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"id":{"type":"integer","format":"int32"},"method":{"type":"string"},"path":{"type":"string"},"referrer":{"type":["string","null"]},"request_headers":{"type":["string","null"]},"response_headers":{"type":["string","null"]},"response_time_ms":{"type":["integer","null"],"format":"int32"},"status_code":{"type":"integer","format":"int32"},"user_agent":{"type":["string","null"]}}},"SessionSummary":{"type":"object","required":["session_id","started_at","duration_seconds","page_views","events_count","requests_count","is_bounced","is_engaged"],"properties":{"duration_seconds":{"type":"integer","format":"int64"},"ended_at":{"type":["string","null"],"format":"date-time","example":"2024-01-01T00:00:00"},"entry_path":{"type":["string","null"]},"events_count":{"type":"integer","format":"int64"},"exit_path":{"type":["string","null"]},"is_bounced":{"type":"boolean"},"is_engaged":{"type":"boolean"},"page_views":{"type":"integer","format":"int64"},"referrer":{"type":["string","null"]},"requests_count":{"type":"integer","format":"int64"},"session_id":{"type":"integer","format":"int32"},"started_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"}}},"SetFlagEnvironmentRequest":{"type":"object","properties":{"enabled":{"type":["boolean","null"],"description":"The kill switch. `false` makes the flag serve its default regardless of\nany override — and, once targeting exists, regardless of any rule."},"value":{"description":"Tri-state: absent leaves the override, `null` clears it (inherit the\nflag default), anything else sets it. Must match `value_type`."}}},"SetPreviewPasswordBody":{"type":"object","required":["password"],"properties":{"password":{"type":"string","description":"Plaintext password to protect the sandbox's preview URLs. Hashed\nserver-side with argon2id — we never persist or echo this back.\nMust be between 8 and 256 characters."}}},"SetPreviewPasswordResponse":{"type":"object","required":["preview_password_hint"],"properties":{"preview_password_hint":{"type":"string","description":"Last 4 chars of the password we just stored. Surface in the UI so\nusers can confirm which password is live without re-entering it."}}},"SetRequest":{"type":"object","description":"Request to set a value","required":["key","value"],"properties":{"ex":{"type":["integer","null"],"format":"int64","description":"Expire in seconds","example":3600},"key":{"type":"string","description":"The key to set","example":"user:123"},"nx":{"type":"boolean","description":"Only set if key does not exist"},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1},"px":{"type":["integer","null"],"format":"int64","description":"Expire in milliseconds"},"value":{"description":"The value to store (can be any JSON value)"},"xx":{"type":"boolean","description":"Only set if key exists"}}},"SetResponse":{"type":"object","description":"Response for set operation","required":["result"],"properties":{"result":{"type":"string","description":"Always \"OK\" on success","example":"OK"}}},"SettingsUpdateResponse":{"type":"object","description":"Response for successful settings update","required":["message"],"properties":{"message":{"type":"string"}}},"SetupDnsChallengeRequest":{"type":"object","description":"Request to setup DNS challenge records using a configured DNS provider","required":["dns_provider_id"],"properties":{"dns_provider_id":{"type":"integer","format":"int32","description":"The ID of the DNS provider to use for creating the TXT records"}}},"SetupDnsChallengeResponse":{"type":"object","description":"Response from DNS challenge setup operation","required":["success","records_created","total_records","results","message"],"properties":{"message":{"type":"string","description":"Human-readable summary message"},"records_created":{"type":"integer","format":"int32","description":"Number of TXT records that were successfully created","minimum":0},"results":{"type":"array","items":{"$ref":"#/components/schemas/DnsChallengeRecordResult"},"description":"Results for each individual TXT record"},"success":{"type":"boolean","description":"Overall success status (true if all records were created)"},"total_records":{"type":"integer","format":"int32","description":"Total number of TXT records required for the challenge","minimum":0}}},"SetupDnsRequest":{"type":"object","description":"Request to setup DNS records using a configured DNS provider","required":["dns_provider_id"],"properties":{"dns_provider_id":{"type":"integer","format":"int32","description":"The ID of the DNS provider to use for creating records"}}},"SetupDnsResponse":{"type":"object","description":"Response from DNS setup operation","required":["success","records_created","total_records","results","message"],"properties":{"message":{"type":"string","description":"Human-readable summary message"},"records_created":{"type":"integer","format":"int32","description":"Number of records that were successfully created","minimum":0},"results":{"type":"array","items":{"$ref":"#/components/schemas/DnsRecordSetupResult"},"description":"Results for each individual record"},"success":{"type":"boolean","description":"Overall success status"},"total_records":{"type":"integer","format":"int32","description":"Total number of records attempted","minimum":0}}},"SiblingRef":{"type":"object","description":"A sibling project that shares the same `trace_id` and has opted in to\ncross-project trace sharing (`cross_project_trace_sharing = TRUE`).\n\nReturned by `CrossProjectTraceService::find_sibling_projects` and exposed\nby the Phase 1 `GET /otel/traces/cross-project/{trace_id}` endpoint.","required":["project_id","project_name","project_slug","first_seen"],"properties":{"first_seen":{"type":"string","format":"date-time"},"project_id":{"type":"integer","format":"int32"},"project_name":{"type":"string"},"project_slug":{"type":"string","description":"URL slug used to link into the sibling project's single-project trace view."}}},"SkillDefinitionResponse":{"type":"object","required":["id","slug","name","content","has_archive","created_at","updated_at"],"properties":{"content":{"type":"string"},"created_at":{"type":"string"},"description":{"type":["string","null"]},"has_archive":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"project_id":{"type":["integer","null"],"format":"int32"},"slug":{"type":"string"},"updated_at":{"type":"string"}}},"SlackConfig":{"type":"object","required":["webhook_url"],"properties":{"channel":{"type":["string","null"]},"webhook_url":{"type":"string"}}},"SlowQueriesResponse":{"type":"object","description":"Response envelope for the slow-queries list endpoint.","required":["queries","page","page_size","total_count"],"properties":{"page":{"type":"integer","format":"int32","description":"Current page number (1-based).","minimum":0},"page_size":{"type":"integer","format":"int32","description":"Number of rows per page used for this request.","minimum":0},"queries":{"type":"array","items":{"$ref":"#/components/schemas/SlowQueryRow"},"description":"Ordered list of query stats, slowest first by mean_exec_time_ms."},"total_count":{"type":"integer","format":"int64","description":"Total number of qualifying rows across all pages.","minimum":0}}},"SlowQueryRow":{"type":"object","description":"A single entry from `pg_stat_statements`, representing one normalized\nquery fingerprint and its aggregate execution stats.","required":["query","database","calls","total_exec_time_ms","mean_exec_time_ms","rows"],"properties":{"cache_hit_ratio":{"type":["number","null"],"format":"double","description":"Shared block cache hit ratio (0.0–1.0).\n`None` when total block accesses are zero (e.g. function-only queries)."},"calls":{"type":"integer","format":"int64","description":"Number of times this query was executed."},"database":{"type":"string","description":"Name of the database this query ran against. `(dropped database)`\nwhen the originating database no longer exists but\n`pg_stat_statements` still holds stats for it."},"mean_exec_time_ms":{"type":"number","format":"double","description":"Average wall-clock time per execution, in milliseconds."},"query":{"type":"string","description":"Normalized query text (parameter literals replaced with `$N`)."},"rows":{"type":"integer","format":"int64","description":"Total number of rows returned or affected."},"total_exec_time_ms":{"type":"number","format":"double","description":"Total wall-clock time spent executing this query, in milliseconds."}}},"SmartFilter":{"oneOf":[{"type":"object","description":"Match specific page path","required":["value","type"],"properties":{"type":{"type":"string","enum":["page_path"]},"value":{"type":"string","description":"Match specific page path"}}},{"type":"object","description":"Match specific hostname","required":["value","type"],"properties":{"type":{"type":"string","enum":["hostname"]},"value":{"type":"string","description":"Match specific hostname"}}},{"type":"object","description":"Match UTM source","required":["value","type"],"properties":{"type":{"type":"string","enum":["utm_source"]},"value":{"type":"string","description":"Match UTM source"}}},{"type":"object","description":"Match UTM campaign","required":["value","type"],"properties":{"type":{"type":"string","enum":["utm_campaign"]},"value":{"type":"string","description":"Match UTM campaign"}}},{"type":"object","description":"Match UTM medium","required":["value","type"],"properties":{"type":{"type":"string","enum":["utm_medium"]},"value":{"type":"string","description":"Match UTM medium"}}},{"type":"object","description":"Match referrer hostname","required":["value","type"],"properties":{"type":{"type":"string","enum":["referrer_hostname"]},"value":{"type":"string","description":"Match referrer hostname"}}},{"type":"object","description":"Match specific channel (organic, paid, direct, referral, etc.)","required":["value","type"],"properties":{"type":{"type":"string","enum":["channel"]},"value":{"type":"string","description":"Match specific channel (organic, paid, direct, referral, etc.)"}}},{"type":"object","description":"Match device type (mobile, desktop, tablet)","required":["value","type"],"properties":{"type":{"type":"string","enum":["device_type"]},"value":{"type":"string","description":"Match device type (mobile, desktop, tablet)"}}},{"type":"object","description":"Match browser","required":["value","type"],"properties":{"type":{"type":"string","enum":["browser"]},"value":{"type":"string","description":"Match browser"}}},{"type":"object","description":"Match operating system","required":["value","type"],"properties":{"type":{"type":"string","enum":["operating_system"]},"value":{"type":"string","description":"Match operating system"}}},{"type":"object","description":"Match language","required":["value","type"],"properties":{"type":{"type":"string","enum":["language"]},"value":{"type":"string","description":"Match language"}}},{"type":"object","description":"Match custom event_data by JSON path\nFormat: {\"path\": \"user.plan\", \"value\": \"premium\"}\nThis will match events where event_data->'user'->>'plan' = 'premium'","required":["value","type"],"properties":{"type":{"type":"string","enum":["custom_data"]},"value":{"type":"object","description":"Match custom event_data by JSON path\nFormat: {\"path\": \"user.plan\", \"value\": \"premium\"}\nThis will match events where event_data->'user'->>'plan' = 'premium'","required":["path","value"],"properties":{"path":{"type":"string"},"value":{"type":"string"}}}}}],"description":"Smart filter presets for common funnel patterns"},"SmokeTestResponse":{"type":"object","required":["passed","environment","cli_installed","cli_authenticated"],"properties":{"auth_info":{"type":["string","null"],"description":"Auth email / method"},"cli_authenticated":{"type":"boolean","description":"Claude CLI authenticated?"},"cli_installed":{"type":"boolean","description":"Claude CLI installed?"},"cli_version":{"type":["string","null"],"description":"Claude CLI version"},"detail":{"type":["string","null"],"description":"Full output for debugging"},"environment":{"type":"string","description":"Where the test ran: \"host\" or \"sandbox\""},"passed":{"type":"boolean","description":"Whether the smoke test passed"},"setup_hint":{"type":["string","null"],"description":"What the user needs to do if the test failed"}}},"SmtpCredentialsRequest":{"type":"object","description":"Generic SMTP credentials request body.\n\nWorks with any SMTP relay — AWS SES SMTP endpoints, Sendgrid, Mailgun,\nPostmark, or a self-hosted Postfix. Use this when you only have SMTP\ncredentials (i.e. you cannot create identities via the upstream API).","required":["host","port"],"properties":{"accept_invalid_certs":{"type":"boolean","description":"Accept self-signed certificates. Only safe for local testing."},"encryption":{"$ref":"#/components/schemas/SmtpEncryptionRoute","description":"TLS mode. Defaults to STARTTLS."},"host":{"type":"string","description":"SMTP host, e.g. `email-smtp.eu-west-1.amazonaws.com`.","example":"email-smtp.eu-west-1.amazonaws.com"},"password":{"type":["string","null"],"description":"SMTP password / API token. Required when `username` is set."},"port":{"type":"integer","format":"int32","description":"SMTP port (587 for STARTTLS, 465 for implicit TLS, 25/1025 for plain).","example":587,"minimum":0},"username":{"type":["string","null"],"description":"SMTP username. Leave empty for unauthenticated relays.","example":"AKIAIOSFODNN7EXAMPLE"}}},"SmtpEncryptionRoute":{"type":"string","description":"TLS mode for the SMTP relay.","enum":["starttls","tls","none"]},"SmtpResult":{"type":"object","description":"SMTP validation result","required":["can_connect_smtp","has_full_inbox","is_catch_all","is_deliverable","is_disabled"],"properties":{"can_connect_smtp":{"type":"boolean","description":"Whether we could connect to the SMTP server"},"error":{"type":["string","null"],"description":"Error message if SMTP check failed"},"has_full_inbox":{"type":"boolean","description":"Whether the mailbox appears to have a full inbox"},"is_catch_all":{"type":"boolean","description":"Whether this is a catch-all domain"},"is_deliverable":{"type":"boolean","description":"Whether the email is deliverable"},"is_disabled":{"type":"boolean","description":"Whether the mailbox is disabled"}}},"SourceArchiveUpload":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary"}}},"SourceBackupEntry":{"type":"object","description":"Entry in the source backup index. Covers both DB-tracked backups\n(have a row in `backups`) and S3-scan discoveries (raw S3 objects with\nno DB row — used for disaster-recovery from another Temps instance).","required":["id","backup_id","name","backup_type","created_at","location","metadata_location","source","state"],"properties":{"backup_id":{"type":"string","description":"UUID identifier from the DB row. Empty for S3-scan entries.","example":"550e8400-e29b-41d4-a716-446655440000"},"backup_type":{"type":"string","description":"Backup variant as recorded by the backup pipeline (e.g. \"full\").","example":"full"},"created_at":{"type":"string","description":"When the backup was created. For S3-scan entries this is the\nobject's LastModified time.","example":"2024-01-15T14:30:00.123Z"},"engine":{"type":["string","null"],"description":"Engine that produced the backup (\"postgres\", \"redis\", \"mongodb\",\n\"s3\", \"rustfs\"). Used by the UI to mark engine-compat with the\ntarget service.","example":"postgres"},"format":{"type":["string","null"],"description":"Storage format: \"walg\" for continuous-archive (PITR-capable),\n\"pg_dump\" for point-in-time dumps, \"\" for non-postgres.","example":"walg"},"id":{"type":"integer","format":"int32","description":"DB row id. Zero for S3-scan entries that have no DB row.","example":1},"location":{"type":"string","description":"Raw S3 URL / key where the backup sits. For Postgres WAL-G backups\nthis starts with `s3://`; for pg_dump-style backups it's the\nrelative object key.","example":"s3://bucket/external_services/postgres/svc-name/walg"},"metadata_location":{"type":"string","description":"Sidecar metadata.json location, if any. Empty when none.","example":""},"name":{"type":"string","description":"Human-friendly display name (\"postgres backup (svc-name)\" for DB\nrows, or a synthesized label derived from the S3 path for scans).","example":"postgres backup (postgres-n4ea)"},"origin_service_name":{"type":["string","null"],"description":"Name of the service that produced the backup. For S3-scan entries\nthis is parsed from the S3 path.","example":"postgres-n4ea"},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Size of the backup in bytes, if known.","example":1024000},"source":{"type":"string","description":"Provenance: \"db\" for rows in this Temps, \"s3_scan\" for objects\ndiscovered by the S3 bucket walk (e.g., backups made by another\nTemps instance).","example":"db"},"state":{"type":"string","description":"Observed state (\"completed\", \"running\", \"failed\") — DB only.\nEmpty string for S3-scan entries.","example":"completed"}}},"SourceBackupIndexResponse":{"type":"object","description":"Response type for source backup index","required":["backups","last_updated"],"properties":{"backups":{"type":"array","items":{"$ref":"#/components/schemas/SourceBackupEntry"},"description":"List of backups in the source"},"last_updated":{"type":"string","description":"When the index was last updated","example":"2024-01-15T14:30:00.123Z"}}},"SourceBody":{"oneOf":[{"type":"object","required":["url","type"],"properties":{"depth":{"type":["integer","null"],"format":"int32","minimum":0},"git_connection_id":{"type":["integer","null"],"format":"int32"},"password":{"type":["string","null"]},"revision":{"type":["string","null"]},"type":{"type":"string","enum":["git"]},"url":{"type":"string"},"username":{"type":["string","null"]}}},{"type":"object","required":["url","type"],"properties":{"type":{"type":"string","enum":["tarball"]},"url":{"type":"string"}}}],"description":"Initial content to seed into the sandbox work dir. Mirrors the\n`@vercel/sandbox` `source` option. `type` is one of:\n- `git` — clone `url`; optionally check out `revision`\n- `tarball` — download `url` (must be tar or tar.gz) and extract\n\nFor private git repos, pass credentials one of two ways:\n1. **Inline (SDK-compatible):** `username` + `password`. GitHub\n tokens use `username: \"x-access-token\"`.\n2. **Stored connection (temps-native):** `git_connection_id`\n references a row in the caller's git provider connections. Temps\n resolves the token server-side and injects it safely.\n\n`git_connection_id` is mutually exclusive with `username`/`password`."},"SourceFileListResponse":{"type":"object","required":["source_files","total"],"properties":{"source_files":{"type":"array","items":{"$ref":"#/components/schemas/SourceFileResponse"}},"total":{"type":"integer","minimum":0}}},"SourceFileResponse":{"type":"object","required":["id","project_id","release","file_path","size_bytes","created_at"],"properties":{"checksum":{"type":["string","null"]},"created_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"file_path":{"type":"string"},"id":{"type":"integer","format":"int32"},"project_id":{"type":"integer","format":"int32"},"release":{"type":"string"},"size_bytes":{"type":"integer","format":"int64"}}},"SourceMapListResponse":{"type":"object","required":["source_maps","total"],"properties":{"source_maps":{"type":"array","items":{"$ref":"#/components/schemas/SourceMapResponse"}},"total":{"type":"integer","minimum":0}}},"SourceMapResponse":{"type":"object","required":["id","project_id","release","file_path","size_bytes","created_at"],"properties":{"checksum":{"type":["string","null"]},"created_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"dist":{"type":["string","null"]},"file_path":{"type":"string"},"id":{"type":"integer","format":"int32"},"project_id":{"type":"integer","format":"int32"},"release":{"type":"string"},"size_bytes":{"type":"integer","format":"int64"}}},"SourceType":{"type":"string","description":"Source type for project deployments\n\nDetermines where the deployment artifacts come from:\n- `Git`: Source code from a Git repository (traditional flow)\n- `DockerImage`: Pre-built Docker image from external registry\n- `StaticFiles`: Pre-built static files uploaded as a bundle\n- `UploadedSource`: Source archive uploaded without a Git repository\n- `Manual`: Flexible type that accepts any deployment method","enum":["git","docker_image","static_files","uploaded_source","manual"]},"SpanEvent":{"type":"object","description":"A span event (log-like annotation on a span).","required":["timestamp","name","attributes"],"properties":{"attributes":{"type":"object","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"name":{"type":"string"},"timestamp":{"type":"string","format":"date-time"}}},"SpanKind":{"type":"string","description":"Span kind.","enum":["UNSPECIFIED","INTERNAL","SERVER","CLIENT","PRODUCER","CONSUMER"]},"SpanRecord":{"type":"object","description":"A single trace span ready for storage.","required":["project_id","resource","trace_id","span_id","name","kind","start_time","end_time","duration_ms","status_code","status_message","attributes","events"],"properties":{"attributes":{"type":"object","description":"Raw key/value pairs exactly as reported by the instrumenting library.\nNumeric values are NOT guaranteed to share `duration_ms`'s unit — they\nmay be seconds, milliseconds, microseconds, or nanoseconds depending on\nthe exporter's own convention, and the unit is not labeled here.","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"deployment_id":{"type":["integer","null"],"format":"int32"},"duration_ms":{"type":"number","format":"double","description":"Span duration in milliseconds. The only field on this struct guaranteed\nto be in milliseconds."},"end_time":{"type":"string","format":"date-time"},"events":{"type":"array","items":{"$ref":"#/components/schemas/SpanEvent"}},"kind":{"$ref":"#/components/schemas/SpanKind"},"name":{"type":"string"},"parent_span_id":{"type":["string","null"]},"project_id":{"type":"integer","format":"int32"},"resource":{"$ref":"#/components/schemas/ResourceInfo"},"span_id":{"type":"string"},"start_time":{"type":"string","format":"date-time"},"status_code":{"$ref":"#/components/schemas/SpanStatusCode"},"status_message":{"type":"string"},"trace_id":{"type":"string"}}},"SpanRow":{"type":"object","required":["id","ts","trace_id","span_id","service","operation","attributes","attributes_truncated"],"properties":{"attributes":{},"attributes_truncated":{"type":"boolean"},"deployment_id":{"type":["integer","null"],"format":"int32"},"duration_ms":{"type":["number","null"],"format":"double"},"environment_id":{"type":["integer","null"],"format":"int32"},"id":{"type":"string"},"operation":{"type":"string"},"parent_span_id":{"type":["string","null"]},"service":{"type":"string"},"span_id":{"type":"string"},"status":{"type":["string","null"]},"trace_id":{"type":"string"},"ts":{"type":"string","format":"date-time"}}},"SpanStatusCode":{"type":"string","description":"Span status code.","enum":["UNSET","OK","ERROR"]},"SpeedMetricsPayload":{"type":"object","description":"Speed metrics payload for recording web vitals","properties":{"cls":{"type":["number","null"],"format":"float","description":"Cumulative Layout Shift (score)"},"fcp":{"type":["number","null"],"format":"float","description":"First Contentful Paint (milliseconds)"},"fid":{"type":["number","null"],"format":"float","description":"First Input Delay (milliseconds)"},"inp":{"type":["number","null"],"format":"float","description":"Interaction to Next Paint (milliseconds)"},"language":{"type":["string","null"],"description":"Browser language"},"lcp":{"type":["number","null"],"format":"float","description":"Largest Contentful Paint (milliseconds)"},"pathname":{"type":["string","null"],"description":"Page pathname"},"query":{"type":["string","null"],"description":"Query string"},"screenHeight":{"type":["integer","null"],"format":"int32","description":"Screen height in pixels"},"screenWidth":{"type":["integer","null"],"format":"int32","description":"Screen width in pixels"},"ttfb":{"type":["number","null"],"format":"float","description":"Time to First Byte (milliseconds)"},"viewportHeight":{"type":["integer","null"],"format":"int32","description":"Viewport height in pixels"},"viewportWidth":{"type":["integer","null"],"format":"int32","description":"Viewport width in pixels"}}},"SpeedSegmentFilters":{"type":"object","description":"Optional segment filters for the performance read endpoints, mirroring\nanalytics' `VisitorSegmentFilters`. Each filter narrows results to samples\nmatching the dimension value, so metrics can be scoped to e.g. one page,\none browser, or one country. Geographic filters resolve via\n`ip_geolocations`; the rest live directly on `performance_metrics`.","properties":{"filter_browser":{"type":["string","null"],"description":"Browser name (matches `performance_metrics.browser`)"},"filter_city":{"type":["string","null"],"description":"Geolocation city (matches `ip_geolocations.city`)"},"filter_country":{"type":["string","null"],"description":"Geolocation country (matches `ip_geolocations.country`)"},"filter_operating_system":{"type":["string","null"],"description":"Operating system (matches `performance_metrics.operating_system`)"},"filter_path":{"type":["string","null"],"description":"Page pathname (matches `performance_metrics.pathname`)"},"filter_region":{"type":["string","null"],"description":"Geolocation region (matches `ip_geolocations.region`)"}}},"StaleSlot":{"type":"object","required":["slot_name","active","retained_bytes"],"properties":{"active":{"type":"boolean"},"retained_bytes":{"type":"integer","format":"int64"},"slot_name":{"type":"string"}}},"StartAnalysisRequest":{"type":"object","required":["error_group_id"],"properties":{"branch":{"type":["string","null"],"description":"Branch to clone instead of the project's main branch."},"error_group_id":{"type":"integer","format":"int32"},"max_turns":{"type":["integer","null"],"format":"int32","description":"Per-run turn cap applied to every phase (1–200). Only enforced for\nCLIs with a turn flag (Claude Code). `None` uses the provider's\nconfigured defaults."},"model":{"type":["string","null"],"description":"Model id for the chosen provider. `None` uses the provider's saved\ndefault model."},"provider":{"type":["string","null"],"description":"AI provider id (\"claude_cli\", \"codex_cli\", \"opencode\"). `None` uses\nthe platform default provider."},"user_context":{"type":["string","null"],"description":"Free-text notes for the model (extra context about the error, retry\nguidance, constraints). Included verbatim in the analysis prompt."}}},"StartPgUpgradeRequest":{"type":"object","required":["from_version","to_version","from_image","to_image"],"properties":{"from_image":{"type":"string","example":"postgres:16-bookworm"},"from_version":{"type":"string","example":"16"},"to_image":{"type":"string","example":"postgres:17-bookworm"},"to_version":{"type":"string","example":"17"}}},"StartRestoreRequest":{"allOf":[{"$ref":"#/components/schemas/RestoreRequestMode","description":"Requested restore mode. See `RestoreRequestMode`."},{"type":"object","properties":{"backup_engine":{"type":["string","null"],"description":"Engine of the backup when specified by `backup_location`\n(\"postgres\", \"redis\", \"mongodb\", \"s3\"). Ignored when `backup_id`\nis used — we infer from the DB row."},"backup_id":{"type":["integer","null"],"format":"int32","description":"DB id of the backup to restore from. Either `backup_id` or\n`backup_location` MUST be provided. Use `backup_id` when restoring\na backup this Temps instance recorded."},"backup_location":{"type":["string","null"],"description":"Raw S3 URL / key of the backup — used when restoring a backup\ndiscovered by S3 scan (i.e., produced by another Temps instance).\nRequires `backup_engine` and `s3_source_id` to also be set."},"s3_source_id":{"type":["integer","null"],"format":"int32","description":"S3 source the `backup_location` lives in. Ignored when `backup_id`\nis used."}}}]},"StatResponse":{"type":"object","required":["path","exists","is_dir","is_file","size"],"properties":{"exists":{"type":"boolean"},"is_dir":{"type":"boolean"},"is_file":{"type":"boolean"},"path":{"type":"string"},"size":{"type":"integer","format":"int64","minimum":0}}},"StaticBundleResponse":{"type":"object","required":["id","project_id","blob_path","content_type","size_bytes","uploaded_at","created_at"],"properties":{"blob_path":{"type":"string"},"checksum":{"type":["string","null"]},"content_type":{"type":"string"},"created_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"format":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"metadata":{},"original_filename":{"type":["string","null"]},"project_id":{"type":"integer","format":"int32"},"size_bytes":{"type":"integer","format":"int64"},"uploaded_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"}}},"StaticParams":{"type":"object","description":"Static threshold detector: compare the aggregated `value` against `threshold`.","required":["comparator","threshold"],"properties":{"comparator":{"$ref":"#/components/schemas/Comparator","description":"How `value` is compared against `threshold`."},"threshold":{"type":"number","format":"double","description":"The threshold the aggregated value is compared against."}}},"StaticPresetConfig":{"type":"object","description":"Configuration for static site presets (Vite, Next.js, Docusaurus, etc.)\nThese presets build static sites that are served via a web server","properties":{"buildCommand":{"type":["string","null"],"description":"Custom build command (overrides preset default)","example":"npm run build:production"},"buildContext":{"type":["string","null"],"description":"Custom build context path (relative to repository root)\nUseful for monorepo setups where the app is in a subdirectory","example":"./apps/frontend"},"installCommand":{"type":["string","null"],"description":"Custom install command (overrides auto-detected package manager)","example":"npm ci"},"outputDir":{"type":["string","null"],"description":"Custom output directory (overrides preset default)\nCommon values: \"dist\", \"build\", \".next\", \"out\"","example":"dist"}}},"StatsFilters":{"type":"object","description":"Filters for statistics queries","properties":{"client_ip":{"type":["string","null"]},"deployment_id":{"type":["integer","null"],"format":"int32"},"device_type":{"type":["string","null"]},"environment_id":{"type":["integer","null"],"format":"int32"},"has_project":{"type":["boolean","null"],"description":"When true, only count requests that matched a project (project_id IS NOT NULL).\nUsed by the health dashboard so totals match the per-project cards."},"host":{"type":["string","null"]},"is_bot":{"type":["boolean","null"]},"method":{"type":["string","null"]},"project_id":{"type":["integer","null"],"format":"int32"},"request_source":{"type":["string","null"]},"routing_status":{"type":["string","null"]},"status_code":{"type":["integer","null"],"format":"int32"},"status_code_class":{"type":["string","null"],"description":"Filter by status code class (e.g. \"2xx\", \"3xx\", \"4xx\", \"5xx\")"}}},"StatusBucket":{"type":"object","required":["bucket_start","status","total_checks","operational_count","degraded_count","down_count","uptime_percentage"],"properties":{"avg_response_time_ms":{"type":["number","null"],"format":"double"},"bucket_start":{"type":"string","format":"date-time"},"degraded_count":{"type":"integer","format":"int64"},"down_count":{"type":"integer","format":"int64"},"max_response_time_ms":{"type":["number","null"],"format":"double"},"min_response_time_ms":{"type":["number","null"],"format":"double"},"operational_count":{"type":"integer","format":"int64"},"p50_response_time_ms":{"type":["number","null"],"format":"double"},"p95_response_time_ms":{"type":["number","null"],"format":"double"},"p99_response_time_ms":{"type":["number","null"],"format":"double"},"status":{"type":"string"},"total_checks":{"type":"integer","format":"int64"},"uptime_percentage":{"type":"number","format":"double"}}},"StatusBucketedResponse":{"type":"object","required":["monitor_id","interval","buckets"],"properties":{"buckets":{"type":"array","items":{"$ref":"#/components/schemas/StatusBucket"}},"interval":{"type":"string"},"monitor_id":{"type":"integer","format":"int32"}}},"StatusCodeCount":{"type":"object","required":["status_code","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"percentage":{"type":"number","format":"double"},"status_code":{"type":"integer","format":"int32"}}},"StatusCodesQuery":{"type":"object","required":["start_date","end_date","project_id"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"StatusPageOverview":{"type":"object","required":["status","monitors","recent_incidents"],"properties":{"monitors":{"type":"array","items":{"$ref":"#/components/schemas/MonitorStatus"}},"recent_incidents":{"type":"array","items":{"$ref":"#/components/schemas/IncidentResponse"}},"status":{"type":"string"}}},"StepConversionResponse":{"type":"object","required":["step_id","step_name","step_order","completions","conversion_rate","drop_off_rate","average_time_to_complete_seconds"],"properties":{"average_time_to_complete_seconds":{"type":"number","format":"double"},"completions":{"type":"integer","format":"int64","minimum":0},"conversion_rate":{"type":"number","format":"double"},"drop_off_rate":{"type":"number","format":"double"},"step_id":{"type":"integer","format":"int32"},"step_name":{"type":"string"},"step_order":{"type":"integer","format":"int32"}}},"StepResourceType":{"type":"string","description":"What kind of resource a migration step operates on","enum":["project","environment","deployment","environment-variable","service","domain","git-link","other"]},"StepResult":{"type":"object","description":"Result of executing a single migration step","required":["step_id","step_title","success","skipped","message","created_resources","duration_seconds"],"properties":{"created_resources":{"type":"array","items":{"$ref":"#/components/schemas/CreatedResource"},"description":"Resources created by this step"},"duration_seconds":{"type":"number","format":"double","description":"Duration of this step"},"message":{"type":"string","description":"Human-readable message about what happened"},"skipped":{"type":"boolean","description":"Whether this step was skipped"},"step_id":{"type":"string","description":"Step ID (matches `MigrationStep.id`)"},"step_title":{"type":"string","description":"Step title (for display)"},"success":{"type":"boolean","description":"Whether this step succeeded"}}},"StepUpResponse":{"type":"object","required":["expires_at"],"properties":{"expires_at":{"type":"string","format":"date-time","description":"ISO 8601 timestamp after which sensitive actions require verification\nagain."}}},"StopSequence":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]},"StorageQuota":{"type":"object","description":"Quota usage information for a project.","required":["project_id","metrics_bytes","traces_bytes","logs_bytes","total_bytes","limit_bytes","usage_pct"],"properties":{"limit_bytes":{"type":"integer","format":"int64","minimum":0},"logs_bytes":{"type":"integer","format":"int64","minimum":0},"metrics_bytes":{"type":"integer","format":"int64","minimum":0},"project_id":{"type":"integer","format":"int32"},"total_bytes":{"type":"integer","format":"int64","minimum":0},"traces_bytes":{"type":"integer","format":"int64","minimum":0},"usage_pct":{"type":"number","format":"double"}}},"StripeConfig":{"type":"object","properties":{"include_unpriced_charges":{"type":"boolean","description":"When an allowlist is set, should we still ingest charges that\nlack a price reference (e.g. standalone `charge.succeeded` without\na subscription)? Default true — charges don't belong to a SKU."},"metered_mode":{"$ref":"#/components/schemas/MeteredMode","description":"How to compute MRR for metered / tiered / hybrid subscriptions."},"price_allowlist":{"type":"array","items":{"type":"string"},"description":"Only events tagged with one of these Stripe price IDs are ingested.\nEmpty = accept all prices."},"product_allowlist":{"type":"array","items":{"type":"string"},"description":"Only events tagged with one of these Stripe product IDs are\ningested. Empty = accept all products. Combined with\n`price_allowlist` via OR — if either list has a match, accept."}}},"SyncedRepositoryListQuery":{"type":"object","properties":{"direction":{"type":["string","null"]},"git_provider_connection_id":{"type":["integer","null"],"format":"int32"},"language":{"type":["string","null"]},"owner":{"type":["string","null"]},"page":{"type":["integer","null"],"format":"int64","minimum":0},"per_page":{"type":["integer","null"],"format":"int64","minimum":0},"private":{"type":["boolean","null"]},"search":{"type":["string","null"]},"sort":{"type":["string","null"]}}},"SyntaxResult":{"type":"object","description":"Syntax validation result","required":["is_valid_syntax"],"properties":{"domain":{"type":["string","null"],"description":"The domain part of the email","example":"gmail.com"},"is_valid_syntax":{"type":"boolean","description":"Whether the email syntax is valid"},"suggestion":{"type":["string","null"],"description":"Suggested email correction if available"},"username":{"type":["string","null"],"description":"The username part of the email","example":"someone"}}},"TagInfo":{"type":"object","required":["name","commit_sha"],"properties":{"commit_sha":{"type":"string"},"name":{"type":"string"}}},"TagListResponse":{"type":"object","required":["tags"],"properties":{"tags":{"type":"array","items":{"$ref":"#/components/schemas/TagInfo"}}}},"TailLogsRequest":{"type":"object","required":["project_id","service","env"],"properties":{"env":{"type":"string"},"external_service_id":{"type":["integer","null"],"format":"int32","description":"When set, tail an imported/managed external service's logs instead of\na project's (`project_id` is ignored in this mode)."},"levels":{"type":"array","items":{"type":"string"}},"project_id":{"type":"integer","format":"int32","description":"Project ID (integer, as used by the rest of the platform)"},"service":{"type":"string"},"text":{"type":["string","null"]}}},"TargetRecommendation":{"type":"object","description":"The temps/Hetzner target sizing and savings estimate","required":["server_type","vcpus","memory_gb","monthly_eur","fits_single_node","sizing_basis","rationale"],"properties":{"fits_single_node":{"type":"boolean","description":"Whether the workloads fit a single recommended server. When `false`,\nthe rationale explains the multi-node option (temps worker nodes)."},"memory_gb":{"type":"integer","format":"int32","description":"Memory (GB) of the recommended server"},"monthly_eur":{"type":"number","format":"double","description":"Estimated monthly price of the recommended server in EUR"},"monthly_savings_usd":{"type":["number","null"],"format":"double","description":"Estimated monthly savings in USD (current cost minus target cost,\ntreating EUR≈USD for the rough comparison — disclaimed in `notes`).\n`None` when the current cost is unknown."},"rationale":{"type":"string","description":"Human-readable recommendation summary"},"server_type":{"type":"string","description":"Recommended Hetzner server type (e.g. \"cpx32\")"},"sizing_basis":{"type":"string","description":"What the sizing was based on, e.g. \"2× measured usage + temps\nplatform overhead\" or \"resource requests (no metrics available)\""},"vcpus":{"type":"integer","format":"int32","description":"vCPUs of the recommended server"},"yearly_savings_usd":{"type":["number","null"],"format":"double","description":"`monthly_savings_usd × 12`"}}},"TeamListResponse":{"type":"object","required":["teams","total","page","page_size"],"properties":{"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"teams":{"type":"array","items":{"$ref":"#/components/schemas/TeamResponse"}},"total":{"type":"integer","format":"int64","minimum":0}}},"TeamMemberResponse":{"type":"object","required":["id","team_id","user_id","role","added_by","created_at","updated_at"],"properties":{"added_by":{"type":"integer","format":"int32"},"created_at":{"type":"string","format":"date-time","example":"2026-07-30T12:15:47.609192Z"},"id":{"type":"integer","format":"int32"},"role":{"$ref":"#/components/schemas/TeamRole","description":"The source of this member's project-scoped permissions, intersected\nwith `project_team_access.role`."},"team_id":{"type":"integer","format":"int32"},"updated_at":{"type":"string","format":"date-time","example":"2026-07-30T12:15:47.609192Z"},"user_email":{"type":["string","null"],"description":"The member's email, joined from `users`."},"user_id":{"type":"integer","format":"int32"},"user_name":{"type":["string","null"],"description":"The member's display name, joined from `users`. `None` if the\nreferenced user no longer exists."}}},"TeamResponse":{"type":"object","required":["id","name","slug","created_by","created_at","updated_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2026-07-30T12:15:47.609192Z"},"created_by":{"type":"integer","format":"int32"},"description":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"slug":{"type":"string"},"updated_at":{"type":"string","format":"date-time","example":"2026-07-30T12:15:47.609192Z"}}},"TeamRole":{"type":"string","description":"Role a user holds within a team, or that a team holds on a project.\n\nNamed `TeamRole` rather than `Role` to keep it distinct from\n`temps_auth::permissions::Role`, which is the instance-wide role\n(Admin/User/…) attached to a session. The two are orthogonal: the\ninstance-wide role decides whether you may touch a resource *kind* at\nall, `TeamRole` decides what you may do *within a project* you have\nteam access to. See `temps_teams::fixed_role_permissions` for the\nproject-scoped permission set each variant maps to.\n\nStored as a `varchar(32)` rather than a Postgres enum so the role set\ncan evolve in pure migration code without a schema-level enum\nalteration blocking a downgrade.","enum":["owner","admin","deployer","viewer"]},"TemplateResponse":{"type":"object","description":"Response type for a single template","required":["slug","name","git","preset","tags","features","services","env_vars","is_featured"],"properties":{"description":{"type":["string","null"],"description":"Short description"},"env_vars":{"type":"array","items":{"$ref":"#/components/schemas/EnvVarTemplateResponse"},"description":"Environment variables template"},"exposed_port":{"type":["integer","null"],"format":"int32","description":"Container port the prebuilt image listens on (image deploys only)."},"features":{"type":"array","items":{"type":"string"},"description":"Feature highlights"},"git":{"$ref":"#/components/schemas/GitRefResponse","description":"Git repository reference"},"health_check_path":{"type":["string","null"],"description":"HTTP health-check path probed after the container starts (image deploys)."},"image":{"type":["string","null"],"description":"Prebuilt Docker image reference. When set, the one-click deploy pulls and\nruns this image directly (no build); when absent it builds from `git`."},"image_url":{"type":["string","null"],"description":"URL to template image/icon"},"is_featured":{"type":"boolean","description":"Whether the template is featured/promoted"},"name":{"type":"string","description":"Display name"},"preset":{"type":"string","description":"Framework/preset to use"},"screenshot_url":{"type":["string","null"],"description":"URL to a wide screenshot/banner preview of the deployed template.\nAbsent for templates that don't have one captured yet."},"services":{"type":"array","items":{"type":"string"},"description":"Required external services"},"slug":{"type":"string","description":"Unique identifier for the template (used in URLs)"},"tags":{"type":"array","items":{"type":"string"},"description":"Tags/categories for filtering"}}},"TestEmailRequest":{"type":"object","description":"Request body for testing an email provider","required":["from"],"properties":{"from":{"type":"string","description":"Sender email address (must be verified with the provider)","example":"test@example.com"},"from_name":{"type":["string","null"],"description":"Sender display name","example":"My App"}}},"TestEmailResponse":{"type":"object","description":"Response for test email endpoint","required":["success","sent_to"],"properties":{"error":{"type":["string","null"],"description":"Error message if the test failed"},"provider_message_id":{"type":["string","null"],"description":"Provider message ID if successful"},"sent_to":{"type":"string","description":"The email address the test was sent to","example":"user@example.com"},"success":{"type":"boolean","description":"Whether the test email was sent successfully"}}},"TestProviderKeyRequest":{"type":"object","required":["provider","api_key"],"properties":{"api_key":{"type":"string","description":"The raw API key to test"},"base_url":{"type":["string","null"],"description":"Optional custom base URL"},"provider":{"type":"string","description":"Provider ID: \"openai\", \"anthropic\", \"xai\", \"gemini\""}}},"TestProviderKeyResponse":{"type":"object","required":["success","provider","latency_ms"],"properties":{"error":{"type":["string","null"],"description":"Error message if the test failed"},"latency_ms":{"type":"integer","format":"int64","description":"Response time in milliseconds","minimum":0},"provider":{"type":"string"},"success":{"type":"boolean"}}},"TestProviderResponse":{"type":"object","required":["success"],"properties":{"message":{"type":["string","null"]},"success":{"type":"boolean"}}},"TimeBucketStats":{"type":"object","description":"Time bucket statistics response","required":["bucket","request_count","avg_response_time_ms","error_count","total_request_bytes","total_response_bytes"],"properties":{"avg_response_time_ms":{"type":"number","format":"double","description":"Average response time in milliseconds"},"bucket":{"type":"string","description":"Bucket timestamp in RFC3339 format","example":"2025-10-23T12:00:00Z"},"error_count":{"type":"integer","format":"int64","description":"Number of errors (status >= 400)"},"request_count":{"type":"integer","format":"int64","description":"Total number of requests in this bucket"},"total_request_bytes":{"type":"integer","format":"int64","description":"Total request bytes"},"total_response_bytes":{"type":"integer","format":"int64","description":"Total response bytes"}}},"TimeBucketStatsResponse":{"type":"object","description":"Response for time bucket stats","required":["stats","start_time","end_time","bucket_interval"],"properties":{"bucket_interval":{"type":"string"},"end_time":{"type":"string"},"start_time":{"type":"string"},"stats":{"type":"array","items":{"$ref":"#/components/schemas/TimeBucketStats"}}}},"TimeseriesBucket":{"type":"object","required":["bucket","request_count","input_tokens","output_tokens","avg_latency_ms"],"properties":{"avg_latency_ms":{"type":"number","format":"double"},"bucket":{"type":"string","description":"ISO 8601 timestamp"},"input_tokens":{"type":"integer","format":"int64"},"output_tokens":{"type":"integer","format":"int64"},"request_count":{"type":"integer","format":"int64"}}},"TimeseriesQueryParams":{"type":"object","properties":{"bucket":{"type":["string","null"],"description":"Bucket size: \"hour\", \"day\", \"week\" (defaults to \"day\")"},"conversation_id":{"type":["string","null"],"description":"Filter by conversation ID"},"from":{"type":["string","null"],"description":"ISO 8601 start time (defaults to 24h ago)"},"model":{"type":["string","null"],"description":"Filter by model name"},"provider":{"type":["string","null"],"description":"Filter by provider name"},"tags":{"type":["string","null"],"description":"Filter by tags (comma-separated, AND logic)"},"to":{"type":["string","null"],"description":"ISO 8601 end time (defaults to now)"},"user_id":{"type":["integer","null"],"format":"int32","description":"Filter by user ID"}}},"TlsMode":{"type":"string","enum":["None","Starttls","Tls"]},"TodayStatsResponse":{"type":"object","description":"Today's stats response","required":["total_requests","date"],"properties":{"date":{"type":"string","description":"Date for which stats are returned","example":"2025-10-23"},"total_requests":{"type":"integer","format":"int64","description":"Total requests today"}}},"ToggleDeploymentMetricsRequest":{"type":"object","description":"Request body to toggle OTLP metric ingestion for a deployment.","required":["enabled"],"properties":{"enabled":{"type":"boolean","description":"Whether to enable (`true`) or disable (`false`) metric ingestion."},"path":{"type":["string","null"],"description":"Prometheus scrape path (optional, defaults to `/metrics`)."},"port":{"type":["integer","null"],"format":"int32","description":"Prometheus scrape port (optional).","minimum":0}}},"ToggleServiceMetricsRequest":{"type":"object","description":"Request body to toggle metric collection for an external service.","required":["enabled"],"properties":{"enabled":{"type":"boolean","description":"Whether to enable (`true`) or disable (`false`) metric collection."}}},"TokenRenewalRequest":{"type":"object","required":["refresh_token"],"properties":{"refresh_token":{"type":"string"}}},"ToolCallEvent":{"type":"object","description":"Payload for the `tool_call` SSE event: the model is about to run a tool.\nSerialized as compact single-line JSON onto one `data:` line.","required":["id","name","arguments"],"properties":{"arguments":{"type":"string","description":"The raw JSON-args string the model emitted."},"id":{"type":"string"},"name":{"type":"string"}}},"ToolInfo":{"type":"object","description":"One persisted tool invocation + its result, attached to an assistant message.","required":["id","name","arguments"],"properties":{"arguments":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"},"result":{"type":["string","null"]}}},"ToolResultEvent":{"type":"object","description":"Payload for the `tool_result` SSE event: a tool finished running. Serialized\nas compact single-line JSON; `content` is JSON-string-escaped so it stays on\none `data:` line even when long.","required":["id","name","content"],"properties":{"content":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"}}},"TopModelsQueryParams":{"type":"object","properties":{"from":{"type":["string","null"],"description":"ISO 8601 start time (defaults to 24h ago)"},"limit":{"type":["integer","null"],"format":"int64","description":"Max results (defaults to 10)","minimum":0},"tags":{"type":["string","null"],"description":"Filter by tags (comma-separated, AND logic)"},"to":{"type":["string","null"],"description":"ISO 8601 end time (defaults to now)"},"user_id":{"type":["integer","null"],"format":"int32","description":"Filter by user ID"}}},"TraceProjectRef":{"type":"object","description":"All projects that contributed spans to a trace, including their sharing flag.\n\nReturned by `CrossProjectTraceService::find_trace_projects`.","required":["project_id","project_name","project_slug","first_seen","sharing"],"properties":{"first_seen":{"type":"string","format":"date-time"},"project_id":{"type":"integer","format":"int32"},"project_name":{"type":"string"},"project_slug":{"type":"string","description":"URL slug used to link into the project's single-project trace view."},"sharing":{"type":"boolean","description":"Whether this project has `cross_project_trace_sharing = true`."}}},"TraceSummariesResponse":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/TraceSummary"}},"total":{"type":["integer","null"],"format":"int64","description":"Total traces matching the filters, ignoring pagination. Omitted when\nthe request passed `include_total=false`, in which case the caller\nasked not to pay for the count — treat its absence as \"unknown\", not\nas zero.","minimum":0}}},"TraceSummary":{"type":"object","description":"A trace summary for the list view — one row per trace, aggregated from spans.","required":["trace_id","root_span_name","service_name","kind","status_code","start_time","duration_ms","span_count","error_count"],"properties":{"deployment_environment":{"type":["string","null"],"description":"The deployment environment from the root span's resource attributes (e.g. \"production\")."},"duration_ms":{"type":"number","format":"double"},"error_count":{"type":"integer","format":"int64"},"kind":{"$ref":"#/components/schemas/SpanKind"},"root_span_name":{"type":"string"},"service_name":{"type":"string"},"span_count":{"type":"integer","format":"int64"},"start_time":{"type":"string","format":"date-time"},"status_code":{"$ref":"#/components/schemas/SpanStatusCode"},"trace_id":{"type":"string"}}},"TracesResponse":{"type":"object","required":["data","count"],"properties":{"count":{"type":"integer","minimum":0},"data":{"type":"array","items":{"$ref":"#/components/schemas/SpanRecord"}}}},"TrackedLinkResponse":{"type":"object","description":"Tracked link with click count","required":["link_index","original_url","click_count"],"properties":{"click_count":{"type":"integer","format":"int32"},"link_index":{"type":"integer","format":"int32"},"original_url":{"type":"string"}}},"TrackingEventResponse":{"type":"object","description":"Email tracking event","required":["id","email_id","event_type","created_at"],"properties":{"created_at":{"type":"string"},"email_id":{"type":"string"},"event_type":{"type":"string"},"id":{"type":"integer","format":"int64"},"ip_address":{"type":["string","null"]},"link_index":{"type":["integer","null"],"format":"int32"},"link_url":{"type":["string","null"]},"user_agent":{"type":["string","null"]}}},"TriggerAgentRequest":{"type":"object","properties":{"trigger_source_id":{"type":["integer","null"],"format":"int32"},"trigger_source_type":{"type":["string","null"]},"user_context":{"type":["string","null"],"description":"Optional context from the user (e.g. a research topic, bug description, or instructions)."}}},"TriggerDigestResponse":{"type":"object","required":["success","message"],"properties":{"message":{"type":"string"},"success":{"type":"boolean"}}},"TriggerPipelinePayload":{"type":"object","properties":{"branch":{"type":["string","null"]},"commit":{"type":["string","null"]},"environment_id":{"type":["integer","null"],"format":"int32","description":"Optional environment ID - if not provided, will use the project's preview environment"},"tag":{"type":["string","null"]}}},"TriggerPipelineResponse":{"type":"object","required":["message","project_id","environment_id"],"properties":{"branch":{"type":["string","null"]},"commit":{"type":["string","null"]},"environment_id":{"type":"integer","format":"int32"},"message":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"tag":{"type":["string","null"]}}},"TriggerScanRequest":{"type":"object","required":["environment_id"],"properties":{"environment_id":{"type":"integer","format":"int32","description":"Environment ID to scan (uses the current deployment for this environment)","example":1}}},"TriggerScanResponse":{"type":"object","required":["scan_id","status","message"],"properties":{"message":{"type":"string"},"scan_id":{"type":"integer","format":"int32"},"status":{"type":"string"}}},"TtlRequest":{"type":"object","description":"Request to get TTL for a key","required":["key"],"properties":{"key":{"type":"string","description":"The key to check TTL for","example":"session:abc"},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1}}},"TtlResponse":{"type":"object","description":"Response for TTL operation","required":["ttl"],"properties":{"ttl":{"type":"integer","format":"int64","description":"TTL in seconds, -1 if no expiration, -2 if key doesn't exist","example":3600}}},"TxtRecord":{"type":"object","required":["name","value"],"properties":{"name":{"type":"string"},"value":{"type":"string"}}},"UiManifest":{"type":"object","description":"Describes the plugin's embedded UI bundle.","required":["entry_js"],"properties":{"css":{"type":"array","items":{"type":"string"},"description":"CSS files to load"},"entry_js":{"type":"string","description":"JavaScript entry point filename relative to the bundle root"},"routes":{"type":"array","items":{"$ref":"#/components/schemas/UiRoute"},"description":"Client-side routes the plugin handles"}}},"UiRoute":{"type":"object","description":"A client-side route provided by the plugin UI.","required":["path","title"],"properties":{"path":{"type":"string","description":"Route path pattern (e.g., \"/my-plugin\", \"/my-plugin/:id\")"},"title":{"type":"string","description":"Page title for breadcrumbs"}}},"UndrainNodeResponse":{"type":"object","description":"Response after undraining (reactivating) a node.","required":["id","name","status","message"],"properties":{"id":{"type":"integer","format":"int32"},"message":{"type":"string"},"name":{"type":"string"},"status":{"type":"string"}}},"UnifiedTrace":{"type":"object","description":"Merged cross-project trace result (Phase 2 unified waterfall).\n\nSpans are sorted by `start_time ASC`. At most 20 projects and 10,000\nspans total are included; `truncated` / `truncated_projects` signal when\nthe caps were hit.","required":["trace_id","projects","spans","start_time","end_time","total_duration_ms","span_count","error_count","has_redacted_spans","truncated","truncated_projects"],"properties":{"end_time":{"type":"string","format":"date-time"},"error_count":{"type":"integer","minimum":0},"has_redacted_spans":{"type":"boolean","description":"`true` when at least one project has `cross_project_trace_sharing = false`\nand its spans were therefore excluded from the result set."},"projects":{"type":"array","items":{"$ref":"#/components/schemas/ProjectRef"},"description":"Projects that contributed spans to this result set."},"span_count":{"type":"integer","minimum":0},"spans":{"type":"array","items":{"$ref":"#/components/schemas/AnnotatedSpan"},"description":"Annotated, merged span list sorted by `start_time ASC`."},"start_time":{"type":"string","format":"date-time"},"total_duration_ms":{"type":"number","format":"double","description":"Trace wall-clock duration in milliseconds (`end_time – start_time`)."},"trace_id":{"type":"string"},"truncated":{"type":"boolean","description":"`true` when the 20-project or 10,000-span cap was hit."},"truncated_projects":{"type":"array","items":{"type":"integer","format":"int32"},"description":"project_ids excluded due to truncation (most-recent first_seen dropped first)."}}},"UniqueCountsQuery":{"type":"object","description":"Query parameters for unique counts over time frame","required":["start_date","end_date"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32","description":"Optional deployment filter"},"end_date":{"type":"string","format":"date-time","description":"End date for the query range"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Optional environment filter"},"metric":{"type":"string","description":"Metric to count: \"sessions\" (unique sessions), \"visitors\" (unique visitors),\n\"returning_visitors\" (visitors seen before the range), or \"page_views\"\n(total page views) (default: \"sessions\")"},"start_date":{"type":"string","format":"date-time","description":"Start date for the query range"}}},"UniqueCountsResponse":{"type":"object","required":["count"],"properties":{"count":{"type":"integer","format":"int64"}}},"UnsupportedFeature":{"type":"object","description":"A feature from the source platform that cannot be migrated","required":["feature","reason"],"properties":{"alternative":{"type":["string","null"],"description":"Suggested alternative in Temps (if any)"},"feature":{"type":"string","description":"Feature name (e.g., \"Edge Middleware\", \"Serverless Functions\", \"Cron Jobs\")"},"reason":{"type":"string","description":"Why it can't be migrated"}}},"UpdateAdminGateRequest":{"type":"object","required":["allowed_ips","allowed_hosts","trust_forwarded_for"],"properties":{"allowed_hosts":{"type":"array","items":{"type":"string"}},"allowed_ips":{"type":"array","items":{"type":"string"}},"trust_forwarded_for":{"type":"boolean"}}},"UpdateAiProviderRequest":{"type":"object","description":"Body for `PATCH /settings/ai-providers/{provider_id}` — updates\nprovider-scoped settings (just the default model for now) without\ntouching the credential. Keeping credentials out of this shape means\nthe UI can auto-save model changes on select, without forcing the user\nto re-paste their token or config file.\nName-spaced schema name avoids an OpenAPI collision with\n`temps-notifications::UpdateProviderRequest`, which has different fields.\nBoth are exposed as `utoipa::ToSchema`; without the override the merged\nOpenAPI doc would silently shadow one struct with the other and break\ngenerated CLI/web clients.","properties":{"default_model":{"type":["string","null"],"description":"New default model id. `None` or an empty string clears the stored\nvalue so the CLI falls back to its own default."},"max_turns_analysis":{"type":["integer","null"],"format":"int32","description":"Default max turns for the autofixer analysis phase (1–200). `0`\nclears the stored value (built-in default applies); omitted/`None`\nleaves the current value unchanged — so a PATCH that only updates\n`default_model` doesn't wipe the turn settings."},"max_turns_feedback":{"type":["integer","null"],"format":"int32","description":"Default max turns for autofixer feedback rounds (1–200). `0` clears;\nomitted leaves unchanged."},"max_turns_fix":{"type":["integer","null"],"format":"int32","description":"Default max turns for the autofixer fix phase (1–200). `0` clears;\nomitted leaves unchanged."}}},"UpdateAiProviderResponse":{"type":"object","required":["provider_id"],"properties":{"default_model":{"type":["string","null"]},"max_turns_analysis":{"type":["integer","null"],"format":"int32"},"max_turns_feedback":{"type":["integer","null"],"format":"int32"},"max_turns_fix":{"type":["integer","null"],"format":"int32"},"provider_id":{"type":"string"}}},"UpdateAlertRuleRequest":{"type":"object","properties":{"cooldown_minutes":{"type":["integer","null"],"format":"int32"},"enabled":{"type":["boolean","null"]},"environment_filter":{"type":["integer","null"],"format":"int32"},"error_level_filter":{"type":["string","null"]},"name":{"type":["string","null"]},"notification_priority":{"type":["string","null"]},"trigger_config":{},"trigger_type":{"type":["string","null"]}}},"UpdateApiKeyRequest":{"type":"object","properties":{"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"is_active":{"type":["boolean","null"]},"name":{"type":["string","null"]},"permissions":{"type":["array","null"],"items":{"type":"string"},"example":["projects:read","deployments:read"]}}},"UpdateAutomaticDeployRequest":{"type":"object","required":["automatic_deploy"],"properties":{"automatic_deploy":{"type":"boolean"}}},"UpdateBackupScheduleRequest":{"type":"object","description":"Request body for updating an existing backup schedule via `PATCH /api/backups/schedules/{id}`.\n\nAll fields are optional; only present fields are updated. Absent fields\nleave the corresponding column unchanged.","properties":{"description":{"type":["string","null"],"description":"New human-readable description. Pass an empty string `\"\"` to clear."},"enabled":{"type":["boolean","null"],"description":"Enable or disable the schedule. Skipped when `None`."},"include_control_plane":{"type":["boolean","null"],"description":"Toggle whether the control-plane backup is produced on every run."},"max_runtime_secs":{"type":["integer","null"],"format":"int64","description":"Per-schedule wall-clock timeout override (seconds).\n\n- `None` (field absent) — leave current value unchanged\n- `Some(None)` (field present, JSON `null`) — clear override; fall back to engine default\n- `Some(Some(n))` — set to `n` seconds (must be >= 60)"},"name":{"type":["string","null"],"description":"New schedule name. Skipped when `None`. Must not be empty if provided."},"retention_period":{"type":["integer","null"],"format":"int32","description":"Days to retain backups produced by this schedule. Must be >= 1."},"schedule_expression":{"type":["string","null"],"description":"New cron expression. When changed, `next_run` is recomputed."},"tags":{"type":["array","null"],"items":{"type":"string"},"description":"Replace the full tag list. Skipped when `None`."},"target_all_services":{"type":["boolean","null"],"description":"Toggle between \"back up every database\" (`true`) and \"back up only\nthe explicit list\" (`false`). When set to `true`, the server clears\nthe explicit membership rows for this schedule."}}},"UpdateBlobRequest":{"type":"object","description":"Request to update Blob service configuration","properties":{"docker_image":{"type":["string","null"],"description":"Docker image to use (e.g., \"rustfs/rustfs:1.0.0-alpha.98\")","example":"rustfs/rustfs:1.0.0-alpha.98"}}},"UpdateBlobResponse":{"type":"object","description":"Response after updating Blob service","required":["success","message","status"],"properties":{"message":{"type":"string","description":"Human-readable message","example":"Blob service updated successfully"},"status":{"$ref":"#/components/schemas/BlobStatusResponse","description":"Current status"},"success":{"type":"boolean","description":"Whether the operation succeeded","example":true}}},"UpdateCloudflareProviderRequest":{"type":"object","required":["config"],"properties":{"config":{"$ref":"#/components/schemas/CloudflareConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":["string","null"]}}},"UpdateConfigBody":{"type":"object","properties":{"config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ProviderConfig","description":"Typed provider configuration. Setting `config` to `null` clears\nthe stored config back to the accept-everything default. The\nconfig's `provider` tag must match the integration's provider."}]}}},"UpdateCustomDomainRequest":{"type":"object","properties":{"branch":{"type":["string","null"]},"domain":{"type":["string","null"]},"environment_id":{"type":["integer","null"],"format":"int32"},"redirect_to":{"type":["string","null"]},"service_name":{"type":["string","null"],"description":"Docker Compose service name this domain routes to (empty string clears it)"},"status_code":{"type":["integer","null"],"format":"int32"}}},"UpdateDashboardRequest":{"type":"object","properties":{"layout":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DashboardLayout"}]},"name":{"type":["string","null"]}}},"UpdateDeploymentConfigRequest":{"type":"object","properties":{"automaticDeploy":{"type":["boolean","null"]},"cpuLimit":{"type":["integer","null"],"format":"int32"},"cpuRequest":{"type":["integer","null"],"format":"int32"},"crossArchitectureBuilds":{"type":["boolean","null"],"description":"Build one image per architecture the eligible nodes run. Off by\ndefault; environments inherit this and may override it. Cross-builds\nare emulated on the control plane and substantially slower, so they are\nopted into rather than triggered by cluster topology."},"exposedPort":{"type":["integer","null"],"format":"int32"},"memoryLimit":{"type":["integer","null"],"format":"int32"},"memoryRequest":{"type":["integer","null"],"format":"int32"},"performanceMetricsEnabled":{"type":["boolean","null"]},"replicas":{"type":["integer","null"],"format":"int32"},"security":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SecurityConfig"}]},"sessionRecordingEnabled":{"type":["boolean","null"]}}},"UpdateDeploymentTokenRequest":{"type":"object","properties":{"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"is_active":{"type":["boolean","null"]},"name":{"type":["string","null"]},"permissions":{"type":["array","null"],"items":{"type":"string"},"example":["visitors:enrich","emails:send"]}}},"UpdateDnsProviderRequest":{"type":"object","description":"Request to update a DNS provider","properties":{"credentials":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DnsProviderCredentials","description":"New credentials"}]},"description":{"type":["string","null"],"description":"New description"},"is_active":{"type":["boolean","null"],"description":"Active status"},"name":{"type":["string","null"],"description":"New name"}}},"UpdateEmailProviderRequest":{"type":"object","description":"Request body for `PATCH /email-providers/{id}`.\n\nAll fields are optional. Omit any field to leave it unchanged. The\n`provider_type` is immutable — to switch providers, delete the row and\ncreate a new one. For credentials, supplying any credential variant\nre-encrypts the stored blob; omitting them preserves the existing secret\n(so operators can rename without re-typing passwords).","properties":{"is_active":{"type":["boolean","null"]},"name":{"type":["string","null"],"example":"My AWS SES"},"region":{"type":["string","null"],"example":"us-east-1"},"scaleway_credentials":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ScalewayCredentialsRequest"}]},"ses_credentials":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SesCredentialsRequest"}]},"smtp_credentials":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SmtpCredentialsRequest"}]},"sns_topic_arn":{"type":["string","null"],"description":"Rotate or clear the exact SNS topic allowed for this SES provider.\nOmit to preserve it, send `null` to clear it, or send a string to set it."}}},"UpdateEnvironmentSettingsRequest":{"type":"object","properties":{"anti_affinity":{"type":["boolean","null"],"description":"Anti-affinity: spread replicas across different nodes.\nWhen enabled, the scheduler avoids placing two replicas of the same\nenvironment on the same node. Defaults to `true`."},"attack_mode":{"type":["boolean","null"],"description":"Per-environment CAPTCHA attack-mode override (tri-state):\n- absent → leave the current override unchanged\n- JSON `null` → clear the override (inherit the project-level setting)\n- `true`/`false` → override the project setting for this environment"},"automatic_deploy":{"type":["boolean","null"],"description":"Enable/disable automatic deployments for this environment"},"branch":{"type":["string","null"]},"cpu_limit":{"type":["integer","null"],"format":"int32","description":"Maximum (limit) CPU in microcores. Send JSON `null` to clear → \"no limit\".\nAbsent leaves the current value unchanged."},"cpu_request":{"type":["integer","null"],"format":"int32","description":"Minimum (request) CPU in microcores. Send JSON `null` to clear (no request).\nAbsent leaves the current value unchanged."},"cross_architecture_builds":{"type":["boolean","null"],"description":"Build one image per architecture the eligible nodes run (overrides the\nproject-level setting). Off by default: cross-architecture builds are\nemulated on the control plane and substantially slower, so they are\nopted into per environment rather than triggered by cluster topology."},"exposed_port":{"type":["integer","null"],"format":"int32","description":"Port exposed by the container (overrides project-level port for this environment)\n\nPriority order for port resolution:\n1. Image EXPOSE directive (auto-detected from built image)\n2. This environment-level exposed_port (overrides project setting)\n3. Project-level exposed_port (fallback)\n4. Default: 3000","example":8080},"force_https":{"type":["boolean","null"],"description":"Per-environment HTTP→HTTPS redirect override (tri-state):\n- absent → leave the current override unchanged\n- JSON `null` → clear the override (inherit the proxy default, which\n redirects only when the host has an active TLS certificate)\n- `true` → always redirect plain HTTP to HTTPS for this environment,\n even when no local certificate exists (TLS terminated upstream)\n- `false` → never redirect this environment, even when a certificate does\n exist\n\nRequests under `/.well-known/acme-challenge/` are never redirected\nregardless of this setting, so ACME HTTP-01 validation always completes."},"idle_timeout_seconds":{"type":["integer","null"],"format":"int32","description":"Seconds of inactivity before stopping containers (60-86400). Default: 300."},"memory_limit":{"type":["integer","null"],"format":"int32","description":"Maximum (limit) memory in MB. Send JSON `null` to clear → \"no limit\".\nAbsent leaves the current value unchanged."},"memory_request":{"type":["integer","null"],"format":"int32","description":"Minimum (request) memory in MB. Send JSON `null` to clear (no request).\nAbsent leaves the current value unchanged."},"on_demand":{"type":["boolean","null"],"description":"Enable on-demand mode (scale-to-zero). Containers are stopped after\nidle_timeout_seconds of no traffic and started on the next request."},"password":{"type":["string","null"],"description":"Set a password to protect this environment. The proxy will show an HTML\npassword form before allowing access. The password is bcrypt-hashed\nserver-side and never stored in plaintext.\nSend an empty string to remove password protection."},"performance_metrics_enabled":{"type":["boolean","null"],"description":"Enable/disable performance metrics collection"},"protected":{"type":["boolean","null"],"description":"When true, git pushes do NOT auto-deploy to this environment.\nDeployments must be promoted from another environment."},"replicas":{"type":["integer","null"],"format":"int32"},"security":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SecurityConfig","description":"Security configuration for this environment (overrides project-level settings)"}]},"session_recording_enabled":{"type":["boolean","null"],"description":"Enable/disable session recording"},"target_labels":{"description":"Label selector for node-based scheduling (overrides project-level setting).\nSame key with array value -> OR, different keys -> AND.\nExample: `{\"region\": [\"us\", \"asia\"], \"gpu\": \"true\"}`"},"target_nodes":{"type":["array","null"],"items":{"type":"integer","format":"int32"},"description":"Optional list of node IDs to deploy to (overrides project-level setting)"},"wake_timeout_seconds":{"type":["integer","null"],"format":"int32","description":"Max seconds to wait for containers to start on wake (5-120). Default: 30."}}},"UpdateEnvironmentSubdomainRequest":{"type":"object","description":"Request to rename an environment's auto-managed subdomain.\n\nThe subdomain is the host label inserted in front of the platform's\npreview domain (e.g. `myapp` in `myapp.preview.temps.sh`). Renaming\nreplaces the previous subdomain entirely — the old hostname stops\nresolving immediately after this request succeeds.","required":["subdomain"],"properties":{"subdomain":{"type":"string","description":"New subdomain label. Must be a DNS-safe slug (lowercase letters,\ndigits, and hyphens, 1-63 characters). The value is slugified\nserver-side, so casing and disallowed characters are normalized.","example":"myapp"}}},"UpdateEnvironmentVariableRequest":{"type":"object","required":["key","environment_ids"],"properties":{"environment_ids":{"type":"array","items":{"type":"integer","format":"int32"}},"include_in_preview":{"type":"boolean"},"is_secret":{"type":["boolean","null"],"description":"Optional secret-flag transition.\n- `Some(true)` promotes a regular var to a secret.\n- `Some(false)` is rejected if the row is already secret (one-way flag).\n- `None` (omitted) leaves the flag unchanged."},"key":{"type":"string"},"value":{"type":["string","null"],"description":"New plaintext value. `None` (omitted) keeps the existing ciphertext,\nwhich is the only way to edit a secret env var without re-typing its\nvalue (e.g. changing which environments it applies to)."}}},"UpdateErrorGroupRequest":{"type":"object","required":["status"],"properties":{"assigned_to":{"type":["string","null"]},"status":{"type":"string"}}},"UpdateExternalServiceRequest":{"type":"object","required":["parameters"],"properties":{"docker_image":{"type":["string","null"],"description":"Docker image to use for the service (e.g., \"gotempsh/postgres-walg:18-bookworm\", \"timescale/timescaledb-ha:pg18\")\nWhen provided, the service will be recreated with the new image while preserving data"},"parameters":{"type":"object","additionalProperties":{},"propertyNames":{"type":"string"}}}},"UpdateFlagRequest":{"type":"object","properties":{"client_visible":{"type":["boolean","null"]},"default_value":{"description":"Must match the flag's existing `value_type`."},"description":{"type":["string","null"],"description":"Tri-state: absent leaves it, `null` clears it, a string sets it."}}},"UpdateGitSettingsRequest":{"type":"object","required":["main_branch","repo_owner","repo_name","directory"],"properties":{"directory":{"type":"string"},"git_provider_connection_id":{"type":["integer","null"],"format":"int32"},"git_url":{"type":["string","null"],"description":"Git clone URL for public repositories"},"is_public_repo":{"type":["boolean","null"],"description":"Whether this is a public repository (no git provider connection needed)"},"main_branch":{"type":"string"},"preset":{"type":["string","null"]},"preset_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PresetConfigSchema","description":"Preset-specific configuration (e.g., Dockerfile path for Docker preset)\n\nExample for Dockerfile preset:\n```json\n{\n \"dockerfilePath\": \"docker/Dockerfile\",\n \"buildContext\": \"./api\"\n}\n```"}]},"repo_name":{"type":"string"},"repo_owner":{"type":"string"}}},"UpdateIncidentStatusRequest":{"type":"object","required":["status","message"],"properties":{"message":{"type":"string"},"status":{"type":"string"}}},"UpdateIpAccessControlRequest":{"type":"object","description":"Request to update an IP access control rule","properties":{"action":{"type":["string","null"],"description":"Optional new action"},"ip_address":{"type":["string","null"],"description":"Optional new IP address"},"reason":{"type":["string","null"],"description":"Optional new reason"}}},"UpdateKvRequest":{"type":"object","description":"Request to update KV service configuration","properties":{"docker_image":{"type":["string","null"],"description":"Docker image to use (e.g., \"gotempsh/redis-walg:8-bookworm\")","example":"gotempsh/redis-walg:8-bookworm"}}},"UpdateKvResponse":{"type":"object","description":"Response after updating KV service","required":["success","message","status"],"properties":{"message":{"type":"string","description":"Status message","example":"KV service updated successfully"},"status":{"$ref":"#/components/schemas/KvStatusResponse","description":"Current service status"},"success":{"type":"boolean","description":"Whether the operation succeeded"}}},"UpdateManagedDomainApiRequest":{"type":"object","description":"Request to update a managed domain's settings.","properties":{"auto_manage":{"type":["boolean","null"],"description":"Toggle automatic DNS management for this domain."},"generated_hostname_mode":{"type":["string","null"],"description":"`\"standard\"` or `\"flat\"`. Persisted as-is; switching to `\"flat\"` does not\nrecompute existing hostnames — use the apply endpoint for that."},"sync_generated_records":{"type":["boolean","null"],"description":"Toggle DNS record sync for this domain."}}},"UpdateMcpRequest":{"type":"object","required":["config"],"properties":{"config":{"type":"object"},"description":{"type":["string","null"]},"name":{"type":["string","null"]}}},"UpdateMemberRoleRequest":{"type":"object","description":"The new fixed role for an existing membership.","required":["role"],"properties":{"role":{"$ref":"#/components/schemas/TeamRole"}}},"UpdateMetricAlertRequest":{"type":"object","properties":{"aggregation":{"type":["string","null"]},"detection_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DetectionConfig","description":"Replaces the detector wholesale when present (absent = leave unchanged)."}]},"dynamic_alerts":{"type":["boolean","null"],"description":"Toggles per-series (\"dynamic\") alerting (absent = leave unchanged)."},"enabled":{"type":["boolean","null"]},"for_duration_secs":{"type":["integer","null"],"format":"int32"},"group_by":{"type":["array","null"],"items":{"type":"string"},"description":"Replaces the group_by keys wholesale when present (absent = leave unchanged)."},"grouped_notification_threshold":{"type":["integer","null"],"format":"int32","description":"Updates the notification-grouping threshold (absent = leave unchanged)."},"label_filters":{"type":["array","null"],"items":{"type":"array","items":false,"prefixItems":[{"type":"string"},{"type":"string"}]},"description":"Replaces the label filters wholesale when present (absent = leave unchanged)."},"max_series":{"type":["integer","null"],"format":"int32","description":"Updates the dynamic-alerting cardinality cap (absent = leave unchanged)."},"metric_name":{"type":["string","null"]},"name":{"type":["string","null"]},"severity":{"type":["string","null"]},"window_secs":{"type":["integer","null"],"format":"int32"}}},"UpdateNotificationEmailProviderRequest":{"type":"object","required":["config"],"properties":{"config":{"$ref":"#/components/schemas/EmailConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":["string","null"]}}},"UpdateOidcProviderRequest":{"type":"object","properties":{"client_id":{"type":["string","null"]},"client_secret":{"type":["string","null"]},"default_role":{"type":["string","null"]},"enabled":{"type":["boolean","null"]},"group_claim":{"type":["string","null"]},"issuer_url":{"type":["string","null"]},"jit_provisioning":{"type":["boolean","null"]},"name":{"type":["string","null"]},"role_claim":{"type":["string","null"]},"scopes":{"type":["string","null"]},"template":{"type":["string","null"]},"trust_idp_email":{"type":["boolean","null"]}}},"UpdatePreferencesRequest":{"type":"object","required":["preferences"],"properties":{"preferences":{"$ref":"#/components/schemas/NotificationPreferencesResponse"}}},"UpdateProjectSecretRequest":{"type":"object","description":"Request to update a project secret. The `value` field is optional — omit it\nto rotate only the environment scoping / preview flag without touching the\nciphertext.","properties":{"environment_ids":{"type":"array","items":{"type":"integer","format":"int32"}},"include_in_preview":{"type":"boolean"},"value":{"type":["string","null"],"description":"New plaintext value, <= 1 MiB. Omit to keep the existing value."}}},"UpdateProjectSettingsRequest":{"type":"object","properties":{"ai_alert_summaries_enabled":{"type":["boolean","null"],"description":"Opt in to AI summarization of metric alert notifications (ADR-021)."},"ai_debug_chat_enabled":{"type":["boolean","null"],"description":"Opt in to AI debugging chat, e.g. on deployment failures (ADR-023)."},"ai_write_actions_enabled":{"type":["boolean","null"],"description":"Opt in to AI propose-then-confirm write capability."},"attack_mode":{"type":["boolean","null"],"description":"Enable/disable attack mode (CAPTCHA protection) for all project environments"},"cross_project_trace_sharing":{"type":["boolean","null"],"description":"ADR-027 Phase 3 opt-out: set to false to suppress this project's traces\nfrom appearing in cross-project discovery results. Default true (consistent\nwith the OSS global-observability model). Omit to leave unchanged."},"directory":{"type":["string","null"]},"enable_preview_environments":{"type":["boolean","null"],"description":"Enable automatic preview environment creation for each branch"},"error_source_context_enabled":{"type":["boolean","null"],"description":"Opt in to native error-tracking source context (source-file upload +\nsource code shown in stack traces)."},"error_source_root":{"type":["string","null"],"description":"Set the auto-capture source root (relative to the checkout). Send an\nempty string to clear it back to the build-context default. Omit to\nleave unchanged."},"git_provider_connection_id":{"type":["integer","null"],"format":"int32"},"main_branch":{"type":["string","null"]},"preset":{"type":["string","null"]},"preset_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PresetConfigSchema","description":"Preset-specific configuration (e.g., Dockerfile path for Docker preset)\n\nExample for Dockerfile preset:\n```json\n{\n \"dockerfilePath\": \"docker/Dockerfile\",\n \"buildContext\": \"./api\"\n}\n```"}]},"preview_envs_idle_timeout_seconds":{"type":["integer","null"],"format":"int32","description":"Idle timeout (seconds, 60..=86400) for on-demand preview environments."},"preview_envs_on_demand":{"type":["boolean","null"],"description":"When true, newly-created preview environments default to on-demand mode."},"preview_envs_wake_timeout_seconds":{"type":["integer","null"],"format":"int32","description":"Wake timeout (seconds, 5..=120) for on-demand preview environments."},"repo_name":{"type":["string","null"]},"repo_owner":{"type":["string","null"]},"slug":{"type":["string","null"]}}},"UpdateProviderCredentialsRequest":{"type":"object","description":"Partial-update payload for provider credentials. Every field is optional;\nonly the fields the user re-enters are applied. The server validates that\nthe fields supplied make sense for the provider's current auth_method\n(e.g. `app_id` + `private_key` only apply to GitHub Apps).","properties":{"app_id":{"type":["string","null"],"description":"Application ID (GitHub App integer as string; GitLab App string)."},"app_secret":{"type":["string","null"],"description":"GitLab App secret (not used by GitHub App — use `client_secret`)."},"client_id":{"type":["string","null"],"description":"OAuth client ID (GitLab OAuth, GitHub App)."},"client_secret":{"type":["string","null"],"description":"OAuth client secret (GitLab OAuth, GitHub App)."},"private_key":{"type":["string","null"],"description":"GitHub App private key (PEM)."},"redirect_uri":{"type":["string","null"],"description":"OAuth redirect URI (GitLab OAuth / GitLab App)."},"token":{"type":["string","null"],"description":"PAT for PAT-type providers."},"webhook_secret":{"type":["string","null"],"description":"GitHub App webhook secret."}}},"UpdateProviderKeyRequest":{"type":"object","properties":{"api_key":{"type":["string","null"]},"base_url":{"type":["string","null"],"description":"Double-Option: absent = leave unchanged, present-null = clear (revert to\nthe provider's default endpoint), present-value = set."},"default_model":{"type":["string","null"],"description":"Double-Option: absent = leave unchanged, present-null = clear the pinned\nmodel (revert to the per-provider default), present-value = set."},"display_name":{"type":["string","null"]},"is_active":{"type":["boolean","null"]}}},"UpdateProviderRequest":{"type":"object","properties":{"config":{},"enabled":{"type":["boolean","null"]},"name":{"type":["string","null"]}}},"UpdateRouteRequest":{"type":"object","required":["host","port","enabled"],"properties":{"enabled":{"type":"boolean"},"host":{"type":"string"},"port":{"type":"integer","format":"int32"},"route_type":{"type":["string","null"],"description":"Route type: \"http\" (default) matches on HTTP Host header,\n\"tls\" matches on TLS SNI hostname for TCP passthrough"}}},"UpdateS3SourceRequest":{"type":"object","properties":{"access_key_id":{"type":["string","null"],"description":"Optional new access key ID","example":"AKIAXXXXXXXXXXXXXXXX"},"bucket_name":{"type":["string","null"],"description":"Optional new bucket name"},"bucket_path":{"type":["string","null"],"description":"Optional new bucket path"},"endpoint":{"type":["string","null"],"description":"Optional new endpoint URL for S3-compatible services","example":"http://minio.example.com:9000"},"force_path_style":{"type":["boolean","null"],"description":"Optional new path-style addressing setting","example":true},"name":{"type":["string","null"],"description":"Optional new name for the source"},"region":{"type":["string","null"],"description":"Optional new region"},"secret_key":{"type":["string","null"],"description":"Optional new secret key"}}},"UpdateSecretBody":{"type":"object","required":["signing_secret"],"properties":{"signing_secret":{"type":"string","description":"New signing secret from the provider's dashboard. Encrypted at\nrest; never returned in any API response."}}},"UpdateSelfRequest":{"type":"object","properties":{"email":{"type":["string","null"],"example":"john.doe@example.com"},"name":{"type":["string","null"],"example":"John Doe"}}},"UpdateSessionDurationRequest":{"type":"object","required":["duration"],"properties":{"duration":{"type":"integer","format":"int32"}}},"UpdateSessionDurationResponse":{"type":"object","required":["message"],"properties":{"message":{"type":"string"}}},"UpdateSkillRequest":{"type":"object","properties":{"content":{"type":["string","null"]},"description":{"type":["string","null"]},"name":{"type":["string","null"]}}},"UpdateSlackProviderRequest":{"type":"object","required":["config"],"properties":{"config":{"$ref":"#/components/schemas/SlackConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":["string","null"]}}},"UpdateSpeedMetricsPayload":{"type":"object","description":"Update speed metrics payload for late-loading metrics","properties":{"cls":{"type":["number","null"],"format":"float","description":"Cumulative Layout Shift (score)"},"inp":{"type":["number","null"],"format":"float","description":"Interaction to Next Paint (milliseconds)"}}},"UpdateStatusResponse":{"type":"object","description":"Result of the background release-update check, driving the web console's\nupgrade banner. All optional fields are set together iff\n`update_available` is true.","required":["update_available","docs_url"],"properties":{"channel":{"type":["string","null"],"description":"Channel the install tracks: `stable` or `beta`."},"checked_at":{"type":["string","null"],"description":"When the check that found the update ran (ISO 8601, UTC)."},"current_version":{"type":["string","null"],"description":"Version tag of the running binary, e.g. `v0.1.0-beta.45`."},"docs_url":{"type":"string","description":"Docs page with upgrade instructions. Always present so the UI links\nthe same page regardless of update state."},"latest_version":{"type":["string","null"],"description":"Newest published tag on this install's channel."},"release_url":{"type":["string","null"],"description":"Release-notes page (GitHub release) for the newer version."},"update_available":{"type":"boolean","description":"True when a newer release than the running binary has been published\non this install's channel."}}},"UpdateTeamRequest":{"type":"object","properties":{"description":{"type":["string","null"]},"name":{"type":["string","null"]}}},"UpdateTokenRequest":{"type":"object","required":["access_token"],"properties":{"access_token":{"type":"string"},"refresh_token":{"type":["string","null"]}}},"UpdateTokenResponse":{"type":"object","required":["connection_id","message","is_active"],"properties":{"connection_id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"message":{"type":"string"}}},"UpdateUserRequest":{"type":"object","properties":{"email":{"type":["string","null"],"example":"john.doe@example.com"},"name":{"type":["string","null"],"example":"John Doe"}}},"UpdateWebhookProviderRequest":{"type":"object","required":["config"],"properties":{"config":{"$ref":"#/components/schemas/WebhookConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":["string","null"]}}},"UpdateWebhookRequestBody":{"type":"object","properties":{"enabled":{"type":["boolean","null"],"description":"Whether the webhook is enabled"},"events":{"type":["array","null"],"items":{"type":"string"},"description":"Event types to subscribe to"},"secret":{"type":["string","null"],"description":"Secret for HMAC signature verification"},"url":{"type":["string","null"],"description":"Target URL for webhook delivery"}}},"UpgradeExternalServiceRequest":{"type":"object","required":["docker_image"],"properties":{"docker_image":{"type":"string","description":"Docker image to upgrade to (e.g., \"gotempsh/postgres-walg:18-bookworm\")\nThis will trigger pg_upgrade for PostgreSQL or equivalent upgrade procedures for other services","example":"gotempsh/postgres-walg:18-bookworm"}}},"UpgradeRequest":{"type":"object","required":["image"],"properties":{"image":{"type":"string","description":"Image reference to pull and run (e.g.\n`ghcr.io/gotempsh/temps-preview-gateway:latest`). Empty resets to default."}}},"UpsertAgentRequest":{"type":"object","properties":{"ai_model":{"type":["string","null"],"description":"Preferred model identifier for the CLI. `Some(\"\")` clears the stored value."},"ai_provider":{"type":["string","null"]},"ai_provider_key_id":{"type":["integer","null"],"format":"int32"},"api_key":{"type":["string","null"],"description":"Plain-text API key — will be encrypted before storage"},"branch_prefix":{"type":["string","null"]},"config_repo_branch":{"type":["string","null"],"description":"Branch of the config repo to use (default: \"main\")."},"config_repo_url":{"type":["string","null"],"description":"Private config repo containing .claude/ directory (skills, MCP, plugins)."},"cooldown_minutes":{"type":["integer","null"],"format":"int32"},"daily_budget_cents":{"type":["integer","null"],"format":"int32"},"deliverable":{"type":["string","null"]},"description":{"type":["string","null"]},"enabled":{"type":["boolean","null"]},"max_turns":{"type":["integer","null"],"format":"int32"},"mcp_servers_config":{"description":"MCP servers config (Claude Code settings.json mcpServers format).\nCredential-bearing legacy inline objects are write-only: normal reads\nmask them, and updates must omit this field to preserve existing values."},"name":{"type":["string","null"]},"prompt":{"type":["string","null"]},"sandbox_enabled":{"type":["boolean","null"]},"skills_config":{"description":"Skills config as JSON array."},"slug":{"type":["string","null"]},"timeout_seconds":{"type":["integer","null"],"format":"int32"},"tools_config":{"description":"Tools config as JSON array. Custom-tool webhook URLs and headers are\nwrite-only; omit this field on update to preserve them."},"trigger_config":{"description":"Trigger configuration JSON: { \"error\": { \"new_issue\": true, \"regression\": true }, \"manual\": true }"}}},"UpsertSecretRequest":{"type":"object","required":["name","value"],"properties":{"description":{"type":["string","null"]},"mount_path":{"type":["string","null"],"description":"Required for \"file\" type secrets — absolute path inside the sandbox"},"name":{"type":"string"},"secret_type":{"type":"string","description":"\"env\" (environment variable) or \"file\" (written to mount_path)"},"value":{"type":"string"}}},"UptimeDataPoint":{"type":"object","required":["timestamp","status"],"properties":{"error_message":{"type":["string","null"]},"response_time_ms":{"type":["integer","null"],"format":"int32"},"status":{"type":"string"},"timestamp":{"type":"string","format":"date-time"}}},"UptimeHistoryResponse":{"type":"object","required":["monitor_id","uptime_data"],"properties":{"monitor_id":{"type":"integer","format":"int32"},"uptime_data":{"type":"array","items":{"$ref":"#/components/schemas/UptimeDataPoint"}}}},"UsageFilter":{"type":"object","description":"Filters for querying AI usage data.\n\nCost bounds are expressed in microcents (the unit stored in\n`estimated_cost_microcents`). At most one of `gte`/`gt` and one of\n`lte`/`lt` is meaningful per query; if both are set the stricter wins\nnaturally because they are ANDead together.","properties":{"conversation_id":{"type":["string","null"]},"cost_gt":{"type":["integer","null"],"format":"int64","description":"Cost strictly greater-than, in microcents."},"cost_gte":{"type":["integer","null"],"format":"int64","description":"Cost greater-than-or-equal, in microcents."},"cost_lt":{"type":["integer","null"],"format":"int64","description":"Cost strictly less-than, in microcents."},"cost_lte":{"type":["integer","null"],"format":"int64","description":"Cost less-than-or-equal, in microcents."},"model":{"type":["string","null"]},"provider":{"type":["string","null"]},"status":{"type":["integer","null"],"format":"int32","description":"Filter by HTTP status code (exact match)."},"tags":{"type":["string","null"],"description":"Comma-separated tags to filter by (AND logic)."},"tokens_gt":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) strictly greater-than."},"tokens_gte":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) greater-than-or-equal."},"tokens_lt":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) strictly less-than."},"tokens_lte":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) less-than-or-equal."},"user_id":{"type":["integer","null"],"format":"int32"}}},"UsageInfo":{"type":"object","required":["prompt_tokens","completion_tokens","total_tokens"],"properties":{"completion_tokens":{"type":"integer","format":"int64"},"prompt_tokens":{"type":"integer","format":"int64"},"total_tokens":{"type":"integer","format":"int64"}}},"UsageLogEntry":{"type":"object","required":["id","timestamp","provider","model","input_tokens","output_tokens","latency_ms","estimated_cost_microcents","status","is_streaming","is_byok","tags"],"properties":{"conversation_id":{"type":["string","null"]},"estimated_cost_microcents":{"type":"integer","format":"int64"},"id":{"type":"integer","format":"int64"},"input_tokens":{"type":"integer","format":"int64"},"is_byok":{"type":"boolean"},"is_streaming":{"type":"boolean"},"latency_ms":{"type":"integer","format":"int32"},"model":{"type":"string"},"output_tokens":{"type":"integer","format":"int64"},"provider":{"type":"string"},"request_id":{"type":["string","null"]},"status":{"type":"integer","format":"int32"},"tags":{"type":"array","items":{"type":"string"}},"timestamp":{"type":"string"},"trace_id":{"type":["string","null"]}}},"UsageLogPage":{"type":"object","description":"A page of recent usage log entries plus the total count for pagination.","required":["entries","total"],"properties":{"entries":{"type":"array","items":{"$ref":"#/components/schemas/UsageLogEntry"},"description":"The usage log entries for the requested page."},"total":{"type":"integer","format":"int64","description":"Total number of entries matching the filter (across all pages)."}}},"UsageQueryParams":{"type":"object","properties":{"conversation_id":{"type":["string","null"],"description":"Filter by conversation ID"},"from":{"type":["string","null"],"description":"ISO 8601 start time (defaults to 24h ago)"},"model":{"type":["string","null"],"description":"Filter by model name"},"provider":{"type":["string","null"],"description":"Filter by provider name"},"tags":{"type":["string","null"],"description":"Filter by tags (comma-separated, AND logic)"},"to":{"type":["string","null"],"description":"ISO 8601 end time (defaults to now)"},"user_id":{"type":["integer","null"],"format":"int32","description":"Filter by user ID"}}},"UsageSource":{"type":"string","description":"How the \"actual usage\" numbers were obtained","enum":["metrics-api","requests-only","unavailable"]},"UsageSummary":{"type":"object","required":["total_requests","total_input_tokens","total_output_tokens","total_tokens","avg_latency_ms","total_cost_microcents","error_count","streaming_count","byok_count"],"properties":{"avg_latency_ms":{"type":"number","format":"double"},"byok_count":{"type":"integer","format":"int64"},"error_count":{"type":"integer","format":"int64"},"streaming_count":{"type":"integer","format":"int64"},"total_cost_microcents":{"type":"integer","format":"int64"},"total_input_tokens":{"type":"integer","format":"int64"},"total_output_tokens":{"type":"integer","format":"int64"},"total_requests":{"type":"integer","format":"int64"},"total_tokens":{"type":"integer","format":"int64"}}},"UserResponse":{"type":"object","required":["id","username","name","avatar_url","mfa_enabled","role"],"properties":{"avatar_url":{"type":"string"},"email":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"mfa_enabled":{"type":"boolean"},"name":{"type":"string"},"role":{"type":"string","description":"User's role (e.g., \"admin\", \"user\", \"demo\")"},"username":{"type":"string"}}},"ValidateEmailRequest":{"type":"object","description":"Request body for validating an email address","required":["email"],"properties":{"email":{"type":"string","description":"Email address to validate","example":"someone@gmail.com"}},"additionalProperties":false},"ValidateEmailResponse":{"type":"object","description":"Complete email validation response","required":["email","is_reachable","syntax","mx","misc","smtp"],"properties":{"email":{"type":"string","description":"The email address that was validated","example":"someone@gmail.com"},"is_reachable":{"$ref":"#/components/schemas/ReachabilityStatus","description":"Overall reachability status: safe, risky, invalid, or unknown"},"misc":{"$ref":"#/components/schemas/MiscResult","description":"Miscellaneous validation result"},"mx":{"$ref":"#/components/schemas/MxResult","description":"MX record validation result"},"smtp":{"$ref":"#/components/schemas/SmtpResult","description":"SMTP validation result"},"syntax":{"$ref":"#/components/schemas/SyntaxResult","description":"Syntax validation result"}}},"ValidationLevel":{"type":"string","description":"Validation severity level","enum":["info","warning","error","critical"]},"ValidationReport":{"type":"object","description":"Complete validation report","required":["results","overall_status","summary"],"properties":{"overall_status":{"$ref":"#/components/schemas/ValidationStatus","description":"Overall status"},"results":{"type":"array","items":{"$ref":"#/components/schemas/ValidationResult"},"description":"All validation results"},"summary":{"$ref":"#/components/schemas/ValidationSummary","description":"Summary statistics"}}},"ValidationResponse":{"type":"object","required":["connection_id","is_valid","message"],"properties":{"connection_id":{"type":"integer","format":"int32"},"is_valid":{"type":"boolean"},"message":{"type":"string"}}},"ValidationResult":{"type":"object","description":"Result of a validation check","required":["rule_id","rule_name","level","passed","message","affected_resources"],"properties":{"affected_resources":{"type":"array","items":{"type":"string"},"description":"Affected resources/fields"},"level":{"$ref":"#/components/schemas/ValidationLevel","description":"Validation level"},"message":{"type":"string","description":"Message describing the result"},"passed":{"type":"boolean","description":"Whether the validation passed"},"remediation":{"type":["string","null"],"description":"Suggested remediation (if failed)"},"rule_id":{"type":"string","description":"Rule that was checked"},"rule_name":{"type":"string","description":"Human-readable rule name"}}},"ValidationStatus":{"type":"string","description":"Overall validation status","enum":["passed","passed-with-warnings","failed-with-warnings","failed"]},"ValidationSummary":{"type":"object","description":"Validation summary statistics","required":["total_count","passed_count","failed_count","info_count","warning_count","error_count","critical_count"],"properties":{"critical_count":{"type":"integer","description":"Critical-level results","minimum":0},"error_count":{"type":"integer","description":"Error-level results","minimum":0},"failed_count":{"type":"integer","description":"Validations that failed","minimum":0},"info_count":{"type":"integer","description":"Info-level results","minimum":0},"passed_count":{"type":"integer","description":"Validations that passed","minimum":0},"total_count":{"type":"integer","description":"Total validations run","minimum":0},"warning_count":{"type":"integer","description":"Warning-level results","minimum":0}}},"VerifyMfaRequest":{"type":"object","required":["code"],"properties":{"code":{"type":"string"}}},"VerifyStepUpRequest":{"type":"object","required":["code"],"properties":{"code":{"type":"string","description":"Current TOTP value or an unused recovery code."}}},"ViewItem":{"type":"object","required":["label","value"],"properties":{"label":{"type":"string","format":"date-time"},"value":{"type":"integer","format":"int64"}}},"ViewsOverTime":{"type":"object","required":["items","metric","present_index"],"properties":{"comparison_labels":{"type":["array","null"],"items":{"type":"string"}},"comparison_plot":{"type":["array","null"],"items":{"type":"integer","format":"int64"}},"full_intervals":{"type":["array","null"],"items":{"type":"string"}},"items":{"type":"array","items":{"$ref":"#/components/schemas/ViewItem"}},"metric":{"type":"string"},"present_index":{"type":"integer","minimum":0}}},"ViewsOverTimeQuery":{"type":"object","required":["start_date","end_date","project_id"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"VisitorDetails":{"type":"object","required":["id","visitor_id","project_id","environment_id","first_seen","last_seen","is_crawler"],"properties":{"city":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"crawler_name":{"type":["string","null"]},"custom_data":{},"environment_id":{"type":"integer","format":"int32"},"first_channel":{"type":["string","null"],"description":"Marketing channel from the first visit (e.g. \"Organic Search\", \"Direct\")"},"first_referrer":{"type":["string","null"],"description":"Full referrer URL from the visitor's first session"},"first_referrer_hostname":{"type":["string","null"],"description":"Hostname extracted from first_referrer"},"first_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"id":{"type":"integer","format":"int32"},"ip_address":{"type":["string","null"]},"ip_address_id":{"type":["integer","null"],"format":"int32"},"is_crawler":{"type":"boolean"},"is_eu":{"type":["boolean","null"]},"last_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"latitude":{"type":["number","null"],"format":"double"},"longitude":{"type":["number","null"],"format":"double"},"project_id":{"type":"integer","format":"int32"},"region":{"type":["string","null"]},"timezone":{"type":["string","null"]},"user_agent":{"type":["string","null"]},"visitor_id":{"type":"string"}}},"VisitorFacetValue":{"type":"object","description":"A single facet value with its visitor count. Used to populate filter\ndropdowns on the visitors page (e.g. \"Germany — 1,234 visitors\").","required":["value","count"],"properties":{"code":{"type":["string","null"],"description":"Optional secondary code for the value. Currently only populated for\nthe `country` facet, where it carries the 2-letter ISO country code\nso the UI can render a flag without re-mapping."},"count":{"type":"integer","format":"int64","description":"Distinct visitor count matching this value in the current segment."},"value":{"type":"string","description":"The dimension value (e.g. \"United States\", \"Chrome\", \"google.com\").\n`None` is encoded as the literal string \"Direct\" for referrer and as\nthe empty string for the rest."}}},"VisitorFacets":{"type":"object","description":"All filter dropdown contents in one response. Each list is the top N\nvalues for that dimension within the current date range and segment\n(excluding the dimension being queried so the dropdown still shows\nalternatives when a value is already selected).","required":["country","region","city","channel","referrer"],"properties":{"channel":{"type":"array","items":{"$ref":"#/components/schemas/VisitorFacetValue"}},"city":{"type":"array","items":{"$ref":"#/components/schemas/VisitorFacetValue"}},"country":{"type":"array","items":{"$ref":"#/components/schemas/VisitorFacetValue"}},"referrer":{"type":"array","items":{"$ref":"#/components/schemas/VisitorFacetValue"}},"region":{"type":"array","items":{"$ref":"#/components/schemas/VisitorFacetValue"}}}},"VisitorFacetsQuery":{"allOf":[{"$ref":"#/components/schemas/VisitorSegmentFilters"},{"type":"object","required":["start_date","end_date","project_id"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"has_activity_only":{"type":["boolean","null"]},"include_crawlers":{"type":["boolean","null"]},"per_facet_limit":{"type":["integer","null"],"format":"int32","description":"Maximum number of values returned per dimension (default: 50, max: 200)."},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}}],"description":"Query parameters for the visitor-facets endpoint. Mirrors the shape of\n`VisitorsListQuery` so the same segment filters apply — facet counts are\nalways computed against the *currently filtered* visitor pool, minus the\ndimension being aggregated."},"VisitorInfo":{"type":"object","required":["id","visitor_id","project_id","environment_id","first_seen","last_seen","is_crawler"],"properties":{"city":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"crawler_name":{"type":["string","null"]},"current_page":{"type":["string","null"],"description":"Most recent page path visited by this visitor"},"custom_data":{},"environment_id":{"type":"integer","format":"int32"},"first_channel":{"type":["string","null"],"description":"Marketing channel from the first visit (e.g. \"Organic Search\", \"Direct\")"},"first_referrer":{"type":["string","null"],"description":"Full referrer URL from the visitor's first session"},"first_referrer_hostname":{"type":["string","null"],"description":"Hostname extracted from first_referrer"},"first_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"id":{"type":"integer","format":"int32"},"ip_address":{"type":["string","null"]},"ip_address_id":{"type":["integer","null"],"format":"int32"},"is_crawler":{"type":"boolean"},"is_eu":{"type":["boolean","null"]},"last_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"latitude":{"type":["number","null"],"format":"double"},"longitude":{"type":["number","null"],"format":"double"},"project_id":{"type":"integer","format":"int32"},"region":{"type":["string","null"]},"timezone":{"type":["string","null"]},"user_agent":{"type":["string","null"]},"visitor_id":{"type":"string"}}},"VisitorJourneyQuery":{"type":"object","required":["project_id"],"properties":{"limit_sessions":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"}}},"VisitorJourneyResponse":{"type":"object","description":"Complete visitor journey response","required":["visitor_id","total_sessions","total_events","sessions"],"properties":{"sessions":{"type":"array","items":{"$ref":"#/components/schemas/JourneySession"},"description":"Sessions with their events, ordered newest first"},"total_events":{"type":"integer","format":"int64","description":"Total number of events across all sessions"},"total_sessions":{"type":"integer","format":"int64","description":"Total number of sessions"},"visitor_id":{"type":"integer","format":"int32","description":"Visitor internal ID"}}},"VisitorLocationsQuery":{"type":"object","required":["start_date","end_date","project_id"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"granularity":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/LocationGranularity"}]},"limit":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"VisitorRecord":{"type":"object","required":["id","visitor_id","project_id","created_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"custom_data":{},"id":{"type":"integer","format":"int32"},"project_id":{"type":"integer","format":"int32"},"visitor_id":{"type":"string"}}},"VisitorSegmentFilters":{"type":"object","description":"Optional segment filters for [`VisitorsListQuery`]. Each filter narrows the\nresult set to visitors who match the given dimension value within the date\nrange. All filters resolve against `visitor` / `ip_geolocations` — by\ndesign we never touch the events hypertable here so filtering stays fast\nregardless of event volume.","properties":{"filter_channel":{"type":["string","null"],"description":"First-touch marketing channel (matches `visitor.first_channel`)"},"filter_city":{"type":["string","null"],"description":"Geolocation city (matches `ip_geolocations.city`)"},"filter_country":{"type":["string","null"],"description":"Geolocation country (matches `ip_geolocations.country`)"},"filter_referrer":{"type":["string","null"],"description":"First-touch referrer hostname (matches `visitor.first_referrer_hostname`)"},"filter_region":{"type":["string","null"],"description":"Geolocation region (matches `ip_geolocations.region`)"}}},"VisitorSessionsQuery":{"type":"object","required":["project_id"],"properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"}}},"VisitorSessionsResponse":{"type":"object","required":["visitor_id","sessions","total_sessions"],"properties":{"sessions":{"type":"array","items":{"$ref":"#/components/schemas/SessionSummary"}},"total_sessions":{"type":"integer","format":"int64"},"visitor_id":{"type":"string"}}},"VisitorStats":{"type":"object","required":["visitor_id","first_seen","last_seen","total_sessions","total_page_views","total_events","average_session_duration","bounce_rate","engagement_rate","top_pages","top_referrers","devices_used","locations"],"properties":{"average_session_duration":{"type":"number","format":"double"},"bounce_rate":{"type":"number","format":"double"},"devices_used":{"type":"array","items":{"type":"string"}},"engagement_rate":{"type":"number","format":"double"},"first_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"last_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"locations":{"type":"array","items":{"$ref":"#/components/schemas/LocationInfo"}},"top_pages":{"type":"array","items":{"$ref":"#/components/schemas/PageVisit"}},"top_referrers":{"type":"array","items":{"type":"string"}},"total_events":{"type":"integer","format":"int64"},"total_page_views":{"type":"integer","format":"int64"},"total_sessions":{"type":"integer","format":"int64"},"visitor_id":{"type":"integer","format":"int32"}}},"VisitorWithGeolocation":{"type":"object","required":["id","visitor_id","project_id","environment_id","first_seen","last_seen","is_crawler"],"properties":{"city":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"crawler_name":{"type":["string","null"]},"custom_data":{},"environment_id":{"type":"integer","format":"int32"},"first_channel":{"type":["string","null"],"description":"Marketing channel from the first visit (e.g. \"Organic Search\", \"Direct\")"},"first_referrer":{"type":["string","null"],"description":"Full referrer URL from the visitor's first session"},"first_referrer_hostname":{"type":["string","null"],"description":"Hostname extracted from first_referrer"},"first_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"id":{"type":"integer","format":"int32"},"ip_address":{"type":["string","null"]},"is_crawler":{"type":"boolean"},"is_eu":{"type":["boolean","null"]},"last_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"latitude":{"type":["number","null"],"format":"double"},"longitude":{"type":["number","null"],"format":"double"},"project_id":{"type":"integer","format":"int32"},"region":{"type":["string","null"]},"timezone":{"type":["string","null"]},"user_agent":{"type":["string","null"]},"visitor_id":{"type":"string"}}},"VisitorsListQuery":{"allOf":[{"$ref":"#/components/schemas/VisitorSegmentFilters"},{"type":"object","required":["start_date","end_date","project_id"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"has_activity_only":{"type":["boolean","null"],"description":"Filter to only include visitors with recorded activity (events/sessions).\nWhen true, excludes \"ghost\" visitors that have no events."},"include_crawlers":{"type":["boolean","null"]},"limit":{"type":["integer","null"],"format":"int32"},"offset":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}}]},"VisitorsResponse":{"type":"object","required":["visitors","total_count","filtered_count"],"properties":{"filtered_count":{"type":"integer","format":"int64"},"total_count":{"type":"integer","format":"int64"},"visitors":{"type":"array","items":{"$ref":"#/components/schemas/VisitorInfo"}}}},"VolumeMount":{"type":"object","description":"Volume mount in deployment","required":["source","destination","read_only","type"],"properties":{"destination":{"type":"string","description":"Destination path in container"},"read_only":{"type":"boolean","description":"Read-only flag"},"source":{"type":"string","description":"Source (volume name or path)"},"type":{"$ref":"#/components/schemas/VolumeType","description":"Volume type"}}},"VolumeType":{"type":"string","description":"Volume type","enum":["bind","volume","tmpfs"]},"VulnerabilityResponse":{"type":"object","required":["id","scan_id","vulnerability_id","package_name","installed_version","severity","title","created_at"],"properties":{"class":{"type":["string","null"],"example":"os-pkgs"},"created_at":{"type":"string","example":"2025-12-08T12:15:47.609192Z"},"cvss_score":{"type":["number","null"],"format":"float"},"description":{"type":["string","null"]},"fixed_version":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"installed_version":{"type":"string"},"last_modified_date":{"type":["string","null"],"example":"2025-12-08T12:15:47.609192Z"},"package_name":{"type":"string"},"primary_url":{"type":["string","null"]},"published_date":{"type":["string","null"],"example":"2025-12-08T12:15:47.609192Z"},"references":{},"scan_id":{"type":"integer","format":"int32"},"severity":{"type":"string"},"target":{"type":["string","null"],"example":"alpine:3.18 (alpine 3.18.0)"},"title":{"type":"string"},"type":{"type":["string","null"],"example":"alpine"},"vulnerability_id":{"type":"string"}}},"WalWarning":{"oneOf":[{"type":"object","description":"`pg_wal` is significantly larger than `max_wal_size`.","required":["pg_wal_bytes","max_wal_size_bytes","ratio","kind"],"properties":{"kind":{"type":"string","enum":["wal_bloat"]},"max_wal_size_bytes":{"type":"integer","format":"int64"},"pg_wal_bytes":{"type":"integer","format":"int64"},"ratio":{"type":"number","format":"double"}}},{"type":"object","description":"A replication slot is holding WAL it's not consuming.","required":["slot_name","retained_bytes","active","kind"],"properties":{"active":{"type":"boolean"},"kind":{"type":"string","enum":["stale_slot"]},"retained_bytes":{"type":"integer","format":"int64"},"slot_name":{"type":"string"}}},{"type":"object","description":"`archive_status/*.ready` count exceeds threshold — `archive_command`\nis either failing or running slower than WAL generation.","required":["ready_count","kind"],"properties":{"kind":{"type":"string","enum":["archive_backlog"]},"ready_count":{"type":"integer","format":"int64"}}},{"type":"object","description":"`archive_mode = on` but `archive_command` is empty / `/bin/true`.\nWAL accumulates forever waiting for a destination that never accepts.","required":["kind"],"properties":{"kind":{"type":"string","enum":["archive_mode_without_command"]}}},{"type":"object","description":"Oldest WAL segment is older than `WAL_NOT_RECYCLED_AGE_SECS`.\nIndependent signal: something is blocking recycling even if total\nsize hasn't exploded yet.","required":["oldest_age_secs","kind"],"properties":{"kind":{"type":"string","enum":["wal_not_recycled"]},"oldest_age_secs":{"type":"integer","format":"int64"}}}],"description":"One actionable warning surfaced to the UI.\n\nEach variant carries the data needed to render a remediation hint without\nthe frontend re-querying anything."},"WalWarningSeverity":{"type":"string","enum":["warning","critical"]},"WebhookConfig":{"type":"object","description":"Configuration for a generic webhook notification provider","required":["url"],"properties":{"headers":{"type":"object","description":"Custom headers to include in the request (e.g., for authentication tokens)","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"},"example":{"Authorization":"Bearer your-token","X-Custom-Header":"custom-value"}},"method":{"type":"string","description":"HTTP method to use (POST, PUT, PATCH). Defaults to POST.","example":"POST"},"timeout_secs":{"type":"integer","format":"int64","description":"Request timeout in seconds. Defaults to 30.","example":30,"minimum":0},"url":{"type":"string","description":"The URL to send webhook requests to","example":"https://api.example.com/notifications"}}},"WebhookDeliveryResponse":{"type":"object","required":["id","webhook_id","event_type","event_id","payload","success","attempt_number","created_at"],"properties":{"attempt_number":{"type":"integer","format":"int32"},"created_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"delivered_at":{"type":["string","null"],"format":"date-time"},"error_message":{"type":["string","null"]},"event_id":{"type":"string"},"event_type":{"type":"string"},"id":{"type":"integer","format":"int32"},"payload":{"type":"string","description":"JSON payload that was sent to the webhook endpoint","example":{"event_type":"deployment.succeeded","data":{"deployment_id":123}}},"status_code":{"type":["integer","null"],"format":"int32"},"success":{"type":"boolean"},"webhook_id":{"type":"integer","format":"int32"}}},"WebhookResponse":{"type":"object","required":["id","project_id","url","events","enabled","has_secret","created_at","updated_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"enabled":{"type":"boolean"},"events":{"type":"array","items":{"type":"string"}},"has_secret":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"project_id":{"type":"integer","format":"int32"},"updated_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"url":{"type":"string"}}},"WebhookTriggerRequest":{"allOf":[{"description":"Arbitrary JSON payload from the caller. Passed to the agent as user_context."}]},"WebhookTriggerResponse":{"type":"object","required":["run_id","status"],"properties":{"run_id":{"type":"integer","format":"int32"},"status":{"type":"string"}}},"WorkflowDryRunRequest":{"type":"object","required":["yaml"],"properties":{"cpu_limit":{"type":["number","null"],"format":"double","description":"Optional CPU override applied after parsing YAML (clamped server-side).\nWhen `Some`, this takes precedence over `cpu_limit` inside the YAML —\nlets the CLI pass `--cpu` without rewriting the YAML text."},"error_group_id":{"type":["integer","null"],"format":"int32","description":"Optional error group to link this dry-run to. When set, the executor's\n`load_error_context` path injects `{{error_type}}` / `{{error_message}}`\n/ `{{stack_trace}}` into the prompt — same behaviour as a committed\nworkflow triggered with `trigger_source_type = \"error_group\"`. Must\nbelong to `project_id` (handler enforces)."},"memory_limit_mb":{"type":["integer","null"],"format":"int64","description":"Optional memory override in MB (clamped server-side). Same precedence\nrule as `cpu_limit`.","minimum":0},"user_context":{"type":["string","null"],"description":"Optional context appended to the prompt (e.g. \"test against staging\nonly\"). Mirrors `TriggerAgentRequest.user_context`."},"yaml":{"type":"string","description":"Full WorkflowYamlConfig as YAML text. Server validates and re-serializes\nbefore storing on the run row."}}},"WorkloadDescriptor":{"type":"object","description":"Brief descriptor for discovered workloads (used in listing)","required":["id","workload_type","status","labels"],"properties":{"created_at":{"type":["string","null"],"format":"date-time","description":"Creation timestamp"},"id":{"$ref":"#/components/schemas/WorkloadId","description":"Unique ID in source system"},"image":{"type":["string","null"],"description":"Image/build reference (for containers)"},"labels":{"type":"object","description":"Labels/tags from source system","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"name":{"type":["string","null"],"description":"Workload name (if any)"},"status":{"$ref":"#/components/schemas/WorkloadStatus","description":"Current status"},"workload_type":{"$ref":"#/components/schemas/WorkloadType","description":"Workload type (container, function, static-site, etc.)"}}},"WorkloadId":{"type":"string","description":"Unique identifier for a workload in the source system"},"WorkloadStatus":{"type":"string","description":"Workload status in source system","enum":["running","paused","stopped","exited","failed","deployed","building","unknown"]},"WorkloadType":{"type":"string","description":"Workload type","enum":["container","function","static-site","server-side-app","worker","database","message-queue","cache","cron-job","other"]},"WriteFileBody":{"type":"object","required":["path","contents_b64"],"properties":{"contents_b64":{"type":"string","description":"File contents, base64-encoded. Required — lets callers ship binary\ndata over JSON without charset games."},"mode":{"type":["integer","null"],"format":"int32","description":"Unix permission mask (e.g. 0o644). Defaults to 0o644 when absent.","minimum":0},"path":{"type":"string","description":"Absolute path inside the sandbox. Must start with `/`."}},"additionalProperties":false},"WriteFilesBody":{"type":"object","required":["files"],"properties":{"files":{"type":"array","items":{"$ref":"#/components/schemas/WriteFileBody"},"description":"List of files to write. Each entry must include an absolute\n`path` and base64-encoded `contents_b64`. Empty list is a no-op."}},"additionalProperties":false},"WriteFilesResponse":{"type":"object","required":["written"],"properties":{"written":{"type":"integer","description":"Number of files successfully written before the first failure\n(if any). On full success this equals `files.len()`.","minimum":0}}},"ZoneListResponse":{"type":"object","description":"Zone list response","required":["zones"],"properties":{"zones":{"type":"array","items":{"$ref":"#/components/schemas/DnsZone"}}}}},"securitySchemes":{"bearer_auth":{"type":"http","scheme":"bearer","description":"Bearer token authentication. Use format: `Bearer `. Supports API keys (starting with `tk_`), CLI tokens, and session tokens."}}},"tags":[{"name":"Events","description":"Analytics events tracking endpoints"},{"name":"Metrics","description":"Analytics metrics collection endpoints including performance web vitals"},{"name":"Funnels","description":"Funnel management endpoints"},{"name":"Analytics","description":"Analytics and session replay management"},{"name":"Performance","description":"Performance metrics management"},{"name":"geo","description":"Geolocation API endpoints"},{"name":"Platform","description":"Platform information and compatibility"},{"name":"Teams","description":"Teams and project-scoped access"},{"name":"Git Providers","description":"Git provider management endpoints"},{"name":"Repositories","description":"Repository management endpoints"},{"name":"Public Repositories","description":"Endpoints for accessing public repositories without authentication. Supports GitHub and GitLab."},{"name":"Notification Providers","description":"Notification provider management endpoints"},{"name":"Notification Preferences","description":"User notification preferences and settings"},{"name":"DNS Providers","description":"DNS provider management endpoints"},{"name":"Internal DNS","description":"Per-node DNS resolver sync (ADR-011)"},{"name":"Domains","description":"Domain management endpoints"},{"name":"Email Providers","description":"Email provider management endpoints"},{"name":"Email Domains","description":"Email domain management and verification"},{"name":"Emails","description":"Email sending and retrieval"},{"name":"Email Tracking","description":"Email open and click tracking"},{"name":"Email Validation","description":"Email address validation and verification"},{"name":"Webhooks","description":"Webhook management endpoints"},{"name":"Webhook Deliveries","description":"Webhook delivery history and retry endpoints"},{"name":"External Services","description":"External service integration endpoints"},{"name":"External Services - Query","description":"Data querying and exploration endpoints"},{"name":"Metrics","description":"Time-series metrics and alert rule endpoints"},{"name":"KV Store","description":"Key-Value storage operations"},{"name":"KV Management","description":"KV service management operations"},{"name":"Blob","description":"Blob storage operations"},{"name":"Blob Management","description":"Blob service management operations"},{"name":"Feature Flags","description":"Runtime configuration that changes without a redeploy"},{"name":"Environments","description":"Environment management operations"},{"name":"Secrets","description":"File-mounted secrets (/run/secrets/)"},{"name":"Projects","description":"Project management endpoints"},{"name":"Presets","description":"Available deployment presets"},{"name":"Templates","description":"Project template endpoints"},{"name":"Custom Domains","description":"Custom domain management for projects"},{"name":"error-tracking","description":"Error tracking data fetching endpoints"},{"name":"Vulnerability Scans","description":"Vulnerability scan management endpoints"},{"name":"Agents","description":"Autonomous AI agents, autofixer (interactive AI debugging), skills/MCP definitions, and preview gateway management."},{"name":"Crons","description":"Cron jobs management API"},{"name":"Sandboxes","description":"Standalone sandbox API (`/v1/sandboxes/*`) for running isolated containers."},{"name":"Logs","description":"Log search, context, live tail, and retention management"},{"name":"Imports","description":"Import workloads from external sources"},{"name":"Status Page","description":"Status page and monitoring endpoints"},{"name":"OTel Ingest","description":"OTLP/HTTP ingest endpoints (protobuf)"},{"name":"OTel","description":"Query endpoints for the monitoring UI"},{"name":"GenAI","description":"GenAI agent activity tracing endpoints"},{"name":"Alarms","description":"Unified alarm history — list, summarise, acknowledge, resolve"},{"name":"Authentication","description":"Authentication and authorization endpoints"},{"name":"Users","description":"User management endpoints"},{"name":"Backups","description":"Backup management endpoints"},{"name":"Restore","description":"External service restore operations"},{"name":"Revenue","description":"Per-project revenue tracking integrations and analytics"},{"name":"Observability","description":"Unified observability event stream — runtime logs, requests, spans, errors, revenue"},{"name":"AI Gateway","description":"OpenAI-compatible chat, embeddings, and model endpoints"},{"name":"AI Gateway Admin","description":"Provider key management endpoints"},{"name":"AI Gateway Usage","description":"Usage analytics and reporting endpoints"},{"name":"AI Gateway Pricing","description":"Model pricing endpoints"},{"name":"API Keys","description":"API key management endpoints"},{"name":"Load Balancer","description":"Load balancer management endpoints"},{"name":"IP Access Control","description":"IP access control management endpoints"},{"name":"Files","description":"Static file serving endpoints"},{"name":"External Plugins","description":"External plugin management and discovery"}]} +{"openapi":"3.1.0","info":{"title":"Temps","description":"An API for managing projects, deployments, and infrastructure resources","contact":{"name":"Temps Support","url":"https://temps.sh"},"version":"1.0.0"},"servers":[{"url":"/api","description":"Base path for all API endpoints"}],"paths":{"/.well-known/temps.json":{"get":{"tags":["Platform"],"summary":"Get platform information","operationId":"get_platform_info","responses":{"200":{"description":"Successfully retrieved platform information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlatformInfo"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/0/organizations/{org_slug}/chunk-upload/":{"get":{"tags":["sentry-compat"],"summary":"Chunk upload options (stub for sentry-cli compatibility).","description":"sentry-cli checks this endpoint to determine if chunk-based upload is supported.\nWe return a response indicating that chunk upload is NOT supported, which forces\nsentry-cli to fall back to the standard file-by-file upload.","operationId":"chunk_upload_options","parameters":[{"name":"org_slug","in":"path","description":"Organization slug (ignored)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Chunk upload options","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryChunkUploadResponse"}}}}}}},"/0/organizations/{org_slug}/releases/":{"post":{"tags":["sentry-compat"],"summary":"Create a release (stub for sentry-cli compatibility).","description":"sentry-cli calls this before uploading files. Since Temps implicitly creates\nreleases when source maps are uploaded, this is a no-op that returns the\nexpected response format.","operationId":"create_release","parameters":[{"name":"org_slug","in":"path","description":"Organization slug (ignored in single-tenant mode)","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryCreateReleaseRequest"}}},"required":true},"responses":{"201":{"description":"Release created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryReleaseResponse"}}}},"401":{"description":"Unauthorized"}}}},"/0/projects/{org_slug}/{project_slug}/releases/":{"post":{"tags":["sentry-compat"],"summary":"Create a release for a specific project (stub for sentry-cli compatibility).","description":"sentry-cli calls this endpoint (instead of /organizations/.../releases/) when\nboth SENTRY_ORG and SENTRY_PROJECT env vars are set. Behaves identically to\nthe organizations endpoint but validates the project slug.","operationId":"create_project_release","parameters":[{"name":"org_slug","in":"path","description":"Organization slug (ignored in single-tenant mode)","required":true,"schema":{"type":"string"}},{"name":"project_slug","in":"path","description":"Project slug or numeric ID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryCreateReleaseRequest"}}},"required":true},"responses":{"201":{"description":"Release created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryReleaseResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Project not found"}}}},"/0/projects/{org_slug}/{project_slug}/releases/{version}/":{"put":{"tags":["sentry-compat"],"summary":"Finalize a release (stub for sentry-cli compatibility).","description":"sentry-cli calls `releases finalize` after uploading source maps. This sets\nthe dateReleased on the release. Since Temps stores source maps independently\nof releases, this is a no-op that returns the expected response.","operationId":"finalize_project_release","parameters":[{"name":"org_slug","in":"path","description":"Organization slug (ignored)","required":true,"schema":{"type":"string"}},{"name":"project_slug","in":"path","description":"Project slug or numeric ID","required":true,"schema":{"type":"string"}},{"name":"version","in":"path","description":"Release version to finalize","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Release finalized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryReleaseResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Project not found"}}}},"/0/projects/{org_slug}/{project_slug}/releases/{version}/files/":{"get":{"tags":["sentry-compat"],"summary":"List files for a release.","description":"Returns all source maps stored for a specific release in sentry-cli compatible format.","operationId":"list_release_files","parameters":[{"name":"org_slug","in":"path","description":"Organization slug (ignored)","required":true,"schema":{"type":"string"}},{"name":"project_slug","in":"path","description":"Project slug or numeric ID","required":true,"schema":{"type":"string"}},{"name":"version","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of release files","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SentryReleaseFileResponse"}}}}},"401":{"description":"Unauthorized"},"404":{"description":"Project not found"}}},"post":{"tags":["sentry-compat"],"summary":"Upload a source map file for a release.","description":"Accepts the same multipart format as the Sentry release files API.\nThe `name` field should be the URL path of the file (e.g., `~/dist/bundle.js.map`).\n\nThe route has a 50 MiB body limit applied at the router level (Fix #4).\nA per-field size check provides an additional defense-in-depth layer.","operationId":"upload_release_file","parameters":[{"name":"org_slug","in":"path","description":"Organization slug (ignored)","required":true,"schema":{"type":"string"}},{"name":"project_slug","in":"path","description":"Project slug or numeric ID","required":true,"schema":{"type":"string"}},{"name":"version","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"201":{"description":"File uploaded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryReleaseFileResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"404":{"description":"Project not found"},"413":{"description":"Source map file exceeds the 50 MiB per-field limit"}}}},"/_temps/event":{"post":{"tags":["Metrics"],"summary":"Record analytics event","operationId":"record_event_metrics","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventMetricsPayload"}}},"required":true},"responses":{"204":{"description":"Event recorded successfully"},"400":{"description":"Bad request"},"500":{"description":"Internal server error"}}}},"/_temps/session-replay/events":{"post":{"tags":["Analytics"],"summary":"Add events to existing session replay","operationId":"add_session_replay_events","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionReplayEventsRequest"}}},"required":true},"responses":{"200":{"description":"Events added successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddEventsResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Session not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/_temps/session-replay/init":{"post":{"tags":["Analytics"],"summary":"Initialize session replay with metadata","operationId":"init_session_replay","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionReplayInitRequest"}}},"required":true},"responses":{"201":{"description":"Session initialized successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionReplayInitResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/_temps/speed":{"post":{"tags":["Performance"],"summary":"Record performance metrics from client","operationId":"record_speed_metrics","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpeedMetricsPayload"}}},"required":true},"responses":{"204":{"description":"Metrics recorded successfully"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Host not found in route table","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/_temps/speed/update":{"post":{"tags":["Performance"],"summary":"Update late performance metrics","operationId":"update_speed_metrics","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSpeedMetricsPayload"}}},"required":true},"responses":{"204":{"description":"Metrics updated successfully"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Host not found or metrics not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/admin/gate-settings":{"get":{"tags":["AdminGate"],"operationId":"get_admin_gate","responses":{"200":{"description":"Current admin gate config","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminGateResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["AdminGate"],"operationId":"patch_admin_gate","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAdminGateRequest"}}},"required":true},"responses":{"200":{"description":"Updated admin gate config","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminGateResponse"}}}},"400":{"description":"Invalid IP/CIDR/host"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"409":{"description":"Env-overridden or would lock out caller"}},"security":[{"bearer_auth":[]}]}},"/admin/oidc/providers":{"get":{"tags":["Authentication"],"operationId":"list_oidc_providers","responses":{"200":{"description":"OIDC providers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/OidcProviderResponse"}}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Authentication"],"operationId":"create_oidc_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateOidcProviderRequest"}}},"required":true},"responses":{"201":{"description":"OIDC provider created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OidcProviderResponse"}}}},"409":{"description":"Another OIDC provider already uses that name"}},"security":[{"bearer_auth":[]}]}},"/admin/oidc/providers/{provider_id}":{"delete":{"tags":["Authentication"],"operationId":"delete_oidc_provider","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"OIDC provider deleted"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Authentication"],"operationId":"update_oidc_provider","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateOidcProviderRequest"}}},"required":true},"responses":{"200":{"description":"OIDC provider updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OidcProviderResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/admin/oidc/providers/{provider_id}/role-mappings":{"get":{"tags":["Authentication"],"operationId":"list_oidc_role_mappings","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"OIDC role mappings","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/OidcRoleMappingResponse"}}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Authentication"],"operationId":"create_oidc_role_mapping","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateOidcRoleMappingRequest"}}},"required":true},"responses":{"201":{"description":"Role mapping created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OidcRoleMappingResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/admin/oidc/providers/{provider_id}/test":{"post":{"tags":["Authentication"],"operationId":"test_oidc_provider","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Connection test result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OidcTestConnectionResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/admin/oidc/providers/{provider_id}/users":{"get":{"tags":["Authentication"],"operationId":"list_oidc_provider_users","parameters":[{"name":"provider_id","in":"path","description":"OIDC provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Users authenticated via this OIDC provider","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/OidcProviderUserResponse"}}}}},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]}},"/admin/oidc/role-mappings/{mapping_id}":{"delete":{"tags":["Authentication"],"operationId":"delete_oidc_role_mapping","parameters":[{"name":"mapping_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Role mapping deleted"}},"security":[{"bearer_auth":[]}]}},"/agents/webhook/{webhook_id}":{"post":{"tags":["Agents"],"summary":"Public webhook endpoint. Authenticated via `X-Webhook-Token` header.","description":"`POST /api/agents/webhook/{webhook_id}`\nHeader: `X-Webhook-Token: `\n\nThe `webhook_id` in the URL is a short non-secret identifier (safe to log).\nThe actual credential is the secret token in the header.\n\nAccepts any JSON body, which is passed as `user_context` to the agent run.","operationId":"webhook_trigger","parameters":[{"name":"webhook_id","in":"path","description":"Webhook ID (non-secret)","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookTriggerRequest"}}},"required":true},"responses":{"202":{"description":"Agent run created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookTriggerResponse"}}}},"401":{"description":"Missing or invalid X-Webhook-Token header"},"404":{"description":"Invalid webhook ID"},"422":{"description":"Agent disabled"}}}},"/ai/conversations":{"get":{"tags":["AI Chat"],"summary":"List every active conversation across all projects, most-recently-active\nfirst, annotated with project name/slug. Powers the unified \"all chats\"\nswitcher in the AI assistant dock.","operationId":"list_all_conversations","responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GlobalConversationResponse"}}}}},"401":{"description":""},"403":{"description":""}},"security":[{"bearer_auth":[]}]}},"/ai/pricing":{"get":{"tags":["AI Gateway Pricing"],"operationId":"get_pricing","responses":{"200":{"description":"Model pricing information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PricingResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/providers":{"get":{"tags":["AI Gateway Admin"],"operationId":"list_provider_keys","responses":{"200":{"description":"List of provider keys","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProviderKeyResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["AI Gateway Admin"],"operationId":"create_provider_key","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProviderKeyRequest"}}},"required":true},"responses":{"201":{"description":"Provider key created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderKeyResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/providers/test":{"post":{"tags":["AI Gateway Admin"],"operationId":"test_provider_key_inline","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestProviderKeyRequest"}}},"required":true},"responses":{"200":{"description":"Test result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestProviderKeyResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/providers/{id}":{"delete":{"tags":["AI Gateway Admin"],"operationId":"delete_provider_key","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Provider key deleted"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["AI Gateway Admin"],"operationId":"update_provider_key","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProviderKeyRequest"}}},"required":true},"responses":{"200":{"description":"Provider key updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderKeyResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/providers/{id}/test":{"post":{"tags":["AI Gateway Admin"],"operationId":"test_provider_key_by_id","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Test result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestProviderKeyResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Provider key not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/usage/by-provider":{"get":{"tags":["AI Gateway Usage"],"operationId":"get_usage_by_provider","parameters":[{"name":"from","in":"query","description":"ISO 8601 start time (defaults to 24h ago)","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","description":"ISO 8601 end time (defaults to now)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Usage broken down by provider","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProviderUsage"}}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/usage/conversations":{"get":{"tags":["AI Gateway Usage"],"operationId":"get_conversations","parameters":[{"name":"from","in":"query","description":"ISO 8601 start time (defaults to 24h ago)","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","description":"ISO 8601 end time (defaults to now)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max results (defaults to 50, max 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"user_id","in":"query","description":"Filter by user ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"tags","in":"query","description":"Filter by tags (comma-separated)","required":false,"schema":{"type":"string"}},{"name":"model","in":"query","description":"Filter by model name","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Conversation summaries","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ConversationSummary"}}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/usage/conversations/{conversation_id}":{"get":{"tags":["AI Gateway Usage"],"operationId":"get_conversation_detail","parameters":[{"name":"conversation_id","in":"path","description":"Conversation ID","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max results (defaults to 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Invocations within a conversation","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/UsageLogEntry"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/usage/recent":{"get":{"tags":["AI Gateway Usage"],"operationId":"get_usage_recent","parameters":[{"name":"limit","in":"query","description":"Page size (defaults to 20, max 50)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"offset","in":"query","description":"Number of results to skip for pagination (defaults to 0)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"provider","in":"query","description":"Filter by provider name","required":false,"schema":{"type":"string"}},{"name":"model","in":"query","description":"Filter by model name","required":false,"schema":{"type":"string"}},{"name":"status","in":"query","description":"Filter by HTTP status code (exact match)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"cost_gte","in":"query","description":"Cost greater-than-or-equal, in microcents","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"cost_gt","in":"query","description":"Cost strictly greater-than, in microcents","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"cost_lte","in":"query","description":"Cost less-than-or-equal, in microcents","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"cost_lt","in":"query","description":"Cost strictly less-than, in microcents","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"tokens_gte","in":"query","description":"Total tokens greater-than-or-equal","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"tokens_gt","in":"query","description":"Total tokens strictly greater-than","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"tokens_lte","in":"query","description":"Total tokens less-than-or-equal","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"tokens_lt","in":"query","description":"Total tokens strictly less-than","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Page of recent usage log entries","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsageLogPage"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/usage/summary":{"get":{"tags":["AI Gateway Usage"],"operationId":"get_usage_summary","parameters":[{"name":"from","in":"query","description":"ISO 8601 start time (defaults to 24h ago)","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","description":"ISO 8601 end time (defaults to now)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Usage summary for the time range","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsageSummary"}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/usage/timeseries":{"get":{"tags":["AI Gateway Usage"],"operationId":"get_usage_timeseries","parameters":[{"name":"from","in":"query","description":"ISO 8601 start time (defaults to 24h ago)","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","description":"ISO 8601 end time (defaults to now)","required":false,"schema":{"type":"string"}},{"name":"bucket","in":"query","description":"Bucket size: hour, day, week (defaults to day)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Time-series usage data","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TimeseriesBucket"}}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/usage/top-models":{"get":{"tags":["AI Gateway Usage"],"operationId":"get_usage_top_models","parameters":[{"name":"from","in":"query","description":"ISO 8601 start time (defaults to 24h ago)","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","description":"ISO 8601 end time (defaults to now)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max results (defaults to 10)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Top models by request count","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ModelUsage"}}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/v1/chat/completions":{"post":{"tags":["AI Gateway"],"operationId":"chat_completions","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatCompletionRequest"}}},"required":true},"responses":{"200":{"description":"Chat completion response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatCompletionResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}},"404":{"description":"Model not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/v1/embeddings":{"post":{"tags":["AI Gateway"],"operationId":"embeddings","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmbeddingRequest"}}},"required":true},"responses":{"200":{"description":"Embedding response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmbeddingResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}},"404":{"description":"Model not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/v1/models":{"get":{"tags":["AI Gateway"],"operationId":"list_models","responses":{"200":{"description":"List of available models","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelListResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/analytics/active-visitors":{"get":{"tags":["Analytics"],"summary":"Get detailed active visitors","operationId":"get_analytics_active_visitors","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Deployment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"window_minutes","in":"query","description":"Time window in minutes for active visitors (default: 5)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved active visitors","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActiveVisitorsResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/event-detail":{"get":{"tags":["Analytics"],"summary":"Get detailed analytics for a specific event","operationId":"get_event_detail","parameters":[{"name":"event_name","in":"query","description":"Event name to get details for","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date (ISO 8601)","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date (ISO 8601)","required":true,"schema":{"type":"string"}},{"name":"bucket_interval","in":"query","description":"Bucket interval: hour, day, week, month (default: auto)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved event details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventDetailResponse"}}}},"400":{"description":"Invalid parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/event-entries":{"get":{"tags":["Analytics"],"summary":"Get paginated list of raw occurrences of a specific event, including custom JSON properties","operationId":"get_event_entries","parameters":[{"name":"event_name","in":"query","description":"Event name to list occurrences for","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date (ISO 8601)","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date (ISO 8601)","required":true,"schema":{"type":"string"}},{"name":"page","in":"query","description":"Page number (1-based, default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Items per page (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Successfully retrieved event entries","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventEntriesResponse"}}}},"400":{"description":"Invalid parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/event-visitors":{"get":{"tags":["Analytics"],"summary":"Get paginated list of visitors who triggered a specific event","operationId":"get_event_visitors","parameters":[{"name":"event_name","in":"query","description":"Event name to list visitors for","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date (ISO 8601)","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date (ISO 8601)","required":true,"schema":{"type":"string"}},{"name":"page","in":"query","description":"Page number (1-based, default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Items per page (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Successfully retrieved event visitors","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventVisitorsResponse"}}}},"400":{"description":"Invalid parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/events":{"get":{"tags":["Analytics"],"operationId":"get_analytics_events_count","parameters":[{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"limit","in":"query","description":"Maximum number of results to return","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"custom_events_only","in":"query","description":"Only return custom events, excluding system events like page_view, page_leave, heartbeat (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"breakdown","in":"query","description":"Breakdown by geography: 'country', 'region', or 'city' (optional)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved event counts","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EventCount"}}}}},"400":{"description":"Invalid date format, missing required parameters, or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/general-stats":{"get":{"tags":["Analytics"],"summary":"Get general statistics across all projects for a time frame","operationId":"get_general_stats","parameters":[{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"project_ids","in":"query","description":"Optional: Filter by specific project IDs (comma-separated)","required":false,"schema":{"type":"array","items":{"type":"integer","format":"int32"}}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"include_project_breakdown","in":"query","description":"Whether to include per-project breakdown (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Successfully retrieved general statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GeneralStatsResponse"}}}},"400":{"description":"Invalid date format or parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/has-events":{"get":{"tags":["Analytics"],"operationId":"check_analytics_has_events","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Analytics events existence check","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HasAnalyticsEventsResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/live-visitors":{"get":{"tags":["Analytics"],"summary":"Get list of currently live visitors from visitor table","operationId":"get_live_visitors_list","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"window_minutes","in":"query","description":"Time window in minutes for live visitors (default: 5)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved live visitors list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LiveVisitorsListResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/page-flow":{"get":{"tags":["Analytics"],"summary":"Get page flow analytics: entry pages, exit pages, drop-off points, and page transitions","operationId":"get_page_flow","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max entry/exit pages to return (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"transitions_limit","in":"query","description":"Max page transitions to return (default: 50, max: 200)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"min_views_for_dropoff","in":"query","description":"Minimum views for drop-off analysis (default: 5)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved page flow analytics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PageFlowResponse"}}}},"400":{"description":"Invalid parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/page-hourly-sessions":{"get":{"tags":["Analytics"],"operationId":"get_page_hourly_sessions","parameters":[{"name":"page_path","in":"query","description":"The page path to get sessions for","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_time","in":"query","description":"Start time in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"bucket_interval","in":"query","description":"Bucket interval: 'hour', 'day', 'week', or 'month' (default: auto-determined based on range)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved page sessions with time buckets","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PageHourlySessionsResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/page-path-detail":{"get":{"tags":["Analytics"],"summary":"Get detailed analytics for a specific page path\nReturns visitors, page views, activity over time, geographic distribution, and referrers","operationId":"get_page_path_detail","parameters":[{"name":"page_path","in":"query","description":"The page path to get details for (URL-encoded)","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"bucket_interval","in":"query","description":"Bucket interval for time series: 'hour', 'day', 'week', 'month' (default: auto based on date range)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved page path detail analytics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PagePathDetailResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/page-path-visitors":{"get":{"tags":["Analytics"],"summary":"Get individual visitor sessions for a specific page path","operationId":"get_page_path_visitors","parameters":[{"name":"page_path","in":"query","description":"The page path to get visitors for (URL-encoded)","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"page","in":"query","description":"Page number (1-based, default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Items per page (default: 50, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Successfully retrieved page path visitors","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PagePathVisitorsResponse"}}}},"400":{"description":"Invalid parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/page-paths":{"get":{"tags":["Analytics"],"operationId":"get_page_paths","parameters":[{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS (optional)","required":false,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS (optional)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Maximum number of page paths to return (default: 100, max: 1000)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved page paths","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PagePathsResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/page-paths-sparklines":{"get":{"tags":["Analytics"],"operationId":"get_page_paths_sparklines","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_time","in":"query","description":"Start time in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"page_paths","in":"query","description":"Comma-separated list of page paths","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sparkline data for all requested page paths","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PagePathsSparklineResponse"}}}},"400":{"description":"Invalid parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/recent-activity":{"get":{"tags":["Analytics"],"summary":"Get recent activity events for real-time activity feed","operationId":"get_recent_activity","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"since_id","in":"query","description":"Return events with ID greater than this (cursor-based polling)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"limit","in":"query","description":"Max events to return (default: 50, max: 100)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved recent activity events","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecentActivityResponse"}}}},"400":{"description":"Invalid parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/sessions/{session_id}":{"get":{"tags":["Analytics"],"summary":"Get detailed information about a specific session including events and request logs","operationId":"get_session_details","parameters":[{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved session details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionDetails"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Session not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/sessions/{session_id}/events":{"get":{"tags":["Analytics"],"operationId":"get_analytics_session_events","parameters":[{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS","required":false,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Number of results to return (default: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"offset","in":"query","description":"Number of results to skip (default: 0)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved session events","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionEventsResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Session not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/sessions/{session_id}/logs":{"get":{"tags":["Analytics"],"operationId":"get_session_logs","parameters":[{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS","required":false,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Number of results to return (default: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"offset","in":"query","description":"Number of results to skip (default: 0)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved session logs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionLogsResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Session not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitor-facets":{"get":{"tags":["Analytics"],"summary":"Get filter dropdown contents for the visitors page. Returns the top\nvalues per dimension with distinct visitor counts so the UI can render\n\"Country — 1,234 visitors\" rows. Each dimension is computed against the\nsegment minus its own filter, so a selected value never collapses its\nown dropdown.","operationId":"get_visitor_facets","parameters":[{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"include_crawlers","in":"query","description":"Include crawlers (default: false)","required":false,"schema":{"type":"boolean"}},{"name":"has_activity_only","in":"query","description":"Hide ghost visitors (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"per_facet_limit","in":"query","description":"Top N values per dimension (default: 50, max: 200)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"filter_country","in":"query","description":"Geolocation country","required":false,"schema":{"type":"string"}},{"name":"filter_region","in":"query","description":"Geolocation region","required":false,"schema":{"type":"string"}},{"name":"filter_city","in":"query","description":"Geolocation city","required":false,"schema":{"type":"string"}},{"name":"filter_channel","in":"query","description":"First-touch channel","required":false,"schema":{"type":"string"}},{"name":"filter_referrer","in":"query","description":"First-touch referrer hostname (use 'Direct' for null)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Top values per dimension","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorFacets"}}}},"400":{"description":"Invalid date format or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors":{"get":{"tags":["Analytics"],"summary":"Get list of visitors with summary information","operationId":"get_visitors","parameters":[{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"include_crawlers","in":"query","description":"Include crawlers (default: false)","required":false,"schema":{"type":"boolean"}},{"name":"limit","in":"query","description":"Maximum number of visitors to return (default: 50)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"offset","in":"query","description":"Number of visitors to skip (default: 0)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"has_activity_only","in":"query","description":"Filter to only include visitors with recorded activity (events/sessions). When true, excludes ghost visitors (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"filter_country","in":"query","description":"Geolocation country","required":false,"schema":{"type":"string"}},{"name":"filter_region","in":"query","description":"Geolocation region","required":false,"schema":{"type":"string"}},{"name":"filter_city","in":"query","description":"Geolocation city","required":false,"schema":{"type":"string"}},{"name":"filter_channel","in":"query","description":"First-touch channel","required":false,"schema":{"type":"string"}},{"name":"filter_referrer","in":"query","description":"First-touch referrer hostname (use 'Direct' for null)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved visitors","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorsResponse"}}}},"400":{"description":"Invalid date format, missing required parameters, or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/guid/{visitor_id}":{"get":{"tags":["Analytics"],"summary":"Get visitor by GUID with geolocation data","operationId":"get_visitor_by_guid","parameters":[{"name":"visitor_id","in":"path","description":"Visitor GUID (supports enc_ prefix for encrypted IDs)","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved visitor with geolocation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorWithGeolocation"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/id/{id}":{"get":{"tags":["Analytics"],"summary":"Get visitor by numeric ID with geolocation data","operationId":"get_visitor_by_id","parameters":[{"name":"id","in":"path","description":"Visitor numeric ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved visitor with geolocation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorWithGeolocation"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/{visitor_id}":{"get":{"tags":["Analytics"],"summary":"Get detailed information about a specific visitor by numeric ID","operationId":"get_visitor_details","parameters":[{"name":"visitor_id","in":"path","description":"Visitor numeric ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved visitor details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorDetails"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/{visitor_id}/enrich":{"put":{"tags":["Analytics"],"operationId":"enrich_visitor","parameters":[{"name":"visitor_id","in":"path","description":"Visitor ID - can be numeric ID, GUID, or encrypted GUID (enc_xxx)","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnrichVisitorRequest"}}},"required":true},"responses":{"200":{"description":"Successfully enriched visitor data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnrichVisitorResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/{visitor_id}/info":{"get":{"tags":["Analytics"],"summary":"Get visitor record from database","operationId":"get_visitor_info","parameters":[{"name":"visitor_id","in":"path","description":"Visitor numeric ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved visitor info","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorRecord"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/{visitor_id}/journey":{"get":{"tags":["Analytics"],"summary":"Get the complete visitor journey: all events across all sessions, grouped by session","operationId":"get_visitor_journey","parameters":[{"name":"visitor_id","in":"path","description":"Visitor numeric ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"limit_sessions","in":"query","description":"Maximum number of sessions to return (default: 50)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved visitor journey","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorJourneyResponse"}}}},"400":{"description":"Invalid parameters"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/{visitor_id}/sessions":{"get":{"tags":["Analytics"],"summary":"Get all sessions for a specific visitor by numeric ID","operationId":"get_analytics_visitor_sessions","parameters":[{"name":"visitor_id","in":"path","description":"Visitor numeric ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"limit","in":"query","description":"Maximum number of sessions to return (default: 100)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved visitor sessions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorSessionsResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/{visitor_id}/stats":{"get":{"tags":["Analytics"],"summary":"Get visitor statistics","operationId":"get_visitor_stats","parameters":[{"name":"visitor_id","in":"path","description":"Visitor numeric ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved visitor statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorStats"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/api-keys":{"get":{"tags":["API Keys"],"operationId":"list_api_keys","parameters":[{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page (default: 20)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"API keys retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["API Keys"],"operationId":"create_api_key","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateApiKeyRequest"}}},"required":true},"responses":{"201":{"description":"API key created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateApiKeyResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"409":{"description":"Conflict - API key name already exists"},"428":{"description":"Recent MFA verification required"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/api-keys/permissions":{"get":{"tags":["API Keys"],"operationId":"get_api_key_permissions","responses":{"200":{"description":"Available permissions and roles retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AvailablePermissions"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/api-keys/{id}":{"get":{"tags":["API Keys"],"operationId":"get_api_key","parameters":[{"name":"id","in":"path","description":"API key ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"API key retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["API Keys"],"operationId":"update_api_key","parameters":[{"name":"id","in":"path","description":"API key ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateApiKeyRequest"}}},"required":true},"responses":{"200":{"description":"API key updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"409":{"description":"Conflict - API key name already exists"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["API Keys"],"operationId":"delete_api_key","parameters":[{"name":"id","in":"path","description":"API key ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"API key deleted successfully"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/api-keys/{id}/activate":{"post":{"tags":["API Keys"],"operationId":"activate_api_key","parameters":[{"name":"id","in":"path","description":"API key ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"API key activated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/api-keys/{id}/deactivate":{"post":{"tags":["API Keys"],"operationId":"deactivate_api_key","parameters":[{"name":"id","in":"path","description":"API key ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"API key deactivated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/api-keys/{id}/rotate":{"post":{"tags":["API Keys"],"operationId":"rotate_api_key","parameters":[{"name":"id","in":"path","description":"API key ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"API key rotated successfully; the response contains the new plaintext secret, shown only once","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateApiKeyResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"428":{"description":"Recent MFA verification required"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/auth/cli/device/approve":{"post":{"tags":["Authentication"],"operationId":"cli_device_approve","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDeviceApproveRequest"}}},"required":true},"responses":{"200":{"description":"Session approved; CLI can now claim the API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDeviceApproveResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Browser session required"},"404":{"description":"Unknown user_code"},"409":{"description":"Already resolved"},"410":{"description":"Session expired"},"428":{"description":"Recent MFA verification required"},"500":{"description":"Internal server error"}},"security":[{"session_token":[]}]}},"/auth/cli/device/deny":{"post":{"tags":["Authentication"],"operationId":"cli_device_deny","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDeviceApproveRequest"}}},"required":true},"responses":{"200":{"description":"Session denied","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDeviceApproveResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Unknown user_code"},"409":{"description":"Already resolved"},"410":{"description":"Session expired"},"500":{"description":"Internal server error"}},"security":[{"session_token":[]}]}},"/auth/cli/device/lookup":{"get":{"tags":["Authentication"],"operationId":"cli_device_lookup","parameters":[{"name":"user_code","in":"query","description":"`user_code` as displayed in the CLI / pasted into the URL.","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Device session metadata","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDeviceLookupResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Unknown user_code"},"410":{"description":"Device session expired"},"500":{"description":"Internal server error"}},"security":[{"session_token":[]}]}},"/auth/cli/device/poll":{"post":{"tags":["Authentication"],"operationId":"cli_device_poll","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDevicePollRequest"}}},"required":true},"responses":{"200":{"description":"Poll result; check `status` field","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDevicePollResponse"}}}},"404":{"description":"Unknown device_code"},"500":{"description":"Internal server error"}}}},"/auth/cli/device/start":{"post":{"tags":["Authentication"],"operationId":"cli_device_start","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDeviceStartRequest"}}},"required":true},"responses":{"200":{"description":"Device session created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDeviceStartResponse"}}}},"500":{"description":"Internal server error"}}}},"/auth/cli/logout":{"post":{"tags":["Authentication"],"operationId":"cli_logout","responses":{"204":{"description":"API key revoked"},"401":{"description":"Not authenticated"},"403":{"description":"Endpoint requires API key authentication"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/auth/email-status":{"get":{"tags":["Authentication"],"operationId":"email_status","responses":{"200":{"description":"Email configuration status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailStatusResponse"}}}},"500":{"description":"Internal server error"}}}},"/auth/login":{"post":{"tags":["Authentication"],"operationId":"login","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginRequest"}}},"required":true},"responses":{"200":{"description":"Login successful, session cookie set","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthResponse"}}}},"401":{"description":"Invalid credentials, or the account's role requires MFA enrollment that has not been completed"},"500":{"description":"Internal server error"}}}},"/auth/oidc/callback":{"get":{"tags":["Authentication"],"operationId":"oidc_callback","parameters":[{"name":"code","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"state","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"error","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"error_description","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"302":{"description":"Redirect to app with session cookie or login error"}}}},"/auth/oidc/login/{slug}":{"get":{"tags":["Authentication"],"operationId":"start_oidc_login_by_slug","parameters":[{"name":"slug","in":"path","description":"OIDC provider slug (from /email-status or /auth/oidc/providers)","required":true,"schema":{"type":"string"}},{"name":"return_to","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"302":{"description":"Redirect to IdP authorize URL"},"404":{"description":"Provider not found"},"503":{"description":"OIDC provider unreachable"}}}},"/auth/oidc/providers":{"get":{"tags":["Authentication"],"operationId":"list_public_providers","responses":{"200":{"description":"Enabled OIDC providers for login page","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OidcProvidersListResponse"}}}}}}},"/auth/password-change-required":{"post":{"tags":["Authentication"],"operationId":"change_required_password","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RequiredPasswordChangeRequest"}}},"required":true},"responses":{"200":{"description":"Required password change completed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RequiredPasswordChangeResponse"}}}},"400":{"description":"Password does not meet requirements"},"401":{"description":"Password-change session is missing or expired"},"500":{"description":"Internal server error"}}}},"/auth/password-reset/request":{"post":{"tags":["Authentication"],"operationId":"request_password_reset","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailRequest"}}},"required":true},"responses":{"200":{"description":"Reset email sent if account exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthResponse"}}}},"503":{"description":"Email service not configured"}}}},"/auth/password-reset/verify":{"post":{"tags":["Authentication"],"operationId":"reset_password","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResetPasswordRequest"}}},"required":true},"responses":{"200":{"description":"Password reset successful","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthResponse"}}}},"400":{"description":"Invalid or expired token"},"500":{"description":"Internal server error"}}}},"/auth/step-up":{"post":{"tags":["Authentication"],"operationId":"verify_step_up","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyStepUpRequest"}}},"required":true},"responses":{"200":{"description":"Session elevated for sensitive actions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StepUpResponse"}}}},"400":{"description":"Verification code is empty"},"401":{"description":"Invalid code or expired session"},"403":{"description":"Browser session required"},"428":{"description":"MFA setup required"},"429":{"description":"Too many verification attempts"},"500":{"description":"Verification infrastructure failed"}},"security":[{"session_token":[]}]}},"/auth/verify-email":{"get":{"tags":["Authentication"],"operationId":"verify_email","parameters":[{"name":"token","in":"query","description":"Email verification token","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Email verified successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthResponse"}}}},"400":{"description":"Invalid or expired token"},"500":{"description":"Internal server error"}}}},"/auth/verify-mfa":{"post":{"tags":["Authentication"],"operationId":"verify_mfa_challenge","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MfaVerificationRequest"}}},"required":true},"responses":{"204":{"description":"MFA verification successful"},"400":{"description":"Invalid request"},"401":{"description":"Invalid MFA code"},"500":{"description":"Internal server error"}}}},"/backups/alerts":{"get":{"tags":["Backups"],"summary":"List open backup alerts.","description":"Returns all alerts that have not yet been resolved, ordered by `opened_at`\ndescending (newest first). The UI renders these as a banner above the\nBackups page content. Alerts are auto-opened by the watcher and\nauto-resolved when the triggering condition clears.\n\n**Schedule overdue** — the backup scheduler did not enqueue a job within\nthe expected window (1 hour past `next_run`). Usually means the scheduler\ntask is dead or wedged.\n\n**Job stalled** — a `backup_jobs` row has been in `state='pending'` for\nmore than 1 hour. The runner never claimed the job. Usually means the\nrunner task is dead or the runner concurrency cap is too low.","operationId":"list_backup_alerts","responses":{"200":{"description":"List of open backup alerts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupAlertListResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/cleanup":{"post":{"tags":["Backups"],"summary":"Preview or run retention using each selected schedule's configured retention days.","operationId":"cleanup_expired_backups","parameters":[{"name":"dry_run","in":"query","description":"Return the backups selected by retention without deleting anything.","required":false,"schema":{"type":"boolean"}},{"name":"schedule_id","in":"query","description":"Limit cleanup to one backup schedule.","required":false,"schema":{"type":["integer","null"],"format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CleanupExpiredBackupsRequest"}}},"required":true},"responses":{"200":{"description":"Retention cleanup completed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RetentionCleanupReport"}}}},"400":{"description":"Missing or invalid preview candidate list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Schedule or backup not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"409":{"description":"Cleanup preview is stale","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Cleanup could not be started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/external-services/{id}/run":{"post":{"tags":["Backups"],"summary":"Run a backup for an external service manually.","description":"Enqueues the backup for asynchronous execution via the `BackupRunner`\n(ADR-014). Returns `202 Accepted` immediately: pending parent and child\nrows are inserted, and a `backup_jobs` row is enqueued for the resolved\nengine. Poll `GET /backups/{id}` to observe `pending → running → completed`.","operationId":"run_external_service_backup","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RunExternalServiceBackupRequest"}}},"required":true},"responses":{"202":{"description":"Backup enqueued for async execution","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceBackupResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"External service or S3 source not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/external-services/{service_id}/backups":{"get":{"tags":["Backups"],"summary":"List all backups for a specific external service (DB-only, no S3 scan).","description":"Returns a paginated list of backups that belong to this service.\nCompletes in <100 ms regardless of S3 endpoint latency because it\nnever touches S3.","operationId":"list_external_service_backups","parameters":[{"name":"service_id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-based). Defaults to 1.","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"page_size","in":"query","description":"Items per page. Defaults to 20, max 100.","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Paginated list of backups for this service","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceBackupListResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/external-services/{service_id}/schedules":{"get":{"tags":["Backups"],"summary":"List the schedules that target a specific external service. Useful for\nthe service detail page (\"which schedules back this DB up?\").","operationId":"list_service_schedules","parameters":[{"name":"service_id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Schedules backing up this service","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BackupScheduleResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Service not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/s3-sources":{"get":{"tags":["Backups"],"summary":"List all S3 sources","operationId":"list_s3_sources","responses":{"200":{"description":"List of S3 sources","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/S3SourceResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Backups"],"summary":"Create a new S3 source","operationId":"create_s3_source","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateS3SourceRequest"}}},"required":true},"responses":{"201":{"description":"S3 source created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/S3SourceResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/s3-sources/test":{"post":{"tags":["Backups"],"summary":"Test S3 connectivity against a prospective source configuration (before creating it).\nThe credentials are NOT persisted. Useful for validating the form in the UI.","operationId":"test_s3_connection_preview","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateS3SourceRequest"}}},"required":true},"responses":{"200":{"description":"Connection test result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/S3ConnectionTestResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/s3-sources/{id}":{"get":{"tags":["Backups"],"summary":"Get an S3 source by ID","operationId":"get_s3_source","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"S3 source details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/S3SourceResponse"}}}},"404":{"description":"S3 source not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Backups"],"summary":"Delete an S3 source","operationId":"delete_s3_source","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"S3 source deleted"},"404":{"description":"S3 source not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Backups"],"summary":"Update an S3 source","operationId":"update_s3_source","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateS3SourceRequest"}}},"required":true},"responses":{"200":{"description":"S3 source updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/S3SourceResponse"}}}},"404":{"description":"S3 source not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/s3-sources/{id}/backups":{"get":{"tags":["Backups"],"summary":"List all backups in an S3 source","operationId":"list_source_backups","parameters":[{"name":"include_s3_scan","in":"query","description":"When `true`, scan the S3 bucket for backups not tracked in the\nlocal database (useful after disaster-recovery from another Temps\ninstance). Defaults to `false` — the fast DB-only path.","required":false,"schema":{"type":"boolean"}},{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of all backups in the source","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceBackupIndexResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"S3 source not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/backups/s3-sources/{id}/run":{"post":{"tags":["Backups"],"summary":"Run a backup immediately for an S3 source.","description":"Enqueues the backup for asynchronous execution via the `BackupRunner`\n(ADR-014). Returns `202 Accepted` immediately: a `backups` row is inserted\nwith `state='pending'` and a `backup_jobs` row is enqueued for the\n`ControlPlaneEngine`. Poll `GET /backups/{id}` to observe\n`pending → running → completed`.","operationId":"run_backup_for_source","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RunBackupRequest"}}},"required":true},"responses":{"202":{"description":"Backup enqueued for async execution","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"S3 source not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/s3-sources/{id}/set-default":{"post":{"tags":["Backups"],"summary":"Mark an S3 source as the default. All new backups/schedules/services that do not\nexplicitly reference a source will use the default. Returns the updated source.","operationId":"set_default_s3_source","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"S3 source marked as default","content":{"application/json":{"schema":{"$ref":"#/components/schemas/S3SourceResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"S3 source not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/s3-sources/{id}/test":{"post":{"tags":["Backups"],"summary":"Test connectivity to an existing S3 source using its stored credentials.","operationId":"test_s3_source_connection","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Connection test result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/S3ConnectionTestResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"S3 source not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedule-runs/{id}/cancel":{"post":{"tags":["Backups"],"summary":"Cancel every non-terminal child backup belonging to a schedule run.","description":"Loops over `state IN ('pending','running')` children and flips each via\nthe same path as the per-backup cancel endpoint. The parent\n`schedule_runs.finished_at` is stamped automatically once no live\nchildren remain. Idempotent: cancelling a run with no live children is\na 200 with `cancelled = 0`.","operationId":"cancel_schedule_run","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Cancel processed (idempotent)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CancelBackupResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Schedule run not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedule-runs/{id}/jobs":{"get":{"tags":["Backups"],"summary":"List the individual backup jobs for a single scheduler run.","description":"Returns each child `backups` row joined with its external service name and\nthe most-recent `backup_jobs` engine key. Used by the schedule detail\naccordion to show per-job detail on row expand.\n\n`page_size` defaults to 50 and is capped at 200.","operationId":"list_schedule_run_jobs","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Jobs for this scheduler run","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ScheduleRunJobEntry"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedules":{"get":{"tags":["Backups"],"summary":"List all backup schedules","operationId":"list_backup_schedules","responses":{"200":{"description":"List of backup schedules","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BackupScheduleResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Backups"],"summary":"Create a new backup schedule","operationId":"create_backup_schedule","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateBackupScheduleRequest"}}},"required":true},"responses":{"201":{"description":"Backup schedule created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupScheduleResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}":{"get":{"tags":["Backups"],"summary":"Get a backup schedule by ID","operationId":"get_backup_schedule","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Backup schedule details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupScheduleResponse"}}}},"404":{"description":"Backup schedule not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Backups"],"summary":"Delete a backup schedule","operationId":"delete_backup_schedule","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Backup schedule deleted"},"404":{"description":"Backup schedule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Backups"],"summary":"Update a backup schedule (partial update).","description":"All request fields are optional; only fields that are present in the\nJSON body are updated. Absent fields leave the corresponding column\nunchanged. If `schedule_expression` is changed, `next_run` is\nrecomputed automatically.","operationId":"update_backup_schedule","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateBackupScheduleRequest"}}},"required":true},"responses":{"200":{"description":"Schedule updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupScheduleResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Schedule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}/backups":{"get":{"tags":["Backups"],"summary":"List backups for a schedule","operationId":"list_backups_for_schedule","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of backups for the schedule","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BackupResponse"}}}}},"404":{"description":"Backup schedule not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}/disable":{"patch":{"tags":["Backups"],"summary":"Disable a backup schedule","operationId":"disable_backup_schedule","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Backup schedule disabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupScheduleResponse"}}}},"404":{"description":"Backup schedule not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}/enable":{"patch":{"tags":["Backups"],"summary":"Enable a backup schedule","operationId":"enable_backup_schedule","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Backup schedule enabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupScheduleResponse"}}}},"404":{"description":"Backup schedule not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}/run":{"post":{"tags":["Backups"],"summary":"Immediately fan-out a run for the given schedule (Run Now).","description":"Creates one `schedule_runs` row, one control-plane backup job, and one\nbackup job per supported external service — all in a single transaction.\nReturns `202 Accepted` with a [`ScheduleRunResponse`] containing the new\n`schedule_run_id` and the list of enqueued jobs. Returns `409 Conflict` if\na run for this schedule is already in flight or if the schedule is disabled.","operationId":"run_schedule_now","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"202":{"description":"Fan-out run enqueued for async execution","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScheduleRunResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Schedule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"409":{"description":"Run already in flight or schedule disabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}/runs":{"get":{"tags":["Backups"],"summary":"Paginated run history for a backup schedule (one row per scheduler tick).","description":"Returns one [`ScheduleRunSummary`] per scheduler tick, with child backup\ncounts aggregated in a single SQL round-trip. Legacy `backups` rows (pre-\nfan-out) are surfaced as synthetic single-job runs so history does not\ndisappear. Ordered by `started_at DESC` (newest first).\n\nUse `GET /backups/schedule-runs/{run_id}/jobs` to drill into a single run.","operationId":"list_schedule_runs","parameters":[{"name":"page","in":"query","description":"Page number (1-based, defaults to 1, clamped to 1 if < 1).","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"page_size","in":"query","description":"Items per page (defaults to 20, clamped to 100 if > 100).","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Paginated run history for the schedule","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScheduleRunSummaryList"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Schedule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}/services":{"get":{"tags":["Backups"],"summary":"List the external services attached to a backup schedule.","operationId":"list_schedule_services","parameters":[{"name":"id","in":"path","description":"Schedule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Services attached to this schedule","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ExternalServiceSummary"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Schedule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Backups"],"summary":"Attach one or more external services to a backup schedule. Idempotent —\nservices that are already attached are silently skipped (`ON CONFLICT\nDO NOTHING`). Returns the count of newly inserted rows + the total\nmembership after the operation.","operationId":"attach_schedule_services","parameters":[{"name":"id","in":"path","description":"Schedule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttachScheduleServicesRequest"}}},"required":true},"responses":{"200":{"description":"Services attached","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttachScheduleServicesResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Schedule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}/services/{service_id}":{"delete":{"tags":["Backups"],"summary":"Detach a single external service from a backup schedule. Idempotent —\nreturns `204` whether or not a row was actually removed.","operationId":"detach_schedule_service","parameters":[{"name":"id","in":"path","description":"Schedule ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"service_id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Service detached (or was not attached)"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/{id}":{"get":{"tags":["Backups"],"summary":"Get a backup by ID","operationId":"get_backup","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Backup details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Backup not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Backups"],"summary":"Permanently delete one terminal backup from object storage and the database.","operationId":"delete_backup","parameters":[{"name":"id","in":"path","description":"Backup UUID","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Backup deleted"},"400":{"description":"Backup artifact cannot be safely attributed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Backup not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"409":{"description":"Backup is running, referenced, or lacks safe artifact identity","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Object storage or database error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/{id}/cancel":{"post":{"tags":["Backups"],"summary":"Cancel a single in-flight backup.","description":"Flips the parent `backups` row + its latest `backup_jobs` row to\n`failed` with reason `\"cancelled by user \"`. The in-process\n`CancellationToken` is observed on the next heartbeat tick (≤5s), so the\nengine exits cleanly and rollback reaps the sidecar. Idempotent: cancelling\nan already-terminal backup is a 200 with `cancelled = 0`.","operationId":"cancel_backup","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Cancel processed (idempotent)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CancelBackupResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Backup not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/{id}/children":{"get":{"tags":["Backups"],"summary":"List the external-service child backups that belong to a parent backup.","description":"Each entry in `children` corresponds to one `external_service_backups` row,\njoined with `external_services` so the caller receives the service name and\ntype without a second request.\n\nReturns an empty `{ \"children\": [] }` — **not 404** — when the parent\nbackup exists but has no children (e.g. control-plane backups).\nReturns 404 when the parent backup itself does not exist.","operationId":"list_backup_children","parameters":[{"name":"id","in":"path","description":"Integer row id of the parent backup","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Child backup list (may be empty)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChildBackupListResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Parent backup not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/blob":{"get":{"tags":["Blob"],"summary":"List blobs","operationId":"blob_list","parameters":[{"name":"limit","in":"query","description":"Maximum number of items to return","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"prefix","in":"query","description":"Prefix to filter by","required":false,"schema":{"type":"string"}},{"name":"cursor","in":"query","description":"Continuation token for pagination","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of blobs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListBlobsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Blob"],"summary":"Upload a blob","operationId":"blob_put","requestBody":{"description":"Binary blob data","content":{"application/octet-stream":{"schema":{"type":"string"}}},"required":true},"responses":{"201":{"description":"Blob uploaded successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlobResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Blob"],"summary":"Delete blobs","operationId":"blob_delete","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteBlobRequest"}}},"required":true},"responses":{"200":{"description":"Blobs deleted successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteBlobResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/blob/copy":{"post":{"tags":["Blob"],"summary":"Copy a blob to a new location","operationId":"blob_copy","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CopyBlobRequest"}}},"required":true},"responses":{"200":{"description":"Blob copied successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlobResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Source blob not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/blob/disable":{"delete":{"tags":["Blob Management"],"summary":"Disable Blob service","operationId":"blob_disable","responses":{"200":{"description":"Blob service disabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DisableBlobResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Blob service not enabled"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/blob/enable":{"post":{"tags":["Blob Management"],"summary":"Enable Blob service","operationId":"blob_enable","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnableBlobRequest"}}},"required":true},"responses":{"200":{"description":"Blob service enabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnableBlobResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/blob/status":{"get":{"tags":["Blob Management"],"summary":"Get Blob service status","operationId":"blob_status","responses":{"200":{"description":"Blob service status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlobStatusResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/blob/update":{"patch":{"tags":["Blob Management"],"summary":"Update Blob service configuration","operationId":"blob_update","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateBlobRequest"}}},"required":true},"responses":{"200":{"description":"Blob service updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateBlobResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Blob service not enabled"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/blob/{project_id}/{path}":{"get":{"tags":["Blob"],"summary":"Download a blob","operationId":"blob_download","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","description":"Blob path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Blob content"},"404":{"description":"Blob not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"head":{"tags":["Blob"],"summary":"Get blob metadata","operationId":"blob_head","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","description":"Blob path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Blob metadata in headers"},"404":{"description":"Blob not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/dashboard/projects-analytics":{"get":{"tags":["Events"],"summary":"Get dashboard analytics for multiple projects in a single batch request","description":"Returns unique visitor counts and hourly sparkline data for all requested projects\nusing only 2 SQL queries instead of 2×N per-project queries.","operationId":"get_dashboard_projects_analytics","parameters":[{"name":"project_ids","in":"query","description":"Comma-separated list of project IDs","required":true,"schema":{"type":"string"}},{"name":"start_date","in":"query","description":"Start date for filtering","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date for filtering","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved batch analytics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DashboardProjectsAnalyticsResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/deployments/activity-graph":{"get":{"tags":["Deployments"],"summary":"Get deployment activity graph showing daily deployment counts\nSimilar to GitHub's contribution graph","operationId":"get_activity_graph","parameters":[{"name":"project_id","in":"query","description":"Filter by project ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"days","in":"query","description":"Number of days to include (default: 365)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved activity graph","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivityGraphResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/deployments/{deployment_id}/vulnerability-scan":{"get":{"tags":["Vulnerability Scans"],"operationId":"get_scan_by_deployment","parameters":[{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Scan for the specified deployment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScanResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"No scan found for deployment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/deployments/{id}/metrics":{"get":{"tags":["Metrics"],"summary":"Fetch a time-series range for a single metric on a deployment.","operationId":"DeploymentMetricsGetRange","parameters":[{"name":"id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"metric","in":"query","description":"Metric name, e.g. `\"pg.connections_active\"`.","required":true,"schema":{"type":"string"}},{"name":"range","in":"query","description":"Time window: `\"1h\"` | `\"6h\"` | `\"24h\"` | `\"7d\"`.","required":false,"schema":{"type":"string"}},{"name":"percentile","in":"query","description":"Optional histogram percentile (0–100). When provided, the endpoint\nfetches histogram buckets and computes the requested quantile.","required":false,"schema":{"type":["number","null"],"format":"double"}}],"responses":{"200":{"description":"Metric time series data points","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MetricDataPoint"}}}}},"400":{"description":"Invalid query parameters"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"},"503":{"description":"Metrics store not available"}},"security":[{"bearer_auth":[]}]}},"/deployments/{id}/metrics/enable":{"patch":{"tags":["Metrics"],"summary":"Enable or disable OTLP metric ingestion for a deployment.","description":"When `enabled=true`, seeds the default container alert rules for the\ndeployment via [`temps_monitoring::seed_default_container_rules`] (idempotent).","operationId":"DeploymentMetricsToggle","parameters":[{"name":"id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToggleDeploymentMetricsRequest"}}},"required":true},"responses":{"200":{"description":"Metrics toggle applied"},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/deployments/{id}/metrics/latest":{"get":{"tags":["Metrics"],"summary":"Fetch the most-recent metric values for a deployment.","operationId":"DeploymentMetricsGetLatest","parameters":[{"name":"id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Map of metric name to latest value","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"number","format":"double"},"propertyNames":{"type":"string"}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"},"503":{"description":"Metrics store not available"}},"security":[{"bearer_auth":[]}]}},"/dns-providers":{"get":{"tags":["DNS Providers"],"summary":"List all DNS providers","operationId":"list_dns_providers","responses":{"200":{"description":"List of DNS providers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/DnsProviderResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["DNS Providers"],"summary":"Create a new DNS provider","description":"The provider's credentials will be tested before creation.\nIf the connection test fails, the provider will not be created.","operationId":"create_dns_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDnsProviderRequest"}}},"required":true},"responses":{"201":{"description":"DNS provider created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsProviderResponse"}}}},"400":{"description":"Invalid request or connection test failed"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{id}":{"get":{"tags":["DNS Providers"],"summary":"Get a DNS provider by ID","operationId":"get_dns_provider","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"DNS provider details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsProviderResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["DNS Providers"],"summary":"Update a DNS provider","description":"If new credentials are supplied, they are tested before the update is\npersisted (same as creation) -- otherwise a provider's credentials (and,\nfor Pebble, its target URL) could be swapped for something invalid or\nunsafe without ever going through validation.","operationId":"update_provider","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDnsProviderRequest"}}},"required":true},"responses":{"200":{"description":"DNS provider updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsProviderResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["DNS Providers"],"summary":"Delete a DNS provider","operationId":"delete_dns_provider","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"DNS provider deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{id}/domains":{"get":{"tags":["DNS Providers"],"summary":"List managed domains for a provider","operationId":"list_managed_domains","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of managed domains","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ManagedDomainResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["DNS Providers"],"summary":"Add a managed domain to a provider","operationId":"add_managed_domain","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddManagedDomainApiRequest"}}},"required":true},"responses":{"201":{"description":"Managed domain added","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagedDomainResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{id}/test":{"post":{"tags":["DNS Providers"],"summary":"Test provider connection","operationId":"test_provider_connection","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Connection test result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectionTestResult"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{id}/zones":{"get":{"tags":["DNS Providers"],"summary":"List zones available in a provider","operationId":"list_provider_zones","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of zones","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ZoneListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{provider_id}/domains/{domain}":{"delete":{"tags":["DNS Providers"],"summary":"Remove a managed domain","operationId":"remove_managed_domain","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Managed domain removed"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["DNS Providers"],"summary":"Update a managed domain's settings (hostname mode, sync opt-in, auto-manage).","operationId":"update_managed_domain","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateManagedDomainApiRequest"}}},"required":true},"responses":{"200":{"description":"Managed domain updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagedDomainResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{provider_id}/domains/{domain}/apply-hostname-mode":{"post":{"tags":["DNS Providers"],"summary":"Apply a hostname mode to a managed domain (persist + optional DNS sync +\nroute reload).","operationId":"apply_hostname_mode","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApplyHostnameModeRequest"}}},"required":true},"responses":{"200":{"description":"Hostname mode applied","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HostnamePreviewResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions or token lacks zone access"},"404":{"description":"Domain not found"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{provider_id}/domains/{domain}/hostname-preview":{"get":{"tags":["DNS Providers"],"summary":"Preview the impact of switching a managed domain's hostname mode.","operationId":"preview_hostname_mode","parameters":[{"name":"mode","in":"query","description":"Target mode: standard|flat","required":true,"schema":{"type":"string"}},{"name":"sync","in":"query","description":"Include DNS record changes","required":false,"schema":{"type":"boolean"}},{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Hostname mode preview","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HostnamePreviewResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{provider_id}/domains/{domain}/verify":{"post":{"tags":["DNS Providers"],"summary":"Verify a managed domain","operationId":"verify_managed_domain","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Domain verification result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagedDomainResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"}},"security":[{"bearer_auth":[]}]}},"/dns/lookup":{"get":{"tags":["DNS"],"summary":"Lookup DNS A records for a domain","operationId":"lookup_dns_a_records","parameters":[{"name":"domain","in":"query","description":"Domain name to lookup","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved DNS A records","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsLookupResponse"}}}},"400":{"description":"Invalid domain name or lookup failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsLookupError"}}}}}}},"/domains":{"get":{"tags":["Domains"],"summary":"List all domains","operationId":"list_domains","parameters":[{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20},{"name":"search","in":"query","description":"Search domains by name (substring match)","required":false,"schema":{"type":["string","null"]},"example":"example.com"}],"responses":{"200":{"description":"Domains retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListDomainsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Domains"],"summary":"Create a new domain","description":"Creates a new domain and automatically requests a Let's Encrypt challenge.\nYou can specify the challenge type (HTTP-01 or DNS-01) in the request.\n\n- **HTTP-01**: Validates domain ownership by placing a file on your web server at `/.well-known/acme-challenge/`\n- **DNS-01**: Validates domain ownership by adding a TXT record to your DNS (required for wildcard domains)","operationId":"create_domain","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDomainRequest"}}},"required":true},"responses":{"201":{"description":"Domain created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainResponse"}}}},"400":{"description":"Invalid input"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/by-host/{hostname}":{"get":{"tags":["Domains"],"summary":"Get domain details by hostname","operationId":"get_domain_by_host","parameters":[{"name":"hostname","in":"path","description":"Domain hostname","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Domain details retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/by-host/{hostname}/cert-status":{"get":{"tags":["Domains"],"summary":"Get on-demand TLS certificate status for a hostname","description":"Returns the current cert lifecycle state for a single hostname (from the\n`domains` row) plus the most recent on-demand issuance attempt (from the\n`on_demand_cert_attempts` audit log). This is the operator's first-line\ndiagnostic, surfaced by `temps domain cert-status` (ADR-018 §5). Returns the\nhostname with `None` fields when no on-demand activity exists for it (never a\n404, so the CLI can render \"no attempts recorded\").","operationId":"get_on_demand_cert_status","parameters":[{"name":"hostname","in":"path","description":"Domain hostname","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"On-demand cert status retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CertStatusResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/on-demand-certs":{"get":{"tags":["Domains"],"summary":"List on-demand TLS certificate attempts","description":"Returns rows from the append-only `on_demand_cert_attempts` audit log\n(ADR-018 §5), newest first, each joined with the current authoritative cert\nstate (`status`, `expiration_time`, `backoff_until`) from the `domains` row.\nThis backs the console \"Certificates\" surface. No certificate or private-key\nmaterial is returned — only audit metadata.","operationId":"list_on_demand_certs","parameters":[{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20}],"responses":{"200":{"description":"On-demand cert attempts retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListOnDemandCertsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain_id}/order":{"get":{"tags":["Domains"],"summary":"Get ACME order for a domain","operationId":"get_domain_order","parameters":[{"name":"domain_id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Order retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AcmeOrderResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Order not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Domains"],"summary":"Create or recreate ACME order for a domain","description":"Creates a new ACME order with Let's Encrypt for the specified domain.\nIf an order already exists, you should cancel it first using the cancel-order endpoint.\nReturns the challenge details that need to be fulfilled (DNS record or HTTP token).","operationId":"create_or_recreate_order","parameters":[{"name":"domain_id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Order created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainChallengeResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Domains"],"summary":"Cancel ACME order for a domain","description":"Cancels the current ACME order for a domain and clears all challenge data.\nThis allows you to start over with a new order if the previous one failed or got stuck.","operationId":"cancel_domain_order","parameters":[{"name":"domain_id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Order cancelled successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain_id}/order/finalize":{"post":{"tags":["Domains"],"summary":"Finalize ACME order for a domain","description":"Finalizes the ACME order by completing the challenge validation and requesting the certificate.\nThis should be called after the challenge has been set up (DNS record added or HTTP token served).","operationId":"finalize_order","parameters":[{"name":"domain_id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Order finalized successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain or order not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain_id}/setup-dns":{"post":{"tags":["Domains"],"summary":"Setup DNS challenge records automatically using a DNS provider","description":"This endpoint automatically creates the required DNS TXT records for ACME DNS-01 challenge\nvalidation using a configured DNS provider. The domain must have an active DNS challenge\npending (created via POST /domains/{id}/order with dns-01 challenge type).\n\nThis is similar to how email domain DNS records are auto-provisioned.","operationId":"setup_dns_challenge","parameters":[{"name":"domain_id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetupDnsChallengeRequest"}}},"required":true},"responses":{"200":{"description":"DNS records created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetupDnsChallengeResponse"}}}},"400":{"description":"Bad request - DNS provider not configured or no challenge pending"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain or DNS provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain}":{"get":{"tags":["Domains"],"summary":"Get domain by ID","operationId":"get_domain_by_id","parameters":[{"name":"domain","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Domain retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Domains"],"summary":"Delete a domain","operationId":"delete_domain","parameters":[{"name":"domain","in":"path","description":"Domain name","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Domain deleted successfully"},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain}/challenge-token":{"get":{"tags":["Domains"],"summary":"Get challenge token for a domain (returns plain text token)","operationId":"get_challenge_token","parameters":[{"name":"domain","in":"path","description":"Domain name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Challenge token retrieved successfully","content":{"text/plain":{"schema":{"type":"string"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Challenge not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain}/http-challenge-debug":{"get":{"tags":["Domains"],"summary":"Get HTTP challenge debug information","description":"Returns detailed debug information for HTTP-01 challenge including:\n- Whether a challenge exists for the domain\n- The challenge token and URL that Let's Encrypt will access\n- DNS resolution information showing where the domain currently points\n\nThis is useful for debugging why HTTP-01 challenges fail.","operationId":"get_http_challenge_debug","parameters":[{"name":"domain","in":"path","description":"Domain name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Debug information retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpChallengeDebugResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain}/provision":{"post":{"tags":["Domains"],"summary":"Provision a domain certificate","operationId":"provision_domain","parameters":[{"name":"domain","in":"path","description":"Domain name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Certificate provisioning initiated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProvisionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain}/renew":{"post":{"tags":["Domains"],"summary":"Renew domain certificate","description":"For HTTP-01 domains: Automatically renews the certificate\nFor DNS-01 domains (wildcards): Creates a new ACME order and returns challenge data","operationId":"renew_domain","parameters":[{"name":"domain","in":"path","description":"Domain name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Certificate renewal initiated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProvisionResponse"}}}},"202":{"description":"DNS challenge created - manual action required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainChallengeResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain}/status":{"get":{"tags":["Domains"],"summary":"Check domain status","operationId":"check_domain_status","parameters":[{"name":"domain","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Domain status retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/drop/inspect":{"post":{"tags":["Projects"],"summary":"Inspect a source ZIP without creating a project or retaining the upload.","operationId":"inspect_drop_archive","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/DropArchiveUpload"}}},"required":true},"responses":{"200":{"description":"Detected deployable project roots","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DropInspectionResponse"}}}},"400":{"description":"Invalid or unsupported archive"}},"security":[{"bearer_auth":[]}]}},"/email-domains":{"get":{"tags":["Email Domains"],"summary":"List all email domains","operationId":"list_email_domains","parameters":[{"name":"provider_id","in":"query","description":"Only return domains belonging to this provider","required":false,"schema":{"type":["integer","null"],"format":"int32"}}],"responses":{"200":{"description":"List of email domains","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EmailDomainResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Email Domains"],"summary":"Create a new email domain","operationId":"create_email_domain","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEmailDomainRequest"}}},"required":true},"responses":{"201":{"description":"Domain created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailDomainWithDnsResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-domains/by-domain/{domain}":{"get":{"tags":["Email Domains"],"summary":"Get an email domain by domain name with DNS records","operationId":"get_domain_by_name","parameters":[{"name":"domain","in":"path","description":"Domain name (e.g., 'mail.example.com')","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Email domain details with DNS records","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailDomainWithDnsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-domains/{id}":{"get":{"tags":["Email Domains"],"summary":"Get an email domain by ID with DNS records","operationId":"get_domain","parameters":[{"name":"id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Email domain details with DNS records","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailDomainWithDnsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Email Domains"],"summary":"Delete an email domain","operationId":"delete_email_domain","parameters":[{"name":"id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Domain deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-domains/{id}/dns-records":{"get":{"tags":["Email Domains"],"summary":"Get DNS records for an email domain","operationId":"get_domain_dns_records","parameters":[{"name":"id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"DNS records for the domain","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/DnsRecordResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-domains/{id}/setup-dns":{"post":{"tags":["Email Domains"],"summary":"Setup DNS records for an email domain using a configured DNS provider","operationId":"setup_dns","parameters":[{"name":"id","in":"path","description":"Email Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetupDnsRequest"}}},"required":true},"responses":{"200":{"description":"DNS records setup result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetupDnsResponse"}}}},"400":{"description":"Invalid request or DNS provider not configured"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-domains/{id}/verify":{"post":{"tags":["Email Domains"],"summary":"Verify an email domain's DNS configuration","operationId":"verify_domain","parameters":[{"name":"id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Domain verification result with DNS records","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailDomainWithDnsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-providers":{"get":{"tags":["Email Providers"],"summary":"List all email providers","operationId":"list_email_providers","responses":{"200":{"description":"List of email providers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EmailProviderResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Email Providers"],"summary":"Create a new email provider","operationId":"create_email_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEmailProviderRequest"}}},"required":true},"responses":{"201":{"description":"Provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailProviderResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-providers/{id}":{"get":{"tags":["Email Providers"],"summary":"Get an email provider by ID","operationId":"get_email_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Email provider details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailProviderResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Email Providers"],"summary":"Delete an email provider","operationId":"delete_email_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Provider deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Email Providers"],"summary":"Update an email provider","description":"Partial update — any field left out keeps its current value. Most importantly,\nomitting the credential block (`ses_credentials`/`scaleway_credentials`/`smtp_credentials`)\npreserves the stored secret, so operators can rename a provider without re-typing\npasswords. `provider_type` is immutable; to switch providers, delete and recreate.","operationId":"update_email_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEmailProviderRequest"}}},"required":true},"responses":{"200":{"description":"Provider updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailProviderResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"},"409":{"description":"Provider type mismatch"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-providers/{id}/test":{"post":{"tags":["Email Providers"],"summary":"Test an email provider by sending a test email to the logged-in user","operationId":"test_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestEmailRequest"}}},"required":true},"responses":{"200":{"description":"Test email result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestEmailResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-providers/{id}/tracking/setup":{"post":{"tags":["Email Providers"],"summary":"One-click AWS-side setup of SES event tracking (SNS topic + webhook\nsubscription + SESv2 event destination), using the provider's stored\ncredentials.","operationId":"setup_email_tracking","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Setup completed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailTrackingSetupResponse"}}}},"400":{"description":"Provider does not support event tracking"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"},"502":{"description":"An AWS call failed — the response detail names the failed step"}},"security":[{"bearer_auth":[]}]}},"/email-providers/{id}/tracking/status":{"get":{"tags":["Email Providers"],"summary":"Live status of SES event tracking for a provider","operationId":"get_email_tracking_status","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Event tracking status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailTrackingStatusResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]}},"/emails":{"get":{"tags":["Emails"],"summary":"List emails with optional filtering","operationId":"list_emails","parameters":[{"name":"domain_id","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"project_id","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"status","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"from_address","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"page","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"page_size","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}}],"responses":{"200":{"description":"List of emails","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedEmailsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Emails"],"summary":"Send an email","operationId":"send_email","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendEmailRequestBody"}}},"required":true},"responses":{"201":{"description":"Email sent successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendEmailResponseBody"}}}},"400":{"description":"Invalid request or domain not verified"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/emails/events":{"get":{"tags":["Email Tracking"],"summary":"GET /emails/events","operationId":"get_global_events","parameters":[{"name":"event_type","in":"query","description":"Filter by event type (open, click)","required":false,"schema":{"type":"string"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Paginated tracking events","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedEventsResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/emails/events/stats":{"get":{"tags":["Email Tracking"],"summary":"GET /emails/events/stats","operationId":"get_global_event_stats","responses":{"200":{"description":"Global tracking statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GlobalEventStatsResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/emails/stats":{"get":{"tags":["Emails"],"summary":"Get email statistics","operationId":"get_email_stats","parameters":[{"name":"domain_id","in":"query","description":"Optional domain ID to filter stats","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Email statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailStatsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/emails/validate":{"post":{"tags":["Email Validation"],"summary":"Validate an email address","operationId":"validate_email","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateEmailRequest"}}},"required":true},"responses":{"200":{"description":"Email validation result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateEmailResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/emails/{email_id}/track/click/{link_index}":{"get":{"tags":["Email Tracking"],"summary":"Track email link click - redirects to original URL","description":"This endpoint replaces original links in tracked emails.\nNo authentication required - it's called when the recipient clicks a link.","operationId":"track_click","parameters":[{"name":"email_id","in":"path","description":"Email ID (UUID)","required":true,"schema":{"type":"string"}},{"name":"link_index","in":"path","description":"Link index","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"302":{"description":"Redirect to original URL"},"404":{"description":"Link not found"}}}},"/emails/{email_id}/track/open":{"get":{"tags":["Email Tracking"],"summary":"Track email open - returns a 1x1 transparent GIF","description":"This endpoint is embedded as an tag in emails.\nNo authentication required - it's called by the email client.","operationId":"track_open","parameters":[{"name":"email_id","in":"path","description":"Email ID (UUID)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"1x1 transparent tracking pixel"},"404":{"description":"Email not found"}}}},"/emails/{id}":{"get":{"tags":["Emails"],"summary":"Get an email by ID","operationId":"get_email","parameters":[{"name":"id","in":"path","description":"Email ID (UUID)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Email details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Email not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/emails/{id}/tracking":{"get":{"tags":["Email Tracking"],"summary":"Get email tracking summary","operationId":"get_email_tracking","parameters":[{"name":"id","in":"path","description":"Email ID (UUID)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Tracking summary","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailTrackingResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Email not found"}},"security":[{"bearer_auth":[]}]}},"/emails/{id}/tracking/events":{"get":{"tags":["Email Tracking"],"summary":"Get email tracking events","operationId":"get_email_events","parameters":[{"name":"id","in":"path","description":"Email ID (UUID)","required":true,"schema":{"type":"string"}},{"name":"event_type","in":"query","description":"Filter by event type (open, click)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Tracking events","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TrackingEventResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Email not found"}},"security":[{"bearer_auth":[]}]}},"/emails/{id}/tracking/links":{"get":{"tags":["Email Tracking"],"summary":"Get tracked links for an email","operationId":"get_email_links","parameters":[{"name":"id","in":"path","description":"Email ID (UUID)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Tracked links","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TrackedLinkResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Email not found"}},"security":[{"bearer_auth":[]}]}},"/external-services":{"get":{"tags":["External Services"],"summary":"Get all external services","operationId":"list_services","parameters":[{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20},{"name":"sort_by","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"List of external services","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}}},"500":{"description":"Internal server error"}}},"post":{"tags":["External Services"],"summary":"Create new external service","operationId":"create_service","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateExternalServiceRequest"}}},"required":true},"responses":{"201":{"description":"Service created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}},"400":{"description":"Invalid request"},"500":{"description":"Internal server error"}}}},"/external-services/available-containers":{"get":{"tags":["External Services"],"summary":"List available Docker containers that can be imported as services","operationId":"list_available_containers","responses":{"200":{"description":"List of available containers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AvailableContainerInfo"}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/by-slug/{slug}":{"get":{"tags":["External Services"],"summary":"Get external service details by slug","operationId":"get_service_by_slug","parameters":[{"name":"slug","in":"path","description":"External service slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"External service details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceDetails"}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/health-status-batch":{"get":{"tags":["External Services"],"summary":"Current health status for many services at once","description":"Powers the status dot on the Storage list page. Pass a comma-separated\nlist of service IDs via `?ids=1,2,3`. Omit to get every service.","operationId":"list_service_health_statuses","parameters":[{"name":"ids","in":"query","description":"Comma-separated service IDs. Omit for all services.","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Batch of current health statuses","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceHealthStatusBatchResponse"}}}},"500":{"description":"Internal server error"}}}},"/external-services/import":{"post":{"tags":["External Services"],"summary":"Import an existing Docker container as a managed external service","operationId":"import_external_service","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportExternalServiceRequest"}}},"required":true},"responses":{"201":{"description":"Service imported successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/projects/{project_id}":{"get":{"tags":["External Services"],"summary":"List services linked to a project","operationId":"list_project_services","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20},{"name":"sort_by","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"List of services linked to project","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProjectServiceInfo"}}}}},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}}},"/external-services/projects/{project_id}/environment":{"get":{"tags":["External Services"],"summary":"Get all environment variables for all services linked to a project","operationId":"get_project_service_environment_variables","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Map of service IDs to their environment variables","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"object","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"propertyNames":{"type":"integer","format":"int32"}}}}},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}}},"/external-services/providers/metadata":{"get":{"tags":["External Services"],"summary":"Get provider metadata (display names, icons, descriptions)","operationId":"get_providers_metadata","responses":{"200":{"description":"List of provider metadata","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProviderMetadata"}}}}},"500":{"description":"Internal server error"}}}},"/external-services/providers/metadata/{service_type}":{"get":{"tags":["External Services"],"summary":"Get metadata for a specific provider","operationId":"get_provider_metadata","parameters":[{"name":"service_type","in":"path","description":"Service type (mongodb, postgres, redis, s3)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Provider metadata","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderMetadata"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}}}},"/external-services/types":{"get":{"tags":["External Services"],"summary":"Get available service types","operationId":"get_service_types","responses":{"200":{"description":"List of available service types","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ServiceTypeRoute"}}}}},"500":{"description":"Internal server error"}}}},"/external-services/types/{service_type}/parameters":{"get":{"tags":["External Services"],"summary":"Get parameter schema for a specific service type","operationId":"get_service_type_parameters","parameters":[{"name":"service_type","in":"path","description":"Service type","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Service type parameter schema"},"404":{"description":"Service type not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}":{"get":{"tags":["External Services"],"summary":"Get external service details","operationId":"get_service","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"External service details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceDetails"}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}},"put":{"tags":["External Services"],"summary":"Update external service","operationId":"update_service","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateExternalServiceRequest"}}},"required":true},"responses":{"200":{"description":"Service updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}},"400":{"description":"Invalid request"},"404":{"description":"Service not found"},"409":{"description":"A major upgrade is in progress for this service"},"500":{"description":"Internal server error"}}},"delete":{"tags":["External Services"],"summary":"Delete external service","operationId":"delete_service","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Service deleted successfully"},"400":{"description":"Cannot delete: service is still linked to projects"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/cluster-health":{"get":{"tags":["External Services"],"summary":"Per-member health for a Postgres HA cluster.","description":"Reads pg_auto_failover's `pgautofailover.node` table from the cluster's\nmonitor (TLS, autoctl_node) and joins each member with its\n`pg_stat_replication` row from the current primary. Returns one row per\ndata member with role/state, sync state, and replay lag.\n\nReturns `200` with `monitor_error` set when the monitor is briefly\nunreachable (UI surfaces it as a banner above the table); the table\nitself is empty in that case. Returns `400` for non-cluster services.","operationId":"get_cluster_health","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Per-member cluster health report","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClusterHealthReportResponse"}}}},"400":{"description":"Service is not a cluster"},"401":{"description":"Unauthorized"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/health-check":{"post":{"tags":["External Services"],"summary":"Run a health check for one service right now","description":"Triggers the same engine-specific probe as the background monitor, writes\na history row, updates the denormalized fields on `external_services`, and\nfires alerts on the Nth consecutive failure (so consecutive-failure state\nstays honest). Returns the fresh snapshot the UI can display immediately.","operationId":"trigger_service_health_check","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Fresh health snapshot after probing","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceHealthResponse"}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"},"503":{"description":"Health monitor not running on this node"}}}},"/external-services/{id}/health-status":{"get":{"tags":["External Services"],"summary":"Persisted health status for an external service","description":"Returns the latest health probe result recorded by\n`ExternalServiceHealthMonitor`, plus recent check history for sparklines\nand a 24-hour uptime percentage. Safe to poll from the UI every 30s.","operationId":"get_service_health_status","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"limit","in":"query","description":"Max number of recent checks (default 50, max 200)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Current health + recent history","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceHealthResponse"}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/members":{"post":{"tags":["External Services"],"summary":"Begin adding a single new member to a running cluster.","description":"Currently only `replica` members can be added at runtime. The\nresponse is **202 Accepted** as soon as the validation passes and\nthe placeholder `service_members` row is inserted. The actual\ncontainer provisioning + DNS registration runs in the background;\npoll `GET /external-services/{id}/members/{member_id}` to watch\n`provisioning_step` advance through the phases.","operationId":"add_cluster_member","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddClusterMemberRequest"}}},"required":true},"responses":{"202":{"description":"Cluster member provisioning started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceMemberInfo"}}}},"400":{"description":"Validation failed (wrong topology, status, or role)"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/members/{member_id}":{"get":{"tags":["External Services"],"summary":"Get a single cluster member's current state.","description":"Used by the add-member page to poll the row every second while the\nbackground provisioning task walks through its phases. The\n`provisioning_step` field advances through `inserting_row` →\n`provisioning_container` → `registering_dns` → `done` (or `failed`\nwith `provisioning_error` set).","operationId":"get_cluster_member","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"member_id","in":"path","description":"Cluster member ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Cluster member details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceMemberInfo"}}}},"404":{"description":"Service or member not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["External Services"],"summary":"Remove a single member from a running cluster.","description":"Refuses to remove the monitor (singleton), the current primary\n(failover first), or any member if the cluster would drop below the\n2-data-member quorum required for HA. Stops + removes the container,\ndeletes the row, and drops the Tier-2 DNS record.","operationId":"remove_cluster_member","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"member_id","in":"path","description":"Cluster member ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Cluster member removed"},"400":{"description":"Validation failed (monitor, primary, or quorum violation)"},"404":{"description":"Service or member not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/members/{member_id}/promote":{"post":{"tags":["External Services"],"summary":"Promote a replica to primary by triggering a pg_auto_failover\nfailover. The monitor demotes the current primary and the chosen\nreplica transitions to primary; the role reconciler then refreshes\nthe role-aliased VIPs (≤30s).","operationId":"promote_cluster_member","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"member_id","in":"path","description":"Cluster member ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"202":{"description":"Promotion initiated"},"400":{"description":"Validation failed (monitor, already primary, not running, etc.)"},"404":{"description":"Service or member not found"},"500":{"description":"pg_autoctl perform promotion failed"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/metrics":{"get":{"tags":["Metrics"],"summary":"Fetch a time-series range for a single metric on an external service.","description":"Pass `percentile` to compute a histogram quantile instead of a plain\ngauge/counter average.","operationId":"ExternalServiceMetricsGetRange","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"metric","in":"query","description":"Metric name, e.g. `\"pg.connections_active\"`.","required":true,"schema":{"type":"string"}},{"name":"range","in":"query","description":"Time window: `\"1h\"` | `\"6h\"` | `\"24h\"` | `\"7d\"`.","required":false,"schema":{"type":"string"}},{"name":"percentile","in":"query","description":"Optional histogram percentile (0–100). When provided, the endpoint\nfetches histogram buckets and computes the requested quantile.","required":false,"schema":{"type":["number","null"],"format":"double"}}],"responses":{"200":{"description":"Metric time series data points","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MetricDataPoint"}}}}},"400":{"description":"Invalid query parameters"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"},"503":{"description":"Metrics store not available"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/metrics/alert-rules":{"get":{"tags":["Metrics"],"summary":"List all monitoring alert rules for an external service.","operationId":"ExternalServiceMetricsGetAlertRules","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of alert rules","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ServiceAlertRuleResponse"}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Metrics"],"summary":"Create a monitoring alert rule for an external service.","description":"If metric collection is enabled and the service engine has default rules,\nseeding is idempotent (ON CONFLICT DO NOTHING).","operationId":"ExternalServiceMetricsCreateAlertRule","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceCreateAlertRuleRequest"}}},"required":true},"responses":{"201":{"description":"Alert rule created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceAlertRuleResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/metrics/alert-rules/{rule_id}":{"put":{"tags":["Metrics"],"summary":"Update an existing monitoring alert rule for an external service.","operationId":"ExternalServiceMetricsUpdateAlertRule","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"rule_id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceUpdateAlertRuleRequest"}}},"required":true},"responses":{"200":{"description":"Updated alert rule","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceAlertRuleResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Alert rule not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Metrics"],"summary":"Delete a monitoring alert rule for an external service.","operationId":"ExternalServiceMetricsDeleteAlertRule","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"rule_id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Alert rule deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Alert rule not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/metrics/by-database":{"get":{"tags":["Metrics"],"summary":"Return the latest per-database metric values for a Postgres service.","description":"Groups `pg_stat_database` / size metrics by `datname` so the UI can show a\nbreakdown table (each database with its own size, cache-hit ratio, etc.)\nrather than collapsing every database into one value.","operationId":"ExternalServiceMetricsByDatabase","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Per-database metric breakdown","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DatabaseMetricsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"},"503":{"description":"Metrics not available"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/metrics/enable":{"patch":{"tags":["Metrics"],"summary":"Enable or disable metric collection for an external service.","description":"When `enabled=true`, seeds the default alert rules for the service's engine\nvia [`temps_monitoring::seed_default_rules`] (idempotent).","operationId":"ExternalServiceMetricsToggle","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToggleServiceMetricsRequest"}}},"required":true},"responses":{"200":{"description":"Metrics toggle applied"},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/metrics/latest":{"get":{"tags":["Metrics"],"summary":"Fetch the most-recent value for every tracked metric on an external service.","operationId":"ExternalServiceMetricsGetLatest","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Map of metric name to latest value","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"number","format":"double"},"propertyNames":{"type":"string"}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"},"503":{"description":"Metrics store not available"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/metrics/status":{"get":{"tags":["Metrics"],"summary":"Return the freshness status (last-received timestamp) for a service.","description":"Cheap O(1) lookup against `service_metrics_status` — used by the UI to show\n\"last received at …\" without scanning the metrics hypertable.","operationId":"ExternalServiceMetricsStatus","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Metrics freshness status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MetricsStatusResponse"}}}},"503":{"description":"Metrics not available"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/parameters/{param_name}":{"get":{"tags":["External Services"],"summary":"Reveal one sensitive service parameter. Service detail responses never\ncontain plaintext values; every successful reveal is recorded separately.","operationId":"reveal_service_parameter","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"param_name","in":"path","description":"Sensitive parameter name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sensitive parameter value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SensitiveValueResponse"}}}},"400":{"description":"Parameter is not sensitive"},"403":{"description":"Caller cannot access a project linked to this service"},"404":{"description":"Service or parameter not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/preview-environment-masked":{"get":{"tags":["External Services"],"summary":"Get environment variables preview with masked sensitive values","operationId":"get_service_preview_environment_variables_masked","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Preview of environment variables with sensitive values masked as ***","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/preview-environment-names":{"get":{"tags":["External Services"],"summary":"Get environment variable names preview (safe - no sensitive values)","operationId":"get_service_preview_environment_variable_names","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of environment variable names that would be provided","content":{"application/json":{"schema":{"type":"array","items":{"type":"string"}}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/projects":{"get":{"tags":["External Services"],"summary":"List projects linked to service","operationId":"list_service_projects","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20},{"name":"sort_by","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"List of linked projects","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProjectServiceInfo"}}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}},"post":{"tags":["External Services"],"summary":"Link service to project","operationId":"link_service_to_project","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LinkServiceRequest"}}},"required":true},"responses":{"201":{"description":"Service linked to project successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectServiceInfo"}}}},"404":{"description":"Service or project not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/projects/{project_id}":{"delete":{"tags":["External Services"],"summary":"Unlink service from project","operationId":"unlink_service_from_project","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Service unlinked from project successfully"},"404":{"description":"Service link not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/projects/{project_id}/environment":{"get":{"tags":["External Services"],"summary":"Get all environment variables for a service-project pair","operationId":"get_service_environment_variables","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of environment variables","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EnvironmentVariableInfo"}}}}},"404":{"description":"Service or project not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/projects/{project_id}/environment/{var_name}":{"get":{"tags":["External Services"],"summary":"Get specific environment variable for a service-project pair","operationId":"get_service_environment_variable","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"var_name","in":"path","description":"Environment variable name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Environment variable value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentVariableInfo"}}}},"403":{"description":"Plaintext secret access is not permitted"},"404":{"description":"Service, project, or variable not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/resources":{"patch":{"tags":["External Services"],"summary":"Update a service's resource limits (memory, CPU caps).","description":"Persists the new caps to the encrypted config AND live-applies them\nvia Docker's update API. Memory and CPU can be hot-changed without a\nrestart on running containers; stopped containers also accept the\nupdate and pick up the new caps on next start.\n\nPass `null` (or omit) any field to leave it unlimited. A request where\nevery field is `null` removes any existing limits.\n\nThe response includes a per-container `applied[]` list so the caller\ncan tell which members got the update and which were skipped (e.g.,\ncontainer not yet created, or `docker update` rejected because the\nnew memory cap is below current usage).","operationId":"update_service_resources","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceResourceLimits"}}},"required":true},"responses":{"200":{"description":"Updated resource limits","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResourceLimitsUpdateResponse"}}}},"400":{"description":"Invalid resource limits"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/restore":{"post":{"tags":["Restore"],"operationId":"start_restore","parameters":[{"name":"id","in":"path","description":"External service id (source for the restore)","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartRestoreRequest"}}},"required":true},"responses":{"202":{"description":"Restore run started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RestoreRunView"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Backup or service not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/restore-capabilities":{"get":{"tags":["Restore"],"operationId":"get_restore_capabilities","parameters":[{"name":"id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Capabilities declared by the service","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RestoreCapabilitiesResponse"}}}},"404":{"description":"Service not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/restore-plan":{"post":{"tags":["Restore"],"operationId":"plan_restore","parameters":[{"name":"id","in":"path","description":"Target service id","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartRestoreRequest"}}},"required":true},"responses":{"200":{"description":"Preview of what the restore will do","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RestorePlan"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Backup or service not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/restore-runs":{"get":{"tags":["Restore"],"operationId":"list_restore_runs_for_service","parameters":[{"name":"id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Recent restore runs for the service","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RestoreRunView"}}}}}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/retry":{"post":{"tags":["External Services"],"summary":"Retry a failed cluster service initialization.","description":"Cleans up any leftover containers from the previous attempt and\nre-runs cluster initialization with the provided member specifications.","operationId":"retry_cluster","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RetryClusterRequest"}}},"required":true},"responses":{"200":{"description":"Cluster retry initiated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}},"400":{"description":"Service is not a failed cluster"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/runtime":{"get":{"tags":["External Services"],"summary":"Inspect a service's container(s): status, restart count, OOM-killed flag,\nexit code, and the cgroup limits actually applied.","operationId":"get_service_runtime","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Container runtime snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceRuntimeReport"}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/start":{"post":{"tags":["External Services"],"summary":"Start an external service","operationId":"start_service","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Service started successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}},"404":{"description":"Service not found"},"409":{"description":"A Postgres major upgrade is in progress for this service"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/stats":{"get":{"tags":["External Services"],"summary":"Sample current CPU/memory usage from each of a service's containers.\nOne-shot sample, no streaming. Cheap to call (single Docker round-trip\nper member) so the UI can poll on a 5–10s interval.","operationId":"get_service_stats","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Container stats snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceStatsReport"}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/stop":{"post":{"tags":["External Services"],"summary":"Stop an external service","operationId":"stop_service","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Service stopped successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/upgrade":{"post":{"tags":["External Services"],"summary":"Upgrade external service to new Docker image with data migration\nThis endpoint uses service-specific upgrade procedures (e.g., pg_upgrade for PostgreSQL)","operationId":"upgrade_service","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpgradeExternalServiceRequest"}}},"required":true},"responses":{"200":{"description":"Service upgraded successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}},"400":{"description":"Invalid request or upgrade not supported"},"404":{"description":"Service not found"},"409":{"description":"A major upgrade is already in progress for this service"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/wal-health":{"get":{"tags":["External Services"],"summary":"Postgres WAL & archive health snapshot","description":"Returns the latest WAL/archive health snapshot recorded by the background\nhealth monitor for a Postgres external service. Powers the warning banner\non the service detail page when the disk is filling up due to stale\nreplication slots, archive backlog, or misconfigured `archive_command`.\n\nReturns 404 when no snapshot exists yet (probe hasn't run, or the service\nisn't Postgres).","operationId":"getPostgresWalHealth","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Latest WAL health snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PostgresWalHealth"}}}},"404":{"description":"Service not found, or no WAL snapshot available"},"500":{"description":"Internal server error"}}}},"/external-services/{service_id}/pg-stat-statements/enable":{"post":{"tags":["External Services"],"summary":"Enable `pg_stat_statements` on a standalone Postgres service.","description":"Stops the container and restarts it so that the\n`shared_preload_libraries=pg_stat_statements` CMD flag (baked into every\nnew standalone Postgres container) takes effect. The named data volume is\nreused unchanged — no data is lost.\n\n**Clustered (HA) services are rejected** with 422 — a blind single-container\nrestart bypasses controlled failover. For clustered services the response\nbody describes the manual rolling-restart steps.\n\nConfirmation is the caller's responsibility (UI dialog / CLI `--yes` flag)\nbefore invoking this endpoint.","operationId":"ExternalServiceEnablePgStatStatements","parameters":[{"name":"service_id","in":"path","description":"ID of the provisioned standalone Postgres service","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Container restarted; pg_stat_statements now active","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnablePgStatStatementsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions (requires external_services:write)"},"404":{"description":"Service not found"},"422":{"description":"Service is not standalone Postgres (cluster or wrong type)"},"500":{"description":"Restart failed"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/pg-stat-statements/reset":{"post":{"tags":["External Services"],"summary":"Reset all statistics accumulated by `pg_stat_statements` for a Postgres\nservice. This affects every user, database, and normalized query tracked by\nthe target Postgres instance and cannot be undone.","operationId":"ExternalServiceResetPgStatStatements","parameters":[{"name":"service_id","in":"path","description":"ID of the provisioned Postgres service","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"Explicit confirmation of the global, irreversible reset","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResetPgStatStatementsRequest"}}},"required":true},"responses":{"200":{"description":"All accumulated pg_stat_statements statistics cleared","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResetPgStatStatementsResponse"}}}},"400":{"description":"Missing or invalid reset confirmation"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions (requires external_services:write)"},"404":{"description":"Service not found"},"422":{"description":"Service is not Postgres"},"502":{"description":"Target Postgres rejected or failed the reset operation"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/pg-stat-statements/slow-queries":{"get":{"tags":["External Services"],"operationId":"get_slow_queries","parameters":[{"name":"service_id","in":"path","description":"ID of the provisioned Postgres service","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-based). Defaults to 1.","required":false,"schema":{"type":["integer","null"],"format":"int32","minimum":0}},{"name":"page_size","in":"query","description":"Number of rows per page (1–100). Defaults to 20.","required":false,"schema":{"type":["integer","null"],"format":"int32","minimum":0}},{"name":"sort_by","in":"query","description":"Column to sort by: one of `calls`, `total_exec_time_ms`,\n`mean_exec_time_ms`, `rows`, `cache_hit_ratio`. Defaults to\n`mean_exec_time_ms`. Applied server-side so ordering stays\nconsistent across pages.","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","description":"Sort direction: `asc` or `desc`. Defaults to `desc`.","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"Paginated slow queries from pg_stat_statements","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SlowQueriesResponse"}}}},"400":{"description":"Invalid pagination or sort parameters"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions (requires external_services:read)"},"404":{"description":"Service not found"},"422":{"description":"Service is not a Postgres service"},"503":{"description":"pg_stat_statements extension not available (container restart required)"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/containers":{"get":{"tags":["External Services - Query"],"summary":"List containers at the root level (databases, keyspaces, etc.)","operationId":"list_root_containers","parameters":[{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of root containers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ContainerResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/containers/{path}":{"get":{"tags":["External Services - Query"],"summary":"List containers at a specific path\nPath segments are separated by forward slashes\nExample: /external-services/1/query/containers/mydb lists schemas in database \"mydb\"","operationId":"list_containers_at_path","parameters":[{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of containers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ContainerResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service or container not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/containers/{path}/entities":{"get":{"tags":["External Services - Query"],"summary":"List entities (tables, collections, etc.) in a container\nExample: /external-services/1/query/containers/mydb/public/entities lists tables in the public schema","operationId":"list_entities","parameters":[{"name":"limit","in":"query","description":"Maximum number of entities to return (default: 100, max: 1000)","required":false,"schema":{"type":"integer","minimum":0}},{"name":"token","in":"query","description":"Continuation token for pagination","required":false,"schema":{"type":"string"}},{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Paginated list of entities","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedEntitiesResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service or container not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/containers/{path}/entities/{entity}":{"get":{"tags":["External Services - Query"],"summary":"Get detailed information about an entity (table schema)","operationId":"get_entity_info","parameters":[{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","required":true,"schema":{"type":"string"}},{"name":"entity","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Entity details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EntityInfoResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service, container, or entity not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/containers/{path}/entities/{entity}/data":{"post":{"tags":["External Services - Query"],"summary":"Query data from an entity with optional filters, pagination, and sorting","operationId":"query_data","parameters":[{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","required":true,"schema":{"type":"string"}},{"name":"entity","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QueryDataRequest"}}},"required":true},"responses":{"200":{"description":"Query results","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QueryDataResponse"}}}},"400":{"description":"Invalid query"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service, container, or entity not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/containers/{path}/entities/{entity}/download":{"get":{"tags":["External Services - Query"],"summary":"Download an object (S3 only) as a streaming response","operationId":"download_object","parameters":[{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","required":true,"schema":{"type":"string"}},{"name":"entity","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Object data stream","content":{"application/octet-stream":{}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Object not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/containers/{path}/info":{"get":{"tags":["External Services - Query"],"summary":"Get information about a specific container","operationId":"get_container_info","parameters":[{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Container information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service or container not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/explorer-support":{"get":{"tags":["External Services - Query"],"summary":"Check if a service supports query explorer functionality","operationId":"check_explorer_support","parameters":[{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Explorer support information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExplorerSupportResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/upgrades":{"get":{"tags":["Postgres Upgrades"],"summary":"List recent upgrades for a single service (newest first, page size 50).","operationId":"list_pg_upgrades","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Recent upgrades","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PgUpgradeResponse"}}}}},"500":{"description":"Internal error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Postgres Upgrades"],"summary":"Start a new PostgreSQL major-version upgrade for a service.","operationId":"start_pg_upgrade","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartPgUpgradeRequest"}}},"required":true},"responses":{"201":{"description":"Upgrade started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PgUpgradeResponse"}}}},"400":{"description":"Invalid request"},"409":{"description":"An upgrade is already running for this service"},"412":{"description":"No default S3 source configured"},"500":{"description":"Internal error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/upgrades/{id}":{"get":{"tags":["Postgres Upgrades"],"summary":"Get a single upgrade by id, scoped to a service.","operationId":"get_pg_upgrade","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"id","in":"path","description":"Upgrade id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Upgrade","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PgUpgradeResponse"}}}},"404":{"description":"Not found"},"500":{"description":"Internal error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/upgrades/{id}/cancel":{"post":{"tags":["Postgres Upgrades"],"summary":"Cancel an in-flight upgrade. The orchestrator stops at its next phase\nboundary; already-terminal upgrades return 409.","operationId":"cancel_pg_upgrade","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"id","in":"path","description":"Upgrade id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Cancellation requested","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PgUpgradeResponse"}}}},"404":{"description":"Not found"},"409":{"description":"Upgrade already terminal"},"500":{"description":"Internal error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/upgrades/{id}/logs":{"get":{"tags":["Postgres Upgrades"],"summary":"Get the accumulated JSONL log content for an upgrade (for dashboard display).","operationId":"get_pg_upgrade_logs","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"id","in":"path","description":"Upgrade id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Log content","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PgUpgradeLogResponse"}}}},"404":{"description":"Not found"},"500":{"description":"Internal error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/upgrades/{id}/retry":{"post":{"tags":["Postgres Upgrades"],"summary":"Retry a failed upgrade. The phase is preserved, so the state machine\nresumes from where it failed.","operationId":"retry_pg_upgrade","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"id","in":"path","description":"Upgrade id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Retry scheduled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PgUpgradeResponse"}}}},"400":{"description":"Upgrade is not in a retriable state"},"404":{"description":"Not found"},"500":{"description":"Internal error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/upgrades/{id}/rollback":{"post":{"tags":["Postgres Upgrades"],"summary":"Roll a completed upgrade back to its pre-upgrade PGDATA volume and old image.\nOnly valid while the rollback retention window is still open (see\n`ROLLBACK_RETENTION_DAYS`) and the rollback volume has not been swept.","operationId":"rollback_pg_upgrade","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"id","in":"path","description":"Upgrade id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Rollback complete","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PgUpgradeResponse"}}}},"404":{"description":"Not found"},"409":{"description":"Upgrade is not in a rollbackable state (not completed, volume swept, or retention expired)"},"500":{"description":"Internal error"}},"security":[{"bearer_auth":[]}]}},"/files/{file_path}":{"get":{"tags":["Files"],"operationId":"get_file","parameters":[{"name":"file_path","in":"path","description":"Relative path to the file from static directory","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"File content retrieved successfully","content":{"application/octet-stream":{}}},"401":{"description":"Authentication required"},"403":{"description":"Access denied - path outside static directory or insufficient permissions"},"404":{"description":"File not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/flags/exposure":{"post":{"tags":["Feature Flags"],"summary":"Record which flags a running app actually evaluated.","description":"This is what makes `last_evaluated_at` mean something. The snapshot\nendpoint hands the SDK every flag in the environment and evaluation then\nhappens locally, so the control plane cannot otherwise tell a flag that is\nreferenced by live code from one nothing has called in a year. Stamping on\nsnapshot fetch would mark every flag as freshly used and defeat the point.\n\nScope comes from the deployment token, never the body. The endpoint writes\nonly `last_evaluated_at` — never a flag's value — so \"a deployment token\ncannot change what a flag serves\" still holds despite this being a write.","operationId":"record_flag_exposure","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecordExposureRequest"}}},"required":true},"responses":{"200":{"description":"Exposure recorded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecordExposureResponse"}}}},"400":{"description":"Deployment token required"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/flags/snapshot":{"get":{"tags":["Feature Flags"],"summary":"Every flag for the caller's environment, collapsed to what the evaluator\nneeds.","description":"Scope comes from the deployment token, never from the URL: a container's\nbaked-in `TEMPS_API_TOKEN` identifies exactly one project (and usually one\nenvironment), so a compromised app cannot read another tenant's flags by\nchanging a path parameter.\n\nSupports `If-None-Match`, so the SDK's background poll is a 304 in the\ncommon case.","operationId":"get_flag_snapshot","parameters":[{"name":"environment_id","in":"query","description":"Required only when the calling token is project-wide rather than scoped\nto a single environment.","required":false,"schema":{"type":["integer","null"],"format":"int32"}}],"responses":{"200":{"description":"Snapshot for the environment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagSnapshotResponse"}}}},"304":{"description":"Snapshot unchanged"},"400":{"description":"Environment could not be determined"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/geo/{ip}":{"get":{"tags":["geo"],"summary":"Get geolocation information for an IP address","operationId":"get_ip_geolocation","parameters":[{"name":"ip","in":"path","description":"IP address to geolocate (IPv4 or IPv6)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Geolocation information retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GeoLocationResponse"}}}},"400":{"description":"Invalid IP address","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"IP address not found in database","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/git-connections":{"get":{"tags":["Git Providers"],"summary":"List user's git provider connections","operationId":"list_connections","parameters":[{"name":"page","in":"query","description":"Page number for pagination (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Number of items per page (default: 30, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"sort","in":"query","description":"Sort field (created_at, updated_at, account_name)","required":false,"schema":{"type":"string"}},{"name":"direction","in":"query","description":"Sort direction (asc, desc), default: desc","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of connections","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectionListResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}":{"delete":{"tags":["Git Providers"],"summary":"Permanently delete a git provider connection","operationId":"delete_connection","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Connection deleted successfully"},"400":{"description":"Connection is in use by projects and cannot be deleted"},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}/activate":{"post":{"tags":["Git Providers"],"summary":"Activate a git provider connection","operationId":"activate_connection","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Connection activated successfully"},"400":{"description":"Provider is deactivated and connection cannot be activated"},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}/deactivate":{"post":{"tags":["Git Providers"],"summary":"Deactivate a git provider connection","operationId":"deactivate_connection","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Connection deactivated successfully"},"400":{"description":"Connection is in use by projects and cannot be deactivated"},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}/health-check":{"post":{"tags":["Git Provider Connections"],"summary":"Run an on-demand health check for a git connection.","description":"Probes the upstream (GitHub App, PAT, or OAuth token), persists the result,\nand fires admin notifications on status transitions. Returns the updated\nconnection.","operationId":"run_connection_health_check","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Health check completed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}/repositories":{"get":{"tags":["Git Providers"],"summary":"List repositories for a specific connection","description":"Fetches repositories from the connected git provider with support for pagination, search, and filtering.\nThis endpoint calls the provider's API directly to get the most up-to-date repository list.","operationId":"list_repositories_by_connection","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"sort","in":"query","description":"Sort field (name, created_at, updated_at, stars, etc.)","required":false,"schema":{"type":"string"}},{"name":"direction","in":"query","description":"Sort direction (asc, desc)","required":false,"schema":{"type":"string"}},{"name":"search","in":"query","description":"Search term to filter repositories","required":false,"schema":{"type":"string"}},{"name":"owner","in":"query","description":"Filter by repository owner","required":false,"schema":{"type":"string"}},{"name":"language","in":"query","description":"Filter by programming language","required":false,"schema":{"type":"string"}},{"name":"private","in":"query","description":"Filter by private status (true/false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of repositories","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositoryListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}/sync":{"post":{"tags":["Git Providers"],"summary":"Start a repository sync for a connection","description":"Kicks off a background sync of the connection's repositories from the\nprovider. Returns `202 Accepted` immediately — the caller should poll\nthe connection endpoint for `syncing` / `synced_repository_count`\nupdates rather than waiting on this response. The sync is guarded by\na hard deadline and always releases the `syncing` flag on exit, so a\nclient that disconnects mid-sync will not leave the connection stuck.","operationId":"sync_repositories","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"202":{"description":"Repository sync started in background","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositorySyncStartedResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"409":{"description":"Sync already in progress"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}/update-token":{"post":{"tags":["Git Provider Connections"],"summary":"Update access token for a connection (when tokens expire or are rotated)","operationId":"update_connection_token","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTokenRequest"}}},"required":true},"responses":{"200":{"description":"Token updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTokenResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}/validate":{"get":{"tags":["Git Provider Connections"],"summary":"Validate a connection by testing the access token","operationId":"validate_connection","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Connection validation result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers":{"get":{"tags":["Git Providers"],"summary":"List all git providers","operationId":"list_git_providers","responses":{"200":{"description":"List of providers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProviderResponse"}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Git Providers"],"summary":"Create a new git provider configuration","operationId":"create_git_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProviderRequest"}}},"required":true},"responses":{"201":{"description":"Provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/bitbucket":{"post":{"tags":["Git Providers"],"summary":"Create a Bitbucket Cloud provider with access token or app password authentication","operationId":"create_bitbucket_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateBitbucketRequest"}}},"required":true},"responses":{"201":{"description":"Bitbucket provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request — missing or invalid auth fields"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/generic":{"post":{"tags":["Git Providers"],"summary":"Create a Generic git provider for self-hosted or arbitrary HTTPS git hosts.\nSupports public repositories (no token) and private repositories (token-based).","operationId":"create_generic_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGenericRequest"}}},"required":true},"responses":{"201":{"description":"Generic git provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request — invalid clone URL or missing fields"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/gitea/pat":{"post":{"tags":["Git Providers"],"summary":"Create a Gitea Personal Access Token provider","operationId":"create_gitea_pat_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGiteaPATRequest"}}},"required":true},"responses":{"201":{"description":"Gitea PAT provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request — invalid URL or missing fields"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/github/pat":{"post":{"tags":["Git Providers"],"summary":"Create a GitHub Personal Access Token provider","operationId":"create_github_pat_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGitHubPATRequest"}}},"required":true},"responses":{"201":{"description":"GitHub PAT provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/gitlab/oauth":{"post":{"tags":["Git Providers"],"summary":"Create a GitLab OAuth provider","operationId":"create_gitlab_oauth_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGitLabOAuthRequest"}}},"required":true},"responses":{"201":{"description":"GitLab OAuth provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/gitlab/pat":{"post":{"tags":["Git Providers"],"summary":"Create a GitLab PAT provider","operationId":"create_gitlab_pat_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGitLabPATRequest"}}},"required":true},"responses":{"201":{"description":"GitLab PAT provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}":{"get":{"tags":["Git Providers"],"summary":"Get a specific git provider","operationId":"get_git_provider","parameters":[{"name":"provider_id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Provider details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Git Providers"],"summary":"Permanently delete a git provider","operationId":"delete_git_provider","parameters":[{"name":"provider_id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Provider deleted successfully"},"400":{"description":"Provider has connections and cannot be deleted"},"401":{"description":"Unauthorized"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/activate":{"post":{"tags":["Git Providers"],"summary":"Activate a git provider","operationId":"activate_provider","parameters":[{"name":"provider_id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Provider activated successfully"},"401":{"description":"Unauthorized"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/callback":{"get":{"tags":["Git Providers"],"summary":"Handle OAuth callback for a git provider","operationId":"handle_git_provider_oauth_callback","parameters":[{"name":"provider_id","in":"path","description":"Git provider ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"code","in":"query","description":"OAuth authorization code","required":true,"schema":{"type":"string"}},{"name":"state","in":"query","description":"CSRF state token","required":true,"schema":{"type":"string"}}],"responses":{"302":{"description":"Redirect to success page"},"400":{"description":"Bad request"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}}}},"/git-providers/{provider_id}/connections":{"get":{"tags":["Git Providers"],"summary":"Get connections for a specific git provider","operationId":"get_provider_connections","parameters":[{"name":"provider_id","in":"path","description":"Provider ID to get connections for","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of connections for the provider","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ConnectionResponse"}}}}},"401":{"description":"Unauthorized"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/credentials":{"patch":{"tags":["Git Providers"],"summary":"Partially update credentials for an existing git provider. Only the fields\nyou send are replaced; omitted fields keep their stored values. Fields that\ndon't apply to the provider's auth method are ignored on the service side.","operationId":"update_git_provider_credentials","parameters":[{"name":"provider_id","in":"path","description":"Git provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProviderCredentialsRequest"}}},"required":true},"responses":{"200":{"description":"Credentials updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/deactivate":{"post":{"tags":["Git Providers"],"summary":"Deactivate a git provider","operationId":"deactivate_provider","parameters":[{"name":"provider_id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Provider deactivated successfully"},"401":{"description":"Unauthorized"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/deletion-check":{"get":{"tags":["Git Providers"],"summary":"Check if a git provider can be safely deleted","operationId":"check_provider_deletion_safety","parameters":[{"name":"provider_id","in":"path","description":"Git provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deletion check result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderDeletionCheckResponse"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/oauth/authorize":{"get":{"tags":["Git Providers"],"summary":"Start OAuth flow for a git provider","operationId":"start_git_provider_oauth","parameters":[{"name":"provider_id","in":"path","description":"Git provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"302":{"description":"Redirect to OAuth provider"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/repositories":{"get":{"tags":["Git Providers"],"summary":"List all repositories for a specific provider","description":"Lists repositories synced to the database across every connection under\nthis provider, with the same pagination/filtering as `/repositories`.","operationId":"list_repositories_by_provider","parameters":[{"name":"provider_id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"sort","in":"query","description":"Sort field (name, created_at, updated_at, stars, watchers, size, issues)","required":false,"schema":{"type":"string"}},{"name":"direction","in":"query","description":"Sort direction (asc, desc)","required":false,"schema":{"type":"string"}},{"name":"search","in":"query","description":"Search term to filter repositories","required":false,"schema":{"type":"string"}},{"name":"owner","in":"query","description":"Filter by repository owner","required":false,"schema":{"type":"string"}},{"name":"language","in":"query","description":"Filter by programming language","required":false,"schema":{"type":"string"}},{"name":"private","in":"query","description":"Filter by private status (true/false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of repositories","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositoryListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/safe-delete":{"delete":{"tags":["Git Providers"],"summary":"Safely delete a git provider (only if no projects are using it)","operationId":"delete_provider_safely","parameters":[{"name":"provider_id","in":"path","description":"Git provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Provider successfully deleted"},"400":{"description":"Cannot delete provider because it's in use"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git/public/{provider}/{owner}/{repo}":{"get":{"tags":["Public Repositories"],"summary":"Get information about a public repository (supports GitHub and GitLab)","operationId":"get_public_repository","parameters":[{"name":"provider","in":"path","description":"Git provider (github or gitlab)","required":true,"schema":{"type":"string"}},{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"repo","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Repository information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicRepositoryInfo"}}}},"400":{"description":"Provider not supported"},"404":{"description":"Repository not found"},"429":{"description":"API rate limit exceeded"},"500":{"description":"Internal server error"}}}},"/git/public/{provider}/{owner}/{repo}/branches":{"get":{"tags":["Public Repositories"],"summary":"Get branches for a public repository (supports GitHub and GitLab)","operationId":"get_public_branches","parameters":[{"name":"provider","in":"path","description":"Git provider (github or gitlab)","required":true,"schema":{"type":"string"}},{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"repo","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}},{"name":"fresh","in":"query","description":"Force fetch fresh data, bypassing cache (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of branches","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BranchListResponse"}}}},"400":{"description":"Provider not supported"},"404":{"description":"Repository not found"},"429":{"description":"API rate limit exceeded"},"500":{"description":"Internal server error"}}}},"/git/public/{provider}/{owner}/{repo}/presets":{"get":{"tags":["Public Repositories"],"summary":"Detect presets for a public repository (supports GitHub and GitLab)","operationId":"detect_public_presets","parameters":[{"name":"provider","in":"path","description":"Git provider (github or gitlab)","required":true,"schema":{"type":"string"}},{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"repo","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}},{"name":"branch","in":"query","description":"Branch name to detect presets for (default: repository's default branch)","required":false,"schema":{"type":["string","null"]}},{"name":"fresh","in":"query","description":"Force fetch fresh data, bypassing cache (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Detected presets","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicPresetResponse"}}}},"400":{"description":"Provider not supported"},"404":{"description":"Repository or branch not found"},"429":{"description":"API rate limit exceeded"},"500":{"description":"Internal server error"}}}},"/imports/discover":{"post":{"tags":["Imports"],"summary":"Discover workloads from a source","operationId":"discover_workloads","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiscoverRequest"}}},"required":true},"responses":{"200":{"description":"List of discovered workloads","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiscoverResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/imports/execute":{"post":{"tags":["Imports"],"summary":"Execute an import","operationId":"execute_import","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecuteImportRequest"}}},"required":true},"responses":{"202":{"description":"Import execution started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecuteImportResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/imports/plan":{"post":{"tags":["Imports"],"summary":"Create an import plan","operationId":"create_plan","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePlanRequest"}}},"required":true},"responses":{"200":{"description":"Import plan created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePlanResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/imports/sources":{"get":{"tags":["Imports"],"summary":"List available import sources","operationId":"list_sources","responses":{"200":{"description":"List of available import sources","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ImportSourceInfo"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/imports/{session_id}":{"get":{"tags":["Imports"],"summary":"Get import status","operationId":"get_import_status","parameters":[{"name":"session_id","in":"path","description":"Import session ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Import status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportStatusResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Import session not found"}},"security":[{"bearer_auth":[]}]}},"/incidents/{incident_id}":{"get":{"tags":["Status Page"],"summary":"Get an incident by ID","operationId":"get_incident","parameters":[{"name":"incident_id","in":"path","description":"Incident ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved incident","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncidentResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Incident not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/incidents/{incident_id}/status":{"patch":{"tags":["Status Page"],"summary":"Update incident status","operationId":"update_incident_status","parameters":[{"name":"incident_id","in":"path","description":"Incident ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateIncidentStatusRequest"}}},"required":true},"responses":{"200":{"description":"Incident status updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncidentResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Incident not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/incidents/{incident_id}/updates":{"get":{"tags":["Status Page"],"summary":"Get incident updates","operationId":"get_incident_updates","parameters":[{"name":"incident_id","in":"path","description":"Incident ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved incident updates","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/IncidentUpdateResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Incident not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/internal/nodes":{"get":{"tags":["Nodes"],"summary":"List all registered nodes (admin — session auth via RequireAuth)","operationId":"admin_list_nodes","responses":{"200":{"description":"List of nodes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NodeListResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/internal/nodes/register":{"post":{"tags":["Nodes"],"summary":"Register a new worker node or reconnect an existing one","operationId":"register_node","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterNodeApiRequest"}}},"required":true},"responses":{"200":{"description":"Node reconnected successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterNodeResponse"}}}},"201":{"description":"Node registered successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterNodeResponse"}}}},"400":{"description":"Validation error"},"500":{"description":"Internal server error"}}}},"/internal/nodes/{node_id}":{"get":{"tags":["Nodes"],"summary":"Get a specific node by ID (admin — session auth via RequireAuth)","operationId":"admin_get_node","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Node details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NodeInfoResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Nodes"],"summary":"Remove a node from the cluster entirely. The node should be drained first\nto ensure containers have been rescheduled. If the node still has active\ncontainers, it will be drained automatically before removal.","operationId":"admin_remove_node","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Node removed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RemoveNodeResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Node not found"},"409":{"description":"Node still has active containers"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/internal/nodes/{node_id}/containers":{"get":{"tags":["Nodes"],"summary":"List all containers running on a specific node","operationId":"admin_list_node_containers","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Containers on this node","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NodeContainerListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/internal/nodes/{node_id}/dns/ack":{"post":{"tags":["Internal DNS"],"summary":"`POST /internal/nodes/{node_id}/dns/ack`","operationId":"post_dns_ack","parameters":[{"name":"node_id","in":"path","description":"Node id, must match the bearer token's node","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsAckRequest"}}},"required":true},"responses":{"200":{"description":"ACK accepted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsAckResponse"}}}},"400":{"description":"ACK higher than server generation"},"401":{"description":"Missing or invalid bearer token"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}}}},"/internal/nodes/{node_id}/dns/changes":{"get":{"tags":["Internal DNS"],"summary":"`GET /internal/nodes/{node_id}/dns/changes?since=N`","operationId":"get_dns_changes","parameters":[{"name":"node_id","in":"path","description":"Node id, must match the bearer token's node","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"since","in":"query","description":"Highest generation the agent has already applied. Pass `0` to\nrequest a full zone snapshot. Defaults to `0` if omitted.","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Diff or full snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsChangesResponse"}}}},"401":{"description":"Missing or invalid bearer token"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}}}},"/internal/nodes/{node_id}/drain":{"get":{"tags":["Nodes"],"summary":"Get the drain status for a node, including migration progress.","description":"Returns container counts and whether the drain is complete.\nCan be polled to track drain progress.","operationId":"admin_drain_status","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Drain status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DrainStatusResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Nodes"],"summary":"Drain a node: mark it as \"draining\" so no new replicas are scheduled on it,\nand trigger redeployment of all affected environments so their containers\nare rescheduled to healthy nodes.","operationId":"admin_drain_node","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Node drain initiated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DrainNodeResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Nodes"],"summary":"Undrain (reactivate) a node so it can accept new deployments again.\nOnly works for nodes in \"draining\" or \"drained\" status.","operationId":"admin_undrain_node","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Node reactivated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UndrainNodeResponse"}}}},"400":{"description":"Node not in drainable state"},"401":{"description":"Unauthorized"},"404":{"description":"Node not found"}},"security":[{"bearer_auth":[]}]}},"/internal/nodes/{node_id}/heartbeat":{"post":{"tags":["Nodes"],"summary":"Receive a heartbeat from a worker node","operationId":"node_heartbeat","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HeartbeatApiRequest"}}},"required":true},"responses":{"200":{"description":"Heartbeat received","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HeartbeatResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}}}},"/internal/nodes/{node_id}/network/peers":{"get":{"tags":["Nodes"],"summary":"`GET /internal/nodes/{node_id}/network/peers`","operationId":"list_peers","parameters":[{"name":"node_id","in":"path","description":"Node id, must match the bearer token's node","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Peer list and self-allocation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PeerListResponse"}}}},"401":{"description":"Missing or invalid bearer token"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}}}},"/internal/nodes/{node_id}/s3-credentials/{s3_source_id}":{"get":{"tags":["Nodes"],"summary":"Get decrypted S3 credentials for a backup/restore operation.","description":"Agents call this endpoint to receive the S3 credentials they need to upload\nor download backups. The credentials are decrypted from the stored S3 source\nand returned over the authenticated TLS/WireGuard channel.","operationId":"get_s3_credentials","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"s3_source_id","in":"path","description":"S3 source ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"S3 credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/S3CredentialsResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"S3 source not found"},"500":{"description":"Internal server error"}}}},"/ip-access-control":{"get":{"tags":["IP Access Control"],"summary":"List all IP access control rules","operationId":"list_ip_access_control","parameters":[{"name":"action","in":"query","description":"Filter by action (\"block\" or \"allow\")","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"List of IP access control rules","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/IpAccessControlResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["IP Access Control"],"summary":"Create a new IP access control rule","operationId":"create_ip_access_control","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateIpAccessControlRequest"}}},"required":true},"responses":{"201":{"description":"IP access control rule created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IpAccessControlResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"409":{"description":"Duplicate IP address","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ip-access-control/check/{ip}":{"get":{"tags":["IP Access Control"],"summary":"Check if an IP address is blocked","operationId":"check_ip_blocked","parameters":[{"name":"ip","in":"path","description":"IP address to check","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"IP block status"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ip-access-control/{id}":{"get":{"tags":["IP Access Control"],"summary":"Get a single IP access control rule by ID","operationId":"get_ip_access_control","parameters":[{"name":"id","in":"path","description":"IP access control rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"IP access control rule details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IpAccessControlResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"IP access control rule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["IP Access Control"],"summary":"Delete an IP access control rule","operationId":"delete_ip_access_control","parameters":[{"name":"id","in":"path","description":"IP access control rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"IP access control rule deleted"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"IP access control rule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["IP Access Control"],"summary":"Update an IP access control rule","operationId":"update_ip_access_control","parameters":[{"name":"id","in":"path","description":"IP access control rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateIpAccessControlRequest"}}},"required":true},"responses":{"200":{"description":"IP access control rule updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IpAccessControlResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"IP access control rule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/kv/del":{"post":{"tags":["KV Store"],"summary":"Delete one or more keys","operationId":"kv_del","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DelRequest"}}},"required":true},"responses":{"200":{"description":"Keys deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DelResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/disable":{"delete":{"tags":["KV Management"],"summary":"Disable KV service","operationId":"kv_disable","responses":{"200":{"description":"KV service disabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DisableKvResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"KV service not enabled"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/enable":{"post":{"tags":["KV Management"],"summary":"Enable KV service","operationId":"kv_enable","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnableKvRequest"}}},"required":true},"responses":{"200":{"description":"KV service enabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnableKvResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/expire":{"post":{"tags":["KV Store"],"summary":"Set expiration on a key","operationId":"kv_expire","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExpireRequest"}}},"required":true},"responses":{"200":{"description":"Expiration set","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExpireResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/get":{"post":{"tags":["KV Store"],"summary":"Get a value by key","operationId":"kv_get","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetRequest"}}},"required":true},"responses":{"200":{"description":"Value retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/incr":{"post":{"tags":["KV Store"],"summary":"Increment a numeric value","operationId":"kv_incr","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncrRequest"}}},"required":true},"responses":{"200":{"description":"Value incremented","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncrResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/keys":{"post":{"tags":["KV Store"],"summary":"Get keys matching a pattern","operationId":"kv_keys","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KeysRequest"}}},"required":true},"responses":{"200":{"description":"Keys retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KeysResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/set":{"post":{"tags":["KV Store"],"summary":"Set a value with optional expiration","operationId":"kv_set","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetRequest"}}},"required":true},"responses":{"200":{"description":"Value set","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/status":{"get":{"tags":["KV Management"],"summary":"Get KV service status","operationId":"kv_status","responses":{"200":{"description":"KV service status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KvStatusResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/ttl":{"post":{"tags":["KV Store"],"summary":"Get time-to-live for a key","operationId":"kv_ttl","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TtlRequest"}}},"required":true},"responses":{"200":{"description":"TTL retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TtlResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/update":{"patch":{"tags":["KV Management"],"summary":"Update KV service configuration","operationId":"kv_update","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateKvRequest"}}},"required":true},"responses":{"200":{"description":"KV service updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateKvResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"KV service not enabled"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/lb/routes":{"get":{"tags":["Load Balancer"],"operationId":"list_routes","responses":{"200":{"description":"List of routes","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RouteResponse"}}}}},"500":{"description":"Internal server error"}}},"post":{"tags":["Load Balancer"],"operationId":"create_route","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRouteRequest"}}},"required":true},"responses":{"201":{"description":"Route created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteResponse"}}}},"400":{"description":"Invalid request"}}}},"/lb/routes/{domain}":{"get":{"tags":["Load Balancer"],"operationId":"get_route","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Route found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteResponse"}}}},"404":{"description":"Route not found"}}},"put":{"tags":["Load Balancer"],"operationId":"update_route","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateRouteRequest"}}},"required":true},"responses":{"200":{"description":"Route updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteResponse"}}}},"404":{"description":"Route not found"}}},"delete":{"tags":["Load Balancer"],"operationId":"delete_route","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Route deleted successfully"},"404":{"description":"Route not found"}}}},"/logout":{"post":{"tags":["Authentication"],"operationId":"logout","responses":{"200":{"description":"Successfully logged out"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"session_token":[]}]}},"/logs/context":{"get":{"tags":["Logs"],"summary":"Get context lines surrounding a specific log line","operationId":"get_log_context","parameters":[{"name":"chunk_id","in":"query","description":"Chunk ID","required":true,"schema":{"type":"string"}},{"name":"line_offset","in":"query","description":"Line offset within the chunk","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"lines","in":"query","description":"Context lines before and after (default: 25)","required":false,"schema":{"type":"integer","format":"int32","minimum":0}}],"responses":{"200":{"description":"Context lines","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContextLogsResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Chunk not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/logs/search":{"post":{"tags":["Logs"],"summary":"Search logs with structured filters and full text search","operationId":"search_logs","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchLogsRequest"}}},"required":true},"responses":{"200":{"description":"Search results","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchLogsResponse"}}}},"400":{"description":"Invalid search parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/logs/tail":{"get":{"tags":["Logs"],"summary":"Live tail logs via Server-Sent Events","operationId":"tail_logs","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"string"}},{"name":"service","in":"query","description":"Service name","required":true,"schema":{"type":"string"}},{"name":"env","in":"query","description":"Environment","required":true,"schema":{"type":"string"}},{"name":"levels","in":"query","description":"Optional level filters","required":true,"schema":{"type":"array","items":{"type":"string"}}},{"name":"text","in":"query","description":"Optional text filter","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"SSE stream of log lines"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/monitors-health/projects":{"get":{"tags":["Status Page"],"summary":"Get monitor-based health summaries for multiple projects in a single query","operationId":"get_projects_monitor_health","parameters":[{"name":"project_ids","in":"query","description":"Comma-separated list of project IDs","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Health summaries per project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectsMonitorHealthResponse"}}}},"400":{"description":"Invalid parameters"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/monitors/{monitor_id}":{"get":{"tags":["Status Page"],"summary":"Get a monitor by ID","operationId":"get_monitor","parameters":[{"name":"monitor_id","in":"path","description":"Monitor ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved monitor","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MonitorResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Monitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Status Page"],"summary":"Delete a monitor","operationId":"delete_monitor","parameters":[{"name":"monitor_id","in":"path","description":"Monitor ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Monitor deleted successfully"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Monitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/monitors/{monitor_id}/bucketed":{"get":{"tags":["Status Page"],"summary":"Get bucketed status data for a monitor using TimescaleDB","operationId":"get_bucketed_status","parameters":[{"name":"monitor_id","in":"path","description":"Monitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"interval","in":"query","description":"Bucket interval: '5min', 'hourly', or 'daily' (default: hourly)","required":false,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601) (default: 24 hours ago)","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (ISO 8601) (default: now)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved bucketed status data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatusBucketedResponse"}}}},"400":{"description":"Invalid parameters"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Monitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/monitors/{monitor_id}/current-status":{"get":{"tags":["Status Page"],"summary":"Get current status and uptime metrics for a monitor","operationId":"get_current_monitor_status","parameters":[{"name":"monitor_id","in":"path","description":"Monitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_time","in":"query","description":"Custom start time (ISO 8601) - overrides timeframe","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"Custom end time (ISO 8601)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved current status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CurrentStatusResponse"}}}},"400":{"description":"Invalid time parameters"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Monitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/monitors/{monitor_id}/uptime":{"get":{"tags":["Status Page"],"summary":"Get uptime history for a monitor","operationId":"get_uptime_history","parameters":[{"name":"monitor_id","in":"path","description":"Monitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"days","in":"query","description":"Number of days of history (default: 60) - ignored if start_time/end_time provided","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601) - overrides days parameter","required":true,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (ISO 8601) - defaults to now","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved uptime history","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UptimeHistoryResponse"}}}},"400":{"description":"Invalid time parameters"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Monitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/nodes/{id}/metrics":{"get":{"tags":["Metrics"],"summary":"Fetch a time-series range for a single metric on a node.","operationId":"NodeMetricsGetRange","parameters":[{"name":"id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"metric","in":"query","description":"Metric name, e.g. `\"pg.connections_active\"`.","required":true,"schema":{"type":"string"}},{"name":"range","in":"query","description":"Time window: `\"1h\"` | `\"6h\"` | `\"24h\"` | `\"7d\"`.","required":false,"schema":{"type":"string"}},{"name":"percentile","in":"query","description":"Optional histogram percentile (0–100). When provided, the endpoint\nfetches histogram buckets and computes the requested quantile.","required":false,"schema":{"type":["number","null"],"format":"double"}}],"responses":{"200":{"description":"Metric time series data points","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MetricDataPoint"}}}}},"400":{"description":"Invalid query parameters"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"},"503":{"description":"Metrics store not available"}},"security":[{"bearer_auth":[]}]}},"/notification-preferences":{"get":{"tags":["Notification Preferences"],"summary":"Get notification preferences","operationId":"get_preferences","responses":{"200":{"description":"Successfully retrieved preferences","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationPreferencesResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Notification Preferences"],"summary":"Update notification preferences","operationId":"update_preferences","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePreferencesRequest"}}},"required":true},"responses":{"200":{"description":"Successfully updated preferences","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationPreferencesResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Notification Preferences"],"summary":"Delete notification preferences","operationId":"delete_preferences","responses":{"204":{"description":"Successfully deleted preferences"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers":{"get":{"tags":["Notification Providers"],"summary":"List all notification providers","operationId":"list_notification_providers","parameters":[{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20},{"name":"sort_by","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"Successfully retrieved providers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}}},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Notification Providers"],"summary":"Create a new notification provider","operationId":"create_notification_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProviderRequest"}}},"required":true},"responses":{"201":{"description":"Successfully created provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"400":{"description":"Invalid request"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/cloudflare":{"post":{"tags":["Notification Providers"],"summary":"Create a new Cloudflare Email Sending notification provider","operationId":"create_cloudflare_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCloudflareProviderRequest"}}},"required":true},"responses":{"201":{"description":"Successfully created Cloudflare provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"400":{"description":"Invalid request"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/cloudflare/{id}":{"put":{"tags":["Notification Providers"],"summary":"Update a Cloudflare Email Sending notification provider","operationId":"update_cloudflare_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCloudflareProviderRequest"}}},"required":true},"responses":{"200":{"description":"Successfully updated Cloudflare provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/email":{"post":{"tags":["Notification Providers"],"summary":"Create a new Email notification provider","operationId":"create_notification_email_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateNotificationEmailProviderRequest"}}},"required":true},"responses":{"201":{"description":"Successfully created Email provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"400":{"description":"Invalid request"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/email/{id}":{"put":{"tags":["Notification Providers"],"summary":"Update an Email notification provider","operationId":"update_notification_email_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateNotificationEmailProviderRequest"}}},"required":true},"responses":{"200":{"description":"Successfully updated Email provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/slack":{"post":{"tags":["Notification Providers"],"summary":"Create a new Slack notification provider","operationId":"create_slack_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSlackProviderRequest"}}},"required":true},"responses":{"201":{"description":"Successfully created Slack provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"400":{"description":"Invalid request"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/slack/{id}":{"put":{"tags":["Notification Providers"],"summary":"Update a Slack notification provider","operationId":"update_slack_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSlackProviderRequest"}}},"required":true},"responses":{"200":{"description":"Successfully updated Slack provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/webhook":{"post":{"tags":["Notification Providers"],"summary":"Create a new Webhook notification provider","description":"Webhook providers send notifications as JSON payloads to any HTTP endpoint.\nYou can configure custom headers for authentication (Bearer tokens, API keys, etc.).\nThe webhook will receive a JSON payload with notification details including:\nid, title, message, type, priority, severity, timestamp, and metadata.","operationId":"create_webhook_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWebhookProviderRequest"}}},"required":true},"responses":{"201":{"description":"Successfully created Webhook provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"400":{"description":"Invalid request"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/webhook/{id}":{"put":{"tags":["Notification Providers"],"summary":"Update a Webhook notification provider","operationId":"update_webhook_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWebhookProviderRequest"}}},"required":true},"responses":{"200":{"description":"Successfully updated Webhook provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/{id}":{"get":{"tags":["Notification Providers"],"summary":"Get a single notification provider","operationId":"get_notification_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Notification Providers"],"summary":"Update a notification provider","operationId":"update_notification_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProviderRequest"}}},"required":true},"responses":{"200":{"description":"Successfully updated provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"400":{"description":"Invalid masked provider configuration"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Notification Providers"],"summary":"Delete a notification provider","operationId":"delete_notification_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Successfully deleted provider"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/{id}/config/{field}":{"get":{"tags":["Notification Providers"],"operationId":"reveal_notification_provider_config","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"field","in":"path","description":"Sensitive field, such as password or headers.Authorization","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sensitive provider configuration value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SensitiveConfigValueResponse"}}}},"400":{"description":"Field is not revealable"},"403":{"description":"Missing secrets:read permission"},"404":{"description":"Provider or field not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/{id}/test":{"post":{"tags":["Notification Providers"],"summary":"Test a notification provider","operationId":"test_notification_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Test result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestProviderResponse"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/orders":{"get":{"tags":["Domains"],"summary":"List all ACME orders","operationId":"list_orders","parameters":[{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20},{"name":"sort_by","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"Orders retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListOrdersResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/otel/alerts":{"get":{"tags":["Alerts"],"summary":"List alert rules for a project (newest first, paginated).","operationId":"list_alerts","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Alert rules for the project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricAlertsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Alerts"],"summary":"Create a new alert rule for a project.","operationId":"create_alert","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMetricAlertRequest"}}},"required":true},"responses":{"201":{"description":"Alert rule created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricAlertRuleResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/alerts/preview":{"post":{"tags":["Alerts"],"summary":"Backtest an anomaly detector over a time range without saving a rule.","description":"Replays the metric against the same band the evaluator would use, returning\nthe per-bucket band + which points would have fired. Powers the form's\n\"would this have fired?\" preview and the explorer band overlay. Read-only.","operationId":"preview_alert","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnomalyPreviewRequest"}}},"required":true},"responses":{"200":{"description":"Per-bucket band + breach points","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnomalyPreviewResponse"}}}},"400":{"description":"Not an anomaly detector / bad input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/alerts/{id}":{"get":{"tags":["Alerts"],"summary":"Fetch a single alert rule by id.","operationId":"get_alert","parameters":[{"name":"id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Owning project ID (scopes the lookup)","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Alert rule","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricAlertRuleResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Alert rule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Alerts"],"summary":"Delete an alert rule.","operationId":"delete_alert","parameters":[{"name":"id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Owning project ID (scopes the delete)","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Alert rule deleted"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Alert rule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Alerts"],"summary":"Update an alert rule's fields.","operationId":"update_alert","parameters":[{"name":"id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Owning project ID (scopes the update)","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMetricAlertRequest"}}},"required":true},"responses":{"200":{"description":"Alert rule updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricAlertRuleResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Alert rule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/dashboards":{"get":{"tags":["Dashboards"],"summary":"List dashboards for a project (newest first, paginated).","operationId":"list_dashboards","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Dashboards for the project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelDashboardsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Dashboards"],"summary":"Create a new dashboard for a project.","operationId":"create_dashboard","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDashboardRequest"}}},"required":true},"responses":{"201":{"description":"Dashboard created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelDashboardResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/dashboards/{id}":{"get":{"tags":["Dashboards"],"summary":"Fetch a single dashboard by id.","operationId":"get_dashboard","parameters":[{"name":"id","in":"path","description":"Dashboard ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Owning project ID (scopes the lookup)","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Dashboard","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelDashboardResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Dashboard not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Dashboards"],"summary":"Delete a dashboard.","operationId":"delete_dashboard","parameters":[{"name":"id","in":"path","description":"Dashboard ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Owning project ID (scopes the delete)","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Dashboard deleted"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Dashboard not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Dashboards"],"summary":"Update a dashboard's name and/or layout.","operationId":"update_dashboard","parameters":[{"name":"id","in":"path","description":"Dashboard ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Owning project ID (scopes the update)","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDashboardRequest"}}},"required":true},"responses":{"200":{"description":"Dashboard updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelDashboardResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Dashboard not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/genai/traces":{"get":{"tags":["GenAI"],"summary":"Query GenAI trace summaries — traces containing spans with `gen_ai.*` attributes.","description":"`duration_ms` is the only field guaranteed to be milliseconds. `gen_ai.*`\nspan attributes (e.g. time-to-first-token, token latency) often follow the\nOTel GenAI semantic conventions, which use **seconds** (a fractional\ndouble), not milliseconds — do not read them as ms without converting.","operationId":"query_genai_traces","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"service_name","in":"query","description":"Filter by service name","required":false,"schema":{"type":"string"}},{"name":"gen_ai_system","in":"query","description":"Filter by AI system (openai, anthropic, etc.)","required":false,"schema":{"type":"string"}},{"name":"gen_ai_model","in":"query","description":"Filter by model (gpt-4, claude-sonnet-4-20250514, etc.)","required":false,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Start time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max traces to return (default: 50, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"offset","in":"query","description":"Offset for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"GenAI trace summaries","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenAiTraceSummariesResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/genai/traces/{project_id}/{trace_id}":{"get":{"tags":["GenAI"],"summary":"Get GenAI span details for a specific trace.","description":"`duration_ms` is the only field guaranteed to be milliseconds. `gen_ai.*`\nspan attributes (e.g. time-to-first-token, token latency) often follow the\nOTel GenAI semantic conventions, which use **seconds** (a fractional\ndouble), not milliseconds — do not read them as ms without converting.","operationId":"get_genai_trace","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"trace_id","in":"path","description":"Trace ID (hex)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"GenAI trace span details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenAiTraceDetailResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/global/traces/{trace_id}":{"get":{"tags":["Traces"],"summary":"Assemble a unified cross-project span waterfall (Phase 2).","description":"Fans out to every project that holds spans for `trace_id` (up to 20\nprojects, 10,000 total spans). Spans are annotated with\n`project_id`/`project_name` and sorted by `start_time ASC`.\n`truncated: true` signals a hit on either cap; `truncated_projects`\nlists the dropped project IDs. See ADR-027 §4 for the full design.","operationId":"getUnifiedTrace","parameters":[{"name":"trace_id","in":"path","description":"Trace ID (32 lowercase hex characters)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Unified cross-project trace waterfall","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnifiedTrace"}}}},"400":{"description":"trace_id is not 32 lowercase hex characters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions or deployment token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/health/{project_id}":{"get":{"tags":["OTel"],"summary":"Get health summaries for a project.","operationId":"get_health","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Health summaries","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/insights/{project_id}":{"get":{"tags":["Insights"],"summary":"List anomaly insights for a project.","operationId":"list_insights","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"status","in":"query","description":"Filter by status (active, resolved)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max insights to return (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"offset","in":"query","description":"Offset for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Insights list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InsightsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/logs":{"get":{"tags":["Telemetry Logs"],"summary":"Query log records with optional filters.","operationId":"query_logs","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"severity","in":"query","description":"Filter by severity (TRACE, DEBUG, INFO, WARN, ERROR, FATAL)","required":false,"schema":{"type":"string"}},{"name":"service_name","in":"query","description":"Filter by service name","required":false,"schema":{"type":"string"}},{"name":"search","in":"query","description":"Full-text search in log body (ILIKE)","required":false,"schema":{"type":"string"}},{"name":"trace_id","in":"query","description":"Filter by correlated trace ID","required":false,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Start time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max logs to return (default: 100, max: 1000)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"offset","in":"query","description":"Offset for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Log records","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LogsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/metric-label-keys":{"get":{"tags":["Telemetry Metrics"],"summary":"List the attribute (label) keys observed on a metric — powers the\nlabel-filter key autocomplete.","operationId":"list_metric_label_keys","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"metric_name","in":"query","description":"Metric to inspect","required":true,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Window start (RFC 3339); defaults to 24h before end","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"Window end (RFC 3339); defaults to now","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Distinct label keys","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricLabelKeysResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/metric-label-values":{"get":{"tags":["Telemetry Metrics"],"summary":"List the distinct values seen for a label key on a metric — powers value\nautocomplete once a key is chosen.","operationId":"list_metric_label_values","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"metric_name","in":"query","description":"Metric to inspect","required":true,"schema":{"type":"string"}},{"name":"label_key","in":"query","description":"Label key whose values to list (must match [a-zA-Z0-9_.:-])","required":true,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Window start (RFC 3339); defaults to 24h before end","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"Window end (RFC 3339); defaults to now","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Distinct label values","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricLabelValuesResponse"}}}},"400":{"description":"Invalid label key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/metric-names/{project_id}":{"get":{"tags":["Telemetry Metrics"],"summary":"List distinct metric names for a project.","operationId":"list_metric_names","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of metric names","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricNamesResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/metrics":{"get":{"tags":["Telemetry Metrics"],"summary":"Query metrics with time bucketing.","operationId":"query_metrics","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"metric_name","in":"query","description":"Filter by metric name","required":false,"schema":{"type":"string"}},{"name":"service_name","in":"query","description":"Filter by service name","required":false,"schema":{"type":"string"}},{"name":"environment","in":"query","description":"Filter by deployment environment","required":false,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Start time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"bucket_interval","in":"query","description":"Bucket interval (e.g. '1 hour', '5 minutes')","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max buckets to return (default: 1000)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"metric_type","in":"query","description":"Filter by metric type (gauge, sum, histogram, exponential_histogram, summary)","required":false,"schema":{"type":"string"}},{"name":"aggregation","in":"query","description":"Per-bucket aggregation: avg (default), sum, min, max, count, rate, p50/p95/p99, quantile:0.95","required":false,"schema":{"type":"string"}},{"name":"label_filters","in":"query","description":"Comma-separated key=value data-point label filters (keys must match [a-zA-Z0-9_.:-])","required":false,"schema":{"type":"string"}},{"name":"group_by","in":"query","description":"Comma-separated label keys to group series by","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Metrics data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricsResponse"}}}},"400":{"description":"Invalid label key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/pipeline-stats":{"get":{"tags":["OTel"],"summary":"Get OTel pipeline statistics (admin/system view).","operationId":"get_pipeline_stats","responses":{"200":{"description":"Pipeline statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PipelineStatsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/quota/{project_id}":{"get":{"tags":["OTel"],"summary":"Get storage quota for a project.","operationId":"get_quota","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Storage quota","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuotaResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/trace-summaries":{"get":{"tags":["Traces"],"summary":"Query trace summaries — one row per trace with span count, error count,\nroot span info, and proper trace-level pagination.","operationId":"query_trace_summaries","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"trace_id","in":"query","description":"Filter by trace ID","required":false,"schema":{"type":"string"}},{"name":"service_name","in":"query","description":"Filter by service name","required":false,"schema":{"type":"string"}},{"name":"status","in":"query","description":"Filter by status (OK, ERROR)","required":false,"schema":{"type":"string"}},{"name":"min_duration_ms","in":"query","description":"Minimum trace duration in ms","required":false,"schema":{"type":"number","format":"double"}},{"name":"start_time","in":"query","description":"Start time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"name_pattern","in":"query","description":"Filter by span name pattern (ILIKE)","required":false,"schema":{"type":"string"}},{"name":"sort_by","in":"query","description":"Sort field: 'start_time' (default) or 'duration'","required":false,"schema":{"type":"string"}},{"name":"sort_order","in":"query","description":"Sort direction: 'asc' or 'desc' (default)","required":false,"schema":{"type":"string"}},{"name":"include_total","in":"query","description":"Compute the `total` count (default: true). Set false to skip the second aggregation when only the page is needed","required":false,"schema":{"type":"boolean"}},{"name":"limit","in":"query","description":"Max traces to return (default: 50, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"offset","in":"query","description":"Offset for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Trace summaries","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TraceSummariesResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/traces":{"get":{"tags":["Traces"],"summary":"Query trace spans with optional filters.","description":"Each returned span has a `duration_ms` field (float, milliseconds) — this is\nthe ONLY field guaranteed to be in milliseconds. Spans also carry an\n`attributes` map of raw key/value pairs exactly as reported by the\ninstrumenting library: numeric attribute values may be seconds, milliseconds,\nmicroseconds, or nanoseconds depending on that library's convention, and\nnothing in this response labels the unit. Never assume an attribute's\nnumeric value shares `duration_ms`'s unit, and never state a duration in\nmilliseconds unless it came from a `duration_ms` field.","operationId":"query_traces","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"trace_id","in":"query","description":"Filter by trace ID","required":false,"schema":{"type":"string"}},{"name":"service_name","in":"query","description":"Filter by service name","required":false,"schema":{"type":"string"}},{"name":"status","in":"query","description":"Filter by status (OK, ERROR, UNSET)","required":false,"schema":{"type":"string"}},{"name":"min_duration_ms","in":"query","description":"Minimum span duration in ms","required":false,"schema":{"type":"number","format":"double"}},{"name":"start_time","in":"query","description":"Start time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"limit","in":"query","description":"Max spans to return (default: 100, max: 1000)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"offset","in":"query","description":"Offset for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Trace spans","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TracesResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/traces/cross-project/{trace_id}":{"get":{"tags":["Traces"],"summary":"Discover sibling projects that share the same `trace_id` (Phase 1 banner).","description":"Returns an empty `siblings` list when the trace is single-project — never\n404. Project names are included so the UI can render navigation links\nwithout a second round-trip. See ADR-027 §3 for the full auth model and\ntopology-disclosure trade-offs.","operationId":"getCrossProjectTraceSiblings","parameters":[{"name":"trace_id","in":"path","description":"Trace ID (32 lowercase hex characters)","required":true,"schema":{"type":"string"}},{"name":"exclude_project_id","in":"query","description":"Project ID to exclude (the caller's own project) so the UI does not render a self-link","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Sibling projects sharing this trace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CrossProjectTraceResponse"}}}},"400":{"description":"trace_id is not 32 lowercase hex characters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions or deployment token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/traces/{project_id}/{trace_id}":{"get":{"tags":["Traces"],"summary":"Get all spans for a specific trace.","description":"Each span has a `duration_ms` field (float, milliseconds) — the ONLY field\nguaranteed to be in milliseconds — plus an `attributes` map of raw\nkey/value pairs exactly as the instrumenting library reported them.\nNumeric attribute values (e.g. connection-pool wait times, queue delays)\nmay be in seconds, milliseconds, microseconds, or nanoseconds depending on\nthat library's own convention; this response never labels the unit. When\nexplaining what a span spent time on, only quote milliseconds from\n`duration_ms` (or from `start_time`/`end_time` deltas) — never assume a raw\nattribute number is already in milliseconds.","operationId":"get_trace","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"trace_id","in":"path","description":"Trace ID (hex)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Trace spans tree","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TracesResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/v1/logs":{"post":{"tags":["OTel Ingest"],"summary":"Ingest log records via OTLP/HTTP protobuf.","description":"Authenticates via API key in header, decompresses, decodes protobuf,\nchecks rate limit and storage quota, routes high-severity logs\nto DB and all logs to S3.","operationId":"ingest_logs","requestBody":{"description":"OTLP ExportLogsServiceRequest (protobuf, optionally gzip/zstd compressed)","content":{"application/x-protobuf":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"Logs accepted (OTLP protobuf response)"},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"413":{"description":"Storage quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"api_key":[]}]}},"/otel/v1/metrics":{"post":{"tags":["OTel Ingest"],"summary":"Ingest metrics via OTLP/HTTP protobuf.","description":"Authenticates via API key in header, decompresses, decodes protobuf,\nchecks rate limit and storage quota, then stores.","operationId":"ingest_metrics","requestBody":{"description":"OTLP ExportMetricsServiceRequest (protobuf, optionally gzip/zstd compressed)","content":{"application/x-protobuf":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"Metrics accepted (OTLP protobuf response)"},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"413":{"description":"Storage quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"api_key":[]}]}},"/otel/v1/traces":{"post":{"tags":["OTel Ingest"],"summary":"Ingest trace spans via OTLP/HTTP protobuf.","description":"Authenticates via API key in header, decompresses, decodes protobuf,\nchecks rate limit and storage quota, then stores spans.","operationId":"ingest_traces","requestBody":{"description":"OTLP ExportTraceServiceRequest (protobuf, optionally gzip/zstd compressed)","content":{"application/x-protobuf":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"Traces accepted (OTLP protobuf response)"},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"413":{"description":"Storage quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"api_key":[]}]}},"/otel/v1/{project_id}/{environment_id}/{deployment_id}/logs":{"post":{"tags":["OTel Ingest"],"summary":"Ingest log records with project/environment/deployment in the URL path.","operationId":"ingest_logs_by_path","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"OTLP ExportLogsServiceRequest (protobuf, optionally gzip/zstd compressed)","content":{"application/x-protobuf":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"Logs accepted (OTLP protobuf response)"},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"413":{"description":"Storage quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"api_key":[]}]}},"/otel/v1/{project_id}/{environment_id}/{deployment_id}/metrics":{"post":{"tags":["OTel Ingest"],"summary":"Ingest metrics with project/environment/deployment in the URL path.","operationId":"ingest_metrics_by_path","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"OTLP ExportMetricsServiceRequest (protobuf, optionally gzip/zstd compressed)","content":{"application/x-protobuf":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"Metrics accepted (OTLP protobuf response)"},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"413":{"description":"Storage quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"api_key":[]}]}},"/otel/v1/{project_id}/{environment_id}/{deployment_id}/traces":{"post":{"tags":["OTel Ingest"],"summary":"Ingest trace spans with project/environment/deployment in the URL path.","operationId":"ingest_traces_by_path","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"OTLP ExportTraceServiceRequest (protobuf, optionally gzip/zstd compressed)","content":{"application/x-protobuf":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"Traces accepted (OTLP protobuf response)"},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"413":{"description":"Storage quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"api_key":[]}]}},"/performance/has-metrics":{"get":{"tags":["Performance"],"summary":"Check if performance metrics exist for a project","operationId":"has_performance_metrics","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully checked performance metrics availability","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HasMetricsResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/performance/metrics":{"get":{"tags":["Performance"],"summary":"Get performance metrics","operationId":"get_performance_metrics","parameters":[{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Deployment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"device_type","in":"query","description":"Device type filter: desktop or mobile (optional)","required":false,"schema":{"type":"string"}},{"name":"include_bots","in":"query","description":"Include crawler/datacenter bot samples (default false)","required":false,"schema":{"type":"boolean"}},{"name":"filter_path","in":"query","description":"Filter to one page pathname (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_country","in":"query","description":"Filter to one country (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_region","in":"query","description":"Filter to one region (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_city","in":"query","description":"Filter to one city (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_browser","in":"query","description":"Filter to one browser (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_operating_system","in":"query","description":"Filter to one operating system (optional)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved performance metrics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PerformanceMetricsResponse"}}}},"400":{"description":"Invalid date format or missing parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/performance/metrics-over-time":{"get":{"tags":["Performance"],"summary":"Get metrics over time","operationId":"get_metrics_over_time","parameters":[{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DDTHH:MM:SSZ","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DDTHH:MM:SSZ","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Deployment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"device_type","in":"query","description":"Device type filter: desktop or mobile (optional)","required":false,"schema":{"type":"string"}},{"name":"include_bots","in":"query","description":"Include crawler/datacenter bot samples (default false)","required":false,"schema":{"type":"boolean"}},{"name":"filter_path","in":"query","description":"Filter to one page pathname (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_country","in":"query","description":"Filter to one country (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_region","in":"query","description":"Filter to one region (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_city","in":"query","description":"Filter to one city (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_browser","in":"query","description":"Filter to one browser (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_operating_system","in":"query","description":"Filter to one operating system (optional)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved metrics over time","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MetricsOverTimeResponse"}}}},"400":{"description":"Invalid date format or missing parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/performance/page-metrics":{"get":{"tags":["Performance"],"summary":"Get grouped page metrics","operationId":"get_grouped_page_metrics","parameters":[{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DDTHH:MM:SSZ","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DDTHH:MM:SSZ","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Deployment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"group_by","in":"query","description":"Group by: path, country, region, city, device_type, browser, operating_system","required":true,"schema":{"type":"string"}},{"name":"device_type","in":"query","description":"Device type filter: desktop or mobile (optional)","required":false,"schema":{"type":"string"}},{"name":"include_bots","in":"query","description":"Include crawler/datacenter bot samples (default false)","required":false,"schema":{"type":"boolean"}},{"name":"filter_path","in":"query","description":"Filter to one page pathname (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_country","in":"query","description":"Filter to one country (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_region","in":"query","description":"Filter to one region (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_city","in":"query","description":"Filter to one city (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_browser","in":"query","description":"Filter to one browser (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_operating_system","in":"query","description":"Filter to one operating system (optional)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved grouped page metrics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GroupedPageMetricsResponse"}}}},"400":{"description":"Invalid date format, missing parameters, or invalid group_by value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/platform/access-info":{"get":{"tags":["Platform"],"summary":"Get information about how the service is being accessed","description":"Returns details about the server's access mode, public IP address, private IP address,\nand domain creation capabilities. Both IP addresses are always included when available.","operationId":"get_access_info","responses":{"200":{"description":"Service access information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceAccessInfo"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/platform/private-ip":{"get":{"tags":["Platform"],"summary":"Get private/local IP address of the server","operationId":"get_private_ip","responses":{"200":{"description":"Successfully retrieved private IP address"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/platform/public-ip":{"get":{"tags":["Platform"],"summary":"Get public IP address of the server","operationId":"get_public_ip","responses":{"200":{"description":"Successfully retrieved public IP address"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/presets":{"get":{"tags":["Presets"],"summary":"List all available presets","operationId":"list_presets","responses":{"200":{"description":"List of available presets","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListPresetsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/presets/{slug}/dockerfile":{"post":{"tags":["Presets"],"summary":"Generate a Dockerfile from a preset","description":"Returns the Dockerfile content and build arguments for a given preset slug.\nThe CLI can use this to build Docker images locally without needing a Dockerfile\nin the project directory, enabling zero-config deployments.","operationId":"generate_preset_dockerfile","parameters":[{"name":"slug","in":"path","description":"Preset slug (e.g., nextjs, vite, python)","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateDockerfileRequest"}}},"required":true},"responses":{"200":{"description":"Generated Dockerfile","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateDockerfileResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Preset not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/preview-gateway/logs":{"get":{"tags":["Preview Gateway"],"operationId":"get_preview_gateway_logs","parameters":[{"name":"tail","in":"query","description":"Lines to tail (default 200, max 2000)","required":false,"schema":{"type":"integer","minimum":0}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LogsResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/preview-gateway/restart":{"post":{"tags":["Preview Gateway"],"operationId":"restart_preview_gateway","responses":{"204":{"description":"Gateway restarted"}},"security":[{"bearer_auth":[]}]}},"/preview-gateway/settings":{"get":{"tags":["Preview Gateway"],"operationId":"get_preview_gateway_settings","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreviewGatewaySettingsResponse"}}}}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Preview Gateway"],"operationId":"patch_preview_gateway_settings","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PatchSettingsRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreviewGatewaySettingsResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/preview-gateway/status":{"get":{"tags":["Preview Gateway"],"operationId":"get_preview_gateway_status","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayStatus"}}}}},"security":[{"bearer_auth":[]}]}},"/preview-gateway/upgrade":{"post":{"tags":["Preview Gateway"],"operationId":"upgrade_preview_gateway","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpgradeRequest"}}},"required":true},"responses":{"204":{"description":"Gateway upgraded"}},"security":[{"bearer_auth":[]}]}},"/projects":{"get":{"tags":["Projects"],"summary":"Get a list of all projects","operationId":"get_projects","parameters":[{"name":"page","in":"query","description":"Page number (1-based)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"per_page","in":"query","description":"Number of items per page","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"List of projects","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedProjectList"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Projects"],"summary":"Create a new project","operationId":"create_project","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectRequest"}}},"required":true},"responses":{"200":{"description":"Project created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"400":{"description":"Invalid input"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/by-slug/{slug}":{"get":{"tags":["Projects"],"summary":"Get details of a specific project by slug","operationId":"get_project_by_slug","parameters":[{"name":"slug","in":"path","description":"Project slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Project details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"404":{"description":"Project not found"}},"security":[{"bearer_auth":[]}]}},"/projects/from-template":{"post":{"tags":["Projects"],"summary":"Create a new project from a template","description":"Creates a new repository from a template and sets up the project with the\nspecified configuration. The template is cloned to a new repository under\nthe authenticated user's account or specified organization.","operationId":"create_project_from_template","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectFromTemplateRequest"}}},"required":true},"responses":{"201":{"description":"Project created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectFromTemplateResponse"}}}},"400":{"description":"Invalid input"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Template not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/statistics":{"get":{"tags":["Projects"],"summary":"Get project statistics","operationId":"get_project_statistics","responses":{"200":{"description":"Project statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectStatisticsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{id}":{"get":{"tags":["Projects"],"summary":"Get details of a specific project","operationId":"get_project","parameters":[{"name":"id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Project details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"404":{"description":"Project not found"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Projects"],"operationId":"update_project","parameters":[{"name":"id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectRequest"}}},"required":true},"responses":{"200":{"description":"Project updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Projects"],"operationId":"delete_project","parameters":[{"name":"id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Project deleted successfully"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{id}/deployments":{"get":{"tags":["Projects"],"operationId":"get_project_deployments","parameters":[{"name":"id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"per_page","in":"query","description":"Items per page","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"environment_id","in":"query","description":"Environment ID filter","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of deployments","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentListResponse"}}}},"404":{"description":"Project not found"}}}},"/projects/{id}/last-deployment":{"get":{"tags":["Deployments"],"summary":"Get the last deployment for a specific project","operationId":"get_last_deployment","parameters":[{"name":"id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Last deployment details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentResponse"}}}},"404":{"description":"Project not found or no deployments"},"500":{"description":"Internal server error"}}}},"/projects/{id}/source":{"patch":{"tags":["Projects"],"summary":"Change a project's source type to a Git-less type (docker_image /\nstatic_files / manual). Switching TO Git is done via the Git settings\nendpoint (`POST /projects/{id}/git`), which also supplies the repository and\nprovider connection.","operationId":"change_project_source","parameters":[{"name":"id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeProjectSourceRequest"}}},"required":true},"responses":{"200":{"description":"Source type changed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"400":{"description":"Invalid source type change (e.g. switching to Git here)"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{id}/trigger-pipeline":{"post":{"tags":["Projects"],"summary":"Trigger pipeline for a specific project","operationId":"trigger_project_pipeline","parameters":[{"name":"id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerPipelinePayload"}}},"required":true},"responses":{"200":{"description":"Pipeline triggered successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerPipelineResponse"}}}},"400":{"description":"Invalid request"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/access":{"get":{"tags":["Teams"],"operationId":"list_project_access","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Access grants","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProjectAccessResponse"}}}}},"403":{"description":"Insufficient permissions or no access to this project"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Teams"],"operationId":"grant_project_access","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectAccessRequest"}}},"required":true},"responses":{"201":{"description":"Access granted (idempotent upsert)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectAccessResponse"}}}},"403":{"description":"Insufficient permissions or no access to this project"},"404":{"description":"Team not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/access/{team_id}":{"delete":{"tags":["Teams"],"operationId":"revoke_project_access","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"team_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Access revoked"},"403":{"description":"Insufficient permissions or no access to this project"},"404":{"description":"Grant not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/active-visitors":{"get":{"tags":["Events"],"summary":"Get active visitors count","operationId":"get_active_visitors","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved active visitors count","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActiveVisitorsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents":{"get":{"tags":["Agents"],"operationId":"list_agents","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of agents for project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListAgentsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Agents"],"operationId":"create_agent","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertAgentRequest"}}},"required":true},"responses":{"201":{"description":"Agent created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentConfigResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/cli-status":{"get":{"tags":["Agents"],"operationId":"get_cli_status","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"provider","in":"query","description":"AI provider: claude_cli or codex_cli","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"CLI status"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/runs":{"get":{"tags":["Agents"],"operationId":"list_all_runs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-based)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (max 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List of all agent runs for a project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListRunsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/runs/latest-for-source":{"get":{"tags":["Agents"],"operationId":"latest_run_for_source","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"trigger_source_type","in":"query","description":"Trigger source type, e.g. 'error_group'","required":true,"schema":{"type":"string"}},{"name":"trigger_source_id","in":"query","description":"Trigger source ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Latest matching run, or null if none","content":{"application/json":{"schema":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AgentRunResponse"}]}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/runs/{run_id}":{"get":{"tags":["Agents"],"operationId":"get_run_with_logs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Run with logs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRunWithLogsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/runs/{run_id}/cancel":{"post":{"tags":["Agents"],"operationId":"cancel_run","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Agent run ID to cancel","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Run cancelled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRunResponse"}}}},"400":{"description":"Run is already in a terminal state"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/runs/{run_id}/retry":{"post":{"tags":["Agents"],"summary":"Retry a completed, failed, cancelled, or no_fix run with the same trigger context.\nCreates a new run record and spawns the executor.","operationId":"retry_run","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID to retry","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"202":{"description":"New run created from retry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRunResponse"}}}},"400":{"description":"Run is still active"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/runs/{run_id}/stream":{"get":{"tags":["Agents"],"summary":"SSE endpoint for real-time streaming of run events.\nPolls the agent_run_logs table every 500ms for new entries and streams them.\nCloses when the run reaches a terminal status.","operationId":"stream_run_events","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Agent run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Server-Sent Events stream of run log events and terminal status","content":{"text/event-stream":{}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/sandbox-status":{"get":{"tags":["Agents"],"operationId":"get_sandbox_status","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Project-scoped sandbox readiness (Docker + agent image)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxStatusResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/smoke-test":{"post":{"tags":["Agents"],"summary":"Run a smoke test to verify the selected AI CLI works in the environment\nwhere agents will actually execute (host or sandbox container). If no\n`provider_id` is supplied the globally active provider is tested.","operationId":"smoke_test_agent","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"provider_id","in":"query","description":"Provider id to test; defaults to the globally active provider","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Smoke test result for the AI CLI in the agent's execution environment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SmokeTestResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/{slug}":{"get":{"tags":["Agents"],"operationId":"get_agent","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Agent slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Agent config","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentConfigResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Agent not found"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Agents"],"operationId":"update_agent","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Agent slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertAgentRequest"}}},"required":true},"responses":{"200":{"description":"Agent updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentConfigResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Agent not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Agents"],"operationId":"delete_agent","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Agent slug","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Agent deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Agent not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/{slug}/runs":{"get":{"tags":["Agents"],"operationId":"list_agent_runs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Agent slug","required":true,"schema":{"type":"string"}},{"name":"page","in":"query","description":"Page number (1-based)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (max 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List of runs for a specific agent","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListRunsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Agent not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/{slug}/trigger":{"post":{"tags":["Agents"],"operationId":"trigger_agent","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Agent slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerAgentRequest"}}},"required":true},"responses":{"202":{"description":"Agent run created and queued","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRunResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"402":{"description":"Daily budget exceeded"},"403":{"description":"Insufficient permissions"},"404":{"description":"Agent not found"},"422":{"description":"AI CLI not installed"},"429":{"description":"Cooldown active"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/aggregated-buckets":{"get":{"tags":["Events"],"summary":"Get aggregated metrics by time bucket","operationId":"get_aggregated_buckets","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date for the query range","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date for the query range","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Optional environment filter","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Optional deployment filter","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"aggregation_level","in":"query","description":"Aggregation level: events, sessions, or visitors (default: events)","required":false,"schema":{"type":"string"}},{"name":"bucket_size","in":"query","description":"Time bucket size: '1 hour', '1 day', '1 week', etc. (default: '1 hour')","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved aggregated buckets","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AggregatedBucketsResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/conversations":{"get":{"tags":["AI Chat"],"summary":"Find the existing chat for a context (returns `null` if none yet). Requires\nthe per-project `ai_debug_chat_enabled` toggle to be on; returns 403 when the\nfeature is disabled so revoking it consistently hides existing chat content.","operationId":"find_conversation","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"context_type","in":"query","required":true,"schema":{"type":"string"}},{"name":"context_id","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ConversationResponse"}]}}}},"401":{"description":""},"403":{"description":""}},"security":[{"bearer_auth":[]}]},"post":{"tags":["AI Chat"],"summary":"Get-or-create the chat for a context (seeds it on first open).","operationId":"create_conversation","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateConversationRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversationResponse"}}}},"401":{"description":""},"403":{"description":""},"404":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/conversations/list":{"get":{"tags":["AI Chat"],"summary":"List all active conversations for a project, most-recently-active first.\nPowers the conversation switcher in the AI assistant sidebar.","operationId":"list_conversations","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ConversationResponse"}}}}},"401":{"description":""},"403":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/conversations/{public_id}":{"get":{"tags":["AI Chat"],"summary":"Full conversation history (excluding the internal system seed).","operationId":"get_conversation","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"public_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversationDetailResponse"}}}},"401":{"description":""},"403":{"description":""},"404":{"description":""}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["AI Chat"],"summary":"Rename a conversation (set its human-facing title).","operationId":"rename_conversation","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"public_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RenameConversationRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversationResponse"}}}},"400":{"description":""},"401":{"description":""},"403":{"description":""},"404":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/conversations/{public_id}/archive":{"post":{"tags":["AI Chat"],"summary":"Archive (soft-delete) a conversation.","operationId":"archive_conversation","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"public_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":""},"401":{"description":""},"403":{"description":""},"404":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/conversations/{public_id}/messages":{"post":{"tags":["AI Chat"],"summary":"Send a user message; stream the assistant reply as Server-Sent Events.","operationId":"send_message","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"public_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendMessageRequest"}}},"required":true},"responses":{"200":{"description":"SSE stream of assistant text deltas","content":{"text/event-stream":{}}},"401":{"description":""},"403":{"description":""},"404":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/conversations/{public_id}/pending-actions":{"get":{"tags":["AI Chat"],"summary":"List all pending actions for a conversation (most-recently-proposed first).","operationId":"list_pending_actions","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"public_id","in":"path","description":"Conversation public id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PendingActionResponse"}}}}},"401":{"description":""},"403":{"description":""},"404":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/pending-actions/{action_public_id}":{"get":{"tags":["AI Chat"],"summary":"Get a single pending action by its public id (scoped to the project).","operationId":"get_pending_action","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"action_public_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PendingActionResponse"}}}},"401":{"description":""},"403":{"description":""},"404":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/pending-actions/{action_public_id}/confirm":{"post":{"tags":["AI Chat"],"summary":"Confirm a proposed AI action: validate permission, atomically claim, execute,\npersist outcome. The execution uses the CONFIRMING user's auth — never the model's.","operationId":"confirm_pending_action","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"action_public_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PendingActionResponse"}}}},"401":{"description":""},"403":{"description":""},"404":{"description":""},"409":{"description":""},"503":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/pending-actions/{action_public_id}/reject":{"post":{"tags":["AI Chat"],"summary":"Reject a proposed AI action (no execution). Status transitions to \"rejected\".","operationId":"reject_pending_action","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"action_public_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PendingActionResponse"}}}},"401":{"description":""},"403":{"description":""},"404":{"description":""},"409":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/readiness":{"get":{"tags":["AI Chat"],"summary":"Report which AI prerequisites this project satisfies.","description":"Read-only and cheap, so the UI can decide up front whether to show a working\nentry point, an onboarding path, or nothing — instead of letting the user\nclick something that fails with a 409 they can't act on.","operationId":"get_chat_readiness","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Which AI prerequisites are met","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatReadinessResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/alarms":{"get":{"tags":["Alarms"],"summary":"List alarms for a project with optional filters.","operationId":"listProjectAlarms","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"alarm_type","in":"query","description":"Filter by alarm type (e.g. `container_restart`, `outage`).","required":false,"schema":{"type":["string","null"]}},{"name":"status","in":"query","description":"Filter by status: `firing`, `acknowledged`, or `resolved`.","required":false,"schema":{"type":["string","null"]}},{"name":"severity","in":"query","description":"Filter by severity: `info`, `warning`, or `critical`.","required":false,"schema":{"type":["string","null"]}},{"name":"environment_id","in":"query","description":"Filter by environment ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"service_id","in":"query","description":"Filter by external service ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"page","in":"query","description":"Page number (1-based, default 1).","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page (default 20, max 100).","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}}],"responses":{"200":{"description":"Paginated list of alarms","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlarmListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/alarms/summary":{"get":{"tags":["Alarms"],"summary":"Get alarm counts by status/severity/type for a project (dashboard summary widget).","operationId":"getProjectAlarmsSummary","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Alarm summary counts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlarmSummaryResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/alarms/{alarm_id}/acknowledge":{"post":{"tags":["Alarms"],"summary":"Acknowledge a firing alarm (marks it as seen but not resolved).","operationId":"acknowledgeAlarm","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"alarm_id","in":"path","description":"Alarm ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Alarm acknowledged"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Alarm not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/alarms/{alarm_id}/resolve":{"post":{"tags":["Alarms"],"summary":"Resolve an alarm.","operationId":"resolveAlarm","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"alarm_id","in":"path","description":"Alarm ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Alarm resolved"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Alarm not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/analyze":{"post":{"tags":["Autofixer"],"summary":"Start an autofixer analysis run for the given error group.\nCreates the run record immediately and spawns analysis in the background.","operationId":"start_analysis","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartAnalysisRequest"}}},"required":true},"responses":{"202":{"description":"Analysis started; returns run_id for streaming","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutofixerRunResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/runs/{run_id}":{"get":{"tags":["Autofixer"],"summary":"Get a single autofixer run with its logs.","operationId":"get_run","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Run with logs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutofixerRunWithLogsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/runs/{run_id}/add-context":{"post":{"tags":["Autofixer"],"summary":"Append a user message to the run's context field.","operationId":"add_context","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddContextRequest"}}},"required":true},"responses":{"200":{"description":"Context appended"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/runs/{run_id}/cancel":{"post":{"tags":["Autofixer"],"summary":"Cancel an autofixer run and clean up the work directory.","operationId":"cancel","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Run cancelled"},"400":{"description":"Run is already in a terminal state"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/runs/{run_id}/create-pr":{"post":{"tags":["Autofixer"],"summary":"Push the fix branch and create a pull request.\nRequires phase == \"fix_ready\".","operationId":"create_pr","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"201":{"description":"PR created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePrResponse"}}}},"400":{"description":"Run not in fix_ready phase"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/runs/{run_id}/fix":{"post":{"tags":["Autofixer"],"summary":"Transition from analysis to fix phase.\nRequires phase == \"analyzed\".","operationId":"start_fix","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"202":{"description":"Fix generation started"},"400":{"description":"Run not in analyzed phase"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/runs/{run_id}/re-analyze":{"post":{"tags":["Autofixer"],"summary":"Continue the conversation with user feedback.\nUses the same Claude session (--continue) in the existing work directory.\nRequires phase == \"analyzed\".","operationId":"re_analyze","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"202":{"description":"Conversation continued with feedback"},"400":{"description":"Run not in analyzed phase"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/runs/{run_id}/stream":{"get":{"tags":["Agents"],"summary":"SSE endpoint: streams run log events in real-time.\nPolls every 500 ms. Keeps the connection open through \"analyzed\" and \"fix_ready\"\nwaiting states; closes only on terminal statuses.","operationId":"stream_events","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Autofixer run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Server-Sent Events stream of autofixer run logs and status updates","content":{"text/event-stream":{}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/automatic-deploy":{"post":{"tags":["Projects"],"summary":"Update automatic deployment setting for a project","operationId":"update_automatic_deploy","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAutomaticDeployRequest"}}},"required":true},"responses":{"200":{"description":"Automatic deployment setting updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/custom-domains":{"get":{"tags":["Custom Domains"],"summary":"List all custom domains for a project","operationId":"list_custom_domains_for_project","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Custom domains retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListCustomDomainsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Custom Domains"],"summary":"Create a custom domain for a project","operationId":"create_custom_domain","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomDomainRequest"}}},"required":true},"responses":{"201":{"description":"Custom domain created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomDomainResponse"}}}},"400":{"description":"Invalid input"},"401":{"description":"Unauthorized"},"409":{"description":"Domain already exists"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/custom-domains/{domain_id}":{"get":{"tags":["Custom Domains"],"summary":"Get a custom domain by ID","operationId":"get_custom_domain","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain_id","in":"path","description":"Custom domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Custom domain retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomDomainResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Custom domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Custom Domains"],"summary":"Update a custom domain","operationId":"update_custom_domain","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain_id","in":"path","description":"Custom domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCustomDomainRequest"}}},"required":true},"responses":{"200":{"description":"Custom domain updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomDomainResponse"}}}},"400":{"description":"Invalid input"},"401":{"description":"Unauthorized"},"404":{"description":"Custom domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Custom Domains"],"summary":"Delete a custom domain","operationId":"delete_custom_domain","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain_id","in":"path","description":"Custom domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Custom domain deleted successfully"},"401":{"description":"Unauthorized"},"404":{"description":"Custom domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/custom-domains/{domain_id}/link-certificate/{certificate_id}":{"post":{"tags":["Custom Domains"],"summary":"Link a custom domain to a certificate","operationId":"link_custom_domain_to_certificate","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain_id","in":"path","description":"Custom domain ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"certificate_id","in":"path","description":"Certificate ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Custom domain linked to certificate successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomDomainResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Custom domain or certificate not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/deployment-config":{"patch":{"tags":["Projects"],"summary":"Update deployment configuration for a project","operationId":"update_project_deployment_config","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDeploymentConfigRequest"}}},"required":true},"responses":{"200":{"description":"Deployment configuration updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"400":{"description":"Invalid deployment configuration"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/deployment-tokens":{"get":{"tags":["Deployment Tokens"],"summary":"List all deployment tokens for a project","operationId":"list_deployment_tokens","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List of deployment tokens","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentTokenListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Deployment Tokens"],"summary":"Create a new deployment token for a project","operationId":"create_deployment_token","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDeploymentTokenRequest"}}},"required":true},"responses":{"201":{"description":"Deployment token created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDeploymentTokenResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"409":{"description":"Token with this name already exists"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/deployment-tokens/{token_id}":{"get":{"tags":["Deployment Tokens"],"summary":"Get a specific deployment token","operationId":"get_deployment_token","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"token_id","in":"path","description":"Deployment token ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deployment token details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentTokenResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Deployment token not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Deployment Tokens"],"summary":"Delete a deployment token","operationId":"delete_deployment_token","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"token_id","in":"path","description":"Deployment token ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Deployment token deleted successfully"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Deployment token not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Deployment Tokens"],"summary":"Update a deployment token","operationId":"update_deployment_token","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"token_id","in":"path","description":"Deployment token ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDeploymentTokenRequest"}}},"required":true},"responses":{"200":{"description":"Deployment token updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentTokenResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Deployment token not found"},"409":{"description":"Token with this name already exists"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/deployment-tokens/{token_id}/rotate":{"post":{"tags":["Deployment Tokens"],"summary":"Rotate a deployment token, invalidating its old secret and issuing a new one","operationId":"rotate_deployment_token","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"token_id","in":"path","description":"Deployment token ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deployment token rotated successfully; the response contains the new plaintext token, shown only once","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDeploymentTokenResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Deployment token not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/deployments/{deployment_id}":{"get":{"tags":["Deployments"],"summary":"Get a specific deployment by ID for a project (identified by ID or slug)","operationId":"get_deployment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deployment details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentResponse"}}}},"404":{"description":"Project or deployment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/deployments/{deployment_id}/cancel":{"post":{"tags":["Projects"],"summary":"Cancel a deployment","operationId":"cancel_deployment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deployment cancelled successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentStateResponse"}}}},"400":{"description":"Deployment cannot be cancelled (already completed, failed, or cancelled)"},"404":{"description":"Project or deployment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/deployments/{deployment_id}/container-logs":{"get":{"tags":["Deployments"],"summary":"List the captured (historical) container-log dumps for a deployment.","description":"Container runtime logs are normally only available live from the running\ncontainer. When a deployment is superseded its containers are torn down and\nthose logs would be lost — so just before teardown we capture each\ncontainer's logs to durable storage. This endpoint lists what was captured\nfor a given (often older) deployment, so a user can read the logs of a\ncontainer that no longer exists.","operationId":"list_deployment_container_logs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Captured container logs for the deployment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentContainerLogsListResponse"}}}},"404":{"description":"Deployment not found in this project"},"500":{"description":"Internal server error"}},"security":[{"bearer_token":[]}]}},"/projects/{project_id}/deployments/{deployment_id}/container-logs/{log_id}":{"get":{"tags":["Deployments"],"summary":"Get the captured text content of a single historical container-log dump.","operationId":"get_deployment_container_log_content","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"log_id","in":"path","description":"Captured log ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Captured container log content","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentContainerLogContentResponse"}}}},"404":{"description":"Captured log not found in this project"},"500":{"description":"Internal server error"}},"security":[{"bearer_token":[]}]}},"/projects/{project_id}/deployments/{deployment_id}/jobs":{"get":{"tags":["Deployments"],"summary":"Get jobs for a specific deployment","description":"Returns all jobs (workflow tasks) for a deployment, ordered by execution order.\nThis replaces the old deployment stages endpoint.","operationId":"get_deployment_jobs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Jobs retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentJobsResponse"}}}},"404":{"description":"Deployment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/deployments/{deployment_id}/jobs/{job_id}/logs":{"get":{"tags":["Deployments"],"summary":"Get logs for a specific deployment job","operationId":"get_deployment_job_logs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"job_id","in":"path","description":"Job ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Job logs retrieved successfully","content":{"text/plain":{"schema":{"type":"string"}}}},"404":{"description":"Job or logs not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_token":[]}]}},"/projects/{project_id}/deployments/{deployment_id}/jobs/{job_id}/logs/tail":{"get":{"tags":["Deployments"],"summary":"Tail logs for a specific deployment job in real-time via WebSocket","description":"**WebSocket Streaming**: Logs are sent as raw text, one line per WebSocket message.\n\n**Authentication**: Requires authentication via session cookie (browser clients)\nor API key (API clients). For browser-based WebSocket connections, ensure the user\nis logged in - the browser automatically includes session cookies in the WebSocket\nupgrade request.\n\n**API Client Authentication**: Include API key in Authorization header:\n```text\nAuthorization: Bearer tk_your_api_key_here\n```","operationId":"tail_deployment_job_logs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"job_id","in":"path","description":"Job ID","required":true,"schema":{"type":"string"}}],"responses":{"101":{"description":"WebSocket connection established for streaming deployment job logs"},"404":{"description":"Job or logs not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_token":[]}]}},"/projects/{project_id}/deployments/{deployment_id}/operations":{"get":{"tags":["Deployments"],"summary":"Get all operations for a deployment","operationId":"get_deployment_operations","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of operations","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperationResultsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Deployment not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Deployments"],"summary":"Execute a deployment operation (deploy, mark_complete, take_screenshot)","operationId":"execute_deployment_operation","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecuteOperationRequest"}}},"required":true},"responses":{"202":{"description":"Operation executed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperationResultResponse"}}}},"400":{"description":"Invalid operation"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Deployment not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/deployments/{deployment_id}/operations/{operation_type}":{"get":{"tags":["Deployments"],"summary":"Get the status of a specific operation type","operationId":"get_deployment_operation_status","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","required":true,"schema":{"type":"string"}},{"name":"operation_type","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Operation status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperationResultResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Operation not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/deployments/{deployment_id}/pause":{"post":{"tags":["Projects"],"summary":"Pause a deployment","operationId":"pause_deployment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deployment paused successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentStateResponse"}}}},"404":{"description":"Project or deployment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/deployments/{deployment_id}/promote":{"post":{"tags":["Deployments"],"summary":"Promote a deployment to another environment","description":"Creates a new deployment in the target environment using the source deployment's\nDocker image. Useful for promoting a validated preview/staging deployment to production.","operationId":"promote_deployment","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Source deployment ID to promote","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PromoteDeploymentRequest"}}},"required":true},"responses":{"200":{"description":"Promotion initiated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentResponse"}}}},"400":{"description":"Invalid deployment state for promotion"},"404":{"description":"Project, deployment, or target environment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/deployments/{deployment_id}/resume":{"post":{"tags":["Projects"],"summary":"Resume a deployment","operationId":"resume_deployment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deployment resumed successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentStateResponse"}}}},"404":{"description":"Project or deployment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/deployments/{deployment_id}/rollback":{"post":{"tags":["Projects"],"operationId":"rollback_to_deployment","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID to rollback to","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Rollback initiated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentResponse"}}}},"404":{"description":"Project or deployment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/deployments/{deployment_id}/teardown":{"delete":{"tags":["Projects"],"summary":"Teardown a specific deployment","operationId":"teardown_deployment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Deployment torn down successfully"},"404":{"description":"Project or deployment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/dsns":{"get":{"tags":[],"summary":"List all DSNs for a project","operationId":"list_dsns","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of DSNs","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProjectDSNResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"post":{"tags":[],"summary":"Create a new DSN for a project","operationId":"create_dsn","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDSNRequest"}}},"required":true},"responses":{"201":{"description":"DSN created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectDSNResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/dsns/get-or-create":{"post":{"tags":[],"summary":"Get or create DSN for a project/environment/deployment combination","operationId":"get_or_create_dsn","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetOrCreateDSNRequest"}}},"required":true},"responses":{"200":{"description":"DSN retrieved or created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectDSNResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/dsns/{dsn_id}/regenerate":{"post":{"tags":[],"summary":"Regenerate DSN keys (rotate keys)","operationId":"regenerate_dsn","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"dsn_id","in":"path","description":"DSN ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegenerateDSNRequest"}}},"required":true},"responses":{"200":{"description":"DSN keys regenerated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectDSNResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"DSN not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/dsns/{dsn_id}/revoke":{"post":{"tags":[],"summary":"Revoke (deactivate) a DSN","operationId":"revoke_dsn","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"dsn_id","in":"path","description":"DSN ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"DSN revoked"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"DSN not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/env-vars":{"get":{"tags":["Projects"],"summary":"Get environment variables for a project, optionally filtered by environment","operationId":"get_environment_variables","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Optional environment ID to filter by","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of environment variables","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EnvironmentVariableResponse"}}}}},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}},"post":{"tags":["Projects"],"summary":"Create a new environment variable","operationId":"create_environment_variable","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEnvironmentVariableRequest"}}},"required":true},"responses":{"201":{"description":"Environment variables created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentVariableResponse"}}}},"400":{"description":"Invalid input"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/env-vars/resolved":{"get":{"tags":["Projects"],"summary":"Resolved env vars for a project (manual + integration-sourced, merged).","description":"Returns the effective set of environment variables a deployment would see,\ncombining manually-defined vars with those contributed by linked external\nservices (Postgres, Redis, S3, etc.). Each entry is tagged with its source\nso the UI can render an integration icon, and manual entries that shadow an\nintegration key carry a reference to the integration they override.\n\nValues are always returned as a masked preview. Use the per-key reveal\nendpoint for plaintext (audit-logged).","operationId":"get_resolved_environment_variables","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Optional environment ID to filter manual vars by","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Resolved environment variables","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ResolvedEnvVarResponse"}}}}},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/env-vars/resolved/{key}/value":{"get":{"tags":["Projects"],"summary":"Reveal the plaintext value of a resolved environment variable.","description":"Mirrors `GET /projects/{id}/env-vars/{key}/value` but handles keys sourced\nfrom linked integrations (which are not stored in the `env_vars` table).\nResolution order mirrors the merged view:\n\n1. Manual env var with this key — this endpoint reads the manual store when\n the key exists there, then writes its own reveal audit event so callers\n can safely use one endpoint regardless of source.\n2. Integration env var supplied by a linked external service.\n\nReturns 404 when neither a manual var nor an integration produces the key.","operationId":"get_resolved_environment_variable_value","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"key","in":"path","description":"Environment variable key","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Optional environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"var_id","in":"query","description":"Exact manual environment-variable row ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"service_id","in":"query","description":"Integration service ID shown by the resolved list","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Resolved environment variable value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentVariableValueResponse"}}}},"403":{"description":"Plaintext secret access is not permitted"},"404":{"description":"Project, key, or integration not found"},"409":{"description":"Environment variable key is ambiguous"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/env-vars/{key}/value":{"get":{"tags":["Projects"],"summary":"Get environment variable value by key","operationId":"get_environment_variable_value","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"key","in":"path","description":"Environment variable key","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Optional environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"var_id","in":"query","description":"Exact environment-variable row ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Environment variable value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentVariableValueResponse"}}}},"403":{"description":"Plaintext secret access is not permitted"},"404":{"description":"Project or variable not found"},"409":{"description":"Environment variable key is ambiguous"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/env-vars/{var_id}":{"put":{"tags":["Projects"],"summary":"Update an environment variable","operationId":"update_environment_variable","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"var_id","in":"path","description":"Environment variable ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEnvironmentVariableRequest"}}},"required":true},"responses":{"200":{"description":"Environment variables updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentVariableResponse"}}}},"400":{"description":"Invalid input"},"404":{"description":"Project or variable not found"},"500":{"description":"Internal server error"}}},"delete":{"tags":["Projects"],"summary":"Delete an environment variable","operationId":"delete_environment_variable","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"var_id","in":"path","description":"Environment variable ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Environment variable deleted successfully"},"404":{"description":"Project or variable not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments":{"get":{"tags":["Projects"],"summary":"Get all environments for a project","operationId":"get_environments","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of environments","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EnvironmentResponse"}}}}},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}},"post":{"tags":["Projects"],"summary":"Create a new environment for a project","operationId":"create_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEnvironmentRequest"}}},"required":true},"responses":{"201":{"description":"Environment created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentResponse"}}}},"400":{"description":"Invalid input"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}":{"get":{"tags":["Projects"],"summary":"Get a specific environment by ID or slug","operationId":"get_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Environment details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentResponse"}}}},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}}},"delete":{"tags":["Projects"],"summary":"Delete an environment permanently","description":"Permanently deletes an environment and all related data. Cannot delete:\n- Production environments (name = \"Production\")\n\nWarning: This action is permanent and cannot be undone.\nActive deployments are automatically cancelled before deletion.","operationId":"delete_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Environment permanently deleted"},"400":{"description":"Cannot delete production environment"},"404":{"description":"Project or environment not found"},"428":{"description":"Recent MFA verification required"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/crons":{"get":{"tags":["Crons"],"operationId":"get_environment_crons","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of cron jobs","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CronInfo"}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/crons/{cron_id}":{"get":{"tags":["Crons"],"operationId":"get_cron_by_id","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"cron_id","in":"path","description":"Cron Job ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Cron job details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CronInfo"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Cron job not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/crons/{cron_id}/executions":{"get":{"tags":["Crons"],"operationId":"get_cron_executions","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"cron_id","in":"path","description":"Cron Job ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"per_page","in":"query","description":"Items per page (default: 20)","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"List of cron job executions","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CronExecutionInfo"}}}}},"401":{"description":"Unauthorized"},"404":{"description":"Cron job not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/domains":{"get":{"tags":["Projects"],"summary":"Get all environment domains for a specific environment","operationId":"get_environment_domains","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of environment domains","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EnvironmentDomainResponse"}}}}},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}}},"post":{"tags":["Projects"],"summary":"Add a new environment domain","operationId":"add_environment_domain","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddEnvironmentDomainRequest"}}},"required":true},"responses":{"201":{"description":"Domain added successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentDomainResponse"}}}},"400":{"description":"Invalid input"},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/domains/{domain_id}":{"delete":{"tags":["Projects"],"summary":"Delete an environment domain","operationId":"delete_environment_domain","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain_id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Domain deleted successfully"},"404":{"description":"Project, environment, or domain not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/settings":{"put":{"tags":["Projects"],"summary":"Update environment settings","operationId":"update_environment_settings","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEnvironmentSettingsRequest"}}},"required":true},"responses":{"200":{"description":"Environment settings updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentResponse"}}}},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/sleep":{"post":{"tags":["Environments"],"summary":"Sleep an on-demand environment","description":"Manually put an on-demand environment to sleep. Stops containers and sets\n`sleeping = true`. If no OnDemandWaker is available, falls back to DB flag only.","operationId":"sleep_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Environment put to sleep","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentResponse"}}}},"400":{"description":"On-demand not enabled for this environment"},"404":{"description":"Environment not found"},"429":{"description":"Too many state transitions, retry after cooldown"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/subdomain":{"patch":{"tags":["Projects"],"summary":"Rename the auto-managed subdomain for an environment.","description":"Replaces the environment's previous subdomain entirely — the old\nhostname stops resolving once the proxy reloads its route table.\nCustom domains attached to the environment are unaffected.","operationId":"update_environment_subdomain","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEnvironmentSubdomainRequest"}}},"required":true},"responses":{"200":{"description":"Subdomain updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentResponse"}}}},"400":{"description":"Invalid subdomain or conflict with another environment"},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/teardown":{"delete":{"tags":["Projects"],"summary":"Teardown an environment and all its active deployments","operationId":"teardown_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Environment torn down successfully"},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/wake":{"post":{"tags":["Environments"],"summary":"Wake a sleeping on-demand environment","description":"Manually wake an environment that has been put to sleep by the on-demand\nidle timeout. Starts containers, waits for health checks, then sets\n`sleeping = false`. If no OnDemandWaker is available (proxy not running\nin same process), falls back to setting the DB flag only.","operationId":"wake_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Environment woken up","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentResponse"}}}},"400":{"description":"On-demand not enabled for this environment"},"404":{"description":"Environment not found"},"429":{"description":"Too many state transitions, retry after cooldown"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{environment_id}/container-logs":{"get":{"tags":["Deployments"],"summary":"Get logs for a container in an environment via WebSocket","operationId":"get_container_logs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date for logs","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"end_date","in":"query","description":"End date for logs","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"tail","in":"query","description":"Number of lines to tail (or 'all')","required":false,"schema":{"type":"string"}},{"name":"container_name","in":"query","description":"Optional container name (defaults to first/primary container)","required":false,"schema":{"type":"string"}},{"name":"timestamps","in":"query","description":"Include timestamps in log output (default: false)","required":false,"schema":{"type":"boolean"}},{"name":"follow","in":"query","description":"Follow log output in real-time (default: true)","required":false,"schema":{"type":"boolean"}}],"responses":{"101":{"description":"WebSocket connection established for streaming container logs"},"400":{"description":"Not a server-type project"},"404":{"description":"Project, deployment, or container not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/containers":{"get":{"tags":["Deployments"],"summary":"List all containers for an environment","operationId":"list_containers","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of containers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerListResponse"}}}},"400":{"description":"Not a server-type project"},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}":{"get":{"tags":["Containers"],"summary":"Get detailed information about a specific container","operationId":"get_container_detail","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Container details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerDetailResponse"}}}},"404":{"description":"Container not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/environment/{variable_name}":{"get":{"tags":["Containers"],"operationId":"get_container_environment_variable","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}},{"name":"variable_name","in":"path","description":"Environment variable name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Environment variable value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerEnvironmentVariableValueResponse"}}}},"403":{"description":"Plaintext secret access is not permitted"},"404":{"description":"Container or environment variable not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/logs":{"get":{"tags":["Deployments"],"summary":"Get logs for a specific container by container ID via WebSocket","operationId":"get_container_logs_by_id","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}},{"name":"start_date","in":"query","description":"Start date for logs","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"end_date","in":"query","description":"End date for logs","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"tail","in":"query","description":"Number of lines to tail (or 'all')","required":false,"schema":{"type":"string"}},{"name":"timestamps","in":"query","description":"Include timestamps in log output (default: false)","required":false,"schema":{"type":"boolean"}},{"name":"follow","in":"query","description":"Follow log output in real-time (default: true)","required":false,"schema":{"type":"boolean"}}],"responses":{"101":{"description":"WebSocket connection established for streaming container logs"},"400":{"description":"Not a server-type project"},"404":{"description":"Project, environment, or container not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/metrics":{"get":{"tags":["Containers"],"summary":"Get metrics/stats for a specific container","operationId":"get_container_metrics","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Container metrics retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerMetricsResponse"}}}},"404":{"description":"Container not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/metrics/history":{"get":{"tags":["Containers"],"summary":"Fetch a time-series range for a single container resource metric\n(recorded by the container health monitor every ~30s).","description":"Useful metric names: `container.cpu_percent`,\n`container.cpu_utilization_percent`, `container.memory_used_bytes`,\n`container.memory_percent`, `container.network_rx_bytes_delta`,\n`container.network_tx_bytes_delta`.","operationId":"ContainerMetricsGetHistory","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}},{"name":"metric","in":"query","description":"Dotted metric name, e.g. `container.cpu_percent` or\n`container.memory_used_bytes`.","required":true,"schema":{"type":"string"}},{"name":"range","in":"query","description":"Time window: `1h`, `6h`, `24h`, or `7d` (defaults to `1h`).","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Metric time series data points","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ContainerMetricHistoryPoint"}}}}},"401":{"description":"Unauthorized"},"404":{"description":"Container not found"},"500":{"description":"Internal server error"},"503":{"description":"Metrics store not available"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/metrics/stream":{"get":{"tags":["Containers"],"summary":"Stream container metrics via Server-Sent Events (SSE)","operationId":"stream_container_metrics","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}},{"name":"interval","in":"query","description":"Update interval in milliseconds (default: 1000)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Metrics stream established (Server-Sent Events)"},"404":{"description":"Container not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/restart":{"post":{"tags":["Containers"],"summary":"Restart a container","operationId":"restart_container","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Container restarted successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerActionResponse"}}}},"404":{"description":"Container not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/start":{"post":{"tags":["Containers"],"summary":"Start a container","operationId":"start_container","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Container started successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerActionResponse"}}}},"404":{"description":"Container not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/stop":{"post":{"tags":["Containers"],"summary":"Stop a specific container","operationId":"stop_container","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Container stopped successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerActionResponse"}}}},"404":{"description":"Container not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{environment_id}/deploy/image":{"post":{"tags":["Deployments"],"summary":"Deploy from an external Docker image","description":"Triggers a deployment using a pre-built Docker image from an external registry.\nThe image will be pulled and deployed to the specified environment.","operationId":"deploy_from_image","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeployFromImageRequest"}}},"required":true},"responses":{"202":{"description":"Deployment started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RemoteDeploymentResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/deploy/image-upload":{"post":{"tags":["Deployments"],"summary":"Deploy from an uploaded Docker image tarball","description":"Uploads a Docker image tarball (from `docker save`) and deploys it directly.\nThe image is imported using `docker load` and then deployed to the specified environment.\nThis is useful when you want to deploy an image without pushing to a registry first.\n\nThe uploaded file should be a tarball created by `docker save myimage:tag > image.tar`\nor `docker save myimage:tag | gzip > image.tar.gz` (gzip compressed tarballs are also supported).","operationId":"deploy_from_image_upload","parameters":[{"name":"tag","in":"query","description":"Tag to apply to the imported image (e.g., \"myapp:v1.0\")\nIf not provided, a unique tag will be generated","required":false,"schema":{"type":["string","null"]}},{"name":"health_check_path","in":"query","description":"Optional HTTP health-check path override (e.g. \"/api/healthz\").\nMust start with '/'. When omitted, defaults to \"/\".","required":false,"schema":{"type":["string","null"]}},{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"202":{"description":"Image imported and deployment started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RemoteDeploymentResponse"}}}},"400":{"description":"Invalid request or unsupported format"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project or environment not found"},"413":{"description":"Image tarball too large"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/deploy/source":{"post":{"tags":["Deployments"],"summary":"Upload source code and immediately start a preset-based deployment.","operationId":"deploy_from_uploaded_source","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/SourceArchiveUpload"}}},"required":true},"responses":{"202":{"description":"Source deployment started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RemoteDeploymentResponse"}}}},"400":{"description":"Invalid source archive"},"404":{"description":"Project or environment not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/deploy/static":{"post":{"tags":["Deployments"],"summary":"Deploy from an uploaded static bundle","description":"Triggers a deployment using a previously uploaded static file bundle.","operationId":"deploy_from_static","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeployFromStaticRequest"}}},"required":true},"responses":{"202":{"description":"Deployment started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RemoteDeploymentResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project, environment, or bundle not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/error-alert-rules":{"get":{"tags":["error-alert-rules"],"summary":"List all alert rules for a project","operationId":"list_alert_rules","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of alert rules","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AlertRuleResponse"}}}}},"500":{"description":"Internal server error"}}},"post":{"tags":["error-alert-rules"],"summary":"Create a new alert rule","operationId":"create_alert_rule","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAlertRuleRequest"}}},"required":true},"responses":{"201":{"description":"Alert rule created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlertRuleResponse"}}}},"400":{"description":"Validation error"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-alert-rules/{rule_id}":{"get":{"tags":["error-alert-rules"],"summary":"Get a specific alert rule","operationId":"get_alert_rule","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"rule_id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Alert rule details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlertRuleResponse"}}}},"404":{"description":"Alert rule not found"},"500":{"description":"Internal server error"}}},"put":{"tags":["error-alert-rules"],"summary":"Update an existing alert rule","operationId":"update_alert_rule","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"rule_id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAlertRuleRequest"}}},"required":true},"responses":{"200":{"description":"Alert rule updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlertRuleResponse"}}}},"400":{"description":"Validation error"},"404":{"description":"Alert rule not found"},"500":{"description":"Internal server error"}}},"delete":{"tags":["error-alert-rules"],"summary":"Delete an alert rule","operationId":"delete_alert_rule","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"rule_id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Alert rule deleted"},"404":{"description":"Alert rule not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-dashboard-stats":{"get":{"tags":["error-tracking"],"summary":"Get error dashboard statistics","operationId":"get_error_dashboard_stats","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_time","in":"query","required":true,"schema":{"type":"string","format":"date-time"}},{"name":"end_time","in":"query","required":true,"schema":{"type":"string","format":"date-time"}},{"name":"environment_id","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"compare_to_previous","in":"query","required":false,"schema":{"type":["boolean","null"]}}],"responses":{"200":{"description":"Error dashboard statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDashboardStatsResponse"}}}},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-groups":{"get":{"tags":["error-tracking"],"summary":"List error groups for a project","operationId":"list_error_groups","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"status","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"environment_id","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"start_date","in":"query","required":false,"schema":{"type":["string","null"],"format":"date-time"}},{"name":"end_date","in":"query","required":false,"schema":{"type":["string","null"],"format":"date-time"}},{"name":"sort_by","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Paginated list of error groups","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedErrorGroupsResponse"}}}},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-groups/{group_id}":{"get":{"tags":["error-tracking"],"summary":"Get a specific error group","operationId":"get_error_group","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"group_id","in":"path","description":"Error group ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Error group details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorGroupResponse"}}}},"404":{"description":"Error group not found"},"500":{"description":"Internal server error"}}},"put":{"tags":["error-tracking"],"summary":"Update error group status","operationId":"update_error_group","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"group_id","in":"path","description":"Error group ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateErrorGroupRequest"}}},"required":true},"responses":{"200":{"description":"Error group updated successfully"},"404":{"description":"Error group not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-groups/{group_id}/events":{"get":{"tags":["error-tracking"],"summary":"List error events for a specific group","operationId":"list_error_events","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"group_id","in":"path","description":"Error group ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Paginated list of error events","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedErrorEventsResponse"}}}},"404":{"description":"Error group not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-groups/{group_id}/events/{event_id}":{"get":{"tags":["error-tracking"],"summary":"Get a specific error event","operationId":"get_error_event","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"group_id","in":"path","description":"Error group ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"event_id","in":"path","description":"Error event ID","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Error event details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEventResponse"}}}},"404":{"description":"Event not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-stats":{"get":{"tags":["error-tracking"],"summary":"Get error statistics for a project","operationId":"get_error_stats","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Error statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorGroupStatsResponse"}}}},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-time-series":{"get":{"tags":["error-tracking"],"summary":"Get error time series data for charts","operationId":"get_error_time_series","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_time","in":"query","required":true,"schema":{"type":"string","format":"date-time"}},{"name":"end_time","in":"query","required":true,"schema":{"type":"string","format":"date-time"}},{"name":"bucket","in":"query","description":"Time bucket size (e.g., \"1h\", \"15m\", \"1d\", \"1 hour\", \"30 minutes\")","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Error time series data","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ErrorTimeSeriesDataResponse"}}}}},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/events":{"get":{"tags":["Events"],"summary":"Get event counts with filtering","operationId":"get_events_count","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date for filtering events","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date for filtering events","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"limit","in":"query","description":"Maximum number of events to return (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"custom_events_only","in":"query","description":"Only return custom events, excluding system events like page_view, page_leave, heartbeat (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"aggregation_level","in":"query","description":"Aggregation level: events, sessions, or visitors (default: events)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved event counts","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EventCount"}}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/events/breakdown":{"get":{"tags":["Events"],"summary":"Get event type breakdown","operationId":"get_event_type_breakdown","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date for filtering events","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date for filtering events","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"aggregation_level","in":"query","description":"Aggregation level: events, sessions, or visitors (default: events)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved event type breakdown","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EventTypeBreakdown"}}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/events/ingest":{"post":{"tags":["Events"],"summary":"Record an analytics event via the console API with explicit project ID.","description":"The app backend forwards the user's encrypted Temps cookies, so visitor/session\nidentity is resolved automatically by middleware. No geolocation or user-agent\nenrichment is performed — this is a lightweight server-side ingestion path.","operationId":"record_console_event","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConsoleEventPayload"}}},"required":true},"responses":{"200":{"description":"Event recorded successfully"},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/events/properties/breakdown":{"get":{"tags":["Events"],"summary":"Get property breakdown by grouping events by a column","operationId":"get_property_breakdown","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in '%Y-%m-%d %H:%M:%S' format","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in '%Y-%m-%d %H:%M:%S' format","required":true,"schema":{"type":"string"}},{"name":"group_by","in":"query","description":"Column to group by (channel, device_type, browser, etc.)","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"event_name","in":"query","description":"Filter by event name","required":false,"schema":{"type":"string"}},{"name":"aggregation_level","in":"query","description":"Aggregation level: events, sessions, or visitors - default: events","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Maximum number of results (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"include_crawlers","in":"query","description":"Include crawler/bot traffic (default: false)","required":false,"schema":{"type":"boolean"}},{"name":"filter_country","in":"query","description":"Filter by country (for region/city drill-downs)","required":false,"schema":{"type":"string"}},{"name":"filter_region","in":"query","description":"Filter by region (for city drill-downs)","required":false,"schema":{"type":"string"}},{"name":"filter_browser","in":"query","description":"Filter by browser name (for version drill-downs)","required":false,"schema":{"type":"string"}},{"name":"filter_os","in":"query","description":"Filter by OS name (for version drill-downs)","required":false,"schema":{"type":"string"}},{"name":"filter_channel","in":"query","description":"Filter by channel name (for channel drill-downs)","required":false,"schema":{"type":"string"}},{"name":"filter_referrer","in":"query","description":"Filter by referrer hostname (for referrer drill-downs)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved property breakdown","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PropertyBreakdownResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/events/properties/timeline":{"get":{"tags":["Events"],"summary":"Get property timeline by grouping events by a column over time","operationId":"get_property_timeline","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in '%Y-%m-%d %H:%M:%S' format","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in '%Y-%m-%d %H:%M:%S' format","required":true,"schema":{"type":"string"}},{"name":"group_by","in":"query","description":"Column to group by (channel, device_type, browser, etc.)","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"event_name","in":"query","description":"Filter by event name","required":false,"schema":{"type":"string"}},{"name":"aggregation_level","in":"query","description":"Aggregation level: events, sessions, or visitors - default: events","required":false,"schema":{"type":"string"}},{"name":"bucket_size","in":"query","description":"Time bucket: hour, day, week, month (default: auto-detect)","required":false,"schema":{"type":"string"}},{"name":"include_crawlers","in":"query","description":"Include crawler/bot traffic (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Successfully retrieved property timeline","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PropertyTimelineResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/events/timeline":{"get":{"tags":["Events"],"summary":"Get events timeline","operationId":"get_events_timeline","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date for filtering events","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date for filtering events","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"event_name","in":"query","description":"Filter by specific event name","required":false,"schema":{"type":"string"}},{"name":"bucket_size","in":"query","description":"Bucket size: hour, day, or week (auto-detected if not specified)","required":false,"schema":{"type":"string"}},{"name":"aggregation_level","in":"query","description":"Aggregation level: events, sessions, or visitors (default: events)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved events timeline","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EventTimeline"}}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/events/unique":{"get":{"tags":["Funnels"],"summary":"Get all unique/distinct event types for a project (paginated)","operationId":"get_unique_events","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page (default: 50, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Unique event types retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventTypesResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/external-images":{"get":{"tags":["External Images"],"summary":"List external images for a project","operationId":"list_remote_external_images","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page (default: 20)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List of external images","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedExternalImagesResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["External Images"],"summary":"Register an external Docker image","description":"Registers an external Docker image reference without triggering a deployment.\nThe image can be deployed later using the deploy/image endpoint.","operationId":"register_external_image","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterImageRequest"}}},"required":true},"responses":{"201":{"description":"Image registered successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalImageResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/external-images/{image_id}":{"get":{"tags":["External Images"],"summary":"Get details of a specific external image","operationId":"get_remote_external_image","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"image_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Image details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalImageResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Image not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["External Images"],"summary":"Delete an external image","operationId":"delete_external_image","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"image_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Image deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Image not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/flags":{"get":{"tags":["Feature Flags"],"operationId":"list_flags","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"include_archived","in":"query","description":"Include archived flags. Defaults to false.","required":false,"schema":{"type":"boolean"}},{"name":"page","in":"query","description":"1-indexed page number. Defaults to 1.","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page. Defaults to 20, capped at 100.","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}}],"responses":{"200":{"description":"Flags listed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Feature Flags"],"operationId":"create_flag","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFlagRequest"}}},"required":true},"responses":{"201":{"description":"Flag created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"409":{"description":"Flag key already exists"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/flags/{key}":{"get":{"tags":["Feature Flags"],"operationId":"get_flag","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"key","in":"path","description":"Flag key","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Flag retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Flag not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Feature Flags"],"operationId":"archive_flag","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"key","in":"path","description":"Flag key","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Flag archived","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArchiveFlagResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Flag not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Feature Flags"],"operationId":"update_flag","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"key","in":"path","description":"Flag key","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateFlagRequest"}}},"required":true},"responses":{"200":{"description":"Flag updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Flag not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/flags/{key}/environments/{environment_id}":{"put":{"tags":["Feature Flags"],"summary":"Set a flag's value in one environment, and/or flip its kill switch.","operationId":"set_flag_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"key","in":"path","description":"Flag key","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetFlagEnvironmentRequest"}}},"required":true},"responses":{"200":{"description":"Environment value set","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagEnvironmentResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Flag or environment not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/flags/{key}/restore":{"post":{"tags":["Feature Flags"],"summary":"Bring an archived flag back.","description":"Archiving is otherwise one-way: the key stays reserved so the flag cannot\neven be re-created under the same name, which makes an accidental archive\nunrecoverable through the API.","operationId":"restore_flag","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"key","in":"path","description":"Flag key","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Flag restored","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Flag not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/funnels":{"get":{"tags":["Funnels"],"summary":"List all funnels for a project","operationId":"list_funnels","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Funnels retrieved successfully","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/FunnelResponse"}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Funnels"],"summary":"Create a new funnel","operationId":"create_funnel","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFunnelRequest"}}},"required":true},"responses":{"201":{"description":"Funnel created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFunnelResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/funnels/preview":{"post":{"tags":["Funnels"],"summary":"Preview funnel metrics without creating the funnel","operationId":"preview_funnel_metrics","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFunnelRequest"}}},"required":true},"responses":{"200":{"description":"Funnel metrics preview","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FunnelMetricsResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/funnels/{funnel_id}":{"put":{"tags":["Funnels"],"summary":"Update a funnel","operationId":"update_funnel","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"funnel_id","in":"path","description":"Funnel ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFunnelRequest"}}},"required":true},"responses":{"200":{"description":"Funnel updated successfully"},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"404":{"description":"Funnel not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Funnels"],"summary":"Delete a funnel","operationId":"delete_funnel","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"funnel_id","in":"path","description":"Funnel ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Funnel deleted successfully"},"401":{"description":"Unauthorized"},"404":{"description":"Funnel not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/funnels/{funnel_id}/metrics":{"get":{"tags":["Funnels"],"summary":"Get funnel metrics","operationId":"get_funnel_metrics","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"funnel_id","in":"path","description":"Funnel ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID filter","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"country_code","in":"query","description":"Country code filter","required":false,"schema":{"type":"string"}},{"name":"start_date","in":"query","description":"Start date filter (ISO 8601)","required":false,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date filter (ISO 8601)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Funnel metrics retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FunnelMetricsResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"404":{"description":"Funnel not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/git":{"post":{"tags":["Projects"],"summary":"Update git settings for a project","operationId":"update_git_settings","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateGitSettingsRequest"}}},"required":true},"responses":{"200":{"description":"Git settings updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"400":{"description":"Invalid git configuration or branch does not exist"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/gitlab/reinstall-webhook":{"post":{"tags":["Projects"],"summary":"Reinstall the GitLab webhook for a project","description":"Removes the existing webhook (if any) and installs a fresh one.\nUse this when a webhook has been manually deleted on the GitLab side\nand automatic deployments have stopped working.","operationId":"reinstall_gitlab_webhook","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Webhook reinstalled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReinstallWebhookResponse"}}}},"400":{"description":"Project is not connected to a GitLab repository"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/has-error-groups":{"get":{"tags":["error-tracking"],"summary":"Check if project has any error groups","operationId":"has_error_groups","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Error groups existence check","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HasErrorGroupsResponse"}}}},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/has-events":{"get":{"tags":["Events"],"summary":"Check if project has any analytics events","operationId":"has_analytics_events","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully checked for events","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HasEventsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/hourly-visits":{"get":{"tags":["Events"],"summary":"Get hourly visits","operationId":"get_hourly_visits","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date for filtering visits","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date for filtering visits","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"aggregation_level","in":"query","description":"Aggregation level: events (page views), sessions (unique sessions), or visitors (unique visitors) - default: events","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved hourly visits","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EventTimeline"}}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/images":{"get":{"tags":["External Images"],"summary":"List all external images for a project","operationId":"list_external_images","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of external images","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PushedExternalImageResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/images/push":{"post":{"tags":["External Images"],"summary":"Push an external Docker image","operationId":"push_external_image","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PushImageRequest"}}},"required":true},"responses":{"201":{"description":"Image pushed successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PushedExternalImageResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/images/{image_id}":{"get":{"tags":["External Images"],"summary":"Get details of a specific external image","operationId":"get_external_image","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"image_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Image details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PushedExternalImageResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Image not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/incidents":{"get":{"tags":["Status Page"],"summary":"List incidents for a project","operationId":"list_incidents","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"status","in":"query","description":"Filter by status","required":false,"schema":{"type":"string"}},{"name":"page","in":"query","description":"Page number","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Successfully retrieved incidents"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Status Page"],"summary":"Create a new incident","operationId":"create_incident","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateIncidentRequest"}}},"required":true},"responses":{"201":{"description":"Incident created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncidentResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/incidents/bucketed":{"get":{"tags":["Status Page"],"summary":"Get bucketed incident data for a project","operationId":"get_bucketed_incidents","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"interval","in":"query","description":"Bucket interval: '5min', 'hourly', or 'daily' (default: hourly)","required":false,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601) (default: 7 days ago)","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (ISO 8601) (default: now)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved bucketed incident data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncidentBucketedResponse"}}}},"400":{"description":"Invalid parameters"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/logs":{"delete":{"tags":["Logs"],"summary":"Purge all logs for a project before a given timestamp","operationId":"purge_project_logs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PurgeLogsRequest"}}},"required":true},"responses":{"200":{"description":"Purge completed"},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/mcp-servers":{"get":{"tags":["Agents"],"operationId":"list_mcps","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListMcpsResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Agents"],"operationId":"create_mcp","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMcpRequest"}}},"required":true},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpDefinitionResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/mcp-servers/{slug}":{"get":{"tags":["Agents"],"operationId":"get_mcp","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"MCP server not found"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Agents"],"operationId":"update_mcp","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMcpRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"MCP server not found"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Agents"],"operationId":"delete_mcp","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"MCP server deleted"},"401":{"description":"Unauthorized"},"404":{"description":"MCP server not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/mcp-servers/{slug}/config/{field}":{"get":{"tags":["Agents"],"operationId":"reveal_mcp_config","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}},{"name":"field","in":"path","description":"Sensitive field path, such as url or env.API_TOKEN","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SensitiveMcpConfigValueResponse"}}}},"400":{"description":"Field is not revealable"},"401":{"description":"Unauthorized"},"403":{"description":"Missing secrets:read permission"},"404":{"description":"MCP server or field not found"},"500":{"description":"Configuration read or audit failed"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/monitors":{"get":{"tags":["Status Page"],"summary":"List monitors for a project","operationId":"list_monitors","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved monitors","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MonitorResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Status Page"],"summary":"Create a new monitor","operationId":"create_monitor","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMonitorRequest"}}},"required":true},"responses":{"201":{"description":"Monitor created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MonitorResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/observe/events":{"get":{"tags":["Observability"],"summary":"List a merged page of observability events for a project.","description":"Each row carries everything the side panel needs to render — no\nfollow-up fetch is required for the common case. Heavy fields\n(stacktraces, headers, span attributes) are truncated server-side and\nexpose a `*_truncated` flag; clients fetch the full row from the\n`/full` endpoint only when the user explicitly clicks \"Show full\".","operationId":"observability_list_events","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"kinds","in":"query","description":"Comma-separated kinds: `log,request,span,error,revenue`. Empty or\nmissing returns every kind.","required":false,"schema":{"type":"string"}},{"name":"from","in":"query","description":"Inclusive lower bound on event timestamp (ISO 8601, `Z` suffix).","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","description":"Inclusive upper bound on event timestamp.","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"deployment_id","in":"query","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"search","in":"query","description":"Free-text substring matched against per-kind summary fields\n(request path / error class / revenue event_type).","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Page size (default 50, max 200).","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"hide_bots","in":"query","description":"When `true`, exclude bot/crawler request rows. When `false`, only\ninclude bot rows. Omitted means \"include everything\" (default).\nOnly affects the `Request` kind.","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Merged event page","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventsResponse"}}}},"400":{"description":"Invalid filter (kinds, time range, …)","content":{"text/plain":{"schema":{"type":"string"}}}},"401":{"description":"Unauthorized","content":{"text/plain":{"schema":{"type":"string"}}}},"403":{"description":"Insufficient permissions","content":{"text/plain":{"schema":{"type":"string"}}}},"500":{"description":"Internal server error","content":{"text/plain":{"schema":{"type":"string"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/observe/events/{kind}/{event_id}/full":{"get":{"tags":["Observability"],"summary":"Fetch the un-truncated form of one event by `(kind, id)`. Side panel\n\"Show full\" action calls this — the list response carries truncated\npreviews + a `*_truncated` flag to let the UI decide whether to fetch.","operationId":"observability_full_event","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"kind","in":"path","description":"Event kind discriminator","required":true,"schema":{"$ref":"#/components/schemas/EventKind"}},{"name":"event_id","in":"path","description":"Per-kind identity: request_id for requests, `{trace_id}:{span_id}` for spans, serial id for errors/revenue","required":true,"schema":{"type":"string"}},{"name":"ts","in":"query","description":"The row's event timestamp as returned by the list endpoint. Optional,\nbut strongly recommended: it bounds the lookup to the storage\npartitions/chunks around that instant instead of scanning the whole\nretention window.","required":false,"schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"Full row","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FullEvent"}}}},"401":{"description":"Unauthorized","content":{"text/plain":{"schema":{"type":"string"}}}},"403":{"description":"Insufficient permissions","content":{"text/plain":{"schema":{"type":"string"}}}},"404":{"description":"Event not found in project","content":{"text/plain":{"schema":{"type":"string"}}}},"500":{"description":"Internal server error","content":{"text/plain":{"schema":{"type":"string"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/releases/{release}/source-files":{"get":{"tags":["source-maps"],"summary":"List uploaded source files for a release (metadata only).","operationId":"list_source_files","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"release","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of source files","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceFileListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["source-maps"],"summary":"Upload a raw source file for a release (native symbolication).","description":"Accepts a multipart form with:\n- `file`: the source file bytes (required)\n- `file_path`: the path of the file as it appears in stack frames (required;\n derived from the uploaded filename if omitted). Normalized with the `~`\n prefix convention, matching source-map storage.\n\nRequires the project's `error_source_context_enabled` toggle to be on.\nUpserts on (project, release, file_path).","operationId":"upload_source_file","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"release","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"201":{"description":"Source file uploaded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceFileResponse"}}}},"400":{"description":"Missing fields"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"409":{"description":"Source context disabled for project"},"413":{"description":"Source file too large"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["source-maps"],"summary":"Delete all uploaded source files for a release.","operationId":"delete_release_source_files","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"release","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Source files deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/releases/{release}/source-maps":{"get":{"tags":["source-maps"],"summary":"List all source maps for a specific release","operationId":"list_source_maps","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"release","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of source maps","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceMapListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["source-maps"],"summary":"Upload a source map for a release.","description":"Accepts a multipart form with:\n- `file`: The .map file (required)\n- `file_path`: The URL path of the minified file as it appears in stack traces (required).\n Uses the ~ prefix convention (e.g., \"~/assets/main.js\").\n If a full URL is provided, it will be normalized automatically.\n- `dist`: Optional distribution identifier\n\nIf a source map already exists for the same (project, release, file_path), it is replaced.","operationId":"upload_source_map","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"release","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"201":{"description":"Source map uploaded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceMapResponse"}}}},"400":{"description":"Invalid source map or missing fields"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"413":{"description":"Source map too large"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["source-maps"],"summary":"Delete all source maps for a specific release","operationId":"delete_release_source_maps","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"release","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Source maps deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/events":{"get":{"tags":["Revenue"],"summary":"Recent ingested events for the activity feed.","operationId":"revenue_recent_events","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RecentEventResponse"}}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/integrations":{"get":{"tags":["Revenue"],"summary":"List revenue integrations for a project.","operationId":"revenue_list_integrations","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/IntegrationResponse"}}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Revenue"],"summary":"Create a new revenue integration. Response contains the generated\nwebhook path that the user must paste into their provider's dashboard.","operationId":"revenue_create_integration","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateIntegrationBody"}}},"required":true},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntegrationResponse"}}}},"400":{"description":"Validation error"},"409":{"description":"Already connected"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/integrations/{integration_id}":{"delete":{"tags":["Revenue"],"summary":"Delete a revenue integration (permanent — use rotate_token to refresh\ncredentials without breaking history).","operationId":"revenue_delete_integration","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"integration_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/integrations/{integration_id}/config":{"post":{"tags":["Revenue"],"summary":"Replace the typed provider config on an integration. Passing `null`\nclears the config back to the accept-everything default. The config's\nprovider tag must match the integration's provider.","operationId":"revenue_update_config","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"integration_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateConfigBody"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntegrationResponse"}}}},"400":{"description":"Validation error"},"404":{"description":"Integration not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/integrations/{integration_id}/import/invoices":{"post":{"tags":["Revenue"],"summary":"Import a Stripe invoices CSV export. Each paid invoice becomes an\n`invoice.paid` event so historical MRR/charge totals populate the\ntimeseries. Ingestion is idempotent: re-uploading the same file is a\nno-op.","operationId":"revenue_import_invoices_csv","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"integration_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportOutcomeResponse"}}}},"400":{"description":"Malformed CSV or wrong provider"},"404":{"description":"Integration not found"},"413":{"description":"CSV too large"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/integrations/{integration_id}/import/subscriptions":{"post":{"tags":["Revenue"],"summary":"Import a Stripe subscriptions CSV export. Use this to backfill MRR /\nactive subscriptions when migrating from Stripe without providing\nAPI keys. Webhooks remain the source of truth for live updates —\nCSV rows never overwrite newer webhook state.","operationId":"revenue_import_subscriptions_csv","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"integration_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportOutcomeResponse"}}}},"400":{"description":"Malformed CSV or wrong provider"},"404":{"description":"Integration not found"},"413":{"description":"CSV too large"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/integrations/{integration_id}/rotate-token":{"post":{"tags":["Revenue"],"summary":"Rotate the webhook path token. Returns the new integration state —\nthe user must paste the new URL into their provider's dashboard.","operationId":"revenue_rotate_token","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"integration_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntegrationResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/integrations/{integration_id}/update-secret":{"post":{"tags":["Revenue"],"summary":"Replace the stored signing secret without rotating the webhook URL.\nUse this after rotating the secret in the provider's dashboard.","operationId":"revenue_update_secret","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"integration_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSecretBody"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntegrationResponse"}}}},"400":{"description":"Validation error"},"404":{"description":"Integration not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/metrics/customers":{"get":{"tags":["Revenue"],"summary":"New + churned customers per bucket.","operationId":"revenue_metrics_customers","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CustomerMovementResponse"}}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/metrics/mrr":{"get":{"tags":["Revenue"],"summary":"Bucketed MRR timeseries for the revenue chart.","operationId":"revenue_metrics_mrr","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MrrBucketResponse"}}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/metrics/summary":{"get":{"tags":["Revenue"],"summary":"Current MRR / ARR / churn / ARPU for a project, in one currency.","operationId":"revenue_metrics_summary","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MetricsSummaryResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/secrets":{"get":{"tags":["Secrets"],"summary":"List project secrets (metadata only — values never returned).","operationId":"listProjectSecrets","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Optional environment filter","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of secrets (metadata only, no values)","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProjectSecretResponse"}}}}},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}},"post":{"tags":["Secrets"],"summary":"Create a new secret. The value is encrypted before storage and will be\nmounted as a file at `/run/secrets/` on the next deployment.\nThe plaintext value is NOT returned — the response carries only metadata.","operationId":"createProjectSecret","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectSecretRequest"}}},"required":true},"responses":{"201":{"description":"Secret created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectSecretResponse"}}}},"400":{"description":"Invalid key or value too large"},"409":{"description":"Key already exists in project"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/secrets/{secret_id}":{"put":{"tags":["Secrets"],"summary":"Update a project secret. Value rotation requires a redeploy to take effect —\nrunning containers keep their currently-mounted values until the next\ndeployment.","operationId":"updateProjectSecret","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"secret_id","in":"path","description":"Secret ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProjectSecretRequest"}}},"required":true},"responses":{"200":{"description":"Secret updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectSecretResponse"}}}},"400":{"description":"Value too large"},"404":{"description":"Secret not found"},"500":{"description":"Internal server error"}}},"delete":{"tags":["Secrets"],"summary":"Delete a project secret. Running containers keep their mounted secret files\nuntil they are redeployed.","operationId":"deleteProjectSecret","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"secret_id","in":"path","description":"Secret ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Secret deleted"},"404":{"description":"Secret not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/settings":{"post":{"tags":["Projects"],"summary":"Update project settings","operationId":"update_project_settings","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProjectSettingsRequest"}}},"required":true},"responses":{"200":{"description":"Project settings updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/skills":{"get":{"tags":["Agents"],"operationId":"list_skills","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListSkillsResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Agents"],"operationId":"create_skill","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSkillRequest"}}},"required":true},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/skills/upload":{"post":{"tags":["Agents"],"summary":"Upload a skill with an archive (tar.gz) — project-scoped.","operationId":"upload_skill","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"type":"string"}}},"required":true},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/skills/{slug}":{"get":{"tags":["Agents"],"operationId":"get_skill","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Agents"],"operationId":"update_skill","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSkillRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Agents"],"operationId":"delete_skill","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Skill deleted"},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/skills/{slug}/archive":{"get":{"tags":["Agents"],"summary":"Download a skill's archive (tar.gz) — project-scoped.","operationId":"download_skill_archive","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Skill archive tar.gz","content":{"application/gzip":{}}},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found or has no archive"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/source-map-releases":{"get":{"tags":["source-maps"],"summary":"List all releases that have source maps for a project","operationId":"list_releases","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of releases","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReleaseListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/source-maps/{source_map_id}":{"delete":{"tags":["source-maps"],"summary":"Delete a specific source map by ID","operationId":"delete_source_map","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"source_map_id","in":"path","description":"Source map ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Source map deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Source map not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/static-bundles":{"get":{"tags":["Static Bundles"],"summary":"List static bundles for a project","operationId":"list_static_bundles","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page (default: 20)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List of static bundles","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedStaticBundlesResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/static-bundles/{bundle_id}":{"get":{"tags":["Static Bundles"],"summary":"Get details of a specific static bundle","operationId":"get_static_bundle","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"bundle_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Bundle details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StaticBundleResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Bundle not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Static Bundles"],"summary":"Delete a static bundle","operationId":"delete_static_bundle","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"bundle_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Bundle deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Bundle not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/status":{"get":{"tags":["Status Page"],"summary":"Get status page overview","operationId":"get_status_overview","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved status overview","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatusPageOverview"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/unique-counts":{"get":{"tags":["Events"],"summary":"Get unique counts over time frame","operationId":"get_unique_counts","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in '%Y-%m-%d %H:%M:%S' format","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in '%Y-%m-%d %H:%M:%S' format","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"metric","in":"query","description":"Metric to count: 'sessions' (unique sessions), 'visitors' (unique visitors), 'returning_visitors' (visitors seen before the range), or 'page_views' (total page views) (default: 'sessions')","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved count","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UniqueCountsResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/upload/static":{"post":{"tags":["Static Bundles"],"summary":"Upload a static bundle for later deployment","description":"Uploads a tar.gz or zip file containing static assets. The bundle can be\ndeployed later using the deploy/static endpoint.","operationId":"upload_static_bundle","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/SourceArchiveUpload"}}},"required":true},"responses":{"201":{"description":"Bundle uploaded successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StaticBundleResponse"}}}},"400":{"description":"Invalid request or unsupported format"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project not found"},"413":{"description":"Bundle too large"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/vulnerability-scans":{"get":{"tags":["Vulnerability Scans"],"operationId":"list_project_scans","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List of vulnerability scans","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ScanResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Vulnerability Scans"],"operationId":"trigger_scan","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerScanRequest"}}},"required":true},"responses":{"202":{"description":"Scan triggered successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerScanResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/vulnerability-scans/environments":{"get":{"tags":["Vulnerability Scans"],"operationId":"get_latest_scans_per_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Latest scans per environment for current deployments","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ScanResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/vulnerability-scans/latest":{"get":{"tags":["Vulnerability Scans"],"operationId":"get_latest_scan","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Latest scan for project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScanResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"No scans found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/webhooks":{"get":{"tags":["Webhooks"],"summary":"List all webhooks for a project","operationId":"list_webhooks","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20},{"name":"sort_by","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"List of webhooks","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/WebhookResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Webhooks"],"summary":"Create a new webhook","operationId":"create_webhook","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWebhookRequestBody"}}},"required":true},"responses":{"201":{"description":"Webhook created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/webhooks/{webhook_id}":{"get":{"tags":["Webhooks"],"summary":"Get a specific webhook","operationId":"get_webhook","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"webhook_id","in":"path","description":"Webhook ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Webhook details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Webhook not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Webhooks"],"summary":"Update a webhook","operationId":"update_webhook","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"webhook_id","in":"path","description":"Webhook ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWebhookRequestBody"}}},"required":true},"responses":{"200":{"description":"Webhook updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Webhook not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Webhooks"],"summary":"Delete a webhook","operationId":"delete_webhook","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"webhook_id","in":"path","description":"Webhook ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Webhook deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Webhook not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/webhooks/{webhook_id}/deliveries":{"get":{"tags":["Webhook Deliveries"],"summary":"List webhook deliveries","operationId":"list_deliveries","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"webhook_id","in":"path","description":"Webhook ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"limit","in":"query","description":"Number of deliveries to return (default: 50)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List of deliveries","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/WebhookDeliveryResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/webhooks/{webhook_id}/deliveries/{delivery_id}":{"get":{"tags":["Webhook Deliveries"],"summary":"Get a specific webhook delivery by ID","operationId":"get_delivery","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"webhook_id","in":"path","description":"Webhook ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"delivery_id","in":"path","description":"Delivery ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Delivery details including full payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDeliveryResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Delivery not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/webhooks/{webhook_id}/deliveries/{delivery_id}/retry":{"post":{"tags":["Webhook Deliveries"],"summary":"Retry a failed delivery","operationId":"retry_delivery","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"webhook_id","in":"path","description":"Webhook ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"delivery_id","in":"path","description":"Delivery ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Delivery retried","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDeliveryResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Delivery not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/workflows/dry-run":{"post":{"tags":["Workflows"],"operationId":"workflow_dry_run","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkflowDryRunRequest"}}},"required":true},"responses":{"202":{"description":"Ephemeral run created and queued","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRunResponse"}}}},"400":{"description":"Validation error (bad YAML, oversized payload, capped limits exceeded)"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/proxy-logs":{"get":{"tags":["Proxy Logs"],"summary":"Get proxy logs with optional filters and pagination","operationId":"get_proxy_logs","parameters":[{"name":"project_id","in":"query","description":"Filter by project ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"session_id","in":"query","description":"Filter by session ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"visitor_id","in":"query","description":"Filter by visitor ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"start_date","in":"query","description":"Start date for filtering (ISO 8601 format).\n\n**Defaults to 1 hour before `end_date` (or before now) when omitted.**\nThe listing is always time-bounded: an unbounded query would have to\nconsider the entire retention window — 100M+ rows on a busy deployment —\nto return a single page. Pass an explicit `start_date` to widen the\nwindow, up to the configured retention horizon.\n\nThe maximum span between `start_date` and `end_date` is 7 days when\n`project_id` is omitted, or 30 days when a single `project_id` is set —\na project-scoped query is bounded by that project's own row count\nrather than the whole deployment's. A wider request is rejected with a\n400 naming the applicable cap.","required":false,"schema":{"type":["string","null"],"format":"date-time"}},{"name":"end_date","in":"query","description":"End date for filtering (ISO 8601 format). Defaults to now.","required":false,"schema":{"type":["string","null"],"format":"date-time"}},{"name":"method","in":"query","description":"Filter by HTTP method (GET, POST, etc.)","required":false,"schema":{"type":["string","null"]}},{"name":"host","in":"query","description":"Filter by host header","required":false,"schema":{"type":["string","null"]}},{"name":"path","in":"query","description":"Filter by path (supports partial match)","required":false,"schema":{"type":["string","null"]}},{"name":"client_ip","in":"query","description":"Filter by client IP address","required":false,"schema":{"type":["string","null"]}},{"name":"status_code","in":"query","description":"Filter by HTTP status code","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"response_time_min","in":"query","description":"Filter by minimum response time in ms","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"response_time_max","in":"query","description":"Filter by maximum response time in ms","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"routing_status","in":"query","description":"Filter by routing status (routed, no_project, error, pending)","required":false,"schema":{"type":["string","null"]}},{"name":"request_source","in":"query","description":"Filter by request source (proxy, api, console, cli)","required":false,"schema":{"type":["string","null"]}},{"name":"is_system_request","in":"query","description":"Filter by system request flag","required":false,"schema":{"type":["boolean","null"]}},{"name":"user_agent","in":"query","description":"Filter by user agent string (partial match)","required":false,"schema":{"type":["string","null"]}},{"name":"browser","in":"query","description":"Filter by browser name","required":false,"schema":{"type":["string","null"]}},{"name":"operating_system","in":"query","description":"Filter by operating system","required":false,"schema":{"type":["string","null"]}},{"name":"device_type","in":"query","description":"Filter by device type (mobile, desktop, tablet)","required":false,"schema":{"type":["string","null"]}},{"name":"is_bot","in":"query","description":"Filter by bot detection","required":false,"schema":{"type":["boolean","null"]}},{"name":"exclude_bots","in":"query","description":"When `true`, exclude rows flagged as bots while KEEPING rows whose\n`is_bot` is NULL (older rows without detection metadata). This is the\ntri-state complement of `is_bot=false`, which matches only rows\nexplicitly detected as non-bots. `false`/omitted is a no-op.","required":false,"schema":{"type":["boolean","null"]}},{"name":"bot_name","in":"query","description":"Filter by bot name","required":false,"schema":{"type":["string","null"]}},{"name":"ai_provider","in":"query","description":"Filter by AI provider (e.g. `OpenAI`, `Anthropic`, `Perplexity`). Matches\nthe canonical provider returned by the AI agent detector.","required":false,"schema":{"type":["string","null"]}},{"name":"ai_agent","in":"query","description":"Filter by AI agent name (e.g. `GPTBot`, `ChatGPT-User`). Equivalent to\nfiltering `bot_name` against a known AI taxonomy.","required":false,"schema":{"type":["string","null"]}},{"name":"is_ai_agent","in":"query","description":"When `true`, only return requests classified as known AI agents\n(regardless of provider/agent). Mutually compatible with the above.","required":false,"schema":{"type":["boolean","null"]}},{"name":"request_size_min","in":"query","description":"Filter by minimum request size in bytes","required":false,"schema":{"type":["integer","null"],"format":"int64"}},{"name":"request_size_max","in":"query","description":"Filter by maximum request size in bytes","required":false,"schema":{"type":["integer","null"],"format":"int64"}},{"name":"response_size_min","in":"query","description":"Filter by minimum response size in bytes","required":false,"schema":{"type":["integer","null"],"format":"int64"}},{"name":"response_size_max","in":"query","description":"Filter by maximum response size in bytes","required":false,"schema":{"type":["integer","null"],"format":"int64"}},{"name":"cache_status","in":"query","description":"Filter by cache status","required":false,"schema":{"type":["string","null"]}},{"name":"container_id","in":"query","description":"Filter by container ID","required":false,"schema":{"type":["string","null"]}},{"name":"upstream_host","in":"query","description":"Filter by upstream host","required":false,"schema":{"type":["string","null"]}},{"name":"has_error","in":"query","description":"Filter by presence of error message","required":false,"schema":{"type":["boolean","null"]}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (default: 20, max: 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"sort_by","in":"query","description":"Sort by field (default: timestamp)","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","description":"Sort order (asc or desc, default: desc)","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"List of proxy logs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProxyLogsPaginatedResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/ai-agents/known":{"get":{"tags":["Proxy Logs"],"summary":"List every AI agent the detector knows how to classify.","description":"Returned in the same order as the internal taxonomy so the UI can use it as\na stable dropdown.","operationId":"list_known_ai_agents","responses":{"200":{"description":"Known AI agents","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KnownAiAgentsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/request/{request_id}":{"get":{"tags":["Proxy Logs"],"summary":"Get a proxy log by request ID (for tracing)","operationId":"get_proxy_log_by_request_id","parameters":[{"name":"request_id","in":"path","description":"Request ID from pingora","required":true,"schema":{"type":"string"}},{"name":"timestamp","in":"query","description":"Event time of the log row (ISO 8601). When provided, the lookup is\nbounded to the hypertable chunks around this instant instead of\nscanning (and decompressing) the whole retention window. The list\nendpoint already returns this value per row — always pass it when\nnavigating from a list.","required":false,"schema":{"type":["string","null"],"format":"date-time"}}],"responses":{"200":{"description":"Proxy log found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProxyLogResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Proxy log not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/ai-agent-pages":{"get":{"tags":["Proxy Logs"],"summary":"Get the top pages accessed by a specific AI agent over a time window.","description":"Returns page paths ranked by request count, scoped to a single canonical\nagent name (e.g. `ChatGPT-User`). Use `GET /proxy-logs/ai-agents/known` to\nlist all valid agent names. Unknown agent names return an empty items array.","operationId":"get_ai_agent_pages","parameters":[{"name":"agent","in":"query","description":"Canonical agent name to filter by (e.g. `ChatGPT-User`, `ClaudeBot`).\nMust be a name returned by `GET /proxy-logs/ai-agents/known`.","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Filter by project ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601). Defaults to `end_time - 7d`.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-22T00:00:00Z"},{"name":"end_time","in":"query","description":"End time (ISO 8601). Defaults to now.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-29T00:00:00Z"},{"name":"limit","in":"query","description":"Maximum rows to return. Capped at 100 server-side.","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}}],"responses":{"200":{"description":"Pages breakdown for the requested agent","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiAgentPagesResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/ai-agents":{"get":{"tags":["Proxy Logs"],"summary":"Get the per-AI-agent breakdown for a project over a time window.","operationId":"get_ai_agent_breakdown","parameters":[{"name":"project_id","in":"query","description":"Filter by project ID (recommended for per-project analytics).","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601). Defaults to `end_time - 7d`.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-22T00:00:00Z"},{"name":"end_time","in":"query","description":"End time (ISO 8601). Defaults to now.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-29T00:00:00Z"},{"name":"limit","in":"query","description":"Maximum rows to return. Capped at 100 server-side.","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"path","in":"query","description":"Optional exact path filter. Only used by the AI pages breakdown — when\nset, returns the single matching page so callers can ask \"how many AI\nagents hit this page?\".","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"AI agent breakdown","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiAgentBreakdownResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/ai-agents/timeline":{"get":{"tags":["Proxy Logs"],"summary":"Time-bucketed AI-agent request volume, split by provider or agent.","description":"Powers the \"AI agents over time\" stacked chart. Same data source as the AI\nagent breakdown (request logs), just bucketed.","operationId":"get_ai_agent_timeline","parameters":[{"name":"project_id","in":"query","description":"Filter by project ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601). Defaults to `end_time - 7d`.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-22T00:00:00Z"},{"name":"end_time","in":"query","description":"End time (ISO 8601). Defaults to now.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-29T00:00:00Z"},{"name":"group_by","in":"query","description":"Grouping dimension: `provider` (default) or `agent`.","required":false,"schema":{"type":["string","null"]},"example":"provider"},{"name":"bucket","in":"query","description":"Bucket interval override (e.g. `1 hour`, `1 day`). Auto-selected from the\nwindow width when omitted.","required":false,"schema":{"type":["string","null"]},"example":"1 hour"}],"responses":{"200":{"description":"AI agent timeline","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiAgentTimelineResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/ai-pages":{"get":{"tags":["Proxy Logs"],"summary":"Get the top pages crawled by AI agents over a time window.","operationId":"get_ai_page_breakdown","parameters":[{"name":"project_id","in":"query","description":"Filter by project ID (recommended for per-project analytics).","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601). Defaults to `end_time - 7d`.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-22T00:00:00Z"},{"name":"end_time","in":"query","description":"End time (ISO 8601). Defaults to now.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-29T00:00:00Z"},{"name":"limit","in":"query","description":"Maximum rows to return. Capped at 100 server-side.","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"path","in":"query","description":"Optional exact path filter. Only used by the AI pages breakdown — when\nset, returns the single matching page so callers can ask \"how many AI\nagents hit this page?\".","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"AI page breakdown","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiPageBreakdownResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/ai-status":{"get":{"tags":["Proxy Logs"],"summary":"HTTP status-class breakdown for AI-agent traffic — are bots being served\n(2xx) or hitting broken/blocked pages (4xx/5xx)?","operationId":"get_ai_status_breakdown","parameters":[{"name":"project_id","in":"query","description":"Filter by project ID (recommended for per-project analytics).","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601). Defaults to `end_time - 7d`.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-22T00:00:00Z"},{"name":"end_time","in":"query","description":"End time (ISO 8601). Defaults to now.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-29T00:00:00Z"},{"name":"limit","in":"query","description":"Maximum rows to return. Capped at 100 server-side.","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"path","in":"query","description":"Optional exact path filter. Only used by the AI pages breakdown — when\nset, returns the single matching page so callers can ask \"how many AI\nagents hit this page?\".","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"AI status breakdown","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiStatusBreakdownResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/projects-health":{"get":{"tags":["Proxy Logs"],"summary":"Get health summaries for multiple projects (last 1 hour)","operationId":"get_projects_health","parameters":[{"name":"project_ids","in":"query","description":"Comma-separated list of project IDs","required":true,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Optional start time (ISO 8601). Defaults to `end_time - 1h`.","required":false,"schema":{"type":["string","null"]},"example":"2025-10-23T00:00:00Z"},{"name":"end_time","in":"query","description":"Optional end time (ISO 8601). Defaults to now.","required":false,"schema":{"type":["string","null"]},"example":"2025-10-23T23:59:59Z"},{"name":"is_bot","in":"query","description":"Filter by bot detection. Pass `false` to exclude bots, `true` for bots only.","required":false,"schema":{"type":["boolean","null"]}}],"responses":{"200":{"description":"Health summaries per project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectsHealthResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/time-buckets":{"get":{"tags":["Proxy Logs"],"summary":"Get time-bucketed statistics with optional filters","operationId":"get_time_bucket_stats","parameters":[{"name":"start_time","in":"query","description":"Start time (ISO 8601 format)","required":true,"schema":{"type":"string"},"example":"2025-10-23T00:00:00Z"},{"name":"end_time","in":"query","description":"End time (ISO 8601 format)","required":true,"schema":{"type":"string"},"example":"2025-10-23T23:59:59Z"},{"name":"bucket_interval","in":"query","description":"Bucket interval (e.g., \"1 hour\", \"1 day\", \"5 minutes\")","required":false,"schema":{"type":"string"}},{"name":"method","in":"query","description":"Filter by HTTP method","required":false,"schema":{"type":"string"}},{"name":"client_ip","in":"query","description":"Filter by client IP","required":false,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Filter by project ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"host","in":"query","description":"Filter by host","required":false,"schema":{"type":"string"}},{"name":"status_code","in":"query","description":"Filter by status code","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"status_code_class","in":"query","description":"Filter by status code class (e.g. \"2xx\", \"3xx\", \"4xx\", \"5xx\")","required":false,"schema":{"type":"string"}},{"name":"routing_status","in":"query","description":"Filter by routing status","required":false,"schema":{"type":"string"}},{"name":"request_source","in":"query","description":"Filter by request source","required":false,"schema":{"type":"string"}},{"name":"is_bot","in":"query","description":"Filter by bot detection","required":false,"schema":{"type":"boolean"}},{"name":"device_type","in":"query","description":"Filter by device type","required":false,"schema":{"type":"string"}},{"name":"has_project","in":"query","description":"When true, only count requests that matched a project\n(project_id IS NOT NULL). Makes chart totals line up with the\nper-project health cards.","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Time-bucketed statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TimeBucketStatsResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/today":{"get":{"tags":["Proxy Logs"],"summary":"Get today's request count with optional filters","operationId":"get_today_stats","parameters":[{"name":"method","in":"query","description":"Filter by HTTP method","required":false,"schema":{"type":["string","null"]}},{"name":"client_ip","in":"query","description":"Filter by client IP","required":false,"schema":{"type":["string","null"]}},{"name":"project_id","in":"query","description":"Filter by project ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"host","in":"query","description":"Filter by host","required":false,"schema":{"type":["string","null"]}},{"name":"status_code","in":"query","description":"Filter by status code","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"status_code_class","in":"query","description":"Filter by status code class (e.g. \"2xx\", \"3xx\", \"4xx\", \"5xx\")","required":false,"schema":{"type":["string","null"]}},{"name":"routing_status","in":"query","description":"Filter by routing status","required":false,"schema":{"type":["string","null"]}},{"name":"request_source","in":"query","description":"Filter by request source","required":false,"schema":{"type":["string","null"]}},{"name":"is_bot","in":"query","description":"Filter by bot detection","required":false,"schema":{"type":["boolean","null"]}},{"name":"device_type","in":"query","description":"Filter by device type","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"Today's request count","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TodayStatsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/{id}":{"get":{"tags":["Proxy Logs"],"summary":"Get a single proxy log by ID","operationId":"get_proxy_log_by_id","parameters":[{"name":"id","in":"path","description":"Proxy log ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"timestamp","in":"query","description":"Event time of the log row (ISO 8601). When provided, the lookup is\nbounded to the hypertable chunks around this instant instead of\nscanning (and decompressing) the whole retention window. The list\nendpoint already returns this value per row — always pass it when\nnavigating from a list.","required":false,"schema":{"type":["string","null"],"format":"date-time"}}],"responses":{"200":{"description":"Proxy log found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProxyLogResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Proxy log not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/repositories":{"get":{"tags":["Git Providers"],"summary":"List synced repositories with advanced filtering","description":"Lists repositories that have been synced to the database with filtering options.\nThis provides fast access to repository metadata with filtering by connection, search, and other criteria.","operationId":"list_synced_repositories","parameters":[{"name":"page","in":"query","description":"Page number for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"sort","in":"query","description":"Sort field (name, created_at, updated_at, stars, watchers, size, issues)","required":false,"schema":{"type":"string"}},{"name":"direction","in":"query","description":"Sort direction (asc, desc)","required":false,"schema":{"type":"string"}},{"name":"search","in":"query","description":"Search term to filter repositories","required":false,"schema":{"type":"string"}},{"name":"owner","in":"query","description":"Filter by repository owner","required":false,"schema":{"type":"string"}},{"name":"language","in":"query","description":"Filter by programming language","required":false,"schema":{"type":"string"}},{"name":"private","in":"query","description":"Filter by private status (true/false)","required":false,"schema":{"type":"boolean"}},{"name":"git_provider_connection_id","in":"query","description":"Filter by git provider connection ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of synced repositories","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositoryListResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repositories/{owner}/{name}":{"get":{"tags":["Git Providers"],"summary":"Get repository by owner and name from any connection","operationId":"get_repository_by_name","parameters":[{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}},{"name":"connection_id","in":"query","description":"Optional specific connection ID to search","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Repository found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositoryResponse"}}}},"404":{"description":"Repository not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repositories/{owner}/{name}/all":{"get":{"tags":["Git Providers"],"summary":"Get all repositories with same owner/name from all git providers","operationId":"get_all_repositories_by_name","parameters":[{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Repositories found from all providers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RepositoryResponse"}}}}},"404":{"description":"No repositories found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repositories/{owner}/{name}/preset":{"get":{"tags":["Git Providers"],"summary":"Get repository preset by owner and name","operationId":"get_repository_preset_by_name","parameters":[{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}},{"name":"branch","in":"query","description":"Git branch to check (defaults to repository's default branch)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Repository preset calculated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositoryPresetResponse"}}}},"404":{"description":"Repository not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repositories/{owner}/{repo}/branches":{"get":{"tags":["Repositories"],"summary":"Get repository branches","operationId":"get_repository_branches","parameters":[{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"repo","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}},{"name":"connection_id","in":"query","description":"Git provider connection ID (required when multiple connections have the same repo)","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"fresh","in":"query","description":"Force fetch fresh data, bypassing cache (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of branches","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BranchListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Repository not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repositories/{owner}/{repo}/tags":{"get":{"tags":["Repositories"],"summary":"Get repository tags","operationId":"get_repository_tags","parameters":[{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"repo","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}},{"name":"connection_id","in":"query","description":"Git provider connection ID (required when multiple connections have the same repo)","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"fresh","in":"query","description":"Force fetch fresh data, bypassing cache (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of tags","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TagListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Repository not found"},"429":{"description":"Fresh tag lookup rate limit exceeded"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repositories/{repository_id}/preset/live":{"get":{"tags":["Git Providers"],"operationId":"get_repository_preset_live","parameters":[{"name":"repository_id","in":"path","description":"Repository ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"branch","in":"query","description":"Git branch to check (defaults to repository's default branch)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Repository presets calculated successfully - includes root preset and projects in subdirectories","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositoryPresetResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"The git provider rejected the stored credential - the connection must be re-authorized"},"404":{"description":"Repository not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repository/{repository_id}":{"get":{"tags":["Git Providers"],"summary":"Get repository by ID","operationId":"get_repository_by_id","parameters":[{"name":"repository_id","in":"path","description":"Repository ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Repository found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositoryResponse"}}}},"404":{"description":"Repository not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repository/{repository_id}/branches":{"get":{"tags":["Repositories"],"summary":"Get repository branches by repository ID","operationId":"get_branches_by_repository_id","parameters":[{"name":"repository_id","in":"path","description":"Repository ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"fresh","in":"query","description":"Force fetch fresh data, bypassing cache (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of branches","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BranchListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Repository not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repository/{repository_id}/commits":{"get":{"tags":["Repositories"],"summary":"List recent commits for a repository branch","operationId":"list_commits_by_repository_id","parameters":[{"name":"repository_id","in":"path","description":"Repository ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"branch","in":"query","description":"Branch name to list commits for","required":true,"schema":{"type":"string"}},{"name":"per_page","in":"query","description":"Number of commits to return (default: 20, max: 100)","required":false,"schema":{"type":["integer","null"],"format":"int32","minimum":0}}],"responses":{"200":{"description":"List of commits","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommitListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Repository not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repository/{repository_id}/commits/{commit_sha}":{"get":{"tags":["Repositories"],"summary":"Check if a commit exists in a repository","operationId":"check_commit_exists","parameters":[{"name":"repository_id","in":"path","description":"Repository ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"commit_sha","in":"path","description":"Commit SHA to check","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Commit existence check result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommitExistsResponse"}}}},"400":{"description":"Invalid commit SHA"},"401":{"description":"Unauthorized"},"404":{"description":"Repository not found"},"429":{"description":"Commit lookup rate limit exceeded"},"500":{"description":"Internal server error"},"502":{"description":"Git provider request failed"}},"security":[{"bearer_auth":[]}]}},"/repository/{repository_id}/tags":{"get":{"tags":["Repositories"],"summary":"Get repository tags by repository ID","operationId":"get_tags_by_repository_id","parameters":[{"name":"repository_id","in":"path","description":"Repository ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"fresh","in":"query","description":"Force fetch fresh data, bypassing cache (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of tags","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TagListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Repository not found"},"429":{"description":"Fresh tag lookup rate limit exceeded"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/restore-runs/{id}":{"get":{"tags":["Restore"],"operationId":"get_restore_run","parameters":[{"name":"id","in":"path","description":"Restore run id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Restore run progress","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RestoreRunView"}}}},"404":{"description":"Restore run not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/revenue/events":{"get":{"tags":["Revenue"],"summary":"Org-wide revenue events across every project. Powers the revenue\ntransactions page. Supports filtering by project, date range, and\nevent type.","operationId":"revenue_global_events","parameters":[{"name":"project_id","in":"query","description":"Filter to a single project","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"from","in":"query","description":"Lower bound (inclusive), ISO-8601","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","description":"Upper bound (inclusive), ISO-8601","required":false,"schema":{"type":"string"}},{"name":"event_types","in":"query","description":"Comma-separated event types (e.g. `invoice.paid,charge.succeeded`)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max rows, default 100, max 500","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GlobalRecentEventResponse"}}}}}},"security":[{"bearer_auth":[]}]}},"/revenue/metrics/global-mrr":{"get":{"tags":["Revenue"],"summary":"Org-wide MRR total, summed across every project in the install.\nPowers the single-number MRR card on the main dashboard.","operationId":"revenue_metrics_global_mrr","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GlobalMrrResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/revenue/metrics/global-summary":{"get":{"tags":["Revenue"],"summary":"Org-wide revenue summary: MRR, paid cash (30d + all-time), refunds,\nactive subscriptions/customers, and transaction count. Powers the\nheader on the Revenue transactions page.","operationId":"revenue_metrics_global_summary","parameters":[{"name":"currency","in":"query","description":"ISO-4217 currency code, default USD","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GlobalRevenueSummaryResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/revenue/providers":{"get":{"tags":["Revenue"],"summary":"List registered providers (what the UI needs to render the \"Connect\"\ndropdown + its wizard instructions).","operationId":"revenue_list_providers","responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProviderDescriptor"}}}}}},"security":[{"bearer_auth":[]}]}},"/session-replays":{"get":{"tags":["Analytics"],"summary":"Get session replays for a project","operationId":"get_project_session_replays","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-based)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Items per page","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Session replays retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetProjectSessionReplaysResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/sessions/{session_id}/events":{"get":{"tags":["Events"],"summary":"Get events for a specific session","operationId":"get_session_events","parameters":[{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved session events","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalyticsSessionEventsResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Session not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings":{"get":{"tags":["Settings"],"summary":"Get application settings","operationId":"get_settings","responses":{"200":{"description":"Application settings with masked sensitive fields","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppSettingsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Settings"],"summary":"Update application settings","operationId":"update_settings","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppSettings"}}},"required":true},"responses":{"200":{"description":"Settings updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SettingsUpdateResponse"}}}},"400":{"description":"Bad request - invalid settings"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/agent-token":{"post":{"tags":["Agents"],"summary":"Save an encrypted AI provider token for use in sandbox containers.","operationId":"save_agent_token","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveAgentTokenRequest"}}},"required":true},"responses":{"200":{"description":"Token encrypted and persisted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveAgentTokenResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Encryption or database error"}},"security":[{"bearer_auth":[]}]}},"/settings/ai-providers":{"get":{"tags":["Agents"],"summary":"List the AI provider catalog. Includes per-provider \"is a credential\nconfigured?\" so the settings UI can render configured/not-configured\nbadges without leaking the encrypted credential.","operationId":"list_ai_providers","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderCatalogResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/settings/ai-providers/{provider_id}":{"patch":{"tags":["Agents"],"summary":"Update provider-scoped settings without touching the saved credential.\nToday that means just `default_model`; future per-provider settings\n(base URL overrides, request headers, etc.) can land here too without\nchanging the shape of `save_credential`.","operationId":"update_ai_provider","parameters":[{"name":"provider_id","in":"path","description":"AI provider ID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAiProviderRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAiProviderResponse"}}}},"400":{"description":"Unknown provider"},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/settings/ai-providers/{provider_id}/activate":{"post":{"tags":["Agents"],"summary":"Activate a provider as the platform-wide default. Refuses to activate a\nprovider that doesn't have a credential saved yet — the UI enforces the\nsame rule on the button, but we re-check server-side so a stale tab\ncan't bypass it.","operationId":"activate_ai_provider","parameters":[{"name":"provider_id","in":"path","description":"AI provider ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivateProviderResponse"}}}},"400":{"description":"Provider not configured"},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/settings/ai-providers/{provider_id}/credential":{"post":{"tags":["Agents"],"summary":"Save (or replace) a provider's credential. The credential is encrypted\nwith `EncryptionService` and stored inside\n`agent_sandbox.providers[provider_id].credentials_encrypted`.","description":"The plaintext shape depends on the flavor's `credential_format`:\n - `ApiKey` / `OauthToken`: the key/token string.\n - `ConfigFile`: the full file body (e.g. OpenCode's `auth.json`).","operationId":"save_ai_provider_credential","parameters":[{"name":"provider_id","in":"path","description":"AI provider ID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveCredentialRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveCredentialResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/settings/disk-status":{"get":{"tags":["Settings"],"summary":"Get current disk usage for the control-plane server","description":"Returns live disk usage for the monitored path along with any disks that\nmeet or exceed the configured alert threshold. Read-only — does not send\nnotifications. Used by the dashboard to surface a low-disk-space warning.","operationId":"get_disk_status","responses":{"200":{"description":"Current disk usage and threshold alerts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiskSpaceCheckResult"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/enrollment-tokens":{"get":{"tags":["Settings"],"summary":"List currently-valid node enrollment tokens (hashes elided).","operationId":"list_enrollment_tokens","responses":{"200":{"description":"Active enrollment tokens","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnrollmentTokenListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Settings"],"summary":"Mint a short-lived, single-use node enrollment token.","operationId":"mint_enrollment_token","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MintEnrollmentTokenRequest"}}},"required":true},"responses":{"200":{"description":"Enrollment token minted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MintEnrollmentTokenResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/enrollment-tokens/{id}":{"delete":{"tags":["Settings"],"summary":"Revoke a node enrollment token by id.","operationId":"revoke_enrollment_token","parameters":[{"name":"id","in":"path","description":"Enrollment token id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Enrollment token revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SettingsUpdateResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Enrollment token not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/join-token":{"delete":{"tags":["Settings"],"summary":"Revoke the current join token","description":"Removes the stored join token hash, allowing any node to register\n(if no other authentication is in place).","operationId":"revoke_join_token","responses":{"200":{"description":"Join token revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SettingsUpdateResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/join-token/generate":{"post":{"tags":["Settings"],"summary":"Generate a new join token for multi-node cluster registration","description":"Creates a random 32-byte hex token, stores the SHA-256 hash in settings,\nand returns the plaintext exactly once. If a token already exists, it is replaced.","operationId":"generate_join_token","responses":{"200":{"description":"Join token generated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateJoinTokenResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/join-token/status":{"get":{"tags":["Settings"],"summary":"Check whether a join token is currently configured","operationId":"get_join_token_status","responses":{"200":{"description":"Join token status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JoinTokenStatusResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/mcp-servers":{"get":{"tags":["Agents"],"operationId":"list_global_mcps","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListMcpsResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Agents"],"operationId":"create_global_mcp","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMcpRequest"}}},"required":true},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpDefinitionResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/settings/mcp-servers/{slug}":{"get":{"tags":["Agents"],"operationId":"get_global_mcp","parameters":[{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"MCP server not found"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Agents"],"operationId":"update_global_mcp","parameters":[{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMcpRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"MCP server not found"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Agents"],"operationId":"delete_global_mcp","parameters":[{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"MCP server deleted"},"401":{"description":"Unauthorized"},"404":{"description":"MCP server not found"}},"security":[{"bearer_auth":[]}]}},"/settings/mcp-servers/{slug}/config/{field}":{"get":{"tags":["Agents"],"operationId":"reveal_global_mcp_config","parameters":[{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}},{"name":"field","in":"path","description":"Sensitive field path, such as url or env.API_TOKEN","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SensitiveMcpConfigValueResponse"}}}},"400":{"description":"Field is not revealable"},"401":{"description":"Unauthorized"},"403":{"description":"Missing secrets:read permission"},"404":{"description":"MCP server or field not found"},"500":{"description":"Configuration read or audit failed"}},"security":[{"bearer_auth":[]}]}},"/settings/routes/refresh":{"post":{"tags":["Settings"],"summary":"Manually refresh the proxy route table","description":"Reloads all routes from the database into the in-memory proxy cache.\nUseful as a workaround when routes are out of sync.","operationId":"refresh_route_table","responses":{"200":{"description":"Route table refreshed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteRefreshResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/sandbox-rebuild":{"post":{"tags":["Agents"],"operationId":"rebuild_sandbox_image","responses":{"200":{"description":"Server-Sent Events stream of rebuild progress; final event `{\"type\":\"done\",\"success\":bool,...}`","content":{"text/event-stream":{}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/settings/sandbox-status":{"get":{"tags":["Agents"],"operationId":"get_global_sandbox_status","responses":{"200":{"description":"Global sandbox readiness for the settings page","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxStatusResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/settings/secrets":{"get":{"tags":["Secrets"],"operationId":"list_secrets","responses":{"200":{"description":"List of global agent secrets","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListSecretsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Secrets"],"operationId":"upsert_secret","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertSecretRequest"}}},"required":true},"responses":{"201":{"description":"Secret created/updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SecretResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/settings/secrets/{name}":{"delete":{"tags":["Secrets"],"operationId":"delete_secret","parameters":[{"name":"name","in":"path","description":"Secret name","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Secret deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Secret not found"}},"security":[{"bearer_auth":[]}]}},"/settings/skills":{"get":{"tags":["Agents"],"operationId":"list_global_skills","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListSkillsResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Agents"],"operationId":"create_global_skill","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSkillRequest"}}},"required":true},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/settings/skills/upload":{"post":{"tags":["Agents"],"summary":"Upload a skill with an archive (tar.gz) — global.","operationId":"upload_global_skill","requestBody":{"content":{"multipart/form-data":{"schema":{"type":"string"}}},"required":true},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/settings/skills/{slug}":{"get":{"tags":["Agents"],"operationId":"get_global_skill","parameters":[{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Agents"],"operationId":"update_global_skill","parameters":[{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSkillRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Agents"],"operationId":"delete_global_skill","parameters":[{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Skill deleted"},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found"}},"security":[{"bearer_auth":[]}]}},"/settings/skills/{slug}/archive":{"get":{"tags":["Agents"],"summary":"Download a skill's archive (tar.gz) — global.","operationId":"download_global_skill_archive","parameters":[{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Skill archive tar.gz","content":{"application/gzip":{}}},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found or has no archive"}},"security":[{"bearer_auth":[]}]}},"/settings/update":{"get":{"tags":["Settings"],"summary":"Report whether a release update can be applied from the console.","operationId":"get_update_capability","responses":{"200":{"description":"Self-update capability for this install","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCapabilityResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Settings"],"summary":"Install a release and restart the server.","description":"Returns as soon as the attempt is accepted: the download and swap run in the\nbackground and the process then exits so its supervisor restarts it on the\nnew binary. Poll `GET /settings/update` for progress — after the restart,\n`last_attempt` carries the outcome.","operationId":"start_update","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartUpdateRequest"}}},"required":true},"responses":{"202":{"description":"Update accepted; the server will restart","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartUpdateResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"409":{"description":"Update unavailable or already running","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"501":{"description":"This process cannot apply updates","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/settings/update-status":{"get":{"tags":["Settings"],"summary":"Report whether a newer temps release is available for this install.","operationId":"get_update_status","responses":{"200":{"description":"Release update status for this install","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateStatusResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/teams":{"get":{"tags":["Teams"],"operationId":"list_teams","parameters":[{"name":"page","in":"query","description":"1-indexed page","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"default 20, max 100","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Paginated teams","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Teams"],"operationId":"create_team","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTeamRequest"}}},"required":true},"responses":{"201":{"description":"Team created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamResponse"}}}},"400":{"description":"Validation error"},"403":{"description":"Insufficient permissions"},"409":{"description":"Slug already taken"}},"security":[{"bearer_auth":[]}]}},"/teams/{team_id}":{"get":{"tags":["Teams"],"operationId":"get_team","parameters":[{"name":"team_id","in":"path","description":"Team id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Team","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamResponse"}}}},"403":{"description":"Insufficient permissions"},"404":{"description":"Team not found"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Teams"],"operationId":"delete_team","parameters":[{"name":"team_id","in":"path","description":"Team id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Team deleted"},"403":{"description":"Insufficient permissions"},"404":{"description":"Team not found"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Teams"],"operationId":"update_team","parameters":[{"name":"team_id","in":"path","description":"Team id","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTeamRequest"}}},"required":true},"responses":{"200":{"description":"Updated team","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamResponse"}}}},"400":{"description":"Validation error"},"403":{"description":"Insufficient permissions"},"404":{"description":"Team not found"}},"security":[{"bearer_auth":[]}]}},"/teams/{team_id}/members":{"get":{"tags":["Teams"],"operationId":"list_team_members","parameters":[{"name":"team_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Members","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TeamMemberResponse"}}}}},"403":{"description":"Insufficient permissions"},"404":{"description":"Team not found"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Teams"],"operationId":"add_team_member","parameters":[{"name":"team_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTeamMemberRequest"}}},"required":true},"responses":{"201":{"description":"Member added","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamMemberResponse"}}}},"403":{"description":"Insufficient permissions"},"404":{"description":"Team not found"},"409":{"description":"User already a member"}},"security":[{"bearer_auth":[]}]}},"/teams/{team_id}/members/{user_id}":{"delete":{"tags":["Teams"],"operationId":"remove_team_member","parameters":[{"name":"team_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"user_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Member removed"},"403":{"description":"Insufficient permissions"},"404":{"description":"Member not found"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Teams"],"operationId":"update_team_member_role","parameters":[{"name":"team_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"user_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMemberRoleRequest"}}},"required":true},"responses":{"200":{"description":"Updated membership","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamMemberResponse"}}}},"403":{"description":"Insufficient permissions"},"404":{"description":"Member not found"}},"security":[{"bearer_auth":[]}]}},"/teams/{team_id}/projects":{"get":{"tags":["Teams"],"operationId":"list_team_projects","parameters":[{"name":"team_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Projects this team has access to","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProjectAccessResponse"}}}}},"403":{"description":"Insufficient permissions"},"404":{"description":"Team not found"}},"security":[{"bearer_auth":[]}]}},"/templates":{"get":{"tags":["Templates"],"summary":"List all available templates","description":"Returns a list of all public templates, optionally filtered by tag or featured status.","operationId":"list_project_templates","parameters":[{"name":"tag","in":"query","description":"Filter templates by tag","required":false,"schema":{"type":"string"}},{"name":"featured","in":"query","description":"Only return featured templates","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of templates","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListTemplatesResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/templates/tags":{"get":{"tags":["Templates"],"summary":"List all available template tags","description":"Returns a list of all unique tags used by public templates.","operationId":"list_project_template_tags","responses":{"200":{"description":"List of tags","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListTagsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/templates/{slug}":{"get":{"tags":["Templates"],"summary":"Get a specific template by slug","description":"Returns detailed information about a single template.","operationId":"get_project_template","parameters":[{"name":"slug","in":"path","description":"Template slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Template details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TemplateResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Template not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/user/me":{"get":{"tags":["Authentication"],"operationId":"get_current_user","responses":{"200":{"description":"Successfully retrieved user information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"session_token":[]}]}},"/users":{"get":{"tags":["Users"],"operationId":"list_users","parameters":[{"name":"include_deleted","in":"query","description":"Include deleted users in the response","required":true,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List all users with their roles","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RouteUserWithRoles"}}}}},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Users"],"summary":"Create a new user with roles","operationId":"create_user","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUserRequest"}}},"required":true},"responses":{"201":{"description":"User created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteUserWithRoles"}}}},"400":{"description":"Invalid input"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/me":{"patch":{"tags":["Users"],"summary":"Update current user's information","operationId":"update_self","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSelfRequest"}}},"required":true},"responses":{"200":{"description":"User updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteUserWithRoles"}}}},"400":{"description":"Invalid input"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/me/mfa":{"delete":{"tags":["Users"],"operationId":"disable_mfa","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DisableMfaRequest"}}},"required":true},"responses":{"204":{"description":"MFA disabled"},"400":{"description":"Invalid verification code"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/me/mfa/setup":{"post":{"tags":["Users"],"operationId":"setup_mfa","responses":{"200":{"description":"MFA setup data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MfaSetupResponse"}}}},"401":{"description":"Unauthorized"},"409":{"description":"MFA is already enabled; verify and disable it before re-enrollment"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/me/mfa/verify":{"post":{"tags":["Users"],"operationId":"verify_and_enable_mfa","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyMfaRequest"}}},"required":true},"responses":{"204":{"description":"MFA verified and enabled"},"400":{"description":"Invalid code"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/me/password":{"post":{"tags":["Users"],"operationId":"change_password_self","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangePasswordRequest"}}},"required":true},"responses":{"204":{"description":"Password updated"},"400":{"description":"Validation error (weak password, same as current, MFA missing)"},"401":{"description":"Current password incorrect or MFA code invalid"},"403":{"description":"Account has no password set (SSO only)"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/{user_id}":{"delete":{"tags":["Users"],"summary":"Delete a user","operationId":"delete_user","parameters":[{"name":"user_id","in":"path","description":"User ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"User deleted successfully"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden - Cannot delete yourself or non-admin attempt"},"404":{"description":"User not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Users"],"summary":"Update user information (admin only)","operationId":"update_user","parameters":[{"name":"user_id","in":"path","description":"User ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUserRequest"}}},"required":true},"responses":{"200":{"description":"User updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteUserWithRoles"}}}},"400":{"description":"Invalid input"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden - Non-admin attempt"},"404":{"description":"User not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/{user_id}/restore":{"post":{"tags":["Users"],"operationId":"restore_user","parameters":[{"name":"user_id","in":"path","description":"User ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"User restored successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteUserWithRoles"}}}},"400":{"description":"User is not deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden - Non-admin attempt"},"404":{"description":"User not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/{user_id}/roles":{"post":{"tags":["Users"],"operationId":"assign_role","parameters":[{"name":"user_id","in":"path","description":"User ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssignRoleRequest"}}},"required":true},"responses":{"200":{"description":"Role assigned successfully"},"400":{"description":"Invalid role type"},"401":{"description":"Unauthorized"},"403":{"description":"Admin role required or self-modification forbidden"},"404":{"description":"User or role not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/{user_id}/roles/{role_type}":{"delete":{"tags":["Users"],"operationId":"remove_role","parameters":[{"name":"user_id","in":"path","description":"User ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"role_type","in":"path","description":"Role type to remove","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Role removed successfully"},"400":{"description":"Invalid role type"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden - Cannot modify own roles or non-admin attempt"},"404":{"description":"User or role not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes":{"get":{"tags":["Sandboxes"],"operationId":"list_sandboxes","parameters":[{"name":"page","in":"query","description":"Page (1-indexed)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page (default 20, max 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List sandboxes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListSandboxesResponse"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Sandboxes"],"operationId":"create_sandbox","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSandboxBody"}}},"required":true},"responses":{"201":{"description":"Sandbox created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/rootfs":{"get":{"tags":["Sandboxes"],"summary":"Inspect rootfs storage: the Firecracker digest-keyed cache (with which\nsandboxes reference each entry) and per-VM disks. Empty on Docker-only\nhosts. Admin/read scope — this exposes host storage layout.","operationId":"rootfs_report","responses":{"200":{"description":"Rootfs storage report"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/rootfs/gc":{"post":{"tags":["Sandboxes"],"summary":"Reclaim rootfs cache entries not backing any live sandbox. Idempotent;\nsafe to call any time (live VMs hold their own per-VM disks).","operationId":"rootfs_gc","responses":{"200":{"description":"Reclaimed cache entries"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}":{"get":{"tags":["Sandboxes"],"operationId":"get_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sandbox details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"404":{"description":"Not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/cmd":{"post":{"tags":["Sandboxes"],"summary":"Run a command inside the sandbox (`@vercel/sandbox`-compatible).","description":"`wait=false` (default) returns `{ command: {..., exitCode: null} }`\nimmediately once the background task is spawned.\n\n`wait=true` streams `application/x-ndjson`: the first line is the\nrunning envelope, the second is the finished envelope with `exitCode`.","operationId":"cmd","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CmdBody"}}},"required":true},"responses":{"200":{"description":"Command started (wait=false) or finished (wait=true)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CmdResponse"}}}},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/cmd/{cmd_id}":{"get":{"tags":["Sandboxes"],"operationId":"get_cmd","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"cmd_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Command snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CmdResponse"}}}},"404":{"description":"Sandbox or command not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/cmd/{cmd_id}/logs":{"get":{"tags":["Sandboxes"],"summary":"Stream a command's stdout/stderr as `application/x-ndjson`\n(`@vercel/sandbox`-compatible). Each line is either\n`{stream:\"stdout\"|\"stderr\", data:\"...\"}` or\n`{stream:\"error\", data:{code, message}}`.","operationId":"cmd_logs","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"cmd_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"NDJSON stream of log events"},"404":{"description":"Sandbox or command not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/destroy":{"post":{"tags":["Sandboxes"],"operationId":"destroy_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Sandbox destroyed (alias for `/stop` with an explicit verb)"},"404":{"description":"Not found"},"409":{"description":"Sandbox belongs to an active agent run — stop the run instead"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/domain":{"get":{"tags":["Sandboxes"],"operationId":"domain","parameters":[{"name":"port","in":"query","description":"Port inside the sandbox (1..=65535)","required":true,"schema":{"type":"integer","format":"int32","minimum":0}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Preview URL for the port","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxDomainResponse"}}}},"400":{"description":"Invalid port"},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/events":{"get":{"tags":["Sandboxes"],"summary":"The operations timeline for a sandbox (lifecycle events only — never\nshell/exec activity), newest first.","operationId":"list_events","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Operations timeline","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxEventsResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/exec":{"post":{"tags":["Sandboxes"],"operationId":"exec","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecBody"}}},"required":true},"responses":{"200":{"description":"Command finished (non-zero exit is NOT an error)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecResponse"}}}},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/exec-detached":{"post":{"tags":["Sandboxes"],"operationId":"exec_detached","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecBody"}}},"required":true},"responses":{"202":{"description":"Command accepted; poll /jobs/{job_id}","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecDetachedResponse"}}}},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/extend-timeout":{"post":{"tags":["Sandboxes"],"operationId":"extend_timeout","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExtendTimeoutBody"}}},"required":true},"responses":{"200":{"description":"Timeout extended","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"400":{"description":"Validation error"},"404":{"description":"Not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/fs/mkdir":{"post":{"tags":["Sandboxes"],"operationId":"mkdir","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MkdirBody"}}},"required":true},"responses":{"204":{"description":"Directory created (or already existed)"},"400":{"description":"Validation error"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/fs/read":{"get":{"tags":["Sandboxes"],"operationId":"read_file","parameters":[{"name":"path","in":"query","description":"Absolute file path inside the sandbox","required":true,"schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"File contents (base64)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReadFileResponse"}}}},"400":{"description":"Validation error"},"404":{"description":"Sandbox or file not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/fs/stat":{"get":{"tags":["Sandboxes"],"operationId":"stat_path","parameters":[{"name":"path","in":"query","description":"Absolute path inside the sandbox","required":true,"schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Stat info (exists=false when missing — not an error)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatResponse"}}}},"400":{"description":"Validation error"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/fs/write":{"post":{"tags":["Sandboxes"],"summary":"Write a file into the sandbox. Accepts two body shapes — the SDK\npicks one based on `Content-Type`:","description":"- **`application/json`** (temps-native): `{path, contents_b64, mode}`\n — one file, base64-encoded.\n- **`application/gzip`** (`@vercel/sandbox`): a gzipped tarball of\n one-or-more entries, with the target extract dir carried in the\n `x-cwd` header. The SDK's `writeFile` and `writeFiles` both post\n here; they differ only in how many entries the tarball contains.\n\nWhy merge them on one route: the SDK is hardcoded to\n`POST /fs/write`, so splitting tar uploads onto a separate path would\nforce us to break SDK compat. Instead we dispatch on Content-Type,\npreserve JSON for native callers, and add tar for SDK callers.","operationId":"write_file","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WriteFileBody"}}},"required":true},"responses":{"204":{"description":"File(s) written"},"400":{"description":"Validation error or invalid base64"},"404":{"description":"Sandbox not found"},"415":{"description":"Unsupported Content-Type (expected application/json or application/gzip)"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/fs/write-batch":{"post":{"tags":["Sandboxes"],"summary":"Batch-write multiple files in a single request. Mirrors\n`@vercel/sandbox` `writeFiles()`. Semantics are fail-fast: if any\nfile errors, previously-written entries are left in place and the\nerror describes which file broke.","operationId":"write_files","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WriteFilesBody"}}},"required":true},"responses":{"200":{"description":"All files written","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WriteFilesResponse"}}}},"400":{"description":"Validation error or invalid base64"},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/jobs":{"get":{"tags":["Sandboxes"],"operationId":"list_jobs","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Detached jobs for this sandbox","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListJobsResponse"}}}},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/jobs/{job_id}":{"get":{"tags":["Sandboxes"],"operationId":"job_status","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"job_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Job status snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobStatusResponse"}}}},"404":{"description":"Sandbox or job not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/jobs/{job_id}/kill":{"post":{"tags":["Sandboxes"],"summary":"Terminate a detached job. Aborts the server-side tracking task and\nsends SIGTERM (or SIGKILL if `force=true`) to any matching processes\ninside the sandbox container. Returns 204 on success; 404 if the\nsandbox or job is unknown.","operationId":"kill_job","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"job_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KillJobBody"}}},"required":true},"responses":{"204":{"description":"Job killed"},"404":{"description":"Sandbox or job not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/jobs/{job_id}/logs":{"get":{"tags":["Sandboxes"],"summary":"SSE endpoint streaming each stdout/stderr line from a detached job\nas it's produced. Mirrors the `Command.logs()` async iterator shape\non `@vercel/sandbox` — events carry `{ stream, data }`.","description":"Late subscribers only see events produced after they connect. The\nJobState snapshot (`GET /jobs/{job_id}`) covers the history.\n\nA \"done\" sentinel event fires when the broadcast channel closes\n(the exec task has exited and dropped the sender), signalling\ncallers they can stop reading.","operationId":"job_logs","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"job_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"SSE stream of log events"},"404":{"description":"Sandbox or job not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/pause":{"post":{"tags":["Sandboxes"],"operationId":"pause_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sandbox paused (container stopped, state preserved)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"404":{"description":"Not found"},"409":{"description":"Sandbox is in an incompatible state (e.g. already destroyed)"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/preview-link":{"post":{"tags":["Sandboxes"],"summary":"Mint a shareable link to a sandbox preview.","description":"`GET /domain` returns the bare preview URL, which is useless to anyone who\ndoes not already hold the sandbox's preview password — so sharing a\nprotected preview meant sharing that password, which is the same secret for\nevery recipient and can only be withdrawn by rotating it for all of them.\n\nThis returns the same URL carrying a short-lived, sandbox-scoped grant. The\nrecipient's browser exchanges it for the ordinary preview cookie and lands\non `path`. The grant never reaches the sandbox, so preview application code\ncannot read it and re-share it.\n\nAnyone holding the returned URL can view the preview until it expires;\nthere is no per-link revocation short of rotating the preview password.","operationId":"sandbox_create_preview_link","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreviewShareLinkBody"}}},"required":true},"responses":{"200":{"description":"Shareable preview link","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreviewShareLinkResponse"}}}},"400":{"description":"Invalid port"},"404":{"description":"Sandbox not found"},"409":{"description":"Sandbox has no preview password"},"500":{"description":"Preview grant minting failed"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/preview-password":{"put":{"tags":["Sandboxes"],"operationId":"set_preview_password","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetPreviewPasswordBody"}}},"required":true},"responses":{"200":{"description":"Preview password set or rotated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetPreviewPasswordResponse"}}}},"400":{"description":"Password too short or too long"},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Sandboxes"],"operationId":"clear_preview_password","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Preview password removed (sandbox is now URL-only protected)"},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/resize":{"post":{"tags":["Sandboxes"],"summary":"Grow a Firecracker sandbox's root disk. Offline resize — the VM reboots\n(filesystem/data persist) rather than resizing fully live.","operationId":"resize_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResizeSandboxBody"}}},"required":true},"responses":{"200":{"description":"Resized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"400":{"description":"Invalid size or unsupported backend"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/restart":{"post":{"tags":["Sandboxes"],"operationId":"restart_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sandbox container restarted in place","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"404":{"description":"Not found"},"409":{"description":"Sandbox is stopped (use /resume) or already destroyed"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/resume":{"post":{"tags":["Sandboxes"],"operationId":"resume_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sandbox resumed; expires_at refreshed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"404":{"description":"Not found"},"409":{"description":"Sandbox is not in a resumable state"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/source":{"post":{"tags":["Sandboxes"],"operationId":"source_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceBody"}}},"required":true},"responses":{"200":{"description":"Source content seeded into the sandbox work dir","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"400":{"description":"Validation error (embedded creds, conflicting fields, etc.)"},"404":{"description":"Sandbox not found"},"409":{"description":"Sandbox is not running"},"500":{"description":"Source seed failed inside sandbox"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/stop":{"post":{"tags":["Sandboxes"],"operationId":"stop_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Sandbox stopped and destroyed"},"404":{"description":"Not found"},"409":{"description":"Sandbox belongs to an active agent run — stop the run instead"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/{cmd_id}/kill":{"post":{"tags":["Sandboxes"],"summary":"Kill a running command (`@vercel/sandbox`-compatible). The SDK\ncalls `POST /v1/sandboxes/{id}/{cmdId}/kill` — note the path has the\ncommand ID directly under the sandbox, NOT under `/jobs/` or `/cmd/`.","operationId":"cmd_kill","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"cmd_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CmdKillBody"}}}},"responses":{"200":{"description":"Command killed; returns final snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CmdResponse"}}}},"404":{"description":"Sandbox or command not found"}},"security":[{"bearer_auth":[]}]}},"/visitors/{visitor_id}/session-replays":{"get":{"tags":["Analytics"],"summary":"Get session replays for a visitor","operationId":"get_visitor_sessions","parameters":[{"name":"visitor_id","in":"path","description":"Visitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-based)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Items per page","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Session replays retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetVisitorSessionsResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/visitors/{visitor_id}/session-replays/{session_id}":{"get":{"tags":["Analytics"],"summary":"Get session replay data with visitor info (without events)","operationId":"get_session_replay","parameters":[{"name":"visitor_id","in":"path","description":"Visitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Session replay retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetSessionReplayResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Session not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Analytics"],"summary":"Delete a session replay","operationId":"delete_session_replay","parameters":[{"name":"visitor_id","in":"path","description":"Visitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Session replay deleted successfully"},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Session not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/visitors/{visitor_id}/session-replays/{session_id}/duration":{"put":{"tags":["Analytics"],"summary":"Update session duration","operationId":"update_session_duration","parameters":[{"name":"visitor_id","in":"path","description":"Visitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSessionDurationRequest"}}},"required":true},"responses":{"200":{"description":"Session duration updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSessionDurationResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Session not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/visitors/{visitor_id}/session-replays/{session_id}/events":{"get":{"tags":["Analytics"],"summary":"Get session replay events (with session and visitor metadata)","operationId":"get_session_replay_events","parameters":[{"name":"visitor_id","in":"path","description":"Visitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Session replay with events retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionReplayWithEventsDto"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Session not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Analytics"],"summary":"Add events to an existing session","operationId":"add_events","parameters":[{"name":"visitor_id","in":"path","description":"Visitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddEventsRequest"}}},"required":true},"responses":{"200":{"description":"Events added successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddEventsResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Session not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/vulnerability-scans/{scan_id}":{"get":{"tags":["Vulnerability Scans"],"operationId":"get_scan","parameters":[{"name":"scan_id","in":"path","description":"Scan ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Scan details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScanResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Scan not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Vulnerability Scans"],"operationId":"delete_scan","parameters":[{"name":"scan_id","in":"path","description":"Scan ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Scan deleted"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Scan not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/vulnerability-scans/{scan_id}/vulnerabilities":{"get":{"tags":["Vulnerability Scans"],"operationId":"get_scan_vulnerabilities","parameters":[{"name":"scan_id","in":"path","description":"Scan ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"severity","in":"query","description":"Filter by severity (CRITICAL, HIGH, MEDIUM, LOW)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of vulnerabilities","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/VulnerabilityResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Scan not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/webhook-event-types":{"get":{"tags":["Webhooks"],"summary":"List available event types","operationId":"list_event_types","responses":{"200":{"description":"List of available event types","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EventTypeResponse"}}}}}}}},"/weekly-digest/trigger":{"post":{"tags":["Notification Preferences"],"summary":"Trigger weekly digest generation manually","operationId":"trigger_weekly_digest","responses":{"200":{"description":"Weekly digest triggered successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerDigestResponse"}}}},"500":{"description":"Failed to generate digest"}},"security":[{"bearer_auth":[]}]}},"/x/plugins":{"get":{"tags":["External Plugins"],"summary":"List all running external plugins and their manifests.","description":"Requires only a valid session/token (no specific permission) since the\nmanifest drives sidebar navigation rendering for every authenticated\nuser, not just admins.","operationId":"list_external_plugins","responses":{"200":{"description":"List of all running external plugins","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PluginManifest"}}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/x/plugins/reload":{"post":{"tags":["External Plugins"],"summary":"Reload all external plugins.","description":"Stops all running plugin processes, re-scans the plugins directory,\nstarts any discovered binaries, and hot-swaps the proxy router so new\nand removed plugins take effect immediately without a server restart.\n\nRequires `SystemAdmin` permission.","operationId":"reload_plugins","responses":{"200":{"description":"Plugins reloaded successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReloadResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/{project_id}/envelope/":{"post":{"tags":["sentry-ingestor"],"summary":"Ingest a Sentry envelope (binary payload)","operationId":"ingest_sentry_envelope","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"Sentry envelope as binary data","content":{"application/octet-stream":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"Envelope ingested"},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"413":{"description":"Request body too large (exceeds 2 MiB)"}}}},"/{project_id}/store/":{"post":{"tags":["sentry-ingestor"],"summary":"Ingest a Sentry event (JSON payload)","operationId":"ingest_sentry_event","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryEventRequest"}}},"required":true},"responses":{"200":{"description":"Event ingested","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryEventResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"413":{"description":"Request body too large (exceeds 2 MiB)"}}}},"audit/logs":{"get":{"tags":["Audit Logs"],"summary":"List audit logs with optional filtering","operationId":"list_audit_logs","parameters":[{"name":"operation_type","in":"query","description":"Filter logs by operation type (omit for all)","required":false,"schema":{"type":"string"},"example":"user.login"},{"name":"user_id","in":"query","description":"Filter logs by user ID (omit for all users)","required":false,"schema":{"type":"integer","format":"int32"},"example":1},{"name":"from","in":"query","description":"Start timestamp (milliseconds since epoch)","required":false,"schema":{"type":"string","format":"date-time"},"example":1},{"name":"to","in":"query","description":"End timestamp (milliseconds since epoch)","required":false,"schema":{"type":"string","format":"date-time"},"example":1},{"name":"limit","in":"query","description":"Maximum number of logs to return","required":false,"schema":{"type":"integer","format":"int32"},"example":100},{"name":"offset","in":"query","description":"Number of logs to skip","required":false,"schema":{"type":"integer","format":"int32"},"example":0}],"responses":{"200":{"description":"List of audit logs","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AuditLogResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"api_key":[]}]}},"audit/logs/{id}":{"get":{"tags":["Audit Logs"],"summary":"Get a specific audit log entry by ID","operationId":"get_audit_log","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Audit log details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuditLogResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Audit log not found"},"500":{"description":"Internal server error"}},"security":[{"api_key":[]}]}}},"components":{"schemas":{"AcmeOrderResponse":{"type":"object","required":["id","order_url","domain_id","email","status","identifiers","created_at","updated_at"],"properties":{"authorizations":{},"certificate_url":{"type":["string","null"]},"challenge_validation":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ChallengeValidationStatus","description":"Live challenge validation status fetched from Let's Encrypt"}]},"created_at":{"type":"integer","format":"int64"},"domain_id":{"type":"integer","format":"int32"},"email":{"type":"string"},"error":{"type":["string","null"]},"error_type":{"type":["string","null"]},"expires_at":{"type":["integer","null"],"format":"int64"},"finalize_url":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"identifiers":{},"order_url":{"type":"string"},"status":{"type":"string"},"updated_at":{"type":"integer","format":"int64"}}},"ActivateProviderResponse":{"type":"object","required":["default_provider"],"properties":{"default_provider":{"type":"string"}}},"ActiveVisitor":{"type":"object","required":["session_id","session_start","last_activity","page_count","event_count","duration_seconds","is_active"],"properties":{"current_page":{"type":["string","null"]},"duration_seconds":{"type":"integer","format":"int64"},"event_count":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"last_activity":{"type":"string"},"page_count":{"type":"integer","format":"int32"},"session_id":{"type":"string"},"session_start":{"type":"string"},"visitor_id":{"type":["string","null"]}}},"ActiveVisitorsQuery":{"type":"object","properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"}}},"ActiveVisitorsResponse":{"type":"object","required":["active_visitors","window_minutes"],"properties":{"active_visitors":{"type":"integer","format":"int64"},"window_minutes":{"type":"integer","format":"int32"}}},"ActivityDay":{"type":"object","description":"Daily activity count for a single day","required":["date","count","level"],"properties":{"count":{"type":"integer","format":"int64","description":"Number of deployments on this day"},"date":{"type":"string","description":"Date in YYYY-MM-DD format","example":"2024-06-15"},"level":{"type":"integer","format":"int32","description":"Intensity level (0-4) for visualization\n0: No activity, 1: Low (1-2), 2: Medium (3-5), 3: High (6-10), 4: Very High (11+)","example":2}}},"ActivityEvent":{"type":"object","description":"A single activity event for the real-time activity feed","required":["id","timestamp","event_type","page_path","is_crawler"],"properties":{"browser":{"type":["string","null"],"description":"Browser"},"city":{"type":["string","null"],"description":"Visitor's city (from ip_geolocations)"},"country":{"type":["string","null"],"description":"Visitor's country (from ip_geolocations)"},"country_code":{"type":["string","null"],"description":"Visitor's country code (from ip_geolocations)"},"device_type":{"type":["string","null"],"description":"Device type"},"event_name":{"type":["string","null"],"description":"Event name (for custom events)"},"event_type":{"type":"string","description":"Event type: \"page_view\", \"custom\", etc."},"id":{"type":"integer","format":"int64","description":"Event ID"},"is_crawler":{"type":"boolean","description":"Whether this event was from a crawler"},"latitude":{"type":["number","null"],"format":"double","description":"Latitude"},"longitude":{"type":["number","null"],"format":"double","description":"Longitude"},"operating_system":{"type":["string","null"],"description":"Operating system"},"page_path":{"type":"string","description":"Page path where the event happened"},"page_title":{"type":["string","null"],"description":"Page title"},"referrer":{"type":["string","null"],"description":"Referrer"},"timestamp":{"type":"string","format":"date-time","description":"When the event occurred"},"visitor_id":{"type":["integer","null"],"format":"int32","description":"Visitor numeric ID"}}},"ActivityGraphQuery":{"type":"object","description":"Query parameters for activity graph endpoint","properties":{"days":{"type":"integer","format":"int32","description":"Number of days to include (default: 365 for last year)"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Optional environment ID to filter activity"},"project_id":{"type":["integer","null"],"format":"int32","description":"Optional project ID to filter activity"}}},"ActivityGraphResponse":{"type":"object","description":"Response for activity graph showing daily deployment activity","required":["days","total_count","start_date","end_date"],"properties":{"days":{"type":"array","items":{"$ref":"#/components/schemas/ActivityDay"},"description":"Array of daily activity counts"},"end_date":{"type":"string","description":"Date range end (YYYY-MM-DD)","example":"2024-12-31"},"start_date":{"type":"string","description":"Date range start (YYYY-MM-DD)","example":"2024-01-01"},"total_count":{"type":"integer","format":"int64","description":"Total count of activities across all days"}}},"AddClusterMemberRequest":{"type":"object","description":"Request body for adding a single member to a running cluster.","required":["role"],"properties":{"node_id":{"type":["integer","null"],"format":"int32","description":"Target worker node ID. Omit or null to run on the control plane."},"role":{"type":"string","description":"Member role. Currently only `replica` is accepted at runtime —\nmonitor is a singleton, primary is elected by pg_auto_failover.","example":"replica"}}},"AddContextRequest":{"type":"object","required":["message"],"properties":{"message":{"type":"string"}}},"AddEnvironmentDomainRequest":{"type":"object","required":["domain","is_primary"],"properties":{"domain":{"type":"string"},"is_primary":{"type":"boolean"}}},"AddEventsRequest":{"type":"object","required":["events"],"properties":{"events":{"type":"string"}}},"AddEventsResponse":{"type":"object","required":["event_count","message"],"properties":{"event_count":{"type":"integer","minimum":0},"message":{"type":"string"}}},"AddManagedDomainApiRequest":{"type":"object","description":"Request to add a managed domain","required":["domain"],"properties":{"auto_manage":{"type":"boolean"},"domain":{"type":"string","example":"example.com"},"generated_hostname_mode":{"type":["string","null"],"description":"Generated hostname layout: `\"standard\"` (default) or `\"flat\"`."},"sync_generated_records":{"type":"boolean","description":"Opt in to reconciling generated hostnames into this domain's DNS zone."}}},"AdminGateResponse":{"type":"object","required":["allowed_ips","allowed_hosts","trust_forwarded_for","source","editable"],"properties":{"allowed_hosts":{"type":"array","items":{"type":"string"},"description":"`Host` header values allowed. Empty = any host."},"allowed_ips":{"type":"array","items":{"type":"string"},"description":"IPs / CIDRs allowed to reach the admin listener. Empty = any source."},"editable":{"type":"boolean","description":"True when the config is writable through this API. False when env\nvars are dictating the active config."},"source":{"$ref":"#/components/schemas/AdminGateSource","description":"Where the active config came from."},"trust_forwarded_for":{"type":"boolean","description":"When true, the gate trusts `X-Forwarded-For` from loopback peers."}}},"AdminGateSource":{"type":"string","description":"Where the active gate configuration came from. Env-supplied configs are\nfrozen at the process level — the UI shows them read-only and refuses to\npersist DB writes. DB-supplied configs are editable at runtime.","enum":["default","db","env"]},"AgentConfigResponse":{"type":"object","description":"Response DTO for a single agent — masks the encrypted API key.","required":["id","project_id","slug","name","source","enabled","trigger_config","ai_provider","api_key_set","max_turns","timeout_seconds","daily_budget_cents","cooldown_minutes","branch_prefix","deliverable","created_at","updated_at"],"properties":{"ai_model":{"type":["string","null"],"description":"Preferred model for the CLI (e.g. \"sonnet\", \"gpt-5-codex\"). `None` means default."},"ai_provider":{"type":"string"},"ai_provider_key_id":{"type":["integer","null"],"format":"int32"},"api_key_set":{"type":"boolean","description":"`true` if an API key is set; `false` otherwise."},"branch_prefix":{"type":"string"},"config_repo_branch":{"type":["string","null"],"description":"Branch of the config repo to use."},"config_repo_url":{"type":["string","null"],"description":"Private config repo containing .claude/ directory (skills, MCP, plugins)."},"cooldown_minutes":{"type":"integer","format":"int32"},"created_at":{"type":"string"},"daily_budget_cents":{"type":"integer","format":"int32"},"deliverable":{"type":"string"},"description":{"type":["string","null"]},"enabled":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"max_turns":{"type":"integer","format":"int32"},"mcp_servers_config":{"description":"MCP servers config (Claude Code settings.json mcpServers format).\nCredential-bearing legacy inline values are write-only and appear as\n`***`. Omit this field on update to preserve their stored values."},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"prompt":{"type":["string","null"]},"sandbox_enabled":{"type":["boolean","null"],"description":"None = use global sandbox setting, true = force on, false = force off"},"skills_config":{"description":"Skills config as JSON array."},"slug":{"type":"string"},"source":{"type":"string"},"timeout_seconds":{"type":"integer","format":"int32"},"tools_config":{"description":"Tools config as JSON array. Legacy custom-tool webhook URLs and headers\nare write-only and appear as `***`. Omit this field on update to\npreserve their stored values."},"trigger_config":{},"updated_at":{"type":"string"},"webhook_token":{"type":["string","null"],"description":"Secret token for the `X-Webhook-Token` header. Shown once when created,\nmasked with `***` prefix in subsequent reads."},"webhook_url":{"type":["string","null"],"description":"Public webhook URL for triggering this agent externally.\nOnly set when `on: { webhook: true }` is configured.\nUsage: `POST {webhook_url}` with header `X-Webhook-Token: {webhook_token}`"}}},"AgentRunLogResponse":{"type":"object","required":["id","run_id","level","message","created_at"],"properties":{"created_at":{"type":"string"},"id":{"type":"integer","format":"int64"},"level":{"type":"string"},"message":{"type":"string"},"metadata":{},"run_id":{"type":"integer","format":"int32"}}},"AgentRunResponse":{"type":"object","required":["id","project_id","source","trigger_type","status","tokens_input","tokens_output","estimated_cost_cents","files_changed","created_at","sandbox_enabled"],"properties":{"agent_name":{"type":["string","null"],"description":"Name of the agent that created this run, if available."},"agent_slug":{"type":["string","null"],"description":"Slug of the agent that created this run, if available."},"ai_model":{"type":["string","null"]},"ai_output":{"type":["string","null"]},"ai_provider":{"type":["string","null"],"description":"AI provider slug that executed this run (e.g. claude_cli, codex_cli, opencode)."},"ai_reasoning":{"type":["string","null"]},"ai_session_id":{"type":["string","null"],"description":"Claude CLI session UUID for resuming conversations via `--resume`."},"analysis":{"type":["string","null"],"description":"Report / analysis text produced by the agent (used for report/notification deliverables)."},"branch_name":{"type":["string","null"]},"commit_sha":{"type":["string","null"]},"completed_at":{"type":["string","null"]},"config_id":{"type":["integer","null"],"format":"int32","description":"Optional. NULL for ephemeral CLI runs (`source = \"cli_ephemeral\"`) and\nhistorical autofixer runs that pre-date the agent_id column."},"created_at":{"type":"string"},"ephemeral_yaml":{"type":["string","null"],"description":"Full WorkflowYamlConfig as YAML text. Populated only when\n`source = \"cli_ephemeral\"`. Used by the web UI to show a \"View YAML\"\nmodal so the user can see exactly what the executor ran."},"error_message":{"type":["string","null"]},"estimated_cost_cents":{"type":"integer","format":"int32"},"files_changed":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"phase":{"type":["string","null"],"description":"Autofixer phase: \"analyzing\", \"analyzed\", \"fixing\", \"fix_ready\", \"no_fix\",\n\"pr_created\", or NULL for non-autofixer runs."},"pr_number":{"type":["integer","null"],"format":"int32"},"pr_url":{"type":["string","null"]},"preview_url":{"type":["string","null"]},"project_id":{"type":"integer","format":"int32"},"prompt_text":{"type":["string","null"],"description":"Final assembled prompt the AI CLI actually saw (trigger context block +\nYAML prompt, with error-group fields interpolated). Captured once per\nrun. `None` for pre-migration rows."},"run_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AutofixRunConfig","description":"Per-run AI options the user chose when starting an autofixer run\n(provider, model, max_turns, branch). NULL for generic agent runs\nand historical rows. Used to prefill the retry dialog."}]},"sandbox_enabled":{"type":"boolean","description":"Legacy field — all runs now execute in a sandbox. Kept for\nbackwards-compatible JSON shape; always `true`."},"source":{"type":"string","description":"`committed` (the run's config lives in `project_agents`) or\n`cli_ephemeral` (the config was uploaded via the CLI for a one-off\ndry run; see `ephemeral_yaml`)."},"started_at":{"type":["string","null"]},"status":{"type":"string"},"tokens_input":{"type":"integer","format":"int32"},"tokens_output":{"type":"integer","format":"int32"},"trigger_source_id":{"type":["integer","null"],"format":"int32"},"trigger_source_type":{"type":["string","null"]},"trigger_type":{"type":"string"},"user_context":{"type":["string","null"],"description":"User-provided context for this run (e.g. webhook payload, manual instructions)."}}},"AgentRunWithLogsResponse":{"type":"object","required":["run","logs"],"properties":{"logs":{"type":"array","items":{"$ref":"#/components/schemas/AgentRunLogResponse"}},"run":{"$ref":"#/components/schemas/AgentRunResponse"}}},"AgentSandboxSettings":{"type":"object","description":"Global agent sandbox settings. Controls whether agent runs are isolated\ninside Docker containers by default. Individual agents can override this.","properties":{"api_key_encrypted":{"type":["string","null"],"description":"DEPRECATED: use `providers[default_provider].credentials_encrypted` instead.","default":null},"auth_type":{"type":"string","description":"DEPRECATED: use `providers[default_provider].auth_type` instead.","default":"subscription"},"cpu_limit":{"type":"number","format":"double","description":"CPU limit in cores for sandbox containers","default":4.0,"example":4.0},"custom_image":{"type":"string","description":"Custom Docker image (only used when runtime is \"custom\").\nMust have git and claude CLI installed.","default":"","example":""},"default_provider":{"type":"string","description":"Default AI provider for agents: \"claude_cli\", \"opencode\", or \"codex_cli\".\nWorkspaces always use this provider — no per-session override.","default":"claude_cli","example":"claude_cli"},"enabled":{"type":"boolean","description":"Sandbox is always enabled — the executor refuses to run any agent\noutside a sandboxed container. Field is retained so existing settings\nrows still deserialize, but it is ignored at runtime.","default":true},"memory_limit_mb":{"type":"integer","format":"int64","description":"Memory limit in MB for sandbox containers","default":8192,"example":8192,"minimum":0},"network_mode":{"type":"string","description":"Network access level: \"full\" (unrestricted), \"restricted\" (Temps network only), \"none\" (no network)","default":"full","example":"full"},"providers":{"type":"object","description":"Per-provider auth + config. Keyed by provider id (e.g. `claude_cli`,\n`codex_cli`, `opencode`). Adding a new provider only requires a new\ncatalog entry on the Rust side — the JSON column stays migration-free.","default":{},"additionalProperties":{"$ref":"#/components/schemas/ProviderConfig"},"propertyNames":{"type":"string"}},"runtime":{"type":"string","description":"Runtime preset: \"node\", \"bun\", \"python\", \"rust\", \"go\", \"full\", or \"custom\"","default":"node","example":"node"},"sandbox_backend":{"type":["string","null"],"description":"Default isolation backend for sandboxes: \"docker\" (default) or\n\"firecracker\" (ADR-029; requires `temps firecracker setup`). Only\nconsulted when the Firecracker backend probes available — otherwise\nDocker is used regardless.","default":null,"example":"docker"}}},"AgentSandboxSettingsMasked":{"type":"object","description":"Agent sandbox settings with masked per-provider credentials.\nEach provider entry reports only whether a credential is saved, not\nthe encrypted blob itself. Non-sensitive fields (auth_type, default_model,\nextra) are passed through so the UI can render provider-specific state.","required":["default_provider","providers","api_key_saved","auth_type","enabled","runtime","custom_image","cpu_limit","memory_limit_mb","network_mode","sandbox_backend"],"properties":{"api_key_saved":{"type":"boolean"},"auth_type":{"type":"string"},"cpu_limit":{"type":"number","format":"double"},"custom_image":{"type":"string"},"default_provider":{"type":"string"},"enabled":{"type":"boolean"},"memory_limit_mb":{"type":"integer","format":"int64","minimum":0},"network_mode":{"type":"string"},"providers":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/ProviderConfigMasked"},"propertyNames":{"type":"string"}},"runtime":{"type":"string"},"sandbox_backend":{"type":"string"}}},"AggregatedBucketItem":{"type":"object","required":["timestamp","count"],"properties":{"count":{"type":"integer","format":"int64"},"timestamp":{"type":"string"}}},"AggregatedBucketsQuery":{"type":"object","description":"Query parameters for aggregated metrics by time bucket","required":["start_date","end_date"],"properties":{"aggregation_level":{"$ref":"#/components/schemas/AggregationLevel","description":"Aggregation level: events, sessions, or visitors"},"bucket_size":{"type":"string","description":"Time bucket size: \"1 hour\", \"1 day\", \"1 week\", etc. (default: \"1 hour\")"},"deployment_id":{"type":["integer","null"],"format":"int32","description":"Optional deployment filter"},"end_date":{"type":"string","format":"date-time","description":"End date for the query range"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Optional environment filter"},"start_date":{"type":"string","format":"date-time","description":"Start date for the query range"}}},"AggregatedBucketsResponse":{"type":"object","required":["bucket_size","aggregation_level","items","total"],"properties":{"aggregation_level":{"type":"string"},"bucket_size":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/AggregatedBucketItem"}},"total":{"type":"integer","format":"int64"}}},"AggregationLevel":{"type":"string","enum":["events","sessions","visitors"]},"AggregationTemporality":{"type":"string","description":"The aggregation temporality of a Sum/Histogram/ExponentialHistogram metric.\n\nMirrors OTel's `AggregationTemporality` proto enum: whether reported values\nare cumulative since the start of the series (Cumulative) or only the delta\nsince the previous report (Delta).","enum":["unspecified","delta","cumulative"]},"AiAgentBreakdownResponse":{"type":"object","description":"Response wrapping the AI agent breakdown rows.","required":["items","start_time","end_time"],"properties":{"end_time":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/AiAgentBreakdownRow"}},"start_time":{"type":"string"}}},"AiAgentBreakdownRow":{"type":"object","description":"One row in the AI-agent analytics breakdown. `agent` is the canonical\ncrawler name (e.g. `GPTBot`, `Claude-User`), `provider` is the vendor used\nfor grouping + logos. The UI mirrors the browsers card and ranks by\n`request_count`.","required":["provider","agent","purpose","request_count","unique_ips"],"properties":{"agent":{"type":"string"},"last_seen":{"type":["string","null"],"description":"Last-seen timestamp in RFC3339 format, or `None` if no rows matched.","example":"2026-05-29T12:00:00Z"},"provider":{"type":"string"},"purpose":{"type":"string"},"request_count":{"type":"integer","format":"int64"},"unique_ips":{"type":"integer","format":"int64"}}},"AiAgentDescriptor":{"type":"object","description":"Static descriptor for one entry in the known-AI-agents taxonomy.","required":["provider","agent","purpose"],"properties":{"agent":{"type":"string"},"provider":{"type":"string"},"purpose":{"type":"string"}}},"AiAgentPageRow":{"type":"object","description":"One row in the pages-by-agent breakdown. Returned by\n[`ProxyLogService::get_ai_agent_pages`] for a single named agent.\n`unique_ips` counts distinct client IPs that hit this path via that agent\n(same definition as the per-agent unique-IPs in [`AiAgentBreakdownRow`]).","required":["path","request_count","unique_ips"],"properties":{"last_seen":{"type":["string","null"],"description":"Last-seen timestamp in RFC3339 format, or `None` if no rows matched.","example":"2026-05-29T12:00:00Z"},"path":{"type":"string"},"request_count":{"type":"integer","format":"int64"},"unique_ips":{"type":"integer","format":"int64"}}},"AiAgentPagesResponse":{"type":"object","description":"Response wrapping the per-agent pages breakdown rows.","required":["agent","items","start_time","end_time"],"properties":{"agent":{"type":"string","description":"The agent name this breakdown is scoped to."},"end_time":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/AiAgentPageRow"}},"start_time":{"type":"string"}}},"AiAgentTimelineResponse":{"type":"object","description":"Response wrapping the AI agent timeline rows.","required":["items","start_time","end_time","bucket","group_by"],"properties":{"bucket":{"type":"string","description":"Bucket interval used for the buckets (so the UI can label the x-axis).","example":"1 hour"},"end_time":{"type":"string"},"group_by":{"type":"string","description":"Echoes the grouping dimension actually applied.","example":"provider"},"items":{"type":"array","items":{"$ref":"#/components/schemas/AiAgentTimelineRow"}},"start_time":{"type":"string"}}},"AiAgentTimelineRow":{"type":"object","description":"One point in the AI-agent timeline: the request count for a single\n(`bucket`, `key`) pair, where `key` is a provider or agent name depending on\nthe requested grouping. The UI pivots these into one stacked series per\n`key` across the shared bucket x-axis.","required":["bucket","key","request_count"],"properties":{"bucket":{"type":"string","description":"Bucket start in RFC3339 format.","example":"2026-05-29T12:00:00Z"},"key":{"type":"string","description":"Provider or agent name this count belongs to.","example":"OpenAI"},"request_count":{"type":"integer","format":"int64"}}},"AiChatLimitsSettings":{"type":"object","description":"Bounds on one AI chat turn.\n\nA turn is bounded by TIME rather than by a number of steps. A step count\nsays nothing about cost or about how long someone has been watching a\nspinner, and it cuts short exactly the long, productive turns the chat\nexists for. The user can already see each tool call and press Stop; the\ndeadline is what guarantees an *unattended* turn still ends.\n\nThe right value is a property of the model, which is why it is configurable\nrather than compiled in: a full alert-suggestion turn takes ~10 minutes\nagainst a slow local model and seconds against a hosted one.","properties":{"turn_timeout_secs":{"type":"integer","format":"int32","description":"How long one turn may run before it is stopped and the partial answer\nreturned, in seconds. The user is told the turn was cut short.\n\nChecked between steps, not mid-call: a model round already in flight\nfinishes, so a turn can overrun by up to one round. Against a slow\nself-hosted model that is a minute or two. Aborting mid-stream would cut\nthe answer off in the middle of a sentence and throw away work already\npaid for, which is worse than a late stop.","default":900,"example":900,"maximum":3600,"minimum":30}}},"AiConfigSettings":{"type":"object","description":"Global AI configuration settings. Controls the default config repo\ncontaining `.claude/` directory (skills, MCP servers, plugins) that\ngets overlaid into every agent sandbox.","properties":{"config_repo":{"type":"string","description":"Global config repo URL in \"owner/repo\" format (e.g. \"myorg/claude-config\").\nCloned at agent run time and overlaid into the sandbox's `.claude/` directory.","default":"","example":""},"config_repo_branch":{"type":"string","description":"Branch of the config repo to use.","default":"main","example":"main"}}},"AiPageBreakdownResponse":{"type":"object","description":"Response wrapping the AI page breakdown rows.","required":["items","start_time","end_time"],"properties":{"end_time":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/AiPageBreakdownRow"}},"start_time":{"type":"string"}}},"AiPageBreakdownRow":{"type":"object","description":"One row in the AI-crawled-pages breakdown. `agent_count` is the number of\n*distinct* AI agents that hit this path, so the UI can show both how heavily\nand how broadly a page is being crawled.","required":["path","request_count","agent_count"],"properties":{"agent_count":{"type":"integer","format":"int64"},"last_seen":{"type":["string","null"],"description":"Last-seen timestamp in RFC3339 format, or `None` if no rows matched.","example":"2026-05-29T12:00:00Z"},"path":{"type":"string"},"request_count":{"type":"integer","format":"int64"}}},"AiStatusBreakdownResponse":{"type":"object","description":"Response wrapping the AI status breakdown rows.","required":["items","start_time","end_time"],"properties":{"end_time":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/AiStatusBreakdownRow"}},"start_time":{"type":"string"}}},"AiStatusBreakdownRow":{"type":"object","description":"One row in the AI-agent HTTP status breakdown: the request count for a\nstatus class (`2xx`/`3xx`/`4xx`/`5xx`/`other`) across crawler traffic.","required":["status_class","request_count"],"properties":{"request_count":{"type":"integer","format":"int64"},"status_class":{"type":"string","description":"Status class label.","example":"2xx"}}},"AlarmListResponse":{"type":"object","description":"Paginated list of alarms.","required":["items","total","page","page_size"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AlarmResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"AlarmResponse":{"type":"object","description":"Full alarm representation returned by list/summary endpoints.","required":["id","project_id","alarm_type","severity","status","title","fired_at","created_at","updated_at"],"properties":{"acknowledged_at":{"type":["string","null"],"description":"ISO-8601 UTC timestamp when the alarm was acknowledged, if any."},"acknowledged_by":{"type":["integer","null"],"format":"int32","description":"User ID who acknowledged the alarm, if any."},"alarm_type":{"type":"string"},"container_id":{"type":["integer","null"],"format":"int32"},"created_at":{"type":"string","description":"ISO-8601 UTC timestamp when the row was created."},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"fired_at":{"type":"string","description":"ISO-8601 UTC timestamp when the alarm fired."},"id":{"type":"integer","format":"int32"},"message":{"type":["string","null"]},"metadata":{"description":"Arbitrary JSON metadata attached by the alarm source."},"project_id":{"type":"integer","format":"int32"},"resolved_at":{"type":["string","null"],"description":"ISO-8601 UTC timestamp when the alarm was resolved, if any."},"service_id":{"type":["integer","null"],"format":"int32"},"severity":{"type":"string"},"status":{"type":"string"},"title":{"type":"string"},"updated_at":{"type":"string","description":"ISO-8601 UTC timestamp when the row was last updated."}}},"AlarmSummaryResponse":{"type":"object","description":"Re-export AlarmSummary for the OpenAPI schema.","required":["total_active","firing","acknowledged","critical","warning","by_type"],"properties":{"acknowledged":{"type":"integer","format":"int32","minimum":0},"by_type":{"type":"object","additionalProperties":{"type":"integer","format":"int32","minimum":0},"propertyNames":{"type":"string"}},"critical":{"type":"integer","format":"int32","minimum":0},"firing":{"type":"integer","format":"int32","minimum":0},"total_active":{"type":"integer","format":"int32","minimum":0},"warning":{"type":"integer","format":"int32","minimum":0}}},"AlertRuleResponse":{"type":"object","required":["id","project_id","name","trigger_type","trigger_config","notification_priority","cooldown_minutes","enabled","created_at","updated_at"],"properties":{"cooldown_minutes":{"type":"integer","format":"int32"},"created_at":{"type":"string"},"enabled":{"type":"boolean"},"environment_filter":{"type":["integer","null"],"format":"int32"},"error_level_filter":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"notification_priority":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"trigger_config":{},"trigger_type":{"type":"string"},"updated_at":{"type":"string"}}},"AllocEntry":{"type":"object","description":"Wire-format allocation. `null` in the JSON when the node hasn't been\nallocated yet — workers should treat that as \"single-host mode, do\nnot bring up the overlay\".","required":["node_id","compute_cidr","bridge_address","underlay_address"],"properties":{"bridge_address":{"type":"string"},"compute_cidr":{"type":"string"},"node_id":{"type":"string","description":"Stable v5 UUID derived from the database node id."},"underlay_address":{"type":"string"}}},"AnalyticsSessionEventsResponse":{"type":"object","required":["session_id","events","total_events"],"properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/SessionEvent"}},"session_id":{"type":"string"},"total_events":{"type":"integer","minimum":0}}},"AnnotatedSpan":{"type":"object","description":"A single span annotated with the project that originally stored it.\nUsed in `UnifiedTrace` to let the UI colour-code spans by project.","required":["project_id","project_name","span"],"properties":{"project_id":{"type":"integer","format":"int32","description":"The project that stored this span (same as `span.project_id`)."},"project_name":{"type":"string","description":"Human-readable project name for waterfall colour-coding and legend."},"span":{"$ref":"#/components/schemas/SpanRecord","description":"Original span data verbatim from storage."}}},"AnomalyAlgorithm":{"type":"string","description":"Anomaly baseline algorithm. Adding one (e.g. a new robust variant) is a\ncode-only enum addition — no migration, since it lives inside the blob.","enum":["robust","basic","agile","ewma"]},"AnomalyParams":{"type":"object","description":"Seasonal anomaly-band detector parameters (stub — not yet evaluated).","properties":{"algorithm":{"$ref":"#/components/schemas/AnomalyAlgorithm","description":"Baseline model. `robust` is the default (seasonal, stable, flags level\nshifts); `ewma`/`agile` adopt level shifts; `basic` is non-seasonal."},"baseline_lookback_days":{"type":["integer","null"],"format":"int32","description":"How far back to build the baseline. `None` = an evaluator default."},"deviations":{"type":"number","format":"double","description":"Band width in robust standard deviations (Datadog's `bounds`)."},"direction":{"$ref":"#/components/schemas/Direction","description":"Which side(s) of the band a deviation must be on to count."},"pct_anomalous":{"type":"number","format":"double","description":"Fraction (0..=1) of points in the window that must be anomalous to fire."},"seasonality":{"$ref":"#/components/schemas/Seasonality","description":"Seasonality model for the baseline."}}},"AnomalyPreviewPointResponse":{"type":"object","required":["bucket","value","lower","upper","breaching"],"properties":{"breaching":{"type":"boolean"},"bucket":{"type":"string","example":"2025-10-12T12:15:47Z"},"lower":{"type":"number","format":"double","description":"Lower edge of the expected band at this point."},"upper":{"type":"number","format":"double","description":"Upper edge of the expected band at this point."},"value":{"type":"number","format":"double"}}},"AnomalyPreviewRequest":{"type":"object","required":["project_id","metric_name","aggregation","window_secs","detection_config"],"properties":{"aggregation":{"type":"string","description":"One of `avg|sum|min|max|count|rate|p50|p90|p95|p99`."},"detection_config":{"$ref":"#/components/schemas/DetectionConfig","description":"The detector to backtest. `static` and `anomaly` are supported — the\nkinds the evaluator actually runs."},"end_time":{"type":["string","null"],"description":"RFC 3339; defaults to now.","example":"2025-10-12T12:15:47Z"},"metric_name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"start_time":{"type":["string","null"],"description":"RFC 3339; defaults to 7 days before `end_time`.","example":"2025-10-12T12:15:47Z"},"window_secs":{"type":"integer","format":"int32"}}},"AnomalyPreviewResponse":{"type":"object","required":["points","breach_count","baseline_samples","sufficient"],"properties":{"baseline_samples":{"type":"integer","format":"int64","description":"Baseline sample count (drives the `sufficient` flag)."},"breach_count":{"type":"integer","format":"int64","description":"How many points in the range would have fired."},"points":{"type":"array","items":{"$ref":"#/components/schemas/AnomalyPreviewPointResponse"}},"sufficient":{"type":"boolean","description":"Whether the baseline had enough history for a trustworthy band."}}},"ApiKeyListResponse":{"type":"object","required":["api_keys","total"],"properties":{"api_keys":{"type":"array","items":{"$ref":"#/components/schemas/ApiKeyResponse"}},"total":{"type":"integer","format":"int64","minimum":0}}},"ApiKeyResponse":{"type":"object","required":["id","name","key_prefix","role_type","is_active","created_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00Z"},"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"key_prefix":{"type":"string"},"last_used_at":{"type":["string","null"],"format":"date-time","example":"2024-01-01T00:00:00Z"},"name":{"type":"string"},"permissions":{"type":["array","null"],"items":{"type":"string"}},"role_type":{"type":"string"}}},"AppSettings":{"type":"object","description":"Application settings stored in the database\nAll fields have sensible defaults for easy onboarding","properties":{"agent_sandbox":{"oneOf":[{"$ref":"#/components/schemas/AgentSandboxSettings"}],"default":{"default_provider":"claude_cli","providers":{},"auth_type":"subscription","api_key_encrypted":null,"enabled":true,"runtime":"node","custom_image":"","cpu_limit":4.0,"memory_limit_mb":8192,"network_mode":"full","sandbox_backend":null}},"ai_chat_limits":{"oneOf":[{"$ref":"#/components/schemas/AiChatLimitsSettings","description":"Limits on a single AI chat turn. Operator-tunable because the right\nvalue depends on the model: a turn against a slow self-hosted model can\nlegitimately take ten minutes, while a hosted one finishes in seconds\nand a shorter ceiling keeps costs predictable."}],"default":{"turn_timeout_secs":900}},"ai_config":{"oneOf":[{"$ref":"#/components/schemas/AiConfigSettings"}],"default":{"config_repo":"","config_repo_branch":"main"}},"build_limits":{"oneOf":[{"$ref":"#/components/schemas/BuildLimitsSettings","description":"Build-time resource limits applied on the control plane to prevent\n`docker build` from saturating host CPU/RAM. Worker nodes are\nintentionally NOT subject to these limits (each worker is dedicated\nhardware that already has its own per-host headroom)."}],"default":{"max_concurrent":2,"cpu_limit_cores":0.0,"memory_limit_mb":0}},"cluster_dns":{"oneOf":[{"$ref":"#/components/schemas/ClusterDnsSettings","description":"Cluster-DNS resolver settings (ADR-024, experimental beta). Off by\ndefault — see `ClusterDnsSettings` for the incident background and\ntrade-offs. Must be explicitly enabled by operators who need\n`*.temps.local` service-to-service resolution inside containers."}],"default":{"enabled":false}},"console_version":{"type":["string","null"],"description":"Binary version tag (e.g. \"v0.1.0\") of the *console* process\n(`temps serve`, role=all or role=console) that last started. Written\non console startup; read by the standalone `temps proxy` to detect\nversion skew during a rolling upgrade (ADR-017 Phase 3). `None` on\ninstalls that never ran a console build carrying this field.\n\nThis is informational state written by the binary itself — NOT an\noperator-tunable setting. It is intentionally absent from\n`AppSettingsResponse` and the PATCH path so an operator cannot\naccidentally overwrite the self-recorded value.","default":null},"container_logs":{"oneOf":[{"$ref":"#/components/schemas/ContainerLogSettings"}],"default":{"max_size":"50m","max_file":3,"service_max_size":"20m","service_max_file":3}},"disk_space_alert":{"oneOf":[{"$ref":"#/components/schemas/DiskSpaceAlertSettings"}],"default":{"enabled":true,"threshold_percent":80,"check_interval_seconds":300,"monitor_path":null}},"dns_provider":{"oneOf":[{"$ref":"#/components/schemas/DnsProviderSettings"}],"default":{"provider":"manual","cloudflare_api_key":null}},"docker_registry":{"oneOf":[{"$ref":"#/components/schemas/DockerRegistrySettings"}],"default":{"enabled":false,"registry_url":null,"username":null,"password":null,"tls_verify":true,"ca_certificate":null}},"edge_target":{"type":["string","null"],"description":"Public edge target that generated DNS records point at when a managed\ndomain opts into automatic record sync. An IPv4/IPv6 address produces an\n`A`/`AAAA` record; anything else is treated as a `CNAME` target. `None`\ndisables DNS record sync regardless of per-domain opt-in.","default":null},"external_url":{"type":["string","null"],"default":null},"insecure_tls":{"type":"boolean","description":"Skip TLS certificate verification on outbound HTTP clients built by the\nserver (deployer, agent, remote service client). Strictly opt-in for\noperators running self-signed control plane / worker certs on a trusted\ninternal network. Worker→control-plane traffic that traverses the public\ninternet must keep this `false` — otherwise a MitM steals the join token.","default":false},"internal_url":{"type":["string","null"],"description":"URL that service containers use to reach the Temps API from *inside*\nthe Docker network (OTLP metrics ingest, agent callbacks, etc.). On\nDocker Desktop this defaults to `http://host.docker.internal:`;\non Linux it requires the `host.docker.internal:host-gateway` host\nmapping (which Temps adds to provisioned containers). Distinct from\n`external_url`, which is the public-facing address.","default":null},"letsencrypt":{"oneOf":[{"$ref":"#/components/schemas/LetsEncryptSettings"}],"default":{"email":null,"environment":"production"}},"monitoring":{"oneOf":[{"$ref":"#/components/schemas/MonitoringSettings","description":"Metrics observability settings. Controls the MetricsStore backend,\nscrape interval, and tiered retention windows."}],"default":{"enabled":false,"store":"timescale_db","scrape_interval_secs":30,"retention_raw_days":7,"retention_hourly_days":90,"retention_daily_years":2,"clickhouse_url":null}},"multi_node":{"oneOf":[{"$ref":"#/components/schemas/MultiNodeSettings"}],"default":{"join_token_hash":null,"private_address":null,"legacy_shared_token_enabled":true,"cluster_ca_cert_pem":null,"cluster_ca_key_encrypted":null,"require_mtls":false,"node_cpu_alert_percent":90.0,"node_memory_alert_percent":90.0,"node_disk_alert_percent":90.0}},"observability_compression":{"oneOf":[{"$ref":"#/components/schemas/ObservabilityCompressionSettings","description":"TimescaleDB compression delays for immutable observability data.\nChanges are applied at runtime by the Settings API."}],"default":{"proxy_logs_after_hours":24,"otel_spans_after_hours":24}},"observability_retention":{"oneOf":[{"$ref":"#/components/schemas/ObservabilityRetentionSettings","description":"Retention windows for raw proxy and OpenTelemetry telemetry.\nTimescaleDB policies are updated at runtime by the Settings API."}],"default":{"proxy_logs_days":30,"otel_spans_days":90,"otel_logs_days":90,"otel_metrics_days":90}},"on_demand_tls":{"oneOf":[{"$ref":"#/components/schemas/OnDemandTlsSettings"}],"default":{"enabled":false,"zone":null,"max_concurrent":3,"hourly_cap":10,"deployment_url_mode":"http"}},"preview_domain":{"type":"string","default":"localho.st"},"preview_gateway":{"oneOf":[{"$ref":"#/components/schemas/PreviewGatewaySettings"}],"default":{"image":"ghcr.io/gotempsh/temps-preview-gateway:latest","host_port":8090,"auto_upgrade":true}},"rate_limiting":{"oneOf":[{"$ref":"#/components/schemas/RateLimitSettings"}],"default":{"enabled":false,"max_requests_per_minute":60,"max_requests_per_hour":1000,"whitelist_ips":[],"blacklist_ips":[]}},"require_mfa_for_admins":{"type":"boolean","description":"When `true`, any user holding the `Admin` role must have MFA enrolled\n(`users.mfa_enabled = true`) to complete a **password** login. Users\nwithout MFA enrolled are rejected with a typed error instructing them\nto enroll before retrying. This only gates the password-login path\n(`AuthService::login`) -- SSO/OIDC logins are handled by a separate\ncode path (`OidcService::resolve_user` + `oidc_handler`) and are\nintentionally unaffected, since federating identity to a\nproperly-hardened IdP is itself an acceptable alternative to local\nTOTP MFA. Modeled as a settings row (not an env var) per CLAUDE.md so\nan operator can flip it at runtime via the Settings API without\nrestarting the binary.","default":false},"screenshots":{"oneOf":[{"$ref":"#/components/schemas/ScreenshotSettings"}],"default":{"enabled":false,"provider":"local","url":""}},"security_headers":{"oneOf":[{"$ref":"#/components/schemas/SecurityHeadersSettings"}],"default":{"enabled":false,"preset":"moderate","content_security_policy":"default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self'; frame-ancestors 'self'","x_frame_options":"SAMEORIGIN","x_content_type_options":"nosniff","x_xss_protection":"1; mode=block","strict_transport_security":"max-age=31536000; includeSubDomains","referrer_policy":"strict-origin-when-cross-origin","permissions_policy":"geolocation=(), microphone=(), camera=()"}},"self_update":{"oneOf":[{"$ref":"#/components/schemas/SelfUpdateSettings","description":"One-click \"Update now\" from the console. Enabled by default; an admin\ncan turn it off here to keep upgrades on the CLI/config-management path.\n\nThis is the *soft* switch — it is stored in the database, so whoever can\nwrite settings can also turn it back on. Operators who need an upgrade\npath that no console session can re-open should start the server with\n`--disable-self-update`, which wins over this field unconditionally."}],"default":{"enabled":true}},"setup_complete":{"type":"boolean","description":"Set to `true` by `temps setup` (all modes) once initial configuration\nhas been applied. The web onboarding wizard reads this from the server\nand skips itself when true, preventing the \"Configure Base Domain\" wall\nfrom appearing on installs that were already configured via the CLI.","default":false}}},"AppSettingsResponse":{"type":"object","description":"Safe response for application settings that masks sensitive fields","required":["preview_domain","screenshots","letsencrypt","dns_provider","security_headers","rate_limiting","docker_registry","disk_space_alert","container_logs","agent_sandbox","ai_config","preview_gateway","multi_node","monitoring","observability_compression","observability_retention","effective_metrics_store","effective_observability_store","insecure_tls","setup_complete","require_mfa_for_admins","cluster_dns","build_limits","ai_chat_limits","self_update"],"properties":{"agent_sandbox":{"$ref":"#/components/schemas/AgentSandboxSettingsMasked"},"ai_chat_limits":{"$ref":"#/components/schemas/AiChatLimitsSettings","description":"Per-turn limits for the AI chat. No sensitive content."},"ai_config":{"$ref":"#/components/schemas/AiConfigSettings"},"build_limits":{"$ref":"#/components/schemas/BuildLimitsSettings","description":"Build-time resource limits (control-plane only). No sensitive content,\npassed through as-is."},"cluster_dns":{"$ref":"#/components/schemas/ClusterDnsSettings","description":"Cluster-DNS resolver settings (ADR-024, experimental beta). No masking\nneeded — `enabled` is a plain bool with no sensitive content. Passed\nthrough as-is so the settings UI can read and toggle the flag."},"container_logs":{"$ref":"#/components/schemas/ContainerLogSettings"},"disk_space_alert":{"$ref":"#/components/schemas/DiskSpaceAlertSettings"},"dns_provider":{"$ref":"#/components/schemas/DnsProviderSettingsMasked"},"docker_registry":{"$ref":"#/components/schemas/DockerRegistrySettingsMasked"},"edge_target":{"type":["string","null"],"description":"Public edge target that synced DNS records point at (IP → A/AAAA, else CNAME)."},"effective_metrics_store":{"$ref":"#/components/schemas/MetricsStoreKind","description":"The storage backend the runtime is **actually** using for metrics,\nafter reconciling the `monitoring.store` toggle with the server's\n`TEMPS_CLICKHOUSE_*` configuration. When `monitoring.store` is\n`click_house` but those env vars are not fully set, the runtime falls\nback to TimescaleDB — in that case this reports `timescale_db` even\nthough `monitoring.store` says `click_house`. The UI shows this as the\neffective backend and warns when it diverges from the configured store."},"effective_observability_store":{"$ref":"#/components/schemas/MetricsStoreKind","description":"Storage backend actually used for proxy logs, OTel spans, and OTel\nmetrics. OTel logs remain TimescaleDB-backed. Unlike resource metrics,\nthese domains switch to ClickHouse whenever the server-level ClickHouse\nconnection is configured; they do not use the monitoring store toggle."},"external_url":{"type":["string","null"]},"insecure_tls":{"type":"boolean"},"internal_url":{"type":["string","null"]},"letsencrypt":{"$ref":"#/components/schemas/LetsEncryptSettings"},"monitored_services_count":{"type":["integer","null"],"format":"int64","description":"Number of enabled, running services the MetricsScraper currently\nincludes. Used for the lightweight storage estimate in the UI.","minimum":0},"monitoring":{"$ref":"#/components/schemas/MonitoringSettingsMasked"},"multi_node":{"$ref":"#/components/schemas/MultiNodeSettingsMasked"},"observability_compression":{"$ref":"#/components/schemas/ObservabilityCompressionSettings","description":"TimescaleDB compression delays for immutable proxy logs and OTel spans."},"observability_retention":{"$ref":"#/components/schemas/ObservabilityRetentionSettings","description":"Retention windows for raw proxy logs and OpenTelemetry data."},"preview_domain":{"type":"string"},"preview_gateway":{"$ref":"#/components/schemas/PreviewGatewaySettingsMasked"},"rate_limiting":{"$ref":"#/components/schemas/RateLimitSettings"},"require_mfa_for_admins":{"type":"boolean","description":"When enabled, Admin-role accounts without MFA enrolled are rejected\nat password login (bherila/temps#32). SSO/OIDC logins are unaffected."},"screenshots":{"$ref":"#/components/schemas/ScreenshotSettings"},"security_headers":{"$ref":"#/components/schemas/SecurityHeadersSettings"},"self_update":{"$ref":"#/components/schemas/SelfUpdateSettings","description":"Whether admins may apply a release from the console. This is the\ndatabase-backed toggle only — a server started with\n`--disable-self-update` refuses regardless of what this says, which\n`GET /settings/update` reports as the authoritative answer."},"setup_complete":{"type":"boolean","description":"Whether `temps setup` has been run at least once. The web onboarding\nwizard checks this field on load and skips itself when true."}}},"ApplyHostnameModeRequest":{"type":"object","description":"Request to apply a hostname mode (recompute + optional DNS sync).","required":["mode"],"properties":{"mode":{"type":"string","description":"Target mode to apply: `\"standard\"` or `\"flat\"`."},"sync_dns":{"type":"boolean","description":"Also reconcile the provider's DNS zone for the affected hostnames."}}},"ArchiveFlagResponse":{"type":"object","required":["key"],"properties":{"archived_at":{"type":["string","null"]},"key":{"type":"string"}}},"ArchiveMode":{"type":"string","enum":["off","on","always","unknown"]},"AssignRoleRequest":{"type":"object","required":["user_id","role_type"],"properties":{"role_type":{"type":"string"},"user_id":{"type":"integer","format":"int32"}}},"AttachScheduleServicesRequest":{"type":"object","description":"Body for `POST /api/backups/schedules/{id}/services` — attach external\nservices to a backup schedule. Idempotent.","required":["service_ids"],"properties":{"service_ids":{"type":"array","items":{"type":"integer","format":"int32"},"description":"External service ids to attach. Duplicates are de-duplicated server-side."}}},"AttachScheduleServicesResponse":{"type":"object","description":"Response for `POST /api/backups/schedules/{id}/services`.","required":["inserted","total_attached"],"properties":{"inserted":{"type":"integer","format":"int64","description":"Number of rows actually inserted (excludes rows skipped by\n`ON CONFLICT DO NOTHING`).","minimum":0},"total_attached":{"type":"integer","description":"Total number of services now attached to the schedule.","minimum":0}}},"AuditLogIpInfo":{"type":"object","description":"IP address information in audit log","required":["ip"],"properties":{"city":{"type":["string","null"],"description":"City name","example":"San Francisco"},"country":{"type":["string","null"],"description":"Country code","example":"US"},"ip":{"type":"string","description":"IP address","example":"192.168.1.1"},"latitude":{"type":["number","null"],"format":"double","description":"Latitude","example":37.7749},"longitude":{"type":["number","null"],"format":"double","description":"Longitude","example":122.4194}}},"AuditLogResponse":{"type":"object","description":"Response type for audit log entries","required":["id","operation_type","audit_date"],"properties":{"audit_date":{"type":"integer","format":"int64","description":"When the action occurred","example":11932193},"data":{"description":"Additional context about the action"},"id":{"type":"integer","format":"int32","description":"Unique identifier for the audit log entry"},"ip_address":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AuditLogIpInfo","description":"IP address details"}]},"operation_type":{"type":"string","description":"The type of action that was performed","example":"USER_LOGIN"},"user":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AuditLogUserInfo","description":"User details who performed the action"}]},"user_id":{"type":["integer","null"],"format":"int32","description":"The user who performed the action (`null` when that account has\nsince been deleted; `data` retains the original actor context)"}}},"AuditLogUserInfo":{"type":"object","description":"User information in audit log","required":["id","name","email"],"properties":{"email":{"type":"string","description":"User's email","example":"john.doe@example.com"},"id":{"type":"integer","format":"int32","description":"User ID"},"name":{"type":"string","description":"User's name","example":"John Doe"}}},"AuthFlavorDto":{"type":"object","description":"One auth flavor surfaced to the UI. Mirrors `AuthFlavor` in the catalog\nbut without the seed-path / env-var fields the frontend doesn't need\n(those are server-side only — exposing them just bloats the response).","required":["id","label","description","format"],"properties":{"description":{"type":"string"},"env_var":{"type":["string","null"],"description":"For `api_key` format: the env var name that will be set inside the\nsandbox. Useful for showing the user \"we'll set OPENAI_API_KEY\" so\nthey know what their key controls."},"format":{"type":"string","description":"`api_key`, `oauth_token`, or `config_file` — drives which input UI\nthe settings page renders (single-line vs. multi-line textarea)."},"id":{"type":"string"},"label":{"type":"string"}}},"AuthResponse":{"type":"object","required":["success","message","mfa_required","mfa_enrollment_required","password_change_required"],"properties":{"message":{"type":"string"},"mfa_enrollment_required":{"type":"boolean"},"mfa_required":{"type":"boolean"},"mfa_setup":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/MfaSetupResponse"}]},"password_change_required":{"type":"boolean"},"success":{"type":"boolean"},"user_id":{"type":["integer","null"],"format":"int32"}}},"AuthStatusResponse":{"type":"object","required":["status"],"properties":{"cli_token":{"type":["string","null"]},"status":{"type":"string"}}},"AuthTokenResponse":{"type":"object","required":["access_token","refresh_token","expires_at"],"properties":{"access_token":{"type":"string"},"expires_at":{"type":"integer","format":"int64"},"refresh_token":{"type":"string"}}},"AutoWatchParams":{"type":"object","description":"Auto-watch (Watchdog-style) detector parameters (stub — not evaluated).","properties":{"direction":{"$ref":"#/components/schemas/Direction","description":"The engine self-tunes the band; the user supplies only the direction."}}},"AutofixRunConfig":{"type":"object","description":"User-chosen per-run options, persisted as JSON in `agent_runs.run_config`.\nEvery field is optional — unset fields fall back to the provider defaults\nin settings, then to built-in defaults.","properties":{"branch":{"type":["string","null"],"description":"Branch to clone instead of the project's main branch.","default":null},"max_turns":{"type":["integer","null"],"format":"int32","description":"Per-run turn cap applied to every phase of this run. Only enforced\nfor CLIs with a turn flag (Claude Code); Codex/OpenCode run to\ncompletion. `None` uses the provider's per-phase defaults.","default":null},"model":{"type":["string","null"],"description":"Model id for the chosen provider. `None` uses the provider's saved\ndefault model, or the CLI's own default.","default":null},"provider":{"type":["string","null"],"description":"AI provider id (\"claude_cli\", \"codex_cli\", \"opencode\"). `None` uses\nthe platform default provider from agent sandbox settings.","default":null}}},"AutofixerRunResponse":{"type":"object","required":["id","project_id","status","tokens_input","tokens_output","files_changed","created_at"],"properties":{"ai_model":{"type":["string","null"]},"ai_output":{"type":["string","null"]},"ai_provider":{"type":["string","null"],"description":"AI provider slug this run executes with (e.g. claude_cli, codex_cli)."},"analysis":{"type":["string","null"]},"branch_name":{"type":["string","null"]},"completed_at":{"type":["string","null"]},"created_at":{"type":"string"},"error_message":{"type":["string","null"]},"files_changed":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"phase":{"type":["string","null"]},"pr_number":{"type":["integer","null"],"format":"int32"},"pr_url":{"type":["string","null"]},"project_id":{"type":"integer","format":"int32"},"run_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AutofixRunConfig","description":"Per-run options the run was started with; used to prefill the\nretry / start-over dialog."}]},"started_at":{"type":["string","null"]},"status":{"type":"string"},"tokens_input":{"type":"integer","format":"int32"},"tokens_output":{"type":"integer","format":"int32"},"trigger_source_id":{"type":["integer","null"],"format":"int32"},"user_context":{"type":["string","null"]}}},"AutofixerRunWithLogsResponse":{"type":"object","required":["run","logs"],"properties":{"logs":{"type":"array","items":{"$ref":"#/components/schemas/AgentRunLogResponse"}},"run":{"$ref":"#/components/schemas/AutofixerRunResponse"}}},"AvailableContainerInfo":{"type":"object","description":"Available Docker container that can be imported as a service","required":["container_id","container_name","image","version","service_type","is_running"],"properties":{"container_id":{"type":"string","description":"Container ID or name","example":"abc123def456"},"container_name":{"type":"string","description":"Container display name","example":"my-postgres"},"exposed_ports":{"type":"array","items":{"type":"integer","format":"int32","minimum":0},"description":"Exposed ports (e.g., [5432] for PostgreSQL, [6379] for Redis)"},"image":{"type":"string","description":"Docker image name (e.g., \"gotempsh/postgres-walg:18-bookworm\")","example":"gotempsh/postgres-walg:18-bookworm"},"is_running":{"type":"boolean","description":"Whether the container is currently running","example":true},"service_type":{"$ref":"#/components/schemas/ServiceTypeRoute","description":"Service type this container represents"},"version":{"type":"string","description":"Extracted version from image","example":"18"}}},"AvailablePermissions":{"type":"object","description":"Response containing all available permissions for frontend validation","required":["permissions","roles"],"properties":{"permissions":{"type":"array","items":{"$ref":"#/components/schemas/PermissionInfo"},"description":"All available permissions in the system"},"roles":{"type":"array","items":{"$ref":"#/components/schemas/RoleInfo"},"description":"All available roles"}}},"BackupAlertListResponse":{"type":"object","description":"Response body for the list-backup-alerts endpoint.","required":["alerts"],"properties":{"alerts":{"type":"array","items":{"$ref":"#/components/schemas/BackupAlertResponse"},"description":"All currently open (unresolved) alerts, newest first."}}},"BackupAlertResponse":{"type":"object","description":"A single open backup alert surfaced in the UI banner.\n\nAlerts are auto-opened by the watcher and auto-resolved when the triggering\ncondition clears. No manual dismiss is required or supported.\n\nThe optional `schedule_s3_source_id` field is included so the UI can\ndeep-link an `overdue_schedule` alert to the S3 source detail page that\nhosts the schedule. `stalled_job` alerts no longer carry a deep-link\ntarget — the alert message text contains the backup id for display.","required":["id","kind","severity","message","opened_at"],"properties":{"id":{"type":"integer","format":"int64","description":"Database id of the alert row."},"kind":{"type":"string","description":"`\"overdue_schedule\"` or `\"stalled_job\"`."},"message":{"type":"string","description":"Human-readable description of the alert condition."},"opened_at":{"type":"string","description":"RFC 3339 timestamp when the alert was opened.","example":"2026-05-15T10:00:00Z"},"schedule_id":{"type":["integer","null"],"format":"int32","description":"FK to `backup_schedules.id`. Set for `overdue_schedule` alerts."},"schedule_name":{"type":["string","null"],"description":"Human-readable name of the linked schedule, if applicable."},"schedule_s3_source_id":{"type":["integer","null"],"format":"int32","description":"FK to `backup_schedules.s3_source_id`. The UI uses this to deep-link\nthe alert to the S3 source detail page that hosts the schedule.\nSet for `overdue_schedule` alerts."},"severity":{"type":"string","description":"`\"warning\"` or `\"critical\"`."}}},"BackupResponse":{"type":"object","description":"Response type for backup","required":["id","name","backup_id","backup_type","state","started_at","s3_source_id","s3_location","metadata","compression_type","created_by","tags"],"properties":{"attempts":{"type":["integer","null"],"format":"int32","description":"How many times this job has been claimed and run. `null` for legacy\nbackups with no `backup_jobs` row."},"backup_id":{"type":"string"},"backup_type":{"type":"string"},"checksum":{"type":["string","null"]},"completed_at":{"type":["integer","null"],"format":"int64"},"compression_type":{"type":"string"},"created_by":{"type":"integer","format":"int32"},"current_step":{"type":["string","null"],"description":"Name of the engine step currently executing (e.g., `\"walg_push\"`).\n`null` when no `backup_jobs` row exists for this backup (legacy rows\npre-dating ADR-014), or when the job has not yet completed its first step."},"error_message":{"type":["string","null"]},"expires_at":{"type":["integer","null"],"format":"int64"},"external_service":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ExternalServiceSummary","description":"External service that owns this backup (Redis, Postgres, etc.).\n`null` for control-plane backups (the Temps server's own database)."}]},"file_count":{"type":["integer","null"],"format":"int32"},"id":{"type":"integer","format":"int32"},"live_size_bytes":{"type":["integer","null"],"format":"int64","description":"Best-effort partial size while a backup is still running, computed\nby listing the S3 prefix. Null when the backup is finished\n(`size_bytes` is authoritative in that case)."},"max_attempts":{"type":["integer","null"],"format":"int32","description":"Maximum attempts before the job is permanently failed. `null` for\nlegacy backups."},"max_runtime_secs":{"type":["integer","null"],"format":"int64","description":"Resolved wall-clock timeout for this backup job (seconds). `null` for\nlegacy backups. Derived from the three-tier resolution order:\ncaller override → schedule override → engine default."},"metadata":{},"name":{"type":"string"},"s3_location":{"type":"string"},"s3_source_id":{"type":"integer","format":"int32"},"schedule_id":{"type":["integer","null"],"format":"int32"},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Final size of the backup once completed. Null while running."},"started_at":{"type":"integer","format":"int64"},"state":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}}}},"BackupScheduleResponse":{"type":"object","description":"Response type for backup schedule","required":["id","name","backup_type","retention_period","s3_source_id","schedule_expression","enabled","created_at","updated_at","tags","target_all_services","include_control_plane"],"properties":{"backup_type":{"type":"string"},"created_at":{"type":"integer","format":"int64"},"description":{"type":["string","null"]},"enabled":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"include_control_plane":{"type":"boolean","description":"When `true`, every run also produces a `control_plane` backup\n(Temps's own Postgres). When `false`, only the external service\nfan-out happens."},"last_run":{"type":["integer","null"],"format":"int64"},"max_runtime_secs":{"type":["integer","null"],"format":"int64","description":"Per-schedule wall-clock timeout override for backup jobs (seconds).\n`null` means the engine-family default is used. See\n`temps_backup_core::timeouts::default_max_runtime_secs`."},"name":{"type":"string"},"next_run":{"type":["integer","null"],"format":"int64"},"retention_period":{"type":"integer","format":"int32"},"s3_source_id":{"type":"integer","format":"int32"},"schedule_expression":{"type":"string","example":"0 0 * * *"},"tags":{"type":"array","items":{"type":"string"}},"target_all_services":{"type":"boolean","description":"When `true`, the schedule auto-includes every external service on\nthe host (and any future ones). When `false`, the schedule only\ntargets services attached via `backup_schedule_services`."},"updated_at":{"type":"integer","format":"int64"}}},"BitbucketAuthInput":{"oneOf":[{"type":"object","description":"Personal / Workspace / Repository Access Token.","required":["token","type"],"properties":{"token":{"type":"string","description":"The Bitbucket access token value."},"type":{"type":"string","enum":["access_token"]}}},{"type":"object","description":"HTTP Basic / App Password authentication.","required":["username","password","type"],"properties":{"password":{"type":"string","description":"App password generated in Bitbucket security settings."},"type":{"type":"string","enum":["app_password"]},"username":{"type":"string","description":"Bitbucket account username."}}}],"description":"Authentication input for a Bitbucket Cloud provider. Use `access_token` for\na Repository or Workspace Access Token (PAT), or `username` + `app_password`\nfor App Password (HTTP Basic) authentication."},"BlobResponse":{"type":"object","description":"Response after uploading a blob","required":["url","pathname","contentType","size","uploadedAt"],"properties":{"contentType":{"type":"string","description":"Content type of the blob","example":"image/png"},"pathname":{"type":"string","description":"Original pathname","example":"images/avatar-abc123.png"},"size":{"type":"integer","format":"int64","description":"Size in bytes","example":12345},"uploadedAt":{"type":"string","format":"date-time","description":"Upload timestamp","example":"2025-01-03T12:00:00Z"},"url":{"type":"string","description":"URL path to access the blob","example":"/api/blob/123/images/avatar-abc123.png"}}},"BlobStatusResponse":{"type":"object","description":"Response for Blob service status","required":["enabled","healthy"],"properties":{"docker_image":{"type":["string","null"],"description":"Docker image being used","example":"ghcr.io/rustfs/rustfs:0.5.0"},"enabled":{"type":"boolean","description":"Whether the Blob service is enabled","example":true},"healthy":{"type":"boolean","description":"Whether the service is healthy","example":true},"version":{"type":["string","null"],"description":"Current version (if running)","example":"0.5.0"}}},"BranchInfo":{"type":"object","required":["name","commit_sha","protected"],"properties":{"commit_sha":{"type":"string"},"name":{"type":"string"},"protected":{"type":"boolean"}}},"BranchListResponse":{"type":"object","required":["branches"],"properties":{"branches":{"type":"array","items":{"$ref":"#/components/schemas/BranchInfo"}}}},"BrowserCount":{"type":"object","required":["browser","count","percentage"],"properties":{"browser":{"type":"string"},"count":{"type":"integer","format":"int64"},"percentage":{"type":"number","format":"double"}}},"BrowsersQuery":{"type":"object","required":["start_date","end_date","project_id"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"BuildConfiguration":{"type":"object","description":"Build configuration (for building images from source)","required":["context","args"],"properties":{"args":{"type":"object","description":"Build arguments","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"context":{"type":"string","description":"Build context (Dockerfile path or buildpack)"},"dockerfile":{"type":["string","null"],"description":"Dockerfile path (relative to context)"},"target":{"type":["string","null"],"description":"Target stage (for multi-stage builds)"}}},"BuildLimitsSettings":{"type":"object","description":"Control-plane build resource limits.\n\nCaps how many builds run concurrently AND how much CPU/memory each build\nis allowed to consume. A single global semaphore in the deployer crate\ngates every `DockerRuntime::build_image` call to `max_concurrent`. When\nthe semaphore is full, additional builds queue and wait — they do not\nfail. Per-build CPU/memory caps are forwarded to Docker via\n`BuildImageOptions { memory, cpuquota, cpuperiod }`.\n\n`cpu_limit_cores = 0.0` or `memory_limit_mb = 0` means \"no explicit cap\"\n— fall back to the legacy 50%-of-host heuristic for backwards\ncompatibility with operators who never visit the settings page.","properties":{"cpu_limit_cores":{"type":"number","format":"float","description":"CPU cores allowed per build (float, e.g. 2.0 = 2 cores, 0.5 = half\na core). 0 means \"use the legacy 50%-of-host default\".","default":0.0,"example":2.0,"minimum":0},"max_concurrent":{"type":"integer","format":"int32","description":"Maximum number of `docker build` operations allowed to run at the\nsame time on the control plane. Additional builds queue. Min 1.","default":2,"example":2,"minimum":1},"memory_limit_mb":{"type":"integer","format":"int32","description":"Memory allowed per build, in megabytes. 0 means \"use the legacy\n50%-of-host default\". Docker enforces this as a hard cap — builds\nthat exceed it OOM-kill.","default":0,"example":2048,"minimum":0}}},"CancelBackupResponse":{"type":"object","description":"Response body for cancel endpoints.","required":["cancelled"],"properties":{"cancelled":{"type":"integer","format":"int64","description":"Number of rows that were actually flipped to `failed`. `0` is a valid\nsuccess and means the backup was already terminal — the call is\nidempotent.","minimum":0}}},"CertStatusResponse":{"type":"object","description":"Current on-demand cert status for a single hostname (ADR-018 §5). Backs\n`GET /domains/by-host/{hostname}/cert-status`.","required":["hostname"],"properties":{"backoff_until":{"type":["integer","null"],"format":"int64","description":"On-demand negative-cache deadline (epoch millis), when in backoff."},"hostname":{"type":"string","description":"SNI hostname."},"last_attempt":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/OnDemandCertAttemptResponse","description":"The most recent on-demand issuance attempt for this hostname, if any."}]},"status":{"type":["string","null"],"description":"Current cert lifecycle status from the `domains` row, when one exists."}}},"ChallengeConfig":{"type":"object","description":"Challenge configuration (future feature)\nFor CAPTCHA, JS challenges, proof-of-work, etc.","required":["challengeType","difficulty"],"properties":{"challengeType":{"type":"string","description":"Challenge type: \"captcha\", \"js_challenge\", \"proof_of_work\""},"difficulty":{"type":"integer","format":"int32","description":"Challenge difficulty level (1-10)","minimum":0},"protectedPaths":{"type":"array","items":{"type":"string"},"description":"Paths that require challenges"}}},"ChallengeError":{"type":"object","required":["type","detail","status"],"properties":{"detail":{"type":"string","description":"Human-readable error description"},"status":{"type":"integer","format":"int32","description":"HTTP status code"},"type":{"type":"string","description":"Error type (e.g., \"urn:ietf:params:acme:error:unauthorized\")"}}},"ChallengeValidationStatus":{"type":"object","required":["type","url","status","token"],"properties":{"error":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ChallengeError","description":"Error details if validation failed"}]},"status":{"type":"string","description":"Challenge status (e.g., \"pending\", \"valid\", \"invalid\")"},"token":{"type":"string","description":"Challenge token"},"type":{"type":"string","description":"Challenge type (e.g., \"dns-01\", \"http-01\")"},"url":{"type":"string","description":"Challenge validation URL"},"validated":{"type":["string","null"],"description":"When the challenge was validated (if successful)"}}},"ChangePasswordRequest":{"type":"object","required":["current_password","new_password"],"properties":{"current_password":{"type":"string","example":"current_password_value"},"mfa_code":{"type":["string","null"],"description":"TOTP code (or recovery code). Required iff the user has MFA enabled.","example":"123456"},"new_password":{"type":"string","example":"new_password_value"},"revoke_other_sessions":{"type":"boolean","description":"When true, every session OTHER than the one making this request is\nrevoked. Defaults to false; the UI surfaces this as a checkbox."}}},"ChangeProjectSourceRequest":{"type":"object","description":"Change a project's source type to a Git-less type (docker_image /\nstatic_files / manual). Switching TO `git` is done via the Git settings\nendpoint (which also supplies the repository + provider connection).","required":["source_type"],"properties":{"source_type":{"$ref":"#/components/schemas/SourceType"}}},"ChatCompletionChoice":{"type":"object","required":["index","message"],"properties":{"finish_reason":{"type":["string","null"]},"index":{"type":"integer","format":"int32"},"message":{"$ref":"#/components/schemas/ChatMessage"}}},"ChatCompletionRequest":{"allOf":[{"type":["object","null"],"description":"Tolerates extra SDK fields (stream_options, logprobs, etc.)","additionalProperties":{},"propertyNames":{"type":"string"}},{"type":"object","required":["model","messages"],"properties":{"frequency_penalty":{"type":["number","null"],"format":"double"},"max_tokens":{"type":["integer","null"],"format":"int64"},"messages":{"type":"array","items":{"$ref":"#/components/schemas/ChatMessage"}},"model":{"type":"string"},"n":{"type":["integer","null"],"format":"int32"},"presence_penalty":{"type":["number","null"],"format":"double"},"response_format":{},"seed":{"type":["integer","null"],"format":"int64"},"stop":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/StopSequence"}]},"stream":{"type":"boolean"},"temperature":{"type":["number","null"],"format":"double"},"tool_choice":{},"tools":{"type":["array","null"],"items":{}},"top_p":{"type":["number","null"],"format":"double"},"user":{"type":["string","null"]}}}],"description":"OpenAI-compatible chat completion request.\nUses `deny_unknown_fields = false` (serde default) so that SDK-specific\nfields like `stream_options`, `logprobs`, `top_logprobs`, `logit_bias`,\n`parallel_tool_calls`, etc. are silently accepted without breaking."},"ChatCompletionResponse":{"type":"object","required":["id","object","created","model","choices"],"properties":{"choices":{"type":"array","items":{"$ref":"#/components/schemas/ChatCompletionChoice"}},"created":{"type":"integer","format":"int64"},"id":{"type":"string"},"model":{"type":"string"},"object":{"type":"string"},"usage":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/UsageInfo"}]}}},"ChatMessage":{"type":"object","required":["role"],"properties":{"content":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/MessageContent"}]},"name":{"type":["string","null"]},"role":{"type":"string"},"tool_call_id":{"type":["string","null"]},"tool_calls":{"type":["array","null"],"items":{}}}},"ChatReadinessResponse":{"type":"object","description":"What still has to be true before an AI chat can run a turn in this project.\n\nThe three gates are independent and fail for different reasons with different\nfixes, so they are reported separately rather than collapsed into one boolean:\nan instance admin configures a provider (instance-wide), while the two toggles\nare per-project. Collapsing them would leave the user with \"AI unavailable\"\nand no idea which of three places to go.","required":["ai_configured","chat_enabled","write_actions_enabled"],"properties":{"ai_configured":{"type":"boolean","description":"An AI provider is configured on this instance. Fixed in\nSettings → AI Providers; instance-wide, not per project."},"chat_enabled":{"type":"boolean","description":"The per-project read-only chat toggle is on (the default)."},"write_actions_enabled":{"type":"boolean","description":"The per-project write-actions opt-in is on. Required for any flow where\nthe assistant *proposes* changes; irrelevant for read-only questions."}}},"ChildBackupEntryResponse":{"type":"object","description":"A single child backup entry in the `GET /backups/{id}/children` response.\n\nEach entry corresponds to one `external_service_backups` row joined with\n`external_services`, providing service metadata without a second request.","required":["id","service_id","service_name","service_type","state","backup_type","started_at","s3_location","compression_type"],"properties":{"backup_type":{"type":"string","description":"Backup variant (e.g. \"full\", \"incremental\")."},"compression_type":{"type":"string","description":"Compression algorithm used (e.g. \"gzip\", \"lz4\")."},"error_message":{"type":["string","null"],"description":"Engine-reported error message when `state = \"failed\"`."},"finished_at":{"type":["string","null"],"description":"When the child backup finished, if known.","example":"2025-01-15T14:35:00.456Z"},"id":{"type":"integer","format":"int32","description":"Row ID from `external_service_backups`."},"s3_location":{"type":"string","description":"Object key or `s3://` URL where the backup data lives."},"service_id":{"type":"integer","format":"int32","description":"FK to `external_services.id`."},"service_name":{"type":"string","description":"Human-readable name of the external service (e.g. \"redis-prod\")."},"service_type":{"type":"string","description":"Service type string (e.g. \"postgres\", \"redis\", \"mongodb\", \"s3\").","example":"postgres"},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Size of the child backup in bytes, if available."},"started_at":{"type":"string","description":"When the child backup started (RFC 3339).","example":"2025-01-15T14:30:00.123Z"},"state":{"type":"string","description":"Current state: \"pending\" | \"running\" | \"completed\" | \"failed\"."}}},"ChildBackupListResponse":{"type":"object","description":"Response body for `GET /backups/{id}/children`.\n\nReturns an empty `children` list (not 404) when the parent backup has no\nchild records (e.g. control-plane backups).","required":["children"],"properties":{"children":{"type":"array","items":{"$ref":"#/components/schemas/ChildBackupEntryResponse"},"description":"Zero or more child backup entries ordered by `external_service_backups.id` ASC."}}},"CleanupExpiredBackupsRequest":{"type":"object","properties":{"expected_backup_ids":{"type":["array","null"],"items":{"type":"string"},"description":"Exact candidates returned by the dry run. Execution fails if the\nretention selection has changed since preview."}}},"CliDeviceApproveRequest":{"type":"object","required":["user_code"],"properties":{"user_code":{"type":"string"}}},"CliDeviceApproveResponse":{"type":"object","required":["user_code","status"],"properties":{"status":{"type":"string"},"user_code":{"type":"string"}}},"CliDeviceLookupResponse":{"type":"object","required":["user_code","status","expires_at"],"properties":{"client_name":{"type":["string","null"]},"expires_at":{"type":"string","format":"date-time"},"requested_ip":{"type":["string","null"]},"status":{"type":"string","description":"`pending` | `approved` | `denied` | `expired`."},"user_code":{"type":"string"}}},"CliDevicePollRequest":{"type":"object","required":["device_code"],"properties":{"device_code":{"type":"string"}}},"CliDevicePollResponse":{"oneOf":[{"type":"object","description":"Still waiting on the user to approve in the browser.","required":["status"],"properties":{"status":{"type":"string","enum":["authorization_pending"]}}},{"type":"object","description":"CLI is polling faster than the server-suggested interval.","required":["status"],"properties":{"status":{"type":"string","enum":["slow_down"]}}},{"type":"object","description":"User denied the request in the browser.","required":["status"],"properties":{"status":{"type":"string","enum":["access_denied"]}}},{"type":"object","description":"The session has expired without approval.","required":["status"],"properties":{"status":{"type":"string","enum":["expired_token"]}}},{"type":"object","description":"The session was approved; this is the only response that carries\nthe API key. The key is returned exactly once and then cleared\nfrom the session row.","required":["user_id","email","role","api_key","key_prefix","status"],"properties":{"api_key":{"type":"string"},"email":{"type":"string"},"expires_at":{"type":["string","null"],"format":"date-time"},"key_prefix":{"type":"string"},"role":{"type":"string"},"status":{"type":"string","enum":["approved"]},"user_id":{"type":"integer","format":"int32"}}}]},"CliDeviceStartRequest":{"type":"object","properties":{"client_name":{"type":["string","null"],"description":"Friendly hostname / client identifier shown in the browser approval\nscreen. Sanitized before display.","example":"dviejo-mac.local"}}},"CliDeviceStartResponse":{"type":"object","required":["device_code","user_code","verification_uri","verification_uri_complete","expires_in","interval"],"properties":{"device_code":{"type":"string","description":"Opaque secret the CLI polls with. Never display to a human."},"expires_in":{"type":"integer","format":"int64","description":"Seconds until the device_code expires."},"interval":{"type":"integer","format":"int64","description":"Suggested polling interval, in seconds."},"user_code":{"type":"string","description":"Short human-readable code the user types into the browser.","example":"ABCD-1234"},"verification_uri":{"type":"string","description":"Base verification URL — the CLI may display this when the\npre-filled URL is too long to be useful.","example":"https://temps.example.com/cli-login"},"verification_uri_complete":{"type":"string","description":"`verification_uri` with `user_code` pre-filled. Open this directly.","example":"https://temps.example.com/cli-login/ABCD-1234"}}},"CliLoginRequest":{"type":"object","required":["username","password"],"properties":{"password":{"type":"string"},"username":{"type":"string"}}},"CloudProvider":{"type":"string","description":"Cloud provider detected from node metadata","enum":["aws","gcp","azure","hetzner","digitalocean","other"]},"CloudflareConfig":{"type":"object","description":"Configuration for a Cloudflare Email Sending notification provider.\n\nNotifications are delivered through Cloudflare's transactional Email Sending\nAPI. Only the account, token, sender and recipients are configured here —\nsubject and body are derived from each notification.","required":["account_id","api_token","from_address","to_addresses"],"properties":{"account_id":{"type":"string","description":"Cloudflare account id that owns the Email Sending configuration.","example":"023e105f4ecef8ad9ca31a8372d0c353"},"api_token":{"type":"string","description":"Cloudflare API token with the Email Sending permission. Encrypted at\nrest and masked in normal API responses."},"from_address":{"type":"string","description":"Verified sender address (must belong to a domain enabled for Cloudflare\nEmail Sending).","example":"welcome@infracf.example.com"},"from_name":{"type":["string","null"],"description":"Optional human-friendly sender name shown in the recipient's inbox."},"to_addresses":{"type":"array","items":{"type":"string"},"description":"Recipients that should receive the notification."}}},"ClusterCapacity":{"type":"object","description":"Total cluster capacity (sum of node allocatable resources)","required":["node_count","cpu_millis","memory_mb"],"properties":{"cpu_millis":{"type":"integer","format":"int64","description":"Total allocatable CPU in millicores"},"memory_mb":{"type":"integer","format":"int64","description":"Total allocatable memory in MB"},"node_count":{"type":"integer","description":"Number of nodes","minimum":0}}},"ClusterDnsSettings":{"type":"object","description":"Cluster-DNS resolver settings (ADR-024, experimental beta).\n\nWhen `enabled`, the Temps control plane starts a Hickory DNS resolver and\ninjects it as the first nameserver into every deployed container via\n`HostConfig.Dns` — giving containers the ability to resolve `*.temps.local`\nFQDNs for service-to-service communication. Worker nodes pick this flag up\nfrom the `/api/internal/nodes/{id}/network/peers` wire response and gate\ntheir own per-node resolver the same way.\n\n**Default: `false` (disabled).**\n\nWhy disabled by default: a production incident showed that when the injected\nHickory resolver was slow or transiently unresponsive for a non-`*.temps.local`\n(external) hostname, glibc's resolver cycled through all three nameservers\n(`172.20.0.1`, `1.1.1.1`, `8.8.8.8`) at ~5 s timeout × 2 attempts each,\ncausing 22–27 s delays for outbound TCP connections. Disabling the injection\nrestores Docker's embedded DNS as the sole resolver, eliminating that failure\nmode. Operators running single/multi-node installs that depend on\n`*.temps.local` resolution must explicitly opt in by setting `enabled: true`.\n\n`bool` defaults to `false` in Rust and JSON (`#[serde(default)]`), so the\nsafe-off behaviour is automatic for new installs and legacy settings rows.","properties":{"enabled":{"type":"boolean","description":"Master switch. When `false` (default), no custom DNS is injected into\ncontainers — they use Docker's embedded DNS which forwards to the host's\nown `resolv.conf`. When `true`, the control-plane Hickory resolver is\nstarted and its bridge IP is injected as the first nameserver so\n`*.temps.local` FQDNs resolve inside containers.","default":false,"example":false}}},"ClusterHealthReportResponse":{"type":"object","description":"Response body for `GET /external-services/{id}/cluster-health`.","required":["checked_at","monitor_response_ms","members"],"properties":{"checked_at":{"type":"string","description":"ISO-8601 wall-clock when the report was generated.","example":"2025-10-12T12:15:47.609192Z"},"members":{"type":"array","items":{"$ref":"#/components/schemas/ClusterMemberHealthResponse"}},"monitor_error":{"type":["string","null"],"description":"Set when the monitor itself was unreachable. UI shows a banner."},"monitor_response_ms":{"type":"integer","format":"int64","description":"Round-trip to query the monitor (ms)."}}},"ClusterMemberHealthResponse":{"type":"object","description":"One row in the cluster Members table — see `GET /external-services/{id}/cluster-health`.","required":["nodename","nodehost","nodeport","reported_state","goal_state","health","seconds_since_report","candidate_priority","replication_quorum"],"properties":{"candidate_priority":{"type":"integer","format":"int32"},"goal_state":{"type":"string","description":"What the monitor *wants* the node to be. Differs from\n`reported_state` mid-transition (failover, demotion, etc.)."},"health":{"type":"integer","format":"int32","description":"pg_auto_failover liveness signal: `1` healthy, `0` unknown\n(no recent report), `-1` unhealthy."},"nodehost":{"type":"string"},"nodename":{"type":"string"},"nodeport":{"type":"integer","format":"int32"},"replay_lag_ms":{"type":["integer","null"],"format":"int64","description":"`replay_lag` from `pg_stat_replication`, in milliseconds."},"replication_quorum":{"type":"boolean"},"reported_state":{"type":"string","description":"What the node *last told the monitor* it was. Stale during outages."},"seconds_since_report":{"type":"integer","format":"int64","description":"Wall-clock seconds since the node last reported in."},"sync_state":{"type":["string","null"],"description":"`sync` / `quorum` / `async` for secondaries; `null` for the primary."}}},"ClusterMemberRequest":{"type":"object","description":"Request spec for a single cluster member.","required":["role"],"properties":{"node_id":{"type":["integer","null"],"format":"int32","description":"Target worker node ID. Omit or null to run on the control plane."},"role":{"type":"string","description":"Service-type-specific role (e.g., \"monitor\", \"primary\", \"replica\")","example":"primary"}}},"CmdBody":{"type":"object","required":["command"],"properties":{"args":{"type":"array","items":{"type":"string"},"description":"Arguments to pass to the binary. Defaults to empty."},"command":{"type":"string","description":"Binary name (argv[0]) — e.g. `\"ls\"`, `\"node\"`. The SDK sends this\nseparately from `args`."},"cwd":{"type":["string","null"],"description":"Working directory override."},"env":{"type":"object","description":"Extra env vars.","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"sudo":{"type":"boolean","description":"When true, the SDK runs the command privileged. We ignore it today\n— the underlying provider always runs as the sandbox's own user."},"wait":{"type":"boolean","description":"When true, the response is an `application/x-ndjson` stream where\nthe first line is the running-command envelope and the second line\nis the finished-command envelope with `exitCode`."}}},"CmdInner":{"type":"object","description":"Inner `command` object — matches the SDK's zod validator exactly.\n`exitCode` is `null` until the command terminates; `startedAt` is Unix\nepoch milliseconds.","required":["id","name","args","cwd","sandboxId","startedAt"],"properties":{"args":{"type":"array","items":{"type":"string"}},"cwd":{"type":"string"},"exitCode":{"type":["integer","null"],"format":"int32"},"id":{"type":"string"},"name":{"type":"string"},"sandboxId":{"type":"string"},"startedAt":{"type":"integer","format":"int64"}}},"CmdKillBody":{"type":"object","description":"SDK-shaped kill body. The SDK sends `{signal: AbortSignal}` but only\nuses the signal for HTTP request abortion client-side; there's no\nsignal name on the wire.","properties":{"force":{"type":"boolean","description":"Optional: when true, SIGKILL instead of SIGTERM."}}},"CmdResponse":{"type":"object","description":"`@vercel/sandbox` envelope: `{ command: {...} }`.","required":["command"],"properties":{"command":{"$ref":"#/components/schemas/CmdInner"}}},"CommitExistsResponse":{"type":"object","required":["exists"],"properties":{"commit":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/CommitInfo","description":"Commit metadata when the requested SHA exists."}]},"commit_sha":{"type":["string","null"]},"exists":{"type":"boolean"}}},"CommitInfo":{"type":"object","required":["sha","message","author","author_email","date"],"properties":{"author":{"type":"string","description":"Author name"},"author_email":{"type":"string","description":"Author email"},"date":{"type":"string","format":"date-time","description":"Commit date in ISO 8601 format","example":"2025-10-12T12:15:47.609192Z"},"message":{"type":"string","description":"Commit message"},"sha":{"type":"string","description":"Commit SHA hash"}}},"CommitListResponse":{"type":"object","required":["commits"],"properties":{"commits":{"type":"array","items":{"$ref":"#/components/schemas/CommitInfo"}}}},"Comparator":{"type":"string","description":"Comparator for static/forecast threshold detectors. Serializes to the\nkeyword forms `gt|gte|lt|lte` (NOT the SQL operators used by\n`temps-monitoring::compare`).","enum":["gt","gte","lt","lte"]},"ComposePublicPort":{"type":"object","description":"A port that should be exposed publicly through the proxy for a compose service.","required":["service","port"],"properties":{"port":{"type":"integer","format":"int32","description":"Container port to expose (e.g. 8123)","minimum":0},"service":{"type":"string","description":"Compose service name (e.g. \"web\", \"clickhouse\")"}}},"ConnectionListQuery":{"type":"object","properties":{"direction":{"type":["string","null"]},"page":{"type":["integer","null"],"format":"int64","minimum":0},"per_page":{"type":["integer","null"],"format":"int64","minimum":0},"sort":{"type":["string","null"]}}},"ConnectionListResponse":{"type":"object","required":["connections","total_count","page","per_page"],"properties":{"connections":{"type":"array","items":{"$ref":"#/components/schemas/ConnectionResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"per_page":{"type":"integer","format":"int64","minimum":0},"total_count":{"type":"integer","minimum":0}}},"ConnectionResponse":{"type":"object","required":["id","provider_id","account_name","account_type","is_active","is_expired","syncing","synced_repository_count","health_status","consecutive_health_failures","created_at","updated_at"],"properties":{"account_name":{"type":"string"},"account_type":{"type":"string"},"consecutive_health_failures":{"type":"integer","format":"int32"},"created_at":{"type":"string","format":"date-time"},"health_message":{"type":["string","null"],"description":"Human-readable reason when health_status is \"unhealthy\"; null otherwise."},"health_status":{"type":"string","description":"Current health status: \"healthy\", \"unhealthy\", or \"unknown\"."},"id":{"type":"integer","format":"int32"},"installation_id":{"type":["string","null"]},"is_active":{"type":"boolean"},"is_expired":{"type":"boolean"},"last_health_check_at":{"type":["string","null"],"format":"date-time"},"last_synced_at":{"type":["string","null"],"format":"date-time"},"provider_id":{"type":"integer","format":"int32"},"synced_repository_count":{"type":"integer","format":"int32","description":"Running count of repositories persisted by the current (or most\nrecent) sync. Resets to 0 when a new sync begins; useful for showing\nlive progress on large syncs."},"syncing":{"type":"boolean"},"updated_at":{"type":"string","format":"date-time"},"user_id":{"type":["integer","null"],"format":"int32"}}},"ConnectionTestResult":{"type":"object","description":"Connection test result","required":["success","message"],"properties":{"message":{"type":"string"},"success":{"type":"boolean"}}},"ConsoleEventPayload":{"type":"object","description":"Payload for server-side event ingestion via the console API.\n\nThe app backend reads the encrypted `_temps_visitor_id` and `_temps_sid`\ncookie values from the user's request and forwards them here.\nTemps decrypts them server-side to resolve visitor/session identity.","required":["event_name","environment_id","deployment_id"],"properties":{"deployment_id":{"type":"integer","format":"int32","description":"Deployment ID to attribute the event to"},"environment_id":{"type":"integer","format":"int32","description":"Environment ID to attribute the event to"},"event_data":{"description":"Arbitrary JSON event data"},"event_name":{"type":"string","description":"Event name (e.g. \"purchase\", \"signup\", custom event names)"},"request_path":{"type":"string","description":"Page path context (defaults to \"/\")"},"request_query":{"type":"string","description":"Query string context"},"session_id":{"type":["string","null"],"description":"Encrypted `_temps_sid` cookie value from the user's browser"},"visitor_id":{"type":["string","null"],"description":"Encrypted `_temps_visitor_id` cookie value from the user's browser"}}},"ContainerActionResponse":{"type":"object","description":"Response indicating success of container state change","required":["container_id","container_name","action","status","message"],"properties":{"action":{"type":"string"},"container_id":{"type":"string"},"container_name":{"type":"string"},"message":{"type":"string"},"status":{"type":"string"}}},"ContainerDetailResponse":{"type":"object","description":"Detailed container information with environment variables and metrics","required":["id","container_id","container_name","image_name","status","deployment_id","created_at","deployed_at","container_port","environment_variables"],"properties":{"container_id":{"type":"string"},"container_name":{"type":"string"},"container_port":{"type":"integer","format":"int32","description":"Port inside the container"},"cpu_limit_cores":{"type":["number","null"],"format":"double","description":"CPU limit in whole cores (e.g. 1.0). None when no limit is configured."},"created_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"deployed_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"deployment_id":{"type":"integer","format":"int32"},"environment_variables":{"type":"array","items":{"$ref":"#/components/schemas/EnvVarResponse"},"description":"Environment variables (sensitive values masked)"},"error_message":{"type":["string","null"],"description":"Free-form error string from Docker's container state on exit."},"exit_code":{"type":["integer","null"],"format":"int32","description":"Process exit code reported by Docker. None while still running."},"exit_reason":{"type":["string","null"],"description":"Human-readable reason the container exited."},"finished_at":{"type":["string","null"],"description":"When the container exited (Docker's FinishedAt). None while running.","example":"2025-10-12T12:16:47.609192Z"},"host_port":{"type":["integer","null"],"format":"int32","description":"Port on the host machine"},"id":{"type":"integer","format":"int32"},"image_name":{"type":"string"},"oom_killed":{"type":["boolean","null"],"description":"True when Docker's OOM killer terminated the container."},"ready_at":{"type":["string","null"],"example":"2025-10-12T12:16:47.609192Z"},"resource_limits":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ResourceLimitsResponse","description":"Resource limits"}]},"restart_count":{"type":["integer","null"],"format":"int64","description":"Container restart count from Docker"},"service_name":{"type":["string","null"],"description":"Compose service name (e.g. \"web\", \"redis\"). None for single-container deployments."},"service_url":{"type":["string","null"],"description":"Per-service URL for compose deployments"},"started_at":{"type":["string","null"],"description":"When the container's main process most recently started.","example":"2025-10-12T12:15:50.000000Z"},"status":{"type":"string"}}},"ContainerEnvironmentVariableValueResponse":{"type":"object","required":["value"],"properties":{"value":{"type":"string"}}},"ContainerInfoResponse":{"type":"object","required":["container_id","container_name","image_name","status","created_at"],"properties":{"container_id":{"type":"string"},"container_name":{"type":"string"},"cpu_limit_cores":{"type":["number","null"],"format":"double","description":"CPU limit in whole cores (e.g. 1.0). None when no limit is configured."},"created_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"error_message":{"type":["string","null"],"description":"Free-form error string from Docker's container state on exit."},"exit_code":{"type":["integer","null"],"format":"int32","description":"Process exit code reported by Docker. None while still running."},"exit_reason":{"type":["string","null"],"description":"Human-readable reason the container exited (e.g. \"OOMKilled\",\n\"Killed by SIGKILL (exit code 137)\", \"Exit code 1\"). None while running."},"finished_at":{"type":["string","null"],"description":"When the container exited (Docker's FinishedAt). None while running.","example":"2025-10-12T12:16:47.609192Z"},"image_name":{"type":"string"},"node_name":{"type":["string","null"],"description":"Node name where this container is running. None for local (single-node) deployments."},"oom_killed":{"type":["boolean","null"],"description":"True when Docker's OOM killer terminated the container."},"restart_count":{"type":["integer","null"],"format":"int64","description":"Container restart count from Docker. The UI shows a chip when this is\n> 0 so a crash loop is visible without opening detail."},"service_name":{"type":["string","null"],"description":"Compose service name (e.g. \"web\", \"redis\"). None for single-container deployments."},"service_url":{"type":["string","null"],"description":"Per-service URL for compose deployments (e.g. \"https://web-myapp.localho.st\")"},"started_at":{"type":["string","null"],"description":"When the container's main process most recently started. The UI uses\nthis for the uptime label so the count resets when a container is\nrestarted in place. None for containers that never started.","example":"2025-10-12T12:15:50.000000Z"},"status":{"type":"string"}}},"ContainerInventoryItem":{"type":"object","description":"A container reported by the agent during heartbeat reconciliation.","required":["container_id","container_name"],"properties":{"container_id":{"type":"string","description":"Docker container ID"},"container_name":{"type":"string","description":"Docker container name"}}},"ContainerListResponse":{"type":"object","required":["containers","total"],"properties":{"containers":{"type":"array","items":{"$ref":"#/components/schemas/ContainerInfoResponse"}},"total":{"type":"integer","minimum":0}}},"ContainerLogSettings":{"type":"object","description":"Docker container log rotation settings\nControls the `--log-opt max-size` and `--log-opt max-file` for containers","properties":{"max_file":{"type":"integer","format":"int32","description":"Maximum number of rotated log files to keep (e.g., 3 means up to 3 x max_size total)","default":3,"example":3,"minimum":0},"max_size":{"type":"string","description":"Maximum size of each log file (e.g., \"50m\", \"100m\", \"1g\")\nDocker default is unlimited; we default to \"50m\" to prevent disk exhaustion","default":"50m","example":"50m"},"service_max_file":{"type":"integer","format":"int32","description":"Maximum rotated log files for external service containers","default":3,"example":3,"minimum":0},"service_max_size":{"type":"string","description":"Maximum size for external service container logs (postgres, redis, etc.)\nDefaults to \"20m\" since services are typically less verbose than app containers","default":"20m","example":"20m"}}},"ContainerLogsQuery":{"type":"object","properties":{"container_name":{"type":["string","null"],"description":"Optional container name to get logs from (if deployment has multiple containers)"},"end_date":{"type":["integer","null"],"format":"int64"},"follow":{"type":"boolean","description":"Follow log output in real-time (default: true for backward compatibility)"},"start_date":{"type":["integer","null"],"format":"int64"},"tail":{"type":["string","null"]},"timestamps":{"type":"boolean","description":"Include timestamps in log output (default: false)"}}},"ContainerMetricHistoryPoint":{"type":"object","description":"One bucketed data point of a container resource metric time series.","required":["time","value"],"properties":{"time":{"type":"string","description":"Bucket timestamp (ISO 8601 with `Z` suffix).","example":"2025-10-12T12:15:00+00:00"},"value":{"type":"number","format":"double","description":"Averaged metric value for the bucket."}}},"ContainerMetricsHistoryQuery":{"type":"object","description":"Query parameters for the container metrics history endpoint.","required":["metric"],"properties":{"metric":{"type":"string","description":"Dotted metric name, e.g. `container.cpu_percent` or\n`container.memory_used_bytes`."},"range":{"type":"string","description":"Time window: `1h`, `6h`, `24h`, or `7d` (defaults to `1h`)."}}},"ContainerMetricsResponse":{"type":"object","description":"Container resource metrics (CPU, memory usage)","required":["container_id","container_name","cpu_percent","memory_bytes","network_rx_bytes","network_tx_bytes","timestamp"],"properties":{"container_id":{"type":"string"},"container_name":{"type":"string"},"cpu_limit_cores":{"type":["number","null"],"format":"double","description":"CPU limit in whole cores (e.g. 1.0). None = no limit."},"cpu_percent":{"type":"number","format":"double","description":"CPU usage as a multi-core percentage (Docker convention: 200 = 2 cores\nfully pinned). Divide by 100 to get cores used."},"memory_bytes":{"type":"integer","format":"int64","description":"Memory usage in bytes","minimum":0},"memory_limit_bytes":{"type":["integer","null"],"format":"int64","description":"Memory limit in bytes (if set)","minimum":0},"memory_percent":{"type":["number","null"],"format":"double","description":"Memory usage percentage (0-100) if limit is set"},"network_rx_bytes":{"type":"integer","format":"int64","description":"Network bytes received","minimum":0},"network_tx_bytes":{"type":"integer","format":"int64","description":"Network bytes transmitted","minimum":0},"timestamp":{"type":"string","description":"Timestamp of metrics collection","example":"2025-10-12T12:15:47.609192Z"}}},"ContainerResponse":{"type":"object","required":["name","container_type","can_contain_containers","can_contain_entities","metadata"],"properties":{"can_contain_containers":{"type":"boolean","description":"Can this container hold other containers?","example":true},"can_contain_entities":{"type":"boolean","description":"Can this container hold entities (tables, collections, etc.)?","example":false},"child_container_type":{"type":["string","null"],"description":"Type of child containers (if can_contain_containers is true)","example":"schema"},"container_type":{"type":"string","description":"Container type (database, schema, keyspace, bucket, etc.)","example":"database"},"entity_count_hint":{"type":["string","null"],"description":"Hint for UI on expected entity count (small = sidebar, large = pagination)","example":"large"},"entity_type_label":{"type":["string","null"],"description":"Label for entity type (if can_contain_entities is true)","example":"table"},"metadata":{"description":"Additional metadata"},"name":{"type":"string","description":"Container name","example":"mydb"}}},"ContainerRuntimeInfo":{"type":"object","description":"Snapshot of a container's lifecycle state from `docker inspect`.\n`restart_count` and `oom_killed` are the load-bearing fields when\ndiagnosing crash loops — the kernel OOM killer never reaches the\napplication's logs, so seeing `oom_killed=true` is the only signal\nthat a memory limit was the cause.","required":["role","container_name","resource_limits"],"properties":{"container_id":{"type":["string","null"],"description":"Container Docker id, when present. None = container does not exist\n(was never created or was removed externally)."},"container_name":{"type":"string","description":"Stable name of the Docker container (e.g. `postgres-mydb`)."},"exit_code":{"type":["integer","null"],"format":"int64","description":"Last container exit code, when known. Non-zero = unclean stop."},"finished_at":{"type":["string","null"],"description":"ISO-8601 timestamp of the most recent termination, when known."},"image":{"type":["string","null"],"description":"Currently-effective Docker image (e.g. `gotempsh/postgres-walg:18-bookworm`)."},"oom_killed":{"type":["boolean","null"],"description":"True when the container's last termination was caused by the\nkernel OOM killer. Set if the user enabled hard memory limits\nand the working set exceeded them."},"resource_limits":{"$ref":"#/components/schemas/ServiceResourceLimits","description":"Currently-applied resource limits read off the container's\n`HostConfig`. Compare this against the user-configured limits to\ndetect drift (an old container that never picked up new caps)."},"restart_count":{"type":["integer","null"],"format":"int64","description":"Total restarts since the container was created. Useful for\ndetecting crash loops — a steady stream means something is killing\nthe container repeatedly (frequently OOM)."},"role":{"type":"string","description":"`service_members.role` for cluster members; \"standalone\" otherwise."},"started_at":{"type":["string","null"],"description":"ISO-8601 timestamp of when the container last started. None when\nit has never started (i.e. created but never run)."},"status":{"type":["string","null"],"description":"Bollard container state (\"running\", \"exited\", \"dead\", etc.). None\nwhen the container does not exist."}}},"ContainerStatsSample":{"type":"object","description":"Live resource usage sample for a single container.\n\n`cpu_percent` is computed by Docker's standard formula:\n ((cpu_delta / system_delta) * online_cpus) * 100\n`memory_percent` is `(memory_usage / memory_limit) * 100` — when no\nmemory limit is set the limit reported by Docker is the host's total\nRAM, so a 5% reading means \"5% of host RAM\", not \"5% of allocated\".","required":["role","container_name"],"properties":{"container_name":{"type":"string"},"cpu_percent":{"type":["number","null"],"format":"double","description":"CPU usage as a percentage. `None` when the container is not running\n(Docker returns no usable counters)."},"memory_limit_bytes":{"type":["integer","null"],"format":"int64","description":"Memory limit in bytes (host RAM if no limit set).","minimum":0},"memory_percent":{"type":["number","null"],"format":"double","description":"Memory usage as a percentage of `memory_limit_bytes`."},"memory_usage_bytes":{"type":["integer","null"],"format":"int64","description":"Resident memory usage in bytes.","minimum":0},"online_cpus":{"type":["integer","null"],"format":"int32","description":"Number of cores Docker observed at sample time. Used by the UI\nto label \"x/y cores\" instead of just a percent.","minimum":0},"role":{"type":"string"}}},"ContentPart":{"type":"object","required":["type"],"properties":{"image_url":{},"text":{"type":["string","null"]},"type":{"type":"string"}}},"ContextLine":{"type":"object","description":"A line in context response","required":["timestamp","level","message","line_offset","is_match"],"properties":{"fields":{},"is_match":{"type":"boolean","description":"Whether this line matched the original search"},"level":{"$ref":"#/components/schemas/LogLevel"},"line_offset":{"type":"integer","format":"int32"},"message":{"type":"string"},"timestamp":{"type":"string"}}},"ContextLogsRequest":{"type":"object","required":["chunk_id","line_offset"],"properties":{"chunk_id":{"type":"string"},"line_offset":{"type":"integer","format":"int32"},"lines":{"type":["integer","null"],"format":"int32","description":"Number of context lines before and after (default: 25)","minimum":0}}},"ContextLogsResponse":{"type":"object","required":["lines","target_index"],"properties":{"lines":{"type":"array","items":{"$ref":"#/components/schemas/ContextLine"}},"target_index":{"type":"integer","minimum":0}}},"ConversationDetailResponse":{"allOf":[{"$ref":"#/components/schemas/ConversationResponse"},{"type":"object","required":["messages"],"properties":{"messages":{"type":"array","items":{"$ref":"#/components/schemas/MessageResponse"},"description":"Turns oldest-first. The `system` seed message is omitted (internal)."}}}]},"ConversationResponse":{"type":"object","required":["public_id","context_type","context_id","status","created_at","last_activity_at"],"properties":{"context_id":{"type":"string"},"context_type":{"type":"string"},"created_at":{"type":"string"},"last_activity_at":{"type":"string"},"public_id":{"type":"string"},"status":{"type":"string"},"title":{"type":["string","null"]}}},"ConversationSummary":{"type":"object","description":"A conversation summary grouping related AI invocations.","required":["conversation_id","message_count","total_input_tokens","total_output_tokens","total_tokens","total_cost_microcents","avg_latency_ms","models_used","first_at","last_at"],"properties":{"avg_latency_ms":{"type":"number","format":"double"},"conversation_id":{"type":"string"},"first_at":{"type":"string"},"last_at":{"type":"string"},"message_count":{"type":"integer","format":"int64"},"models_used":{"type":"array","items":{"type":"string"}},"total_cost_microcents":{"type":"integer","format":"int64"},"total_input_tokens":{"type":"integer","format":"int64"},"total_output_tokens":{"type":"integer","format":"int64"},"total_tokens":{"type":"integer","format":"int64"}}},"ConversationsQueryParams":{"type":"object","properties":{"from":{"type":["string","null"],"description":"ISO 8601 start time (defaults to 24h ago)"},"limit":{"type":["integer","null"],"format":"int64","description":"Max results (defaults to 50, max 100)","minimum":0},"model":{"type":["string","null"],"description":"Filter by model name"},"tags":{"type":["string","null"],"description":"Filter by tags (comma-separated, AND logic)"},"to":{"type":["string","null"],"description":"ISO 8601 end time (defaults to now)"},"user_id":{"type":["integer","null"],"format":"int32","description":"Filter by user ID"}}},"CopyBlobRequest":{"type":"object","description":"Request to copy a blob","required":["fromUrl","toPathname"],"properties":{"fromUrl":{"type":"string","description":"Source blob URL or pathname","example":"/api/blob/10/images/avatar.png"},"projectId":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1},"toPathname":{"type":"string","description":"Destination pathname","example":"images/avatar-copy.png"}}},"CostAnalysis":{"type":"object","description":"Full cluster cost + rightsizing analysis attached to an import plan.","required":["nodes","capacity","requested","usage_source","overprovisioning","recommendation","notes"],"properties":{"actual_usage":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ResourceFootprint","description":"Measured usage from the metrics API (`metrics.k8s.io`).\n`None` when metrics-server is not installed."}]},"capacity":{"$ref":"#/components/schemas/ClusterCapacity","description":"Total cluster capacity (sum of node allocatable resources)"},"control_plane_monthly_usd":{"type":["number","null"],"format":"double","description":"Managed control-plane fee included in `current_monthly_usd` (EKS/GKE\ncharge ~$73/mo per cluster). `None` when not applicable/unknown."},"current_monthly_usd":{"type":["number","null"],"format":"double","description":"Estimated total infrastructure cost per month in USD (compute nodes +\ncontrol-plane fee). `None` when no node could be priced."},"nodes":{"type":"array","items":{"$ref":"#/components/schemas/NodeCostInfo"},"description":"Per-node inventory with price estimates where the instance type is known"},"notes":{"type":"array","items":{"type":"string"},"description":"Honesty notes: what could not be measured, which numbers are\nestimates, and any assumptions made. Always shown to the user."},"overprovisioning":{"$ref":"#/components/schemas/OverprovisioningAssessment","description":"Requests-vs-capacity-vs-usage assessment"},"provider":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/CloudProvider","description":"Detected cloud provider (from node `providerID` prefixes)"}]},"recommendation":{"$ref":"#/components/schemas/TargetRecommendation","description":"The temps/Hetzner target sizing and savings estimate"},"requested":{"$ref":"#/components/schemas/ResourceFootprint","description":"Sum of pod resource *requests* across running pods — what the\nscheduler has reserved, i.e. what the cluster is sized for."},"usage_source":{"$ref":"#/components/schemas/UsageSource","description":"How the usage numbers were obtained (drives UI wording)"}}},"CreateAlertRuleRequest":{"type":"object","required":["name","trigger_type"],"properties":{"cooldown_minutes":{"type":"integer","format":"int32","description":"Minimum minutes between notifications for same rule+group"},"enabled":{"type":"boolean"},"environment_filter":{"type":["integer","null"],"format":"int32","description":"Optional environment ID to filter alerts"},"error_level_filter":{"type":["string","null"],"description":"Optional error type/level filter"},"name":{"type":"string"},"notification_priority":{"type":"string","description":"Notification priority: Low, Normal, High, Critical"},"trigger_config":{"description":"Trigger-specific configuration (e.g., {\"count\": 100, \"window_minutes\": 60} for frequency)"},"trigger_type":{"type":"string","description":"Trigger type: new_issue, regression, frequency, new_user, user_count, status_change"}}},"CreateApiKeyRequest":{"type":"object","required":["name","role_type"],"properties":{"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"name":{"type":"string"},"permissions":{"type":["array","null"],"items":{"type":"string"},"example":["projects:read","deployments:read"]},"role_type":{"type":"string","example":"admin"}}},"CreateApiKeyResponse":{"type":"object","required":["id","name","key_prefix","role_type","api_key","created_at"],"properties":{"api_key":{"type":"string"},"created_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00Z"},"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"id":{"type":"integer","format":"int32"},"key_prefix":{"type":"string"},"name":{"type":"string"},"permissions":{"type":["array","null"],"items":{"type":"string"}},"role_type":{"type":"string"}}},"CreateBackupScheduleRequest":{"type":"object","required":["name","backup_type","retention_period","schedule_expression","enabled","tags"],"properties":{"backup_type":{"type":"string"},"description":{"type":["string","null"]},"enabled":{"type":"boolean"},"include_control_plane":{"type":["boolean","null"],"description":"When `true` (default), every run also produces a `control_plane`\nbackup of Temps's own database. Operators who use Temps purely as\na backup orchestrator for external DBs can set this to `false` to\nkeep the run history focused on those services."},"max_runtime_secs":{"type":["integer","null"],"format":"int64","description":"Optional wall-clock timeout override for jobs created by this schedule\n(seconds). When set, overrides the engine-family default. `null` means\n\"use engine default.\" The per-job `max_runtime_secs` in\n`EnqueueJobParams` can still override this for ad-hoc triggers."},"name":{"type":"string"},"retention_period":{"type":"integer","format":"int32"},"s3_source_id":{"type":["integer","null"],"format":"int32","description":"Optional S3 source. If omitted, the current default S3 source is used."},"schedule_expression":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"target_all_services":{"type":["boolean","null"],"description":"When `true` (default), the schedule backs up every external service\non the host — including databases created in the future. When\n`false`, the schedule backs up only the services explicitly attached\nvia `POST /backups/schedules/{id}/services`. Omit to use the default."}}},"CreateBitbucketRequest":{"type":"object","required":["name","auth"],"properties":{"auth":{"$ref":"#/components/schemas/BitbucketAuthInput","description":"Authentication credentials — either an access token or an app password."},"name":{"type":"string","description":"Display name for this provider."}}},"CreateCloudflareProviderRequest":{"type":"object","required":["name","config"],"properties":{"config":{"$ref":"#/components/schemas/CloudflareConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":"string"}}},"CreateConversationRequest":{"type":"object","required":["context_type","context_id"],"properties":{"context_id":{"type":"string","description":"The entity id (ints stringified)."},"context_type":{"type":"string","description":"e.g. `\"deployment\"`."}}},"CreateDSNRequest":{"type":"object","properties":{"base_url":{"type":["string","null"]},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"name":{"type":["string","null"]}}},"CreateDashboardRequest":{"type":"object","required":["project_id","name","layout"],"properties":{"layout":{"$ref":"#/components/schemas/DashboardLayout"},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"}}},"CreateDeploymentTokenRequest":{"type":"object","required":["name"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32","description":"Optional deployment ID - if set, token is scoped to a specific deployment"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Optional environment ID - if not set, token applies to all environments"},"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"name":{"type":"string"},"permissions":{"type":["array","null"],"items":{"type":"string"},"description":"List of permissions (e.g., [\"visitors:enrich\", \"emails:send\"])\nIf not provided, defaults to full access","example":["visitors:enrich","emails:send"]}}},"CreateDeploymentTokenResponse":{"type":"object","required":["id","project_id","name","token_prefix","token","created_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00Z"},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"permissions":{"type":["array","null"],"items":{"type":"string"}},"project_id":{"type":"integer","format":"int32"},"token":{"type":"string","description":"The full token value - only returned on creation"},"token_prefix":{"type":"string"}}},"CreateDnsProviderRequest":{"type":"object","description":"Request to create a new DNS provider","required":["name","provider_type","credentials"],"properties":{"credentials":{"$ref":"#/components/schemas/DnsProviderCredentials","description":"Provider credentials"},"description":{"type":["string","null"],"description":"Optional description"},"name":{"type":"string","description":"User-friendly name","example":"My Cloudflare"},"provider_type":{"$ref":"#/components/schemas/DnsProviderType","description":"Provider type"}}},"CreateDomainRequest":{"type":"object","required":["domain"],"properties":{"challenge_type":{"type":"string","description":"Challenge type for Let's Encrypt validation. Options: \"http-01\" (default) or \"dns-01\""},"domain":{"type":"string"}}},"CreateEmailDomainRequest":{"type":"object","required":["provider_id","domain"],"properties":{"domain":{"type":"string","description":"Domain name (e.g., \"updates.example.com\")","example":"updates.example.com"},"provider_id":{"type":"integer","format":"int32","description":"Provider ID to use for this domain"}}},"CreateEmailProviderRequest":{"type":"object","required":["name","provider_type","region"],"properties":{"name":{"type":"string","description":"User-friendly name for the provider","example":"My AWS SES"},"provider_type":{"$ref":"#/components/schemas/EmailProviderTypeRoute","description":"Provider type"},"region":{"type":"string","description":"Cloud region. For SMTP this is informational only — the host/port carry the real routing.","example":"us-east-1"},"scaleway_credentials":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ScalewayCredentialsRequest","description":"Scaleway credentials (required if provider_type is scaleway)"}]},"ses_credentials":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SesCredentialsRequest","description":"AWS SES credentials (required if provider_type is ses)"}]},"smtp_credentials":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SmtpCredentialsRequest","description":"Generic SMTP credentials (required if provider_type is smtp). Use when\nyou only have SMTP creds and want to import an already-set-up domain."}]},"sns_topic_arn":{"type":["string","null"],"description":"Exact SNS topic allowed to deliver SES events for this provider."}}},"CreateEnvironmentRequest":{"type":"object","required":["name","branch"],"properties":{"branch":{"type":"string"},"name":{"type":"string"},"set_as_preview":{"type":"boolean","description":"If true, set this environment as the preview environment for the project"}}},"CreateEnvironmentVariableRequest":{"type":"object","required":["key","value","environment_ids"],"properties":{"environment_ids":{"type":"array","items":{"type":"integer","format":"int32"}},"include_in_preview":{"type":"boolean","description":"Include this environment variable in preview environments (default: true)"},"is_secret":{"type":"boolean","description":"When true the variable is treated as write-only: never returned in\nplaintext from the API, masked in the UI, and updates that omit the\nvalue preserve the existing ciphertext. The flag is one-way — secret\nvars cannot be demoted back to regular vars."},"key":{"type":"string"},"value":{"type":"string"}}},"CreateExternalServiceRequest":{"type":"object","required":["name","service_type","parameters"],"properties":{"members":{"type":"array","items":{"$ref":"#/components/schemas/ClusterMemberRequest"},"description":"Cluster member specifications. Required when topology is \"cluster\"."},"name":{"type":"string"},"node_id":{"type":["integer","null"],"format":"int32","description":"Target node ID for the service. Omit or null to run on the control plane."},"parameters":{"type":"object","additionalProperties":{},"propertyNames":{"type":"string"}},"service_type":{"$ref":"#/components/schemas/ServiceTypeRoute"},"topology":{"type":"string","description":"Service topology: \"standalone\" (default) or \"cluster\" (HA multi-member).","example":"standalone"},"version":{"type":["string","null"]}}},"CreateFlagRequest":{"type":"object","required":["key","value_type","default_value"],"properties":{"client_visible":{"type":"boolean","description":"Whether the flag may be exposed on the unauthenticated same-origin\nevaluation endpoint. Defaults to `false`: flags are server-only unless\nexplicitly opted in, because targeting rules can encode business logic."},"default_value":{"description":"Served whenever evaluation cannot do better. Must match `value_type`.\n\nLeft unannotated so utoipa emits a free-form schema: a bool flag's\ndefault is `false`, not an object, and `value_type = Object` would tell\nevery generated client otherwise."},"description":{"type":["string","null"]},"key":{"type":"string","description":"Stable key used in application code. Immutable after create.","example":"checkout.v2"},"value_type":{"$ref":"#/components/schemas/FlagValueType","description":"Fixed at create: retyping would invalidate every stored value and every\ncall site."}}},"CreateFunnelRequest":{"type":"object","required":["name","steps"],"properties":{"description":{"type":["string","null"]},"name":{"type":"string"},"steps":{"type":"array","items":{"$ref":"#/components/schemas/CreateFunnelStep"}}}},"CreateFunnelResponse":{"type":"object","required":["funnel_id","message"],"properties":{"funnel_id":{"type":"integer","format":"int32"},"message":{"type":"string"}}},"CreateFunnelStep":{"type":"object","required":["event_name"],"properties":{"event_filter":{"type":"array","items":{"$ref":"#/components/schemas/SmartFilter"}},"event_name":{"type":"string"}}},"CreateGenericRequest":{"type":"object","required":["name","clone_url"],"properties":{"base_url":{"type":["string","null"],"description":"Optional base URL of the git host for display purposes (no API is called)."},"clone_url":{"type":"string","description":"HTTPS clone URL for the repository, e.g. `https://git.example.com/org/repo.git`."},"name":{"type":"string","description":"Display name for this provider."},"token":{"type":["string","null"],"description":"Access token or password. Omit (or set to `null`) for public repositories."},"token_username":{"type":["string","null"],"description":"HTTP Basic username used with the token. Defaults to `x-access-token` when\nabsent or empty. Ignored for public (unauthenticated) repositories."}}},"CreateGitHubPATRequest":{"type":"object","required":["name","token"],"properties":{"name":{"type":"string"},"token":{"type":"string"}}},"CreateGitLabOAuthRequest":{"type":"object","required":["name","client_id","client_secret","redirect_uri"],"properties":{"base_url":{"type":["string","null"]},"client_id":{"type":"string"},"client_secret":{"type":"string"},"name":{"type":"string"},"redirect_uri":{"type":"string"}}},"CreateGitLabPATRequest":{"type":"object","required":["name","token"],"properties":{"base_url":{"type":["string","null"]},"name":{"type":"string"},"token":{"type":"string"}}},"CreateGiteaPATRequest":{"type":"object","required":["name","token","base_url"],"properties":{"base_url":{"type":"string","description":"HTTPS base URL of the Gitea instance, e.g. `https://git.example.com`."},"name":{"type":"string","description":"Display name for this provider."},"token":{"type":"string","description":"Personal access token issued by the Gitea instance."}}},"CreateIncidentRequest":{"type":"object","required":["title","severity"],"properties":{"description":{"type":["string","null"]},"environment_id":{"type":["integer","null"],"format":"int32"},"monitor_id":{"type":["integer","null"],"format":"int32"},"severity":{"type":"string"},"title":{"type":"string"}}},"CreateIntegrationBody":{"type":"object","required":["provider","signing_secret"],"properties":{"provider":{"type":"string","description":"Registered provider name, e.g. \"stripe\"."},"signing_secret":{"type":"string","description":"Signing secret from the provider's dashboard."}}},"CreateIpAccessControlRequest":{"type":"object","description":"Request to create an IP access control rule","required":["ip_address","action"],"properties":{"action":{"type":"string","description":"Action to take: \"block\" or \"allow\"","example":"block"},"ip_address":{"type":"string","description":"IP address in CIDR notation (e.g., \"192.168.1.1\" or \"10.0.0.0/24\")","example":"192.168.1.100"},"reason":{"type":["string","null"],"description":"Optional reason for the action","example":"Malicious activity detected"}}},"CreateMcpRequest":{"type":"object","required":["slug","name","config"],"properties":{"config":{"type":"object"},"description":{"type":["string","null"]},"name":{"type":"string"},"slug":{"type":"string"}}},"CreateMetricAlertRequest":{"type":"object","required":["project_id","name","metric_name","aggregation","detection_config","window_secs","for_duration_secs","severity","enabled"],"properties":{"aggregation":{"type":"string","description":"One of `avg|sum|min|max|count|rate|p50|p90|p95|p99`."},"detection_config":{"$ref":"#/components/schemas/DetectionConfig","description":"The detector: a discriminated union keyed by `kind`. Today only\n`{ \"kind\": \"static\", \"comparator\": \"gt\", \"threshold\": 500 }` is evaluable."},"dynamic_alerts":{"type":"boolean","description":"When true (and `group_by` is set) fire one independent alarm per breaching\nseries. Static detectors only. Default false."},"enabled":{"type":"boolean"},"for_duration_secs":{"type":"integer","format":"int32"},"group_by":{"type":"array","items":{"type":"string"},"description":"Label keys to break the metric down by, e.g. `[\"endpoint\",\"region\"]`. Empty\n(the default) = one aggregate stream. Max 2 keys; keys must match\n`[a-zA-Z0-9_.:-]`."},"grouped_notification_threshold":{"type":"integer","format":"int32","description":"When more than this many series transition to firing in the same tick, only\nthe first gets the expensive chart/AI enrichment. Range 1–1000, default 5."},"label_filters":{"type":"array","items":{"type":"array","items":false,"prefixItems":[{"type":"string"},{"type":"string"}]},"description":"AND-combined label equality filters: `[[\"key\",\"value\"],…]`. Empty = no\nfiltering (the default). Max 10 pairs; keys must match `[a-zA-Z0-9_.:-]`;\nvalues capped at 500 characters."},"max_series":{"type":"integer","format":"int32","description":"Cardinality cap for dynamic alerting: at most this many series (top by\n`|value|`). Range 1–100, default 20."},"metric_name":{"type":"string"},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"severity":{"type":"string","description":"One of `info|warning|critical`."},"window_secs":{"type":"integer","format":"int32"}}},"CreateMonitorRequest":{"type":"object","required":["name","monitor_type","environment_id"],"properties":{"check_interval_seconds":{"type":["integer","null"],"format":"int32"},"check_path":{"type":["string","null"]},"environment_id":{"type":"integer","format":"int32"},"monitor_type":{"type":"string"},"name":{"type":"string"}}},"CreateNotificationEmailProviderRequest":{"type":"object","required":["name","config"],"properties":{"config":{"$ref":"#/components/schemas/EmailConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":"string"}}},"CreateOidcProviderRequest":{"type":"object","required":["name","issuer_url","client_id","client_secret"],"properties":{"client_id":{"type":"string"},"client_secret":{"type":"string"},"default_role":{"type":"string"},"enabled":{"type":"boolean"},"group_claim":{"type":"string"},"issuer_url":{"type":"string"},"jit_provisioning":{"type":"boolean"},"name":{"type":"string"},"role_claim":{"type":"string"},"scopes":{"type":"string"},"template":{"type":"string"},"trust_idp_email":{"type":"boolean","description":"Defaults false. Set to true only for IdPs where an admin\ncontrols user provisioning (corporate Okta, Azure AD) and\nself-signup of arbitrary emails is not possible — see the\n`trust_idp_email` field on `oidc_providers::Model` for the\nsecurity tradeoff this enables."}}},"CreateOidcRoleMappingRequest":{"type":"object","required":["priority","idp_group","role"],"properties":{"idp_group":{"type":"string"},"priority":{"type":"integer","format":"int32"},"role":{"type":"string"}}},"CreatePlanRequest":{"type":"object","description":"Request to create an import plan","required":["source","workload_id"],"properties":{"credentials":{"$ref":"#/components/schemas/ImportCredentials","description":"Platform credentials (required for cloud platforms like Vercel, Railway)"},"repository_id":{"type":["integer","null"],"format":"int32","description":"Optional repository ID to associate with the import\nIf provided, preset will be detected from the repository"},"source":{"$ref":"#/components/schemas/ImportSource","description":"Source to import from"},"workload_id":{"$ref":"#/components/schemas/WorkloadId","description":"Workload ID to import"}}},"CreatePlanResponse":{"type":"object","description":"Response with created plan","required":["session_id","plan","validation","can_execute"],"properties":{"can_execute":{"type":"boolean","description":"Whether the plan can be executed"},"plan":{"$ref":"#/components/schemas/ImportPlan","description":"Generated import plan"},"session_id":{"type":"string","description":"Session ID for tracking"},"validation":{"$ref":"#/components/schemas/ValidationReport","description":"Validation report"}}},"CreatePrResponse":{"type":"object","required":["run","pr_url","pr_number","branch_name"],"properties":{"branch_name":{"type":"string"},"pr_number":{"type":"integer","format":"int32"},"pr_url":{"type":"string"},"run":{"$ref":"#/components/schemas/AutofixerRunResponse"}}},"CreateProjectAccessRequest":{"type":"object","required":["team_id","role"],"properties":{"role":{"$ref":"#/components/schemas/TeamRole"},"team_id":{"type":"integer","format":"int32"}}},"CreateProjectFromTemplateRequest":{"type":"object","description":"Request to create a project from a template\n\nSupports two deploy modes:\n * **Fork mode** — when `git_provider_connection_id` is set, the template\n repo is cloned into a new repository under the user's Git account and the\n project tracks that fork (git-push deploys, automatic deploy on push).\n * **One-click public-repo mode** — when `git_provider_connection_id` is\n omitted, the project deploys directly from the template's public source\n repository (no fork, no Git account required). This is the activation\n path: a brand-new user with no Git provider connected can still deploy a\n demo in one click. `repository_name` / `repository_owner` are ignored in\n this mode, and automatic-deploy-on-push is unavailable (there is no fork\n to receive webhooks).","required":["template_slug","project_name"],"properties":{"automatic_deploy":{"type":"boolean","description":"Enable automatic deployment on push (defaults to true). Only honoured in\nfork mode; public-repo deploys cannot receive push webhooks."},"environment_variables":{"type":"array","items":{"$ref":"#/components/schemas/EnvVarInput"},"description":"Environment variables to set (key-value pairs)"},"git_provider_connection_id":{"type":["integer","null"],"format":"int32","description":"Git provider connection ID. When omitted, the project deploys directly\nfrom the template's public source repository instead of forking it."},"private":{"type":"boolean","description":"Whether to make the repository private (defaults to true)"},"project_name":{"type":"string","description":"Name for the new project"},"repository_name":{"type":["string","null"],"description":"Name for the new repository to create. Required in fork mode; ignored in\none-click public-repo mode."},"repository_owner":{"type":["string","null"],"description":"Owner/organization for the new repository (defaults to authenticated user)"},"storage_service_ids":{"type":"array","items":{"type":"integer","format":"int32"},"description":"External storage service IDs to attach to the project"},"template_slug":{"type":"string","description":"Template slug to use as the base"}}},"CreateProjectFromTemplateResponse":{"type":"object","description":"Response after creating a project from template","required":["project_id","project_slug","project_name","repository_url","template_slug","message"],"properties":{"message":{"type":"string","description":"Message with additional info"},"project_id":{"type":"integer","format":"int32","description":"ID of the created project"},"project_name":{"type":"string","description":"Name of the created project"},"project_slug":{"type":"string","description":"Slug of the created project"},"repository_url":{"type":"string","description":"URL of the created repository"},"template_slug":{"type":"string","description":"Template that was used"}}},"CreateProjectRequest":{"type":"object","required":["name","directory","main_branch","preset","storage_service_ids"],"properties":{"automatic_deploy":{"type":["boolean","null"]},"build_command":{"type":["string","null"]},"custom_domain":{"type":["string","null"]},"directory":{"type":"string"},"environment_variables":{"type":["array","null"],"items":{"type":"array","items":false,"prefixItems":[{"type":"string"},{"type":"string"}]}},"exposed_port":{"type":["integer","null"],"format":"int32","description":"Port exposed by the container (fallback when image has no EXPOSE directive)\n\nPriority order for port resolution:\n1. Image EXPOSE directive (auto-detected from built image)\n2. Environment-level exposed_port (overrides this value per environment)\n3. This project-level exposed_port (fallback)\n4. Default: 3000\n\nOnly set this if your image doesn't use EXPOSE directive.","example":8080},"git_provider_connection_id":{"type":["integer","null"],"format":"int32"},"git_url":{"type":["string","null"]},"install_command":{"type":["string","null"]},"is_on_demand":{"type":["boolean","null"]},"is_public_repo":{"type":["boolean","null"]},"is_web_app":{"type":["boolean","null"]},"main_branch":{"type":"string"},"name":{"type":"string"},"output_dir":{"type":["string","null"]},"performance_metrics_enabled":{"type":"boolean"},"preset":{"type":"string"},"preset_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PresetConfigSchema","description":"Preset-specific configuration\n\nDifferent presets accept different configuration options:\n- **Dockerfile preset**: Accepts `DockerfilePresetConfig` with `dockerfile_path` and `build_context`\n- **Nixpacks preset**: Accepts ordered `providers` (for example `[\"...\", \"python\"]`)\n and optional inline `nixpacksConfig` TOML\n- **Static presets** (Vite, Next.js, etc.): Accept `StaticPresetConfig` with build commands and output dir\n\nExample for Dockerfile preset:\n```json\n{\n \"dockerfilePath\": \"docker/Dockerfile\",\n \"buildContext\": \"./api\"\n}\n```"}]},"project_type":{"type":["string","null"]},"repo_name":{"type":["string","null"]},"repo_owner":{"type":["string","null"]},"source_type":{"$ref":"#/components/schemas/SourceType","description":"Source type for deployments\n\nDetermines how the project is deployed:\n- **git** (default): Traditional Git-based deployments - source code is pulled, built, and deployed\n- **docker_image**: Deploy pre-built Docker images from external registries (DockerHub, GHCR, etc.)\n- **static_files**: Deploy pre-built static files uploaded as tar.gz or zip bundles\n\nFor `docker_image` and `static_files` source types, `repo_name` and `repo_owner` are optional."},"storage_service_ids":{"type":"array","items":{"type":"integer","format":"int32"}},"use_default_wildcard":{"type":["boolean","null"]}}},"CreateProjectSecretRequest":{"type":"object","description":"Request to create a new project secret.\n\nProject secrets are mounted into the container as files under\n`/run/secrets/` (mode 0400, tmpfs) instead of as environment variables.\nValues are always encrypted at rest and never returned in plaintext from\nthe API after create. Distinct from agent secrets (global `/settings/secrets`).","required":["key","value"],"properties":{"environment_ids":{"type":"array","items":{"type":"integer","format":"int32"}},"include_in_preview":{"type":"boolean","description":"Include this secret in preview environments."},"key":{"type":"string","description":"Identifier for the secret. Becomes the filename at `/run/secrets/`.\nMust start with a letter or underscore and contain only A-Z, a-z, 0-9, _."},"value":{"type":"string","description":"Plaintext value, <= 1 MiB."}}},"CreateProviderKeyRequest":{"type":"object","required":["provider","display_name","api_key"],"properties":{"api_key":{"type":"string"},"base_url":{"type":["string","null"]},"default_model":{"type":["string","null"],"description":"Optional model id to pin for this provider (e.g. \"gpt-4o-mini\")."},"display_name":{"type":"string"},"provider":{"type":"string"}}},"CreateProviderRequest":{"type":"object","required":["name","provider_type","config"],"properties":{"config":{},"enabled":{"type":["boolean","null"]},"name":{"type":"string"},"provider_type":{"type":"string"}}},"CreateRouteRequest":{"type":"object","required":["domain","host","port"],"properties":{"domain":{"type":"string"},"host":{"type":"string"},"port":{"type":"integer","format":"int32"},"route_type":{"type":["string","null"],"description":"Route type: \"http\" (default) matches on HTTP Host header,\n\"tls\" matches on TLS SNI hostname for TCP passthrough"}}},"CreateS3SourceRequest":{"type":"object","required":["name","bucket_name","bucket_path","access_key_id","secret_key","region"],"properties":{"access_key_id":{"type":"string"},"bucket_name":{"type":"string"},"bucket_path":{"type":"string"},"endpoint":{"type":["string","null"],"description":"Optional endpoint URL for S3-compatible services like MinIO","example":"http://minio.example.com:9000"},"force_path_style":{"type":["boolean","null"],"description":"Whether to use path-style addressing (default: true)","example":true},"is_default":{"type":["boolean","null"],"description":"When true, make this the default source (will swap out any existing default).\nThe very first S3 source is always created as default regardless of this flag.","example":false},"name":{"type":"string"},"region":{"type":"string"},"secret_key":{"type":"string"}}},"CreateSandboxBody":{"type":"object","properties":{"_runtime":{"type":["string","null"]},"backend":{"type":["string","null"],"description":"Isolation backend: `\"docker\"` (default) or `\"firecracker\"` (ADR-029,\nhardware-virtualized microVM — requires a host provisioned with\n`temps firecracker setup`). Omit for the platform default; existing\nclients are unaffected. Requesting an unavailable backend fails with\n400 rather than silently downgrading isolation."},"cpu_limit":{"type":["number","null"],"format":"double"},"disk_size_mb":{"type":["integer","null"],"format":"int64","description":"Root disk size in MB (Firecracker only; Docker ignores it). Omit for\nthe platform default (1 GiB).","minimum":0},"env":{"type":"object","description":"Extra env vars baked into the container on create.","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"image":{"type":["string","null"],"description":"Docker image override. `null` uses the platform default."},"memory_limit_mb":{"type":["integer","null"],"format":"int64","minimum":0},"name":{"type":["string","null"]},"networkPolicy":{},"pids_limit":{"type":["integer","null"],"format":"int64"},"ports":{"type":"array","items":{"type":"integer","format":"int32","minimum":0},"description":"Ports the sandbox will listen on. Each port becomes a `routes[]`\nentry in the create/get response so `@vercel/sandbox`'s\n`sandbox.domain(port)` can resolve it client-side without an\nextra round-trip."},"preview_password":{"type":["string","null"],"description":"Optional preview-URL password. When set, every preview URL served\nfor this sandbox is gated behind a login form. 8–256 characters.\nOmit to leave preview URLs open (the sandbox ID remains the only\ngate). The plaintext is never returned; only the last-4 hint is\nsurfaced in `SandboxResponse.preview_password_hint`."},"projectId":{"type":["string","null"]},"resources":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ResourcesBody","description":"`@vercel/sandbox`'s nested resources object. When present, its\n`memory` / `vcpus` populate `memory_limit_mb` / `cpu_limit` if those\nweren't sent directly."}]},"source":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SourceBody","description":"Optional initial content to seed into the work dir. Clones a\nrepo or extracts a tarball after the sandbox is created."}]},"timeout":{"type":["integer","null"],"format":"int64","description":"Idle timeout as sent by `@vercel/sandbox` (milliseconds). Converted\nto seconds when `timeout_secs` is absent.","minimum":0},"timeout_secs":{"type":["integer","null"],"format":"int64","description":"Idle timeout in seconds (temps-native). Clamped to `[60, 86400]`.","minimum":0}}},"CreateSkillRequest":{"type":"object","required":["slug","name","content"],"properties":{"content":{"type":"string"},"description":{"type":["string","null"]},"name":{"type":"string"},"slug":{"type":"string"}}},"CreateSlackProviderRequest":{"type":"object","required":["name","config"],"properties":{"config":{"$ref":"#/components/schemas/SlackConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":"string"}}},"CreateTeamMemberRequest":{"type":"object","required":["user_id","role"],"properties":{"role":{"$ref":"#/components/schemas/TeamRole"},"user_id":{"type":"integer","format":"int32"}}},"CreateTeamRequest":{"type":"object","required":["name","slug"],"properties":{"description":{"type":["string","null"]},"name":{"type":"string"},"slug":{"type":"string"}}},"CreateUserRequest":{"type":"object","required":["username","roles"],"properties":{"email":{"type":["string","null"]},"must_change_password":{"type":"boolean"},"password":{"type":["string","null"]},"roles":{"type":"array","items":{"type":"string"}},"username":{"type":"string"}}},"CreateWebhookProviderRequest":{"type":"object","required":["name","config"],"properties":{"config":{"$ref":"#/components/schemas/WebhookConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":"string"}}},"CreateWebhookRequestBody":{"type":"object","required":["url","events"],"properties":{"enabled":{"type":["boolean","null"],"description":"Whether the webhook is enabled","default":true},"events":{"type":"array","items":{"type":"string"},"description":"Event types to subscribe to","example":["deployment.created","deployment.succeeded"]},"secret":{"type":["string","null"],"description":"Secret for HMAC signature verification (optional)"},"url":{"type":"string","description":"Target URL for webhook delivery","example":"https://example.com/webhook"}}},"CreatedResource":{"type":"object","description":"Resource created during import (for rollback / audit)","required":["resource_type","resource_id","resource_name"],"properties":{"resource_id":{"type":"integer","format":"int32","description":"Resource ID"},"resource_name":{"type":"string","description":"Resource name"},"resource_type":{"type":"string","description":"Resource type (project, environment, deployment, service, domain, etc.)"}}},"CronExecutionInfo":{"type":"object","required":["id","cron_id","executed_at","url","status_code","headers","response_time_ms"],"properties":{"cron_id":{"type":"integer","format":"int32"},"error_message":{"type":["string","null"]},"executed_at":{"type":"string"},"headers":{"type":"string"},"id":{"type":"integer","format":"int32"},"response_time_ms":{"type":"integer","format":"int32"},"status_code":{"type":"integer","format":"int32"},"url":{"type":"string"}}},"CronInfo":{"type":"object","required":["id","project_id","environment_id","path","schedule","created_at","updated_at"],"properties":{"created_at":{"type":"string"},"deleted_at":{"type":["string","null"]},"environment_id":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"next_run":{"type":["string","null"]},"path":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"schedule":{"type":"string"},"updated_at":{"type":"string"}}},"CrossProjectSiblingRef":{"type":"object","description":"A sibling project that shares the same `trace_id`, returned by the\nPhase 1 cross-project banner endpoint.","required":["project_id","project_name","project_slug","first_seen"],"properties":{"first_seen":{"type":"string","format":"date-time","description":"ISO 8601 timestamp (UTC, `Z` suffix) of first span ingest for this\n`(trace_id, project_id)` pair."},"project_id":{"type":"integer","format":"int32"},"project_name":{"type":"string"},"project_slug":{"type":"string","description":"URL slug used to link into the sibling project's single-project trace view."}}},"CrossProjectTraceResponse":{"type":"object","description":"Response body for `GET /otel/traces/cross-project/{trace_id}`.\n\nAn empty `siblings` vec is the normal single-project case — never 404.","required":["trace_id","siblings"],"properties":{"siblings":{"type":"array","items":{"$ref":"#/components/schemas/CrossProjectSiblingRef"},"description":"Projects other than the caller's that hold spans for this trace,\nordered by `first_seen ASC`."},"trace_id":{"type":"string","description":"The trace_id that was queried (echoed back for client convenience)."}}},"CurrentStatusResponse":{"type":"object","required":["monitor_id","current_status","uptime_percentage"],"properties":{"avg_response_time_ms":{"type":["number","null"],"format":"double"},"current_status":{"type":"string"},"last_check_at":{"type":["string","null"],"format":"date-time"},"monitor_id":{"type":"integer","format":"int32"},"uptime_percentage":{"type":"number","format":"double"}}},"CustomDomainRequest":{"type":"object","required":["domain","environment_id"],"properties":{"branch":{"type":["string","null"]},"domain":{"type":"string"},"environment_id":{"type":"integer","format":"int32"},"redirect_to":{"type":["string","null"]},"service_name":{"type":["string","null"],"description":"Docker Compose service name this domain routes to (only for docker-compose projects)"},"status_code":{"type":["integer","null"],"format":"int32"}}},"CustomDomainResponse":{"type":"object","required":["id","project_id","domain","status","created_at","updated_at"],"properties":{"branch":{"type":["string","null"]},"created_at":{"type":"integer","format":"int64"},"domain":{"type":"string"},"domain_id":{"type":["integer","null"],"format":"int32"},"environment":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DomainEnvironmentResponse"}]},"expiration_time":{"type":["integer","null"],"format":"int64"},"id":{"type":"integer","format":"int32"},"last_renewed":{"type":["integer","null"],"format":"int64"},"message":{"type":["string","null"]},"project_id":{"type":"integer","format":"int32"},"redirect_to":{"type":["string","null"]},"service_name":{"type":["string","null"],"description":"Docker Compose service name this domain routes to"},"status":{"type":"string"},"status_code":{"type":["integer","null"],"format":"int32"},"updated_at":{"type":"integer","format":"int64"}}},"CustomerMovementResponse":{"type":"object","required":["bucket","new_customers","churned_customers"],"properties":{"bucket":{"type":"string","format":"date-time"},"churned_customers":{"type":"integer","format":"int64"},"new_customers":{"type":"integer","format":"int64"}}},"DashboardLayout":{"type":"object","description":"The typed layout persisted (as JSONB) in `metric_dashboards.layout`.","required":["sections"],"properties":{"sections":{"type":"array","items":{"$ref":"#/components/schemas/DashboardSection"},"description":"Ordered sections that make up the dashboard."}}},"DashboardProjectsAnalyticsQuery":{"type":"object","description":"Query parameters for batch dashboard analytics","required":["project_ids","start_date","end_date"],"properties":{"end_date":{"type":"string","format":"date-time","description":"End date for the query range"},"project_ids":{"type":"string","description":"Comma-separated list of project IDs"},"start_date":{"type":"string","format":"date-time","description":"Start date for the query range"}}},"DashboardProjectsAnalyticsResponse":{"type":"object","description":"Batch response for dashboard project analytics","required":["projects"],"properties":{"projects":{"type":"object","description":"Map of project_id -> analytics data","additionalProperties":{"$ref":"#/components/schemas/ProjectDashboardAnalytics"},"propertyNames":{"type":"string"}}}},"DashboardSection":{"type":"object","description":"A titled group of tiles within a dashboard.","required":["id","title","tiles"],"properties":{"id":{"type":"string","description":"Stable client-generated section id."},"tiles":{"type":"array","items":{"$ref":"#/components/schemas/DashboardTile"},"description":"Tiles rendered within this section."},"title":{"type":"string","description":"Section heading."}}},"DashboardTile":{"type":"object","description":"A single metric tile within a dashboard section.","required":["id","metric_name","aggregation"],"properties":{"aggregation":{"type":"string","description":"Aggregation applied per bucket: one of\n`avg|sum|min|max|count|rate|p50|p90|p95|p99`."},"group_by":{"type":"array","items":{"type":"string"},"description":"Label keys to break the metric down by (group-by / multi-series view).\nEmpty = single aggregated series (current behavior). Max 2 keys — more\ndimensions are unreadable in a chart (ADR-026 Phase 2). Each key must\nmatch `[a-zA-Z0-9_.:-]`. Wired directly to `MetricQuery.group_by` by\nthe tile query path (separate frontend task)."},"id":{"type":"string","description":"Stable client-generated tile id (used as a React key / for reordering)."},"label_filters":{"type":"array","items":{"type":"array","items":false,"prefixItems":[{"type":"string"},{"type":"string"}]},"description":"AND-combined label equality filters: `[[\"key\",\"value\"],…]`. Empty = no\nfiltering. Max 10 pairs; keys must match `[a-zA-Z0-9_.:-]`; values\ncapped at 500 characters. Not yet wired into the tile query path\n(Phase 1 ADR-026 — field round-trips and validates; query wiring is\na separate frontend task)."},"metric_name":{"type":"string","description":"The metric name to chart (e.g. `http.server.duration`)."},"title":{"type":["string","null"],"description":"Optional display title; falls back to the metric name in the UI."}}},"DataImplication":{"type":"object","description":"A specific data implication the user needs to understand","required":["severity","message"],"properties":{"message":{"type":"string","description":"Human-readable description of what could happen"},"recommended_action":{"type":["string","null"],"description":"What the user should do about it (if anything)"},"severity":{"$ref":"#/components/schemas/DataImplicationSeverity","description":"Severity of this implication"}}},"DataImplicationSeverity":{"type":"string","description":"Severity of a data implication","enum":["info","warning","data-not-migrated","potential-data-loss"]},"DatabaseMetricsResponse":{"type":"object","description":"Response for the per-database metrics breakdown.","required":["databases"],"properties":{"databases":{"type":"array","items":{"$ref":"#/components/schemas/DatabaseMetricsRow"},"description":"One entry per database, sorted by the first metric descending\n(largest first) so the biggest database leads the table."}}},"DatabaseMetricsRow":{"type":"object","description":"Per-database metric values for a Postgres service.\n\nA Postgres instance can host many databases (some unrelated to this\nservice). The collector records per-`datname` series; this groups the\nlatest value of each requested metric by database so the UI can render a\n\"Databases\" breakdown table instead of one collapsed number.","required":["database","metrics"],"properties":{"database":{"type":"string","description":"Database name (`datname`)."},"metrics":{"type":"object","description":"Latest value of each requested metric for this database\n(e.g. `{\"pg.database_size_bytes\": 7943871, \"pg.cache_hit_ratio\": 0.99}`).","additionalProperties":{"type":"number","format":"double"},"propertyNames":{"type":"string"}}}},"DelRequest":{"type":"object","description":"Request to delete keys","required":["keys"],"properties":{"keys":{"type":"array","items":{"type":"string"},"description":"The key(s) to delete","example":["user:123","user:456"]},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1}}},"DelResponse":{"type":"object","description":"Response for delete operation","required":["deleted"],"properties":{"deleted":{"type":"integer","format":"int64","description":"Number of keys deleted","example":2}}},"DeleteBlobRequest":{"type":"object","description":"Request to delete blobs","required":["pathnames"],"properties":{"pathnames":{"type":"array","items":{"type":"string"},"description":"Pathnames to delete (relative to project)","example":["images/avatar.png","documents/file.pdf"]},"projectId":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1}}},"DeleteBlobResponse":{"type":"object","description":"Response after deleting blobs","required":["deleted"],"properties":{"deleted":{"type":"integer","format":"int64","description":"Number of blobs deleted","example":2}}},"DeleteResponse":{"type":"object","required":["deleted"],"properties":{"deleted":{"type":"integer","format":"int64","minimum":0}}},"DeployFromImageRequest":{"type":"object","properties":{"external_image_id":{"type":["integer","null"],"format":"int32","description":"External image ID (if already registered). If provided without image_ref,\nthe image reference will be fetched from the registered external image."},"health_check_path":{"type":["string","null"],"description":"Optional HTTP health-check path override (e.g. \"/api/healthz\").\nImage deploys can't read `.temps.yaml`, so this sets the path the deployer\nprobes after the container starts and the path the environment's uptime\nmonitor checks. Must start with '/'. When omitted, defaults to \"/\".","example":"/api/healthz"},"image_ref":{"type":["string","null"],"description":"Docker image reference (e.g., \"ghcr.io/org/app:v1.0\")\nRequired if external_image_id is not provided","example":"ghcr.io/myorg/myapp:v1.0"},"metadata":{"description":"Optional deployment metadata"}}},"DeployFromImageUploadQuery":{"type":"object","description":"Query parameters for deploying from an uploaded image tarball","properties":{"health_check_path":{"type":["string","null"],"description":"Optional HTTP health-check path override (e.g. \"/api/healthz\").\nMust start with '/'. When omitted, defaults to \"/\".","example":"/api/healthz"},"tag":{"type":["string","null"],"description":"Tag to apply to the imported image (e.g., \"myapp:v1.0\")\nIf not provided, a unique tag will be generated","example":"myapp:v1.0"}}},"DeployFromStaticRequest":{"type":"object","required":["static_bundle_id"],"properties":{"health_check_path":{"type":["string","null"],"description":"Optional HTTP health-check path override (e.g. \"/api/healthz\").\nStatic deploys can't read `.temps.yaml`, so this sets the path the deployer\nprobes after the container starts and the path the environment's uptime\nmonitor checks. Must start with '/'. When omitted, defaults to \"/\".","example":"/api/healthz"},"metadata":{"description":"Optional deployment metadata"},"static_bundle_id":{"type":"integer","format":"int32","description":"Static bundle ID (required)"}}},"DeploymentConfig":{"type":"object","description":"Deployment configuration shared between projects and environments\n\nThis configuration can be set at the project level (as defaults) and\noverridden at the environment level for specific deployments.\n\nNote: Environment variables are managed separately and are not part of this config.","properties":{"antiAffinity":{"type":"boolean","description":"Anti-affinity: spread replicas across different nodes.\n\nWhen enabled, the scheduler avoids placing two replicas of the same\nenvironment on the same node. If there are fewer eligible nodes than\nreplicas, remaining replicas wrap around (best-effort spreading).\n\nDefaults to `true` — replicas spread by default."},"automaticDeploy":{"type":["boolean","null"],"description":"Enable automatic deployments on git push.\n`None` = inherit from project config; `Some(true/false)` = explicit override.\nStored as JSONB so absent key → `None` (inherit), never silently defaults to false."},"containerExecEnabled":{"type":"boolean","description":"Enable container exec/shell access (disabled by default for security)"},"cpuLimit":{"type":["integer","null"],"format":"int32","description":"CPU limit in microcores, where 1_000_000 = 1 full CPU core\n(e.g., 2_000_000 = 2 CPUs). NOT millicores. `None` = uncapped."},"cpuRequest":{"type":["integer","null"],"format":"int32","description":"CPU request in microcores, where 1_000_000 = 1 full CPU core\n(e.g., 100_000 = 0.1 CPU, 500_000 = 0.5 CPU, 2_000_000 = 2 CPUs).\nNOT millicores — the deployer formats this as `{n}u` and converts\n`n / 1_000_000` cores into Docker nano_cpus."},"crossArchitectureBuilds":{"type":["boolean","null"],"description":"Build one image per architecture the eligible nodes run.\n\n`None`/`false` (the default) builds exactly once, on the control\nplane's native platform — byte-for-byte the behaviour of a\nsingle-architecture cluster. When enabled and the nodes this\ndeployment could land on span more than one architecture, the build\njob produces one image per architecture; the non-native ones go\nthrough the daemon's `platform` option, which requires QEMU binfmt\nhandlers registered on the control plane.\n\n**Opt-in on purpose.** Cross-architecture builds are emulated and\nsubstantially slower, and deriving them from cluster topology would\nmean a single node joining silently changes build behaviour for every\ndeployment in the cluster. It also keeps the decision on operator\nconfig rather than on a value each node reports about itself.\n\n`Option` so an environment inherits the project's setting\n(`None`) or overrides it, matching `automatic_deploy`."},"exposedPort":{"type":["integer","null"],"format":"int32","description":"Port exposed by the container\nIf not specified, will be auto-detected from Docker image or default to 3000"},"idleTimeoutSeconds":{"type":"integer","format":"int32","description":"Seconds of inactivity before containers are stopped in on-demand mode.\nOnly used when `on_demand` is true. Min: 60, Max: 86400 (24h).\nDefault: 300 (5 minutes)."},"memoryLimit":{"type":["integer","null"],"format":"int32","description":"Memory limit in megabytes. Three-state semantics:\n- `None` → inherit the parent layer (env inherits project, project\n inherits the seeded default); used by the settings UI's \"Use default\".\n- `Some(0)` → explicit **uncapped**: stop inheriting and run with no\n memory limit. This is the deliberate escape hatch for dedicated\n workloads, distinct from `None`.\n- `Some(n)` → hard cap of `n` MB.\n\n`merge`/resolution keep `Some(0)` as a present value (it wins precedence\nover a parent cap), and the deployer collapses it to \"no limit\" before\ntalking to Docker."},"memoryRequest":{"type":["integer","null"],"format":"int32","description":"Memory request in megabytes (e.g., 128 = 128MB)"},"onDemand":{"type":"boolean","description":"Enable on-demand mode (scale-to-zero).\nWhen enabled, containers are stopped after `idle_timeout_seconds` of no traffic\nand automatically started when a new request arrives."},"performanceMetricsEnabled":{"type":"boolean","description":"Enable performance metrics collection (speed insights)"},"replicas":{"type":"integer","format":"int32","description":"Number of replicas/instances to run\nDefaults to 1 replica"},"security":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SecurityConfig","description":"Security configuration (headers, rate limiting, attack mode, etc.)\nThese settings inherit and override from parent level (Environment > Project > Global)"}]},"sessionRecordingEnabled":{"type":"boolean","description":"Enable session recording for analytics"},"targetLabels":{"description":"Label selector for node-based scheduling. Replicas are only deployed to\nnodes whose labels match the selector.\n\nMatching rules:\n- **Same key, array value** → OR: node must match any value\n- **Different keys** → AND: node must satisfy all keys\n\nExample: `{\"region\": [\"us\", \"asia\"], \"gpu\": \"true\"}`\n→ (region=us OR region=asia) AND gpu=true\n\nApplied after `target_nodes` filtering (they stack)."},"targetNodes":{"type":["array","null"],"items":{"type":"integer","format":"int32"},"description":"Optional list of node IDs to deploy to. When set, replicas are distributed\nonly across these nodes (round-robin). When None, the scheduler distributes\nacross all active nodes (or deploys locally if no nodes exist)."},"wakeTimeoutSeconds":{"type":"integer","format":"int32","description":"Max seconds to wait for containers to start when waking from on-demand sleep.\nRequests return 503 if exceeded. Default: 30."}}},"DeploymentConfigSnapshot":{"type":"object","description":"Deployment configuration snapshot for deployments\n\nThis extends DeploymentConfig with environment variables to capture\nthe complete state of a deployment at the time it was created.","properties":{"automaticDeploy":{"type":"boolean","description":"Enable automatic deployments on git push"},"containerExecEnabled":{"type":"boolean","description":"Enable container exec/shell access"},"cpuLimit":{"type":["integer","null"],"format":"int32","description":"CPU limit in millicores"},"cpuRequest":{"type":["integer","null"],"format":"int32","description":"CPU request in millicores"},"environmentVariables":{"type":"object","description":"Environment variables used for this deployment","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"exposedPort":{"type":["integer","null"],"format":"int32","description":"Port exposed by the container"},"memoryLimit":{"type":["integer","null"],"format":"int32","description":"Memory limit in megabytes"},"memoryRequest":{"type":["integer","null"],"format":"int32","description":"Memory request in megabytes"},"performanceMetricsEnabled":{"type":"boolean","description":"Enable performance metrics collection"},"replicas":{"type":"integer","format":"int32","description":"Number of replicas"},"sessionRecordingEnabled":{"type":"boolean","description":"Enable session recording"}}},"DeploymentConfiguration":{"type":"object","description":"Deployment-level configuration","required":["image","strategy","env_vars","ports","volumes","network","resources"],"properties":{"build":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/BuildConfiguration","description":"Build configuration (if building from source)"}]},"command":{"type":["array","null"],"items":{"type":"string"},"description":"Command override"},"entrypoint":{"type":["array","null"],"items":{"type":"string"},"description":"Entrypoint override"},"env_vars":{"type":"array","items":{"$ref":"#/components/schemas/EnvironmentVariable"},"description":"Environment variables"},"git":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/GitSourcePlan","description":"Where the application's source code lives, when the source platform\nbuilds from a git repository. Execution uses this to link the temps\nproject to the same repository so the real deployment pipeline can\nclone and build it."}]},"health_check":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/HealthCheckConfiguration","description":"Health check configuration"}]},"image":{"type":"string","description":"Image to deploy"},"network":{"$ref":"#/components/schemas/NetworkConfiguration","description":"Network configuration"},"ports":{"type":"array","items":{"$ref":"#/components/schemas/PortMapping"},"description":"Port mappings"},"resources":{"$ref":"#/components/schemas/ResourceLimits","description":"Resource limits"},"strategy":{"$ref":"#/components/schemas/DeploymentStrategy","description":"Deployment strategy"},"volumes":{"type":"array","items":{"$ref":"#/components/schemas/VolumeMount"},"description":"Volume mounts"},"working_dir":{"type":["string","null"],"description":"Working directory"}}},"DeploymentContainerLogContentResponse":{"type":"object","description":"A single captured container-log dump, including its full text content.","required":["id","container_name","size_bytes","truncated","captured_at","content"],"properties":{"captured_at":{"type":"integer","format":"int64"},"container_name":{"type":"string"},"content":{"type":"string","description":"The captured plain-text log content."},"id":{"type":"integer","format":"int32"},"service_name":{"type":["string","null"]},"size_bytes":{"type":"integer","format":"int64"},"truncated":{"type":"boolean"}}},"DeploymentContainerLogResponse":{"type":"object","description":"Metadata for one captured (historical) container-log dump. Listed on the\ndeployment detail page so a user can pick which past container's logs to read.","required":["id","deployment_id","container_id","container_name","size_bytes","truncated","captured_at"],"properties":{"captured_at":{"type":"integer","format":"int64","description":"Unix epoch milliseconds of when the logs were captured (just before\nteardown). Matches the timestamp convention used by `DeploymentResponse`."},"container_id":{"type":"string"},"container_name":{"type":"string"},"deployment_id":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"node_id":{"type":["integer","null"],"format":"int32"},"service_name":{"type":["string","null"]},"size_bytes":{"type":"integer","format":"int64"},"truncated":{"type":"boolean"}}},"DeploymentContainerLogsListResponse":{"type":"object","description":"The list of captured container-log dumps for a deployment.","required":["logs"],"properties":{"logs":{"type":"array","items":{"$ref":"#/components/schemas/DeploymentContainerLogResponse"}}}},"DeploymentEnvironmentResponse":{"type":"object","required":["id","name","slug","domains"],"properties":{"domains":{"type":"array","items":{"type":"string"}},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"slug":{"type":"string"}}},"DeploymentJobResponse":{"type":"object","required":["id","deployment_id","job_id","job_type","name","status","created_at","updated_at","log_id"],"properties":{"created_at":{"type":"integer","format":"int64"},"dependencies":{},"deployment_id":{"type":"integer","format":"int32"},"description":{"type":["string","null"]},"error_message":{"type":["string","null"]},"execution_order":{"type":["integer","null"],"format":"int32"},"finished_at":{"type":["integer","null"],"format":"int64"},"id":{"type":"integer","format":"int32"},"job_config":{"description":"Internal workflow configuration is intentionally redacted. It can\ncontain legacy plaintext secrets or encrypted secret envelopes."},"job_id":{"type":"string"},"job_type":{"type":"string"},"log_id":{"type":"string"},"name":{"type":"string"},"outputs":{},"started_at":{"type":["integer","null"],"format":"int64"},"status":{"type":"string"},"updated_at":{"type":"integer","format":"int64"}}},"DeploymentJobsResponse":{"type":"object","required":["jobs","total"],"properties":{"jobs":{"type":"array","items":{"$ref":"#/components/schemas/DeploymentJobResponse"}},"total":{"type":"integer","minimum":0}}},"DeploymentListResponse":{"type":"object","required":["deployments","total","page","per_page"],"properties":{"deployments":{"type":"array","items":{"$ref":"#/components/schemas/DeploymentResponse"}},"page":{"type":"integer","format":"int64"},"per_page":{"type":"integer","format":"int64"},"total":{"type":"integer","format":"int64"}}},"DeploymentMetadata":{"type":"object","description":"Deployment metadata - typed information about the deployment","properties":{"buildDurationMs":{"type":["integer","null"],"format":"int64","description":"Build duration in milliseconds"},"builder":{"type":["string","null"],"description":"Docker builder used (e.g., \"nixpacks\", \"dockerfile\")"},"deploymentDurationMs":{"type":["integer","null"],"format":"int64","description":"Deployment duration in milliseconds"},"deploymentSourceType":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SourceType","description":"Source type for THIS specific deployment (for Manual/flexible projects)\nThis allows Manual projects to have deployments via different methods\n(docker_image, static_files, or git) while keeping per-deployment tracking"}]},"dockerfilePath":{"type":["string","null"],"description":"Dockerfile path if using Dockerfile builder"},"externalImageId":{"type":["integer","null"],"format":"int32","description":"External image ID (reference to external_images table)"},"externalImageRef":{"type":["string","null"],"description":"External Docker image reference (for docker_image source type)\ne.g., \"ghcr.io/org/app:v1.0\" or \"docker.io/myapp:sha-abc123\""},"fileCount":{"type":["integer","null"],"format":"int32","description":"Number of files in the build output"},"gitPushEvent":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/GitPushEvent","description":"Git push event that triggered this deployment (if from webhook)"}]},"healthCheckPath":{"type":["string","null"],"description":"Explicit deploy-time HTTP health-check path override.\nImage/static deploys can't read `.temps.yaml`, so this lets the deploy\nrequest set a custom path (e.g. \"/api/healthz\"). When present it takes\npriority over any `.temps.yaml` `health.path` value. Always starts with '/'."},"imageSizeBytes":{"type":["integer","null"],"format":"int64","description":"Total size of the built image in bytes"},"imageUploadedLocally":{"type":"boolean","description":"Whether the image was uploaded directly (via docker save/load) rather than pulled from registry\nWhen true, the PullExternalImageJob is skipped since the image is already loaded locally"},"isRollback":{"type":"boolean","description":"Whether this is a rollback deployment"},"labels":{"type":"array","items":{"type":"string"},"description":"Custom labels/tags for the deployment"},"rolledBackFromId":{"type":["integer","null"],"format":"int32","description":"ID of the deployment this was rolled back from (if applicable)"},"sourceBundleContentType":{"type":["string","null"],"description":"Uploaded source archive content type."},"sourceBundleId":{"type":["integer","null"],"format":"int32","description":"Uploaded source archive ID. Source archives are extracted before the\nregular preset build pipeline and do not require Git metadata."},"sourceBundlePath":{"type":["string","null"],"description":"Uploaded source archive path in the Temps data directory."},"staticBundleContentType":{"type":["string","null"],"description":"Static bundle content type (for proper extraction: application/gzip or application/zip)"},"staticBundleId":{"type":["integer","null"],"format":"int32","description":"Static bundle ID (reference to static_bundles table, for static_files source type)"},"staticBundlePath":{"type":["string","null"],"description":"Static bundle path in blob storage (for static_files source type)"},"uploadedImageId":{"type":["string","null"],"description":"Docker image ID of the locally uploaded image (sha256:...)\nUsed to verify the image exists before deployment"}}},"DeploymentResponse":{"type":"object","required":["id","project_id","environment_id","environment","status","url","created_at","is_current"],"properties":{"branch":{"type":["string","null"]},"cancelled_reason":{"type":["string","null"]},"commit_author":{"type":["string","null"]},"commit_date":{"type":["integer","null"],"format":"int64"},"commit_hash":{"type":["string","null"]},"commit_message":{"type":["string","null"]},"created_at":{"type":"integer","format":"int64"},"deployment_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DeploymentConfigSnapshot","description":"Deployment configuration snapshot (CPU, memory, replicas, environment variables, etc.)"}]},"environment":{"$ref":"#/components/schemas/DeploymentEnvironmentResponse"},"environment_id":{"type":"integer","format":"int32"},"finished_at":{"type":["integer","null"],"format":"int64"},"id":{"type":"integer","format":"int32"},"is_current":{"type":"boolean"},"metadata":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DeploymentMetadata","description":"Deployment metadata (build info, git event, etc.)"}]},"project_id":{"type":"integer","format":"int32"},"screenshot_location":{"type":["string","null"]},"started_at":{"type":["integer","null"],"format":"int64"},"status":{"type":"string"},"tag":{"type":["string","null"]},"url":{"type":"string"}}},"DeploymentStateResponse":{"type":"object","required":["id","state","message"],"properties":{"id":{"type":"integer","format":"int32"},"message":{"type":"string"},"state":{"type":"string"}}},"DeploymentStrategy":{"type":"string","description":"Deployment strategy","enum":["replace","blue-green","rolling"]},"DeploymentTokenListResponse":{"type":"object","required":["tokens","total"],"properties":{"tokens":{"type":"array","items":{"$ref":"#/components/schemas/DeploymentTokenResponse"}},"total":{"type":"integer","format":"int64","minimum":0}}},"DeploymentTokenResponse":{"type":"object","required":["id","project_id","name","token_prefix","is_active","created_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00Z"},"created_by":{"type":["integer","null"],"format":"int32"},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"last_used_at":{"type":["string","null"],"format":"date-time","example":"2024-01-01T00:00:00Z"},"name":{"type":"string"},"permissions":{"type":["array","null"],"items":{"type":"string"}},"project_id":{"type":"integer","format":"int32"},"token_prefix":{"type":"string"}}},"DetectionConfig":{"oneOf":[{"allOf":[{"$ref":"#/components/schemas/StaticParams","description":"v0 (shipping): static threshold comparison of the aggregated value."},{"type":"object","required":["kind"],"properties":{"kind":{"type":"string","enum":["static"]}}}],"description":"v0 (shipping): static threshold comparison of the aggregated value."},{"allOf":[{"$ref":"#/components/schemas/AnomalyParams","description":"Seasonal anomaly band (basic/agile/robust/ewma share this variant — the\nalgorithm is a field, not a new kind). Creation rejected until evaluated."},{"type":"object","required":["kind"],"properties":{"kind":{"type":"string","enum":["anomaly"]}}}],"description":"Seasonal anomaly band (basic/agile/robust/ewma share this variant — the\nalgorithm is a field, not a new kind). Creation rejected until evaluated."},{"allOf":[{"$ref":"#/components/schemas/ForecastParams","description":"Predict a future threshold breach (capacity planning). Stub."},{"type":"object","required":["kind"],"properties":{"kind":{"type":"string","enum":["forecast"]}}}],"description":"Predict a future threshold breach (capacity planning). Stub."},{"allOf":[{"$ref":"#/components/schemas/OutlierParams","description":"Cross-series population outlier (one host misbehaving vs its peers). Stub."},{"type":"object","required":["kind"],"properties":{"kind":{"type":"string","enum":["outlier"]}}}],"description":"Cross-series population outlier (one host misbehaving vs its peers). Stub."},{"allOf":[{"$ref":"#/components/schemas/AutoWatchParams","description":"Watchdog-style self-tuning auto-watch (engine picks bounds). Stub."},{"type":"object","required":["kind"],"properties":{"kind":{"type":"string","enum":["auto_watch"]}}}],"description":"Watchdog-style self-tuning auto-watch (engine picks bounds). Stub."}],"description":"The typed detector definition stored (as jsonb) in\n`metric_alert_rules.detection_config`.\n\nToday only [`DetectionConfig::Static`] is evaluable; the other variants are\nschema-present (so the SDK/UI and storage are already future-shaped) but\nrejected by [`DetectionConfig::validate`] until their evaluator lands. Each is\nthen enabled code-only, with no schema migration."},"DeviceCount":{"type":"object","required":["device_type","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"device_type":{"type":"string"},"percentage":{"type":"number","format":"double"}}},"DigestSections":{"type":"object","description":"Sections that can be included in the weekly digest\nNote: `#[serde(default)]` allows backward compatibility when deserializing\nold data that may have `security` and `resources` fields instead of `projects`","properties":{"deployments":{"type":"boolean","default":true},"errors":{"type":"boolean","default":true},"funnels":{"type":"boolean","default":true},"performance":{"type":"boolean","default":true},"projects":{"type":"boolean","default":true}}},"Direction":{"type":"string","description":"Which side(s) of an anomaly band count as a deviation.","enum":["both","above","below"]},"DisableBlobResponse":{"type":"object","description":"Response after disabling Blob service","required":["success","message"],"properties":{"message":{"type":"string","description":"Human-readable message","example":"Blob service disabled successfully"},"success":{"type":"boolean","description":"Whether the operation succeeded","example":true}}},"DisableKvResponse":{"type":"object","description":"Response after disabling KV service","required":["success","message"],"properties":{"message":{"type":"string","description":"Status message","example":"KV service disabled successfully"},"success":{"type":"boolean","description":"Whether the service was successfully disabled"}}},"DisableMfaRequest":{"type":"object","required":["code"],"properties":{"code":{"type":"string"}}},"DiscoverRequest":{"type":"object","description":"Request to discover workloads","required":["source"],"properties":{"credentials":{"$ref":"#/components/schemas/ImportCredentials","description":"Platform credentials (required for cloud platforms like Vercel, Railway)"},"selector":{"$ref":"#/components/schemas/ImportSelector","description":"Optional selector to filter workloads"},"source":{"$ref":"#/components/schemas/ImportSource","description":"Source to discover from"}}},"DiscoverResponse":{"type":"object","description":"Response with discovered workloads","required":["workloads"],"properties":{"workloads":{"type":"array","items":{"$ref":"#/components/schemas/WorkloadDescriptor"},"description":"Discovered workloads"}}},"DiskInfo":{"type":"object","description":"Disk space information for a single disk/partition","required":["mount_point","total_bytes","used_bytes","available_bytes","usage_percent","file_system"],"properties":{"available_bytes":{"type":"integer","format":"int64","description":"Available space in bytes","minimum":0},"file_system":{"type":"string","description":"File system type (e.g., \"ext4\", \"apfs\")"},"mount_point":{"type":"string","description":"Mount point of the disk"},"total_bytes":{"type":"integer","format":"int64","description":"Total space in bytes","minimum":0},"usage_percent":{"type":"number","format":"double","description":"Usage percentage (0-100)"},"used_bytes":{"type":"integer","format":"int64","description":"Used space in bytes","minimum":0}}},"DiskSpaceAlert":{"type":"object","description":"Alert for a disk that exceeds the threshold","required":["mount_point","usage_percent","threshold_percent","available_bytes","available_human"],"properties":{"available_bytes":{"type":"integer","format":"int64","description":"Available space in bytes","minimum":0},"available_human":{"type":"string","description":"Human-readable available space"},"mount_point":{"type":"string","description":"Mount point of the disk"},"threshold_percent":{"type":"integer","format":"int32","description":"Configured threshold percentage","minimum":0},"usage_percent":{"type":"number","format":"double","description":"Current usage percentage"}}},"DiskSpaceAlertSettings":{"type":"object","description":"Disk space alert settings for monitoring disk usage","properties":{"check_interval_seconds":{"type":"integer","format":"int64","description":"Interval in seconds between disk space checks","default":300,"example":300,"minimum":60},"enabled":{"type":"boolean","description":"Whether disk space alerts are enabled","default":true},"monitor_path":{"type":["string","null"],"description":"Restrict monitoring to the disk backing this path. When unset (the\ndefault), every mounted writable volume is monitored — including\ndedicated volumes such as `/var/lib/docker`.","default":null},"threshold_percent":{"type":"integer","format":"int32","description":"Threshold percentage (0-100) at which to trigger alerts","default":80,"example":80,"maximum":100,"minimum":0}}},"DiskSpaceCheckResult":{"type":"object","description":"Result of a disk space check","required":["checked_at","enabled","threshold_percent","disks","alerts"],"properties":{"alerts":{"type":"array","items":{"$ref":"#/components/schemas/DiskSpaceAlert"},"description":"Disks that meet or exceed the threshold"},"checked_at":{"type":"string","format":"date-time","description":"Timestamp of the check (ISO 8601, UTC)","example":"2026-05-28T12:15:47.609192Z"},"disks":{"type":"array","items":{"$ref":"#/components/schemas/DiskInfo"},"description":"List of all monitored disks"},"enabled":{"type":"boolean","description":"Whether disk space monitoring is enabled in settings"},"threshold_percent":{"type":"integer","format":"int32","description":"Configured alert threshold percentage (0-100)","minimum":0}}},"DnsAckRequest":{"type":"object","required":["applied_generation"],"properties":{"applied_generation":{"type":"integer","format":"int64","description":"Highest generation the agent has actually applied locally."}}},"DnsAckResponse":{"type":"object","required":["node_id","applied_generation","server_generation"],"properties":{"applied_generation":{"type":"integer","format":"int64"},"node_id":{"type":"integer","format":"int32"},"server_generation":{"type":"integer","format":"int64"}}},"DnsChallengeRecordResult":{"type":"object","description":"Result of a single DNS TXT record creation for ACME challenge","required":["name","value","success","message"],"properties":{"message":{"type":"string","description":"Human-readable message about the operation"},"name":{"type":"string","description":"TXT record name (e.g., \"_acme-challenge.example.com\")","example":"_acme-challenge.example.com"},"success":{"type":"boolean","description":"Whether the record was created successfully"},"value":{"type":"string","description":"TXT record value (the ACME challenge token)","example":"abc123..."}}},"DnsChangesResponse":{"type":"object","required":["generation","full_snapshot","records","removed_ids"],"properties":{"full_snapshot":{"type":"boolean","description":"`true` ⇒ replace the local zone with `records`. `false` ⇒ merge\n`records` into the existing zone (and remove `removed_ids`)."},"generation":{"type":"integer","format":"int64","description":"Highest generation included in this response. Agent ACKs this back."},"records":{"type":"array","items":{"$ref":"#/components/schemas/EndpointDto"}},"removed_ids":{"type":"array","items":{"type":"integer","format":"int64"},"description":"IDs the agent should remove from its zone. Always empty in the v1\nprotocol — the resolver reconciles by name on snapshot mode. Kept\nin the wire format so a future tombstone-based protocol doesn't\nrequire a breaking change."}}},"DnsCompletionResponse":{"type":"object","required":["domain","status"],"properties":{"domain":{"type":"string"},"status":{"type":"string"}}},"DnsLookupError":{"type":"object","description":"Error response for DNS lookup failures","required":["error","domain"],"properties":{"domain":{"type":"string","description":"Domain name that failed","example":"nonexistent.com"},"error":{"type":"string","description":"Error message","example":"DNS lookup failed: domain not found"}}},"DnsLookupRequest":{"type":"object","description":"Request to lookup DNS A records for a domain","required":["domain"],"properties":{"domain":{"type":"string","description":"Domain name to lookup","example":"example.com"}}},"DnsLookupResponse":{"type":"object","description":"Response containing DNS A records","required":["domain","records","count","dns_servers"],"properties":{"count":{"type":"integer","description":"Number of records found","example":1,"minimum":0},"dns_servers":{"type":"array","items":{"type":"string"},"description":"DNS servers used for the lookup","example":["8.8.8.8","8.8.4.4"]},"domain":{"type":"string","description":"Domain name that was queried","example":"example.com"},"records":{"type":"array","items":{"type":"string"},"description":"List of A record IP addresses","example":["93.184.216.34"]}}},"DnsProviderCredentials":{"oneOf":[{"type":"object","required":["api_token","type"],"properties":{"account_id":{"type":["string","null"]},"api_token":{"type":"string","example":"your-api-token"},"type":{"type":"string","enum":["cloudflare"]}}},{"type":"object","required":["api_user","api_key","type"],"properties":{"api_key":{"type":"string","example":"your-api-key"},"api_user":{"type":"string","example":"your-username"},"client_ip":{"type":["string","null"]},"sandbox":{"type":"boolean"},"type":{"type":"string","enum":["namecheap"]}}},{"type":"object","required":["access_key_id","secret_access_key","type"],"properties":{"access_key_id":{"type":"string","example":"AKIAIOSFODNN7EXAMPLE"},"region":{"type":["string","null"],"example":"us-east-1"},"secret_access_key":{"type":"string","example":"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"},"session_token":{"type":["string","null"]},"type":{"type":"string","enum":["route53"]}}},{"type":"object","required":["api_token","type"],"properties":{"api_token":{"type":"string","example":"dop_v1_your-token"},"type":{"type":"string","enum":["digitalocean"]}}},{"type":"object","required":["service_account_email","private_key","project_id","type"],"properties":{"private_key":{"type":"string","example":"-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----"},"project_id":{"type":"string","example":"my-gcp-project"},"service_account_email":{"type":"string","example":"dns-admin@myproject.iam.gserviceaccount.com"},"type":{"type":"string","enum":["gcp"]}}},{"type":"object","required":["tenant_id","client_id","client_secret","subscription_id","resource_group","type"],"properties":{"client_id":{"type":"string","example":"00000000-0000-0000-0000-000000000000"},"client_secret":{"type":"string"},"resource_group":{"type":"string","example":"my-resource-group"},"subscription_id":{"type":"string","example":"00000000-0000-0000-0000-000000000000"},"tenant_id":{"type":"string","example":"00000000-0000-0000-0000-000000000000"},"type":{"type":"string","enum":["azure"]}}},{"type":"object","description":"Pebble challtestsrv mock DNS (LOCAL DEV/TEST ONLY)","required":["management_url","type"],"properties":{"management_url":{"type":"string","example":"http://localhost:8055"},"type":{"type":"string","enum":["pebble"]}}}],"description":"DNS provider credentials (API-facing)"},"DnsProviderResponse":{"type":"object","description":"DNS provider response","required":["id","name","provider_type","credentials","is_active","flat_hostnames_supported","created_at","updated_at"],"properties":{"created_at":{"type":"string"},"credentials":{"description":"Masked credentials for display"},"description":{"type":["string","null"]},"flat_hostnames_supported":{"type":"boolean","description":"Whether this provider benefits from the flat hostname mode (e.g. Cloudflare\nUniversal SSL). The UI surfaces/recommends the Flat toggle when true."},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"last_error":{"type":["string","null"]},"last_used_at":{"type":["string","null"]},"name":{"type":"string"},"provider_type":{"type":"string"},"updated_at":{"type":"string"}}},"DnsProviderSettings":{"type":"object","properties":{"cloudflare_api_key":{"type":["string","null"],"default":null},"provider":{"type":"string","default":"manual"}}},"DnsProviderSettingsMasked":{"type":"object","description":"DNS provider settings with masked sensitive fields","required":["provider"],"properties":{"cloudflare_api_key":{"type":["string","null"]},"provider":{"type":"string"}}},"DnsProviderType":{"type":"string","description":"Supported DNS provider types","enum":["cloudflare","namecheap","route53","digitalocean","gcp","azure","manual","pebble"]},"DnsRecord":{"type":"object","description":"A DNS record","required":["zone","name","fqdn","content","ttl"],"properties":{"content":{"$ref":"#/components/schemas/DnsRecordContent","description":"Record content"},"fqdn":{"type":"string","description":"Fully qualified domain name","example":"www.example.com"},"id":{"type":["string","null"],"description":"Provider-specific record ID (if exists)","example":"abc123"},"metadata":{"type":"object","description":"Provider-specific metadata","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"name":{"type":"string","description":"Record name (without zone, e.g., \"www\" or \"@\" for root)","example":"www"},"proxied":{"type":"boolean","description":"Whether this record is proxied (Cloudflare-specific)"},"ttl":{"type":"integer","format":"int32","description":"Time to live in seconds","example":300,"minimum":0},"zone":{"type":"string","description":"Zone/domain this record belongs to","example":"example.com"}}},"DnsRecordChange":{"type":"object","description":"A single DNS record change the Cloudflare sync would make.","required":["action","name","record_type","value"],"properties":{"action":{"type":"string","description":"`\"create\"`, `\"update\"`, or `\"delete\"`."},"name":{"type":"string"},"record_type":{"type":"string","description":"Record type, e.g. `\"A\"` or `\"CNAME\"`."},"value":{"type":"string"}}},"DnsRecordContent":{"oneOf":[{"type":"object","description":"A record - IPv4 address (as string, e.g., \"192.0.2.1\")","required":["value","type"],"properties":{"type":{"type":"string","enum":["A"]},"value":{"type":"object","description":"A record - IPv4 address (as string, e.g., \"192.0.2.1\")","required":["address"],"properties":{"address":{"type":"string","example":"192.0.2.1"}}}}},{"type":"object","description":"AAAA record - IPv6 address (as string, e.g., \"2001:db8::1\")","required":["value","type"],"properties":{"type":{"type":"string","enum":["AAAA"]},"value":{"type":"object","description":"AAAA record - IPv6 address (as string, e.g., \"2001:db8::1\")","required":["address"],"properties":{"address":{"type":"string","example":"2001:db8::1"}}}}},{"type":"object","description":"CNAME record - canonical name","required":["value","type"],"properties":{"type":{"type":"string","enum":["CNAME"]},"value":{"type":"object","description":"CNAME record - canonical name","required":["target"],"properties":{"target":{"type":"string"}}}}},{"type":"object","description":"TXT record - text content","required":["value","type"],"properties":{"type":{"type":"string","enum":["TXT"]},"value":{"type":"object","description":"TXT record - text content","required":["content"],"properties":{"content":{"type":"string"}}}}},{"type":"object","description":"MX record - mail exchange","required":["value","type"],"properties":{"type":{"type":"string","enum":["MX"]},"value":{"type":"object","description":"MX record - mail exchange","required":["priority","target"],"properties":{"priority":{"type":"integer","format":"int32","minimum":0},"target":{"type":"string"}}}}},{"type":"object","description":"NS record - nameserver","required":["value","type"],"properties":{"type":{"type":"string","enum":["NS"]},"value":{"type":"object","description":"NS record - nameserver","required":["nameserver"],"properties":{"nameserver":{"type":"string"}}}}},{"type":"object","description":"SRV record - service","required":["value","type"],"properties":{"type":{"type":"string","enum":["SRV"]},"value":{"type":"object","description":"SRV record - service","required":["priority","weight","port","target"],"properties":{"port":{"type":"integer","format":"int32","minimum":0},"priority":{"type":"integer","format":"int32","minimum":0},"target":{"type":"string"},"weight":{"type":"integer","format":"int32","minimum":0}}}}},{"type":"object","description":"CAA record - certification authority authorization","required":["value","type"],"properties":{"type":{"type":"string","enum":["CAA"]},"value":{"type":"object","description":"CAA record - certification authority authorization","required":["flags","tag","value"],"properties":{"flags":{"type":"integer","format":"int32","minimum":0},"tag":{"type":"string"},"value":{"type":"string"}}}}},{"type":"object","description":"PTR record - pointer","required":["value","type"],"properties":{"type":{"type":"string","enum":["PTR"]},"value":{"type":"object","description":"PTR record - pointer","required":["target"],"properties":{"target":{"type":"string"}}}}}],"description":"DNS record content - varies by record type"},"DnsRecordResponse":{"type":"object","required":["record_type","name","value","status"],"properties":{"name":{"type":"string","description":"DNS record name (host)","example":"temps._domainkey.example.com"},"priority":{"type":["integer","null"],"format":"int32","description":"Priority (for MX records)","example":"10","minimum":0},"record_type":{"type":"string","description":"Record type: TXT, CNAME, MX","example":"TXT"},"status":{"$ref":"#/components/schemas/DnsRecordStatusResponse","description":"Verification status: unknown, verified, pending, failed"},"value":{"type":"string","description":"DNS record value","example":"v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3..."}}},"DnsRecordSetupResult":{"type":"object","description":"Result of a single DNS record creation","required":["record_type","name","success","automatic","message"],"properties":{"automatic":{"type":"boolean","description":"Whether the operation was automatic or manual"},"message":{"type":"string","description":"Human-readable message"},"name":{"type":"string","description":"Record name"},"record_type":{"type":"string","description":"Record type (TXT, CNAME, MX)"},"success":{"type":"boolean","description":"Whether the record was created successfully"}}},"DnsRecordStatusResponse":{"type":"string","description":"DNS record verification status","enum":["unknown","verified","pending","failed"]},"DnsZone":{"type":"object","description":"A DNS zone (domain managed by the provider)","required":["id","name","status","nameservers"],"properties":{"id":{"type":"string","description":"Provider-specific zone ID","example":"zone123"},"metadata":{"type":"object","description":"Provider-specific metadata","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"name":{"type":"string","description":"Zone name (domain)","example":"example.com"},"nameservers":{"type":"array","items":{"type":"string"},"description":"Nameservers for this zone"},"status":{"type":"string","description":"Zone status","example":"active"}}},"DockerComposePresetConfig":{"type":"object","description":"Configuration for Docker Compose deployments.","properties":{"composeOverride":{"type":["string","null"],"description":"User-provided docker-compose.override.yml content."},"composePath":{"type":["string","null"],"description":"Path to the Compose file relative to the project directory."},"publicPorts":{"type":"array","items":{"$ref":"#/components/schemas/ComposePublicPort"},"description":"Compose service ports that should be publicly routed."}}},"DockerRegistrySettings":{"type":"object","properties":{"ca_certificate":{"type":["string","null"],"default":null},"enabled":{"type":"boolean","default":false},"password":{"type":["string","null"],"default":null},"registry_url":{"type":["string","null"],"default":null},"tls_verify":{"type":"boolean","default":true},"username":{"type":["string","null"],"default":null}}},"DockerRegistrySettingsMasked":{"type":"object","description":"Docker registry settings with masked sensitive fields","required":["enabled","tls_verify"],"properties":{"ca_certificate":{"type":["string","null"]},"enabled":{"type":"boolean"},"password":{"type":["string","null"]},"registry_url":{"type":["string","null"]},"tls_verify":{"type":"boolean"},"username":{"type":["string","null"]}}},"DockerfilePresetConfig":{"type":"object","description":"Configuration for Dockerfile preset\nAllows customizing the Dockerfile path and build context for Docker-based deployments","properties":{"buildContext":{"type":["string","null"],"description":"Custom build context path (relative to repository root)\nIf not specified, uses the project's directory setting","example":"./api"},"dockerfilePath":{"type":["string","null"],"description":"Custom Dockerfile path (relative to build context)\nIf not specified, defaults to \"Dockerfile\" in the build context","example":"docker/Dockerfile"},"variant":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DockerfileVariant","description":"Catalog variant. Normally omitted; `custom` selects the generated\nDockerfile compatibility preset."}]}}},"DockerfileVariant":{"type":"string","description":"Catalog variant persisted under the canonical Dockerfile preset.\n\nExisting rows predate this discriminator and therefore deserialize as\n[`DockerfileVariant::File`].","enum":["file","custom"]},"DomainAction":{"type":"string","description":"What to do with a domain during migration","enum":["import","skip"]},"DomainChallengeResponse":{"type":"object","required":["domain","txt_records","status"],"properties":{"domain":{"type":"string"},"status":{"type":"string"},"txt_records":{"type":"array","items":{"$ref":"#/components/schemas/TxtRecord"},"description":"Array of TXT records to add to DNS. For wildcards, multiple records are required."}}},"DomainEnvironmentResponse":{"type":"object","required":["id","name","slug"],"properties":{"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"slug":{"type":"string"}}},"DomainError":{"type":"object","required":["message","code"],"properties":{"code":{"type":"string"},"details":{"type":["string","null"]},"message":{"type":"string"}}},"DomainPlan":{"type":"object","description":"Plan for migrating a single custom domain","required":["domain","environment","action","action_description"],"properties":{"action":{"$ref":"#/components/schemas/DomainAction","description":"What to do with this domain"},"action_description":{"type":"string","description":"Human-readable explanation"},"domain":{"type":"string","description":"Full domain name"},"environment":{"type":"string","description":"Which environment to associate with (\"production\")"},"redirect_to":{"type":["string","null"],"description":"Redirect target (if this is a redirect domain)"},"replacement":{"type":["string","null"],"description":"The temps-side address that replaces this domain when it is skipped.\n\nSource-generated domains (sslip.io / traefik.me / platform subdomains)\nembed the source server's IP and would keep pointing at the old\nmachine — this tells the user where the app will be reachable on\ntemps instead."},"status_code":{"type":["integer","null"],"format":"int32","description":"Redirect status code"}}},"DomainResponse":{"type":"object","required":["id","domain","status","is_wildcard","verification_method","created_at","updated_at"],"properties":{"certificate":{"type":["string","null"],"description":"The PEM-encoded certificate chain (can be displayed in browser or downloaded)"},"created_at":{"type":"integer","format":"int64"},"dns_challenge_token":{"type":["string","null"]},"dns_challenge_value":{"type":["string","null"]},"domain":{"type":"string"},"expiration_time":{"type":["integer","null"],"format":"int64"},"id":{"type":"integer","format":"int32"},"is_wildcard":{"type":"boolean"},"last_error":{"type":["string","null"]},"last_error_type":{"type":["string","null"]},"last_renewed":{"type":["integer","null"],"format":"int64"},"on_demand_backoff_until":{"type":["integer","null"],"format":"int64","description":"On-demand TLS negative-cache deadline (epoch millis), when this hostname's\non-demand HTTP-01 issuance is in backoff after a failure (ADR-018 §4).\n`None` means no active backoff."},"status":{"type":"string"},"updated_at":{"type":"integer","format":"int64"},"verification_method":{"type":"string"}}},"DrainNodeResponse":{"type":"object","required":["id","name","status","affected_environments","message"],"properties":{"affected_environments":{"type":"integer","minimum":0},"id":{"type":"integer","format":"int32"},"message":{"type":"string"},"name":{"type":"string"},"status":{"type":"string"}}},"DrainStatusResponse":{"type":"object","description":"Progress of a node drain operation.","required":["node_id","node_name","status","remaining_containers","drain_complete","can_remove","message"],"properties":{"can_remove":{"type":"boolean","description":"Can the node be safely removed?"},"drain_complete":{"type":"boolean","description":"Whether the drain is complete (all containers migrated)"},"message":{"type":"string"},"node_id":{"type":"integer","format":"int32"},"node_name":{"type":"string"},"remaining_containers":{"type":"integer","description":"Number of containers still on this node","minimum":0},"status":{"type":"string"}}},"DropArchiveUpload":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary"}}},"DropInspectionResponse":{"type":"object","required":["suggestedName","candidates"],"properties":{"candidates":{"type":"array","items":{"$ref":"#/components/schemas/DropPresetCandidate"}},"suggestedName":{"type":"string"}}},"DropOffPoint":{"type":"object","description":"Drop-off point: pages where visitors leave the site","required":["page_path","exit_count","total_views","exit_rate"],"properties":{"exit_count":{"type":"integer","format":"int64","description":"Number of exits from this page"},"exit_rate":{"type":"number","format":"double","description":"Exit rate for this page (exit_count / total_views)"},"page_path":{"type":"string","description":"The page path where visitors drop off"},"total_views":{"type":"integer","format":"int64","description":"Total views of this page"}}},"DropPresetCandidate":{"type":"object","required":["directory","preset","label","confidence","reason","isStatic"],"properties":{"confidence":{"type":"string"},"directory":{"type":"string"},"isStatic":{"type":"boolean"},"label":{"type":"string"},"preset":{"type":"string"},"reason":{"type":"string"}}},"EmailConfig":{"type":"object","required":["smtp_host","smtp_port","username","password","from_address","to_addresses"],"properties":{"accept_invalid_certs":{"type":"boolean"},"from_address":{"type":"string"},"from_name":{"type":["string","null"]},"password":{"type":"string"},"smtp_host":{"type":"string"},"smtp_port":{"type":"integer","format":"int32","minimum":0},"starttls_required":{"type":"boolean"},"tls_mode":{"$ref":"#/components/schemas/TlsMode"},"to_addresses":{"type":"array","items":{"type":"string"}},"username":{"type":"string"}}},"EmailDomainResponse":{"type":"object","required":["id","provider_id","domain","status","created_at","updated_at"],"properties":{"created_at":{"type":"string","example":"2025-12-03T10:30:00Z"},"domain":{"type":"string","example":"updates.example.com"},"id":{"type":"integer","format":"int32"},"last_verified_at":{"type":["string","null"]},"provider_id":{"type":"integer","format":"int32"},"status":{"type":"string","example":"verified"},"updated_at":{"type":"string","example":"2025-12-03T10:30:00Z"},"verification_error":{"type":["string","null"]}}},"EmailDomainWithDnsResponse":{"type":"object","required":["domain","dns_records"],"properties":{"dns_records":{"type":"array","items":{"$ref":"#/components/schemas/DnsRecordResponse"}},"domain":{"$ref":"#/components/schemas/EmailDomainResponse"}}},"EmailProviderResponse":{"type":"object","required":["id","name","provider_type","region","is_active","credentials","created_at","updated_at"],"properties":{"created_at":{"type":"string","example":"2025-12-03T10:30:00Z"},"credentials":{"description":"Masked credentials for display"},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"name":{"type":"string","example":"My AWS SES"},"provider_type":{"$ref":"#/components/schemas/EmailProviderTypeRoute"},"region":{"type":"string","example":"us-east-1"},"sns_topic_arn":{"type":["string","null"]},"updated_at":{"type":"string","example":"2025-12-03T10:30:00Z"}}},"EmailProviderTypeRoute":{"type":"string","enum":["ses","scaleway","smtp"]},"EmailRequest":{"type":"object","description":"Request body carrying just an email address (password-reset request).","required":["email"],"properties":{"email":{"type":"string"}}},"EmailResponse":{"type":"object","required":["id","from_address","to_addresses","subject","status","created_at","track_opens","track_clicks","open_count","click_count"],"properties":{"bcc_addresses":{"type":["array","null"],"items":{"type":"string"}},"cc_addresses":{"type":["array","null"],"items":{"type":"string"}},"click_count":{"type":"integer","format":"int32","description":"Number of times links in the email were clicked"},"created_at":{"type":"string","example":"2025-12-03T10:30:00Z"},"domain_id":{"type":["integer","null"],"format":"int32"},"error_message":{"type":["string","null"]},"first_clicked_at":{"type":["string","null"],"description":"When a link was first clicked"},"first_opened_at":{"type":["string","null"],"description":"When the email was first opened"},"from_address":{"type":"string","example":"hello@updates.example.com"},"from_name":{"type":["string","null"]},"headers":{"type":["object","null"],"additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"html_body":{"type":["string","null"]},"id":{"type":"string","example":"550e8400-e29b-41d4-a716-446655440000"},"open_count":{"type":"integer","format":"int32","description":"Number of times the email was opened"},"project_id":{"type":["integer","null"],"format":"int32"},"provider_message_id":{"type":["string","null"]},"reply_to":{"type":["string","null"]},"sent_at":{"type":["string","null"]},"status":{"type":"string","example":"sent"},"subject":{"type":"string"},"tags":{"type":["array","null"],"items":{"type":"string"}},"text_body":{"type":["string","null"]},"to_addresses":{"type":"array","items":{"type":"string"}},"track_clicks":{"type":"boolean","description":"Whether click tracking is enabled"},"track_opens":{"type":"boolean","description":"Whether open tracking is enabled"},"tracked_html_body":{"type":["string","null"],"description":"The final HTML sent to the provider (with tracking pixel and rewritten links)"}}},"EmailStatsResponse":{"type":"object","required":["total","sent","failed","queued","captured"],"properties":{"captured":{"type":"integer","format":"int64","description":"Emails captured without sending (Mailhog mode - no provider configured)","minimum":0},"failed":{"type":"integer","format":"int64","minimum":0},"queued":{"type":"integer","format":"int64","minimum":0},"sent":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"EmailStatusResponse":{"type":"object","required":["email_configured","password_reset_available","oidc_providers"],"properties":{"email_configured":{"type":"boolean"},"oidc_providers":{"type":"array","items":{"$ref":"#/components/schemas/OidcProviderSummary"}},"password_reset_available":{"type":"boolean"}}},"EmailTrackingResponse":{"type":"object","description":"Email tracking summary","required":["email_id","track_opens","track_clicks","open_count","click_count","unique_opens","unique_clicks","links"],"properties":{"click_count":{"type":"integer","format":"int32"},"email_id":{"type":"string"},"first_clicked_at":{"type":["string","null"]},"first_opened_at":{"type":["string","null"]},"links":{"type":"array","items":{"$ref":"#/components/schemas/TrackedLinkResponse"}},"open_count":{"type":"integer","format":"int32"},"track_clicks":{"type":"boolean"},"track_opens":{"type":"boolean"},"unique_clicks":{"type":"integer","format":"int64","minimum":0},"unique_opens":{"type":"integer","format":"int64","minimum":0}}},"EmailTrackingSetupResponse":{"type":"object","description":"Result of the one-click AWS-side event-tracking setup.","required":["topic_arn","webhook_url","subscription_requested","event_destination_attached"],"properties":{"event_destination_attached":{"type":"boolean","description":"The SESv2 event destination (bounce/complaint/delivery) is attached\nto the `temps-tracking` configuration set."},"subscription_requested":{"type":"boolean","description":"The webhook subscription was requested; SNS confirms it\nasynchronously through the webhook itself."},"topic_arn":{"type":"string","example":"arn:aws:sns:us-east-1:123456789012:temps-email-events-1"},"webhook_url":{"type":"string"}}},"EmailTrackingStatusResponse":{"type":"object","description":"Live status of the SES event-tracking pipeline for one provider.","required":["webhook_url","supports_event_tracking"],"properties":{"last_event_at":{"type":["string","null"],"description":"Most recent delivered/bounced/complained event recorded for an email\nsent through this provider. `null` means no provider feedback has\narrived yet.","example":"2026-07-18T10:31:00Z"},"sns_topic_arn":{"type":["string","null"]},"subscription_confirmed_at":{"type":["string","null"],"description":"When the SNS subscription for the current topic was confirmed.\n`null` with a topic set usually means the subscription is still\npending — most often because the endpoint was subscribed before the\ntopic ARN was saved here.","example":"2026-07-18T10:30:00Z"},"supports_event_tracking":{"type":"boolean","description":"Only SES providers support SNS event tracking."},"webhook_url":{"type":"string","description":"Public webhook endpoint SNS must deliver events to.","example":"https://temps.example.com/api/t/webhook/ses"}}},"EmbeddingData":{"type":"object","required":["object","embedding","index"],"properties":{"embedding":{"type":"array","items":{"type":"number","format":"double"}},"index":{"type":"integer","format":"int32"},"object":{"type":"string"}}},"EmbeddingInput":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]},"EmbeddingRequest":{"type":"object","required":["model","input"],"properties":{"dimensions":{"type":["integer","null"],"format":"int32"},"encoding_format":{"type":["string","null"]},"input":{"$ref":"#/components/schemas/EmbeddingInput"},"model":{"type":"string"}}},"EmbeddingResponse":{"type":"object","required":["object","data","model","usage"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/EmbeddingData"}},"model":{"type":"string"},"object":{"type":"string"},"usage":{"$ref":"#/components/schemas/EmbeddingUsage"}}},"EmbeddingUsage":{"type":"object","required":["prompt_tokens","total_tokens"],"properties":{"prompt_tokens":{"type":"integer","format":"int64"},"total_tokens":{"type":"integer","format":"int64"}}},"EnableBlobRequest":{"type":"object","description":"Request to enable Blob service","properties":{"docker_image":{"type":["string","null"],"description":"Docker image to use (optional, defaults to RustFS)","example":"ghcr.io/rustfs/rustfs:0.5.0"},"root_password":{"type":["string","null"],"description":"Root password for S3 access"},"root_user":{"type":["string","null"],"description":"Root user for S3 access"}}},"EnableBlobResponse":{"type":"object","description":"Response after enabling Blob service","required":["success","message","status"],"properties":{"message":{"type":"string","description":"Human-readable message","example":"Blob service enabled successfully"},"status":{"$ref":"#/components/schemas/BlobStatusResponse","description":"Current status"},"success":{"type":"boolean","description":"Whether the operation succeeded","example":true}}},"EnableKvRequest":{"type":"object","description":"Request to enable the KV service","properties":{"docker_image":{"type":["string","null"],"description":"Docker image to use (optional, uses default if not provided)","example":"gotempsh/redis-walg:8-bookworm"},"max_memory":{"type":["string","null"],"description":"Maximum memory allocation (e.g., \"256mb\", \"1gb\")","example":"256mb"},"persistence":{"type":"boolean","description":"Enable data persistence"}}},"EnableKvResponse":{"type":"object","description":"Response after enabling KV service","required":["success","message","status"],"properties":{"message":{"type":"string","description":"Status message","example":"KV service enabled successfully"},"status":{"$ref":"#/components/schemas/KvStatusResponse","description":"Current service status"},"success":{"type":"boolean","description":"Whether the service was successfully enabled"}}},"EnablePgStatStatementsResponse":{"type":"object","description":"Response for the enable pg_stat_statements endpoint.","required":["message"],"properties":{"message":{"type":"string","description":"Human-readable message confirming the action."}}},"EndpointDto":{"type":"object","description":"One DNS record on the wire. Mirrors `service_endpoints::Model` but\nkeeps the API stable across entity evolution. `target_ip` is a string\n(v4 or v6 literal, or CNAME target hostname) parsed by the resolver.","required":["id","fqdn","record_type","ttl","owner_kind","owner_id","generation"],"properties":{"fqdn":{"type":"string"},"generation":{"type":"integer","format":"int64"},"id":{"type":"integer","format":"int64"},"node_id":{"type":["integer","null"],"format":"int32"},"owner_id":{"type":"integer","format":"int64"},"owner_kind":{"type":"string"},"record_type":{"type":"string"},"target_ip":{"type":["string","null"]},"target_port":{"type":["integer","null"],"format":"int32"},"ttl":{"type":"integer","format":"int32"}}},"EnqueuedJob":{"type":"object","description":"A single job that was successfully enqueued during a fan-out run.","required":["backup_id","job_id","engine"],"properties":{"backup_id":{"type":"integer","format":"int32","description":"FK to `backups.id` for this job."},"engine":{"type":"string","description":"Engine key (e.g. `\"control_plane\"`, `\"redis\"`, `\"postgres_pgdump\"`)."},"job_id":{"type":"integer","format":"int64","description":"FK to `backup_jobs.id` for this job."},"target_service_id":{"type":["integer","null"],"format":"int32","description":"FK to `external_services.id` when this is an external-service job.\n`None` for the control-plane job."}}},"EnrichVisitorRequest":{"type":"object","required":["custom_data"],"properties":{"custom_data":{"type":"object"}}},"EnrichVisitorResponse":{"type":"object","required":["success","visitor_id","message"],"properties":{"message":{"type":"string"},"success":{"type":"boolean"},"visitor_id":{"type":"string"}}},"EnrollmentTokenInfo":{"type":"object","required":["id","expires_at","used_count","max_uses","created_at"],"properties":{"bound_node_name":{"type":["string","null"]},"created_at":{"type":"string"},"expires_at":{"type":"string"},"id":{"type":"integer","format":"int32"},"max_uses":{"type":"integer","format":"int32"},"used_count":{"type":"integer","format":"int32"}}},"EnrollmentTokenListResponse":{"type":"object","required":["tokens"],"properties":{"tokens":{"type":"array","items":{"$ref":"#/components/schemas/EnrollmentTokenInfo"}}}},"EntityInfoResponse":{"type":"object","required":["container_path","entity","entity_type","fields"],"properties":{"container_path":{"type":"array","items":{"type":"string"},"description":"Full container path","example":["mydb","public"]},"entity":{"type":"string","description":"Entity name","example":"users"},"entity_type":{"type":"string","description":"Entity type","example":"table"},"fields":{"type":"array","items":{"$ref":"#/components/schemas/FieldResponse"},"description":"Field definitions"},"metadata":{"description":"Additional metadata (content_type, last_modified, etag, etc.)"},"row_count":{"type":["integer","null"],"description":"Approximate row count (for tables/collections)","example":1234,"minimum":0},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Size in bytes (for objects/files)","example":1048576,"minimum":0},"sort_schema":{"description":"JSON Schema for sort options (if supported)"}}},"EntityResponse":{"type":"object","required":["name","entity_type"],"properties":{"entity_type":{"type":"string","description":"Entity type (table, view, collection, etc.)","example":"table"},"name":{"type":"string","description":"Entity name (table/collection)","example":"users"},"row_count":{"type":["integer","null"],"description":"Approximate row count","example":1234,"minimum":0},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Size in bytes (for files/objects)","example":1048576,"minimum":0}}},"EnvVarInput":{"type":"object","description":"Input for environment variable","required":["name","value"],"properties":{"name":{"type":"string","description":"Variable name"},"value":{"type":"string","description":"Variable value"}}},"EnvVarIntegrationInfo":{"type":"object","required":["service_id","service_name","service_type","service_updated_at"],"properties":{"service_id":{"type":"integer","format":"int32"},"service_name":{"type":"string"},"service_slug":{"type":["string","null"]},"service_type":{"type":"string"},"service_updated_at":{"type":"string"}}},"EnvVarResponse":{"type":"object","description":"Environment variable with masked sensitive values","required":["key","value","is_masked"],"properties":{"is_masked":{"type":"boolean","description":"Whether this is a sensitive/masked value"},"key":{"type":"string"},"value":{"type":"string"}}},"EnvVarTemplateResponse":{"type":"object","description":"Environment variable template response","required":["name","required"],"properties":{"default":{"type":["string","null"],"description":"Default value if not provided by user"},"default_generator":{"type":["string","null"],"description":"Frontend-side generator hint for the default value\n(e.g. `app_url`, `random_secret`, `random_hex_32`)"},"description":{"type":["string","null"],"description":"Description of what this variable is used for"},"example":{"type":["string","null"],"description":"Example value for documentation"},"name":{"type":"string","description":"Name of the environment variable"},"required":{"type":"boolean","description":"Whether this variable is required"}}},"EnvironmentConfiguration":{"type":"object","description":"Environment-level configuration","required":["name","subdomain","resources"],"properties":{"name":{"type":"string","description":"Environment name"},"resources":{"$ref":"#/components/schemas/ResourceLimits","description":"Resource limits for environment"},"subdomain":{"type":"string","description":"Proposed subdomain"}}},"EnvironmentDomainResponse":{"type":"object","required":["id","environment_id","domain","created_at","url"],"properties":{"created_at":{"type":"integer","format":"int64"},"domain":{"type":"string"},"environment_id":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"url":{"type":"string","description":"Full URL for this domain (e.g., https://buildtolearndev-production.example.com)","example":"https://buildtolearndev-production.example.com"}}},"EnvironmentInfo":{"type":"object","required":["id","name","main_url"],"properties":{"current_deployment_id":{"type":["integer","null"],"format":"int32"},"id":{"type":"integer","format":"int32"},"main_url":{"type":"string"},"name":{"type":"string"}}},"EnvironmentResponse":{"type":"object","required":["id","project_id","name","slug","main_url","subdomain","created_at","updated_at","is_preview","protected","sleeping"],"properties":{"attack_mode":{"type":["boolean","null"],"description":"Per-environment CAPTCHA attack-mode override.\n`null` means inherit the project-level `attack_mode`; `true`/`false`\nexplicitly enable/disable the challenge for this environment. Always\nserialized (NOT skipped) so the UI can distinguish `null` from `false`."},"branch":{"type":["string","null"]},"created_at":{"type":"integer","format":"int64"},"current_deployment_id":{"type":["integer","null"],"format":"int32"},"deployment_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DeploymentConfig","description":"Deployment configuration for this environment (overrides project-level config)"}]},"estimated_sleep_at":{"type":["integer","null"],"format":"int64","description":"Estimated time (epoch millis) when the environment will go to sleep\nbased on last activity + idle timeout. NULL when sleeping or on-demand disabled."},"force_https":{"type":["boolean","null"],"description":"Per-environment HTTP→HTTPS redirect override.\n`null` means inherit the proxy default (redirect only when the host has\nan active TLS certificate); `true` always redirects plain HTTP for this\nenvironment, `false` never does. Always serialized (NOT skipped) so the\nUI can distinguish `null` from `false`."},"id":{"type":"integer","format":"int32"},"is_preview":{"type":"boolean","description":"Indicates if this is a preview environment (auto-created per branch)\nFor preview environments, 'branch' contains the feature branch name"},"last_activity_at":{"type":["integer","null"],"format":"int64","description":"Last proxied request timestamp (epoch millis) for on-demand environments.\nNULL when on-demand is disabled or no traffic has been received yet."},"main_url":{"type":"string"},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"protected":{"type":"boolean","description":"When true, git pushes do NOT auto-deploy to this environment.\nDeployments must be promoted from another environment."},"sleeping":{"type":"boolean","description":"When true, the environment's containers are currently stopped due to\ninactivity (on-demand mode) and will start on the next request."},"slug":{"type":"string"},"subdomain":{"type":"string","description":"The host label stored for this environment (e.g.\n`myproject-production`). This is the prefix that is combined with the\nplatform's preview domain at request time to produce `main_url`. Edit\nthis via the rename-subdomain endpoint, not the full URL."},"updated_at":{"type":"integer","format":"int64"}}},"EnvironmentVariable":{"type":"object","description":"Environment variable","required":["key","value","is_secret"],"properties":{"is_secret":{"type":"boolean","description":"Whether this is a secret (should be encrypted)"},"key":{"type":"string","description":"Variable name"},"source_description":{"type":["string","null"],"description":"Where this env var originates from (for traceability)"},"value":{"type":"string","description":"Variable value (may be redacted for secrets)"}}},"EnvironmentVariableInfo":{"type":"object","required":["name","value","sensitive"],"properties":{"name":{"type":"string"},"sensitive":{"type":"boolean","description":"Whether this variable contains sensitive data (passwords, keys, tokens)","example":false},"value":{"type":"string"}}},"EnvironmentVariableResponse":{"type":"object","required":["id","key","created_at","updated_at","environments","include_in_preview","is_secret"],"properties":{"created_at":{"type":"integer","format":"int64"},"environments":{"type":"array","items":{"$ref":"#/components/schemas/EnvironmentInfo"}},"id":{"type":"integer","format":"int32"},"include_in_preview":{"type":"boolean","description":"Include this environment variable in preview environments"},"is_secret":{"type":"boolean","description":"Whether the variable is a write-only secret. Secrets always have\n`value: None` in responses."},"key":{"type":"string"},"updated_at":{"type":"integer","format":"int64"},"value":{"type":["string","null"],"description":"Plaintext value for non-secret vars (or `\"***\"` mask for list responses).\n`None` for secret vars — secrets are write-only."}}},"EnvironmentVariableValueResponse":{"type":"object","required":["value"],"properties":{"value":{"type":"string"}}},"ErrorDashboardStatsQuery":{"type":"object","required":["start_time","end_time"],"properties":{"compare_to_previous":{"type":["boolean","null"]},"end_time":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"start_time":{"type":"string","format":"date-time"}}},"ErrorDashboardStatsResponse":{"type":"object","required":["total_errors","total_errors_previous_period","total_errors_change_percent","error_groups","error_groups_previous_period","start_time","end_time"],"properties":{"comparison_end_time":{"type":["string","null"],"format":"date-time"},"comparison_start_time":{"type":["string","null"],"format":"date-time"},"end_time":{"type":"string","format":"date-time"},"error_groups":{"type":"integer","format":"int64"},"error_groups_previous_period":{"type":"integer","format":"int64"},"start_time":{"type":"string","format":"date-time"},"total_errors":{"type":"integer","format":"int64"},"total_errors_change_percent":{"type":"number","format":"double"},"total_errors_previous_period":{"type":"integer","format":"int64"}}},"ErrorEventResponse":{"type":"object","required":["id","error_group_id","timestamp","created_at"],"properties":{"created_at":{"type":"string"},"data":{"description":"Full error event data (contains raw Sentry event or custom error data)"},"error_group_id":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int64"},"source":{"type":["string","null"],"description":"Source of the error event (e.g., \"sentry\", \"custom\", \"bugsnag\")"},"timestamp":{"type":"string"}}},"ErrorGroupResponse":{"type":"object","required":["id","title","error_type","first_seen","last_seen","total_count","status","project_id","created_at","updated_at"],"properties":{"assigned_to":{"type":["string","null"]},"created_at":{"type":"string"},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"error_type":{"type":"string"},"first_seen":{"type":"string"},"id":{"type":"integer","format":"int32"},"last_seen":{"type":"string"},"message_template":{"type":["string","null"]},"project_id":{"type":"integer","format":"int32"},"status":{"type":"string"},"title":{"type":"string"},"total_count":{"type":"integer","format":"int32"},"updated_at":{"type":"string"},"visitor_id":{"type":["integer","null"],"format":"int32"}}},"ErrorGroupStatsResponse":{"type":"object","required":["total_groups","unresolved_groups","resolved_groups","ignored_groups"],"properties":{"ignored_groups":{"type":"integer","format":"int64"},"resolved_groups":{"type":"integer","format":"int64"},"total_groups":{"type":"integer","format":"int64"},"unresolved_groups":{"type":"integer","format":"int64"}}},"ErrorResponse":{"type":"object","required":["error"],"properties":{"details":{"type":["string","null"]},"error":{"type":"string"}}},"ErrorRow":{"type":"object","required":["id","ts","error_group_id","fingerprint","error_class","stacktrace_preview","stacktrace_truncated"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"error_class":{"type":"string"},"error_group_id":{"type":"integer","format":"int32"},"fingerprint":{"type":"string"},"id":{"type":"integer","format":"int64"},"message":{"type":["string","null"]},"stacktrace_preview":{},"stacktrace_truncated":{"type":"boolean"},"trace_id":{"type":["string","null"]},"ts":{"type":"string","format":"date-time"}}},"ErrorTimeSeriesDataResponse":{"type":"object","required":["timestamp","count"],"properties":{"count":{"type":"integer","format":"int64"},"timestamp":{"type":"string"}}},"ErrorTimeSeriesQuery":{"type":"object","required":["start_time","end_time"],"properties":{"bucket":{"type":"string","description":"Time bucket size (e.g., \"1h\", \"15m\", \"1d\", \"1 hour\", \"30 minutes\")","example":"1h"},"end_time":{"type":"string","format":"date-time"},"start_time":{"type":"string","format":"date-time"}}},"EventActivityBucket":{"type":"object","description":"Time bucket data point for event activity graph","required":["timestamp","count","unique_visitors"],"properties":{"count":{"type":"integer","format":"int64","description":"Number of event occurrences in this bucket"},"timestamp":{"type":"string","description":"Timestamp for this bucket (ISO 8601)"},"unique_visitors":{"type":"integer","format":"int64","description":"Number of unique visitors in this bucket"}}},"EventBreakdown":{"type":"string","enum":["country","region","city"]},"EventBrowserStats":{"type":"object","description":"Browser stats for an event","required":["browser","count","percentage"],"properties":{"browser":{"type":"string","description":"Browser name"},"count":{"type":"integer","format":"int64","description":"Number of event occurrences from this browser"},"percentage":{"type":"number","format":"double","description":"Percentage of total events"}}},"EventCount":{"type":"object","required":["event_name","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"event_name":{"type":"string"},"percentage":{"type":"number","format":"double"}}},"EventCountryStats":{"type":"object","description":"Country stats for an event","required":["country","count","percentage"],"properties":{"count":{"type":"integer","format":"int64","description":"Number of event occurrences from this country"},"country":{"type":"string","description":"Country name"},"country_code":{"type":["string","null"],"description":"ISO country code (2-letter)"},"percentage":{"type":"number","format":"double","description":"Percentage of total events"}}},"EventDetailQuery":{"type":"object","description":"Query parameters for event detail analytics","required":["event_name","project_id","start_date","end_date"],"properties":{"bucket_interval":{"type":["string","null"],"description":"Bucket interval for time series: 'hour', 'day', 'week', 'month' (default: auto)"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"event_name":{"type":"string","description":"The specific event name to get details for"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"EventDetailResponse":{"type":"object","description":"Summary response for a specific event's analytics","required":["event_name","total_count","unique_visitors","unique_sessions","activity_over_time","referrers","countries","browsers","bucket_interval"],"properties":{"activity_over_time":{"type":"array","items":{"$ref":"#/components/schemas/EventActivityBucket"},"description":"Time series data for event activity graph"},"browsers":{"type":"array","items":{"$ref":"#/components/schemas/EventBrowserStats"},"description":"Browser distribution of visitors who triggered this event"},"bucket_interval":{"type":"string","description":"Bucket interval used for time series ('hour', 'day', etc.)"},"countries":{"type":"array","items":{"$ref":"#/components/schemas/EventCountryStats"},"description":"Geographic distribution of visitors who triggered this event"},"event_name":{"type":"string","description":"The event name being analyzed"},"referrers":{"type":"array","items":{"$ref":"#/components/schemas/EventReferrerStats"},"description":"Top referrer hostnames for visitors who triggered this event"},"total_count":{"type":"integer","format":"int64","description":"Total number of times this event was triggered in the date range"},"unique_sessions":{"type":"integer","format":"int64","description":"Number of unique sessions where this event occurred"},"unique_visitors":{"type":"integer","format":"int64","description":"Number of unique visitors who triggered this event"}}},"EventEntriesQuery":{"type":"object","description":"Query parameters for the raw event entries list","required":["event_name","project_id","start_date","end_date"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"event_name":{"type":"string","description":"The specific event name to list occurrences for"},"page":{"type":["integer","null"],"format":"int64","description":"Page number (1-based, default: 1)","minimum":0},"per_page":{"type":["integer","null"],"format":"int64","description":"Items per page (default: 20, max: 100)","minimum":0},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"EventEntriesResponse":{"type":"object","description":"Paginated response for raw event entries","required":["event_name","total_count","page","per_page","entries"],"properties":{"entries":{"type":"array","items":{"$ref":"#/components/schemas/EventEntryInfo"},"description":"Individual event occurrences, most recent first"},"event_name":{"type":"string","description":"The event name"},"page":{"type":"integer","format":"int64","description":"Current page number","minimum":0},"per_page":{"type":"integer","format":"int64","description":"Items per page","minimum":0},"total_count":{"type":"integer","format":"int64","description":"Total number of occurrences of this event in the date range"}}},"EventEntryInfo":{"type":"object","description":"A single raw occurrence of an event, including its custom JSON properties","required":["id","timestamp","page_path","href"],"properties":{"browser":{"type":["string","null"],"description":"Browser name"},"city":{"type":["string","null"],"description":"City of the visitor at the time of the event"},"country":{"type":["string","null"],"description":"Country of the visitor at the time of the event"},"country_code":{"type":["string","null"],"description":"ISO country code (2-letter)"},"device_type":{"type":["string","null"],"description":"Device type (Desktop, Mobile, Tablet)"},"href":{"type":"string","description":"Full URL where the event was triggered"},"id":{"type":"integer","format":"int64","description":"Event row ID"},"page_path":{"type":"string","description":"Page path where the event was triggered"},"props":{"type":["object","null"],"description":"Custom event properties as JSON (null when the event carried no data)"},"session_id":{"type":["string","null"],"description":"Session ID the event belongs to (if any)"},"timestamp":{"type":"string","format":"date-time","description":"When the event occurred"},"visitor_id":{"type":["integer","null"],"format":"int32","description":"Visitor numeric ID (if known)"},"visitor_uuid":{"type":["string","null"],"description":"Visitor UUID (if known)"}}},"EventKind":{"type":"string","description":"Tag enum for filter parameters and routing. Matches the variant\ndiscriminator used by `ObservabilityEvent`.","enum":["request","span","error","revenue"]},"EventMetricsPayload":{"type":"object","required":["event_name","event_data","request_path","request_query"],"properties":{"cls":{"type":["number","null"],"format":"float","description":"Cumulative Layout Shift (score)"},"event_data":{},"event_name":{"type":"string"},"fcp":{"type":["number","null"],"format":"float","description":"First Contentful Paint (milliseconds)"},"fid":{"type":["number","null"],"format":"float","description":"First Input Delay (milliseconds)"},"inp":{"type":["number","null"],"format":"float","description":"Interaction to Next Paint (milliseconds)"},"language":{"type":["string","null"]},"lcp":{"type":["number","null"],"format":"float","description":"Largest Contentful Paint (milliseconds)"},"page_title":{"type":["string","null"]},"referrer":{"type":["string","null"],"description":"Referrer URL (falls back to Referer header if not provided)"},"request_path":{"type":"string"},"request_query":{"type":"string"},"screen_height":{"type":["integer","null"],"format":"int32","minimum":0},"screen_width":{"type":["integer","null"],"format":"int32","minimum":0},"ttfb":{"type":["number","null"],"format":"float","description":"Time to First Byte (milliseconds)"},"viewport_height":{"type":["integer","null"],"format":"int32","minimum":0},"viewport_width":{"type":["integer","null"],"format":"int32","minimum":0}}},"EventReferrerStats":{"type":"object","description":"Referrer stats for an event","required":["referrer","count","percentage"],"properties":{"count":{"type":"integer","format":"int64","description":"Number of event occurrences from this referrer"},"percentage":{"type":"number","format":"double","description":"Percentage of total events"},"referrer":{"type":"string","description":"Referrer hostname or \"Direct\""}}},"EventTimeline":{"type":"object","required":["date","count"],"properties":{"count":{"type":"integer","format":"int64"},"date":{"type":"string","format":"date-time"}}},"EventTimelineQuery":{"type":"object","required":["start_date","end_date"],"properties":{"aggregation_level":{"$ref":"#/components/schemas/AggregationLevel","description":"Aggregation level: events (raw count), sessions (unique sessions), or visitors (unique visitors)"},"bucket_size":{"type":["string","null"],"description":"Bucket size: hour, day, or week (auto-detected if not specified)"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"event_name":{"type":["string","null"]},"start_date":{"type":"string","format":"date-time"}}},"EventType":{"type":"object","required":["name","count"],"properties":{"count":{"type":"integer","format":"int64"},"name":{"type":"string"}}},"EventTypeBreakdown":{"type":"object","required":["event_type","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"event_type":{"type":"string"},"percentage":{"type":"number","format":"double"}}},"EventTypeBreakdownQuery":{"type":"object","required":["start_date","end_date"],"properties":{"aggregation_level":{"$ref":"#/components/schemas/AggregationLevel","description":"Aggregation level: events (raw count), sessions (unique sessions), or visitors (unique visitors)"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"EventTypeResponse":{"type":"object","required":["event_type","description","category"],"properties":{"category":{"type":"string"},"description":{"type":"string"},"event_type":{"type":"string"}}},"EventTypesResponse":{"type":"object","required":["events","total","page","page_size"],"properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/EventType"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"EventVisitorInfo":{"type":"object","description":"A visitor who triggered a specific event","required":["visitor_id","visitor_uuid","event_count","first_triggered","last_triggered"],"properties":{"browser":{"type":["string","null"],"description":"Browser name"},"city":{"type":["string","null"],"description":"Visitor's city"},"country":{"type":["string","null"],"description":"Visitor's country"},"country_code":{"type":["string","null"],"description":"Visitor's country code"},"device_type":{"type":["string","null"],"description":"Device type (Desktop, Mobile, Tablet)"},"event_count":{"type":"integer","format":"int64","description":"Number of times this visitor triggered the event"},"first_triggered":{"type":"string","format":"date-time","description":"When the visitor first triggered the event in the date range"},"last_triggered":{"type":"string","format":"date-time","description":"When the visitor last triggered the event in the date range"},"referrer_hostname":{"type":["string","null"],"description":"Referrer hostname for the event"},"visitor_id":{"type":"integer","format":"int32","description":"Visitor numeric ID"},"visitor_uuid":{"type":"string","description":"Visitor UUID"}}},"EventVisitorsQuery":{"type":"object","description":"Query parameters for event visitors list","required":["event_name","project_id","start_date","end_date"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"event_name":{"type":"string","description":"The specific event name to list visitors for"},"page":{"type":["integer","null"],"format":"int64","description":"Page number (1-based, default: 1)","minimum":0},"per_page":{"type":["integer","null"],"format":"int64","description":"Items per page (default: 20, max: 100)","minimum":0},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"EventVisitorsResponse":{"type":"object","description":"Paginated response for event visitors","required":["event_name","total_count","page","per_page","visitors"],"properties":{"event_name":{"type":"string","description":"The event name"},"page":{"type":"integer","format":"int64","description":"Current page number","minimum":0},"per_page":{"type":"integer","format":"int64","description":"Items per page","minimum":0},"total_count":{"type":"integer","format":"int64","description":"Total number of unique visitors who triggered this event"},"visitors":{"type":"array","items":{"$ref":"#/components/schemas/EventVisitorInfo"},"description":"Individual visitors who triggered this event"}}},"EventsCountQuery":{"type":"object","required":["start_date","end_date"],"properties":{"aggregation_level":{"$ref":"#/components/schemas/AggregationLevel","description":"Aggregation level: events (raw count), sessions (unique sessions), or visitors (unique visitors)"},"custom_events_only":{"type":["boolean","null"],"description":"Only return custom events, excluding system events like page_view, page_leave, heartbeat (default: true)"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"EventsResponse":{"type":"object","required":["events","applied_kinds"],"properties":{"applied_kinds":{"type":"array","items":{"$ref":"#/components/schemas/EventKind"},"description":"Echo of the kinds filter actually applied (server-resolved). Useful\nfor clients that pass `kinds=` empty and want to know what they got."},"events":{"type":"array","items":{"$ref":"#/components/schemas/ObservabilityEvent"}}}},"ExecBody":{"type":"object","required":["cmd"],"properties":{"cmd":{"type":"array","items":{"type":"string"}},"cwd":{"type":["string","null"]},"env":{"type":"object","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}}},"additionalProperties":false},"ExecDetachedResponse":{"type":"object","required":["job_id"],"properties":{"job_id":{"type":"string"}}},"ExecResponse":{"type":"object","required":["exit_code","stdout","stderr"],"properties":{"exit_code":{"type":"integer","format":"int32"},"stderr":{"type":"string"},"stdout":{"type":"string"}}},"ExecuteImportRequest":{"type":"object","description":"Request to execute an import","required":["session_id","project_name","preset","directory","main_branch"],"properties":{"directory":{"type":"string","description":"Project directory","example":"."},"dry_run":{"type":["boolean","null"],"description":"Dry run mode (don't create resources)"},"main_branch":{"type":"string","description":"Main branch name","example":"main"},"preset":{"type":"string","description":"Preset to use for the project (e.g., \"nextjs\", \"express\", \"docker\")"},"project_name":{"type":"string","description":"Project name to use (overrides the name from the plan)","example":"my-app"},"session_id":{"type":"string","description":"Session ID from plan creation"}}},"ExecuteImportResponse":{"type":"object","description":"Response from import execution","required":["session_id","status","step_results"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32","description":"Created deployment ID (if completed)"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Created environment ID (if completed)"},"project_id":{"type":["integer","null"],"format":"int32","description":"Created project ID (if completed)"},"session_id":{"type":"string","description":"Session ID"},"status":{"$ref":"#/components/schemas/ImportExecutionStatus","description":"Execution status"},"step_results":{"type":"array","items":{"$ref":"#/components/schemas/StepResult"},"description":"Per-step results (in execution order)"}}},"ExecuteOperationRequest":{"type":"object","required":["operation"],"properties":{"operation":{"type":"string"}}},"ExpireRequest":{"type":"object","description":"Request to set expiration on a key","required":["key","seconds"],"properties":{"key":{"type":"string","description":"The key to set expiration on","example":"session:abc"},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1},"seconds":{"type":"integer","format":"int64","description":"Expiration time in seconds","example":3600}}},"ExpireResponse":{"type":"object","description":"Response for expire operation","required":["success"],"properties":{"success":{"type":"boolean","description":"True if expiration was set, false if key doesn't exist"}}},"ExplorerSupportResponse":{"type":"object","required":["supported","service_type","capabilities","hierarchy"],"properties":{"capabilities":{"type":"array","items":{"type":"string"},"description":"Capabilities supported by this service","example":["sql"]},"filter_schema":{"description":"JSON Schema for filter format with embedded UI hints (if supported)"},"hierarchy":{"type":"array","items":{"$ref":"#/components/schemas/HierarchyLevel"},"description":"Hierarchy levels (describes the navigation structure)"},"reason":{"type":["string","null"],"description":"Reason why explorer is not supported (if applicable)"},"service_type":{"type":"string","description":"Service type","example":"postgres"},"supported":{"type":"boolean","description":"Whether the service supports query explorer functionality","example":true}}},"ExtendTimeoutBody":{"type":"object","properties":{"duration":{"type":["integer","null"],"format":"int64","description":"`@vercel/sandbox`-compatible alternative — duration in milliseconds.\nUsed when `extra_secs` is absent.","minimum":0},"extra_secs":{"type":["integer","null"],"format":"int64","description":"Extra seconds to add to the existing `expires_at` (temps-native).","minimum":0}}},"ExternalImageResponse":{"type":"object","required":["id","project_id","image_ref","pushed_at","created_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"digest":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"image_ref":{"type":"string"},"metadata":{},"project_id":{"type":"integer","format":"int32"},"pushed_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"size_bytes":{"type":["integer","null"],"format":"int64"},"tag":{"type":["string","null"]}}},"ExternalServiceBackupResponse":{"type":"object","description":"Response type for external service backup","required":["id","service_id","backup_id","backup_type","state","started_at","s3_location","metadata","compression_type","created_by"],"properties":{"backup_id":{"type":"integer","format":"int32"},"backup_type":{"type":"string"},"checksum":{"type":["string","null"]},"compression_type":{"type":"string"},"created_by":{"type":"integer","format":"int32"},"error_message":{"type":["string","null"]},"expires_at":{"type":["string","null"],"example":"2025-02-15T14:30:00.123Z"},"finished_at":{"type":["string","null"],"example":"2025-01-15T14:35:00.456Z"},"id":{"type":"integer","format":"int32"},"metadata":{},"s3_location":{"type":"string"},"service_id":{"type":"integer","format":"int32"},"size_bytes":{"type":["integer","null"],"format":"int64"},"started_at":{"type":"string","example":"2025-01-15T14:30:00.123Z"},"state":{"type":"string"}}},"ExternalServiceDetails":{"type":"object","required":["service","sensitive_parameters"],"properties":{"current_parameters":{"type":["object","null"],"additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"parameter_schema":{},"sensitive_parameters":{"type":"array","items":{"type":"string"},"description":"Parameter names whose values are masked in `current_parameters` and\nmay be fetched only through the audited reveal endpoint."},"service":{"$ref":"#/components/schemas/ExternalServiceInfo"}}},"ExternalServiceInfo":{"type":"object","required":["id","name","service_type","status","created_at","updated_at","topology"],"properties":{"connection_info":{"type":["string","null"]},"created_at":{"type":"string"},"error_message":{"type":["string","null"],"description":"Error message from failed initialization."},"id":{"type":"integer","format":"int32"},"members":{"type":"array","items":{"$ref":"#/components/schemas/ServiceMemberInfo"},"description":"Cluster members (empty for standalone services)."},"metrics_enabled":{"type":"boolean","description":"Whether metric collection is enabled for this service. The UI uses this\nto decide whether to poll the monitoring endpoints."},"name":{"type":"string"},"node_id":{"type":["integer","null"],"format":"int32","description":"Node ID where the service runs. Null means control plane (local)."},"service_type":{"$ref":"#/components/schemas/ServiceTypeRoute"},"status":{"type":"string"},"topology":{"type":"string","description":"Service topology: \"standalone\" (single container) or \"cluster\" (HA multi-member).","example":"standalone"},"updated_at":{"type":"string"},"version":{"type":["string","null"]}}},"ExternalServiceSummary":{"type":"object","description":"Summary of the external service that owns a backup. Only populated for\nexternal-service backups (Redis, Postgres, etc.); absent for control-plane\nbackups.","required":["id","name","service_type"],"properties":{"id":{"type":"integer","format":"int32","description":"Database id of the external service."},"name":{"type":"string","description":"Human-readable service name (e.g. \"redis-prod\")."},"service_type":{"type":"string","description":"Service type string (e.g. \"postgres\", \"redis\", \"mongodb\").","example":"postgres"}}},"FieldResponse":{"type":"object","required":["name","field_type","nullable"],"properties":{"field_type":{"type":"string","description":"Field type (Int32, String, Timestamp, etc.)","example":"Int64"},"name":{"type":"string","description":"Field name","example":"id"},"nullable":{"type":"boolean","description":"Whether the field is nullable","example":false}}},"FiringSeriesEntry":{"type":"object","description":"A single currently-firing series for a dynamic alert rule, snapshotted from\nthe evaluator's in-memory per-series firing map at read time (ADR-026 Phase 3).","required":["series_key","series_label"],"properties":{"alarm_id":{"type":["integer","null"],"format":"int32","description":"The open alarm's id, when one was created (absent if suppressed)."},"series_key":{"type":"array","items":{"type":"array","items":false,"prefixItems":[{"type":"string"},{"type":"string"}]},"description":"The series' label pairs, e.g. `[[\"endpoint\",\"/checkout\"],[\"region\",\"eu-west\"]]`."},"series_label":{"type":"string","description":"The human-readable joined label, e.g. `endpoint=/checkout, region=eu-west`."}}},"FlagEnvironmentResponse":{"type":"object","required":["environment_id","enabled"],"properties":{"enabled":{"type":"boolean"},"environment_id":{"type":"integer","format":"int32"},"value":{}}},"FlagListResponse":{"type":"object","description":"Note the absence of `salt`: it is never exposed. Publishing the bucketing\nsalt would let a client predict, and self-select into, a rollout cohort.","required":["flags","total","page","page_size","total_pages"],"properties":{"flags":{"type":"array","items":{"$ref":"#/components/schemas/FlagResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","description":"Total flags matching the filter, across all pages.","minimum":0},"total_pages":{"type":"integer","format":"int64","minimum":0}}},"FlagResponse":{"type":"object","required":["id","key","value_type","default_value","client_visible","created_at","updated_at","environments"],"properties":{"archived_at":{"type":["string","null"]},"client_visible":{"type":"boolean"},"created_at":{"type":"string"},"default_value":{},"description":{"type":["string","null"]},"environments":{"type":"array","items":{"$ref":"#/components/schemas/FlagEnvironmentResponse"},"description":"Per-environment overrides. Empty means the flag inherits its default\neverywhere."},"id":{"type":"integer","format":"int32"},"key":{"type":"string"},"last_evaluated_at":{"type":["string","null"],"description":"When an app last actually evaluated this flag. `None` means never seen,\nwhich is a real answer rather than missing data."},"updated_at":{"type":"string"},"value_type":{"type":"string"}}},"FlagSnapshot":{"type":"object","description":"A single flag, already resolved down to one environment. This is what the\nevaluator sees and what the SDK caches in memory.","required":["key","value_type","default_value","enabled"],"properties":{"default_value":{"description":"Served whenever evaluation cannot do better. Genuinely polymorphic by\ndesign — the surrounding struct carries the type."},"enabled":{"type":"boolean","description":"False means the kill switch is engaged for this environment."},"environment_value":{"description":"`None` means \"inherit `default_value`\"."},"key":{"type":"string"},"value_type":{"$ref":"#/components/schemas/FlagValueType"}}},"FlagSnapshotResponse":{"type":"object","required":["environment_id","flags"],"properties":{"environment_id":{"type":"integer","format":"int32"},"flags":{"type":"array","items":{"$ref":"#/components/schemas/FlagSnapshot"},"description":"Flags collapsed to what the evaluator needs, sorted by key so the\nserialized form — and therefore the ETag — is stable."}}},"FlagValueType":{"type":"string","description":"The declared type of a flag's value. Fixed at create time.","enum":["bool","string","number","json"]},"ForecastAlgorithm":{"type":"string","description":"Forecast model family.","enum":["linear","seasonal"]},"ForecastParams":{"type":"object","description":"Forecast detector parameters (stub — not yet evaluated).","required":["forecast_horizon_secs","comparator","threshold"],"properties":{"algorithm":{"$ref":"#/components/schemas/ForecastAlgorithm"},"comparator":{"$ref":"#/components/schemas/Comparator","description":"Comparator + threshold the *forecast* is checked against."},"deviations":{"type":"number","format":"double"},"forecast_horizon_secs":{"type":"integer","format":"int32","description":"How far ahead to project before checking the breach condition."},"threshold":{"type":"number","format":"double"}}},"FullError":{"type":"object","required":["id","ts","error_group_id","fingerprint","error_class"],"properties":{"data":{"description":"Full JSONB blob from `error_events.data` — stack trace, breadcrumbs,\nrequest context, everything. Schema is documented per source SDK."},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"error_class":{"type":"string"},"error_group_id":{"type":"integer","format":"int32"},"fingerprint":{"type":"string"},"id":{"type":"integer","format":"int64"},"message":{"type":["string","null"]},"trace_id":{"type":["string","null"]},"ts":{"type":"string","format":"date-time"}}},"FullEvent":{"oneOf":[{"allOf":[{"$ref":"#/components/schemas/FullRequest"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["request"]}}}]},{"allOf":[{"$ref":"#/components/schemas/FullError"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["error"]}}}]},{"allOf":[{"$ref":"#/components/schemas/RevenueRow"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["revenue"]}}}]},{"allOf":[{"$ref":"#/components/schemas/SpanRow","description":"`SpanRow.attributes` is the truncated form; re-fetching returns\nthe same shape so the panel has a stable contract."},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["span"]}}}],"description":"`SpanRow.attributes` is the truncated form; re-fetching returns\nthe same shape so the panel has a stable contract."}],"description":"One un-truncated row, returned by the `/full/{type}/{id}` endpoint when\nthe user clicks \"Show full\". Same shape as the list rows, but with the\nraw heavy fields restored (no truncation flags) so the side panel can\nrender the long form."},"FullRequest":{"type":"object","required":["id","ts","method","host","path","status"],"properties":{"client_ip":{"type":["string","null"]},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"error_group_id":{"type":["integer","null"],"format":"int32"},"host":{"type":"string"},"id":{"type":"string","description":"The request's unique `request_id` — same identity the list rows carry\n(backend-agnostic; ClickHouse rows have no serial PK)."},"latency_ms":{"type":["integer","null"],"format":"int32"},"method":{"type":"string"},"path":{"type":"string"},"referrer":{"type":["string","null"]},"request_headers":{},"response_headers":{},"status":{"type":"integer","format":"int32"},"trace_id":{"type":["string","null"]},"ts":{"type":"string","format":"date-time"},"user_agent":{"type":["string","null"]}}},"FunnelMetricsResponse":{"type":"object","required":["funnel_id","funnel_name","total_entries","step_conversions","overall_conversion_rate","average_completion_time_seconds"],"properties":{"average_completion_time_seconds":{"type":"number","format":"double"},"funnel_id":{"type":"integer","format":"int32"},"funnel_name":{"type":"string"},"overall_conversion_rate":{"type":"number","format":"double"},"step_conversions":{"type":"array","items":{"$ref":"#/components/schemas/StepConversionResponse"}},"total_entries":{"type":"integer","format":"int64","minimum":0}}},"FunnelResponse":{"type":"object","required":["id","name","is_active","created_at","updated_at"],"properties":{"created_at":{"type":"string"},"description":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"name":{"type":"string"},"updated_at":{"type":"string"}}},"GatewayStatus":{"type":"object","description":"Detailed gateway container status surfaced to the settings UI.","required":["present","running","health","container_name","expected_image","drift","auto_upgrade"],"properties":{"auto_upgrade":{"type":"boolean","description":"True if `auto_upgrade` is enabled in settings."},"container_name":{"type":"string","description":"Container name."},"drift":{"type":"boolean","description":"True when `image != expected_image` and the container is present."},"expected_image":{"type":"string","description":"The image the supervisor *expects* (from settings/constant). If this\ndiffers from `image`, the UI shows a \"drift\" badge."},"health":{"type":"string","description":"Higher-level health label: \"running\" | \"restarting\" | \"crash_looping\"\n| \"stopped\" | \"missing\". UI should prefer this over `running`."},"host_port":{"type":["integer","null"],"format":"int32","description":"Host port that the container's :8080 is published on.","minimum":0},"image":{"type":["string","null"],"description":"Image reference the container was created with (e.g.\n`ghcr.io/gotempsh/temps-preview-gateway:latest`)."},"image_digest":{"type":["string","null"],"description":"Image digest if available (e.g. `sha256:…`)."},"last_error":{"type":["string","null"],"description":"Error string Docker recorded for the container (e.g. startup failure)."},"last_exit_code":{"type":["integer","null"],"format":"int64","description":"Exit code of the last run, if the container is not currently running."},"network":{"type":["string","null"],"description":"Network the container is attached to (should be `temps-sandbox-net`)."},"present":{"type":"boolean","description":"Whether the container exists at all."},"restart_count":{"type":["integer","null"],"format":"int64","description":"Number of times Docker has restarted the container."},"running":{"type":"boolean","description":"Whether the container is currently running."},"started_at":{"type":["string","null"],"description":"ISO 8601 timestamp the container was started at, if running."}}},"GenAiEvent":{"type":"object","description":"A GenAI-related event extracted from span events.\n\nCovers `gen_ai.client.inference.operation.details` and `gen_ai.evaluation.result`\nevents per the OTel GenAI semantic conventions.","required":["span_id","trace_id","event_name","timestamp","attributes"],"properties":{"attributes":{"type":"object","description":"All event attributes.","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"event_name":{"type":"string"},"span_id":{"type":"string"},"timestamp":{"type":"string","format":"date-time"},"trace_id":{"type":"string"}}},"GenAiSpanDetail":{"type":"object","description":"A single GenAI span with extracted semantic convention fields.\n\nFields are aligned with the OpenTelemetry GenAI Semantic Conventions spec:\n","required":["span_id","name","kind","start_time","duration_ms","status_code","attributes"],"properties":{"agent_description":{"type":["string","null"],"description":"Agent description from `gen_ai.agent.description`."},"agent_id":{"type":["string","null"],"description":"Agent identifier from `gen_ai.agent.id`."},"agent_name":{"type":["string","null"],"description":"Agent name from `gen_ai.agent.name`."},"agent_version":{"type":["string","null"],"description":"Agent version from `gen_ai.agent.version`."},"attributes":{"type":"object","description":"All span attributes for extensibility.","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"aws_bedrock_guardrail_id":{"type":["string","null"],"description":"AWS Bedrock guardrail ID from `aws.bedrock.guardrail.id`."},"aws_bedrock_knowledge_base_id":{"type":["string","null"],"description":"AWS Bedrock knowledge base ID from `aws.bedrock.knowledge_base.id`."},"azure_resource_provider_namespace":{"type":["string","null"],"description":"Azure resource provider namespace from `azure.resource_provider.namespace`."},"cache_creation_input_tokens":{"type":["integer","null"],"format":"int64","description":"Tokens written to provider cache from `gen_ai.usage.cache_creation.input_tokens`."},"cache_read_input_tokens":{"type":["integer","null"],"format":"int64","description":"Tokens served from provider cache from `gen_ai.usage.cache_read.input_tokens`."},"conversation_id":{"type":["string","null"],"description":"Unique conversation/session/thread ID from `gen_ai.conversation.id`."},"data_source_id":{"type":["string","null"],"description":"Data source identifier from `gen_ai.data_source.id`."},"duration_ms":{"type":"number","format":"double"},"embeddings_dimension_count":{"type":["integer","null"],"format":"int64","description":"Output embedding dimensions from `gen_ai.embeddings.dimension.count`."},"error_type":{"type":["string","null"],"description":"Error type from `error.type` when the span status is ERROR."},"gen_ai_model":{"type":["string","null"],"description":"The requested model from `gen_ai.request.model`."},"gen_ai_operation":{"type":["string","null"],"description":"The operation type from `gen_ai.operation.name` (e.g. \"chat\", \"embeddings\", \"execute_tool\")."},"gen_ai_response_model":{"type":["string","null"],"description":"The model that actually generated the response from `gen_ai.response.model`."},"gen_ai_system":{"type":["string","null"],"description":"The GenAI provider from `gen_ai.provider.name` (falls back to deprecated `gen_ai.system`)."},"input_messages":{"type":["string","null"],"description":"Chat history input from `gen_ai.input.messages` (opt-in, JSON string)."},"input_tokens":{"type":["integer","null"],"format":"int64"},"kind":{"$ref":"#/components/schemas/SpanKind"},"name":{"type":"string"},"openai_api_type":{"type":["string","null"],"description":"OpenAI API type from `openai.api.type` (chat_completions, responses)."},"openai_request_service_tier":{"type":["string","null"],"description":"Requested service tier from `openai.request.service_tier`."},"openai_response_service_tier":{"type":["string","null"],"description":"Actual service tier from `openai.response.service_tier`."},"openai_system_fingerprint":{"type":["string","null"],"description":"System fingerprint from `openai.response.system_fingerprint`."},"output_messages":{"type":["string","null"],"description":"Model output from `gen_ai.output.messages` (opt-in, JSON string)."},"output_tokens":{"type":["integer","null"],"format":"int64"},"output_type":{"type":["string","null"],"description":"Output content type from `gen_ai.output.type` (text, json, image, speech)."},"parent_span_id":{"type":["string","null"]},"request_choice_count":{"type":["integer","null"],"format":"int64","description":"Number of choices requested from `gen_ai.request.choice.count`."},"request_encoding_formats":{"type":["array","null"],"items":{"type":"string"},"description":"Requested encoding formats from `gen_ai.request.encoding_formats`."},"request_frequency_penalty":{"type":["number","null"],"format":"double","description":"Frequency penalty from `gen_ai.request.frequency_penalty`."},"request_max_tokens":{"type":["integer","null"],"format":"int64","description":"Max tokens from `gen_ai.request.max_tokens`."},"request_presence_penalty":{"type":["number","null"],"format":"double","description":"Presence penalty from `gen_ai.request.presence_penalty`."},"request_seed":{"type":["integer","null"],"format":"int64","description":"Seed for reproducibility from `gen_ai.request.seed`."},"request_stop_sequences":{"type":["array","null"],"items":{"type":"string"},"description":"Stop sequences from `gen_ai.request.stop_sequences`."},"request_temperature":{"type":["number","null"],"format":"double","description":"Temperature setting from `gen_ai.request.temperature`."},"request_top_k":{"type":["number","null"],"format":"double","description":"Top-k setting from `gen_ai.request.top_k`."},"request_top_p":{"type":["number","null"],"format":"double","description":"Top-p setting from `gen_ai.request.top_p`."},"response_finish_reasons":{"type":["array","null"],"items":{"type":"string"},"description":"Reasons the model stopped from `gen_ai.response.finish_reasons` (e.g. [\"stop\"])."},"response_id":{"type":["string","null"],"description":"Unique completion ID from `gen_ai.response.id` (e.g. \"chatcmpl-123\")."},"retrieval_documents":{"type":["string","null"],"description":"Retrieved documents from `gen_ai.retrieval.documents` (opt-in, JSON string)."},"retrieval_query_text":{"type":["string","null"],"description":"Retrieval query text from `gen_ai.retrieval.query.text` (opt-in)."},"server_address":{"type":["string","null"],"description":"GenAI server address from `server.address`."},"server_port":{"type":["integer","null"],"format":"int64","description":"GenAI server port from `server.port`."},"span_id":{"type":"string"},"start_time":{"type":"string","format":"date-time"},"status_code":{"$ref":"#/components/schemas/SpanStatusCode"},"system_instructions":{"type":["string","null"],"description":"System instructions from `gen_ai.system_instructions` (opt-in, JSON string)."},"tool_call_arguments":{"type":["string","null"],"description":"Tool call arguments from `gen_ai.tool.call.arguments` (opt-in, JSON string)."},"tool_call_id":{"type":["string","null"],"description":"Tool call ID from `gen_ai.tool.call.id`."},"tool_call_result":{"type":["string","null"],"description":"Tool call result from `gen_ai.tool.call.result` (opt-in, JSON string)."},"tool_definitions":{"type":["string","null"],"description":"Tool definitions from `gen_ai.tool.definitions` (opt-in, JSON string)."},"tool_description":{"type":["string","null"],"description":"Tool description from `gen_ai.tool.description`."},"tool_name":{"type":["string","null"],"description":"Tool name from `gen_ai.tool.name`."},"tool_type":{"type":["string","null"],"description":"Tool type from `gen_ai.tool.type` (function, extension, datastore)."}}},"GenAiTraceDetailResponse":{"type":"object","required":["trace_id","spans","span_count","events","event_count"],"properties":{"event_count":{"type":"integer","minimum":0},"events":{"type":"array","items":{"$ref":"#/components/schemas/GenAiEvent"}},"span_count":{"type":"integer","minimum":0},"spans":{"type":"array","items":{"$ref":"#/components/schemas/GenAiSpanDetail"}},"trace_id":{"type":"string"}}},"GenAiTraceSummariesResponse":{"type":"object","required":["data","total"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/GenAiTraceSummary"}},"total":{"type":"integer","format":"int64","minimum":0}}},"GenAiTraceSummary":{"type":"object","description":"Summary of a GenAI conversation — aggregated from OTel spans with `gen_ai.*` attributes.","required":["trace_id","root_span_name","service_name","start_time","duration_ms","span_count","error_count"],"properties":{"duration_ms":{"type":"number","format":"double"},"error_count":{"type":"integer","format":"int64"},"gen_ai_model":{"type":["string","null"],"description":"The requested model from `gen_ai.request.model`."},"gen_ai_operation":{"type":["string","null"],"description":"The operation type from `gen_ai.operation.name` (e.g. \"chat\", \"embeddings\")."},"gen_ai_system":{"type":["string","null"],"description":"The GenAI provider (e.g. \"openai\", \"anthropic\") from `gen_ai.provider.name`."},"root_span_name":{"type":"string"},"service_name":{"type":"string"},"span_count":{"type":"integer","format":"int64"},"start_time":{"type":"string","format":"date-time"},"total_cache_creation_input_tokens":{"type":["integer","null"],"format":"int64","description":"Total cache-creation input tokens across all spans."},"total_cache_read_input_tokens":{"type":["integer","null"],"format":"int64","description":"Total cache-read input tokens across all spans."},"total_input_tokens":{"type":["integer","null"],"format":"int64","description":"Total input tokens across all spans in this trace."},"total_output_tokens":{"type":["integer","null"],"format":"int64","description":"Total output tokens across all spans in this trace."},"trace_id":{"type":"string"}}},"GeneralStatsQuery":{"type":"object","required":["start_date","end_date"],"properties":{"end_date":{"type":"string","format":"date-time"},"start_date":{"type":"string","format":"date-time"}}},"GeneralStatsResponse":{"type":"object","required":["total_unique_visitors","total_visits","total_page_views","total_events","total_projects","avg_bounce_rate","avg_engagement_rate","project_breakdown"],"properties":{"avg_bounce_rate":{"type":"number","format":"double"},"avg_engagement_rate":{"type":"number","format":"double"},"page_views_trend_percentage":{"type":["number","null"],"format":"double","description":"Percentage change in page views vs previous period"},"previous_page_views":{"type":["integer","null"],"format":"int64","description":"Previous period page views"},"previous_unique_visitors":{"type":["integer","null"],"format":"int64","description":"Previous period unique visitors (same duration, shifted back)"},"project_breakdown":{"type":"array","items":{"$ref":"#/components/schemas/ProjectStatsBreakdown"}},"total_events":{"type":"integer","format":"int64"},"total_page_views":{"type":"integer","format":"int64"},"total_projects":{"type":"integer","format":"int64"},"total_unique_visitors":{"type":"integer","format":"int64"},"total_visits":{"type":"integer","format":"int64"},"visitors_trend_percentage":{"type":["number","null"],"format":"double","description":"Percentage change in unique visitors vs previous period"}}},"GenerateDockerfileRequest":{"type":"object","description":"Request body for generating a Dockerfile from a preset","properties":{"build_command":{"type":["string","null"],"description":"Custom build command (overrides preset default)","example":"npm run build"},"install_command":{"type":["string","null"],"description":"Custom install command (overrides preset default)","example":"npm ci"},"output_dir":{"type":["string","null"],"description":"Output directory for static builds","example":"dist"},"package_manager":{"type":["string","null"],"description":"Package manager used by the project (npm, yarn, pnpm, bun)\nIf not provided, defaults to npm","example":"npm"},"project_name":{"type":["string","null"],"description":"Project name/slug used for container naming","example":"my-app"},"use_buildkit":{"type":"boolean","description":"Whether to use BuildKit cache mounts for faster builds"}}},"GenerateDockerfileResponse":{"type":"object","description":"Response containing a generated Dockerfile and build arguments","required":["dockerfile","build_args","preset"],"properties":{"build_args":{"type":"object","description":"Build arguments to pass to `docker build --build-arg KEY=VALUE`","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"dockerfile":{"type":"string","description":"The generated Dockerfile content"},"preset":{"type":"string","description":"The preset slug used for generation"}}},"GenerateJoinTokenResponse":{"type":"object","description":"Response returned when a join token is generated (plaintext shown once)","required":["token","message"],"properties":{"message":{"type":"string"},"token":{"type":"string","description":"The plaintext join token — shown only once, save it now"}}},"GeoLocationResponse":{"type":"object","description":"Response containing geolocation information for an IP address","required":["ip","is_eu"],"properties":{"city":{"type":["string","null"],"description":"City name","example":"Mountain View"},"country":{"type":["string","null"],"description":"Country name","example":"United States"},"country_code":{"type":["string","null"],"description":"ISO country code (2 letters)","example":"US"},"ip":{"type":"string","description":"IP address that was geolocated","example":"8.8.8.8"},"is_eu":{"type":"boolean","description":"Whether the IP is in the European Union","example":false},"latitude":{"type":["number","null"],"format":"double","description":"Latitude coordinate","example":37.386},"longitude":{"type":["number","null"],"format":"double","description":"Longitude coordinate","example":-122.0838},"region":{"type":["string","null"],"description":"Region/state name","example":"California"},"timezone":{"type":["string","null"],"description":"Timezone identifier","example":"America/Los_Angeles"}}},"GeoRestrictionsConfig":{"type":"object","description":"Geographic restrictions configuration (future feature)","properties":{"allowedCountries":{"type":"array","items":{"type":"string"},"description":"Allow traffic only from specific countries"},"blockedCountries":{"type":"array","items":{"type":"string"},"description":"Block traffic from specific countries (ISO 3166-1 alpha-2 codes)"}}},"GetDeploymentsParams":{"type":"object","properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"page":{"type":["integer","null"],"format":"int64"},"per_page":{"type":["integer","null"],"format":"int64"}}},"GetEnvironmentVariablesQuery":{"type":"object","properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"service_id":{"type":["integer","null"],"format":"int32","description":"Required by integration-value reveals to bind the plaintext response to\nthe exact service displayed by the client."},"var_id":{"type":["integer","null"],"format":"int32","description":"Exact manual env-var row to reveal. Required by the dashboard so\nduplicate keys on disjoint environments cannot cross-reveal."}}},"GetFunnelMetricsQuery":{"type":"object","properties":{"country_code":{"type":["string","null"]},"end_date":{"type":["string","null"],"format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"start_date":{"type":["string","null"],"format":"date-time"}}},"GetOrCreateDSNRequest":{"type":"object","properties":{"base_url":{"type":["string","null"]},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"}}},"GetProjectSecretsQuery":{"type":"object","properties":{"environment_id":{"type":["integer","null"],"format":"int32"}}},"GetProjectSessionReplaysQuery":{"type":"object","required":["project_id"],"properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"page":{"type":["integer","null"],"format":"int64","minimum":0},"per_page":{"type":["integer","null"],"format":"int64","minimum":0},"project_id":{"type":"integer","format":"int32"}}},"GetProjectSessionReplaysResponse":{"type":"object","required":["sessions","page","per_page","total_count"],"properties":{"page":{"type":"integer","format":"int64","minimum":0},"per_page":{"type":"integer","format":"int64","minimum":0},"sessions":{"type":"array","items":{"$ref":"#/components/schemas/SessionReplayWithVisitorDto"}},"total_count":{"type":"integer","format":"int64","minimum":0}}},"GetRequest":{"type":"object","description":"Request to get a value by key","required":["key"],"properties":{"key":{"type":"string","description":"The key to retrieve","example":"user:123"},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1}}},"GetResponse":{"type":"object","description":"Response for get operation","properties":{"value":{"description":"The value, or null if not found"}}},"GetSessionReplayResponse":{"type":"object","required":["session"],"properties":{"session":{"$ref":"#/components/schemas/SessionReplayWithVisitorDto"}}},"GetUniqueEventsQuery":{"type":"object","properties":{"page":{"type":["integer","null"],"format":"int64","minimum":0},"page_size":{"type":["integer","null"],"format":"int64","minimum":0}}},"GetVisitorSessionsQuery":{"type":"object","properties":{"page":{"type":["integer","null"],"format":"int64","minimum":0},"per_page":{"type":["integer","null"],"format":"int64","minimum":0}}},"GetVisitorSessionsResponse":{"type":"object","required":["sessions","page","per_page","total_count"],"properties":{"page":{"type":"integer","format":"int64","minimum":0},"per_page":{"type":"integer","format":"int64","minimum":0},"sessions":{"type":"array","items":{"$ref":"#/components/schemas/SessionReplayWithVisitorDto"}},"total_count":{"type":"integer","minimum":0}}},"GitPushEvent":{"type":"object","description":"Git push event information that triggered the deployment","required":["repo","owner","branch","commit"],"properties":{"branch":{"type":"string","description":"Branch that was pushed"},"commit":{"type":"string","description":"Commit SHA"},"owner":{"type":"string","description":"Repository owner/organization"},"repo":{"type":"string","description":"Repository name"}}},"GitRefResponse":{"type":"object","description":"Git repository reference response","required":["url","ref"],"properties":{"path":{"type":["string","null"],"description":"Path within the repository (for monorepos)"},"ref":{"type":"string","description":"Git reference (branch, tag, or commit)"},"url":{"type":"string","description":"Git repository URL"}}},"GitSourcePlan":{"type":"object","description":"Git repository the source platform deploys from","required":["owner","repo","branch","is_public"],"properties":{"branch":{"type":"string","description":"Branch the source platform deploys"},"clone_url":{"type":["string","null"],"description":"Full clone URL, e.g. `https://github.com/owner/repo.git`"},"is_public":{"type":"boolean","description":"True when the repository is public (no credentials on the source\nplatform) — the project can then build without a git provider\nconnection."},"owner":{"type":"string","description":"Repository owner (organization or user)"},"repo":{"type":"string","description":"Repository name"}}},"GlobalConversationResponse":{"type":"object","description":"A conversation in the unified cross-project switcher: carries the project it\nbelongs to (name/slug) so the UI can show where the chat was started and\nlink back to the source.","required":["public_id","project_id","context_type","context_id","status","created_at","last_activity_at"],"properties":{"context_id":{"type":"string"},"context_type":{"type":"string"},"created_at":{"type":"string"},"last_activity_at":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"project_name":{"type":["string","null"]},"project_slug":{"type":["string","null"]},"public_id":{"type":"string"},"status":{"type":"string"},"title":{"type":["string","null"]}}},"GlobalEventStatsResponse":{"type":"object","required":["delivered","opened","clicked","bounced","complained"],"properties":{"bounce_rate":{"type":["number","null"],"format":"double"},"bounced":{"type":"integer","format":"int64","minimum":0},"click_rate":{"type":["number","null"],"format":"double"},"clicked":{"type":"integer","format":"int64","minimum":0},"complained":{"type":"integer","format":"int64","minimum":0},"delivered":{"type":"integer","format":"int64","minimum":0},"open_rate":{"type":["number","null"],"format":"double"},"opened":{"type":"integer","format":"int64","minimum":0}}},"GlobalMrrResponse":{"type":"object","required":["currency","current_mrr_minor","previous_mrr_minor"],"properties":{"change_percentage":{"type":["number","null"],"format":"double","description":"Percentage change vs 24h ago. Null when previous MRR is zero\n(no baseline to compare against)."},"currency":{"type":"string"},"current_mrr_minor":{"type":"integer","format":"int64"},"previous_mrr_minor":{"type":"integer","format":"int64","description":"MRR 24h before now, reconstructed from the event log."}}},"GlobalRecentEventResponse":{"type":"object","required":["id","project_id","project_name","occurred_at","event_type"],"properties":{"amount_minor":{"type":["integer","null"],"format":"int64"},"currency":{"type":["string","null"]},"customer_ref":{"type":["string","null"]},"event_type":{"type":"string"},"id":{"type":"integer","format":"int64"},"mrr_minor":{"type":["integer","null"],"format":"int64"},"occurred_at":{"type":"string","format":"date-time"},"project_id":{"type":"integer","format":"int32"},"project_name":{"type":"string"}}},"GlobalRevenueSummaryResponse":{"type":"object","required":["currency","current_mrr_minor","paid_last_30d_minor","refunded_last_30d_minor","paid_all_time_minor","refunded_all_time_minor","active_subscriptions","active_customers","transactions_last_30d"],"properties":{"active_customers":{"type":"integer","format":"int64"},"active_subscriptions":{"type":"integer","format":"int64"},"currency":{"type":"string"},"current_mrr_minor":{"type":"integer","format":"int64"},"paid_all_time_minor":{"type":"integer","format":"int64"},"paid_last_30d_minor":{"type":"integer","format":"int64"},"refunded_all_time_minor":{"type":"integer","format":"int64"},"refunded_last_30d_minor":{"type":"integer","format":"int64"},"transactions_last_30d":{"type":"integer","format":"int64"}}},"GroupedPageMetric":{"type":"object","required":["group_key","events"],"properties":{"cls":{"type":["number","null"],"format":"float"},"country_code":{"type":["string","null"],"description":"ISO 3166-1 alpha-2 code of the group's country. Populated for the\ngeographic dimensions (country/region/city) so clients can match map\ngeometries without name-based lookups; null otherwise."},"events":{"type":"integer","format":"int64"},"fcp":{"type":["number","null"],"format":"float"},"group_key":{"type":"string"},"inp":{"type":["number","null"],"format":"float"},"lcp":{"type":["number","null"],"format":"float"},"ttfb":{"type":["number","null"],"format":"float"}}},"GroupedPageMetricsQuery":{"allOf":[{"$ref":"#/components/schemas/SpeedSegmentFilters","description":"Segment filters — same shape as `PerformanceMetricsQuery`."},{"type":"object","required":["start_date","end_date","project_id","group_by"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"device_type":{"type":["string","null"],"description":"Device type filter: \"desktop\" or \"mobile\""},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"group_by":{"type":"string"},"include_bots":{"type":["boolean","null"],"description":"Include crawler/datacenter (bot) samples. Defaults to false."},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}}]},"GroupedPageMetricsResponse":{"type":"object","required":["groups","total_events","grouped_by"],"properties":{"grouped_by":{"type":"string"},"groups":{"type":"array","items":{"$ref":"#/components/schemas/GroupedPageMetric"}},"total_events":{"type":"integer","format":"int64"}}},"HasAnalyticsEventsResponse":{"type":"object","required":["has_events"],"properties":{"has_events":{"type":"boolean"}}},"HasErrorGroupsResponse":{"type":"object","required":["has_error_groups"],"properties":{"has_error_groups":{"type":"boolean"}}},"HasEventsQuery":{"type":"object","required":["project_id"],"properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"}}},"HasEventsResponse":{"type":"object","required":["has_events"],"properties":{"has_events":{"type":"boolean"}}},"HasMetricsQuery":{"type":"object","required":["project_id"],"properties":{"project_id":{"type":"integer","format":"int32"}}},"HasMetricsResponse":{"type":"object","required":["has_metrics"],"properties":{"has_metrics":{"type":"boolean"}}},"HealthCheckConfiguration":{"type":"object","description":"Health check configuration","required":["port","interval","timeout","retries"],"properties":{"http_path":{"type":["string","null"],"description":"HTTP path to check (if applicable)"},"interval":{"type":"integer","format":"int32","description":"Interval between checks (seconds)","minimum":0},"port":{"type":"integer","format":"int32","description":"Port to check","minimum":0},"retries":{"type":"integer","format":"int32","description":"Number of retries before marking unhealthy","minimum":0},"timeout":{"type":"integer","format":"int32","description":"Timeout for each check (seconds)","minimum":0}}},"HealthCheckEntryResponse":{"type":"object","required":["checked_at","status"],"properties":{"checked_at":{"type":"string","description":"ISO 8601 timestamp of when the probe ran.","example":"2026-04-22T11:30:00Z"},"error_message":{"type":["string","null"],"description":"Present only when the probe failed or was degraded."},"response_time_ms":{"type":["integer","null"],"format":"int32","description":"TCP connect latency in milliseconds."},"status":{"type":"string","description":"\"operational\" | \"degraded\" | \"down\"","example":"operational"}}},"HealthResponse":{"type":"object","required":["summaries"],"properties":{"summaries":{"type":"array","items":{"$ref":"#/components/schemas/HealthSummary"}}}},"HealthStatus":{"type":"string","description":"Overall health status.","enum":["healthy","degraded","down","unknown"]},"HealthSummary":{"type":"object","description":"Pre-computed health summary for a project environment.","required":["project_id","service_name","status","uptime_pct","error_rate","p95_latency_ms","cpu_usage_pct","memory_usage_pct","computed_at"],"properties":{"computed_at":{"type":"string","format":"date-time"},"cpu_usage_pct":{"type":"number","format":"double"},"environment_id":{"type":["integer","null"],"format":"int32"},"error_rate":{"type":"number","format":"double"},"last_deploy_at":{"type":["string","null"],"format":"date-time"},"last_deploy_id":{"type":["integer","null"],"format":"int32"},"memory_usage_pct":{"type":"number","format":"double"},"p95_latency_ms":{"type":"number","format":"double"},"project_id":{"type":"integer","format":"int32"},"service_name":{"type":"string"},"status":{"$ref":"#/components/schemas/HealthStatus"},"uptime_pct":{"type":"number","format":"double"}}},"HeartbeatApiRequest":{"type":"object","properties":{"architecture":{"type":["string","null"],"description":"Container platform of this node's Docker daemon (`linux/amd64`,\n`linux/arm64`), read from `docker info` by the agent. Absent from\npre-multi-arch agents; the stored value is then left untouched."},"capacity":{"description":"Resource capacity/usage info as JSON (cpu_usage, memory_usage, etc.)"},"containers":{"type":["array","null"],"items":{"$ref":"#/components/schemas/ContainerInventoryItem"},"description":"Container inventory for reconciliation (sent on first heartbeat after agent startup).\nEach entry has `container_id` and `container_name` of temps-managed containers."},"labels":{"description":"Updated node labels for scheduling (allows runtime label changes)."}}},"HeartbeatResponse":{"type":"object","required":["status","message"],"properties":{"message":{"type":"string"},"status":{"type":"string"}}},"HierarchyLevel":{"type":"object","description":"Describes a level in the data source hierarchy","required":["level","name","container_type","can_list_containers","can_list_entities"],"properties":{"can_list_containers":{"type":"boolean","description":"Can list containers at this level?","example":true},"can_list_entities":{"type":"boolean","description":"Can list entities at this level?","example":false},"container_type":{"type":"string","description":"Type of container at this level","example":"database"},"level":{"type":"integer","format":"int32","description":"Level number (0 = root)","example":0,"minimum":0},"name":{"type":"string","description":"Human-readable name for this level","example":"root"}}},"HistogramSummary":{"type":"object","description":"An explicit-bucket histogram aggregated over a time bucket.\n\nCarries the reduced scalars (count/sum/min/max) plus the explicit bucket\nlayout — `bounds` (the upper bounds) and `bucket_counts` (observation counts,\nsummed element-wise across the window; length is `bounds.len() + 1`, the last\nentry being the +Inf overflow bucket). With these, a caller can reconstruct\nany quantile (e.g. p95) via cumulative-count interpolation.","required":["count","sum","bounds","bucket_counts"],"properties":{"bounds":{"type":"array","items":{"type":"number","format":"double"},"description":"Explicit bucket upper bounds (OTLP `explicit_bounds`), ascending."},"bucket_counts":{"type":"array","items":{"type":"integer","format":"int64","minimum":0},"description":"Per-bucket observation counts summed element-wise across the window.\nLength is `bounds.len() + 1` (the trailing element is the +Inf bucket)."},"count":{"type":"integer","format":"int64","description":"Total observation count summed across the bucket window.","minimum":0},"max":{"type":["number","null"],"format":"double","description":"Maximum observed value, when reported by the producer."},"min":{"type":["number","null"],"format":"double","description":"Minimum observed value, when reported by the producer."},"sum":{"type":"number","format":"double","description":"Sum of observed values across the bucket window."}}},"HostnameChange":{"type":"object","description":"A single generated-hostname change in a flatten preview/apply.","required":["kind","id","old","new"],"properties":{"id":{"type":"integer","format":"int32","description":"Row id of the affected record."},"kind":{"type":"string","description":"`\"deployment\"` or `\"environment\"`."},"new":{"type":"string"},"old":{"type":"string"}}},"HostnamePreviewResponse":{"type":"object","description":"Combined preview of a hostname-mode change.","required":["hostname_changes","dns_changes","total"],"properties":{"dns_changes":{"type":"array","items":{"$ref":"#/components/schemas/DnsRecordChange"}},"hostname_changes":{"type":"array","items":{"$ref":"#/components/schemas/HostnameChange"}},"total":{"type":"integer","minimum":0},"zone_access_ok":{"type":["boolean","null"],"description":"Whether the provider token can manage this zone (None if not checked)."}}},"HourlyPageSessions":{"type":"object","required":["timestamp","session_count","event_count","avg_duration_seconds"],"properties":{"avg_duration_seconds":{"type":"number","format":"double"},"event_count":{"type":"integer","format":"int64"},"session_count":{"type":"integer","format":"int64"},"timestamp":{"type":"string"}}},"HourlyVisitsQuery":{"type":"object","required":["start_date","end_date"],"properties":{"aggregation_level":{"$ref":"#/components/schemas/AggregationLevel","description":"Aggregation level: events (page views), sessions (unique sessions), or visitors (unique visitors)"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"HttpChallengeDebugResponse":{"type":"object","required":["domain","challenge_exists","dns_a_records","dns_aaaa_records"],"properties":{"challenge_exists":{"type":"boolean"},"challenge_token":{"type":["string","null"]},"challenge_url":{"type":["string","null"],"description":"The full URL that Let's Encrypt will try to access to validate the challenge"},"dns_a_records":{"type":"array","items":{"type":"string"},"description":"IPv4 addresses the domain points to"},"dns_aaaa_records":{"type":"array","items":{"type":"string"},"description":"IPv6 addresses the domain points to"},"dns_error":{"type":["string","null"],"description":"Any DNS resolution errors"},"domain":{"type":"string"},"validation_url":{"type":["string","null"],"description":"The ACME validation URL (internal to ACME protocol)"}}},"ImportCredentials":{"type":"object","description":"Platform-specific credentials for accessing the source system.\n\nFor platforms like Vercel and Railway, this contains the API token.\nFor self-hosted platforms like Coolify and Dokploy, this also contains\nthe `base_url` of the instance.\n\nLocal importers (Docker) can use `ImportCredentials::none()`.","properties":{"base_url":{"type":["string","null"],"description":"Base URL override (for self-hosted platforms like Coolify, Dokploy)\n\nExample: `https://coolify.example.com`"},"extra":{"type":"object","description":"Additional platform-specific parameters","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"team_id":{"type":["string","null"],"description":"Team or organization ID (for platforms with team scoping like Vercel)"},"token":{"type":["string","null"],"description":"API token / bearer token for the source platform"}}},"ImportExecutionStatus":{"type":"string","description":"Import execution status","enum":["pending","inprogress","completed","failed"]},"ImportExternalServiceRequest":{"type":"object","description":"Request to import a Docker container as a managed service","required":["name","service_type","parameters","container_id"],"properties":{"container_id":{"type":"string","description":"Container ID or name to import","example":"abc123def456"},"name":{"type":"string","description":"Name to register the service as in Temps","example":"production-database"},"parameters":{"type":"object","description":"Service configuration parameters","additionalProperties":{},"propertyNames":{"type":"string"}},"service_type":{"$ref":"#/components/schemas/ServiceTypeRoute","description":"Service type"},"version":{"type":["string","null"],"description":"Optional version override"}}},"ImportOutcomeResponse":{"type":"object","required":["rows_read","inserted","updated","skipped_stale","skipped_invalid","errors"],"properties":{"errors":{"type":"array","items":{"$ref":"#/components/schemas/ImportRowErrorResponse"}},"inserted":{"type":"integer","minimum":0},"rows_read":{"type":"integer","minimum":0},"skipped_invalid":{"type":"integer","minimum":0},"skipped_stale":{"type":"integer","minimum":0},"updated":{"type":"integer","minimum":0}}},"ImportPlan":{"type":"object","description":"Complete import plan describing all operations to onboard a workload.\n\nThe plan is generated from a snapshot and presented to the user for review\nbefore any resources are created. Users can modify individual items\n(skip services, change actions) before approving execution.","required":["version","source","source_id","project","environment","deployment","summary","metadata"],"properties":{"additional_deployments":{"type":"array","items":{"$ref":"#/components/schemas/DeploymentConfiguration"},"description":"Additional deployments (workers, cron jobs, etc.)"},"cost_analysis":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/CostAnalysis","description":"Cost, overprovisioning, and savings analysis. Populated by importers\nthat can observe the whole source cluster (currently Kubernetes);\n`None` for container/platform imports."}]},"deployment":{"$ref":"#/components/schemas/DeploymentConfiguration","description":"Primary deployment configuration"},"domains":{"type":"array","items":{"$ref":"#/components/schemas/DomainPlan"},"description":"Custom domains to migrate"},"environment":{"$ref":"#/components/schemas/EnvironmentConfiguration","description":"Environment configuration"},"metadata":{"$ref":"#/components/schemas/PlanMetadata","description":"Plan metadata"},"project":{"$ref":"#/components/schemas/ProjectConfiguration","description":"Project configuration"},"services":{"type":"array","items":{"$ref":"#/components/schemas/ServicePlan"},"description":"Services to migrate (databases, caches, blob stores)\n\nEach service has an `action` field the user can change before execution."},"source":{"type":"string","description":"Source system this plan was generated from"},"source_id":{"type":"string","description":"Source workload / project ID in the source system"},"steps":{"type":"array","items":{"$ref":"#/components/schemas/MigrationStep"},"description":"Ordered list of migration steps that will be executed.\n\nThis is the human-readable execution plan. Each step describes what\nwill happen, what risks are involved, and what the user should verify.\nSteps are executed in order. If a step fails, execution stops and\nalready-created resources are reported for manual cleanup."},"summary":{"$ref":"#/components/schemas/MigrationSummary","description":"Human-readable summary of the entire migration"},"version":{"type":"string","description":"Plan version for compatibility tracking"}}},"ImportRowErrorResponse":{"type":"object","required":["row","reason"],"properties":{"reason":{"type":"string"},"row":{"type":"integer","minimum":0}}},"ImportSelector":{"type":"object","description":"Selector for discovering workloads","properties":{"label_filter":{"type":["object","null"],"description":"Filter by labels/tags","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"limit":{"type":["integer","null"],"description":"Limit number of results","minimum":0},"name_pattern":{"type":["string","null"],"description":"Filter by name pattern (glob/regex)"},"status_filter":{"type":["array","null"],"items":{"type":"string"},"description":"Filter by status (running, stopped, deployed, etc.)"},"workload_type_filter":{"type":["array","null"],"items":{"type":"string"},"description":"Filter by workload type (container, function, static-site, etc.)"}}},"ImportSource":{"type":"string","description":"Import source identifier","enum":["docker","coolify","dokploy","vercel","netlify","railway","render","fly","kubernetes","caprover","portainer","kamal","custom"]},"ImportSourceCapabilities":{"type":"object","description":"Source capabilities","required":["supports_volumes","supports_networks","supports_health_checks","supports_resource_limits","supports_build","supports_services","supports_domains","supports_project_snapshot","supports_cost_analysis","requires_credentials"],"properties":{"requires_credentials":{"type":"boolean","description":"Whether this source requires API credentials (token, base URL)"},"supports_build":{"type":"boolean"},"supports_cost_analysis":{"type":"boolean","description":"Supports cluster cost + overprovisioning analysis in the plan"},"supports_domains":{"type":"boolean","description":"Supports custom domain migration"},"supports_health_checks":{"type":"boolean"},"supports_networks":{"type":"boolean"},"supports_project_snapshot":{"type":"boolean","description":"Supports full project-level snapshots"},"supports_resource_limits":{"type":"boolean"},"supports_services":{"type":"boolean","description":"Supports service migration (databases, caches, etc.)"},"supports_volumes":{"type":"boolean"}}},"ImportSourceInfo":{"type":"object","description":"Information about an import source","required":["source","name","version","available","capabilities"],"properties":{"available":{"type":"boolean","description":"Whether the source is currently available"},"capabilities":{"$ref":"#/components/schemas/ImportSourceCapabilities","description":"Capabilities"},"name":{"type":"string","description":"Human-readable name"},"source":{"$ref":"#/components/schemas/ImportSource","description":"Source identifier"},"version":{"type":"string","description":"Source version"}}},"ImportStatusResponse":{"type":"object","description":"Response with import status","required":["session_id","status","errors","warnings","created_at","updated_at"],"properties":{"created_at":{"type":"string","format":"date-time","description":"Created at timestamp"},"deployment_id":{"type":["integer","null"],"format":"int32","description":"Created deployment ID"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Created environment ID"},"errors":{"type":"array","items":{"type":"string"},"description":"Errors (if any)"},"plan":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ImportPlan","description":"Import plan"}]},"project_id":{"type":["integer","null"],"format":"int32","description":"Created project ID"},"session_id":{"type":"string","description":"Session ID"},"status":{"$ref":"#/components/schemas/ImportExecutionStatus","description":"Current status"},"updated_at":{"type":"string","format":"date-time","description":"Updated at timestamp"},"validation":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ValidationReport","description":"Validation report"}]},"warnings":{"type":"array","items":{"type":"string"},"description":"Warnings (if any)"}}},"IncidentBucket":{"type":"object","required":["bucket_start","total_incidents","minor_incidents","major_incidents","critical_incidents","resolved_incidents","active_incidents"],"properties":{"active_incidents":{"type":"integer","format":"int64"},"avg_resolution_time_minutes":{"type":["number","null"],"format":"double"},"bucket_start":{"type":"string","format":"date-time"},"critical_incidents":{"type":"integer","format":"int64"},"major_incidents":{"type":"integer","format":"int64"},"minor_incidents":{"type":"integer","format":"int64"},"resolved_incidents":{"type":"integer","format":"int64"},"total_incidents":{"type":"integer","format":"int64"}}},"IncidentBucketedResponse":{"type":"object","required":["project_id","interval","buckets"],"properties":{"buckets":{"type":"array","items":{"$ref":"#/components/schemas/IncidentBucket"}},"environment_id":{"type":["integer","null"],"format":"int32"},"interval":{"type":"string"},"project_id":{"type":"integer","format":"int32"}}},"IncidentResponse":{"type":"object","required":["id","project_id","title","severity","status","started_at","created_at","updated_at"],"properties":{"created_at":{"type":"string","format":"date-time"},"description":{"type":["string","null"]},"environment_id":{"type":["integer","null"],"format":"int32"},"id":{"type":"integer","format":"int32"},"monitor_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"resolved_at":{"type":["string","null"],"format":"date-time"},"severity":{"type":"string"},"started_at":{"type":"string","format":"date-time"},"status":{"type":"string"},"title":{"type":"string"},"updated_at":{"type":"string","format":"date-time"}}},"IncidentUpdateResponse":{"type":"object","required":["id","incident_id","status","message","created_at"],"properties":{"created_at":{"type":"string","format":"date-time"},"id":{"type":"integer","format":"int32"},"incident_id":{"type":"integer","format":"int32"},"message":{"type":"string"},"status":{"type":"string"}}},"IncrRequest":{"type":"object","description":"Request to increment a value","required":["key"],"properties":{"amount":{"type":["integer","null"],"format":"int64","description":"Amount to increment by (default: 1)"},"key":{"type":"string","description":"The key to increment","example":"counter"},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1}}},"IncrResponse":{"type":"object","description":"Response for increment operation","required":["value"],"properties":{"value":{"type":"integer","format":"int64","description":"New value after increment","example":42}}},"InitAuthResponse":{"type":"object","required":["auth_url","session_token"],"properties":{"auth_url":{"type":"string"},"session_token":{"type":"string"}}},"Insight":{"type":"object","description":"An anomaly insight.","required":["id","project_id","service_name","severity","status","title","description","anomaly_ids","started_at","created_at","updated_at"],"properties":{"anomaly_ids":{"type":"array","items":{"type":"integer","format":"int64"}},"correlated_deploy_id":{"type":["integer","null"],"format":"int32"},"created_at":{"type":"string","format":"date-time"},"description":{"type":"string"},"environment":{"type":["string","null"]},"id":{"type":"integer","format":"int64"},"metric_name":{"type":["string","null"]},"project_id":{"type":"integer","format":"int32"},"resolved_at":{"type":["string","null"],"format":"date-time"},"service_name":{"type":"string"},"severity":{"$ref":"#/components/schemas/InsightSeverity"},"started_at":{"type":"string","format":"date-time"},"status":{"$ref":"#/components/schemas/InsightStatus"},"title":{"type":"string"},"updated_at":{"type":"string","format":"date-time"}}},"InsightSeverity":{"type":"string","description":"Severity of an anomaly insight.","enum":["low","medium","high","critical"]},"InsightStatus":{"type":"string","description":"Status of an insight.","enum":["active","resolved"]},"InsightsResponse":{"type":"object","required":["data","count"],"properties":{"count":{"type":"integer","minimum":0},"data":{"type":"array","items":{"$ref":"#/components/schemas/Insight"}}}},"IntegrationResponse":{"type":"object","required":["id","project_id","provider","webhook_path_token","webhook_path","status","has_secret","created_at"],"properties":{"config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ProviderConfig","description":"Typed provider config — allowlist and metered-billing mode. Null\nwhen the operator hasn't configured one yet (accept everything)."}]},"created_at":{"type":"string","format":"date-time"},"has_secret":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"last_event_at":{"type":["string","null"],"format":"date-time"},"project_id":{"type":"integer","format":"int32"},"provider":{"type":"string"},"status":{"type":"string"},"webhook_path":{"type":"string","description":"Relative path the UI can display and copy. The frontend builds\nthe full URL by prefixing its own origin."},"webhook_path_token":{"type":"string","description":"Unguessable token embedded in the public webhook URL. The full\nURL is `{api_origin}/webhooks/revenue/{provider}/{webhook_path_token}`."}}},"IpAccessControlQuery":{"type":"object","description":"Query parameters for listing IP access control rules","properties":{"action":{"type":["string","null"],"description":"Filter by action (\"block\" or \"allow\")"}}},"IpAccessControlResponse":{"type":"object","description":"Response model for IP access control rules","required":["id","ip_address","action","created_at","updated_at"],"properties":{"action":{"type":"string"},"created_at":{"type":"string","example":"2025-10-12T12:15:47.609Z"},"created_by":{"type":["integer","null"],"format":"int32"},"id":{"type":"integer","format":"int32"},"ip_address":{"type":"string"},"reason":{"type":["string","null"]},"updated_at":{"type":"string","example":"2025-10-12T12:15:47.609Z"}}},"JobStatusResponse":{"type":"object","description":"Snapshot of a background job. `status` is one of \"running\" | \"exited\"\n| \"failed\"; `exit_code` is populated only when `status == \"exited\"`.","required":["status","stdout","stderr"],"properties":{"exit_code":{"type":["integer","null"],"format":"int32"},"reason":{"type":["string","null"]},"status":{"type":"string"},"stderr":{"type":"string"},"stdout":{"type":"string"}}},"JobSummaryResponse":{"type":"object","description":"Row in the jobs list. Omits stdout/stderr so a noisy dev server doesn't\nbloat the list payload — callers drill into `GET /jobs/{id}` for the\nfull buffer.","required":["id","status","cmd","started_at"],"properties":{"cmd":{"type":"string"},"exit_code":{"type":["integer","null"],"format":"int32"},"id":{"type":"string"},"reason":{"type":["string","null"]},"started_at":{"type":"string"},"status":{"type":"string"}}},"JoinTokenStatusResponse":{"type":"object","description":"Response for join token status check","required":["has_token"],"properties":{"has_token":{"type":"boolean","description":"Whether a join token has been configured"}}},"JourneyEvent":{"type":"object","description":"A single event in the visitor journey timeline","required":["id","event_type","event_name","occurred_at","is_entry","is_exit","is_bounce"],"properties":{"event_data":{"description":"Custom event properties (for custom events)"},"event_name":{"type":"string","description":"Resolved event name (event_name for custom events, event_type for system events)"},"event_type":{"type":"string","description":"Event type: \"page_view\", \"page_leave\", \"custom\", \"web_vitals\""},"id":{"type":"integer","format":"int64","description":"Event ID"},"is_bounce":{"type":"boolean","description":"Whether this was a bounce"},"is_entry":{"type":"boolean","description":"Whether this is the entry page of the session"},"is_exit":{"type":"boolean","description":"Whether this is the exit page of the session"},"occurred_at":{"type":"string","format":"date-time","description":"When the event occurred"},"page_path":{"type":["string","null"],"description":"Page path where the event happened"},"page_title":{"type":["string","null"],"description":"Page title (if available)"},"referrer":{"type":["string","null"],"description":"Referrer URL for this event"},"scroll_depth":{"type":["integer","null"],"format":"int32","description":"Scroll depth percentage (0-100)"},"session_page_number":{"type":["integer","null"],"format":"int32","description":"Page number within the session (1-indexed)"},"time_on_page":{"type":["integer","null"],"format":"int32","description":"Time spent on page in seconds (computed, not from column)"}}},"JourneySession":{"type":"object","description":"A session within the visitor journey, grouping events","required":["session_id","started_at","duration_seconds","page_views","events_count","is_bounced","is_engaged","events"],"properties":{"channel":{"type":["string","null"],"description":"Traffic source: channel (e.g. \"organic\", \"direct\", \"social\")"},"duration_seconds":{"type":"integer","format":"int64","description":"Session duration in seconds"},"ended_at":{"type":["string","null"],"format":"date-time","description":"When the session ended"},"entry_path":{"type":["string","null"],"description":"Entry page path"},"events":{"type":"array","items":{"$ref":"#/components/schemas/JourneyEvent"},"description":"Events within this session, ordered chronologically"},"events_count":{"type":"integer","format":"int64","description":"Total events in this session"},"exit_path":{"type":["string","null"],"description":"Exit page path"},"is_bounced":{"type":"boolean","description":"Whether the session was a bounce"},"is_engaged":{"type":"boolean","description":"Whether the visitor was engaged (had non-pageview events)"},"page_views":{"type":"integer","format":"int64","description":"Number of page views in this session"},"referrer":{"type":["string","null"],"description":"Traffic source: referrer URL"},"referrer_hostname":{"type":["string","null"],"description":"Traffic source: referrer hostname"},"session_id":{"type":"integer","format":"int32","description":"Session internal ID"},"started_at":{"type":"string","format":"date-time","description":"When the session started"},"utm_campaign":{"type":["string","null"],"description":"UTM campaign parameter"},"utm_medium":{"type":["string","null"],"description":"UTM medium parameter"},"utm_source":{"type":["string","null"],"description":"UTM source parameter"}}},"KeysRequest":{"type":"object","description":"Request to get keys matching a pattern","required":["pattern"],"properties":{"pattern":{"type":"string","description":"Pattern to match (supports * and ? wildcards)","example":"user:*"},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1}}},"KeysResponse":{"type":"object","description":"Response for keys operation","required":["keys"],"properties":{"keys":{"type":"array","items":{"type":"string"},"description":"List of matching keys","example":["user:1","user:2","user:3"]}}},"KillJobBody":{"type":"object","properties":{"force":{"type":"boolean","description":"When true, sends SIGKILL immediately. Defaults to SIGTERM so the\nprocess gets a chance to flush (mirrors `Command.kill()` in\n`@vercel/sandbox`, which also accepts a signal override)."}},"additionalProperties":false},"KnownAiAgentsResponse":{"type":"object","description":"Response listing every AI agent the detector knows about.","required":["items"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AiAgentDescriptor"}}}},"KvStatusResponse":{"type":"object","description":"Response for KV service status","required":["enabled","healthy"],"properties":{"docker_image":{"type":["string","null"],"description":"Docker image being used","example":"gotempsh/redis-walg:8-bookworm"},"enabled":{"type":"boolean","description":"Whether the KV service is enabled"},"healthy":{"type":"boolean","description":"Whether the underlying Redis service is healthy"},"version":{"type":["string","null"],"description":"Service version","example":"7.2"}}},"LemonSqueezyConfig":{"type":"object","properties":{"product_allowlist":{"type":"array","items":{"type":"string"}},"variant_allowlist":{"type":"array","items":{"type":"string"}}}},"LetsEncryptSettings":{"type":"object","properties":{"email":{"type":["string","null"],"default":null},"environment":{"type":"string","default":"production"}}},"LineContext":{"type":"object","description":"Raw surrounding lines for a single match (grep -C style).","required":["before","after"],"properties":{"after":{"type":"array","items":{"$ref":"#/components/schemas/ContextLine"},"description":"Lines immediately after the match, oldest-first."},"before":{"type":"array","items":{"$ref":"#/components/schemas/ContextLine"},"description":"Lines immediately before the match, oldest-first."}}},"LinkServiceRequest":{"type":"object","required":["project_id"],"properties":{"project_id":{"type":"integer","format":"int32"}}},"ListAgentsResponse":{"type":"object","required":["items","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AgentConfigResponse"}},"total":{"type":"integer","minimum":0}}},"ListApiKeysQuery":{"type":"object","properties":{"page":{"type":["integer","null"],"format":"int64","minimum":0},"page_size":{"type":["integer","null"],"format":"int64","minimum":0}}},"ListAuditLogsQuery":{"type":"object","description":"Query parameters for listing audit logs.\n\nEvery field is optional — omitting one means \"don't filter on it\". Deriving\n`IntoParams` makes utoipa render them as optional query params with the\ncorrect types; the previous hand-written `params((\"operation_type\", Query,\n…))` tuples defaulted every param to `required: true, type: string`, which\nmisled both API clients and the AI `describe_api`/`call_api` tools into\nthinking all filters were mandatory.","properties":{"from":{"type":["string","null"],"format":"date-time","description":"Start timestamp (milliseconds since epoch)"},"limit":{"type":["integer","null"],"format":"int32","description":"Maximum number of logs to return"},"offset":{"type":["integer","null"],"format":"int32","description":"Number of logs to skip"},"operation_type":{"type":["string","null"],"description":"Filter logs by operation type (omit for all)"},"to":{"type":["string","null"],"format":"date-time","description":"End timestamp (milliseconds since epoch)"},"user_id":{"type":["integer","null"],"format":"int32","description":"Filter logs by user ID (omit for all users)"}}},"ListBlobsQuery":{"type":"object","description":"Query parameters for listing blobs","properties":{"cursor":{"type":["string","null"],"description":"Continuation token for pagination"},"limit":{"type":["integer","null"],"format":"int32","description":"Maximum number of items to return","example":100},"prefix":{"type":["string","null"],"description":"Prefix to filter by","example":"images/"},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1}}},"ListBlobsResponse":{"type":"object","description":"Response for listing blobs","required":["blobs","hasMore"],"properties":{"blobs":{"type":"array","items":{"$ref":"#/components/schemas/BlobResponse"},"description":"List of blobs"},"cursor":{"type":["string","null"],"description":"Continuation token for next page"},"hasMore":{"type":"boolean","description":"Whether there are more results","example":false}}},"ListCustomDomainsResponse":{"type":"object","required":["domains","total"],"properties":{"domains":{"type":"array","items":{"$ref":"#/components/schemas/CustomDomainResponse"}},"total":{"type":"integer","minimum":0}}},"ListDeploymentTokensQuery":{"type":"object","properties":{"page":{"type":["integer","null"],"format":"int64","example":1,"minimum":0},"page_size":{"type":["integer","null"],"format":"int64","example":20,"minimum":0}}},"ListDomainsResponse":{"type":"object","required":["domains","total","page","page_size"],"properties":{"domains":{"type":"array","items":{"$ref":"#/components/schemas/DomainResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"ListEntitiesQuery":{"type":"object","properties":{"limit":{"type":"integer","description":"Maximum number of entities to return","example":100,"minimum":0},"token":{"type":["string","null"],"description":"Continuation token for pagination (backend-specific)"}}},"ListErrorEventsQuery":{"type":"object","properties":{"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0}}},"ListErrorGroupsQuery":{"type":"object","properties":{"end_date":{"type":["string","null"],"format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"sort_by":{"type":["string","null"]},"sort_order":{"type":"string"},"start_date":{"type":["string","null"],"format":"date-time"},"status":{"type":["string","null"]}}},"ListJobsResponse":{"type":"object","required":["items"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/JobSummaryResponse"}}}},"ListMcpsResponse":{"type":"object","description":"Concrete list wrapper for MCP server definitions (utoipa requires non-generic types).","required":["items","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/McpDefinitionResponse"}},"total":{"type":"integer","minimum":0}}},"ListOnDemandCertsResponse":{"type":"object","description":"Paginated list of on-demand cert attempts (ADR-018 §5 console \"Certificates\"\nsurface). Joined with current `domains.status`, newest first.","required":["certs","total","page","page_size"],"properties":{"certs":{"type":"array","items":{"$ref":"#/components/schemas/OnDemandCertRow"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"ListOrdersResponse":{"type":"object","required":["orders"],"properties":{"orders":{"type":"array","items":{"$ref":"#/components/schemas/AcmeOrderResponse"}}}},"ListPresetsResponse":{"type":"object","required":["presets","total"],"properties":{"presets":{"type":"array","items":{"$ref":"#/components/schemas/PresetResponse"}},"total":{"type":"integer","minimum":0}}},"ListRunsResponse":{"type":"object","required":["items","total","page","page_size"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AgentRunResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"ListSandboxesResponse":{"type":"object","description":"SDK list response: `{ sandboxes: [...], pagination: {...} }`.","required":["sandboxes","pagination"],"properties":{"pagination":{"$ref":"#/components/schemas/Pagination"},"sandboxes":{"type":"array","items":{"$ref":"#/components/schemas/SandboxInner"}}}},"ListScansQuery":{"type":"object","properties":{"page":{"type":["integer","null"],"format":"int64","example":1,"minimum":0},"page_size":{"type":["integer","null"],"format":"int64","example":20,"minimum":0}}},"ListSecretsResponse":{"type":"object","required":["items","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/SecretResponse"}},"total":{"type":"integer","minimum":0}}},"ListSkillsResponse":{"type":"object","description":"Concrete list wrapper for skill definitions (utoipa requires non-generic types).","required":["items","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/SkillDefinitionResponse"}},"total":{"type":"integer","minimum":0}}},"ListTagsResponse":{"type":"object","description":"Response for listing tags","required":["tags","total"],"properties":{"tags":{"type":"array","items":{"type":"string"},"description":"List of available tags"},"total":{"type":"integer","description":"Total number of tags","minimum":0}}},"ListTemplatesQuery":{"type":"object","description":"Query parameters for listing templates","properties":{"featured":{"type":["boolean","null"],"description":"Only return featured templates"},"tag":{"type":["string","null"],"description":"Filter templates by tag"}}},"ListTemplatesResponse":{"type":"object","description":"Response for listing templates","required":["templates","total"],"properties":{"templates":{"type":"array","items":{"$ref":"#/components/schemas/TemplateResponse"},"description":"List of templates"},"total":{"type":"integer","description":"Total number of templates","minimum":0}}},"ListVulnerabilitiesQuery":{"type":"object","properties":{"page":{"type":["integer","null"],"format":"int64","example":1,"minimum":0},"page_size":{"type":["integer","null"],"format":"int64","example":20,"minimum":0},"severity":{"type":["string","null"],"example":"CRITICAL"}}},"LiveVisitorInfo":{"type":"object","required":["id","visitor_id","project_id","environment_id","first_seen","last_seen","is_crawler"],"properties":{"city":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"crawler_name":{"type":["string","null"]},"current_page":{"type":["string","null"],"description":"Most recent page path visited by this visitor"},"custom_data":{},"environment_id":{"type":"integer","format":"int32"},"first_channel":{"type":["string","null"],"description":"Marketing channel from the first visit (e.g. \"Organic Search\", \"Direct\")"},"first_referrer":{"type":["string","null"],"description":"Full referrer URL from the visitor's first session"},"first_referrer_hostname":{"type":["string","null"],"description":"Hostname extracted from first_referrer"},"first_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"id":{"type":"integer","format":"int32"},"ip_address":{"type":["string","null"]},"ip_address_id":{"type":["integer","null"],"format":"int32"},"is_crawler":{"type":"boolean"},"is_eu":{"type":["boolean","null"]},"last_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"latitude":{"type":["number","null"],"format":"double"},"longitude":{"type":["number","null"],"format":"double"},"project_id":{"type":"integer","format":"int32"},"region":{"type":["string","null"]},"timezone":{"type":["string","null"]},"user_agent":{"type":["string","null"]},"visitor_id":{"type":"string"}}},"LiveVisitorsListResponse":{"type":"object","required":["total_count","visitors","window_minutes"],"properties":{"total_count":{"type":"integer","format":"int64"},"visitors":{"type":"array","items":{"$ref":"#/components/schemas/LiveVisitorInfo"}},"window_minutes":{"type":"integer","format":"int32"}}},"LocationCount":{"type":"object","required":["location","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"location":{"type":"string"},"percentage":{"type":"number","format":"double"}}},"LocationGranularity":{"type":"string","enum":["country","region","city"]},"LocationInfo":{"type":"object","properties":{"city":{"type":["string","null"]},"country":{"type":["string","null"]},"region":{"type":["string","null"]}}},"LogLevel":{"type":"string","description":"Normalized log level","enum":["TRACE","DEBUG","INFO","WARN","ERROR"]},"LogRecord":{"type":"object","description":"A single log record ready for storage.","required":["project_id","resource","timestamp","observed_timestamp","severity","severity_text","body","attributes"],"properties":{"attributes":{"type":"object","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"body":{"type":"string"},"deployment_id":{"type":["integer","null"],"format":"int32"},"observed_timestamp":{"type":"string","format":"date-time"},"project_id":{"type":"integer","format":"int32"},"resource":{"$ref":"#/components/schemas/ResourceInfo"},"severity":{"$ref":"#/components/schemas/LogSeverity"},"severity_text":{"type":"string"},"span_id":{"type":["string","null"]},"timestamp":{"type":"string","format":"date-time"},"trace_id":{"type":["string","null"]}}},"LogSearchLine":{"type":"object","description":"A single line in search results","required":["timestamp","level","service","message","chunk_id","line_offset"],"properties":{"chunk_id":{"type":"string"},"container_id":{"type":"string","description":"Container this line came from — lets the UI tag/group lines by container\nin a combined (\"show all\") multi-container view."},"context":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/LineContext","description":"Raw surrounding lines (grep -C). `None` unless `context_lines > 0` was\nrequested. Overlapping windows between nearby matches are merged: the\nshared neighbors appear on the earlier match only, so the frontend can\nrender one continuous block without duplicated lines."}]},"deploy_id":{"type":["integer","null"],"format":"int32"},"fields":{},"level":{"$ref":"#/components/schemas/LogLevel"},"line_offset":{"type":"integer","format":"int32"},"message":{"type":"string"},"node_id":{"type":["integer","null"],"format":"int32","description":"Worker node the line came from (`None` = control-plane-local)."},"node_name":{"type":["string","null"],"description":"Human-readable node name for display."},"service":{"type":"string"},"timestamp":{"type":"string"}}},"LogSeverity":{"type":"string","description":"Log severity level (simplified from OTel's 24 levels).","enum":["TRACE","DEBUG","INFO","WARN","ERROR","FATAL"]},"LogSource":{"type":"object","description":"A distinct log source (container) seen in the queried scope. Used to populate\nthe history filter dropdowns with the *full* set of containers/nodes for the\nproject + env + deployment + time window — independent of the active\ncontainer/node/service filter, so the user can switch between them.","required":["container_id","service"],"properties":{"container_id":{"type":"string"},"node_id":{"type":["integer","null"],"format":"int32"},"node_name":{"type":["string","null"]},"service":{"type":"string"}}},"LogStream":{"type":"string","description":"Log output stream","enum":["stdout","stderr"]},"LoginRequest":{"type":"object","required":["email","password"],"properties":{"email":{"type":"string"},"password":{"type":"string"}}},"LogsQuery":{"type":"object","properties":{"tail":{"type":["integer","null"],"description":"Number of lines to return from the tail. Defaults to 200, capped at 2000.","minimum":0}}},"LogsResponse":{"type":"object","required":["data","count"],"properties":{"count":{"type":"integer","minimum":0},"data":{"type":"array","items":{"$ref":"#/components/schemas/LogRecord"}}}},"ManagedDomainResponse":{"type":"object","description":"Managed domain response","required":["id","provider_id","domain","auto_manage","verified","generated_hostname_mode","sync_generated_records","created_at","updated_at"],"properties":{"auto_manage":{"type":"boolean"},"created_at":{"type":"string"},"domain":{"type":"string"},"generated_hostname_mode":{"type":"string","description":"Generated hostname layout: `\"standard\"` or `\"flat\"`."},"id":{"type":"integer","format":"int32"},"provider_id":{"type":"integer","format":"int32"},"sync_generated_records":{"type":"boolean","description":"Whether generated hostnames are reconciled into the provider's DNS zone."},"updated_at":{"type":"string"},"verification_error":{"type":["string","null"]},"verified":{"type":"boolean"},"verified_at":{"type":["string","null"]},"zone_access_error":{"type":["string","null"],"description":"Detail for a failed zone-access check."},"zone_access_ok":{"type":["boolean","null"],"description":"Last token zone-access check: `Some(true)`/`Some(false)`/`None` (unchecked)."},"zone_id":{"type":["string","null"]}}},"ManualAction":{"type":"object","description":"A manual action the user must perform outside of the automated migration","required":["timing","description","reason"],"properties":{"description":{"type":"string","description":"Human-readable description"},"reason":{"type":"string","description":"Why this can't be automated"},"timing":{"$ref":"#/components/schemas/ManualActionTiming","description":"When this action needs to happen"}}},"ManualActionTiming":{"type":"string","description":"When a manual action needs to happen relative to migration","enum":["before-migration","after-migration","within-hours"]},"McpDefinitionResponse":{"type":"object","required":["id","slug","name","config","created_at","updated_at"],"properties":{"config":{"type":"object"},"created_at":{"type":"string"},"description":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"project_id":{"type":["integer","null"],"format":"int32"},"slug":{"type":"string"},"updated_at":{"type":"string"}}},"MessageContent":{"oneOf":[{"type":"string"},{"type":"array","items":{"$ref":"#/components/schemas/ContentPart"}}]},"MessagePart":{"oneOf":[{"type":"object","required":["text","type"],"properties":{"text":{"type":"string"},"type":{"type":"string","enum":["text"]}}},{"type":"object","required":["tool","type"],"properties":{"tool":{"$ref":"#/components/schemas/ToolInfo"},"type":{"type":"string","enum":["tool"]}}}],"description":"One ordered segment of an assistant turn: a chunk of prose, or a tool\ninvocation. Mirrors the `metadata.parts` persisted by the chat service."},"MessageResponse":{"type":"object","required":["role","content","created_at"],"properties":{"content":{"type":"string"},"created_at":{"type":"string"},"parts":{"type":["array","null"],"items":{"$ref":"#/components/schemas/MessagePart"},"description":"Ordered render segments (text / tool, in the order they occurred) so a\nreloaded chat shows the same interleaving as the live stream. Absent for\nolder messages persisted before parts were tracked; the client then falls\nback to `tools` (rendered first) + `content`."},"role":{"type":"string"},"tools":{"type":["array","null"],"items":{"$ref":"#/components/schemas/ToolInfo"},"description":"Tools the assistant ran on this turn (persisted in message metadata), so\nthe chat replays its tool work after a reload. Absent for plain turns."}}},"MeteredMode":{"type":"string","description":"How to treat metered-billing subscriptions when computing MRR.\n\n* `DeriveFromInvoices` (default): ignore the subscription row's\n `mrr_minor` for metered items and rely on the per-invoice\n [`NormalizedEventType::MrrRealized`] events instead. Correct for\n pure-metered, hybrid, tiered, and flat — recommended.\n* `UseSubscription`: trust whatever MRR the subscription parser\n returns (0 for metered). Legacy behavior.\n* `Ignore`: drop metered subscriptions from MRR entirely.","enum":["derive_from_invoices","use_subscription","ignore"]},"MetricAggregation":{"oneOf":[{"type":"string","description":"Arithmetic mean of the scalar value in each bucket. The default.","enum":["avg"]},{"type":"string","description":"Sum of the scalar value in each bucket.","enum":["sum"]},{"type":"string","description":"Minimum scalar value in each bucket.","enum":["min"]},{"type":"string","description":"Maximum scalar value in each bucket.","enum":["max"]},{"type":"string","description":"Number of points in each bucket.","enum":["count"]},{"type":"string","description":"Per-second rate of change of a cumulative monotonic counter, computed as\n`(max - min) / window_seconds` within each bucket. Non-monotonic series\nfall back to a simple delta.","enum":["rate_per_sec"]},{"type":"object","description":"A quantile of the scalar value in each bucket. The carried `f64` is the\nrequested quantile in `[0.0, 1.0]`.","required":["quantile"],"properties":{"quantile":{"type":"number","format":"double","description":"A quantile of the scalar value in each bucket. The carried `f64` is the\nrequested quantile in `[0.0, 1.0]`."}}}],"description":"The aggregation applied when reducing raw metric points into a time bucket.\n\nStore-neutral: every storage backend (ClickHouse today, TimescaleDB later)\nmust be able to satisfy this contract. `Quantile(q)` carries the requested\nquantile in `[0.0, 1.0]` (e.g. `0.95` for p95)."},"MetricBucket":{"type":"object","description":"A time-bucketed metric aggregate for chart display.\n\nStore-neutral response contract. The legacy scalar fields\n(`avg_value`/`min_value`/`max_value`/`count`) are always populated for chart\nback-compat. The richer fields describe the explicitly-requested\n[`MetricAggregation`] (`value`), optional `quantiles`, an optional\n`histogram_summary`, and a `series_key` identifying the label-set when the\nquery used `group_by`.","required":["bucket","avg_value","min_value","max_value","count"],"properties":{"avg_value":{"type":"number","format":"double"},"bucket":{"type":"string","format":"date-time"},"count":{"type":"integer","format":"int64"},"histogram_summary":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/HistogramSummary","description":"A reduced histogram summary when the bucketed metric is a histogram."}]},"max_value":{"type":"number","format":"double"},"min_value":{"type":"number","format":"double"},"quantiles":{"type":"array","items":{"type":"array","items":false,"prefixItems":[{"type":"number","format":"double"},{"type":"number","format":"double"}]},"description":"Computed quantile/value pairs `(quantile, value)` when the query asked for\nquantile aggregation; otherwise empty."},"series_key":{"type":["array","null"],"items":{"type":"array","items":false,"prefixItems":[{"type":"string"},{"type":"string"}]},"description":"The label-set this bucket belongs to, as ordered `(key, value)` pairs,\nwhen the query grouped by labels. Empty/`None` = the single ungrouped\naggregate stream."},"value":{"type":"number","format":"double","description":"The value of the requested [`MetricAggregation`] for this bucket. For the\ndefault `Avg` aggregation this equals `avg_value`. `#[serde(default)]` so\npre-existing payloads (which only carried avg/min/max/count) still parse."}}},"MetricDataPoint":{"type":"object","description":"A single `(timestamp, value)` data point in a metric series.","required":["time","value"],"properties":{"time":{"type":"string","description":"ISO 8601 timestamp with `Z` suffix."},"value":{"type":"number","format":"double","description":"Metric value at this bucket."}}},"MetricType":{"type":"string","description":"The type of an OTel metric.","enum":["gauge","sum","histogram","exponential_histogram","summary"]},"MetricsOverTimeResponse":{"type":"object","required":["timestamps","ttfb","lcp","fid","fcp","cls","inp"],"properties":{"cls":{"type":"array","items":{"type":["number","null"],"format":"float"}},"cls_p75":{"type":["number","null"],"format":"float"},"cls_p90":{"type":["number","null"],"format":"float"},"cls_p95":{"type":["number","null"],"format":"float"},"cls_p99":{"type":["number","null"],"format":"float"},"fcp":{"type":"array","items":{"type":["number","null"],"format":"float"}},"fcp_p75":{"type":["number","null"],"format":"float"},"fcp_p90":{"type":["number","null"],"format":"float"},"fcp_p95":{"type":["number","null"],"format":"float"},"fcp_p99":{"type":["number","null"],"format":"float"},"fid":{"type":"array","items":{"type":["number","null"],"format":"float"}},"fid_p75":{"type":["number","null"],"format":"float"},"fid_p90":{"type":["number","null"],"format":"float"},"fid_p95":{"type":["number","null"],"format":"float"},"fid_p99":{"type":["number","null"],"format":"float"},"inp":{"type":"array","items":{"type":["number","null"],"format":"float"}},"inp_p75":{"type":["number","null"],"format":"float"},"inp_p90":{"type":["number","null"],"format":"float"},"inp_p95":{"type":["number","null"],"format":"float"},"inp_p99":{"type":["number","null"],"format":"float"},"lcp":{"type":"array","items":{"type":["number","null"],"format":"float"}},"lcp_p75":{"type":["number","null"],"format":"float"},"lcp_p90":{"type":["number","null"],"format":"float"},"lcp_p95":{"type":["number","null"],"format":"float"},"lcp_p99":{"type":["number","null"],"format":"float"},"timestamps":{"type":"array","items":{"type":"string"}},"ttfb":{"type":"array","items":{"type":["number","null"],"format":"float"}},"ttfb_p75":{"type":["number","null"],"format":"float"},"ttfb_p90":{"type":["number","null"],"format":"float"},"ttfb_p95":{"type":["number","null"],"format":"float"},"ttfb_p99":{"type":["number","null"],"format":"float"}}},"MetricsQuery":{"type":"object","required":["start_date","end_date","project_id"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"MetricsRangeQuery":{"type":"object","description":"Query params for range metric queries.","required":["metric"],"properties":{"metric":{"type":"string","description":"Metric name, e.g. `\"pg.connections_active\"`."},"percentile":{"type":["number","null"],"format":"double","description":"Optional histogram percentile (0–100). When provided, the endpoint\nfetches histogram buckets and computes the requested quantile."},"range":{"type":"string","description":"Time window: `\"1h\"` | `\"6h\"` | `\"24h\"` | `\"7d\"`."}}},"MetricsStatusResponse":{"type":"object","description":"Freshness status: when metrics were last received for this service.","properties":{"last_received_at":{"type":["string","null"],"description":"ISO 8601 timestamp of the most recent metric row, or null if none yet."}}},"MetricsStoreKind":{"type":"string","description":"Which storage backend to use for the MetricsStore.","enum":["timescale_db","click_house"]},"MetricsSummaryResponse":{"type":"object","required":["currency","current_mrr_minor","current_arr_minor","active_subscriptions","active_customers","churned_last_30d","arpu_minor"],"properties":{"active_customers":{"type":"integer","format":"int64"},"active_subscriptions":{"type":"integer","format":"int64"},"arpu_minor":{"type":"integer","format":"int64"},"churned_last_30d":{"type":"integer","format":"int64"},"currency":{"type":"string"},"current_arr_minor":{"type":"integer","format":"int64"},"current_mrr_minor":{"type":"integer","format":"int64"}}},"MfaRequiredResponse":{"type":"object","required":["requires_mfa","session_token"],"properties":{"requires_mfa":{"type":"boolean"},"session_token":{"type":"string"}}},"MfaSetupResponse":{"type":"object","required":["secret_key","qr_code","recovery_codes"],"properties":{"qr_code":{"type":"string"},"recovery_codes":{"type":"array","items":{"type":"string"}},"secret_key":{"type":"string"}}},"MfaVerificationRequest":{"type":"object","required":["code"],"properties":{"code":{"type":"string"}}},"MigrationStep":{"type":"object","description":"A single step in the migration execution plan.\n\nSteps are presented to the user before execution so they know exactly\nwhat will happen. During execution, each step runs in order and reports\nits outcome before proceeding to the next.","required":["order","id","title","description","resource_type","risk","skippable","reversible"],"properties":{"data_implications":{"type":"array","items":{"$ref":"#/components/schemas/DataImplication"},"description":"Data implications — what could go wrong or what the user needs to know"},"description":{"type":"string","description":"Detailed description of what this step does"},"estimated_duration":{"type":["string","null"],"description":"Estimated duration hint (e.g., \"< 1 second\", \"10-30 seconds\")"},"id":{"type":"string","description":"Machine-readable step identifier (e.g., \"create-project\", \"create-service-postgres\")"},"order":{"type":"integer","description":"Step number (1-based, for display)","minimum":0},"post_conditions":{"type":"array","items":{"type":"string"},"description":"Things the user should verify AFTER this step completes"},"pre_conditions":{"type":"array","items":{"type":"string"},"description":"Things the user should verify BEFORE this step runs"},"resource_type":{"$ref":"#/components/schemas/StepResourceType","description":"What kind of resource this step creates/modifies"},"reversible":{"type":"boolean","description":"Whether this step is reversible (can be cleaned up on failure)"},"risk":{"$ref":"#/components/schemas/RiskLevel","description":"Risk level for this step"},"skippable":{"type":"boolean","description":"Whether this step can be skipped by the user"},"skipped":{"type":"boolean","description":"Whether the user has chosen to skip this step (set during review)"},"title":{"type":"string","description":"Human-readable title (e.g., \"Create project 'my-app'\")"}}},"MigrationSummary":{"type":"object","description":"Human-readable summary of the entire migration plan","required":["headline","overall_risk","resource_counts"],"properties":{"critical_warnings":{"type":"array","items":{"type":"string"},"description":"Critical warnings that must be acknowledged before proceeding.\nThese are the most important things the user needs to know."},"headline":{"type":"string","description":"One-line summary (e.g., \"Migrate 'my-app' from Vercel with 1 database, 2 domains\")"},"manual_actions_required":{"type":"array","items":{"$ref":"#/components/schemas/ManualAction"},"description":"Manual actions the user must perform (before or after migration)"},"overall_risk":{"$ref":"#/components/schemas/RiskLevel","description":"Overall risk assessment for the migration"},"resource_counts":{"$ref":"#/components/schemas/ResourceCounts","description":"Resource counts for quick overview"},"unsupported_features":{"type":"array","items":{"$ref":"#/components/schemas/UnsupportedFeature"},"description":"Features from the source platform that cannot be migrated"}}},"MintEnrollmentTokenRequest":{"type":"object","properties":{"bound_node_name":{"type":["string","null"],"description":"Optional: restrict the token to register one specific node name."},"max_uses":{"type":["integer","null"],"format":"int32","description":"Maximum registrations this token may authorize (default 1)."},"ttl_secs":{"type":["integer","null"],"format":"int64","description":"Time-to-live in seconds (default 3600 = 1h)."}}},"MintEnrollmentTokenResponse":{"type":"object","required":["id","token","expires_at","max_uses","message"],"properties":{"ca_fingerprint":{"type":["string","null"],"description":"SHA-256 fingerprint of the cluster CA (if mTLS is set up). Pass it to the\nworker as `temps join --ca-fingerprint ` to verify the CA on join."},"expires_at":{"type":"string"},"id":{"type":"integer","format":"int32"},"max_uses":{"type":"integer","format":"int32"},"message":{"type":"string"},"token":{"type":"string","description":"The plaintext enrollment token — shown only once, save it now."}}},"MiscResult":{"type":"object","description":"Miscellaneous validation result","required":["is_disposable","is_role_account","is_b2c"],"properties":{"gravatar_url":{"type":["string","null"],"description":"Gravatar URL if available"},"is_b2c":{"type":"boolean","description":"Whether the email provider is a B2C (consumer) email provider"},"is_disposable":{"type":"boolean","description":"Whether the email is from a disposable email provider"},"is_role_account":{"type":"boolean","description":"Whether the email is a role-based account (e.g., admin@, info@)"}}},"MkdirBody":{"type":"object","required":["path"],"properties":{"path":{"type":"string"}},"additionalProperties":false},"ModelInfo":{"type":"object","required":["id","object","owned_by"],"properties":{"id":{"type":"string"},"object":{"type":"string"},"owned_by":{"type":"string"}}},"ModelListResponse":{"type":"object","required":["object","data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ModelInfo"}},"object":{"type":"string"}}},"ModelPricing":{"type":"object","description":"Pricing for a single model, all values in USD per 1M tokens.\nFields are optional because not every provider supports every pricing tier.","required":["model","display_name","provider","input_per_million","output_per_million"],"properties":{"batch_input_per_million":{"type":["number","null"],"format":"double","description":"Batch API input cost per 1M tokens (if provider offers batch pricing)"},"batch_output_per_million":{"type":["number","null"],"format":"double","description":"Batch API output cost per 1M tokens"},"cache_hit_per_million":{"type":["number","null"],"format":"double","description":"Cache hit / refresh cost per 1M tokens"},"cache_write_1h_per_million":{"type":["number","null"],"format":"double","description":"1-hour cache write cost per 1M tokens"},"cache_write_5m_per_million":{"type":["number","null"],"format":"double","description":"5-minute cache write cost per 1M tokens (Anthropic-style prompt caching)"},"deprecated":{"type":"boolean","description":"Whether the model is deprecated"},"display_name":{"type":"string","description":"Human-readable model name (e.g. \"Claude Sonnet 4.6\")"},"input_per_million":{"type":"number","format":"double","description":"Base input token cost per 1M tokens"},"model":{"type":"string","description":"Model identifier (e.g. \"gpt-5.4\", \"claude-sonnet-4-6\")"},"output_per_million":{"type":"number","format":"double","description":"Output token cost per 1M tokens"},"provider":{"type":"string","description":"Provider ID (e.g. \"openai\", \"anthropic\")"}}},"ModelUsage":{"type":"object","required":["model","provider","request_count","input_tokens","output_tokens","total_tokens","avg_latency_ms"],"properties":{"avg_latency_ms":{"type":"number","format":"double"},"input_tokens":{"type":"integer","format":"int64"},"model":{"type":"string"},"output_tokens":{"type":"integer","format":"int64"},"provider":{"type":"string"},"request_count":{"type":"integer","format":"int64"},"total_tokens":{"type":"integer","format":"int64"}}},"MonitorResponse":{"type":"object","required":["id","project_id","name","monitor_type","monitor_url","check_interval_seconds","is_active","created_at","updated_at"],"properties":{"check_interval_seconds":{"type":"integer","format":"int32"},"check_path":{"type":["string","null"]},"created_at":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"monitor_type":{"type":"string"},"monitor_url":{"type":"string"},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"updated_at":{"type":"string","format":"date-time"}}},"MonitorStatus":{"type":"object","required":["monitor","current_status","uptime_percentage"],"properties":{"avg_response_time_ms":{"type":["integer","null"],"format":"int32"},"current_status":{"type":"string"},"monitor":{"$ref":"#/components/schemas/MonitorResponse"},"uptime_percentage":{"type":"number","format":"double"}}},"MonitoringSettings":{"type":"object","description":"Global metrics observability configuration.\n\nControls whether the MetricsScraper and AlertEvaluator background tasks\nare active, which storage backend they write to, and how long data is kept\nat each retention tier.","properties":{"clickhouse_url":{"type":["string","null"],"description":"ClickHouse DSN (legacy, optional). The runtime metrics store is built\nfrom the `TEMPS_CLICKHOUSE_*` env vars, never from this field; it is\nretained for compatibility and operator reference only.\nExample: `\"http://localhost:8123\"`.","default":null},"enabled":{"type":"boolean","description":"Enable or disable all metrics collection (scraping + alerting).\nDefaults to `false` so new installs don't write to TimescaleDB until\nan operator explicitly enables the feature.","default":false},"retention_daily_years":{"type":"integer","format":"int32","description":"How many years of daily-aggregate data to keep (converted to days internally).","default":2,"example":2,"maximum":10,"minimum":1},"retention_hourly_days":{"type":"integer","format":"int32","description":"How many days of hourly-aggregate data to keep.","default":90,"example":90,"minimum":1},"retention_raw_days":{"type":"integer","format":"int32","description":"How many days of raw (30 s resolution) metric data to keep.","default":7,"example":7,"minimum":1},"scrape_interval_secs":{"type":"integer","format":"int64","description":"How often the MetricsScraper collects data from all sources, in seconds.\nMinimum effective value is 10 s; values below that are clamped at runtime.","default":30,"example":30,"minimum":10},"store":{"oneOf":[{"$ref":"#/components/schemas/MetricsStoreKind","description":"Storage backend for metric data."}],"default":"timescale_db"}}},"MonitoringSettingsMasked":{"type":"object","description":"Monitoring settings with the ClickHouse DSN masked.\n\n`clickhouse_url` can embed credentials (`http://user:pass@host`), so it is\nreported only as a boolean (`clickhouse_url_set`) rather than echoed back —\nconsistent with how the DNS API key and Docker registry password are masked.","required":["enabled","store","scrape_interval_secs","retention_raw_days","retention_hourly_days","retention_daily_years","clickhouse_url_set"],"properties":{"clickhouse_url_set":{"type":"boolean","description":"True when a ClickHouse DSN is configured. The DSN itself is never\nreturned over HTTP because it may contain credentials."},"enabled":{"type":"boolean"},"retention_daily_years":{"type":"integer","format":"int32","minimum":0},"retention_hourly_days":{"type":"integer","format":"int32","minimum":0},"retention_raw_days":{"type":"integer","format":"int32","minimum":0},"scrape_interval_secs":{"type":"integer","format":"int64","minimum":0},"store":{"$ref":"#/components/schemas/MetricsStoreKind"}}},"MrrBucketResponse":{"type":"object","required":["bucket","mrr_minor","charge_total_minor","refund_total_minor","charge_count"],"properties":{"bucket":{"type":"string","format":"date-time"},"charge_count":{"type":"integer","format":"int64"},"charge_total_minor":{"type":"integer","format":"int64"},"mrr_minor":{"type":"integer","format":"int64"},"refund_total_minor":{"type":"integer","format":"int64"}}},"MultiNodeSettings":{"type":"object","description":"Multi-node cluster settings","properties":{"cluster_ca_cert_pem":{"type":["string","null"],"description":"Per-cluster CA certificate (PEM) for multi-node mTLS (ADR-020 WS-2.1).\nPublic — distributed to nodes as the trust root and used by the control\nplane as the root for verifying agent server certs. Minted lazily on the\nfirst CSR-bearing registration.","default":null},"cluster_ca_key_encrypted":{"type":["string","null"],"description":"Per-cluster CA private key, AES-256-GCM ciphertext (EncryptionService).\nSECRET — never returned over HTTP (elided in the masked response).","default":null},"join_token_hash":{"type":["string","null"],"description":"SHA-256 hash of the join token (never store plaintext)","default":null},"legacy_shared_token_enabled":{"type":"boolean","description":"Whether the legacy single shared join token is still accepted for node\nregistration (ADR-020 WS-1.1). Defaults to `true` so existing clusters\nkeep working on upgrade; fresh installs should set it `false` and rely on\nshort-lived, single-use enrollment tokens instead.","default":true},"node_cpu_alert_percent":{"type":["number","null"],"format":"double","description":"CPU-usage percent above which a worker node raises a resource alert\n(ADR-020 / monitoring). `None` disables CPU alerting. Default 90.","default":90.0},"node_disk_alert_percent":{"type":["number","null"],"format":"double","description":"Disk-usage percent above which a worker node raises a resource alert.\n`None` disables disk alerting. Default 90.","default":90.0},"node_memory_alert_percent":{"type":["number","null"],"format":"double","description":"Memory-usage percent above which a worker node raises a resource alert.\n`None` disables memory alerting. Default 90.","default":90.0},"private_address":{"type":["string","null"],"description":"Private/WireGuard IP address of the control plane node.\nUsed by remote worker nodes to reach services (databases, etc.) running on the control plane.\nSet via `--private-address` or `TEMPS_PRIVATE_ADDRESS`.","default":null},"require_mtls":{"type":"boolean","description":"Whether to enforce multi-node mTLS (ADR-020 WS-2.1). When `false`\n(default), the control plane ignores join-time CSRs and nodes keep\nserving plaintext HTTP — zero behavior change. When `true`, the CP signs\nnode CSRs, nodes serve mutual TLS, and every CP→agent call uses the\ncluster client cert. Observe-then-enforce: flip this on only once all\nworkers have re-enrolled with certs.","default":false}}},"MultiNodeSettingsMasked":{"type":"object","description":"Multi-node settings with `join_token_hash` elided.","required":["has_join_token","require_mtls","legacy_shared_token_enabled"],"properties":{"cluster_ca_fingerprint":{"type":["string","null"],"description":"SHA-256 fingerprint of the cluster CA certificate (public — operators can\nverify it out of band; the CA private key is never exposed)."},"has_join_token":{"type":"boolean"},"legacy_shared_token_enabled":{"type":"boolean","description":"Whether the deprecated shared join token is still accepted."},"node_cpu_alert_percent":{"type":["number","null"],"format":"double","description":"Node resource-alert thresholds (percent); `None` = that alert disabled."},"node_disk_alert_percent":{"type":["number","null"],"format":"double"},"node_memory_alert_percent":{"type":["number","null"],"format":"double"},"private_address":{"type":["string","null"]},"require_mtls":{"type":"boolean","description":"Whether control-plane↔agent mutual TLS is enforced."}}},"MxResult":{"type":"object","description":"MX (Mail Exchange) validation result","required":["accepts_mail","records"],"properties":{"accepts_mail":{"type":"boolean","description":"Whether the domain accepts mail"},"error":{"type":["string","null"],"description":"Error message if MX lookup failed"},"records":{"type":"array","items":{"type":"string"},"description":"List of MX records for the domain","example":["alt1.gmail-smtp-in.l.google.com.","gmail-smtp-in.l.google.com."]}}},"NavEntry":{"type":"object","description":"A navigation entry that the plugin contributes to the Temps UI.","required":["label","icon","section","path","order"],"properties":{"icon":{"type":"string","description":"Lucide icon name (e.g., \"puzzle\", \"database\", \"activity\")"},"label":{"type":"string","description":"Display label in the sidebar"},"order":{"type":"integer","format":"int32","description":"Sort order within the section (lower = higher in list)","minimum":0},"path":{"type":"string","description":"Client-side route path (e.g., \"/my-plugin\")"},"section":{"$ref":"#/components/schemas/NavSection","description":"Which sidebar section this entry belongs to"}}},"NavSection":{"type":"string","description":"Where the plugin's nav entry appears in the Temps UI sidebar.","enum":["platform","settings","project"]},"NetworkConfiguration":{"type":"object","description":"Network configuration","required":["mode","dns_servers"],"properties":{"dns_servers":{"type":"array","items":{"type":"string"},"description":"DNS servers"},"hostname":{"type":["string","null"],"description":"Hostname"},"mode":{"$ref":"#/components/schemas/NetworkMode","description":"Network mode"}}},"NetworkMode":{"oneOf":[{"type":"string","enum":["bridge"]},{"type":"string","enum":["host"]},{"type":"string","enum":["none"]},{"type":"object","required":["custom"],"properties":{"custom":{"type":"string"}}}],"description":"Network mode"},"NixpacksPresetConfig":{"type":"object","description":"Configuration for Nixpacks preset\nNixpacks provider and inline build-plan configuration.","properties":{"nixpacksConfig":{"type":["string","null"],"description":"Optional inline nixpacks.toml contents."},"providers":{"type":"array","items":{"$ref":"#/components/schemas/NixpacksProvider"},"description":"Ordered Nixpacks providers. Empty means repository config or auto-detect;\ninclude `...` to combine auto-detection with explicit providers."}}},"NixpacksProvider":{"type":"string","description":"A Nixpacks build provider.\n\n`Auto` serializes as the native Nixpacks `...` marker, which includes the\nprovider detected from the project alongside any explicitly listed\nproviders.","enum":["...","node","python","rust","go","java","php","ruby","deno","elixir","csharp","fsharp","dart","swift","zig","scala","haskell","clojure","crystal","cobol","gleam","lunatic","scheme","static"]},"NodeContainerListResponse":{"type":"object","required":["containers","total"],"properties":{"containers":{"type":"array","items":{"$ref":"#/components/schemas/NodeContainerResponse"}},"total":{"type":"integer","minimum":0}}},"NodeContainerResponse":{"type":"object","description":"A container running on a specific node, enriched with project/environment context.","required":["container_id","container_name","image_name","status","created_at","deployment_id","project_id","project_name","environment_id","environment_name"],"properties":{"container_id":{"type":"string"},"container_name":{"type":"string"},"created_at":{"type":"string"},"deployment_id":{"type":"integer","format":"int32"},"environment_id":{"type":"integer","format":"int32"},"environment_name":{"type":"string"},"image_name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"project_name":{"type":"string"},"status":{"type":"string"}}},"NodeCostInfo":{"type":"object","description":"One cluster node with capacity and (when priceable) a cost estimate","required":["name","cpu_millis","memory_mb"],"properties":{"cpu_millis":{"type":"integer","format":"int64","description":"CPU capacity in millicores"},"instance_type":{"type":["string","null"],"description":"Instance type from `node.kubernetes.io/instance-type` (e.g. \"m5.xlarge\")"},"memory_mb":{"type":"integer","format":"int64","description":"Memory capacity in MB"},"monthly_usd":{"type":["number","null"],"format":"double","description":"Estimated on-demand monthly price in USD. `None` when the instance\ntype is unknown or not in the price table."},"name":{"type":"string","description":"Node name"},"region":{"type":["string","null"],"description":"Region from `topology.kubernetes.io/region`"}}},"NodeInfoResponse":{"type":"object","required":["id","name","address","private_address","role","status","labels","capacity","created_at"],"properties":{"address":{"type":"string"},"architecture":{"type":["string","null"],"description":"Container platform this node runs (`linux/amd64`, `linux/arm64`).\n`None` until an agent that reports it has heartbeated."},"capacity":{"description":"Resource capacity/usage metrics from the latest heartbeat"},"created_at":{"type":"string"},"id":{"type":"integer","format":"int32"},"labels":{},"last_heartbeat":{"type":["string","null"]},"name":{"type":"string"},"private_address":{"type":"string"},"role":{"type":"string"},"status":{"type":"string"}}},"NodeListResponse":{"type":"object","required":["nodes","total"],"properties":{"nodes":{"type":"array","items":{"$ref":"#/components/schemas/NodeInfoResponse"}},"total":{"type":"integer","minimum":0}}},"NotificationPreferencesResponse":{"type":"object","required":["email_enabled","slack_enabled","batch_similar_notifications","minimum_severity","deployment_failures_enabled","build_errors_enabled","runtime_errors_enabled","error_threshold","error_time_window","ssl_expiration_enabled","ssl_days_before_expiration","domain_expiration_enabled","dns_changes_enabled","backup_failures_enabled","backup_successes_enabled","s3_connection_issues_enabled","retention_policy_violations_enabled","route_downtime_enabled","load_balancer_issues_enabled","weekly_digest_enabled","digest_send_day","digest_send_time","digest_sections"],"properties":{"backup_failures_enabled":{"type":"boolean"},"backup_successes_enabled":{"type":"boolean"},"batch_similar_notifications":{"type":"boolean"},"build_errors_enabled":{"type":"boolean"},"deployment_failures_enabled":{"type":"boolean"},"digest_sections":{"$ref":"#/components/schemas/DigestSections"},"digest_send_day":{"type":"string"},"digest_send_time":{"type":"string"},"dns_changes_enabled":{"type":"boolean"},"domain_expiration_enabled":{"type":"boolean"},"email_enabled":{"type":"boolean"},"error_threshold":{"type":"integer","format":"int32"},"error_time_window":{"type":"integer","format":"int32"},"load_balancer_issues_enabled":{"type":"boolean"},"minimum_severity":{"type":"string"},"retention_policy_violations_enabled":{"type":"boolean"},"route_downtime_enabled":{"type":"boolean"},"runtime_errors_enabled":{"type":"boolean"},"s3_connection_issues_enabled":{"type":"boolean"},"slack_enabled":{"type":"boolean"},"ssl_days_before_expiration":{"type":"integer","format":"int32"},"ssl_expiration_enabled":{"type":"boolean"},"weekly_digest_enabled":{"type":"boolean"}}},"NotificationProviderResponse":{"type":"object","required":["id","name","provider_type","config","enabled","created_at","updated_at"],"properties":{"config":{},"created_at":{"type":"integer","format":"int64"},"enabled":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"provider_type":{"type":"string"},"updated_at":{"type":"integer","format":"int64"}}},"ObservabilityCompressionSettings":{"type":"object","description":"TimescaleDB compression policy configuration for append-only observability\ntables. Values are expressed in hours so operators can choose sub-day\nwindows while keeping the API representation unambiguous.","properties":{"otel_spans_after_hours":{"type":"integer","format":"int32","description":"Compress OpenTelemetry span chunks after this many hours. Defaults to\n24 hours.","default":24,"example":24,"maximum":2160,"minimum":1},"proxy_logs_after_hours":{"type":"integer","format":"int32","description":"Compress proxy-log chunks after this many hours. Defaults to 24 hours.","default":24,"example":24,"maximum":720,"minimum":1}}},"ObservabilityEvent":{"oneOf":[{"allOf":[{"$ref":"#/components/schemas/RequestRow"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["request"]}}}]},{"allOf":[{"$ref":"#/components/schemas/SpanRow"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["span"]}}}]},{"allOf":[{"$ref":"#/components/schemas/ErrorRow"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["error"]}}}]},{"allOf":[{"$ref":"#/components/schemas/RevenueRow"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["revenue"]}}}]}],"description":"Discriminated union of every row that can appear in the Observe list.\n\nSerializes to `{ \"type\": \"request\" | \"span\" | ... , ...rest }` so the UI\ncan switch on `event.type` without ambiguity.\n\n**No `Log` variant**: runtime stdout/stderr lines live on a dedicated\nLogs page rather than Observe. Logs are too high-volume to interleave\nwith business signals (requests, errors, revenue) without dominating\nthe timeline, and they have their own retention/storage constraints\n(TimescaleDB hypertable + chunked file/S3 store) that don't compose\nwith the merge service's per-kind LIMIT strategy."},"ObservabilityRetentionSettings":{"type":"object","description":"Retention policy configuration for raw observability tables. Values are in\ndays. The Settings API applies them to TimescaleDB; ClickHouse-backed proxy\nlogs and spans retain their storage-level per-row TTL behavior.","properties":{"otel_logs_days":{"type":"integer","format":"int32","description":"Retain OpenTelemetry log events for this many days.","default":90,"example":90,"maximum":3650,"minimum":1},"otel_metrics_days":{"type":"integer","format":"int32","description":"Retain OpenTelemetry metric points for this many days.","default":90,"example":90,"maximum":3650,"minimum":1},"otel_spans_days":{"type":"integer","format":"int32","description":"Retain OpenTelemetry spans (traces) for this many days.","default":90,"example":90,"maximum":3650,"minimum":1},"proxy_logs_days":{"type":"integer","format":"int32","description":"Retain proxy request logs for this many days.","default":30,"example":30,"maximum":3650,"minimum":1}}},"OidcProviderResponse":{"type":"object","required":["id","name","issuer_url","client_id","client_secret","scopes","jit_provisioning","enabled","template","group_claim","role_claim","default_role","trust_idp_email"],"properties":{"client_id":{"type":"string"},"client_secret":{"type":"string","description":"Always masked — the secret is never returned after creation."},"default_role":{"type":"string"},"enabled":{"type":"boolean"},"group_claim":{"type":"string"},"id":{"type":"integer","format":"int32"},"issuer_url":{"type":"string"},"jit_provisioning":{"type":"boolean"},"name":{"type":"string"},"role_claim":{"type":"string"},"scopes":{"type":"string"},"template":{"type":"string"},"trust_idp_email":{"type":"boolean","description":"When true, the resolver skips the `email_verified` claim gate\nduring SSO login. Only safe for IdPs where an admin controls\nuser provisioning — see `oidc_providers::Model::trust_idp_email`."}}},"OidcProviderSummary":{"type":"object","required":["slug","name","template"],"properties":{"name":{"type":"string"},"slug":{"type":"string","description":"Stable opaque slug — use this as the path parameter when initiating\nOIDC login (`/auth/oidc/login/{slug}`). The integer database ID is\nintentionally omitted from this public endpoint to prevent provider\nenumeration."},"template":{"type":"string","description":"The template the provider was created from — e.g. `keycloak`,\n`okta`, `auth0`, `google`, `azure-ad`, or `generic`. Surfaced on\nthe public login endpoint so the unauthenticated login page can\nrender the right brand logo on the \"Sign in with X\" button.\nNever sensitive — the template name is part of the provider's\npublic identity, not configuration."}}},"OidcProviderUserResponse":{"type":"object","description":"A user that has logged in via a given OIDC provider. Used by the\nadmin \"Users for provider\" panel — the `oidc_subject` is the\nIdP-side identifier we matched on, useful when diagnosing why a\nuser can or can't log in.","required":["id","name","email","email_verified","mfa_enabled","created_at","updated_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2024-01-15T14:30:00Z"},"email":{"type":"string"},"email_verified":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"mfa_enabled":{"type":"boolean"},"name":{"type":"string"},"oidc_subject":{"type":["string","null"]},"updated_at":{"type":"string","format":"date-time","example":"2024-01-15T14:30:00Z"}}},"OidcProvidersListResponse":{"type":"object","required":["providers"],"properties":{"providers":{"type":"array","items":{"$ref":"#/components/schemas/OidcProviderSummary"}}}},"OidcRoleMappingResponse":{"type":"object","required":["id","provider_id","priority","idp_group","role"],"properties":{"id":{"type":"integer","format":"int32"},"idp_group":{"type":"string"},"priority":{"type":"integer","format":"int32"},"provider_id":{"type":"integer","format":"int32"},"role":{"type":"string"}}},"OidcTestConnectionResponse":{"type":"object","required":["success","message"],"properties":{"message":{"type":"string"},"success":{"type":"boolean"}}},"OnDemandCertAttemptResponse":{"type":"object","description":"A single on-demand HTTP-01 issuance attempt from the append-only\n`on_demand_cert_attempts` audit log. Carries the full forensic detail for one\nattempt; the current cert state lives on the enclosing row's domain fields.\n\nContains no private-key or certificate material — only audit metadata — so it\nis safe to return without masking.","required":["id","hostname","trigger","outcome","created_at"],"properties":{"acme_request_sent":{"type":["boolean","null"],"description":"Did we reach the Let's Encrypt API?"},"acme_response_status":{"type":["string","null"],"description":"HTTP status or ACME error type returned by Let's Encrypt, when known."},"challenge_served":{"type":["boolean","null"],"description":"Did the proxy serve the `/.well-known/acme-challenge/` request?"},"created_at":{"type":"integer","format":"int64","description":"When the attempt was recorded (epoch millis)."},"duration_ms":{"type":["integer","null"],"format":"int32","description":"End-to-end issuance duration in milliseconds (0/None for skipped)."},"error_category":{"type":["string","null"],"description":"Coarse error category for UI labelling: `\"rate_limited\"`, `\"dns_failure\"`,\n`\"acme_order_expired\"`, `\"challenge_mismatch\"`, `\"timeout\"`, `\"internal\"`."},"error_chain":{"type":["string","null"],"description":"Full `Display` chain of the error (all `source()` levels), when failed."},"hostname":{"type":"string","description":"SNI hostname that triggered the attempt."},"id":{"type":"integer","format":"int32"},"outcome":{"type":"string","description":"Final outcome: `\"issued\"`, `\"failed\"`, `\"skipped_duplicate\"`,\n`\"skipped_gate\"`, `\"skipped_rate_limit\"`, or `\"skipped_no_route\"`."},"trigger":{"type":"string","description":"What triggered the attempt (always `\"tls_callback\"` today)."}}},"OnDemandCertRow":{"type":"object","description":"One row of the on-demand certificates list: the most-recent attempt for a\nhostname plus the current authoritative cert state from its `domains` row.","required":["hostname","attempt"],"properties":{"attempt":{"$ref":"#/components/schemas/OnDemandCertAttemptResponse","description":"The audit record for the attempt this row represents (newest first in\nthe list)."},"backoff_until":{"type":["integer","null"],"format":"int64","description":"On-demand negative-cache deadline (epoch millis), when in backoff."},"expiration_time":{"type":["integer","null"],"format":"int64","description":"Certificate expiration (epoch millis), when an active cert exists."},"hostname":{"type":"string","description":"SNI hostname."},"status":{"type":["string","null"],"description":"Current cert lifecycle status from the `domains` row, when one exists:\n`on_demand_pending`, `on_demand_issuing`, `active`, `on_demand_failed`,\netc. `None` when no `domains` row exists yet for this hostname."}}},"OnDemandTlsSettings":{"type":"object","description":"On-demand (lazy) HTTP-01 TLS issuance settings (ADR-018).\n\nWhen `enabled`, the proxy's `certificate_callback` triggers ACME HTTP-01\nissuance for allowlisted, STABLE hostnames (per-environment aliases and the\nconsole host) that have no active cert, rather than silently failing the\nhandshake. Ephemeral per-deployment hostnames are NEVER certed (ADR §2).\n\nOff by default — operators opt in explicitly, except QuickStart (`sslip.io`)\ninstalls where `temps setup` auto-enables it and derives `zone`.","properties":{"deployment_url_mode":{"type":"string","description":"How ephemeral per-deployment hostnames behave when they have no cert\n(they are NEVER certed — see ADR §2). One of:\n - `\"http\"` (default): serve plain HTTP on :80.\n - `\"redirect_to_env\"`: 308-redirect to the stable per-environment URL,\n which IS certed.","default":"http","example":"http"},"enabled":{"type":"boolean","description":"Master switch. When `false` (default) the proxy's on-demand cert gate\nrejects every SNI and no issuance is ever triggered.","default":false,"example":false},"hourly_cap":{"type":"integer","format":"int32","description":"Global cap on total on-demand issuances per hour across all hostnames\n(ADR §4 Layer 3). The operator's self-imposed safety net, separate from\nthe Let's Encrypt rate limit.","default":10,"example":10,"minimum":1},"max_concurrent":{"type":"integer","format":"int32","description":"Maximum number of ACME issuance flows allowed to run simultaneously\n(the concurrent-issuance semaphore, ADR §4 Layer 1). Min 1.","default":3,"example":3,"minimum":1},"zone":{"type":["string","null"],"description":"Zone suffix for the allowlist gate. A hostname passes the gate only if\nit is a direct subdomain of this zone (e.g. zone `1.2.3.4.sslip.io`\nadmits `myapp.1.2.3.4.sslip.io` but not `deep.sub.1.2.3.4.sslip.io`).\n`None` (default) means \"auto-derive from `external_url`\"; if no zone can\nbe derived the gate rejects all SNI, disabling the feature.","default":null,"example":"1.2.3.4.sslip.io"}}},"OpenAiError":{"type":"object","required":["message","type"],"properties":{"code":{"type":["string","null"]},"message":{"type":"string"},"type":{"type":"string"}}},"OpenAiErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"$ref":"#/components/schemas/OpenAiError"}}},"OperatingSystemCount":{"type":"object","required":["operating_system","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"operating_system":{"type":"string"},"percentage":{"type":"number","format":"double"}}},"OperationResultResponse":{"type":"object","required":["operation","success","message","executed_at"],"properties":{"data":{},"executed_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"message":{"type":"string"},"operation":{"type":"string"},"success":{"type":"boolean"}}},"OperationResultsResponse":{"type":"object","required":["deployment_id","operations"],"properties":{"deployment_id":{"type":"string"},"operations":{"type":"array","items":{"$ref":"#/components/schemas/OperationResultResponse"}}}},"OtelDashboardResponse":{"type":"object","required":["id","project_id","name","layout","created_at","updated_at"],"properties":{"created_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"id":{"type":"integer","format":"int32"},"layout":{"$ref":"#/components/schemas/DashboardLayout"},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"updated_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"}}},"OtelDashboardsResponse":{"type":"object","required":["data","total"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/OtelDashboardResponse"}},"total":{"type":"integer","format":"int64","minimum":0}}},"OtelMetricAlertRuleResponse":{"type":"object","required":["id","project_id","name","metric_name","aggregation","detection_kind","detection_config","window_secs","for_duration_secs","severity","enabled","last_state","label_filters","group_by","dynamic_alerts","max_series","grouped_notification_threshold","last_dropped_series_count","series_states","created_at","updated_at"],"properties":{"aggregation":{"type":"string"},"created_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"detection_config":{"$ref":"#/components/schemas/DetectionConfig","description":"The typed detector definition (discriminated union keyed by `kind`)."},"detection_kind":{"type":"string","description":"Coarse detector discriminator: `static|anomaly|forecast|outlier|auto_watch`."},"dynamic_alerts":{"type":"boolean","description":"Whether per-series (\"dynamic\") alerting is enabled for this rule."},"enabled":{"type":"boolean"},"firing_series":{"type":"array","items":{"$ref":"#/components/schemas/FiringSeriesEntry"},"description":"Currently-firing series for a dynamic rule, snapshotted from the evaluator's\nin-memory firing map at read time. Empty for static/aggregate rules or when\nnothing is firing."},"for_duration_secs":{"type":"integer","format":"int32"},"group_by":{"type":"array","items":{"type":"string"},"description":"Label keys the rule breaks the metric down by. Empty = one aggregate stream."},"grouped_notification_threshold":{"type":"integer","format":"int32","description":"Notification-grouping threshold: when more than this many series fire in the\nsame tick, only the first gets chart/AI enrichment (1–1000)."},"id":{"type":"integer","format":"int32"},"label_filters":{"type":"array","items":{"type":"array","items":false,"prefixItems":[{"type":"string"},{"type":"string"}]},"description":"AND-combined label equality filters applied when evaluating this rule.\nEmpty = no filtering (matches all series)."},"last_dropped_series_count":{"type":"integer","format":"int32","description":"Number of series dropped by the cardinality cap on the latest dynamic tick\n(0 when nothing was dropped or for static/aggregate rules). Lets a UI warn\n\"N series were dropped this tick\" without reading server logs."},"last_evaluated_at":{"type":["string","null"],"example":"2025-10-12T12:15:47.609192Z"},"last_state":{"type":"string","description":"One of `ok|firing|unknown`."},"last_value":{"type":["number","null"],"format":"double"},"max_series":{"type":"integer","format":"int32","description":"Cardinality cap for dynamic alerting (1–100)."},"metric_name":{"type":"string"},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"series_states":{"type":"object","description":"Full per-series state snapshot persisted after the latest dynamic-rule tick,\nkeyed by the human-readable series label (`endpoint=/checkout`). Empty for\nstatic/aggregate rules. Unlike `firing_series` (a live in-memory snapshot),\nthis is decoded from the persisted `series_states` jsonb column, so an\nexternal consumer that only reads the rule row still sees per-series detail.","additionalProperties":{"$ref":"#/components/schemas/SeriesStateEntry"},"propertyNames":{"type":"string"}},"severity":{"type":"string"},"updated_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"window_secs":{"type":"integer","format":"int32"}}},"OtelMetricAlertsResponse":{"type":"object","required":["data","total"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/OtelMetricAlertRuleResponse"}},"total":{"type":"integer","format":"int64","minimum":0}}},"OtelMetricLabelKeysResponse":{"type":"object","required":["keys"],"properties":{"keys":{"type":"array","items":{"type":"string"}}}},"OtelMetricLabelValuesResponse":{"type":"object","required":["values"],"properties":{"values":{"type":"array","items":{"type":"string"}}}},"OtelMetricNamesResponse":{"type":"object","required":["names"],"properties":{"names":{"type":"array","items":{"type":"string"}}}},"OtelMetricsResponse":{"type":"object","required":["data","count"],"properties":{"count":{"type":"integer","minimum":0},"data":{"type":"array","items":{"$ref":"#/components/schemas/MetricBucket"}}}},"OutlierAlgorithm":{"type":"string","description":"Outlier detection algorithm.","enum":["dbscan","scaled_dbscan","mad","scaled_mad"]},"OutlierParams":{"type":"object","description":"Outlier (cross-series population) detector parameters (stub — not evaluated).","required":["peer_group_key"],"properties":{"algorithm":{"$ref":"#/components/schemas/OutlierAlgorithm"},"peer_group_key":{"type":"string","description":"Label key defining the peer population compared across series (e.g. `host`)."},"tolerance":{"type":"number","format":"double","description":"Sensitivity; higher tolerates larger spread before flagging."}}},"OverprovisioningAssessment":{"type":"object","description":"Requests-vs-capacity-vs-usage assessment","required":["verdict","explanation"],"properties":{"cpu_request_inflation_ratio":{"type":["number","null"],"format":"double","description":"Ratio of requested CPU to measured CPU usage (e.g. 40.0 = requests\nreserve 40× what the workloads actually use). `None` without metrics."},"cpu_requested_pct":{"type":["number","null"],"format":"double","description":"Requested CPU as % of cluster capacity"},"cpu_utilization_pct":{"type":["number","null"],"format":"double","description":"Measured CPU usage as % of cluster capacity (`None` without metrics)"},"explanation":{"type":"string","description":"Human-readable explanation of the verdict, e.g. \"Cluster capacity is\n8 vCPU but measured usage is 0.3 vCPU (3.7%) — severely overprovisioned\""},"memory_request_inflation_ratio":{"type":["number","null"],"format":"double","description":"Ratio of requested memory to measured memory usage"},"memory_requested_pct":{"type":["number","null"],"format":"double","description":"Requested memory as % of cluster capacity"},"memory_utilization_pct":{"type":["number","null"],"format":"double","description":"Measured memory usage as % of cluster capacity (`None` without metrics)"},"verdict":{"$ref":"#/components/schemas/OverprovisioningVerdict","description":"Overall verdict"}}},"OverprovisioningVerdict":{"type":"string","description":"Overall overprovisioning verdict","enum":["severe","moderate","reasonable","unknown"]},"PageActivityBucket":{"type":"object","description":"Time bucket data point for page activity graph","required":["timestamp","visitors","page_views","avg_time_seconds"],"properties":{"avg_time_seconds":{"type":"number","format":"double","description":"Average time on page in seconds"},"page_views":{"type":"integer","format":"int64","description":"Number of page views in this bucket"},"timestamp":{"type":"string","description":"Timestamp for this bucket (ISO 8601)"},"visitors":{"type":"integer","format":"int64","description":"Number of unique visitors in this bucket"}}},"PageCountryStats":{"type":"object","description":"Geographic distribution of visitors for a page","required":["country","visitors","page_views","percentage"],"properties":{"country":{"type":"string","description":"Country name"},"country_code":{"type":["string","null"],"description":"ISO country code (2-letter)"},"page_views":{"type":"integer","format":"int64","description":"Number of page views from this country"},"percentage":{"type":"number","format":"double","description":"Percentage of total visitors"},"visitors":{"type":"integer","format":"int64","description":"Number of unique visitors from this country"}}},"PageFlowEntry":{"type":"object","description":"A single page with its entry/exit/bounce statistics","required":["page_path","entry_count","exit_count","bounce_count","total_views","entry_rate","exit_rate","bounce_rate"],"properties":{"avg_time_on_page":{"type":["number","null"],"format":"double","description":"Average time spent on this page in seconds"},"bounce_count":{"type":"integer","format":"int64","description":"Number of times visitors bounced on this page"},"bounce_rate":{"type":"number","format":"double","description":"Bounce rate: bounce_count / entry_count (only meaningful for entry pages)"},"entry_count":{"type":"integer","format":"int64","description":"Number of times this page was the entry page of a session"},"entry_rate":{"type":"number","format":"double","description":"Entry rate: entry_count / total_views"},"exit_count":{"type":"integer","format":"int64","description":"Number of times this page was the exit page of a session"},"exit_rate":{"type":"number","format":"double","description":"Exit rate: exit_count / total_views"},"page_path":{"type":"string","description":"The page path (e.g. \"/pricing\", \"/docs/getting-started\")"},"total_views":{"type":"integer","format":"int64","description":"Total page views for this page"}}},"PageFlowQuery":{"type":"object","description":"Query parameters for page flow analytics","required":["project_id","start_date","end_date"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32","description":"Maximum number of entry/exit pages to return (default: 20)"},"min_views_for_dropoff":{"type":["integer","null"],"format":"int32","description":"Minimum views for drop-off analysis (default: 5)"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"},"transitions_limit":{"type":["integer","null"],"format":"int32","description":"Maximum number of transitions to return (default: 50)"}}},"PageFlowResponse":{"type":"object","description":"Complete page flow analytics response","required":["top_entry_pages","top_exit_pages","drop_off_points","transitions","total_pages","total_sessions"],"properties":{"drop_off_points":{"type":"array","items":{"$ref":"#/components/schemas/DropOffPoint"},"description":"Top drop-off points (highest exit rates with meaningful traffic)"},"top_entry_pages":{"type":"array","items":{"$ref":"#/components/schemas/PageFlowEntry"},"description":"Top entry pages (where visitors land), sorted by entry_count DESC"},"top_exit_pages":{"type":"array","items":{"$ref":"#/components/schemas/PageFlowEntry"},"description":"Top exit pages (where visitors leave), sorted by exit_count DESC"},"total_pages":{"type":"integer","format":"int64","description":"Total unique pages seen in the period"},"total_sessions":{"type":"integer","format":"int64","description":"Total sessions in the period"},"transitions":{"type":"array","items":{"$ref":"#/components/schemas/PageTransition"},"description":"Page-to-page transitions (most common navigation paths)"}}},"PageHourlySessionsQuery":{"type":"object","description":"Query parameters for page hourly sessions endpoint","required":["page_path","project_id","start_time","end_time"],"properties":{"bucket_interval":{"type":["string","null"]},"end_time":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"page_path":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"start_time":{"type":"string","format":"date-time"}}},"PageHourlySessionsResponse":{"type":"object","required":["page_path","hourly_data","total_sessions","hours"],"properties":{"hourly_data":{"type":"array","items":{"$ref":"#/components/schemas/HourlyPageSessions"}},"hours":{"type":"integer","format":"int32"},"page_path":{"type":"string"},"total_sessions":{"type":"integer","format":"int64"}}},"PagePathDetailQuery":{"type":"object","description":"Query parameters for page path detail analytics","required":["page_path","project_id","start_date","end_date"],"properties":{"bucket_interval":{"type":["string","null"],"description":"Bucket interval for time series: 'hour', 'day', 'week', 'month' (default: auto)"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"page_path":{"type":"string","description":"The specific page path to get details for (URL-encoded)"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"PagePathDetailResponse":{"type":"object","description":"Detailed analytics response for a specific page path","required":["page_path","unique_visitors","total_page_views","avg_time_on_page","bounce_rate","entry_rate","exit_rate","activity_over_time","countries","referrers","bucket_interval"],"properties":{"activity_over_time":{"type":"array","items":{"$ref":"#/components/schemas/PageActivityBucket"},"description":"Time series data for activity graph"},"avg_time_on_page":{"type":"number","format":"double","description":"Average time on page in seconds"},"bounce_rate":{"type":"number","format":"double","description":"Bounce rate percentage (0-100)"},"bucket_interval":{"type":"string","description":"Bucket interval used for time series ('hour', 'day', etc.)"},"countries":{"type":"array","items":{"$ref":"#/components/schemas/PageCountryStats"},"description":"Geographic distribution of visitors"},"entry_rate":{"type":"number","format":"double","description":"Entry rate - percentage of sessions that started on this page"},"exit_rate":{"type":"number","format":"double","description":"Exit rate - percentage of sessions that ended on this page"},"page_path":{"type":"string","description":"The page path being analyzed"},"referrers":{"type":"array","items":{"$ref":"#/components/schemas/PageReferrerStats"},"description":"Top referrers to this page"},"total_page_views":{"type":"integer","format":"int64","description":"Total page views in the date range"},"unique_visitors":{"type":"integer","format":"int64","description":"Total unique visitors to this page in the date range"}}},"PagePathInfo":{"type":"object","required":["page_path","session_count","page_view_count","first_seen","last_seen"],"properties":{"avg_time_seconds":{"type":["number","null"],"format":"double"},"first_seen":{"type":"string"},"last_seen":{"type":"string"},"page_path":{"type":"string"},"page_view_count":{"type":"integer","format":"int64"},"session_count":{"type":"integer","format":"int64"}}},"PagePathSparkline":{"type":"object","required":["page_path","points"],"properties":{"page_path":{"type":"string"},"points":{"type":"array","items":{"$ref":"#/components/schemas/PagePathSparklinePoint"}}}},"PagePathSparklinePoint":{"type":"object","required":["timestamp","session_count"],"properties":{"session_count":{"type":"integer","format":"int64"},"timestamp":{"type":"string"}}},"PagePathVisitorsQuery":{"type":"object","description":"Query parameters for page path visitors","required":["page_path","project_id","start_date","end_date"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"page":{"type":["integer","null"],"format":"int64","description":"Page number (1-based, default: 1)","minimum":0},"page_path":{"type":"string","description":"The specific page path to get visitors for"},"per_page":{"type":["integer","null"],"format":"int64","description":"Items per page (default: 50, max: 100)","minimum":0},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"PagePathVisitorsResponse":{"type":"object","description":"Response for page path visitors endpoint","required":["page_path","total_count","page","per_page","sessions"],"properties":{"page":{"type":"integer","format":"int64","description":"Current page number","minimum":0},"page_path":{"type":"string","description":"The page path"},"per_page":{"type":"integer","format":"int64","description":"Items per page","minimum":0},"sessions":{"type":"array","items":{"$ref":"#/components/schemas/PageVisitorSession"},"description":"Individual visitor sessions"},"total_count":{"type":"integer","format":"int64","description":"Total number of visitor sessions matching the query"}}},"PagePathsQuery":{"type":"object","required":["project_id"],"properties":{"end_date":{"type":["string","null"],"format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":["string","null"],"format":"date-time"}}},"PagePathsResponse":{"type":"object","required":["page_paths","total_count"],"properties":{"page_paths":{"type":"array","items":{"$ref":"#/components/schemas/PagePathInfo"}},"total_count":{"type":"integer","minimum":0}}},"PagePathsSparklineQuery":{"type":"object","description":"Query parameters for batch page paths sparkline endpoint","required":["project_id","start_time","end_time","page_paths"],"properties":{"end_time":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"page_paths":{"type":"string","description":"Comma-separated list of page paths"},"project_id":{"type":"integer","format":"int32"},"start_time":{"type":"string","format":"date-time"}}},"PagePathsSparklineResponse":{"type":"object","required":["sparklines"],"properties":{"sparklines":{"type":"array","items":{"$ref":"#/components/schemas/PagePathSparkline"}}}},"PageReferrerStats":{"type":"object","description":"Referrer source for the page","required":["referrer","visits","percentage"],"properties":{"percentage":{"type":"number","format":"double","description":"Percentage of total visits"},"referrer":{"type":"string","description":"Referrer URL or domain"},"visits":{"type":"integer","format":"int64","description":"Number of visits from this referrer"}}},"PageSessionComparison":{"type":"object","required":["page_path","date","session_count","event_count","avg_duration_seconds"],"properties":{"avg_duration_seconds":{"type":"number","format":"double"},"date":{"type":"string"},"event_count":{"type":"integer","format":"int64"},"page_path":{"type":"string"},"session_count":{"type":"integer","format":"int64"}}},"PageSessionStats":{"type":"object","required":["page_path","total_sessions","avg_time_seconds","min_time_seconds","max_time_seconds","total_page_views","avg_page_views_per_session"],"properties":{"avg_page_views_per_session":{"type":"number","format":"double"},"avg_time_seconds":{"type":"number","format":"double"},"max_time_seconds":{"type":"number","format":"double"},"min_time_seconds":{"type":"number","format":"double"},"page_path":{"type":"string"},"total_page_views":{"type":"integer","format":"int64"},"total_sessions":{"type":"integer","format":"int64"}}},"PageSessionStatsQuery":{"type":"object","required":["page_path","project_id","start_date","end_date"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"page_path":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"PageTransition":{"type":"object","description":"A page-to-page transition with count","required":["from_page","to_page","transition_count","percentage"],"properties":{"from_page":{"type":"string","description":"The source page path"},"percentage":{"type":"number","format":"double","description":"Percentage of transitions from the source page that go to this destination"},"to_page":{"type":"string","description":"The destination page path"},"transition_count":{"type":"integer","format":"int64","description":"Number of times this transition occurred"}}},"PageVisit":{"type":"object","required":["path","visits"],"properties":{"path":{"type":"string"},"visits":{"type":"integer","format":"int64"}}},"PageVisitorSession":{"type":"object","description":"Individual visitor session that viewed a specific page","required":["visitor_id","visitor_uuid","viewed_at","is_entry","is_exit","is_bounce"],"properties":{"browser":{"type":["string","null"],"description":"Browser name"},"city":{"type":["string","null"],"description":"Visitor's city"},"country":{"type":["string","null"],"description":"Visitor's country"},"country_code":{"type":["string","null"],"description":"Visitor's country code"},"device_type":{"type":["string","null"],"description":"Device type (Desktop, Mobile, Tablet)"},"is_bounce":{"type":"boolean","description":"Whether this was a bounce"},"is_entry":{"type":"boolean","description":"Whether this was the entry page for the session"},"is_exit":{"type":"boolean","description":"Whether this was the exit page for the session"},"operating_system":{"type":["string","null"],"description":"Operating system"},"referrer":{"type":["string","null"],"description":"Referrer URL"},"session_id":{"type":["string","null"],"description":"Session ID"},"session_page_number":{"type":["integer","null"],"format":"int32","description":"Page number in session flow"},"time_on_page":{"type":["integer","null"],"format":"int32","description":"Time spent on this page in seconds"},"viewed_at":{"type":"string","format":"date-time","description":"When the page was viewed"},"visitor_id":{"type":"integer","format":"int32","description":"Visitor numeric ID"},"visitor_uuid":{"type":"string","description":"Visitor UUID"}}},"PagesComparisonResponse":{"type":"object","required":["comparisons","page_paths"],"properties":{"comparisons":{"type":"array","items":{"$ref":"#/components/schemas/PageSessionComparison"}},"page_paths":{"type":"array","items":{"type":"string"}}}},"PaginatedEmailsResponse":{"type":"object","required":["data","total","page","page_size"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/EmailResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"PaginatedEntitiesResponse":{"type":"object","required":["entities","count","limit","has_more"],"properties":{"count":{"type":"integer","description":"Number of entities returned","minimum":0},"entities":{"type":"array","items":{"$ref":"#/components/schemas/EntityResponse"},"description":"List of entities"},"has_more":{"type":"boolean","description":"Whether there are more entities available"},"limit":{"type":"integer","description":"Limit used for this request","minimum":0},"next_token":{"type":["string","null"],"description":"Continuation token for next page (S3, etc.)"},"total":{"type":["integer","null"],"description":"Total number of entities (if available)","minimum":0}}},"PaginatedErrorEventsResponse":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ErrorEventResponse"}},"pagination":{"$ref":"#/components/schemas/PaginationMeta"}}},"PaginatedErrorGroupsResponse":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ErrorGroupResponse"}},"pagination":{"$ref":"#/components/schemas/PaginationMeta"}}},"PaginatedEventsResponse":{"type":"object","required":["events","total","page","page_size"],"properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/TrackingEventResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"PaginatedExternalImagesResponse":{"type":"object","required":["data","total","page","page_size"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ExternalImageResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"PaginatedProjectList":{"type":"object","required":["projects","total","page","per_page"],"properties":{"page":{"type":"integer","format":"int64"},"per_page":{"type":"integer","format":"int64"},"projects":{"type":"array","items":{"$ref":"#/components/schemas/ProjectResponse"}},"total":{"type":"integer","format":"int64"}}},"PaginatedStaticBundlesResponse":{"type":"object","required":["data","total","page","page_size"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/StaticBundleResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"Pagination":{"type":"object","description":"SDK pagination cursor. We use opaque page numbers internally but\nexpose `count`/`next`/`prev` the way `@vercel/sandbox` expects.","required":["count"],"properties":{"count":{"type":"integer","format":"int64","minimum":0},"next":{"type":["integer","null"],"format":"int64","minimum":0},"prev":{"type":["integer","null"],"format":"int64","minimum":0}}},"PaginationMeta":{"type":"object","required":["page","page_size","total_count","total_pages"],"properties":{"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total_count":{"type":"integer","format":"int64","minimum":0},"total_pages":{"type":"integer","format":"int64","minimum":0}}},"PaginationParams":{"type":"object","properties":{"page":{"type":"integer","format":"int64"},"per_page":{"type":"integer","format":"int64"}}},"PasswordProtectionConfig":{"type":"object","description":"Password protection configuration\n\nWhen enabled, the proxy shows an HTML password form before allowing access.\nAfter the user enters the correct password, an HMAC-signed cookie is set\nso subsequent requests pass through without re-entering the password.","required":["enabled","passwordHash"],"properties":{"enabled":{"type":"boolean","description":"Whether password protection is enabled"},"passwordHash":{"type":"string","description":"The bcrypt-hashed password (never stored or returned in plaintext)"}}},"PatchSettingsRequest":{"type":"object","properties":{"auto_upgrade":{"type":["boolean","null"]},"host_port":{"type":["integer","null"],"format":"int32","minimum":0},"image":{"type":["string","null"]}}},"PathVisitors":{"type":"object","required":["name","visitors","percentage"],"properties":{"name":{"type":"string"},"percentage":{"type":"number","format":"double"},"visitors":{"type":"integer","format":"int64"}}},"PathVisitorsAnalyticsQuery":{"type":"object","required":["start_date","end_date","project_id"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"PathVisitorsResponse":{"type":"object","required":["results"],"properties":{"results":{"type":"array","items":{"$ref":"#/components/schemas/PathVisitors"}}}},"PeerEntry":{"type":"object","description":"Wire-format peer entry. Matches `temps_network::config::Peer` but\nuses strings on the wire to keep the API stable across underlying\ntype evolution.","required":["node_id","compute_cidr","underlay_address"],"properties":{"compute_cidr":{"type":"string","description":"Per-node CIDR (e.g. `\"172.20.5.0/24\"`)."},"node_id":{"type":"string","description":"Stable v5 UUID derived from the database node id. Workers use\nthis as the kernel-layer identifier when calling\n`NetworkManager::reconcile_peers`."},"underlay_address":{"type":"string","description":"Address the local node should use to reach this peer over the\nunderlay (private VPC IP for same-DC, public IP for cross-DC)."}}},"PeerListResponse":{"type":"object","description":"Response body for `GET /internal/nodes/{node_id}/network/peers`.","required":["peers","cluster_dns_enabled"],"properties":{"alloc":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AllocEntry","description":"Caller's own allocation, or `null` if multi-host networking has\nnot been enabled for this node yet."}]},"cluster_dns_enabled":{"type":"boolean","description":"Whether the cluster-DNS resolver is enabled on this control plane\n(`AppSettings.cluster_dns.enabled`). Workers should start their\nper-node resolver and write `overlay_bridge_address` only when this\nis `true`. Always serialized (never `skip_serializing_if`) so older\nand newer version skew degrades to the safe default of `false`."},"peers":{"type":"array","items":{"$ref":"#/components/schemas/PeerEntry"},"description":"All other nodes with a `compute_cidr` set, excluding the caller."}}},"PendingActionResponse":{"type":"object","description":"A proposed AI write action awaiting human confirmation.","required":["public_id","operation_id","method","summary","status","step_index","params","created_at"],"properties":{"confirmed_at":{"type":["string","null"]},"created_at":{"type":"string"},"error":{"type":["string","null"]},"executed_at":{"type":["string","null"]},"method":{"type":"string"},"operation_id":{"type":"string"},"params":{"description":"The flat params to be replayed at execute time (shown pre-execution for review)."},"plan_public_id":{"type":["string","null"],"description":"Set when this action is one step of a multi-step plan (chained actions);\nall steps of the plan share this id. Absent for standalone single actions."},"public_id":{"type":"string"},"required_permission":{"type":["string","null"]},"result":{},"status":{"type":"string"},"step_index":{"type":"integer","format":"int32","description":"0-based order of this step within its plan (0 for standalone actions)."},"summary":{"type":"string"}}},"PerformanceMetricsQuery":{"allOf":[{"$ref":"#/components/schemas/SpeedSegmentFilters","description":"Segment filters (filter_path, filter_country, filter_region,\nfilter_city, filter_browser, filter_operating_system) — flattened so\neach remains a top-level query string param."},{"type":"object","required":["start_date","end_date","project_id"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"device_type":{"type":["string","null"],"description":"Device type filter: \"desktop\" or \"mobile\""},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"include_bots":{"type":["boolean","null"],"description":"Include crawler/datacenter (bot) samples. Defaults to false — bots\nare excluded from the read view but always stored at ingest."},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}}]},"PerformanceMetricsResponse":{"type":"object","properties":{"cls":{"type":["number","null"],"format":"float"},"cls_p75":{"type":["number","null"],"format":"float"},"cls_p90":{"type":["number","null"],"format":"float"},"cls_p95":{"type":["number","null"],"format":"float"},"cls_p99":{"type":["number","null"],"format":"float"},"fcp":{"type":["number","null"],"format":"float"},"fcp_p75":{"type":["number","null"],"format":"float"},"fcp_p90":{"type":["number","null"],"format":"float"},"fcp_p95":{"type":["number","null"],"format":"float"},"fcp_p99":{"type":["number","null"],"format":"float"},"fid":{"type":["number","null"],"format":"float"},"fid_p75":{"type":["number","null"],"format":"float"},"fid_p90":{"type":["number","null"],"format":"float"},"fid_p95":{"type":["number","null"],"format":"float"},"fid_p99":{"type":["number","null"],"format":"float"},"inp":{"type":["number","null"],"format":"float"},"inp_p75":{"type":["number","null"],"format":"float"},"inp_p90":{"type":["number","null"],"format":"float"},"inp_p95":{"type":["number","null"],"format":"float"},"inp_p99":{"type":["number","null"],"format":"float"},"lcp":{"type":["number","null"],"format":"float"},"lcp_p75":{"type":["number","null"],"format":"float"},"lcp_p90":{"type":["number","null"],"format":"float"},"lcp_p95":{"type":["number","null"],"format":"float"},"lcp_p99":{"type":["number","null"],"format":"float"},"ttfb":{"type":["number","null"],"format":"float"},"ttfb_p75":{"type":["number","null"],"format":"float"},"ttfb_p90":{"type":["number","null"],"format":"float"},"ttfb_p95":{"type":["number","null"],"format":"float"},"ttfb_p99":{"type":["number","null"],"format":"float"}}},"PermissionInfo":{"type":"object","description":"Information about a single permission","required":["name","description","category"],"properties":{"category":{"type":"string","description":"Category of the permission (e.g., \"Projects\", \"Deployments\")"},"description":{"type":"string","description":"Human-readable description of the permission"},"name":{"type":"string","description":"The permission identifier (e.g., \"projects:read\")"}}},"PgUpgradeLogResponse":{"type":"object","required":["log_id","content"],"properties":{"content":{"type":"string"},"log_id":{"type":"string"}}},"PgUpgradeResponse":{"type":"object","required":["id","service_id","from_version","to_version","from_image","to_image","status","phase","log_id","attempt","created_at"],"properties":{"attempt":{"type":"integer","format":"int32"},"created_at":{"type":"string"},"error_message":{"type":["string","null"]},"finished_at":{"type":["string","null"]},"from_image":{"type":"string"},"from_version":{"type":"string"},"id":{"type":"integer","format":"int32"},"log_id":{"type":"string"},"phase":{"type":"string"},"pre_upgrade_backup_id":{"type":["integer","null"],"format":"int32"},"rollback_volume_name":{"type":["string","null"]},"service_id":{"type":"integer","format":"int32"},"started_at":{"type":["string","null"]},"status":{"type":"string"},"to_image":{"type":"string"},"to_version":{"type":"string"}}},"PipelineStats":{"type":"object","description":"Internal pipeline statistics for self-observability.","required":["metrics_received","metrics_stored","metrics_dropped","spans_received","spans_stored","spans_dropped","logs_received","logs_stored_db","logs_stored_s3","logs_dropped","ingest_errors"],"properties":{"ingest_errors":{"type":"integer","format":"int64","minimum":0},"logs_dropped":{"type":"integer","format":"int64","minimum":0},"logs_received":{"type":"integer","format":"int64","minimum":0},"logs_stored_db":{"type":"integer","format":"int64","minimum":0},"logs_stored_s3":{"type":"integer","format":"int64","minimum":0},"metrics_dropped":{"type":"integer","format":"int64","minimum":0},"metrics_received":{"type":"integer","format":"int64","minimum":0},"metrics_stored":{"type":"integer","format":"int64","minimum":0},"spans_dropped":{"type":"integer","format":"int64","minimum":0},"spans_received":{"type":"integer","format":"int64","minimum":0},"spans_stored":{"type":"integer","format":"int64","minimum":0}}},"PipelineStatsResponse":{"type":"object","required":["stats"],"properties":{"stats":{"$ref":"#/components/schemas/PipelineStats"}}},"PlanComplexity":{"type":"string","description":"Plan complexity indicator","enum":["low","medium","high"]},"PlanMetadata":{"type":"object","description":"Plan metadata","required":["generated_at","generator_version","complexity","warnings"],"properties":{"complexity":{"$ref":"#/components/schemas/PlanComplexity","description":"Estimated complexity (low, medium, high)"},"generated_at":{"type":"string","format":"date-time","description":"When the plan was generated"},"generator_version":{"type":"string","description":"Generator (importer) version"},"warnings":{"type":"array","items":{"type":"string"},"description":"Warnings detected during planning"}}},"PlanSourceBackup":{"type":"object","required":["location","location_was_resolved","format"],"properties":{"created_at":{"type":["string","null"]},"format":{"type":"string","description":"\"walg\", \"pg_dump\", \"unknown\"."},"id":{"type":["integer","null"],"format":"int32","description":"DB id, absent for orphan (S3-scan) backups."},"location":{"type":"string","description":"Resolved S3 location the orchestrator will actually use."},"location_was_resolved":{"type":"boolean","description":"True when the original row's `s3_location` was empty and we resolved\na location by probing S3. The UI shows this as a warning."},"origin_service_name":{"type":["string","null"],"description":"Service that originally produced the backup, if known."},"size_bytes":{"type":["integer","null"],"format":"int64"}}},"PlanTarget":{"type":"object","required":["id","name","container"],"properties":{"container":{"type":"string","description":"Expected Docker container name."},"id":{"type":"integer","format":"int32"},"name":{"type":"string"}}},"PlatformInfo":{"type":"object","description":"Platform compatibility information","required":["os_type","architecture","platforms"],"properties":{"architecture":{"type":"string","description":"System architecture (e.g., \"x86_64\", \"aarch64\")"},"os_type":{"type":"string","description":"Operating system type (e.g., \"linux\", \"windows\", \"darwin\")"},"platforms":{"type":"array","items":{"type":"string"},"description":"List of supported platforms in \"os/arch\" format (e.g., [\"linux/amd64\"])"}}},"PluginManifest":{"type":"object","description":"The complete plugin manifest — the handshake contract.","required":["name","version"],"properties":{"description":{"type":["string","null"],"description":"Short description of what the plugin does"},"display_name":{"type":["string","null"],"description":"Human-readable display name"},"events":{"type":"array","items":{"type":"string"},"description":"Platform event types the plugin subscribes to.\n\nWhen specified, Temps will POST matching events to the plugin's\n`/_events` endpoint. Uses dot-notation event names matching the\nwebhook event types (e.g., \"deployment.succeeded\", \"project.created\").\n\nAvailable events:\n- `deployment.created`, `deployment.succeeded`, `deployment.failed`,\n `deployment.cancelled`, `deployment.ready`\n- `project.created`, `project.deleted`\n- `domain.created`, `domain.provisioned`"},"health_path":{"type":"string","description":"Health check endpoint path (relative to plugin root)"},"name":{"type":"string","description":"Unique plugin identifier (kebab-case, e.g., \"backup-manager\")"},"nav":{"type":"array","items":{"$ref":"#/components/schemas/NavEntry"},"description":"Navigation entries for the UI sidebar"},"requires_db":{"type":"boolean","description":"Whether the plugin needs database access"},"ui":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/UiManifest","description":"UI bundle manifest (if the plugin has a UI)"}]},"version":{"type":"string","description":"SemVer version string"}}},"PortMapping":{"type":"object","description":"Port mapping","required":["container_port","protocol","is_primary"],"properties":{"container_port":{"type":"integer","format":"int32","description":"Container port","minimum":0},"host_port":{"type":["integer","null"],"format":"int32","description":"Host port (optional - can be assigned dynamically)","minimum":0},"is_primary":{"type":"boolean","description":"Whether this is the primary HTTP port"},"protocol":{"$ref":"#/components/schemas/Protocol","description":"Protocol (tcp, udp)"}}},"PostgresWalHealth":{"type":"object","required":["probed_at","pg_wal_bytes","max_wal_size_bytes","archive_mode","archive_backlog","stale_slots","oldest_wal_age_secs","warnings"],"properties":{"archive_backlog":{"type":"integer","format":"int64","description":"Number of `archive_status/*.ready` files — un-shipped WAL segments."},"archive_command":{"type":["string","null"],"description":"The literal `archive_command` setting. May be empty or `/bin/true`\nwhen archiving is effectively disabled despite `archive_mode = on`."},"archive_mode":{"$ref":"#/components/schemas/ArchiveMode"},"archiver_failed_count":{"type":["integer","null"],"format":"int64"},"archiver_last_failed_at":{"type":["string","null"],"format":"date-time"},"max_wal_size_bytes":{"type":"integer","format":"int64","description":"`max_wal_size` setting in bytes (parsed from `pg_settings`)."},"oldest_wal_age_secs":{"type":"integer","format":"int64","description":"Age of the oldest WAL file in `pg_wal/` (seconds)."},"pg_wal_bytes":{"type":"integer","format":"int64","description":"Total size of files under `pg_wal/`, from `pg_ls_waldir()`."},"probed_at":{"type":"string","format":"date-time","description":"When the snapshot was taken."},"stale_slots":{"type":"array","items":{"$ref":"#/components/schemas/StaleSlot"}},"warnings":{"type":"array","items":{"$ref":"#/components/schemas/WalWarning"},"description":"Computed warnings, ordered by severity (critical first)."}}},"PresetConfigSchema":{"oneOf":[{"$ref":"#/components/schemas/DockerfilePresetConfig","description":"Configuration for Dockerfile preset"},{"$ref":"#/components/schemas/DockerComposePresetConfig","description":"Configuration for Docker Compose"},{"$ref":"#/components/schemas/NixpacksPresetConfig","description":"Configuration for Nixpacks provider selection and inline build plan"},{"$ref":"#/components/schemas/StaticPresetConfig","description":"Configuration for static site presets (Vite, Next.js, etc.)"}],"description":"Union type for preset configurations\nUse the appropriate configuration type based on your preset"},"PresetInfo":{"type":"object","description":"Detected preset information","required":["path","preset","preset_label","project_type"],"properties":{"compose_files":{"type":["array","null"],"items":{"type":"string"},"description":"Compose file paths found in the repository (only for docker-compose preset)"},"exposed_port":{"type":["integer","null"],"format":"int32","description":"Default exposed port for this preset"},"icon_url":{"type":["string","null"],"description":"Icon URL for this preset"},"path":{"type":"string","description":"Path where preset was detected (empty for root)"},"preset":{"type":"string","description":"Preset slug (e.g., \"nextjs\", \"fastapi\")"},"preset_label":{"type":"string","description":"Human-readable preset label"},"project_type":{"type":"string","description":"Project type (e.g., \"frontend\", \"backend\", \"fullstack\")"}}},"PresetResponse":{"type":"object","required":["slug","label","icon_url","project_type","description"],"properties":{"default_port":{"type":["integer","null"],"format":"int32","description":"Default port the application listens on (None for static sites)","example":3000,"minimum":0},"description":{"type":"string","description":"Description of what this preset does"},"icon_url":{"type":"string","description":"Icon URL for the preset"},"label":{"type":"string","description":"Display name/label for the preset"},"project_type":{"type":"string","description":"Project type (server or static)"},"slug":{"type":"string","description":"Unique identifier slug for the preset"}}},"PreviewGatewaySettings":{"type":"object","description":"Workspace preview gateway settings.\n\nThe preview gateway is a single shared Docker container that lives on the\n`temps-sandbox-net` network and routes requests to workspace sandbox dev\nservers based on the `Host` header (`ws--.`).\n`temps serve` reconciles this container on startup; these settings let an\noperator override the image, host port, and auto-upgrade behavior.","properties":{"auto_upgrade":{"type":"boolean","description":"When true (default), the supervisor will pull and apply the image\npinned in the Temps binary on every startup. When false, the\ncurrently-running image is left alone — operators upgrade manually\nfrom the settings UI.","default":true,"example":true},"host_port":{"type":"integer","format":"int32","description":"Host port to publish the gateway on (always bound to 127.0.0.1).\nPingora forwards `ws-*` traffic to this port after authenticating.","default":8090,"example":8090,"minimum":0},"image":{"type":"string","description":"Docker image reference for the gateway. Pinned per Temps release.\nOperators can override this to test a custom build.","default":"ghcr.io/gotempsh/temps-preview-gateway:latest","example":"ghcr.io/gotempsh/temps-preview-gateway:latest"},"shared_secret":{"type":"string","description":"Shared secret the host-side Pingora sends on every forwarded preview\nrequest via `X-Temps-Preview-Token`; the gateway rejects requests\nwithout it. Auto-generated on first boot, persisted in DB so the\nsecret is stable across `temps serve` restarts regardless of cwd,\n`TEMPS_DATA_DIR`, or data-dir changes. MUST be masked (`***`) in any\nAPI response — never expose it over HTTP.","default":"","example":""}}},"PreviewGatewaySettingsMasked":{"type":"object","description":"Preview gateway settings with `shared_secret` elided.","required":["image","host_port","auto_upgrade","shared_secret_set"],"properties":{"auto_upgrade":{"type":"boolean"},"host_port":{"type":"integer","format":"int32","minimum":0},"image":{"type":"string"},"shared_secret_set":{"type":"boolean"}}},"PreviewGatewaySettingsResponse":{"type":"object","required":["image","host_port","auto_upgrade","default_image","default_host_port"],"properties":{"auto_upgrade":{"type":"boolean"},"default_host_port":{"type":"integer","format":"int32","description":"The compile-time default host port.","minimum":0},"default_image":{"type":"string","description":"The compile-time default image — exposed so the UI can offer a\n\"Reset to default\" link without round-tripping."},"host_port":{"type":"integer","format":"int32","minimum":0},"image":{"type":"string"}}},"PreviewShareLinkBody":{"type":"object","description":"Request body for minting a preview share link.","required":["port"],"properties":{"path":{"type":["string","null"],"description":"Path the recipient lands on. Must be same-origin (start with a single\n`/`); anything else is replaced with `/` so a share link can never be\nturned into an open redirect."},"port":{"type":"integer","format":"int32","description":"Port inside the sandbox the preview serves on.","minimum":0},"ttl_seconds":{"type":["integer","null"],"format":"int64","description":"How long the link stays usable, in seconds. Clamped to 24 hours.\nDefaults to one hour — long enough to send to a reviewer, short enough\nthat a link pasted in a ticket does not stay live indefinitely.","minimum":0}}},"PreviewShareLinkResponse":{"type":"object","required":["url","expires_at"],"properties":{"expires_at":{"type":"integer","format":"int64","description":"Unix seconds after which the link stops working.","minimum":0},"url":{"type":"string","description":"The full link. Its fragment contains the grant and must be treated as a\ncredential; URL fragments are not sent to servers or in Referer headers."}}},"PricingResponse":{"type":"object","required":["models"],"properties":{"models":{"type":"array","items":{"$ref":"#/components/schemas/ModelPricing"}}}},"ProblemDetails":{"type":"object","description":"Representation of a Problem error to return to the client.\nFollows RFC 7807 - Problem Details for HTTP APIs","required":["title","extensions"],"properties":{"detail":{"type":["string","null"],"description":"A human-readable explanation specific to this occurrence of the problem","example":"The server encountered an unexpected condition"},"extensions":{"type":"object","description":"Additional properties of the problem","additionalProperties":true},"instance":{"type":["string","null"],"description":"A URI reference that identifies the specific occurrence of the problem","example":"/account/12345/msgs/abc"},"title":{"type":"string","description":"A short, human-readable summary of the problem type","example":"Internal Server Error"},"type":{"type":["string","null"],"description":"A URI reference that identifies the problem type","example":"https://example.com/probs/out-of-memory"}},"example":{"type":"https://example.com/probs/out-of-memory","title":"Internal Server Error","detail":"The server encountered an unexpected condition","instance":"/account/12345/msgs/abc","additional_info":"Custom field with additional details"}},"ProjectAccessResponse":{"type":"object","required":["id","project_id","team_id","role","granted_by","created_at","updated_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2026-07-30T12:15:47.609192Z"},"granted_by":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"project_id":{"type":"integer","format":"int32"},"role":{"$ref":"#/components/schemas/TeamRole"},"team_id":{"type":"integer","format":"int32"},"updated_at":{"type":"string","format":"date-time","example":"2026-07-30T12:15:47.609192Z"}}},"ProjectConfiguration":{"type":"object","description":"Project-level configuration","required":["name","slug","project_type","is_web_app"],"properties":{"is_web_app":{"type":"boolean","description":"Whether this is a web application"},"name":{"type":"string","description":"Proposed project name"},"project_type":{"$ref":"#/components/schemas/ProjectType","description":"Project type"},"slug":{"type":"string","description":"Proposed slug (URL-safe identifier)"}}},"ProjectDSNResponse":{"type":"object","required":["id","project_id","name","public_key","dsn","created_at","is_active","event_count"],"properties":{"created_at":{"type":"string"},"deployment_id":{"type":["integer","null"],"format":"int32"},"dsn":{"type":"string"},"environment_id":{"type":["integer","null"],"format":"int32"},"event_count":{"type":"integer","format":"int64"},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"public_key":{"type":"string"}}},"ProjectDashboardAnalytics":{"type":"object","description":"Analytics data for a single project in the dashboard batch response","required":["project_id","unique_visitors","previous_unique_visitors","hourly_visits"],"properties":{"hourly_visits":{"type":"array","items":{"$ref":"#/components/schemas/EventTimeline"},"description":"Hourly sparkline data points"},"previous_unique_visitors":{"type":"integer","format":"int64","description":"Unique visitor count in the previous period (same duration, shifted back)"},"project_id":{"type":"integer","format":"int32"},"trend_percentage":{"type":["number","null"],"format":"double","description":"Percentage change from previous period (positive = growth, negative = decline)\nNull when previous period had zero visitors (no baseline to compare)"},"unique_visitors":{"type":"integer","format":"int64","description":"Unique visitor count in the current time range"}}},"ProjectHealthSummary":{"type":"object","description":"Health summary for a single project (last 1 hour)","required":["project_id","total_requests","total_errors","avg_response_time_ms","error_rate","status"],"properties":{"avg_response_time_ms":{"type":"number","format":"double","description":"Average response time in ms"},"error_rate":{"type":"number","format":"double","description":"Error rate as a percentage (0-100)"},"project_id":{"type":"integer","format":"int32"},"status":{"type":"string","description":"Health status: \"healthy\", \"degraded\", \"down\", \"unknown\""},"total_errors":{"type":"integer","format":"int64","description":"Total server errors (status >= 500) in the period"},"total_requests":{"type":"integer","format":"int64","description":"Total requests in the period"}}},"ProjectInfo":{"type":"object","required":["id","slug","created_at"],"properties":{"created_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"id":{"type":"integer","format":"int32"},"slug":{"type":"string"}}},"ProjectMonitorHealth":{"type":"object","description":"Health summary for a single project based on its production monitors","required":["project_id","status"],"properties":{"project_id":{"type":"integer","format":"int32"},"status":{"type":"string","description":"Overall status: \"operational\", \"degraded\", \"down\", or \"no_monitors\""}}},"ProjectPresetResponse":{"type":"object","required":["path","preset","presetLabel","projectType"],"properties":{"composeFiles":{"type":["array","null"],"items":{"type":"string"},"description":"Compose file paths found in the repository (only for docker-compose preset)"},"exposedPort":{"type":["integer","null"],"format":"int32","description":"Default exposed port for this preset (e.g., 3000 for Next.js, 8000 for FastAPI)"},"iconUrl":{"type":["string","null"],"description":"Icon URL for the preset"},"path":{"type":"string"},"preset":{"type":"string"},"presetLabel":{"type":"string"},"projectType":{"type":"string","description":"Project type category (e.g., \"frontend\", \"backend\", \"fullstack\")"}}},"ProjectQuery":{"type":"object","required":["project_id"],"properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"}}},"ProjectRef":{"type":"object","description":"A lightweight project descriptor included in `UnifiedTrace`.","required":["project_id","project_name","project_slug"],"properties":{"project_id":{"type":"integer","format":"int32"},"project_name":{"type":"string"},"project_slug":{"type":"string","description":"URL slug used to link a span back into its owning project's trace view."}}},"ProjectResponse":{"type":"object","required":["id","slug","name","directory","main_branch","created_at","updated_at","deployment_config","attack_mode","ai_write_actions_enabled","error_source_context_enabled","enable_preview_environments","preview_envs_on_demand","preview_envs_idle_timeout_seconds","preview_envs_wake_timeout_seconds","source_type","cross_project_trace_sharing"],"properties":{"ai_alert_summaries_enabled":{"type":["boolean","null"],"description":"Opt-in to AI summarization of metric alert notifications (NULL/false = off)."},"ai_debug_chat_enabled":{"type":["boolean","null"],"description":"Opt-in to AI debugging chat, e.g. on deployment failures (NULL/false = off)."},"ai_write_actions_enabled":{"type":"boolean","description":"Opt-in to AI propose-then-confirm write capability (false = off)."},"attack_mode":{"type":"boolean","description":"Attack mode - when enabled, requires CAPTCHA verification for all project environments"},"created_at":{"type":"integer","format":"int64"},"cross_project_trace_sharing":{"type":"boolean","description":"ADR-027 Phase 3 opt-out: when false, this project's traces are suppressed\nfrom cross-project discovery results. Default true (consistent with the\nOSS global-observability model where any OtelRead holder can query any\nproject's telemetry)."},"deployment_config":{"$ref":"#/components/schemas/DeploymentConfig","description":"Deployment configuration (resources, autoscaling, features)"},"directory":{"type":"string"},"enable_preview_environments":{"type":"boolean","description":"Enable automatic preview environment creation for each branch"},"error_source_context_enabled":{"type":"boolean","description":"Opt-in to native error-tracking source context (false = off). When on,\nTemps stores uploaded source files and shows source code in stack traces."},"error_source_root":{"type":["string","null"],"description":"Where auto-capture reads source from (relative to the checkout). Null =\nthe deployment's Docker build context."},"git_provider_connection_id":{"type":["integer","null"],"format":"int32"},"git_url":{"type":["string","null"],"description":"Git clone URL for the repository (used for public repos without a provider connection)"},"gitlab_webhook_id":{"type":["integer","null"],"format":"int32","description":"GitLab webhook ID installed on the connected repository.\n`null` when no GitLab webhook is installed (not connected to GitLab,\nor webhook was removed / never created).","example":42},"id":{"type":"integer","format":"int32"},"last_deployment":{"type":["integer","null"],"format":"int64"},"main_branch":{"type":"string"},"name":{"type":"string"},"preset":{"type":["string","null"]},"preset_config":{"description":"Preset-specific configuration (Dockerfile path, build context, etc.)"},"preview_envs_idle_timeout_seconds":{"type":"integer","format":"int32","description":"Idle timeout (seconds) for on-demand preview environments."},"preview_envs_on_demand":{"type":"boolean","description":"When true, newly-created preview environments default to on-demand mode\n(containers stop after the configured idle timeout to save resources)."},"preview_envs_wake_timeout_seconds":{"type":"integer","format":"int32","description":"Wake timeout (seconds) for on-demand preview environments."},"repo_name":{"type":["string","null"]},"repo_owner":{"type":["string","null"]},"slug":{"type":"string"},"source_type":{"$ref":"#/components/schemas/SourceType","description":"Source type for deployments (git, docker_image, or static_files)"},"updated_at":{"type":"integer","format":"int64"}}},"ProjectSecretEnvironmentInfo":{"type":"object","required":["id","name","main_url"],"properties":{"id":{"type":"integer","format":"int32"},"main_url":{"type":"string"},"name":{"type":"string"}}},"ProjectSecretResponse":{"type":"object","description":"Project secret metadata. There is deliberately no `value` field — secret\nplaintext is never returned after creation. Callers that need the value\nmust read it from the mounted file inside the container.","required":["id","project_id","key","include_in_preview","created_at","updated_at","environments"],"properties":{"created_at":{"type":"integer","format":"int64"},"environments":{"type":"array","items":{"$ref":"#/components/schemas/ProjectSecretEnvironmentInfo"}},"id":{"type":"integer","format":"int32"},"include_in_preview":{"type":"boolean"},"key":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"updated_at":{"type":"integer","format":"int64"}}},"ProjectServiceInfo":{"type":"object","required":["id","project","service"],"properties":{"id":{"type":"integer","format":"int32"},"project":{"$ref":"#/components/schemas/ProjectInfo"},"service":{"$ref":"#/components/schemas/ExternalServiceInfo"}}},"ProjectStatisticsResponse":{"type":"object","required":["total_count"],"properties":{"total_count":{"type":"integer","format":"int64"}}},"ProjectStatsBreakdown":{"type":"object","required":["project_id","unique_visitors","total_visits","total_page_views","bounce_rate","engagement_rate"],"properties":{"bounce_rate":{"type":"number","format":"double"},"engagement_rate":{"type":"number","format":"double"},"project_id":{"type":"integer","format":"int32"},"project_name":{"type":["string","null"]},"total_page_views":{"type":"integer","format":"int64"},"total_visits":{"type":"integer","format":"int64"},"unique_visitors":{"type":"integer","format":"int64"}}},"ProjectType":{"type":"string","description":"Project type enumeration","enum":["static","docker","buildpack","git"]},"ProjectUsageInfoResponse":{"type":"object","required":["id","name","slug","connection_id","connection_name"],"properties":{"connection_id":{"type":"integer","format":"int32"},"connection_name":{"type":"string"},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"slug":{"type":"string"}}},"ProjectsHealthResponse":{"type":"object","description":"Batch health summary response","required":["projects"],"properties":{"projects":{"type":"object","description":"Health summaries keyed by project ID","additionalProperties":{"$ref":"#/components/schemas/ProjectHealthSummary"},"propertyNames":{"type":"string"}}}},"ProjectsMonitorHealthResponse":{"type":"object","description":"Batch response for projects health","required":["projects"],"properties":{"projects":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/ProjectMonitorHealth"},"propertyNames":{"type":"string"}}}},"PromoteDeploymentRequest":{"type":"object","required":["target_environment_id"],"properties":{"target_environment_id":{"type":"integer","format":"int32","description":"Target environment ID to promote the deployment to"}}},"PropertyBreakdownItem":{"type":"object","required":["value","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"percentage":{"type":"number","format":"double"},"value":{"type":"string"}}},"PropertyBreakdownQuery":{"type":"object","description":"Query parameters for property breakdown (group by column)","required":["start_date","end_date","group_by"],"properties":{"aggregation_level":{"$ref":"#/components/schemas/AggregationLevel","description":"Aggregation level"},"deployment_id":{"type":["integer","null"],"format":"int32","description":"Optional deployment filter"},"end_date":{"type":"string","format":"date-time","description":"End date for the query range"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Optional environment filter"},"event_name":{"type":["string","null"],"description":"Optional event name filter (e.g., \"page_view\", \"click\")"},"filter_browser":{"type":["string","null"],"description":"Filter by browser name (for browser version drill-downs)"},"filter_channel":{"type":["string","null"],"description":"Filter by channel name (for channel -> referrer drill-downs)"},"filter_country":{"type":["string","null"],"description":"Filter by country (for region/city drill-downs). Requires geolocation join."},"filter_os":{"type":["string","null"],"description":"Filter by operating system name (for OS version drill-downs)"},"filter_referrer":{"type":["string","null"],"description":"Filter by referrer hostname (for referrer -> pages drill-downs)"},"filter_region":{"type":["string","null"],"description":"Filter by region (for city drill-downs). Requires geolocation join."},"group_by":{"$ref":"#/components/schemas/PropertyColumn","description":"Property column to group by"},"include_crawlers":{"type":["boolean","null"],"description":"Include crawler/bot traffic (default: false). Off by default so the\nbreakdown percentages share a denominator with the headline counts,\nwhich always exclude crawlers."},"limit":{"type":["integer","null"],"format":"int32","description":"Maximum number of results to return (default: 20, max: 100)"},"start_date":{"type":"string","format":"date-time","description":"Start date for the query range"}}},"PropertyBreakdownResponse":{"type":"object","required":["property","items","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/PropertyBreakdownItem"}},"property":{"type":"string"},"total":{"type":"integer","format":"int64"}}},"PropertyColumn":{"type":"string","enum":["channel","device_type","browser","browser_version","operating_system","operating_system_version","utm_source","utm_medium","utm_campaign","utm_term","utm_content","referrer_hostname","language","event_type","event_name","page_path","pathname","country","region","city"]},"PropertyTimelineItem":{"type":"object","required":["timestamp","value","count"],"properties":{"count":{"type":"integer","format":"int64"},"timestamp":{"type":"string"},"value":{"type":"string"}}},"PropertyTimelineQuery":{"type":"object","description":"Query parameters for property timeline (group by column over time)","required":["start_date","end_date","group_by"],"properties":{"aggregation_level":{"$ref":"#/components/schemas/AggregationLevel","description":"Aggregation level"},"bucket_size":{"type":["string","null"],"description":"Time bucket size: \"hour\", \"day\", \"week\", \"month\" (default: auto-detect)"},"deployment_id":{"type":["integer","null"],"format":"int32","description":"Optional deployment filter"},"end_date":{"type":"string","format":"date-time","description":"End date for the query range"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Optional environment filter"},"event_name":{"type":["string","null"],"description":"Optional event name filter"},"group_by":{"$ref":"#/components/schemas/PropertyColumn","description":"Property column to group by"},"include_crawlers":{"type":["boolean","null"],"description":"Include crawler/bot traffic (default: false). See\n[`PropertyBreakdownQuery::include_crawlers`]."},"start_date":{"type":"string","format":"date-time","description":"Start date for the query range"}}},"PropertyTimelineResponse":{"type":"object","required":["property","bucket_size","items"],"properties":{"bucket_size":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/PropertyTimelineItem"}},"property":{"type":"string"}}},"Protocol":{"type":"string","description":"Network protocol","enum":["tcp","udp"]},"ProviderCatalogDto":{"type":"object","description":"One catalog entry rendered for the settings UI.","required":["id","name","install_command","auth_command","auth_flavors","models","credential_saved","supports_max_turns"],"properties":{"auth_command":{"type":"string"},"auth_flavors":{"type":"array","items":{"$ref":"#/components/schemas/AuthFlavorDto"}},"credential_saved":{"type":"boolean","description":"True when a credential is currently saved for this provider in the\nsettings JSON. Lets the UI render \"Configured\" badges without the\nfrontend having to inspect the encrypted blob."},"current_auth_type":{"type":["string","null"],"description":"Currently saved auth flavor id (when `credential_saved` is true).\n`None` when no credential is saved yet."},"default_model":{"type":["string","null"],"description":"Currently saved default model id for this provider, if one was\npicked. `None` means \"use the CLI's own default\" — the UI renders\nthat as \"Use provider default\"."},"id":{"type":"string"},"install_command":{"type":"string"},"max_turns_analysis":{"type":["integer","null"],"format":"int32","description":"Default max turns for the autofixer analysis phase. `None` = built-in\ndefault (10). Only enforced for CLIs with a turn flag (Claude Code)."},"max_turns_feedback":{"type":["integer","null"],"format":"int32","description":"Default max turns for autofixer feedback rounds. `None` = built-in\ndefault (10)."},"max_turns_fix":{"type":["integer","null"],"format":"int32","description":"Default max turns for the autofixer fix phase. `None` = built-in\ndefault (20)."},"models":{"type":"array","items":{"type":"string"},"description":"Model ids this provider accepts, in display order. The first entry is\nthe recommended default. Empty when the provider doesn't expose model\nselection (e.g. OpenCode), which the UI uses to hide the dropdown."},"name":{"type":"string"},"supports_max_turns":{"type":"boolean","description":"True when this provider's CLI supports enforcing a turn cap. False\nfor Codex/OpenCode, which run to completion — the UI labels their\nmax-turns inputs accordingly."}}},"ProviderCatalogResponse":{"type":"object","required":["default_provider","providers"],"properties":{"default_provider":{"type":"string","description":"Active provider id from `agent_sandbox.default_provider`. The settings\nUI uses this to highlight which card is the active one."},"providers":{"type":"array","items":{"$ref":"#/components/schemas/ProviderCatalogDto"}}}},"ProviderConfig":{"oneOf":[{"allOf":[{"$ref":"#/components/schemas/StripeConfig"},{"type":"object","required":["provider"],"properties":{"provider":{"type":"string","enum":["stripe"]}}}]},{"allOf":[{"$ref":"#/components/schemas/LemonSqueezyConfig"},{"type":"object","required":["provider"],"properties":{"provider":{"type":"string","enum":["lemon_squeezy"]}}}]}],"description":"Provider-specific integration settings persisted in\n`revenue_integrations.config`.\n\nThe tag is the lowercase provider name, so adding a new provider\nmeans adding a new variant and the existing rows are untouched.\nOld rows (pre-config) and rows with `NULL` config are treated as\n\"accept all events, no filtering\" via [`ProviderConfig::default_for`]."},"ProviderConfigMasked":{"type":"object","required":["auth_type","credential_saved","extra"],"properties":{"auth_type":{"type":"string"},"credential_saved":{"type":"boolean","description":"True if a credential is stored for this provider. The encrypted blob\nis never returned over HTTP."},"default_model":{"type":["string","null"]},"extra":{}}},"ProviderDeletionCheckResponse":{"type":"object","required":["can_delete","projects_in_use","message"],"properties":{"can_delete":{"type":"boolean"},"message":{"type":"string"},"projects_in_use":{"type":"array","items":{"$ref":"#/components/schemas/ProjectUsageInfoResponse"}}}},"ProviderDescriptor":{"type":"object","required":["name","display_name","recommended_events"],"properties":{"display_name":{"type":"string"},"name":{"type":"string"},"recommended_events":{"type":"array","items":{"type":"string"}}}},"ProviderKeyResponse":{"type":"object","required":["id","provider","display_name","api_key_masked","is_active","created_at","updated_at"],"properties":{"api_key_masked":{"type":"string","description":"Masked API key (only last 4 chars visible)"},"base_url":{"type":["string","null"]},"created_at":{"type":"string"},"default_model":{"type":["string","null"],"description":"Model id this provider serves (NULL → per-provider default)."},"display_name":{"type":"string"},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"provider":{"type":"string"},"updated_at":{"type":"string"}}},"ProviderMetadata":{"type":"object","required":["service_type","display_name","description","icon_url","color"],"properties":{"color":{"type":"string","example":"#336791"},"description":{"type":"string","example":"Relational database management system"},"display_name":{"type":"string","example":"PostgreSQL"},"icon_url":{"type":"string","example":"https://cdn.simpleicons.org/postgresql"},"service_type":{"$ref":"#/components/schemas/ServiceTypeRoute"}}},"ProviderResponse":{"type":"object","required":["id","name","provider_type","auth_method","is_active","is_default","created_at","updated_at"],"properties":{"auth_method":{"type":"string"},"base_url":{"type":["string","null"]},"created_at":{"type":"string","format":"date-time"},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"is_default":{"type":"boolean"},"name":{"type":"string"},"provider_type":{"type":"string"},"updated_at":{"type":"string","format":"date-time"}}},"ProviderUsage":{"type":"object","required":["provider","request_count","input_tokens","output_tokens","avg_latency_ms","error_count"],"properties":{"avg_latency_ms":{"type":"number","format":"double"},"error_count":{"type":"integer","format":"int64"},"input_tokens":{"type":"integer","format":"int64"},"output_tokens":{"type":"integer","format":"int64"},"provider":{"type":"string"},"request_count":{"type":"integer","format":"int64"}}},"ProvisionResponse":{"oneOf":[{"allOf":[{"$ref":"#/components/schemas/DomainError"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["error"]}}}]},{"allOf":[{"$ref":"#/components/schemas/DomainResponse"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["complete"]}}}]},{"allOf":[{"$ref":"#/components/schemas/DomainChallengeResponse"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["pending"]}}}]}]},"ProxyLogResponse":{"type":"object","description":"Response model for proxy logs","required":["id","timestamp","method","path","host","status_code","request_source","is_system_request","routing_status","request_id"],"properties":{"bot_name":{"type":["string","null"]},"browser":{"type":["string","null"]},"browser_version":{"type":["string","null"]},"cache_status":{"type":["string","null"]},"client_ip":{"type":["string","null"]},"container_id":{"type":["string","null"]},"deployment_id":{"type":["integer","null"],"format":"int32"},"device_type":{"type":["string","null"]},"environment_id":{"type":["integer","null"],"format":"int32"},"error_message":{"type":["string","null"]},"host":{"type":"string"},"id":{"type":"integer","format":"int32"},"ip_geolocation_id":{"type":["integer","null"],"format":"int32"},"is_bot":{"type":["boolean","null"]},"is_system_request":{"type":"boolean"},"method":{"type":"string"},"operating_system":{"type":["string","null"]},"path":{"type":"string"},"project_id":{"type":["integer","null"],"format":"int32"},"query_string":{"type":["string","null"]},"referrer":{"type":["string","null"]},"request_id":{"type":"string"},"request_size_bytes":{"type":["integer","null"],"format":"int64"},"request_source":{"type":"string"},"response_size_bytes":{"type":["integer","null"],"format":"int64"},"response_time_ms":{"type":["integer","null"],"format":"int32"},"routing_status":{"type":"string"},"session_id":{"type":["integer","null"],"format":"int32"},"status_code":{"type":"integer","format":"int32"},"timestamp":{"type":"string"},"upstream_host":{"type":["string","null"]},"user_agent":{"type":["string","null"]},"visitor_id":{"type":["integer","null"],"format":"int32"}}},"ProxyLogsPaginatedResponse":{"type":"object","description":"Paginated response for proxy logs","required":["logs","total","page","page_size","total_pages"],"properties":{"logs":{"type":"array","items":{"$ref":"#/components/schemas/ProxyLogResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0},"total_pages":{"type":"integer","format":"int64","minimum":0}}},"PublicHostnameStrategy":{"type":"string","description":"Public hostname generation mode for Temps-managed preview routes.\n\nThe mode is stored per managed domain (`dns_managed_domains.generated_hostname_mode`)\nrather than globally, so a provider such as Cloudflare can offer the flat layout\nrequired by its Universal SSL wildcard cert without changing every domain's behaviour.","enum":["standard","flat"]},"PublicPresetResponse":{"type":"object","description":"Response for preset detection","required":["branch","presets"],"properties":{"branch":{"type":"string","description":"Branch name where presets were detected"},"presets":{"type":"array","items":{"$ref":"#/components/schemas/PresetInfo"},"description":"List of detected presets"}}},"PublicRepositoryInfo":{"type":"object","description":"Public repository information","required":["owner","name","full_name","default_branch","stars","forks"],"properties":{"default_branch":{"type":"string","description":"Default branch name"},"description":{"type":["string","null"],"description":"Repository description"},"forks":{"type":"integer","format":"int32","description":"Fork count"},"full_name":{"type":"string","description":"Full repository name (owner/repo)"},"language":{"type":["string","null"],"description":"Primary programming language"},"name":{"type":"string","description":"Repository name"},"owner":{"type":"string","description":"Repository owner"},"stars":{"type":"integer","format":"int32","description":"Star count"}}},"PurgeLogsRequest":{"type":"object","required":["before"],"properties":{"before":{"type":"string","description":"Delete all logs before this timestamp (ISO 8601)"}}},"PushImageRequest":{"type":"object","description":"Request to push an external image","required":["image_ref"],"properties":{"image_ref":{"type":"string"},"metadata":{}}},"PushedExternalImageResponse":{"type":"object","description":"Response for in-memory external image operations (legacy push flow).\n\nRenamed to avoid shadowing the richer database-backed `ExternalImageResponse`\nin `handlers/remote_deployments.rs`. The two types serve different routes\n(`/images` ephemeral push vs `/external-images` registered images).","required":["id","image_ref","pushed_at"],"properties":{"digest":{"type":["string","null"]},"id":{"type":"string"},"image_ref":{"type":"string"},"pushed_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"size":{"type":["integer","null"],"format":"int64","minimum":0}}},"QueryDataRequest":{"type":"object","properties":{"filters":{"description":"JSON filters (backend-specific format)"},"limit":{"type":"integer","description":"Maximum number of rows to return","example":100,"minimum":0},"offset":{"type":"integer","description":"Number of rows to skip","example":0,"minimum":0},"sort_by":{"type":["string","null"],"description":"Sort by field name"},"sort_order":{"type":["string","null"],"description":"Sort order (asc/desc)"}}},"QueryDataResponse":{"type":"object","required":["fields","rows","total_count","returned_count","execution_time_ms"],"properties":{"execution_time_ms":{"type":"integer","format":"int64","description":"Query execution time in milliseconds","example":45,"minimum":0},"fields":{"type":"array","items":{"$ref":"#/components/schemas/FieldResponse"},"description":"Field definitions"},"returned_count":{"type":"integer","description":"Number of rows returned in this response","example":100,"minimum":0},"rows":{"type":"array","items":{},"description":"Data rows (array of JSON objects)"},"total_count":{"type":"integer","format":"int64","description":"Total number of rows matching the query (before limit/offset)","example":1234,"minimum":0}}},"QuotaResponse":{"type":"object","required":["quota"],"properties":{"quota":{"$ref":"#/components/schemas/StorageQuota"}}},"RateLimitConfig":{"type":"object","description":"Rate limiting configuration (subset of global RateLimitSettings)","properties":{"blacklistIps":{"type":"array","items":{"type":"string"},"description":"Blacklist specific IPs for this project/environment"},"maxRequestsPerHour":{"type":["integer","null"],"format":"int32","description":"Override rate limit per hour","minimum":0},"maxRequestsPerMinute":{"type":["integer","null"],"format":"int32","description":"Override rate limit per minute","minimum":0},"whitelistIps":{"type":"array","items":{"type":"string"},"description":"Whitelist specific IPs for this project/environment"}}},"RateLimitSettings":{"type":"object","properties":{"blacklist_ips":{"type":"array","items":{"type":"string"},"default":[]},"enabled":{"type":"boolean","default":false},"max_requests_per_hour":{"type":"integer","format":"int32","default":1000,"minimum":0},"max_requests_per_minute":{"type":"integer","format":"int32","default":60,"minimum":0},"whitelist_ips":{"type":"array","items":{"type":"string"},"default":[]}}},"ReachabilityStatus":{"type":"string","description":"Email reachability status","enum":["safe","risky","invalid","unknown"]},"ReadFileResponse":{"type":"object","required":["path","contents_b64","size"],"properties":{"contents_b64":{"type":"string","description":"File contents, base64-encoded. Symmetric with `WriteFileBody`."},"path":{"type":"string"},"size":{"type":"integer","format":"int64","minimum":0}}},"RecentActivityQuery":{"type":"object","description":"Query parameters for recent activity endpoint","required":["project_id"],"properties":{"environment_id":{"type":["integer","null"],"format":"int32","description":"Environment ID (optional)"},"limit":{"type":["integer","null"],"format":"int32","description":"Max number of events to return (default: 50, max: 100)"},"project_id":{"type":"integer","format":"int32","description":"Project ID"},"since_id":{"type":["integer","null"],"format":"int64","description":"Return events with ID greater than this (for cursor-based polling)"}}},"RecentActivityResponse":{"type":"object","description":"Response for recent activity events endpoint","required":["events","count"],"properties":{"count":{"type":"integer","description":"Total events returned","minimum":0},"events":{"type":"array","items":{"$ref":"#/components/schemas/ActivityEvent"},"description":"Recent events, newest first"}}},"RecentEventResponse":{"type":"object","required":["occurred_at","event_type"],"properties":{"amount_minor":{"type":["integer","null"],"format":"int64"},"currency":{"type":["string","null"]},"customer_ref":{"type":["string","null"]},"event_type":{"type":"string"},"mrr_minor":{"type":["integer","null"],"format":"int64"},"occurred_at":{"type":"string","format":"date-time"}}},"RecentQueryParams":{"type":"object","properties":{"conversation_id":{"type":["string","null"],"description":"Filter by conversation ID"},"cost_gt":{"type":["integer","null"],"format":"int64","description":"Cost strictly greater-than, in microcents"},"cost_gte":{"type":["integer","null"],"format":"int64","description":"Cost greater-than-or-equal, in microcents"},"cost_lt":{"type":["integer","null"],"format":"int64","description":"Cost strictly less-than, in microcents"},"cost_lte":{"type":["integer","null"],"format":"int64","description":"Cost less-than-or-equal, in microcents"},"limit":{"type":["integer","null"],"format":"int64","description":"Page size (defaults to 20, max 50)","minimum":0},"model":{"type":["string","null"],"description":"Filter by model name"},"offset":{"type":["integer","null"],"format":"int64","description":"Number of results to skip for pagination (defaults to 0)","minimum":0},"provider":{"type":["string","null"],"description":"Filter by provider name"},"status":{"type":["integer","null"],"format":"int32","description":"Filter by HTTP status code (exact match)"},"tags":{"type":["string","null"],"description":"Filter by tags (comma-separated, AND logic)"},"tokens_gt":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) strictly greater-than"},"tokens_gte":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) greater-than-or-equal"},"tokens_lt":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) strictly less-than"},"tokens_lte":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) less-than-or-equal"},"user_id":{"type":["integer","null"],"format":"int32","description":"Filter by user ID"}}},"RecordExposureRequest":{"type":"object","description":"Keys a running app actually evaluated since its last report.","required":["keys"],"properties":{"keys":{"type":"array","items":{"type":"string"},"description":"Flag keys evaluated since the last report. Unknown keys are ignored.","example":["checkout.v2","api.rate_limit"]}}},"RecordExposureResponse":{"type":"object","required":["recorded"],"properties":{"recorded":{"type":"integer","format":"int64","description":"How many keys were accepted for processing.\n\nDeliberately not the number of rows updated: echoing that back would\nlet a caller post a single candidate key and read the result as \"this\nflag exists\", turning the endpoint into an existence oracle.","minimum":0}}},"RecordListResponse":{"type":"object","description":"Record list response","required":["records"],"properties":{"records":{"type":"array","items":{"$ref":"#/components/schemas/DnsRecord"}}}},"RecoveryTarget":{"oneOf":[{"type":"object","description":"Recover to a specific timestamp.","required":["time","kind"],"properties":{"kind":{"type":"string","enum":["time"]},"time":{"type":"string","format":"date-time"}}},{"type":"object","description":"Recover to a specific transaction id (Postgres).","required":["xid","kind"],"properties":{"kind":{"type":"string","enum":["xid"]},"xid":{"type":"string"}}},{"type":"object","description":"Recover to a specific log sequence number (Postgres).","required":["lsn","kind"],"properties":{"kind":{"type":"string","enum":["lsn"]},"lsn":{"type":"string"}}},{"type":"object","description":"Recover to a named restore point created via `pg_create_restore_point` (Postgres).","required":["name","kind"],"properties":{"kind":{"type":"string","enum":["name"]},"name":{"type":"string"}}}],"description":"Engine-specific recovery target for PITR.\n\nPostgres honors all variants; Redis/Mongo/S3 will likely reject non-Time\nvariants or define their own semantics when they grow PITR support."},"ReferrerCount":{"type":"object","required":["referrer","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"percentage":{"type":"number","format":"double"},"referrer":{"type":"string"}}},"ReferrersAnalyticsQuery":{"type":"object","required":["start_date","end_date","project_id"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"RegenerateDSNRequest":{"type":"object","properties":{"base_url":{"type":["string","null"]}}},"RegisterImageRequest":{"type":"object","required":["image_ref"],"properties":{"digest":{"type":["string","null"],"description":"Image digest (sha256:...)","example":"sha256:abc123def456"},"image_ref":{"type":"string","description":"Docker image reference (e.g., \"ghcr.io/org/app:v1.0\")","example":"ghcr.io/myorg/myapp:v1.0"},"metadata":{"description":"Additional metadata"},"tag":{"type":["string","null"],"description":"Image tag","example":"v1.0"}}},"RegisterNodeApiRequest":{"type":"object","required":["name","token","address","private_address"],"properties":{"address":{"type":"string","description":"Node's reachable address (e.g., \"10.100.0.2\" or \"192.168.1.50\")"},"architecture":{"type":["string","null"],"description":"Container platform of this node's Docker daemon (`linux/amd64`,\n`linux/arm64`). Optional: agents older than multi-arch support omit it\nand the value is learned from the first heartbeat instead."},"csr_pem":{"type":["string","null"],"description":"Node-generated certificate signing request (PEM) for multi-node mTLS\n(ADR-020 WS-2.1). When present, the control plane signs it with the\ncluster CA and returns the leaf + CA cert. Optional — token-only nodes\n(legacy / edge) still register without one."},"edge_public_key":{"type":["string","null"],"description":"X25519 public key for ECIES certificate encryption (base64-encoded, edge nodes only)"},"join_token":{"type":["string","null"],"description":"Join token to authorize this registration (must match the token generated in Settings)"},"labels":{"description":"Labels for scheduling (e.g., {\"region\": \"us-east\", \"gpu\": \"true\"})"},"name":{"type":"string","description":"Unique name for this node"},"prior_token":{"type":["string","null"],"description":"The node's *current* token, supplied to prove possession when\nre-registering (changing the identity of) a node that already exists.\nOptional; only needed to rebind a still-live node. (ADR-020 WS-1.2.)"},"private_address":{"type":"string","description":"Private/WireGuard address for inter-node communication"},"public_endpoint":{"type":["string","null"],"description":"Public endpoint for WireGuard (e.g., \"203.0.113.1:51820\")"},"role":{"type":["string","null"],"description":"Node role (default: \"worker\")"},"token":{"type":"string","description":"Registration token (plaintext, will be hashed before storage)"},"wg_public_key":{"type":["string","null"],"description":"WireGuard public key"}}},"RegisterNodeResponse":{"type":"object","required":["id","name","status","message"],"properties":{"ca_cert_pem":{"type":["string","null"],"description":"The cluster CA certificate (PEM) the node pins as its trust root.\nPresent only when a `csr_pem` was supplied. (ADR-020 WS-2.1.)"},"cert_pem":{"type":["string","null"],"description":"The signed per-node leaf certificate (PEM) the agent serves as its TLS\nserver cert. Present only when a `csr_pem` was supplied. (ADR-020 WS-2.1.)"},"id":{"type":"integer","format":"int32"},"message":{"type":"string"},"name":{"type":"string"},"status":{"type":"string"}}},"RegisterRequest":{"type":"object","required":["email","password","name"],"properties":{"email":{"type":"string"},"name":{"type":"string"},"password":{"type":"string"}}},"ReinstallWebhookResponse":{"type":"object","description":"Response for `POST /projects/{project_id}/gitlab/reinstall-webhook`","required":["hook_id","message"],"properties":{"hook_id":{"type":"integer","format":"int32","description":"The new GitLab hook ID that was installed."},"message":{"type":"string","description":"Human-readable status message."}}},"ReleaseListResponse":{"type":"object","required":["releases"],"properties":{"releases":{"type":"array","items":{"type":"string"}}}},"ReloadResponse":{"type":"object","description":"Response from the reload endpoint.","required":["loaded","plugins","message"],"properties":{"loaded":{"type":"integer","description":"Number of plugins successfully loaded after reload","minimum":0},"message":{"type":"string","description":"Human-readable status message"},"plugins":{"type":"array","items":{"type":"string"},"description":"Names of loaded plugins"}}},"RemoteDeploymentResponse":{"type":"object","required":["id","project_id","environment_id","slug","state","source_type","created_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"environment_id":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"project_id":{"type":"integer","format":"int32"},"slug":{"type":"string"},"source_type":{"type":"string"},"state":{"type":"string"}}},"RemoveNodeResponse":{"type":"object","required":["id","message"],"properties":{"id":{"type":"integer","format":"int32"},"message":{"type":"string"}}},"RenameConversationRequest":{"type":"object","required":["title"],"properties":{"title":{"type":"string","description":"New human-facing title. Trimmed; must be non-empty after trimming."}}},"RepositoryListQuery":{"type":"object","properties":{"direction":{"type":["string","null"]},"language":{"type":["string","null"]},"owner":{"type":["string","null"]},"page":{"type":["integer","null"],"format":"int64","minimum":0},"per_page":{"type":["integer","null"],"format":"int64","minimum":0},"private":{"type":["boolean","null"]},"search":{"type":["string","null"]},"sort":{"type":["string","null"]}}},"RepositoryListResponse":{"type":"object","required":["repositories","total_count"],"properties":{"repositories":{"type":"array","items":{"$ref":"#/components/schemas/RepositoryResponse"}},"total_count":{"type":"integer","minimum":0}}},"RepositoryPresetResponse":{"type":"object","required":["repository_id","owner","name","presets","calculated_at"],"properties":{"calculated_at":{"type":"string","format":"date-time"},"name":{"type":"string"},"owner":{"type":"string"},"presets":{"type":"array","items":{"$ref":"#/components/schemas/ProjectPresetResponse"}},"repository_id":{"type":"integer","format":"int32"}}},"RepositoryResponse":{"type":"object","required":["id","owner","name","full_name","private","default_branch","created_at","updated_at","pushed_at","git_provider_connection_id"],"properties":{"clone_url":{"type":["string","null"],"description":"HTTPS clone URL (e.g., https://github.com/owner/repo.git)"},"created_at":{"type":"string","format":"date-time"},"default_branch":{"type":"string"},"description":{"type":["string","null"]},"full_name":{"type":"string"},"git_provider_connection_id":{"type":"integer","format":"int32","description":"ID of the git provider connection this repository was synced from."},"id":{"type":"integer","format":"int32"},"language":{"type":["string","null"]},"name":{"type":"string"},"owner":{"type":"string"},"preset":{"type":["array","null"],"items":{"$ref":"#/components/schemas/ProjectPresetResponse"}},"private":{"type":"boolean"},"pushed_at":{"type":"string","format":"date-time"},"ssh_url":{"type":["string","null"],"description":"SSH clone URL (e.g., git@github.com:owner/repo.git)"},"updated_at":{"type":"string","format":"date-time"}}},"RepositorySyncStartedResponse":{"type":"object","description":"Returned by `POST /git-connections/{id}/sync` to acknowledge that a\nsync has been kicked off in the background. Clients should poll the\nconnection's `syncing` and `synced_repository_count` fields to track\nprogress rather than waiting on this response.","required":["connection_id","syncing","started_at"],"properties":{"connection_id":{"type":"integer","format":"int32"},"started_at":{"type":"string","format":"date-time"},"syncing":{"type":"boolean"}}},"RequestRow":{"type":"object","required":["id","ts","method","host","path","status","request_headers","response_headers","headers_truncated"],"properties":{"client_ip":{"type":["string","null"]},"country":{"type":["string","null"]},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"error_group_id":{"type":["integer","null"],"format":"int32"},"headers_truncated":{"type":"boolean"},"host":{"type":"string"},"id":{"type":"string","description":"The request's unique `request_id` (assigned by the proxy). Used as the\nrow identity instead of the storage PK because the ClickHouse backend\nhas no serial id (rows come back with `id = 0`) while `request_id` is\nunique and present on both backends."},"latency_ms":{"type":["integer","null"],"format":"int32"},"method":{"type":"string"},"path":{"type":"string"},"query_string":{"type":["string","null"]},"referrer":{"type":["string","null"]},"request_headers":{},"response_headers":{},"status":{"type":"integer","format":"int32"},"trace_id":{"type":["string","null"]},"ts":{"type":"string","format":"date-time"},"user_agent":{"type":["string","null"]}}},"RequiredPasswordChangeRequest":{"type":"object","required":["new_password"],"properties":{"new_password":{"type":"string"}}},"RequiredPasswordChangeResponse":{"type":"object","required":["success","message","user_id","mfa_enrollment_required"],"properties":{"message":{"type":"string"},"mfa_enrollment_required":{"type":"boolean"},"mfa_setup":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/MfaSetupResponse"}]},"success":{"type":"boolean"},"user_id":{"type":"integer","format":"int32"}}},"ResetPasswordRequest":{"type":"object","required":["token","new_password"],"properties":{"new_password":{"type":"string"},"token":{"type":"string"}}},"ResetPgStatStatementsRequest":{"type":"object","description":"Explicit confirmation required for the destructive statistics reset.\n\nRequiring JSON makes the endpoint non-simple for browsers, preventing a\ndeployed same-site application from triggering it with a plain HTML form.","required":["confirm"],"properties":{"confirm":{"type":"boolean","description":"Must be `true` to acknowledge the global, irreversible reset."}}},"ResetPgStatStatementsResponse":{"type":"object","description":"Response for the pg_stat_statements reset endpoint.","required":["message"],"properties":{"message":{"type":"string","description":"Human-readable message confirming the destructive action."}}},"ResizeSandboxBody":{"type":"object","required":["disk_size_mb"],"properties":{"disk_size_mb":{"type":"integer","format":"int64","description":"New root disk size in MB. Grow-only; must exceed the current size.","minimum":0}},"additionalProperties":false},"ResolvedEnvVarResponse":{"type":"object","description":"One entry in the computed env-var view that merges manual and integration\nsources and tags each result with its origin. `value_preview` is always\nmasked — plaintext must be fetched per-key via the existing reveal endpoint,\nwhich is audit-logged.","required":["key","value_preview","source","environments","include_in_preview"],"properties":{"environments":{"type":"array","items":{"$ref":"#/components/schemas/EnvironmentInfo"},"description":"Environments this var applies to. For integration-sourced vars this\nreflects every environment of the project (integrations are global)."},"include_in_preview":{"type":"boolean","description":"Whether the var would be auto-applied to preview environments.\nIntegration vars always surface in preview; manual vars follow the flag."},"key":{"type":"string"},"source":{"$ref":"#/components/schemas/ResolvedEnvVarSource"},"value_preview":{"type":"string","description":"Masked or truncated preview. Never the raw value."}}},"ResolvedEnvVarSource":{"oneOf":[{"type":"object","description":"Manually-defined env var. If `overrides_service` is set, this key would\notherwise have been supplied by an integration — the UI should show the\nintegration icon plus an \"overridden\" indicator.","required":["var_id","type"],"properties":{"overrides_service":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/EnvVarIntegrationInfo"}]},"type":{"type":"string","enum":["manual"]},"var_id":{"type":"integer","format":"int32"}}},{"type":"object","description":"Supplied by a linked external service (Postgres, Redis, S3, etc.).","required":["service","type"],"properties":{"service":{"$ref":"#/components/schemas/EnvVarIntegrationInfo"},"type":{"type":"string","enum":["integration"]}}}],"description":"Where a resolved env var comes from. Integration-sourced vars may be\n\"shadowed\" by a manual entry with the same key, in which case the response\ncarries `Manual` with `overrides_service` populated so the UI can still show\nthe integration icon."},"ResourceCounts":{"type":"object","description":"Quick count of resources involved in the migration","required":["projects","environments","deployments","environment_variables","services","domains"],"properties":{"deployments":{"type":"integer","minimum":0},"domains":{"type":"integer","minimum":0},"environment_variables":{"type":"integer","minimum":0},"environments":{"type":"integer","minimum":0},"projects":{"type":"integer","minimum":0},"services":{"type":"integer","minimum":0}}},"ResourceFootprint":{"type":"object","description":"A CPU + memory footprint (requests or measured usage)","required":["cpu_millis","memory_mb"],"properties":{"cpu_millis":{"type":"integer","format":"int64","description":"CPU in millicores"},"memory_mb":{"type":"integer","format":"int64","description":"Memory in MB"}}},"ResourceInfo":{"type":"object","description":"Resource attributes extracted from OTel resource descriptors.","required":["service_name","attributes"],"properties":{"attributes":{"type":"object"},"deployment_environment":{"type":["string","null"]},"service_name":{"type":"string"},"service_version":{"type":["string","null"]}}},"ResourceLimitApplyResult":{"type":"object","description":"Per-container outcome of a live `docker update` call. Surfaced from the\nPATCH /resources endpoint so the UI can tell the operator whether the\nnew caps are already in effect or whether they only apply on next\nrecreate (e.g., container was missing).","required":["role","container_name","outcome"],"properties":{"container_name":{"type":"string"},"error":{"type":["string","null"],"description":"Populated only when `outcome == \"failed\"`."},"outcome":{"type":"string","description":"One of:\n- \"applied\" — Docker accepted the update; caps are live now.\n- \"missing\" — container does not exist; caps stored, will apply on next start.\n- \"stopped\" — container exists but isn't running; Docker still\n accepts the update (the new caps apply on next start).\n- \"failed\" — `docker update` returned an error (see `error`)."},"role":{"type":"string","description":"`service_members.role` for cluster members; \"standalone\" otherwise."}}},"ResourceLimits":{"type":"object","description":"Resource limits and requests","properties":{"cpu_limit":{"type":["integer","null"],"format":"int32","description":"CPU limit (millicores)"},"cpu_request":{"type":["integer","null"],"format":"int32","description":"CPU request (millicores)"},"memory_limit":{"type":["integer","null"],"format":"int32","description":"Memory limit (MB)"},"memory_request":{"type":["integer","null"],"format":"int32","description":"Memory request (MB)"}}},"ResourceLimitsResponse":{"type":"object","description":"Container resource limits","properties":{"cpu_limit":{"type":["integer","null"],"format":"int32"},"cpu_request":{"type":["integer","null"],"format":"int32"},"memory_limit":{"type":["integer","null"],"format":"int32"},"memory_request":{"type":["integer","null"],"format":"int32"}}},"ResourceLimitsUpdateResponse":{"type":"object","description":"Response from PATCH /external-services/{id}/resources.","required":["limits","applied"],"properties":{"applied":{"type":"array","items":{"$ref":"#/components/schemas/ResourceLimitApplyResult"},"description":"Per-container result of trying to apply the limits live."},"limits":{"$ref":"#/components/schemas/ServiceResourceLimits","description":"The limits that were persisted to the encrypted config."}}},"ResourcesBody":{"type":"object","description":"Nested `resources: { memory, vcpus }` as sent by `@vercel/sandbox`.\n`memory` is in MB, `vcpus` is fractional CPU count.","properties":{"memory":{"type":["integer","null"],"format":"int64","minimum":0},"vcpus":{"type":["number","null"],"format":"double"}}},"RestoreCapabilities":{"type":"object","description":"Capabilities a service exposes for the generic restore framework.\n\nEach engine overrides `ExternalService::restore_capabilities` to declare\nwhat it supports. The handler layer uses this to validate requests and\nthe UI uses it to conditionally show options (e.g., PITR picker).","required":["restore_in_place","restore_to_new_service","pitr"],"properties":{"earliest_pitr_time":{"type":["string","null"],"format":"date-time","description":"Earliest recoverable timestamp, if `pitr` is true. Derived from\nengine-specific archive metadata (e.g., `pg_stat_archiver`)."},"latest_pitr_time":{"type":["string","null"],"format":"date-time","description":"Latest recoverable timestamp, if `pitr` is true."},"pitr":{"type":"boolean","description":"Point-in-time recovery using engine-specific continuous archives\n(WAL for Postgres, AOF for Redis, oplog for MongoDB, object versions for S3)."},"restore_in_place":{"type":"boolean","description":"Restore a backup onto the same running service (destructive)."},"restore_to_new_service":{"type":"boolean","description":"Restore a backup into a freshly provisioned service."}}},"RestoreCapabilitiesResponse":{"allOf":[{"$ref":"#/components/schemas/RestoreCapabilities","description":"Trait-declared capabilities."},{"type":"object","required":["suggested_new_service_name"],"properties":{"suggested_new_service_name":{"type":"string","description":"Suggested name for the new service when creating a clone. Safe to\npre-fill into the UI dialog; the user can edit before submitting."}}}]},"RestorePlan":{"type":"object","description":"Preview of a restore operation. Answers \"what will happen if I click\nstart?\" with engine-level specificity so the user can confirm before\ncommitting to a destructive action.","required":["engine","target_service","source_backup","strategy","steps","warnings","errors","destructive","mode"],"properties":{"destructive":{"type":"boolean","description":"Whether any step overwrites existing data on the target service."},"engine":{"type":"string","description":"Target engine (\"postgres\", etc.)."},"errors":{"type":"array","items":{"type":"string"},"description":"Blocking problems. The UI disables the Start button when non-empty."},"mode":{"type":"string","description":"Echo of the requested mode for the UI."},"source_backup":{"$ref":"#/components/schemas/PlanSourceBackup","description":"Backup we'll read from."},"steps":{"type":"array","items":{"type":"string"},"description":"Ordered list of human-readable actions the orchestrator will take."},"strategy":{"type":"string","description":"How the restore will be performed: \"walg_restore\", \"pg_dump_restore\",\nor \"unsupported\"."},"target_service":{"$ref":"#/components/schemas/PlanTarget","description":"Service we'll operate on (or provision a sibling of)."},"warnings":{"type":"array","items":{"type":"string"},"description":"Non-blocking caveats the user should see (cross-service, empty\nlocation that will be auto-resolved, missing engine metadata, ...)."}}},"RestoreRequestMode":{"oneOf":[{"type":"object","description":"Restore the backup onto the existing service (destructive).","required":["mode"],"properties":{"mode":{"type":"string","enum":["in_place"]}}},{"type":"object","description":"Provision a new service and restore into it.","required":["name","mode"],"properties":{"mode":{"type":"string","enum":["new_service"]},"name":{"type":"string","description":"Name for the new service. Orchestrator auto-suggests\n`{source}-restore-{yyyymmdd-hhmm}` if caller omits, but we require\nan explicit value at the API boundary."},"parameter_overrides":{"description":"Optional parameter overrides (port, docker_image, database)."}}},{"type":"object","description":"Point-in-time recovery. Only valid on WAL-G backups (Postgres).","required":["to_new_service","target","mode"],"properties":{"mode":{"type":"string","enum":["pitr"]},"new_service_name":{"type":["string","null"],"description":"Required when `to_new_service` is true."},"target":{"$ref":"#/components/schemas/RecoveryTarget","description":"Recovery target kind + value."},"to_new_service":{"type":"boolean","description":"Whether PITR restores in place or creates a new service."}}}],"description":"What the caller wants to do. Mirrors `externalsvc::RestoreMode` but\nflattened for JSON over the wire."},"RestoreRunView":{"type":"object","required":["id","source_backup_id","source_service_id","mode","status","phase","created_at"],"properties":{"created_at":{"type":"string"},"error_message":{"type":["string","null"]},"finished_at":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"mode":{"type":"string"},"phase":{"type":"string"},"recovery_target":{},"source_backup_id":{"type":"integer","format":"int32"},"source_service_id":{"type":"integer","format":"int32"},"started_at":{"type":["string","null"]},"status":{"type":"string"},"target_service_id":{"type":["integer","null"],"format":"int32"},"target_service_name":{"type":["string","null"]}}},"RetentionCleanupFailure":{"type":"object","required":["backup_id","reason","partial","deleted_objects"],"properties":{"backup_id":{"type":"string"},"deleted_objects":{"type":"integer","format":"int64","minimum":0},"partial":{"type":"boolean"},"reason":{"type":"string"}}},"RetentionCleanupReport":{"type":"object","required":["dry_run","expired","deleted","failed","failures","deleted_backup_ids","deleted_backup_ids_truncated","partially_deleted_backup_ids","partially_deleted_backup_ids_truncated","candidate_backup_ids","candidate_backup_ids_truncated"],"properties":{"candidate_backup_ids":{"type":"array","items":{"type":"string"},"description":"Capped sample of backups selected by the retention policy."},"candidate_backup_ids_truncated":{"type":"boolean"},"deleted":{"type":"integer","format":"int64","minimum":0},"deleted_backup_ids":{"type":"array","items":{"type":"string"},"description":"Capped sample of deleted backup UUIDs for audit attribution."},"deleted_backup_ids_truncated":{"type":"boolean"},"dry_run":{"type":"boolean","description":"True when this report is a non-destructive preview."},"expired":{"type":"integer","format":"int64","minimum":0},"failed":{"type":"integer","format":"int64","minimum":0},"failures":{"type":"array","items":{"$ref":"#/components/schemas/RetentionCleanupFailure"},"description":"Capped diagnostic sample; `failed` remains the authoritative total."},"partially_deleted_backup_ids":{"type":"array","items":{"type":"string"}},"partially_deleted_backup_ids_truncated":{"type":"boolean"},"schedule_id":{"type":["integer","null"],"format":"int32","description":"Schedule scope, or `None` when every schedule was considered."}}},"RetryClusterRequest":{"type":"object","description":"Request body for retrying a failed cluster initialization.","properties":{"members":{"type":"array","items":{"$ref":"#/components/schemas/ClusterMemberRequest"},"description":"Cluster member specifications (same format as create).\nIf omitted, the original member configuration is reconstructed from\nthe preserved service_members records."}}},"RevenueRow":{"type":"object","required":["id","ts","provider","event_type"],"properties":{"amount_minor":{"type":["integer","null"],"format":"int64"},"currency":{"type":["string","null"]},"customer_ref":{"type":["string","null"]},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"event_type":{"type":"string"},"id":{"type":"integer","format":"int64"},"provider":{"type":"string"},"trace_id":{"type":["string","null"]},"ts":{"type":"string","format":"date-time"}}},"RiskLevel":{"type":"string","description":"Risk level for a migration step","enum":["none","low","medium","high","critical"]},"RoleInfo":{"type":"object","description":"Information about a role","required":["name","description","permissions"],"properties":{"description":{"type":"string","description":"Human-readable description of the role"},"name":{"type":"string","description":"The role identifier (e.g., \"admin\")"},"permissions":{"type":"array","items":{"type":"string"},"description":"Permissions included in this role"}}},"RootfsCacheEntry":{"type":"object","description":"A cached rootfs image (Firecracker backend). Digest-keyed build artifact\nshared by all VMs created from the same image.","required":["digest","bytes","referenced_by"],"properties":{"bytes":{"type":"integer","format":"int64","description":"Actual on-disk size in bytes (sparse-aware).","minimum":0},"digest":{"type":"string","description":"Image digest this rootfs was built from (the cache key)."},"referenced_by":{"type":"array","items":{"type":"string"},"description":"IDs of live sandboxes whose per-VM disk was cloned from this entry.\nEmpty means the entry is reclaimable — no sandbox needs it."}}},"RootfsGcReport":{"type":"object","description":"Outcome of a rootfs garbage-collection pass.","required":["removed_digests","freed_bytes"],"properties":{"freed_bytes":{"type":"integer","format":"int64","minimum":0},"removed_digests":{"type":"array","items":{"type":"string"},"description":"Digests of cache entries removed because no sandbox referenced them."}}},"RootfsReport":{"type":"object","description":"Snapshot of a backend's rootfs storage for the management API. Backends\nwithout a rootfs concept (Docker, local) return an empty report.","required":["cache_bytes","cache","vm_bytes","vms"],"properties":{"cache":{"type":"array","items":{"$ref":"#/components/schemas/RootfsCacheEntry"}},"cache_bytes":{"type":"integer","format":"int64","minimum":0},"vm_bytes":{"type":"integer","format":"int64","minimum":0},"vms":{"type":"array","items":{"$ref":"#/components/schemas/RootfsVmEntry"}}}},"RootfsVmEntry":{"type":"object","description":"A per-sandbox rootfs disk (Firecracker backend). One per non-destroyed\nsandbox — the authoritative storage, independent of the cache.","required":["sandbox_name","bytes","running"],"properties":{"bytes":{"type":"integer","format":"int64","minimum":0},"running":{"type":"boolean"},"sandbox_name":{"type":"string"}}},"RouteRefreshResponse":{"type":"object","required":["route_count","message"],"properties":{"message":{"type":"string","description":"Human-readable message"},"route_count":{"type":"integer","description":"Number of routes loaded","minimum":0}}},"RouteResponse":{"type":"object","required":["id","domain","host","port","enabled","route_type","created_at","updated_at"],"properties":{"created_at":{"type":"integer","format":"int64"},"domain":{"type":"string"},"enabled":{"type":"boolean"},"host":{"type":"string"},"id":{"type":"integer","format":"int32"},"port":{"type":"integer","format":"int32"},"route_type":{"type":"string","description":"Route type: \"http\" or \"tls\""},"updated_at":{"type":"integer","format":"int64"}}},"RouteRole":{"type":"object","required":["id","name","created_at","updated_at"],"properties":{"created_at":{"type":"integer","format":"int64","example":"1683900000000"},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"updated_at":{"type":"integer","format":"int64","example":"1683900000000"}}},"RouteUser":{"type":"object","required":["id","name","username","email","image","mfa_enabled","email_verified","must_change_password","created_at","updated_at"],"properties":{"created_at":{"type":"integer","format":"int64","example":"1683900000000"},"deleted_at":{"type":["integer","null"],"format":"int64"},"email":{"type":"string"},"email_verified":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"image":{"type":"string"},"mfa_enabled":{"type":"boolean"},"must_change_password":{"type":"boolean"},"name":{"type":"string"},"updated_at":{"type":"integer","format":"int64","example":"1683900000000"},"username":{"type":"string"}}},"RouteUserWithRoles":{"type":"object","required":["user","roles"],"properties":{"roles":{"type":"array","items":{"$ref":"#/components/schemas/RouteRole"}},"user":{"$ref":"#/components/schemas/RouteUser"}}},"RunBackupRequest":{"type":"object","required":["backup_type"],"properties":{"backup_type":{"type":"string","description":"Type of backup to perform","example":"full"}}},"RunExternalServiceBackupRequest":{"type":"object","properties":{"backup_type":{"type":["string","null"],"description":"Type of backup to perform (e.g., \"full\", \"incremental\")","example":"full"},"s3_source_id":{"type":["integer","null"],"format":"int32","description":"ID of the S3 source to store the backup. If omitted, the current default S3 source is used.","example":1}}},"S3ConnectionTestResponse":{"type":"object","description":"Response body for an S3 connection test.","required":["ok","message"],"properties":{"message":{"type":"string","description":"Human-readable message (success confirmation or error detail)."},"ok":{"type":"boolean","description":"Whether the connection and credentials worked."}}},"S3CredentialsResponse":{"type":"object","description":"S3 credentials distributed to agents for backup/restore operations.","required":["access_key_id","secret_key","region","bucket_name","force_path_style"],"properties":{"access_key_id":{"type":"string"},"bucket_name":{"type":"string"},"endpoint":{"type":["string","null"]},"force_path_style":{"type":"boolean"},"region":{"type":"string"},"secret_key":{"type":"string"}}},"S3SourceResponse":{"type":"object","description":"Response type for S3 source","required":["id","name","bucket_name","bucket_path","access_key_id","secret_key","region","is_default","created_at","updated_at"],"properties":{"access_key_id":{"type":"string","example":"AKIAXXXXXXXXXXXXXXXX"},"bucket_name":{"type":"string"},"bucket_path":{"type":"string"},"created_at":{"type":"integer","format":"int64"},"endpoint":{"type":["string","null"],"example":"http://minio.example.com:9000"},"force_path_style":{"type":["boolean","null"]},"id":{"type":"integer","format":"int32"},"is_default":{"type":"boolean"},"name":{"type":"string"},"region":{"type":"string"},"secret_key":{"type":"string","writeOnly":true},"updated_at":{"type":"integer","format":"int64"}}},"SandboxDomainResponse":{"type":"object","required":["url"],"properties":{"url":{"type":"string"}}},"SandboxEvent":{"type":"object","description":"One entry in a sandbox's operations timeline.","required":["event_type","at"],"properties":{"at":{"type":"integer","format":"int64","description":"Unix epoch milliseconds."},"detail":{"description":"Optional structured context (shape depends on `event_type`)."},"event_type":{"type":"string","description":"Machine-readable operation (`created`, `stopped`, `resumed`,\n`restarted`, `timeout_extended`, `resized`, `preview_password_set`,\n`preview_password_cleared`, `preview_share_link_created`, `source_seeded`,\n`destroyed`)."}}},"SandboxEventsResponse":{"type":"object","required":["events"],"properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/SandboxEvent"}}}},"SandboxInner":{"type":"object","description":"Inner `sandbox` object in `@vercel/sandbox` responses. Strict shape —\nthe SDK's zod validator rejects missing required fields.","required":["id","memory","vcpus","region","runtime","timeout","status","requestedAt","createdAt","updatedAt","cwd","name","preview_url_template"],"properties":{"agent_run_id":{"type":["integer","null"],"format":"int32","description":"Agent run this sandbox executes (autofixer / workflow agent).\n`None` for sandboxes created via this API."},"backend":{"type":["string","null"],"description":"Isolation backend: \"docker\" | \"firecracker\". `None` on legacy rows\ncreated before the backend was recorded."},"createdAt":{"type":"integer","format":"int64"},"cwd":{"type":"string"},"disk_size_mb":{"type":["integer","null"],"format":"int64","description":"Configured root disk size in MB (Firecracker). `None` when unknown or\nthe default.","minimum":0},"id":{"type":"string"},"image":{"type":["string","null"]},"memory":{"type":"integer","format":"int64","minimum":0},"name":{"type":"string"},"preview_password_hint":{"type":["string","null"]},"preview_url_template":{"type":"string"},"region":{"type":"string"},"requestedAt":{"type":"integer","format":"int64","description":"Creation time as Unix epoch milliseconds."},"runtime":{"type":"string"},"status":{"type":"string"},"timeout":{"type":"integer","format":"int64","description":"Idle timeout in milliseconds (SDK convention).","minimum":0},"updatedAt":{"type":"integer","format":"int64"},"vcpus":{"type":"number","format":"double"}}},"SandboxResponse":{"type":"object","description":"`@vercel/sandbox` wraps every single-sandbox response as\n`{ sandbox: {...}, routes: [...] }`. The SDK reads both.","required":["sandbox","routes"],"properties":{"routes":{"type":"array","items":{"$ref":"#/components/schemas/SandboxRoute"}},"sandbox":{"$ref":"#/components/schemas/SandboxInner"}}},"SandboxRoute":{"type":"object","description":"A single preview route, one per declared port. We don't know ports\nupfront, so we surface an empty array by default — SDK clients use\ntheir own port when calling `sandbox.domain(port)`.","required":["url","subdomain","port"],"properties":{"port":{"type":"integer","format":"int32","minimum":0},"subdomain":{"type":"string"},"url":{"type":"string"}}},"SandboxStatusResponse":{"type":"object","required":["docker_available","image_ready","image_name","firecracker_available"],"properties":{"docker_available":{"type":"boolean"},"error":{"type":["string","null"]},"firecracker_available":{"type":"boolean"},"image_name":{"type":"string"},"image_ready":{"type":"boolean"}}},"SaveAgentTokenRequest":{"type":"object","required":["token"],"properties":{"token":{"type":"string","description":"The OAuth token from `claude setup-token` or an API key.\nWill be encrypted before storage."}}},"SaveAgentTokenResponse":{"type":"object","required":["saved"],"properties":{"saved":{"type":"boolean"}}},"SaveCredentialRequest":{"type":"object","required":["auth_type","credential"],"properties":{"auth_type":{"type":"string","description":"Auth flavor id (must match one of the provider's catalog entries)."},"credential":{"type":"string","description":"Plaintext credential body (API key, OAuth token, or full config file\ncontents). Encrypted with `EncryptionService` before being persisted\ninside the `agent_sandbox.providers` JSON map."}}},"SaveCredentialResponse":{"type":"object","required":["saved","provider_id","auth_type"],"properties":{"auth_type":{"type":"string"},"provider_id":{"type":"string"},"saved":{"type":"boolean"}}},"ScalewayCredentialsRequest":{"type":"object","required":["api_key","project_id"],"properties":{"api_key":{"type":"string","example":"scw-secret-key-12345"},"project_id":{"type":"string","example":"12345678-1234-1234-1234-123456789012"}}},"ScanResponse":{"type":"object","required":["id","project_id","scanner_type","status","total_count","critical_count","high_count","medium_count","low_count","unknown_count","started_at","created_at","updated_at"],"properties":{"branch":{"type":["string","null"]},"commit_hash":{"type":["string","null"]},"completed_at":{"type":["string","null"],"example":"2025-12-08T12:15:47.609192Z"},"created_at":{"type":"string","example":"2025-12-08T12:15:47.609192Z"},"critical_count":{"type":"integer","format":"int32"},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"error_message":{"type":["string","null"]},"high_count":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"low_count":{"type":"integer","format":"int32"},"medium_count":{"type":"integer","format":"int32"},"project_id":{"type":"integer","format":"int32"},"scanner_type":{"type":"string"},"scanner_version":{"type":["string","null"]},"started_at":{"type":"string","example":"2025-12-08T12:15:47.609192Z"},"status":{"type":"string"},"total_count":{"type":"integer","format":"int32"},"unknown_count":{"type":"integer","format":"int32"},"updated_at":{"type":"string","example":"2025-12-08T12:15:47.609192Z"}}},"ScheduleRunEntry":{"type":"object","description":"A single run-history entry for the schedule detail page (deliverable 1).\n\nCombines one `backups` row with the most-recent `backup_jobs` row for that\nbackup via a lateral JOIN. Fields from `backup_jobs` are `None` for legacy\nbackup rows that pre-date ADR-014.","required":["backup_id","backup_uuid","state","started_at","s3_location"],"properties":{"attempts":{"type":["integer","null"],"format":"int32","description":"Number of claim-and-run attempts so far. `None` for legacy rows."},"backup_id":{"type":"integer","format":"int32","description":"DB id of the `backups` row."},"backup_uuid":{"type":"string","description":"UUID string (`backups.backup_id`)."},"current_step":{"type":["string","null"],"description":"Last completed step reported by the engine (e.g. `\"upload\"`).\n`None` when no step has been persisted yet."},"error_message":{"type":["string","null"],"description":"Engine-reported error message when `state = \"failed\"`."},"finished_at":{"type":["string","null"],"description":"When the backup finished, if known."},"job_id":{"type":["integer","null"],"format":"int64","description":"Most recent `backup_jobs.id` for this backup. `None` for legacy rows."},"s3_location":{"type":"string","description":"S3 object key or URL where the backup data lives."},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Final size in bytes once completed. `None` while running."},"started_at":{"type":"string","description":"When the backup was started (ISO 8601 / RFC 3339)."},"state":{"type":"string","description":"Current state: `\"pending\"`, `\"running\"`, `\"completed\"`, `\"failed\"`."}}},"ScheduleRunJobEntry":{"type":"object","description":"A single job entry inside an expanded schedule run, returned by\n[`BackupService::list_schedule_run_jobs`].","required":["backup_id","backup_uuid","engine","service_name","state","started_at","s3_source_id"],"properties":{"backup_id":{"type":"integer","format":"int32","description":"`backups.id` for this job."},"backup_uuid":{"type":"string","description":"`backups.backup_id` UUID string."},"engine":{"type":"string","description":"Engine key (e.g. `\"control_plane\"`, `\"redis\"`)."},"error_message":{"type":["string","null"],"description":"Engine-reported error message when `state = \"failed\"`."},"finished_at":{"type":["string","null"],"description":"When this child backup finished, if known."},"s3_source_id":{"type":"integer","format":"int32","description":"FK to `s3_sources.id` — needed for the backup detail link."},"service_id":{"type":["integer","null"],"format":"int32","description":"`external_services.id` — `NULL` for the control-plane job."},"service_name":{"type":"string","description":"Name of the external service, or `\"control plane\"` for the\ncontrol-plane job."},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Size in bytes once completed; `None` while running."},"started_at":{"type":"string","description":"When this child backup started (ISO 8601 / RFC 3339)."},"state":{"type":"string","description":"Current state of this child backup."}}},"ScheduleRunListResponse":{"type":"object","description":"Paginated run-history response for a backup schedule (deliverable 1).","required":["runs","total","page","page_size"],"properties":{"page":{"type":"integer","format":"int64","description":"Current page (1-based)."},"page_size":{"type":"integer","format":"int64","description":"Number of items per page (clamped to 1–100)."},"runs":{"type":"array","items":{"$ref":"#/components/schemas/ScheduleRunEntry"},"description":"Run entries, newest first."},"total":{"type":"integer","format":"int64","description":"Total number of runs across all pages."}}},"ScheduleRunResponse":{"type":"object","description":"HTTP response body for `POST /api/backups/schedules/{id}/run` (fan-out).","required":["schedule_run_id","jobs"],"properties":{"jobs":{"type":"array","items":{"$ref":"#/components/schemas/EnqueuedJob"},"description":"All jobs that were enqueued in this fan-out."},"schedule_run_id":{"type":"integer","format":"int64","description":"The `schedule_runs.id` of the newly created run."}}},"ScheduleRunSummary":{"type":"object","description":"Summary of one scheduler tick (or one \"Run now\" click), returned by\n[`BackupService::list_schedule_runs`].\n\nThe `aggregate_state` is computed at read time from child backup counts:\n- `\"running\"` — at least one child is `\"pending\"` or `\"running\"`.\n- `\"failed\"` — at least one child is `\"failed\"` and none are running.\n- `\"completed\"` — all children are `\"completed\"`.","required":["run_id","schedule_id","triggered_by","started_at","aggregate_state","total_jobs","completed_jobs","failed_jobs","running_jobs","pending_jobs"],"properties":{"aggregate_state":{"type":"string","description":"Aggregate state computed from child counts (see struct docs)."},"completed_jobs":{"type":"integer","format":"int64","description":"Number of children in `state = \"completed\"`."},"failed_jobs":{"type":"integer","format":"int64","description":"Number of children in `state = \"failed\"`."},"finished_at":{"type":["string","null"],"description":"When all children reached a terminal state. `None` while any child is\nstill `\"pending\"` or `\"running\"`."},"pending_jobs":{"type":"integer","format":"int64","description":"Number of children in `state = \"pending\"`."},"run_id":{"type":"integer","format":"int64","description":"`schedule_runs.id` for this tick."},"running_jobs":{"type":"integer","format":"int64","description":"Number of children in `state = \"running\"`."},"schedule_id":{"type":"integer","format":"int32","description":"FK to `backup_schedules.id`."},"started_at":{"type":"string","description":"When the fan-out started (ISO 8601 / RFC 3339)."},"total_jobs":{"type":"integer","format":"int64","description":"Total number of child backup jobs in this run."},"triggered_by":{"type":"string","description":"How the run was triggered: `\"cron\"` or `\"manual\"`."}}},"ScheduleRunSummaryList":{"type":"object","description":"Paginated list of schedule run summaries returned by the new\n[`BackupService::list_schedule_runs`].","required":["runs","total","page","page_size"],"properties":{"page":{"type":"integer","format":"int64","description":"Current page (1-based)."},"page_size":{"type":"integer","format":"int64","description":"Number of items per page."},"runs":{"type":"array","items":{"$ref":"#/components/schemas/ScheduleRunSummary"},"description":"Run summaries, newest first. Includes synthetic single-job rows for\nlegacy `backups` rows that have `schedule_id` set but no\n`schedule_run_id` (pre-fan-out history)."},"total":{"type":"integer","format":"int64","description":"Total number of run entries across all pages."}}},"ScreenshotSettings":{"type":"object","properties":{"enabled":{"type":"boolean","default":false},"provider":{"type":"string","default":"local"},"url":{"type":"string","default":""}}},"SearchLogsRequest":{"type":"object","required":["project_id"],"properties":{"container_ids":{"type":"array","items":{"type":"string"},"description":"Filter to specific containers (Docker container IDs). Empty = all\ncontainers. Drives \"filter by container / show all\" in a project's\nhistory, which spans multiple deployments and containers."},"context_lines":{"type":["integer","null"],"format":"int32","description":"grep -C: number of raw context lines to include before and after each\nmatch (0 = none, default). Clamped to 50 server-side. The surrounding\nlines ignore the level/text filters — they are the actual adjacent log\nlines, merged across overlapping matches.","minimum":0},"cursor":{"type":["string","null"],"description":"Pagination cursor"},"deploy_id":{"type":["integer","null"],"format":"int32","description":"Filter by deployment ID (deployments.id)"},"end_time":{"type":["string","null"],"description":"End of time range (ISO 8601). Defaults to now."},"envs":{"type":"array","items":{"type":"string"},"description":"Filter by environments"},"external_service_id":{"type":["integer","null"],"format":"int32","description":"When set, search an imported/managed external service's logs instead\nof a project's. `project_id` is ignored in this mode."},"levels":{"type":"array","items":{"type":"string"},"description":"Filter by log levels"},"node_ids":{"type":"array","items":{"type":"integer","format":"int32"},"description":"Filter to specific worker nodes (node_id). Empty = all nodes, including\ncontrol-plane-local logs."},"page_size":{"type":["integer","null"],"format":"int32","description":"Page size (default: 100, max: 500)","minimum":0},"project_id":{"type":"integer","format":"int32","description":"Project ID (integer, as used by the rest of the platform)"},"services":{"type":"array","items":{"type":"string"},"description":"Filter by services"},"start_time":{"type":["string","null"],"description":"Start of time range (ISO 8601). Defaults to 1 hour ago."},"text":{"type":["string","null"],"description":"Full text search query"}}},"SearchLogsResponse":{"type":"object","required":["lines","search_mode","total_scanned"],"properties":{"available_sources":{"type":"array","items":{"$ref":"#/components/schemas/LogSource"},"description":"Distinct containers/nodes/services available in the queried scope, for\nthe filter dropdowns. Populated on the first page (no cursor)."},"lines":{"type":"array","items":{"$ref":"#/components/schemas/LogSearchLine"}},"next_cursor":{"type":["string","null"]},"search_mode":{"$ref":"#/components/schemas/SearchMode"},"total_scanned":{"type":"integer","format":"int64","minimum":0}}},"SearchMode":{"type":"string","description":"Search execution mode","enum":["index","archive"]},"Seasonality":{"type":"string","description":"Seasonality model for an anomaly baseline.","enum":["none","hourly","daily","weekly"]},"SecretResponse":{"type":"object","required":["id","name","secret_type","value","created_at","updated_at"],"properties":{"created_at":{"type":"string"},"description":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"mount_path":{"type":["string","null"]},"name":{"type":"string"},"secret_type":{"type":"string"},"updated_at":{"type":"string"},"value":{"type":"string","description":"Always masked in responses"}}},"SecurityConfig":{"type":"object","description":"Security configuration for projects and environments\n\nThis configuration can be set at three levels:\n1. Global (in settings table) - applies to all projects\n2. Project level - overrides global settings for specific project\n3. Environment level - overrides project settings for specific environment\n\nThe inheritance chain: Environment > Project > Global","properties":{"attackMode":{"type":["string","null"],"description":"Attack mode configuration (future: \"off\", \"challenge\", \"block\")\nPlaceholder for DDoS protection, bot detection, etc."},"challengeConfig":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ChallengeConfig","description":"Challenge configuration (future: CAPTCHA, JS challenge, etc.)"}]},"enabled":{"type":["boolean","null"],"description":"Enable/disable security features at this level\nIf None, inherits from parent level"},"geoRestrictions":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/GeoRestrictionsConfig","description":"Geographic restrictions (future: country blocking, etc.)"}]},"headers":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SecurityHeadersConfig","description":"Security headers configuration"}]},"passwordProtection":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PasswordProtectionConfig","description":"Password protection: shows an HTML password form before allowing access"}]},"rateLimiting":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/RateLimitConfig","description":"Rate limiting configuration"}]}}},"SecurityHeadersConfig":{"type":"object","description":"Security headers configuration (subset of global SecurityHeadersSettings)","properties":{"contentSecurityPolicy":{"type":["string","null"],"description":"Custom CSP (only used if preset is \"custom\")"},"preset":{"type":["string","null"],"description":"Use a preset: \"strict\", \"moderate\", \"permissive\", \"disabled\", \"custom\""},"referrerPolicy":{"type":["string","null"],"description":"Referrer-Policy override"},"strictTransportSecurity":{"type":["string","null"],"description":"HSTS override"},"xFrameOptions":{"type":["string","null"],"description":"X-Frame-Options override"}}},"SecurityHeadersSettings":{"type":"object","properties":{"content_security_policy":{"type":["string","null"],"default":"default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self'; frame-ancestors 'self'"},"enabled":{"type":"boolean","default":false},"permissions_policy":{"type":["string","null"],"default":"geolocation=(), microphone=(), camera=()"},"preset":{"type":"string","default":"moderate"},"referrer_policy":{"type":"string","default":"strict-origin-when-cross-origin"},"strict_transport_security":{"type":"string","default":"max-age=31536000; includeSubDomains"},"x_content_type_options":{"type":"string","default":"nosniff"},"x_frame_options":{"type":"string","default":"SAMEORIGIN"},"x_xss_protection":{"type":"string","default":"1; mode=block"}}},"SelfUpdateAttempt":{"type":"object","description":"A single update attempt. Persisted to `/self-update.json` so the\nresult survives the restart it causes.","required":["from_version","status","started_at"],"properties":{"error":{"type":["string","null"],"description":"Operator-facing failure reason. Always set when `status` is `Failed`."},"finished_at":{"type":["string","null"],"format":"date-time","description":"When the outcome was decided. `None` while still `Pending`."},"from_version":{"type":"string","description":"Version the attempt started from."},"previous_binary_path":{"type":["string","null"],"description":"Where the replaced binary was kept, so a bad release can be reverted by\nhand (`mv `). Set once the swap completes."},"started_at":{"type":"string","format":"date-time","example":"2026-08-06T09:12:31Z"},"status":{"$ref":"#/components/schemas/SelfUpdateStatus"},"to_version":{"type":["string","null"],"description":"Version the attempt targeted. `None` if it failed before resolving one."},"triggered_by_user_id":{"type":["integer","null"],"format":"int32","description":"User who clicked the button. `None` for attempts started by the CLI."}}},"SelfUpdateBlocker":{"type":"string","description":"Why a one-click update is unavailable. Exactly one is reported — the most\nfundamental blocker wins, so the operator fixes the real problem first\nrather than clearing one only to hit the next.","enum":["disabled_by_flag","disabled_by_setting","container","no_supervisor","binary_not_writable","unsupported_platform","in_progress"]},"SelfUpdatePhase":{"type":"string","description":"Where an in-flight update has got to. Polled by the console so a long\ndownload shows progress instead of an indefinite spinner.","enum":["idle","resolving","downloading","verifying","installing","restarting","failed"]},"SelfUpdateSettings":{"type":"object","description":"Controls the console's one-click \"Update now\" action.","properties":{"enabled":{"type":"boolean","description":"Allow admins to apply a release and restart the server from the console.\n`true` by default: the action is permission-gated, audited, and only\never installs an official release whose published SHA-256 matches.\n\nTurning this off hides nothing — the console still shows the update\nbanner and the manual command, it just refuses to run it for you.","default":true,"example":true}}},"SelfUpdateStatus":{"type":"string","description":"Outcome of an update attempt, as persisted in the journal.","enum":["pending","succeeded","failed"]},"SendEmailRequestBody":{"type":"object","required":["from","to","subject"],"properties":{"bcc":{"type":["array","null"],"items":{"type":"string"},"description":"BCC recipients"},"cc":{"type":["array","null"],"items":{"type":"string"},"description":"CC recipients"},"from":{"type":"string","description":"Sender email address (domain will be auto-extracted for lookup)","example":"hello@updates.example.com"},"from_name":{"type":["string","null"],"description":"Sender display name","example":"My App"},"headers":{"type":["object","null"],"description":"Custom headers","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"html":{"type":["string","null"],"description":"HTML body content","example":"

Hello World

"},"reply_to":{"type":["string","null"],"description":"Reply-to address"},"subject":{"type":"string","description":"Email subject","example":"Welcome to our platform!"},"tags":{"type":["array","null"],"items":{"type":"string"},"description":"Tags for categorization","example":["welcome","onboarding"]},"text":{"type":["string","null"],"description":"Plain text body content","example":"Hello World"},"to":{"type":"array","items":{"type":"string"},"description":"Recipient email addresses","example":["user@example.com"]},"track_clicks":{"type":["boolean","null"],"description":"Enable click tracking (link rewriting). Defaults to false."},"track_opens":{"type":["boolean","null"],"description":"Enable open tracking (tracking pixel injection). Defaults to false."}}},"SendEmailResponseBody":{"type":"object","required":["id","status"],"properties":{"id":{"type":"string","description":"Email ID","example":"550e8400-e29b-41d4-a716-446655440000"},"provider_message_id":{"type":["string","null"],"description":"Provider message ID"},"status":{"type":"string","description":"Email status","example":"sent"}}},"SendMessageRequest":{"type":"object","required":["content"],"properties":{"content":{"type":"string"},"page_context":{"type":["string","null"],"description":"Optional, client-supplied description of the page/entity the user is\ncurrently viewing (e.g. a trace in a project). Injected into the model's\nview of this turn only — never stored or shown in history. Capped server\nside; oversized values are ignored rather than rejected."}}},"SensitiveConfigValueResponse":{"type":"object","required":["value"],"properties":{"value":{"type":"string"}}},"SensitiveMcpConfigValueResponse":{"type":"object","required":["value"],"properties":{"value":{"type":"string"}}},"SensitiveValueResponse":{"type":"object","required":["value"],"properties":{"value":{"type":"string"}}},"SentryChunkUploadResponse":{"type":"object","required":["url","chunkSize","chunksPerRequest","maxFileSize","maxRequestSize","concurrency","hashAlgorithm","compression","accept"],"properties":{"accept":{"type":"array","items":{"type":"string"}},"chunkSize":{"type":"integer","format":"int64","minimum":0},"chunksPerRequest":{"type":"integer","format":"int32","minimum":0},"compression":{"type":"array","items":{"type":"string"}},"concurrency":{"type":"integer","format":"int32","minimum":0},"hashAlgorithm":{"type":"string"},"maxFileSize":{"type":"integer","format":"int64","minimum":0},"maxRequestSize":{"type":"integer","format":"int64","minimum":0},"url":{"type":"string"}}},"SentryCreateReleaseRequest":{"type":"object","required":["version"],"properties":{"projects":{"type":"array","items":{"type":"string"},"description":"Project slugs this release belongs to"},"version":{"type":"string","description":"Release version identifier"}}},"SentryEventRequest":{"type":"object","properties":{"event_id":{"type":["string","null"]},"message":{"type":["string","null"]},"platform":{"type":["string","null"]},"timestamp":{"type":["string","null"]}}},"SentryEventResponse":{"type":"object","required":["id"],"properties":{"id":{"type":"string"}}},"SentryReleaseFileResponse":{"type":"object","required":["id","name","headers","size","sha1","dateCreated"],"properties":{"dateCreated":{"type":"string"},"dist":{"type":["string","null"]},"headers":{},"id":{"type":"string"},"name":{"type":"string"},"sha1":{"type":"string"},"size":{"type":"integer","format":"int64"}}},"SentryReleaseProjectRef":{"type":"object","required":["name","slug"],"properties":{"name":{"type":"string"},"slug":{"type":"string"}}},"SentryReleaseResponse":{"type":"object","required":["version","dateCreated","shortVersion","projects"],"properties":{"dateCreated":{"type":"string"},"dateReleased":{"type":["string","null"]},"projects":{"type":"array","items":{"$ref":"#/components/schemas/SentryReleaseProjectRef"}},"shortVersion":{"type":"string"},"version":{"type":"string"}}},"SeriesStateEntry":{"type":"object","description":"One series' persisted state snapshot for a dynamic rule (ADR-026 follow-up):\nthe state after the latest tick, the value evaluated this tick, and the open\nalarm id (when firing). Serialized into the `series_states` jsonb column keyed\nby the human-readable [`series_label`]; the alert response decodes it back.","required":["state","value"],"properties":{"alarm_id":{"type":["integer","null"],"format":"int32","description":"The open alarm's id when the series is firing; `null` when ok."},"state":{"type":"string","description":"`firing` or `ok` for this series after the latest tick."},"value":{"type":"number","format":"double","description":"The value the rule evaluated for this series this tick."}}},"ServiceAccessInfo":{"type":"object","description":"Response containing information about how the service is being accessed","required":["access_mode","can_create_domains"],"properties":{"access_mode":{"type":"string","description":"Mode of access: \"local\", \"direct\", \"nat\", or \"cloudflare_tunnel\""},"can_create_domains":{"type":"boolean","description":"Whether domain creation is allowed in this mode"},"domain_creation_error":{"type":["string","null"],"description":"Error message if domain creation is not allowed"},"private_ip":{"type":["string","null"],"description":"Server's private/local IP address (always returned if available)"},"public_ip":{"type":["string","null"],"description":"Server's public IP address (always returned if available)"}}},"ServiceAction":{"type":"string","description":"What to do with a service during migration","enum":["create","link-external","skip"]},"ServiceAlertRuleResponse":{"type":"object","description":"Wire representation of a monitoring alert rule.\n\nRegistered under a domain-prefixed OpenAPI schema name to avoid colliding\nwith `temps-error-tracking`'s unrelated `AlertRuleResponse` (utoipa keys\nschemas by their bare struct name, so without `as = ...` the last crate to\nregister would silently shadow this one in the merged spec / generated SDK).","required":["id","name","metric_name","threshold","comparator","severity","for_duration_secs","enabled"],"properties":{"comparator":{"type":"string"},"deployment_id":{"type":["integer","null"],"format":"int32"},"enabled":{"type":"boolean"},"for_duration_secs":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"metric_name":{"type":"string"},"name":{"type":"string"},"service_id":{"type":["integer","null"],"format":"int32"},"severity":{"type":"string"},"silenced_until":{"type":["string","null"]},"threshold":{"type":"number","format":"double"}}},"ServiceBackupEntryResponse":{"type":"object","description":"A single backup entry in the per-service backup list.","required":["id","backup_id","name","state","backup_type","started_at","s3_location","compression_type","s3_source_id","s3_source_name","external_service_backup_id"],"properties":{"backup_id":{"type":"string","description":"UUID string assigned at backup creation time."},"backup_type":{"type":"string","description":"Backup variant (e.g. \"full\", \"incremental\")."},"compression_type":{"type":"string","description":"Compression algorithm used (e.g. \"gzip\")."},"error_message":{"type":["string","null"],"description":"Engine-reported error message, populated when `state = \"failed\"`."},"external_service_backup_id":{"type":"integer","format":"int32","description":"Row ID from `external_service_backups`."},"finished_at":{"type":["string","null"],"description":"ISO 8601 timestamp when the backup finished, if known.","example":"2025-01-15T14:35:00Z"},"id":{"type":"integer","format":"int32","description":"Row ID from the `backups` table."},"name":{"type":"string","description":"Human-friendly display name."},"s3_location":{"type":"string","description":"Object key or `s3://` URL for the backup data."},"s3_source_id":{"type":"integer","format":"int32","description":"FK to `s3_sources.id`."},"s3_source_name":{"type":"string","description":"Human-readable name of the S3 source."},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Size of the backup in bytes, if available."},"started_at":{"type":"string","description":"ISO 8601 timestamp when the backup started.","example":"2025-01-15T14:30:00Z"},"state":{"type":"string","description":"Current state: \"completed\", \"running\", \"failed\"."}}},"ServiceBackupListResponse":{"type":"object","description":"Paginated list of backups for a specific external service.\n\nReturned by `GET /backups/external-services/{service_id}/backups`.","required":["backups","total","page","page_size"],"properties":{"backups":{"type":"array","items":{"$ref":"#/components/schemas/ServiceBackupEntryResponse"},"description":"Backups belonging to this service, newest first."},"page":{"type":"integer","format":"int64","description":"Current page (1-based)."},"page_size":{"type":"integer","format":"int64","description":"Number of items per page."},"total":{"type":"integer","format":"int64","description":"Total number of backups for this service across all pages."}}},"ServiceCreateAlertRuleRequest":{"type":"object","description":"Request body for creating an alert rule on an external service.\n\nDomain-prefixed schema name — see [`AlertRuleResponse`] for why.","required":["name","metric_name","threshold","comparator","severity"],"properties":{"comparator":{"type":"string","description":"One of `>`, `<`, `>=`, `<=`."},"enabled":{"type":"boolean"},"for_duration_secs":{"type":"integer","format":"int32","description":"Seconds the breach must persist before the alarm fires (0 = immediate)."},"metric_name":{"type":"string"},"name":{"type":"string"},"severity":{"type":"string","description":"`\"warning\"` or `\"critical\"`."},"threshold":{"type":"number","format":"double"}}},"ServiceHealthResponse":{"type":"object","required":["service_id","consecutive_failures","recent_checks"],"properties":{"consecutive_failures":{"type":"integer","format":"int32","description":"Consecutive failed probes. Alert fires at 3."},"last_checked_at":{"type":["string","null"]},"last_error":{"type":["string","null"]},"recent_checks":{"type":"array","items":{"$ref":"#/components/schemas/HealthCheckEntryResponse"},"description":"Most recent checks, newest-first (capped at `limit`)."},"response_time_ms":{"type":["integer","null"],"format":"int32"},"service_id":{"type":"integer","format":"int32"},"status":{"type":["string","null"],"description":"Current health. `null` if the service has not been probed yet.","example":"operational"},"uptime_24h_percent":{"type":["number","null"],"format":"double","description":"Uptime percentage over the last 24 hours (0.0 — 100.0).\n`null` when there is not enough history."}}},"ServiceHealthStatusBatchResponse":{"type":"object","required":["statuses"],"properties":{"statuses":{"type":"array","items":{"$ref":"#/components/schemas/ServiceHealthStatusEntryResponse"}}}},"ServiceHealthStatusEntryResponse":{"type":"object","required":["service_id","consecutive_failures"],"properties":{"consecutive_failures":{"type":"integer","format":"int32"},"last_checked_at":{"type":["string","null"]},"service_id":{"type":"integer","format":"int32"},"status":{"type":["string","null"],"description":"\"operational\" | \"degraded\" | \"down\". `null` when the service has not\nbeen probed yet.","example":"operational"}}},"ServiceMemberInfo":{"type":"object","description":"Public info about a cluster member.","required":["id","role","container_name","status","ordinal"],"properties":{"compute_ip":{"type":["string","null"],"description":"Container's IP on the `temps-overlay` multi-host network. Populated\nby the lifecycle hook (ADR-011 Phase 3); `None` on single-host\nclusters where the overlay isn't attached."},"container_name":{"type":"string"},"hostname":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"live_state":{"type":["string","null"],"description":"Live FSM state from the pg_auto_failover monitor (`primary`,\n`secondary`, `catchingup`, `report_lsn`, …). `None` when the\nmonitor is unreachable, the service is not a cluster, or the row\nis the monitor itself.\n\n**The UI must render the role badge from this field**, falling\nback to `role` only when `live_state` is null. `role` is now\nconfig-only (`monitor` or `replica`); flipping the badge to\n\"primary\" when the monitor elects a new one used to require a\nreconciler that lagged ~5s behind real failovers — and during\nthat window the UI showed two primaries. `live_state` is read\ndirectly from the monitor on every list, so it can never lag."},"node_id":{"type":["integer","null"],"format":"int32"},"ordinal":{"type":"integer","format":"int32"},"port":{"type":["integer","null"],"format":"int32"},"provisioning_error":{"type":["string","null"],"description":"Most recent provisioning failure message, when `status='failed'`.\nSet by the background task so the UI can show *why* the new\nreplica didn't come up."},"provisioning_step":{"type":["string","null"],"description":"Last-attempted phase of the async `add_cluster_member` background\ntask (e.g. `validating`, `provisioning_container`, `done`,\n`failed`). `None` for members not created through that flow —\nthe UI falls back to the `status` column for those."},"role":{"type":"string"},"status":{"type":"string"}}},"ServiceParameter":{"type":"object","required":["name","required","encrypted","description"],"properties":{"choices":{"type":["array","null"],"items":{"type":"string"}},"default_value":{"type":["string","null"]},"description":{"type":"string"},"encrypted":{"type":"boolean"},"name":{"type":"string"},"required":{"type":"boolean"},"validation_pattern":{"type":["string","null"]}}},"ServicePlan":{"type":"object","description":"Plan for migrating a single service (database, cache, etc.)","required":["name","service_type","action","action_description"],"properties":{"action":{"$ref":"#/components/schemas/ServiceAction","description":"What to do with this service"},"action_description":{"type":"string","description":"Human-readable explanation of what this action means"},"data_implications":{"type":"array","items":{"$ref":"#/components/schemas/DataImplication"},"description":"Data implications specific to this service"},"env_var_mappings":{"type":"object","description":"Environment variable key mappings: source_key -> temps_key\n\nFor example, Vercel's `POSTGRES_URL` might map to Temps' `DATABASE_URL`.\nBoth keys will be set during migration so the app works with either.","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"name":{"type":"string","description":"Human-readable service name"},"parameters":{"type":"object","description":"Parameters for creating the service in Temps","additionalProperties":{},"propertyNames":{"type":"string"}},"service_type":{"type":"string","description":"Service type (maps to temps-providers ServiceType)"},"version":{"type":["string","null"],"description":"Service version to create (e.g., \"16\" for Postgres 16)"}}},"ServiceResourceLimits":{"type":"object","description":"Optional cgroup resource limits applied to a service container.\n\nAll fields are `Option`: `None` means \"no limit\" (the kernel default),\nmatching Docker's behavior when the corresponding `HostConfig` field is\nleft at zero. Operators opt in to limits explicitly through the\n`PATCH /external-services/{id}/resources` endpoint or by writing the\n`resources` block into `ServiceConfig::parameters` at create time.\n\nThese map directly onto bollard fields:\n- `memory_mb` → `HostConfig.memory` (bytes)\n- `memory_swap_mb`→ `HostConfig.memory_swap` (bytes; ≥ memory)\n- `nano_cpus` → `HostConfig.nano_cpus` (1e9 = 1 full CPU)\n- `cpu_shares` → `HostConfig.cpu_shares` (relative weight, default 1024)\n- `shm_size_mb` → `HostConfig.shm_size` (bytes; default 64 MiB)\n\nIMPORTANT: enabling hard memory limits causes the kernel OOM killer to\nterminate the container when the working set exceeds the limit. The\ncontainer will restart (RestartPolicy::ALWAYS) but in-flight queries\nfail. Surface this clearly in any UI that lets users set limits.","properties":{"cpu_shares":{"type":["integer","null"],"format":"int64","description":"Relative CPU weight (default 1024). Only used when `nano_cpus` is None."},"memory_mb":{"type":["integer","null"],"format":"int64","description":"Hard memory limit in MiB. None = unlimited."},"memory_swap_mb":{"type":["integer","null"],"format":"int64","description":"Memory + swap limit in MiB. None = unlimited.\nMUST be >= memory_mb when both are set; Docker rejects the request otherwise.\nSet equal to `memory_mb` to disable swap entirely."},"nano_cpus":{"type":["integer","null"],"format":"int64","description":"CPU quota in nano-cpus. 1_000_000_000 = 1 full CPU core. None = unlimited."},"shm_size_mb":{"type":["integer","null"],"format":"int64","description":"Shared memory (/dev/shm) size in MiB. None = Docker default (64 MiB).\nMaps to HostConfig.shm_size (bytes). PostgreSQL uses /dev/shm for parallel\nquery workers and large work_mem; the 64 MiB default causes \"could not\nresize shared memory segment ... No space left on device\" under load.\nNOTE: shm_size is fixed at container-create time — Docker's live update\nAPI cannot change it, so changing this value recreates the container."}}},"ServiceRuntimeReport":{"type":"object","description":"Aggregate runtime info for an external service. For standalone services,\n`members` has exactly one entry. For clusters, one entry per member.","required":["service_id","topology","members"],"properties":{"members":{"type":"array","items":{"$ref":"#/components/schemas/ContainerRuntimeInfo"}},"service_id":{"type":"integer","format":"int32"},"topology":{"type":"string"}}},"ServiceStatsReport":{"type":"object","required":["service_id","topology","members"],"properties":{"members":{"type":"array","items":{"$ref":"#/components/schemas/ContainerStatsSample"}},"service_id":{"type":"integer","format":"int32"},"topology":{"type":"string"}}},"ServiceTypeInfo":{"type":"object","required":["service_type","parameters"],"properties":{"parameters":{"type":"array","items":{"$ref":"#/components/schemas/ServiceParameter"},"example":"[{\"name\": \"host\", \"required\": true, \"encrypted\": false, \"description\": \"Database host\"}]"},"service_type":{"$ref":"#/components/schemas/ServiceTypeRoute"}}},"ServiceTypeRoute":{"type":"string","enum":["mariadb","mongodb","postgres","redis","s3","kv","blob","rustfs","minio"]},"ServiceUpdateAlertRuleRequest":{"type":"object","description":"Request body for updating an existing alert rule.\n\nDomain-prefixed schema name — see [`AlertRuleResponse`] for why.","properties":{"comparator":{"type":["string","null"]},"enabled":{"type":["boolean","null"]},"for_duration_secs":{"type":["integer","null"],"format":"int32"},"metric_name":{"type":["string","null"]},"name":{"type":["string","null"]},"severity":{"type":["string","null"]},"threshold":{"type":["number","null"],"format":"double"}}},"SesCredentialsRequest":{"type":"object","required":["access_key_id","secret_access_key"],"properties":{"access_key_id":{"type":"string","example":"AKIAIOSFODNN7EXAMPLE"},"secret_access_key":{"type":"string","example":"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"}}},"SessionDetails":{"type":"object","required":["session_id","visitor_id","started_at","duration_seconds","is_bounced","is_engaged","page_views"],"properties":{"duration_seconds":{"type":"integer","format":"int64"},"ended_at":{"type":["string","null"],"format":"date-time","example":"2024-01-01T00:00:00"},"entry_path":{"type":["string","null"]},"exit_path":{"type":["string","null"]},"is_bounced":{"type":"boolean"},"is_engaged":{"type":"boolean"},"page_views":{"type":"integer","format":"int64"},"referrer":{"type":["string","null"]},"session_id":{"type":"integer","format":"int32"},"started_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"visitor_id":{"type":"string"}}},"SessionDetailsQuery":{"type":"object","required":["project_id"],"properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"}}},"SessionEvent":{"type":"object","required":["id","timestamp"],"properties":{"event_data":{},"event_name":{"type":["string","null"]},"event_type":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"page_title":{"type":["string","null"]},"page_url":{"type":["string","null"]},"timestamp":{"type":"string"}}},"SessionEventDto":{"type":"object","required":["id","session_id","data","timestamp"],"properties":{"data":{},"event_type":{"type":["integer","null"],"format":"int32"},"id":{"type":"integer","format":"int32"},"session_id":{"type":"integer","format":"int32"},"timestamp":{"type":"integer","format":"int64"}}},"SessionEventsQuery":{"type":"object","required":["project_id"],"properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"}}},"SessionEventsResponse":{"type":"object","required":["session_id","events","total_count","offset","limit"],"properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/SessionEvent"}},"limit":{"type":"integer","format":"int32"},"offset":{"type":"integer","format":"int32"},"session_id":{"type":"integer","format":"int32"},"total_count":{"type":"integer","format":"int64"}}},"SessionLogsQuery":{"type":"object","required":["project_id"],"properties":{"end_date":{"type":["string","null"],"format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32"},"offset":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"sort_order":{"type":["string","null"]},"start_date":{"type":["string","null"],"format":"date-time"},"visitor_id":{"type":["integer","null"],"format":"int32"}}},"SessionLogsResponse":{"type":"object","required":["session_id","logs","total_count","offset","limit"],"properties":{"limit":{"type":"integer","format":"int32"},"logs":{"type":"array","items":{"$ref":"#/components/schemas/SessionRequestLog"}},"offset":{"type":"integer","format":"int32"},"session_id":{"type":"integer","format":"int32"},"total_count":{"type":"integer","format":"int64"}}},"SessionReplayEventsRequest":{"type":"object","required":["sessionId","events"],"properties":{"events":{"type":"string"},"sessionId":{"type":"string"}}},"SessionReplayInfoDto":{"type":"object","required":["id","visitor_id"],"properties":{"created_at":{"type":["string","null"]},"duration":{"type":["integer","null"],"format":"int32"},"id":{"type":"string"},"language":{"type":["string","null"]},"screen_height":{"type":["integer","null"],"format":"int32"},"screen_width":{"type":["integer","null"],"format":"int32"},"timezone":{"type":["string","null"]},"url":{"type":["string","null"]},"user_agent":{"type":["string","null"]},"viewport_height":{"type":["integer","null"],"format":"int32"},"viewport_width":{"type":["integer","null"],"format":"int32"},"visitor_id":{"type":"integer","format":"int32"}}},"SessionReplayInitRequest":{"type":"object","required":["sessionId"],"properties":{"colorDepth":{"type":["integer","null"],"format":"int32","minimum":0},"language":{"type":["string","null"]},"screenHeight":{"type":["integer","null"],"format":"int32","minimum":0},"screenWidth":{"type":["integer","null"],"format":"int32","minimum":0},"sessionId":{"type":"string"},"timestamp":{"type":["string","null"]},"timezone":{"type":["string","null"]},"url":{"type":["string","null"]},"userAgent":{"type":["string","null"]},"viewportHeight":{"type":["integer","null"],"format":"int32","minimum":0},"viewportWidth":{"type":["integer","null"],"format":"int32","minimum":0}}},"SessionReplayInitResponse":{"type":"object","required":["session_id","message"],"properties":{"message":{"type":"string"},"session_id":{"type":"string"}}},"SessionReplayWithEventsDto":{"type":"object","required":["session","events"],"properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/SessionEventDto"}},"session":{"$ref":"#/components/schemas/SessionReplayWithVisitorDto"}}},"SessionReplayWithVisitorDto":{"type":"object","required":["id","session_replay_id","visitor_id","visitor_uuid","visitor_project_id","visitor_environment_id","visitor_first_seen","visitor_last_seen","visitor_is_crawler"],"properties":{"browser":{"type":["string","null"]},"browser_version":{"type":["string","null"]},"created_at":{"type":["string","null"]},"device_type":{"type":["string","null"]},"duration":{"type":["integer","null"],"format":"int32"},"id":{"type":"integer","format":"int32"},"language":{"type":["string","null"]},"operating_system":{"type":["string","null"]},"operating_system_version":{"type":["string","null"]},"screen_height":{"type":["integer","null"],"format":"int32"},"screen_width":{"type":["integer","null"],"format":"int32"},"session_replay_id":{"type":"string"},"timezone":{"type":["string","null"]},"url":{"type":["string","null"]},"user_agent":{"type":["string","null"]},"viewport_height":{"type":["integer","null"],"format":"int32"},"viewport_width":{"type":["integer","null"],"format":"int32"},"visitor_city":{"type":["string","null"]},"visitor_country":{"type":["string","null"]},"visitor_country_code":{"type":["string","null"]},"visitor_crawler_name":{"type":["string","null"]},"visitor_custom_data":{},"visitor_environment_id":{"type":"integer","format":"int32"},"visitor_first_seen":{"type":"string"},"visitor_id":{"type":"integer","format":"int32"},"visitor_is_crawler":{"type":"boolean"},"visitor_last_seen":{"type":"string"},"visitor_project_id":{"type":"integer","format":"int32"},"visitor_region":{"type":["string","null"]},"visitor_uuid":{"type":"string"}}},"SessionRequestLog":{"type":"object","required":["id","method","path","status_code","created_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"id":{"type":"integer","format":"int32"},"method":{"type":"string"},"path":{"type":"string"},"referrer":{"type":["string","null"]},"request_headers":{"type":["string","null"]},"response_headers":{"type":["string","null"]},"response_time_ms":{"type":["integer","null"],"format":"int32"},"status_code":{"type":"integer","format":"int32"},"user_agent":{"type":["string","null"]}}},"SessionSummary":{"type":"object","required":["session_id","started_at","duration_seconds","page_views","events_count","requests_count","is_bounced","is_engaged"],"properties":{"duration_seconds":{"type":"integer","format":"int64"},"ended_at":{"type":["string","null"],"format":"date-time","example":"2024-01-01T00:00:00"},"entry_path":{"type":["string","null"]},"events_count":{"type":"integer","format":"int64"},"exit_path":{"type":["string","null"]},"is_bounced":{"type":"boolean"},"is_engaged":{"type":"boolean"},"page_views":{"type":"integer","format":"int64"},"referrer":{"type":["string","null"]},"requests_count":{"type":"integer","format":"int64"},"session_id":{"type":"integer","format":"int32"},"started_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"}}},"SetFlagEnvironmentRequest":{"type":"object","properties":{"enabled":{"type":["boolean","null"],"description":"The kill switch. `false` makes the flag serve its default regardless of\nany override — and, once targeting exists, regardless of any rule."},"value":{"description":"Tri-state: absent leaves the override, `null` clears it (inherit the\nflag default), anything else sets it. Must match `value_type`."}}},"SetPreviewPasswordBody":{"type":"object","required":["password"],"properties":{"password":{"type":"string","description":"Plaintext password to protect the sandbox's preview URLs. Hashed\nserver-side with argon2id — we never persist or echo this back.\nMust be between 8 and 256 characters."}}},"SetPreviewPasswordResponse":{"type":"object","required":["preview_password_hint"],"properties":{"preview_password_hint":{"type":"string","description":"Last 4 chars of the password we just stored. Surface in the UI so\nusers can confirm which password is live without re-entering it."}}},"SetRequest":{"type":"object","description":"Request to set a value","required":["key","value"],"properties":{"ex":{"type":["integer","null"],"format":"int64","description":"Expire in seconds","example":3600},"key":{"type":"string","description":"The key to set","example":"user:123"},"nx":{"type":"boolean","description":"Only set if key does not exist"},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1},"px":{"type":["integer","null"],"format":"int64","description":"Expire in milliseconds"},"value":{"description":"The value to store (can be any JSON value)"},"xx":{"type":"boolean","description":"Only set if key exists"}}},"SetResponse":{"type":"object","description":"Response for set operation","required":["result"],"properties":{"result":{"type":"string","description":"Always \"OK\" on success","example":"OK"}}},"SettingsUpdateResponse":{"type":"object","description":"Response for successful settings update","required":["message"],"properties":{"message":{"type":"string"}}},"SetupDnsChallengeRequest":{"type":"object","description":"Request to setup DNS challenge records using a configured DNS provider","required":["dns_provider_id"],"properties":{"dns_provider_id":{"type":"integer","format":"int32","description":"The ID of the DNS provider to use for creating the TXT records"}}},"SetupDnsChallengeResponse":{"type":"object","description":"Response from DNS challenge setup operation","required":["success","records_created","total_records","results","message"],"properties":{"message":{"type":"string","description":"Human-readable summary message"},"records_created":{"type":"integer","format":"int32","description":"Number of TXT records that were successfully created","minimum":0},"results":{"type":"array","items":{"$ref":"#/components/schemas/DnsChallengeRecordResult"},"description":"Results for each individual TXT record"},"success":{"type":"boolean","description":"Overall success status (true if all records were created)"},"total_records":{"type":"integer","format":"int32","description":"Total number of TXT records required for the challenge","minimum":0}}},"SetupDnsRequest":{"type":"object","description":"Request to setup DNS records using a configured DNS provider","required":["dns_provider_id"],"properties":{"dns_provider_id":{"type":"integer","format":"int32","description":"The ID of the DNS provider to use for creating records"}}},"SetupDnsResponse":{"type":"object","description":"Response from DNS setup operation","required":["success","records_created","total_records","results","message"],"properties":{"message":{"type":"string","description":"Human-readable summary message"},"records_created":{"type":"integer","format":"int32","description":"Number of records that were successfully created","minimum":0},"results":{"type":"array","items":{"$ref":"#/components/schemas/DnsRecordSetupResult"},"description":"Results for each individual record"},"success":{"type":"boolean","description":"Overall success status"},"total_records":{"type":"integer","format":"int32","description":"Total number of records attempted","minimum":0}}},"SiblingRef":{"type":"object","description":"A sibling project that shares the same `trace_id` and has opted in to\ncross-project trace sharing (`cross_project_trace_sharing = TRUE`).\n\nReturned by `CrossProjectTraceService::find_sibling_projects` and exposed\nby the Phase 1 `GET /otel/traces/cross-project/{trace_id}` endpoint.","required":["project_id","project_name","project_slug","first_seen"],"properties":{"first_seen":{"type":"string","format":"date-time"},"project_id":{"type":"integer","format":"int32"},"project_name":{"type":"string"},"project_slug":{"type":"string","description":"URL slug used to link into the sibling project's single-project trace view."}}},"SkillDefinitionResponse":{"type":"object","required":["id","slug","name","content","has_archive","created_at","updated_at"],"properties":{"content":{"type":"string"},"created_at":{"type":"string"},"description":{"type":["string","null"]},"has_archive":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"project_id":{"type":["integer","null"],"format":"int32"},"slug":{"type":"string"},"updated_at":{"type":"string"}}},"SlackConfig":{"type":"object","required":["webhook_url"],"properties":{"channel":{"type":["string","null"]},"webhook_url":{"type":"string"}}},"SlowQueriesResponse":{"type":"object","description":"Response envelope for the slow-queries list endpoint.","required":["queries","page","page_size","total_count"],"properties":{"page":{"type":"integer","format":"int32","description":"Current page number (1-based).","minimum":0},"page_size":{"type":"integer","format":"int32","description":"Number of rows per page used for this request.","minimum":0},"queries":{"type":"array","items":{"$ref":"#/components/schemas/SlowQueryRow"},"description":"Ordered list of query stats, slowest first by mean_exec_time_ms."},"total_count":{"type":"integer","format":"int64","description":"Total number of qualifying rows across all pages.","minimum":0}}},"SlowQueryRow":{"type":"object","description":"A single entry from `pg_stat_statements`, representing one normalized\nquery fingerprint and its aggregate execution stats.","required":["query","database","calls","total_exec_time_ms","mean_exec_time_ms","rows"],"properties":{"cache_hit_ratio":{"type":["number","null"],"format":"double","description":"Shared block cache hit ratio (0.0–1.0).\n`None` when total block accesses are zero (e.g. function-only queries)."},"calls":{"type":"integer","format":"int64","description":"Number of times this query was executed."},"database":{"type":"string","description":"Name of the database this query ran against. `(dropped database)`\nwhen the originating database no longer exists but\n`pg_stat_statements` still holds stats for it."},"mean_exec_time_ms":{"type":"number","format":"double","description":"Average wall-clock time per execution, in milliseconds."},"query":{"type":"string","description":"Normalized query text (parameter literals replaced with `$N`)."},"rows":{"type":"integer","format":"int64","description":"Total number of rows returned or affected."},"total_exec_time_ms":{"type":"number","format":"double","description":"Total wall-clock time spent executing this query, in milliseconds."}}},"SmartFilter":{"oneOf":[{"type":"object","description":"Match specific page path","required":["value","type"],"properties":{"type":{"type":"string","enum":["page_path"]},"value":{"type":"string","description":"Match specific page path"}}},{"type":"object","description":"Match specific hostname","required":["value","type"],"properties":{"type":{"type":"string","enum":["hostname"]},"value":{"type":"string","description":"Match specific hostname"}}},{"type":"object","description":"Match UTM source","required":["value","type"],"properties":{"type":{"type":"string","enum":["utm_source"]},"value":{"type":"string","description":"Match UTM source"}}},{"type":"object","description":"Match UTM campaign","required":["value","type"],"properties":{"type":{"type":"string","enum":["utm_campaign"]},"value":{"type":"string","description":"Match UTM campaign"}}},{"type":"object","description":"Match UTM medium","required":["value","type"],"properties":{"type":{"type":"string","enum":["utm_medium"]},"value":{"type":"string","description":"Match UTM medium"}}},{"type":"object","description":"Match referrer hostname","required":["value","type"],"properties":{"type":{"type":"string","enum":["referrer_hostname"]},"value":{"type":"string","description":"Match referrer hostname"}}},{"type":"object","description":"Match specific channel (organic, paid, direct, referral, etc.)","required":["value","type"],"properties":{"type":{"type":"string","enum":["channel"]},"value":{"type":"string","description":"Match specific channel (organic, paid, direct, referral, etc.)"}}},{"type":"object","description":"Match device type (mobile, desktop, tablet)","required":["value","type"],"properties":{"type":{"type":"string","enum":["device_type"]},"value":{"type":"string","description":"Match device type (mobile, desktop, tablet)"}}},{"type":"object","description":"Match browser","required":["value","type"],"properties":{"type":{"type":"string","enum":["browser"]},"value":{"type":"string","description":"Match browser"}}},{"type":"object","description":"Match operating system","required":["value","type"],"properties":{"type":{"type":"string","enum":["operating_system"]},"value":{"type":"string","description":"Match operating system"}}},{"type":"object","description":"Match language","required":["value","type"],"properties":{"type":{"type":"string","enum":["language"]},"value":{"type":"string","description":"Match language"}}},{"type":"object","description":"Match custom event_data by JSON path\nFormat: {\"path\": \"user.plan\", \"value\": \"premium\"}\nThis will match events where event_data->'user'->>'plan' = 'premium'","required":["value","type"],"properties":{"type":{"type":"string","enum":["custom_data"]},"value":{"type":"object","description":"Match custom event_data by JSON path\nFormat: {\"path\": \"user.plan\", \"value\": \"premium\"}\nThis will match events where event_data->'user'->>'plan' = 'premium'","required":["path","value"],"properties":{"path":{"type":"string"},"value":{"type":"string"}}}}}],"description":"Smart filter presets for common funnel patterns"},"SmokeTestResponse":{"type":"object","required":["passed","environment","cli_installed","cli_authenticated"],"properties":{"auth_info":{"type":["string","null"],"description":"Auth email / method"},"cli_authenticated":{"type":"boolean","description":"Claude CLI authenticated?"},"cli_installed":{"type":"boolean","description":"Claude CLI installed?"},"cli_version":{"type":["string","null"],"description":"Claude CLI version"},"detail":{"type":["string","null"],"description":"Full output for debugging"},"environment":{"type":"string","description":"Where the test ran: \"host\" or \"sandbox\""},"passed":{"type":"boolean","description":"Whether the smoke test passed"},"setup_hint":{"type":["string","null"],"description":"What the user needs to do if the test failed"}}},"SmtpCredentialsRequest":{"type":"object","description":"Generic SMTP credentials request body.\n\nWorks with any SMTP relay — AWS SES SMTP endpoints, Sendgrid, Mailgun,\nPostmark, or a self-hosted Postfix. Use this when you only have SMTP\ncredentials (i.e. you cannot create identities via the upstream API).","required":["host","port"],"properties":{"accept_invalid_certs":{"type":"boolean","description":"Accept self-signed certificates. Only safe for local testing."},"encryption":{"$ref":"#/components/schemas/SmtpEncryptionRoute","description":"TLS mode. Defaults to STARTTLS."},"host":{"type":"string","description":"SMTP host, e.g. `email-smtp.eu-west-1.amazonaws.com`.","example":"email-smtp.eu-west-1.amazonaws.com"},"password":{"type":["string","null"],"description":"SMTP password / API token. Required when `username` is set."},"port":{"type":"integer","format":"int32","description":"SMTP port (587 for STARTTLS, 465 for implicit TLS, 25/1025 for plain).","example":587,"minimum":0},"username":{"type":["string","null"],"description":"SMTP username. Leave empty for unauthenticated relays.","example":"AKIAIOSFODNN7EXAMPLE"}}},"SmtpEncryptionRoute":{"type":"string","description":"TLS mode for the SMTP relay.","enum":["starttls","tls","none"]},"SmtpResult":{"type":"object","description":"SMTP validation result","required":["can_connect_smtp","has_full_inbox","is_catch_all","is_deliverable","is_disabled"],"properties":{"can_connect_smtp":{"type":"boolean","description":"Whether we could connect to the SMTP server"},"error":{"type":["string","null"],"description":"Error message if SMTP check failed"},"has_full_inbox":{"type":"boolean","description":"Whether the mailbox appears to have a full inbox"},"is_catch_all":{"type":"boolean","description":"Whether this is a catch-all domain"},"is_deliverable":{"type":"boolean","description":"Whether the email is deliverable"},"is_disabled":{"type":"boolean","description":"Whether the mailbox is disabled"}}},"SourceArchiveUpload":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary"}}},"SourceBackupEntry":{"type":"object","description":"Entry in the source backup index. Covers both DB-tracked backups\n(have a row in `backups`) and S3-scan discoveries (raw S3 objects with\nno DB row — used for disaster-recovery from another Temps instance).","required":["id","backup_id","name","backup_type","created_at","location","metadata_location","source","state"],"properties":{"backup_id":{"type":"string","description":"UUID identifier from the DB row. Empty for S3-scan entries.","example":"550e8400-e29b-41d4-a716-446655440000"},"backup_type":{"type":"string","description":"Backup variant as recorded by the backup pipeline (e.g. \"full\").","example":"full"},"created_at":{"type":"string","description":"When the backup was created. For S3-scan entries this is the\nobject's LastModified time.","example":"2024-01-15T14:30:00.123Z"},"engine":{"type":["string","null"],"description":"Engine that produced the backup (\"postgres\", \"redis\", \"mongodb\",\n\"s3\", \"rustfs\"). Used by the UI to mark engine-compat with the\ntarget service.","example":"postgres"},"format":{"type":["string","null"],"description":"Storage format: \"walg\" for continuous-archive (PITR-capable),\n\"pg_dump\" for point-in-time dumps, \"\" for non-postgres.","example":"walg"},"id":{"type":"integer","format":"int32","description":"DB row id. Zero for S3-scan entries that have no DB row.","example":1},"location":{"type":"string","description":"Raw S3 URL / key where the backup sits. For Postgres WAL-G backups\nthis starts with `s3://`; for pg_dump-style backups it's the\nrelative object key.","example":"s3://bucket/external_services/postgres/svc-name/walg"},"metadata_location":{"type":"string","description":"Sidecar metadata.json location, if any. Empty when none.","example":""},"name":{"type":"string","description":"Human-friendly display name (\"postgres backup (svc-name)\" for DB\nrows, or a synthesized label derived from the S3 path for scans).","example":"postgres backup (postgres-n4ea)"},"origin_service_name":{"type":["string","null"],"description":"Name of the service that produced the backup. For S3-scan entries\nthis is parsed from the S3 path.","example":"postgres-n4ea"},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Size of the backup in bytes, if known.","example":1024000},"source":{"type":"string","description":"Provenance: \"db\" for rows in this Temps, \"s3_scan\" for objects\ndiscovered by the S3 bucket walk (e.g., backups made by another\nTemps instance).","example":"db"},"state":{"type":"string","description":"Observed state (\"completed\", \"running\", \"failed\") — DB only.\nEmpty string for S3-scan entries.","example":"completed"}}},"SourceBackupIndexResponse":{"type":"object","description":"Response type for source backup index","required":["backups","last_updated"],"properties":{"backups":{"type":"array","items":{"$ref":"#/components/schemas/SourceBackupEntry"},"description":"List of backups in the source"},"last_updated":{"type":"string","description":"When the index was last updated","example":"2024-01-15T14:30:00.123Z"}}},"SourceBody":{"oneOf":[{"type":"object","required":["url","type"],"properties":{"depth":{"type":["integer","null"],"format":"int32","minimum":0},"git_connection_id":{"type":["integer","null"],"format":"int32"},"password":{"type":["string","null"]},"revision":{"type":["string","null"]},"type":{"type":"string","enum":["git"]},"url":{"type":"string"},"username":{"type":["string","null"]}}},{"type":"object","required":["url","type"],"properties":{"type":{"type":"string","enum":["tarball"]},"url":{"type":"string"}}}],"description":"Initial content to seed into the sandbox work dir. Mirrors the\n`@vercel/sandbox` `source` option. `type` is one of:\n- `git` — clone `url`; optionally check out `revision`\n- `tarball` — download `url` (must be tar or tar.gz) and extract\n\nFor private git repos, pass credentials one of two ways:\n1. **Inline (SDK-compatible):** `username` + `password`. GitHub\n tokens use `username: \"x-access-token\"`.\n2. **Stored connection (temps-native):** `git_connection_id`\n references a row in the caller's git provider connections. Temps\n resolves the token server-side and injects it safely.\n\n`git_connection_id` is mutually exclusive with `username`/`password`."},"SourceFileListResponse":{"type":"object","required":["source_files","total"],"properties":{"source_files":{"type":"array","items":{"$ref":"#/components/schemas/SourceFileResponse"}},"total":{"type":"integer","minimum":0}}},"SourceFileResponse":{"type":"object","required":["id","project_id","release","file_path","size_bytes","created_at"],"properties":{"checksum":{"type":["string","null"]},"created_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"file_path":{"type":"string"},"id":{"type":"integer","format":"int32"},"project_id":{"type":"integer","format":"int32"},"release":{"type":"string"},"size_bytes":{"type":"integer","format":"int64"}}},"SourceMapListResponse":{"type":"object","required":["source_maps","total"],"properties":{"source_maps":{"type":"array","items":{"$ref":"#/components/schemas/SourceMapResponse"}},"total":{"type":"integer","minimum":0}}},"SourceMapResponse":{"type":"object","required":["id","project_id","release","file_path","size_bytes","created_at"],"properties":{"checksum":{"type":["string","null"]},"created_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"dist":{"type":["string","null"]},"file_path":{"type":"string"},"id":{"type":"integer","format":"int32"},"project_id":{"type":"integer","format":"int32"},"release":{"type":"string"},"size_bytes":{"type":"integer","format":"int64"}}},"SourceType":{"type":"string","description":"Source type for project deployments\n\nDetermines where the deployment artifacts come from:\n- `Git`: Source code from a Git repository (traditional flow)\n- `DockerImage`: Pre-built Docker image from external registry\n- `StaticFiles`: Pre-built static files uploaded as a bundle\n- `UploadedSource`: Source archive uploaded without a Git repository\n- `Manual`: Flexible type that accepts any deployment method","enum":["git","docker_image","static_files","uploaded_source","manual"]},"SpanEvent":{"type":"object","description":"A span event (log-like annotation on a span).","required":["timestamp","name","attributes"],"properties":{"attributes":{"type":"object","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"name":{"type":"string"},"timestamp":{"type":"string","format":"date-time"}}},"SpanKind":{"type":"string","description":"Span kind.","enum":["UNSPECIFIED","INTERNAL","SERVER","CLIENT","PRODUCER","CONSUMER"]},"SpanRecord":{"type":"object","description":"A single trace span ready for storage.","required":["project_id","resource","trace_id","span_id","name","kind","start_time","end_time","duration_ms","status_code","status_message","attributes","events"],"properties":{"attributes":{"type":"object","description":"Raw key/value pairs exactly as reported by the instrumenting library.\nNumeric values are NOT guaranteed to share `duration_ms`'s unit — they\nmay be seconds, milliseconds, microseconds, or nanoseconds depending on\nthe exporter's own convention, and the unit is not labeled here.","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"deployment_id":{"type":["integer","null"],"format":"int32"},"duration_ms":{"type":"number","format":"double","description":"Span duration in milliseconds. The only field on this struct guaranteed\nto be in milliseconds."},"end_time":{"type":"string","format":"date-time"},"events":{"type":"array","items":{"$ref":"#/components/schemas/SpanEvent"}},"kind":{"$ref":"#/components/schemas/SpanKind"},"name":{"type":"string"},"parent_span_id":{"type":["string","null"]},"project_id":{"type":"integer","format":"int32"},"resource":{"$ref":"#/components/schemas/ResourceInfo"},"span_id":{"type":"string"},"start_time":{"type":"string","format":"date-time"},"status_code":{"$ref":"#/components/schemas/SpanStatusCode"},"status_message":{"type":"string"},"trace_id":{"type":"string"}}},"SpanRow":{"type":"object","required":["id","ts","trace_id","span_id","service","operation","attributes","attributes_truncated"],"properties":{"attributes":{},"attributes_truncated":{"type":"boolean"},"deployment_id":{"type":["integer","null"],"format":"int32"},"duration_ms":{"type":["number","null"],"format":"double"},"environment_id":{"type":["integer","null"],"format":"int32"},"id":{"type":"string"},"operation":{"type":"string"},"parent_span_id":{"type":["string","null"]},"service":{"type":"string"},"span_id":{"type":"string"},"status":{"type":["string","null"]},"trace_id":{"type":"string"},"ts":{"type":"string","format":"date-time"}}},"SpanStatusCode":{"type":"string","description":"Span status code.","enum":["UNSET","OK","ERROR"]},"SpeedMetricsPayload":{"type":"object","description":"Speed metrics payload for recording web vitals","properties":{"cls":{"type":["number","null"],"format":"float","description":"Cumulative Layout Shift (score)"},"fcp":{"type":["number","null"],"format":"float","description":"First Contentful Paint (milliseconds)"},"fid":{"type":["number","null"],"format":"float","description":"First Input Delay (milliseconds)"},"inp":{"type":["number","null"],"format":"float","description":"Interaction to Next Paint (milliseconds)"},"language":{"type":["string","null"],"description":"Browser language"},"lcp":{"type":["number","null"],"format":"float","description":"Largest Contentful Paint (milliseconds)"},"pathname":{"type":["string","null"],"description":"Page pathname"},"query":{"type":["string","null"],"description":"Query string"},"screenHeight":{"type":["integer","null"],"format":"int32","description":"Screen height in pixels"},"screenWidth":{"type":["integer","null"],"format":"int32","description":"Screen width in pixels"},"ttfb":{"type":["number","null"],"format":"float","description":"Time to First Byte (milliseconds)"},"viewportHeight":{"type":["integer","null"],"format":"int32","description":"Viewport height in pixels"},"viewportWidth":{"type":["integer","null"],"format":"int32","description":"Viewport width in pixels"}}},"SpeedSegmentFilters":{"type":"object","description":"Optional segment filters for the performance read endpoints, mirroring\nanalytics' `VisitorSegmentFilters`. Each filter narrows results to samples\nmatching the dimension value, so metrics can be scoped to e.g. one page,\none browser, or one country. Geographic filters resolve via\n`ip_geolocations`; the rest live directly on `performance_metrics`.","properties":{"filter_browser":{"type":["string","null"],"description":"Browser name (matches `performance_metrics.browser`)"},"filter_city":{"type":["string","null"],"description":"Geolocation city (matches `ip_geolocations.city`)"},"filter_country":{"type":["string","null"],"description":"Geolocation country (matches `ip_geolocations.country`)"},"filter_operating_system":{"type":["string","null"],"description":"Operating system (matches `performance_metrics.operating_system`)"},"filter_path":{"type":["string","null"],"description":"Page pathname (matches `performance_metrics.pathname`)"},"filter_region":{"type":["string","null"],"description":"Geolocation region (matches `ip_geolocations.region`)"}}},"StaleSlot":{"type":"object","required":["slot_name","active","retained_bytes"],"properties":{"active":{"type":"boolean"},"retained_bytes":{"type":"integer","format":"int64"},"slot_name":{"type":"string"}}},"StartAnalysisRequest":{"type":"object","required":["error_group_id"],"properties":{"branch":{"type":["string","null"],"description":"Branch to clone instead of the project's main branch."},"error_group_id":{"type":"integer","format":"int32"},"max_turns":{"type":["integer","null"],"format":"int32","description":"Per-run turn cap applied to every phase (1–200). Only enforced for\nCLIs with a turn flag (Claude Code). `None` uses the provider's\nconfigured defaults."},"model":{"type":["string","null"],"description":"Model id for the chosen provider. `None` uses the provider's saved\ndefault model."},"provider":{"type":["string","null"],"description":"AI provider id (\"claude_cli\", \"codex_cli\", \"opencode\"). `None` uses\nthe platform default provider."},"user_context":{"type":["string","null"],"description":"Free-text notes for the model (extra context about the error, retry\nguidance, constraints). Included verbatim in the analysis prompt."}}},"StartPgUpgradeRequest":{"type":"object","required":["from_version","to_version","from_image","to_image"],"properties":{"from_image":{"type":"string","example":"postgres:16-bookworm"},"from_version":{"type":"string","example":"16"},"to_image":{"type":"string","example":"postgres:17-bookworm"},"to_version":{"type":"string","example":"17"}}},"StartRestoreRequest":{"allOf":[{"$ref":"#/components/schemas/RestoreRequestMode","description":"Requested restore mode. See `RestoreRequestMode`."},{"type":"object","properties":{"backup_engine":{"type":["string","null"],"description":"Engine of the backup when specified by `backup_location`\n(\"postgres\", \"redis\", \"mongodb\", \"s3\"). Ignored when `backup_id`\nis used — we infer from the DB row."},"backup_id":{"type":["integer","null"],"format":"int32","description":"DB id of the backup to restore from. Either `backup_id` or\n`backup_location` MUST be provided. Use `backup_id` when restoring\na backup this Temps instance recorded."},"backup_location":{"type":["string","null"],"description":"Raw S3 URL / key of the backup — used when restoring a backup\ndiscovered by S3 scan (i.e., produced by another Temps instance).\nRequires `backup_engine` and `s3_source_id` to also be set."},"s3_source_id":{"type":["integer","null"],"format":"int32","description":"S3 source the `backup_location` lives in. Ignored when `backup_id`\nis used."}}}]},"StartUpdateRequest":{"type":"object","description":"Optional pin for the version to install.","properties":{"version":{"type":["string","null"],"description":"Release tag to install (e.g. `v0.2.0`). Omit to take the newest release\non the channel this install already tracks."}}},"StartUpdateResponse":{"type":"object","description":"Acknowledgement that an update was accepted and is running.","required":["current_version","estimated_restart_secs","message"],"properties":{"current_version":{"type":"string","description":"Version the server is running as it accepts this request."},"estimated_restart_secs":{"type":"integer","format":"int64","description":"How long to allow for the server to come back before treating the\nrestart as failed.","minimum":0},"message":{"type":"string"}}},"StatResponse":{"type":"object","required":["path","exists","is_dir","is_file","size"],"properties":{"exists":{"type":"boolean"},"is_dir":{"type":"boolean"},"is_file":{"type":"boolean"},"path":{"type":"string"},"size":{"type":"integer","format":"int64","minimum":0}}},"StaticBundleResponse":{"type":"object","required":["id","project_id","blob_path","content_type","size_bytes","uploaded_at","created_at"],"properties":{"blob_path":{"type":"string"},"checksum":{"type":["string","null"]},"content_type":{"type":"string"},"created_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"format":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"metadata":{},"original_filename":{"type":["string","null"]},"project_id":{"type":"integer","format":"int32"},"size_bytes":{"type":"integer","format":"int64"},"uploaded_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"}}},"StaticParams":{"type":"object","description":"Static threshold detector: compare the aggregated `value` against `threshold`.","required":["comparator","threshold"],"properties":{"comparator":{"$ref":"#/components/schemas/Comparator","description":"How `value` is compared against `threshold`."},"threshold":{"type":"number","format":"double","description":"The threshold the aggregated value is compared against."}}},"StaticPresetConfig":{"type":"object","description":"Configuration for static site presets (Vite, Next.js, Docusaurus, etc.)\nThese presets build static sites that are served via a web server","properties":{"buildCommand":{"type":["string","null"],"description":"Custom build command (overrides preset default)","example":"npm run build:production"},"buildContext":{"type":["string","null"],"description":"Custom build context path (relative to repository root)\nUseful for monorepo setups where the app is in a subdirectory","example":"./apps/frontend"},"installCommand":{"type":["string","null"],"description":"Custom install command (overrides auto-detected package manager)","example":"npm ci"},"outputDir":{"type":["string","null"],"description":"Custom output directory (overrides preset default)\nCommon values: \"dist\", \"build\", \".next\", \"out\"","example":"dist"}}},"StatsFilters":{"type":"object","description":"Filters for statistics queries","properties":{"client_ip":{"type":["string","null"]},"deployment_id":{"type":["integer","null"],"format":"int32"},"device_type":{"type":["string","null"]},"environment_id":{"type":["integer","null"],"format":"int32"},"has_project":{"type":["boolean","null"],"description":"When true, only count requests that matched a project (project_id IS NOT NULL).\nUsed by the health dashboard so totals match the per-project cards."},"host":{"type":["string","null"]},"is_bot":{"type":["boolean","null"]},"method":{"type":["string","null"]},"project_id":{"type":["integer","null"],"format":"int32"},"request_source":{"type":["string","null"]},"routing_status":{"type":["string","null"]},"status_code":{"type":["integer","null"],"format":"int32"},"status_code_class":{"type":["string","null"],"description":"Filter by status code class (e.g. \"2xx\", \"3xx\", \"4xx\", \"5xx\")"}}},"StatusBucket":{"type":"object","required":["bucket_start","status","total_checks","operational_count","degraded_count","down_count","uptime_percentage"],"properties":{"avg_response_time_ms":{"type":["number","null"],"format":"double"},"bucket_start":{"type":"string","format":"date-time"},"degraded_count":{"type":"integer","format":"int64"},"down_count":{"type":"integer","format":"int64"},"max_response_time_ms":{"type":["number","null"],"format":"double"},"min_response_time_ms":{"type":["number","null"],"format":"double"},"operational_count":{"type":"integer","format":"int64"},"p50_response_time_ms":{"type":["number","null"],"format":"double"},"p95_response_time_ms":{"type":["number","null"],"format":"double"},"p99_response_time_ms":{"type":["number","null"],"format":"double"},"status":{"type":"string"},"total_checks":{"type":"integer","format":"int64"},"uptime_percentage":{"type":"number","format":"double"}}},"StatusBucketedResponse":{"type":"object","required":["monitor_id","interval","buckets"],"properties":{"buckets":{"type":"array","items":{"$ref":"#/components/schemas/StatusBucket"}},"interval":{"type":"string"},"monitor_id":{"type":"integer","format":"int32"}}},"StatusCodeCount":{"type":"object","required":["status_code","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"percentage":{"type":"number","format":"double"},"status_code":{"type":"integer","format":"int32"}}},"StatusCodesQuery":{"type":"object","required":["start_date","end_date","project_id"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"StatusPageOverview":{"type":"object","required":["status","monitors","recent_incidents"],"properties":{"monitors":{"type":"array","items":{"$ref":"#/components/schemas/MonitorStatus"}},"recent_incidents":{"type":"array","items":{"$ref":"#/components/schemas/IncidentResponse"}},"status":{"type":"string"}}},"StepConversionResponse":{"type":"object","required":["step_id","step_name","step_order","completions","conversion_rate","drop_off_rate","average_time_to_complete_seconds"],"properties":{"average_time_to_complete_seconds":{"type":"number","format":"double"},"completions":{"type":"integer","format":"int64","minimum":0},"conversion_rate":{"type":"number","format":"double"},"drop_off_rate":{"type":"number","format":"double"},"step_id":{"type":"integer","format":"int32"},"step_name":{"type":"string"},"step_order":{"type":"integer","format":"int32"}}},"StepResourceType":{"type":"string","description":"What kind of resource a migration step operates on","enum":["project","environment","deployment","environment-variable","service","domain","git-link","other"]},"StepResult":{"type":"object","description":"Result of executing a single migration step","required":["step_id","step_title","success","skipped","message","created_resources","duration_seconds"],"properties":{"created_resources":{"type":"array","items":{"$ref":"#/components/schemas/CreatedResource"},"description":"Resources created by this step"},"duration_seconds":{"type":"number","format":"double","description":"Duration of this step"},"message":{"type":"string","description":"Human-readable message about what happened"},"skipped":{"type":"boolean","description":"Whether this step was skipped"},"step_id":{"type":"string","description":"Step ID (matches `MigrationStep.id`)"},"step_title":{"type":"string","description":"Step title (for display)"},"success":{"type":"boolean","description":"Whether this step succeeded"}}},"StepUpResponse":{"type":"object","required":["expires_at"],"properties":{"expires_at":{"type":"string","format":"date-time","description":"ISO 8601 timestamp after which sensitive actions require verification\nagain."}}},"StopSequence":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]},"StorageQuota":{"type":"object","description":"Quota usage information for a project.","required":["project_id","metrics_bytes","traces_bytes","logs_bytes","total_bytes","limit_bytes","usage_pct"],"properties":{"limit_bytes":{"type":"integer","format":"int64","minimum":0},"logs_bytes":{"type":"integer","format":"int64","minimum":0},"metrics_bytes":{"type":"integer","format":"int64","minimum":0},"project_id":{"type":"integer","format":"int32"},"total_bytes":{"type":"integer","format":"int64","minimum":0},"traces_bytes":{"type":"integer","format":"int64","minimum":0},"usage_pct":{"type":"number","format":"double"}}},"StripeConfig":{"type":"object","properties":{"include_unpriced_charges":{"type":"boolean","description":"When an allowlist is set, should we still ingest charges that\nlack a price reference (e.g. standalone `charge.succeeded` without\na subscription)? Default true — charges don't belong to a SKU."},"metered_mode":{"$ref":"#/components/schemas/MeteredMode","description":"How to compute MRR for metered / tiered / hybrid subscriptions."},"price_allowlist":{"type":"array","items":{"type":"string"},"description":"Only events tagged with one of these Stripe price IDs are ingested.\nEmpty = accept all prices."},"product_allowlist":{"type":"array","items":{"type":"string"},"description":"Only events tagged with one of these Stripe product IDs are\ningested. Empty = accept all products. Combined with\n`price_allowlist` via OR — if either list has a match, accept."}}},"SupervisorKind":{"type":"string","description":"What (if anything) will restart the process after it exits.","enum":["systemd","launchd","container","none"]},"SyncedRepositoryListQuery":{"type":"object","properties":{"direction":{"type":["string","null"]},"git_provider_connection_id":{"type":["integer","null"],"format":"int32"},"language":{"type":["string","null"]},"owner":{"type":["string","null"]},"page":{"type":["integer","null"],"format":"int64","minimum":0},"per_page":{"type":["integer","null"],"format":"int64","minimum":0},"private":{"type":["boolean","null"]},"search":{"type":["string","null"]},"sort":{"type":["string","null"]}}},"SyntaxResult":{"type":"object","description":"Syntax validation result","required":["is_valid_syntax"],"properties":{"domain":{"type":["string","null"],"description":"The domain part of the email","example":"gmail.com"},"is_valid_syntax":{"type":"boolean","description":"Whether the email syntax is valid"},"suggestion":{"type":["string","null"],"description":"Suggested email correction if available"},"username":{"type":["string","null"],"description":"The username part of the email","example":"someone"}}},"TagInfo":{"type":"object","required":["name","commit_sha"],"properties":{"commit_sha":{"type":"string"},"name":{"type":"string"}}},"TagListResponse":{"type":"object","required":["tags"],"properties":{"tags":{"type":"array","items":{"$ref":"#/components/schemas/TagInfo"}}}},"TailLogsRequest":{"type":"object","required":["project_id","service","env"],"properties":{"env":{"type":"string"},"external_service_id":{"type":["integer","null"],"format":"int32","description":"When set, tail an imported/managed external service's logs instead of\na project's (`project_id` is ignored in this mode)."},"levels":{"type":"array","items":{"type":"string"}},"project_id":{"type":"integer","format":"int32","description":"Project ID (integer, as used by the rest of the platform)"},"service":{"type":"string"},"text":{"type":["string","null"]}}},"TargetRecommendation":{"type":"object","description":"The temps/Hetzner target sizing and savings estimate","required":["server_type","vcpus","memory_gb","monthly_eur","fits_single_node","sizing_basis","rationale"],"properties":{"fits_single_node":{"type":"boolean","description":"Whether the workloads fit a single recommended server. When `false`,\nthe rationale explains the multi-node option (temps worker nodes)."},"memory_gb":{"type":"integer","format":"int32","description":"Memory (GB) of the recommended server"},"monthly_eur":{"type":"number","format":"double","description":"Estimated monthly price of the recommended server in EUR"},"monthly_savings_usd":{"type":["number","null"],"format":"double","description":"Estimated monthly savings in USD (current cost minus target cost,\ntreating EUR≈USD for the rough comparison — disclaimed in `notes`).\n`None` when the current cost is unknown."},"rationale":{"type":"string","description":"Human-readable recommendation summary"},"server_type":{"type":"string","description":"Recommended Hetzner server type (e.g. \"cpx32\")"},"sizing_basis":{"type":"string","description":"What the sizing was based on, e.g. \"2× measured usage + temps\nplatform overhead\" or \"resource requests (no metrics available)\""},"vcpus":{"type":"integer","format":"int32","description":"vCPUs of the recommended server"},"yearly_savings_usd":{"type":["number","null"],"format":"double","description":"`monthly_savings_usd × 12`"}}},"TeamListResponse":{"type":"object","required":["teams","total","page","page_size"],"properties":{"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"teams":{"type":"array","items":{"$ref":"#/components/schemas/TeamResponse"}},"total":{"type":"integer","format":"int64","minimum":0}}},"TeamMemberResponse":{"type":"object","required":["id","team_id","user_id","role","added_by","created_at","updated_at"],"properties":{"added_by":{"type":"integer","format":"int32"},"created_at":{"type":"string","format":"date-time","example":"2026-07-30T12:15:47.609192Z"},"id":{"type":"integer","format":"int32"},"role":{"$ref":"#/components/schemas/TeamRole","description":"The source of this member's project-scoped permissions, intersected\nwith `project_team_access.role`."},"team_id":{"type":"integer","format":"int32"},"updated_at":{"type":"string","format":"date-time","example":"2026-07-30T12:15:47.609192Z"},"user_email":{"type":["string","null"],"description":"The member's email, joined from `users`."},"user_id":{"type":"integer","format":"int32"},"user_name":{"type":["string","null"],"description":"The member's display name, joined from `users`. `None` if the\nreferenced user no longer exists."}}},"TeamResponse":{"type":"object","required":["id","name","slug","created_by","created_at","updated_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2026-07-30T12:15:47.609192Z"},"created_by":{"type":"integer","format":"int32"},"description":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"slug":{"type":"string"},"updated_at":{"type":"string","format":"date-time","example":"2026-07-30T12:15:47.609192Z"}}},"TeamRole":{"type":"string","description":"Role a user holds within a team, or that a team holds on a project.\n\nNamed `TeamRole` rather than `Role` to keep it distinct from\n`temps_auth::permissions::Role`, which is the instance-wide role\n(Admin/User/…) attached to a session. The two are orthogonal: the\ninstance-wide role decides whether you may touch a resource *kind* at\nall, `TeamRole` decides what you may do *within a project* you have\nteam access to. See `temps_teams::fixed_role_permissions` for the\nproject-scoped permission set each variant maps to.\n\nStored as a `varchar(32)` rather than a Postgres enum so the role set\ncan evolve in pure migration code without a schema-level enum\nalteration blocking a downgrade.","enum":["owner","admin","deployer","viewer"]},"TemplateResponse":{"type":"object","description":"Response type for a single template","required":["slug","name","git","preset","tags","features","services","env_vars","is_featured"],"properties":{"description":{"type":["string","null"],"description":"Short description"},"env_vars":{"type":"array","items":{"$ref":"#/components/schemas/EnvVarTemplateResponse"},"description":"Environment variables template"},"exposed_port":{"type":["integer","null"],"format":"int32","description":"Container port the prebuilt image listens on (image deploys only)."},"features":{"type":"array","items":{"type":"string"},"description":"Feature highlights"},"git":{"$ref":"#/components/schemas/GitRefResponse","description":"Git repository reference"},"health_check_path":{"type":["string","null"],"description":"HTTP health-check path probed after the container starts (image deploys)."},"image":{"type":["string","null"],"description":"Prebuilt Docker image reference. When set, the one-click deploy pulls and\nruns this image directly (no build); when absent it builds from `git`."},"image_url":{"type":["string","null"],"description":"URL to template image/icon"},"is_featured":{"type":"boolean","description":"Whether the template is featured/promoted"},"name":{"type":"string","description":"Display name"},"preset":{"type":"string","description":"Framework/preset to use"},"screenshot_url":{"type":["string","null"],"description":"URL to a wide screenshot/banner preview of the deployed template.\nAbsent for templates that don't have one captured yet."},"services":{"type":"array","items":{"type":"string"},"description":"Required external services"},"slug":{"type":"string","description":"Unique identifier for the template (used in URLs)"},"tags":{"type":"array","items":{"type":"string"},"description":"Tags/categories for filtering"}}},"TestEmailRequest":{"type":"object","description":"Request body for testing an email provider","required":["from"],"properties":{"from":{"type":"string","description":"Sender email address (must be verified with the provider)","example":"test@example.com"},"from_name":{"type":["string","null"],"description":"Sender display name","example":"My App"}}},"TestEmailResponse":{"type":"object","description":"Response for test email endpoint","required":["success","sent_to"],"properties":{"error":{"type":["string","null"],"description":"Error message if the test failed"},"provider_message_id":{"type":["string","null"],"description":"Provider message ID if successful"},"sent_to":{"type":"string","description":"The email address the test was sent to","example":"user@example.com"},"success":{"type":"boolean","description":"Whether the test email was sent successfully"}}},"TestProviderKeyRequest":{"type":"object","required":["provider","api_key"],"properties":{"api_key":{"type":"string","description":"The raw API key to test"},"base_url":{"type":["string","null"],"description":"Optional custom base URL"},"provider":{"type":"string","description":"Provider ID: \"openai\", \"anthropic\", \"xai\", \"gemini\""}}},"TestProviderKeyResponse":{"type":"object","required":["success","provider","latency_ms"],"properties":{"error":{"type":["string","null"],"description":"Error message if the test failed"},"latency_ms":{"type":"integer","format":"int64","description":"Response time in milliseconds","minimum":0},"provider":{"type":"string"},"success":{"type":"boolean"}}},"TestProviderResponse":{"type":"object","required":["success"],"properties":{"message":{"type":["string","null"]},"success":{"type":"boolean"}}},"TimeBucketStats":{"type":"object","description":"Time bucket statistics response","required":["bucket","request_count","avg_response_time_ms","error_count","total_request_bytes","total_response_bytes"],"properties":{"avg_response_time_ms":{"type":"number","format":"double","description":"Average response time in milliseconds"},"bucket":{"type":"string","description":"Bucket timestamp in RFC3339 format","example":"2025-10-23T12:00:00Z"},"error_count":{"type":"integer","format":"int64","description":"Number of errors (status >= 400)"},"request_count":{"type":"integer","format":"int64","description":"Total number of requests in this bucket"},"total_request_bytes":{"type":"integer","format":"int64","description":"Total request bytes"},"total_response_bytes":{"type":"integer","format":"int64","description":"Total response bytes"}}},"TimeBucketStatsResponse":{"type":"object","description":"Response for time bucket stats","required":["stats","start_time","end_time","bucket_interval"],"properties":{"bucket_interval":{"type":"string"},"end_time":{"type":"string"},"start_time":{"type":"string"},"stats":{"type":"array","items":{"$ref":"#/components/schemas/TimeBucketStats"}}}},"TimeseriesBucket":{"type":"object","required":["bucket","request_count","input_tokens","output_tokens","avg_latency_ms"],"properties":{"avg_latency_ms":{"type":"number","format":"double"},"bucket":{"type":"string","description":"ISO 8601 timestamp"},"input_tokens":{"type":"integer","format":"int64"},"output_tokens":{"type":"integer","format":"int64"},"request_count":{"type":"integer","format":"int64"}}},"TimeseriesQueryParams":{"type":"object","properties":{"bucket":{"type":["string","null"],"description":"Bucket size: \"hour\", \"day\", \"week\" (defaults to \"day\")"},"conversation_id":{"type":["string","null"],"description":"Filter by conversation ID"},"from":{"type":["string","null"],"description":"ISO 8601 start time (defaults to 24h ago)"},"model":{"type":["string","null"],"description":"Filter by model name"},"provider":{"type":["string","null"],"description":"Filter by provider name"},"tags":{"type":["string","null"],"description":"Filter by tags (comma-separated, AND logic)"},"to":{"type":["string","null"],"description":"ISO 8601 end time (defaults to now)"},"user_id":{"type":["integer","null"],"format":"int32","description":"Filter by user ID"}}},"TlsMode":{"type":"string","enum":["None","Starttls","Tls"]},"TodayStatsResponse":{"type":"object","description":"Today's stats response","required":["total_requests","date"],"properties":{"date":{"type":"string","description":"Date for which stats are returned","example":"2025-10-23"},"total_requests":{"type":"integer","format":"int64","description":"Total requests today"}}},"ToggleDeploymentMetricsRequest":{"type":"object","description":"Request body to toggle OTLP metric ingestion for a deployment.","required":["enabled"],"properties":{"enabled":{"type":"boolean","description":"Whether to enable (`true`) or disable (`false`) metric ingestion."},"path":{"type":["string","null"],"description":"Prometheus scrape path (optional, defaults to `/metrics`)."},"port":{"type":["integer","null"],"format":"int32","description":"Prometheus scrape port (optional).","minimum":0}}},"ToggleServiceMetricsRequest":{"type":"object","description":"Request body to toggle metric collection for an external service.","required":["enabled"],"properties":{"enabled":{"type":"boolean","description":"Whether to enable (`true`) or disable (`false`) metric collection."}}},"TokenRenewalRequest":{"type":"object","required":["refresh_token"],"properties":{"refresh_token":{"type":"string"}}},"ToolCallEvent":{"type":"object","description":"Payload for the `tool_call` SSE event: the model is about to run a tool.\nSerialized as compact single-line JSON onto one `data:` line.","required":["id","name","arguments"],"properties":{"arguments":{"type":"string","description":"The raw JSON-args string the model emitted."},"id":{"type":"string"},"name":{"type":"string"}}},"ToolInfo":{"type":"object","description":"One persisted tool invocation + its result, attached to an assistant message.","required":["id","name","arguments"],"properties":{"arguments":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"},"result":{"type":["string","null"]}}},"ToolResultEvent":{"type":"object","description":"Payload for the `tool_result` SSE event: a tool finished running. Serialized\nas compact single-line JSON; `content` is JSON-string-escaped so it stays on\none `data:` line even when long.","required":["id","name","content"],"properties":{"content":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"}}},"TopModelsQueryParams":{"type":"object","properties":{"from":{"type":["string","null"],"description":"ISO 8601 start time (defaults to 24h ago)"},"limit":{"type":["integer","null"],"format":"int64","description":"Max results (defaults to 10)","minimum":0},"tags":{"type":["string","null"],"description":"Filter by tags (comma-separated, AND logic)"},"to":{"type":["string","null"],"description":"ISO 8601 end time (defaults to now)"},"user_id":{"type":["integer","null"],"format":"int32","description":"Filter by user ID"}}},"TraceProjectRef":{"type":"object","description":"All projects that contributed spans to a trace, including their sharing flag.\n\nReturned by `CrossProjectTraceService::find_trace_projects`.","required":["project_id","project_name","project_slug","first_seen","sharing"],"properties":{"first_seen":{"type":"string","format":"date-time"},"project_id":{"type":"integer","format":"int32"},"project_name":{"type":"string"},"project_slug":{"type":"string","description":"URL slug used to link into the project's single-project trace view."},"sharing":{"type":"boolean","description":"Whether this project has `cross_project_trace_sharing = true`."}}},"TraceSummariesResponse":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/TraceSummary"}},"total":{"type":["integer","null"],"format":"int64","description":"Total traces matching the filters, ignoring pagination. Omitted when\nthe request passed `include_total=false`, in which case the caller\nasked not to pay for the count — treat its absence as \"unknown\", not\nas zero.","minimum":0}}},"TraceSummary":{"type":"object","description":"A trace summary for the list view — one row per trace, aggregated from spans.","required":["trace_id","root_span_name","service_name","kind","status_code","start_time","duration_ms","span_count","error_count"],"properties":{"deployment_environment":{"type":["string","null"],"description":"The deployment environment from the root span's resource attributes (e.g. \"production\")."},"duration_ms":{"type":"number","format":"double"},"error_count":{"type":"integer","format":"int64"},"kind":{"$ref":"#/components/schemas/SpanKind"},"root_span_name":{"type":"string"},"service_name":{"type":"string"},"span_count":{"type":"integer","format":"int64"},"start_time":{"type":"string","format":"date-time"},"status_code":{"$ref":"#/components/schemas/SpanStatusCode"},"trace_id":{"type":"string"}}},"TracesResponse":{"type":"object","required":["data","count"],"properties":{"count":{"type":"integer","minimum":0},"data":{"type":"array","items":{"$ref":"#/components/schemas/SpanRecord"}}}},"TrackedLinkResponse":{"type":"object","description":"Tracked link with click count","required":["link_index","original_url","click_count"],"properties":{"click_count":{"type":"integer","format":"int32"},"link_index":{"type":"integer","format":"int32"},"original_url":{"type":"string"}}},"TrackingEventResponse":{"type":"object","description":"Email tracking event","required":["id","email_id","event_type","created_at"],"properties":{"created_at":{"type":"string"},"email_id":{"type":"string"},"event_type":{"type":"string"},"id":{"type":"integer","format":"int64"},"ip_address":{"type":["string","null"]},"link_index":{"type":["integer","null"],"format":"int32"},"link_url":{"type":["string","null"]},"user_agent":{"type":["string","null"]}}},"TriggerAgentRequest":{"type":"object","properties":{"trigger_source_id":{"type":["integer","null"],"format":"int32"},"trigger_source_type":{"type":["string","null"]},"user_context":{"type":["string","null"],"description":"Optional context from the user (e.g. a research topic, bug description, or instructions)."}}},"TriggerDigestResponse":{"type":"object","required":["success","message"],"properties":{"message":{"type":"string"},"success":{"type":"boolean"}}},"TriggerPipelinePayload":{"type":"object","properties":{"branch":{"type":["string","null"]},"commit":{"type":["string","null"]},"environment_id":{"type":["integer","null"],"format":"int32","description":"Optional environment ID - if not provided, will use the project's preview environment"},"tag":{"type":["string","null"]}}},"TriggerPipelineResponse":{"type":"object","required":["message","project_id","environment_id"],"properties":{"branch":{"type":["string","null"]},"commit":{"type":["string","null"]},"environment_id":{"type":"integer","format":"int32"},"message":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"tag":{"type":["string","null"]}}},"TriggerScanRequest":{"type":"object","required":["environment_id"],"properties":{"environment_id":{"type":"integer","format":"int32","description":"Environment ID to scan (uses the current deployment for this environment)","example":1}}},"TriggerScanResponse":{"type":"object","required":["scan_id","status","message"],"properties":{"message":{"type":"string"},"scan_id":{"type":"integer","format":"int32"},"status":{"type":"string"}}},"TtlRequest":{"type":"object","description":"Request to get TTL for a key","required":["key"],"properties":{"key":{"type":"string","description":"The key to check TTL for","example":"session:abc"},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1}}},"TtlResponse":{"type":"object","description":"Response for TTL operation","required":["ttl"],"properties":{"ttl":{"type":"integer","format":"int64","description":"TTL in seconds, -1 if no expiration, -2 if key doesn't exist","example":3600}}},"TxtRecord":{"type":"object","required":["name","value"],"properties":{"name":{"type":"string"},"value":{"type":"string"}}},"UiManifest":{"type":"object","description":"Describes the plugin's embedded UI bundle.","required":["entry_js"],"properties":{"css":{"type":"array","items":{"type":"string"},"description":"CSS files to load"},"entry_js":{"type":"string","description":"JavaScript entry point filename relative to the bundle root"},"routes":{"type":"array","items":{"$ref":"#/components/schemas/UiRoute"},"description":"Client-side routes the plugin handles"}}},"UiRoute":{"type":"object","description":"A client-side route provided by the plugin UI.","required":["path","title"],"properties":{"path":{"type":"string","description":"Route path pattern (e.g., \"/my-plugin\", \"/my-plugin/:id\")"},"title":{"type":"string","description":"Page title for breadcrumbs"}}},"UndrainNodeResponse":{"type":"object","description":"Response after undraining (reactivating) a node.","required":["id","name","status","message"],"properties":{"id":{"type":"integer","format":"int32"},"message":{"type":"string"},"name":{"type":"string"},"status":{"type":"string"}}},"UnifiedTrace":{"type":"object","description":"Merged cross-project trace result (Phase 2 unified waterfall).\n\nSpans are sorted by `start_time ASC`. At most 20 projects and 10,000\nspans total are included; `truncated` / `truncated_projects` signal when\nthe caps were hit.","required":["trace_id","projects","spans","start_time","end_time","total_duration_ms","span_count","error_count","has_redacted_spans","truncated","truncated_projects"],"properties":{"end_time":{"type":"string","format":"date-time"},"error_count":{"type":"integer","minimum":0},"has_redacted_spans":{"type":"boolean","description":"`true` when at least one project has `cross_project_trace_sharing = false`\nand its spans were therefore excluded from the result set."},"projects":{"type":"array","items":{"$ref":"#/components/schemas/ProjectRef"},"description":"Projects that contributed spans to this result set."},"span_count":{"type":"integer","minimum":0},"spans":{"type":"array","items":{"$ref":"#/components/schemas/AnnotatedSpan"},"description":"Annotated, merged span list sorted by `start_time ASC`."},"start_time":{"type":"string","format":"date-time"},"total_duration_ms":{"type":"number","format":"double","description":"Trace wall-clock duration in milliseconds (`end_time – start_time`)."},"trace_id":{"type":"string"},"truncated":{"type":"boolean","description":"`true` when the 20-project or 10,000-span cap was hit."},"truncated_projects":{"type":"array","items":{"type":"integer","format":"int32"},"description":"project_ids excluded due to truncation (most-recent first_seen dropped first)."}}},"UniqueCountsQuery":{"type":"object","description":"Query parameters for unique counts over time frame","required":["start_date","end_date"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32","description":"Optional deployment filter"},"end_date":{"type":"string","format":"date-time","description":"End date for the query range"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Optional environment filter"},"metric":{"type":"string","description":"Metric to count: \"sessions\" (unique sessions), \"visitors\" (unique visitors),\n\"returning_visitors\" (visitors seen before the range), or \"page_views\"\n(total page views) (default: \"sessions\")"},"start_date":{"type":"string","format":"date-time","description":"Start date for the query range"}}},"UniqueCountsResponse":{"type":"object","required":["count"],"properties":{"count":{"type":"integer","format":"int64"}}},"UnsupportedFeature":{"type":"object","description":"A feature from the source platform that cannot be migrated","required":["feature","reason"],"properties":{"alternative":{"type":["string","null"],"description":"Suggested alternative in Temps (if any)"},"feature":{"type":"string","description":"Feature name (e.g., \"Edge Middleware\", \"Serverless Functions\", \"Cron Jobs\")"},"reason":{"type":"string","description":"Why it can't be migrated"}}},"UpdateAdminGateRequest":{"type":"object","required":["allowed_ips","allowed_hosts","trust_forwarded_for"],"properties":{"allowed_hosts":{"type":"array","items":{"type":"string"}},"allowed_ips":{"type":"array","items":{"type":"string"}},"trust_forwarded_for":{"type":"boolean"}}},"UpdateAiProviderRequest":{"type":"object","description":"Body for `PATCH /settings/ai-providers/{provider_id}` — updates\nprovider-scoped settings (just the default model for now) without\ntouching the credential. Keeping credentials out of this shape means\nthe UI can auto-save model changes on select, without forcing the user\nto re-paste their token or config file.\nName-spaced schema name avoids an OpenAPI collision with\n`temps-notifications::UpdateProviderRequest`, which has different fields.\nBoth are exposed as `utoipa::ToSchema`; without the override the merged\nOpenAPI doc would silently shadow one struct with the other and break\ngenerated CLI/web clients.","properties":{"default_model":{"type":["string","null"],"description":"New default model id. `None` or an empty string clears the stored\nvalue so the CLI falls back to its own default."},"max_turns_analysis":{"type":["integer","null"],"format":"int32","description":"Default max turns for the autofixer analysis phase (1–200). `0`\nclears the stored value (built-in default applies); omitted/`None`\nleaves the current value unchanged — so a PATCH that only updates\n`default_model` doesn't wipe the turn settings."},"max_turns_feedback":{"type":["integer","null"],"format":"int32","description":"Default max turns for autofixer feedback rounds (1–200). `0` clears;\nomitted leaves unchanged."},"max_turns_fix":{"type":["integer","null"],"format":"int32","description":"Default max turns for the autofixer fix phase (1–200). `0` clears;\nomitted leaves unchanged."}}},"UpdateAiProviderResponse":{"type":"object","required":["provider_id"],"properties":{"default_model":{"type":["string","null"]},"max_turns_analysis":{"type":["integer","null"],"format":"int32"},"max_turns_feedback":{"type":["integer","null"],"format":"int32"},"max_turns_fix":{"type":["integer","null"],"format":"int32"},"provider_id":{"type":"string"}}},"UpdateAlertRuleRequest":{"type":"object","properties":{"cooldown_minutes":{"type":["integer","null"],"format":"int32"},"enabled":{"type":["boolean","null"]},"environment_filter":{"type":["integer","null"],"format":"int32"},"error_level_filter":{"type":["string","null"]},"name":{"type":["string","null"]},"notification_priority":{"type":["string","null"]},"trigger_config":{},"trigger_type":{"type":["string","null"]}}},"UpdateApiKeyRequest":{"type":"object","properties":{"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"is_active":{"type":["boolean","null"]},"name":{"type":["string","null"]},"permissions":{"type":["array","null"],"items":{"type":"string"},"example":["projects:read","deployments:read"]}}},"UpdateAutomaticDeployRequest":{"type":"object","required":["automatic_deploy"],"properties":{"automatic_deploy":{"type":"boolean"}}},"UpdateBackupScheduleRequest":{"type":"object","description":"Request body for updating an existing backup schedule via `PATCH /api/backups/schedules/{id}`.\n\nAll fields are optional; only present fields are updated. Absent fields\nleave the corresponding column unchanged.","properties":{"description":{"type":["string","null"],"description":"New human-readable description. Pass an empty string `\"\"` to clear."},"enabled":{"type":["boolean","null"],"description":"Enable or disable the schedule. Skipped when `None`."},"include_control_plane":{"type":["boolean","null"],"description":"Toggle whether the control-plane backup is produced on every run."},"max_runtime_secs":{"type":["integer","null"],"format":"int64","description":"Per-schedule wall-clock timeout override (seconds).\n\n- `None` (field absent) — leave current value unchanged\n- `Some(None)` (field present, JSON `null`) — clear override; fall back to engine default\n- `Some(Some(n))` — set to `n` seconds (must be >= 60)"},"name":{"type":["string","null"],"description":"New schedule name. Skipped when `None`. Must not be empty if provided."},"retention_period":{"type":["integer","null"],"format":"int32","description":"Days to retain backups produced by this schedule. Must be >= 1."},"schedule_expression":{"type":["string","null"],"description":"New cron expression. When changed, `next_run` is recomputed."},"tags":{"type":["array","null"],"items":{"type":"string"},"description":"Replace the full tag list. Skipped when `None`."},"target_all_services":{"type":["boolean","null"],"description":"Toggle between \"back up every database\" (`true`) and \"back up only\nthe explicit list\" (`false`). When set to `true`, the server clears\nthe explicit membership rows for this schedule."}}},"UpdateBlobRequest":{"type":"object","description":"Request to update Blob service configuration","properties":{"docker_image":{"type":["string","null"],"description":"Docker image to use (e.g., \"rustfs/rustfs:1.0.0-alpha.98\")","example":"rustfs/rustfs:1.0.0-alpha.98"}}},"UpdateBlobResponse":{"type":"object","description":"Response after updating Blob service","required":["success","message","status"],"properties":{"message":{"type":"string","description":"Human-readable message","example":"Blob service updated successfully"},"status":{"$ref":"#/components/schemas/BlobStatusResponse","description":"Current status"},"success":{"type":"boolean","description":"Whether the operation succeeded","example":true}}},"UpdateCapabilityResponse":{"type":"object","description":"Whether this install can apply a release update on request, and how the last\nattempt went.\n\nDeliberately answerable even when the answer is \"no\": an operator who cannot\nuse the button still needs to know *why* and what to run instead, so this\nnever 404s or returns an empty body when the feature is unavailable.","required":["can_apply","allowed","manual_command","supervisor","binary_path","phase"],"properties":{"allowed":{"type":"boolean","description":"Whether the *caller* holds `platform:update`. Distinct from `can_apply`,\nwhich describes the server: the console shows the action only when both\nare true, so a reader is never offered a button that would 403."},"binary_path":{"type":"string","description":"Binary that would be replaced."},"blocker":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SelfUpdateBlocker","description":"Machine-readable reason `can_apply` is false (`disabled_by_flag`,\n`disabled_by_setting`, `container`, `no_supervisor`, `binary_not_writable`,\n`unsupported_platform`, `in_progress`)."}]},"can_apply":{"type":"boolean","description":"True only when a request would actually download, install and restart."},"caveat":{"type":["string","null"],"description":"Non-blocking warning to show with the confirmation (split topology)."},"last_attempt":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SelfUpdateAttempt","description":"Most recent attempt, including one resolved during this boot — this is\nhow the console reports the outcome of an update that restarted it."}]},"manual_command":{"type":"string","description":"The equivalent command to run by hand. Always present."},"phase":{"$ref":"#/components/schemas/SelfUpdatePhase","description":"Phase of an in-flight attempt: `idle` when none is running."},"phase_error":{"type":["string","null"],"description":"Failure detail while `phase` is `failed`."},"reason":{"type":["string","null"],"description":"Operator-facing explanation of `blocker`."},"supervisor":{"$ref":"#/components/schemas/SupervisorKind","description":"What would restart the process: `systemd`, `launchd`, `container`, `none`."}}},"UpdateCloudflareProviderRequest":{"type":"object","required":["config"],"properties":{"config":{"$ref":"#/components/schemas/CloudflareConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":["string","null"]}}},"UpdateConfigBody":{"type":"object","properties":{"config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ProviderConfig","description":"Typed provider configuration. Setting `config` to `null` clears\nthe stored config back to the accept-everything default. The\nconfig's `provider` tag must match the integration's provider."}]}}},"UpdateCustomDomainRequest":{"type":"object","properties":{"branch":{"type":["string","null"]},"domain":{"type":["string","null"]},"environment_id":{"type":["integer","null"],"format":"int32"},"redirect_to":{"type":["string","null"]},"service_name":{"type":["string","null"],"description":"Docker Compose service name this domain routes to (empty string clears it)"},"status_code":{"type":["integer","null"],"format":"int32"}}},"UpdateDashboardRequest":{"type":"object","properties":{"layout":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DashboardLayout"}]},"name":{"type":["string","null"]}}},"UpdateDeploymentConfigRequest":{"type":"object","properties":{"automaticDeploy":{"type":["boolean","null"]},"cpuLimit":{"type":["integer","null"],"format":"int32"},"cpuRequest":{"type":["integer","null"],"format":"int32"},"crossArchitectureBuilds":{"type":["boolean","null"],"description":"Build one image per architecture the eligible nodes run. Off by\ndefault; environments inherit this and may override it. Cross-builds\nare emulated on the control plane and substantially slower, so they are\nopted into rather than triggered by cluster topology."},"exposedPort":{"type":["integer","null"],"format":"int32"},"memoryLimit":{"type":["integer","null"],"format":"int32"},"memoryRequest":{"type":["integer","null"],"format":"int32"},"performanceMetricsEnabled":{"type":["boolean","null"]},"replicas":{"type":["integer","null"],"format":"int32"},"security":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SecurityConfig"}]},"sessionRecordingEnabled":{"type":["boolean","null"]}}},"UpdateDeploymentTokenRequest":{"type":"object","properties":{"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"is_active":{"type":["boolean","null"]},"name":{"type":["string","null"]},"permissions":{"type":["array","null"],"items":{"type":"string"},"example":["visitors:enrich","emails:send"]}}},"UpdateDnsProviderRequest":{"type":"object","description":"Request to update a DNS provider","properties":{"credentials":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DnsProviderCredentials","description":"New credentials"}]},"description":{"type":["string","null"],"description":"New description"},"is_active":{"type":["boolean","null"],"description":"Active status"},"name":{"type":["string","null"],"description":"New name"}}},"UpdateEmailProviderRequest":{"type":"object","description":"Request body for `PATCH /email-providers/{id}`.\n\nAll fields are optional. Omit any field to leave it unchanged. The\n`provider_type` is immutable — to switch providers, delete the row and\ncreate a new one. For credentials, supplying any credential variant\nre-encrypts the stored blob; omitting them preserves the existing secret\n(so operators can rename without re-typing passwords).","properties":{"is_active":{"type":["boolean","null"]},"name":{"type":["string","null"],"example":"My AWS SES"},"region":{"type":["string","null"],"example":"us-east-1"},"scaleway_credentials":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ScalewayCredentialsRequest"}]},"ses_credentials":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SesCredentialsRequest"}]},"smtp_credentials":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SmtpCredentialsRequest"}]},"sns_topic_arn":{"type":["string","null"],"description":"Rotate or clear the exact SNS topic allowed for this SES provider.\nOmit to preserve it, send `null` to clear it, or send a string to set it."}}},"UpdateEnvironmentSettingsRequest":{"type":"object","properties":{"anti_affinity":{"type":["boolean","null"],"description":"Anti-affinity: spread replicas across different nodes.\nWhen enabled, the scheduler avoids placing two replicas of the same\nenvironment on the same node. Defaults to `true`."},"attack_mode":{"type":["boolean","null"],"description":"Per-environment CAPTCHA attack-mode override (tri-state):\n- absent → leave the current override unchanged\n- JSON `null` → clear the override (inherit the project-level setting)\n- `true`/`false` → override the project setting for this environment"},"automatic_deploy":{"type":["boolean","null"],"description":"Enable/disable automatic deployments for this environment"},"branch":{"type":["string","null"]},"cpu_limit":{"type":["integer","null"],"format":"int32","description":"Maximum (limit) CPU in microcores. Send JSON `null` to clear → \"no limit\".\nAbsent leaves the current value unchanged."},"cpu_request":{"type":["integer","null"],"format":"int32","description":"Minimum (request) CPU in microcores. Send JSON `null` to clear (no request).\nAbsent leaves the current value unchanged."},"cross_architecture_builds":{"type":["boolean","null"],"description":"Build one image per architecture the eligible nodes run (overrides the\nproject-level setting). Off by default: cross-architecture builds are\nemulated on the control plane and substantially slower, so they are\nopted into per environment rather than triggered by cluster topology."},"exposed_port":{"type":["integer","null"],"format":"int32","description":"Port exposed by the container (overrides project-level port for this environment)\n\nPriority order for port resolution:\n1. Image EXPOSE directive (auto-detected from built image)\n2. This environment-level exposed_port (overrides project setting)\n3. Project-level exposed_port (fallback)\n4. Default: 3000","example":8080},"force_https":{"type":["boolean","null"],"description":"Per-environment HTTP→HTTPS redirect override (tri-state):\n- absent → leave the current override unchanged\n- JSON `null` → clear the override (inherit the proxy default, which\n redirects only when the host has an active TLS certificate)\n- `true` → always redirect plain HTTP to HTTPS for this environment,\n even when no local certificate exists (TLS terminated upstream)\n- `false` → never redirect this environment, even when a certificate does\n exist\n\nRequests under `/.well-known/acme-challenge/` are never redirected\nregardless of this setting, so ACME HTTP-01 validation always completes."},"idle_timeout_seconds":{"type":["integer","null"],"format":"int32","description":"Seconds of inactivity before stopping containers (60-86400). Default: 300."},"memory_limit":{"type":["integer","null"],"format":"int32","description":"Maximum (limit) memory in MB. Send JSON `null` to clear → \"no limit\".\nAbsent leaves the current value unchanged."},"memory_request":{"type":["integer","null"],"format":"int32","description":"Minimum (request) memory in MB. Send JSON `null` to clear (no request).\nAbsent leaves the current value unchanged."},"on_demand":{"type":["boolean","null"],"description":"Enable on-demand mode (scale-to-zero). Containers are stopped after\nidle_timeout_seconds of no traffic and started on the next request."},"password":{"type":["string","null"],"description":"Set a password to protect this environment. The proxy will show an HTML\npassword form before allowing access. The password is bcrypt-hashed\nserver-side and never stored in plaintext.\nSend an empty string to remove password protection."},"performance_metrics_enabled":{"type":["boolean","null"],"description":"Enable/disable performance metrics collection"},"protected":{"type":["boolean","null"],"description":"When true, git pushes do NOT auto-deploy to this environment.\nDeployments must be promoted from another environment."},"replicas":{"type":["integer","null"],"format":"int32"},"security":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SecurityConfig","description":"Security configuration for this environment (overrides project-level settings)"}]},"session_recording_enabled":{"type":["boolean","null"],"description":"Enable/disable session recording"},"target_labels":{"description":"Label selector for node-based scheduling (overrides project-level setting).\nSame key with array value -> OR, different keys -> AND.\nExample: `{\"region\": [\"us\", \"asia\"], \"gpu\": \"true\"}`"},"target_nodes":{"type":["array","null"],"items":{"type":"integer","format":"int32"},"description":"Optional list of node IDs to deploy to (overrides project-level setting)"},"wake_timeout_seconds":{"type":["integer","null"],"format":"int32","description":"Max seconds to wait for containers to start on wake (5-120). Default: 30."}}},"UpdateEnvironmentSubdomainRequest":{"type":"object","description":"Request to rename an environment's auto-managed subdomain.\n\nThe subdomain is the host label inserted in front of the platform's\npreview domain (e.g. `myapp` in `myapp.preview.temps.sh`). Renaming\nreplaces the previous subdomain entirely — the old hostname stops\nresolving immediately after this request succeeds.","required":["subdomain"],"properties":{"subdomain":{"type":"string","description":"New subdomain label. Must be a DNS-safe slug (lowercase letters,\ndigits, and hyphens, 1-63 characters). The value is slugified\nserver-side, so casing and disallowed characters are normalized.","example":"myapp"}}},"UpdateEnvironmentVariableRequest":{"type":"object","required":["key","environment_ids"],"properties":{"environment_ids":{"type":"array","items":{"type":"integer","format":"int32"}},"include_in_preview":{"type":"boolean"},"is_secret":{"type":["boolean","null"],"description":"Optional secret-flag transition.\n- `Some(true)` promotes a regular var to a secret.\n- `Some(false)` is rejected if the row is already secret (one-way flag).\n- `None` (omitted) leaves the flag unchanged."},"key":{"type":"string"},"value":{"type":["string","null"],"description":"New plaintext value. `None` (omitted) keeps the existing ciphertext,\nwhich is the only way to edit a secret env var without re-typing its\nvalue (e.g. changing which environments it applies to)."}}},"UpdateErrorGroupRequest":{"type":"object","required":["status"],"properties":{"assigned_to":{"type":["string","null"]},"status":{"type":"string"}}},"UpdateExternalServiceRequest":{"type":"object","required":["parameters"],"properties":{"docker_image":{"type":["string","null"],"description":"Docker image to use for the service (e.g., \"gotempsh/postgres-walg:18-bookworm\", \"timescale/timescaledb-ha:pg18\")\nWhen provided, the service will be recreated with the new image while preserving data"},"parameters":{"type":"object","additionalProperties":{},"propertyNames":{"type":"string"}}}},"UpdateFlagRequest":{"type":"object","properties":{"client_visible":{"type":["boolean","null"]},"default_value":{"description":"Must match the flag's existing `value_type`."},"description":{"type":["string","null"],"description":"Tri-state: absent leaves it, `null` clears it, a string sets it."}}},"UpdateGitSettingsRequest":{"type":"object","required":["main_branch","repo_owner","repo_name","directory"],"properties":{"directory":{"type":"string"},"git_provider_connection_id":{"type":["integer","null"],"format":"int32"},"git_url":{"type":["string","null"],"description":"Git clone URL for public repositories"},"is_public_repo":{"type":["boolean","null"],"description":"Whether this is a public repository (no git provider connection needed)"},"main_branch":{"type":"string"},"preset":{"type":["string","null"]},"preset_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PresetConfigSchema","description":"Preset-specific configuration (e.g., Dockerfile path for Docker preset)\n\nExample for Dockerfile preset:\n```json\n{\n \"dockerfilePath\": \"docker/Dockerfile\",\n \"buildContext\": \"./api\"\n}\n```"}]},"repo_name":{"type":"string"},"repo_owner":{"type":"string"}}},"UpdateIncidentStatusRequest":{"type":"object","required":["status","message"],"properties":{"message":{"type":"string"},"status":{"type":"string"}}},"UpdateIpAccessControlRequest":{"type":"object","description":"Request to update an IP access control rule","properties":{"action":{"type":["string","null"],"description":"Optional new action"},"ip_address":{"type":["string","null"],"description":"Optional new IP address"},"reason":{"type":["string","null"],"description":"Optional new reason"}}},"UpdateKvRequest":{"type":"object","description":"Request to update KV service configuration","properties":{"docker_image":{"type":["string","null"],"description":"Docker image to use (e.g., \"gotempsh/redis-walg:8-bookworm\")","example":"gotempsh/redis-walg:8-bookworm"}}},"UpdateKvResponse":{"type":"object","description":"Response after updating KV service","required":["success","message","status"],"properties":{"message":{"type":"string","description":"Status message","example":"KV service updated successfully"},"status":{"$ref":"#/components/schemas/KvStatusResponse","description":"Current service status"},"success":{"type":"boolean","description":"Whether the operation succeeded"}}},"UpdateManagedDomainApiRequest":{"type":"object","description":"Request to update a managed domain's settings.","properties":{"auto_manage":{"type":["boolean","null"],"description":"Toggle automatic DNS management for this domain."},"generated_hostname_mode":{"type":["string","null"],"description":"`\"standard\"` or `\"flat\"`. Persisted as-is; switching to `\"flat\"` does not\nrecompute existing hostnames — use the apply endpoint for that."},"sync_generated_records":{"type":["boolean","null"],"description":"Toggle DNS record sync for this domain."}}},"UpdateMcpRequest":{"type":"object","required":["config"],"properties":{"config":{"type":"object"},"description":{"type":["string","null"]},"name":{"type":["string","null"]}}},"UpdateMemberRoleRequest":{"type":"object","description":"The new fixed role for an existing membership.","required":["role"],"properties":{"role":{"$ref":"#/components/schemas/TeamRole"}}},"UpdateMetricAlertRequest":{"type":"object","properties":{"aggregation":{"type":["string","null"]},"detection_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DetectionConfig","description":"Replaces the detector wholesale when present (absent = leave unchanged)."}]},"dynamic_alerts":{"type":["boolean","null"],"description":"Toggles per-series (\"dynamic\") alerting (absent = leave unchanged)."},"enabled":{"type":["boolean","null"]},"for_duration_secs":{"type":["integer","null"],"format":"int32"},"group_by":{"type":["array","null"],"items":{"type":"string"},"description":"Replaces the group_by keys wholesale when present (absent = leave unchanged)."},"grouped_notification_threshold":{"type":["integer","null"],"format":"int32","description":"Updates the notification-grouping threshold (absent = leave unchanged)."},"label_filters":{"type":["array","null"],"items":{"type":"array","items":false,"prefixItems":[{"type":"string"},{"type":"string"}]},"description":"Replaces the label filters wholesale when present (absent = leave unchanged)."},"max_series":{"type":["integer","null"],"format":"int32","description":"Updates the dynamic-alerting cardinality cap (absent = leave unchanged)."},"metric_name":{"type":["string","null"]},"name":{"type":["string","null"]},"severity":{"type":["string","null"]},"window_secs":{"type":["integer","null"],"format":"int32"}}},"UpdateNotificationEmailProviderRequest":{"type":"object","required":["config"],"properties":{"config":{"$ref":"#/components/schemas/EmailConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":["string","null"]}}},"UpdateOidcProviderRequest":{"type":"object","properties":{"client_id":{"type":["string","null"]},"client_secret":{"type":["string","null"]},"default_role":{"type":["string","null"]},"enabled":{"type":["boolean","null"]},"group_claim":{"type":["string","null"]},"issuer_url":{"type":["string","null"]},"jit_provisioning":{"type":["boolean","null"]},"name":{"type":["string","null"]},"role_claim":{"type":["string","null"]},"scopes":{"type":["string","null"]},"template":{"type":["string","null"]},"trust_idp_email":{"type":["boolean","null"]}}},"UpdatePreferencesRequest":{"type":"object","required":["preferences"],"properties":{"preferences":{"$ref":"#/components/schemas/NotificationPreferencesResponse"}}},"UpdateProjectSecretRequest":{"type":"object","description":"Request to update a project secret. The `value` field is optional — omit it\nto rotate only the environment scoping / preview flag without touching the\nciphertext.","properties":{"environment_ids":{"type":"array","items":{"type":"integer","format":"int32"}},"include_in_preview":{"type":"boolean"},"value":{"type":["string","null"],"description":"New plaintext value, <= 1 MiB. Omit to keep the existing value."}}},"UpdateProjectSettingsRequest":{"type":"object","properties":{"ai_alert_summaries_enabled":{"type":["boolean","null"],"description":"Opt in to AI summarization of metric alert notifications (ADR-021)."},"ai_debug_chat_enabled":{"type":["boolean","null"],"description":"Opt in to AI debugging chat, e.g. on deployment failures (ADR-023)."},"ai_write_actions_enabled":{"type":["boolean","null"],"description":"Opt in to AI propose-then-confirm write capability."},"attack_mode":{"type":["boolean","null"],"description":"Enable/disable attack mode (CAPTCHA protection) for all project environments"},"cross_project_trace_sharing":{"type":["boolean","null"],"description":"ADR-027 Phase 3 opt-out: set to false to suppress this project's traces\nfrom appearing in cross-project discovery results. Default true (consistent\nwith the OSS global-observability model). Omit to leave unchanged."},"directory":{"type":["string","null"]},"enable_preview_environments":{"type":["boolean","null"],"description":"Enable automatic preview environment creation for each branch"},"error_source_context_enabled":{"type":["boolean","null"],"description":"Opt in to native error-tracking source context (source-file upload +\nsource code shown in stack traces)."},"error_source_root":{"type":["string","null"],"description":"Set the auto-capture source root (relative to the checkout). Send an\nempty string to clear it back to the build-context default. Omit to\nleave unchanged."},"git_provider_connection_id":{"type":["integer","null"],"format":"int32"},"main_branch":{"type":["string","null"]},"preset":{"type":["string","null"]},"preset_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PresetConfigSchema","description":"Preset-specific configuration (e.g., Dockerfile path for Docker preset)\n\nExample for Dockerfile preset:\n```json\n{\n \"dockerfilePath\": \"docker/Dockerfile\",\n \"buildContext\": \"./api\"\n}\n```"}]},"preview_envs_idle_timeout_seconds":{"type":["integer","null"],"format":"int32","description":"Idle timeout (seconds, 60..=86400) for on-demand preview environments."},"preview_envs_on_demand":{"type":["boolean","null"],"description":"When true, newly-created preview environments default to on-demand mode."},"preview_envs_wake_timeout_seconds":{"type":["integer","null"],"format":"int32","description":"Wake timeout (seconds, 5..=120) for on-demand preview environments."},"repo_name":{"type":["string","null"]},"repo_owner":{"type":["string","null"]},"slug":{"type":["string","null"]}}},"UpdateProviderCredentialsRequest":{"type":"object","description":"Partial-update payload for provider credentials. Every field is optional;\nonly the fields the user re-enters are applied. The server validates that\nthe fields supplied make sense for the provider's current auth_method\n(e.g. `app_id` + `private_key` only apply to GitHub Apps).","properties":{"app_id":{"type":["string","null"],"description":"Application ID (GitHub App integer as string; GitLab App string)."},"app_secret":{"type":["string","null"],"description":"GitLab App secret (not used by GitHub App — use `client_secret`)."},"client_id":{"type":["string","null"],"description":"OAuth client ID (GitLab OAuth, GitHub App)."},"client_secret":{"type":["string","null"],"description":"OAuth client secret (GitLab OAuth, GitHub App)."},"private_key":{"type":["string","null"],"description":"GitHub App private key (PEM)."},"redirect_uri":{"type":["string","null"],"description":"OAuth redirect URI (GitLab OAuth / GitLab App)."},"token":{"type":["string","null"],"description":"PAT for PAT-type providers."},"webhook_secret":{"type":["string","null"],"description":"GitHub App webhook secret."}}},"UpdateProviderKeyRequest":{"type":"object","properties":{"api_key":{"type":["string","null"]},"base_url":{"type":["string","null"],"description":"Double-Option: absent = leave unchanged, present-null = clear (revert to\nthe provider's default endpoint), present-value = set."},"default_model":{"type":["string","null"],"description":"Double-Option: absent = leave unchanged, present-null = clear the pinned\nmodel (revert to the per-provider default), present-value = set."},"display_name":{"type":["string","null"]},"is_active":{"type":["boolean","null"]}}},"UpdateProviderRequest":{"type":"object","properties":{"config":{},"enabled":{"type":["boolean","null"]},"name":{"type":["string","null"]}}},"UpdateRouteRequest":{"type":"object","required":["host","port","enabled"],"properties":{"enabled":{"type":"boolean"},"host":{"type":"string"},"port":{"type":"integer","format":"int32"},"route_type":{"type":["string","null"],"description":"Route type: \"http\" (default) matches on HTTP Host header,\n\"tls\" matches on TLS SNI hostname for TCP passthrough"}}},"UpdateS3SourceRequest":{"type":"object","properties":{"access_key_id":{"type":["string","null"],"description":"Optional new access key ID","example":"AKIAXXXXXXXXXXXXXXXX"},"bucket_name":{"type":["string","null"],"description":"Optional new bucket name"},"bucket_path":{"type":["string","null"],"description":"Optional new bucket path"},"endpoint":{"type":["string","null"],"description":"Optional new endpoint URL for S3-compatible services","example":"http://minio.example.com:9000"},"force_path_style":{"type":["boolean","null"],"description":"Optional new path-style addressing setting","example":true},"name":{"type":["string","null"],"description":"Optional new name for the source"},"region":{"type":["string","null"],"description":"Optional new region"},"secret_key":{"type":["string","null"],"description":"Optional new secret key"}}},"UpdateSecretBody":{"type":"object","required":["signing_secret"],"properties":{"signing_secret":{"type":"string","description":"New signing secret from the provider's dashboard. Encrypted at\nrest; never returned in any API response."}}},"UpdateSelfRequest":{"type":"object","properties":{"email":{"type":["string","null"],"example":"john.doe@example.com"},"name":{"type":["string","null"],"example":"John Doe"}}},"UpdateSessionDurationRequest":{"type":"object","required":["duration"],"properties":{"duration":{"type":"integer","format":"int32"}}},"UpdateSessionDurationResponse":{"type":"object","required":["message"],"properties":{"message":{"type":"string"}}},"UpdateSkillRequest":{"type":"object","properties":{"content":{"type":["string","null"]},"description":{"type":["string","null"]},"name":{"type":["string","null"]}}},"UpdateSlackProviderRequest":{"type":"object","required":["config"],"properties":{"config":{"$ref":"#/components/schemas/SlackConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":["string","null"]}}},"UpdateSpeedMetricsPayload":{"type":"object","description":"Update speed metrics payload for late-loading metrics","properties":{"cls":{"type":["number","null"],"format":"float","description":"Cumulative Layout Shift (score)"},"inp":{"type":["number","null"],"format":"float","description":"Interaction to Next Paint (milliseconds)"}}},"UpdateStatusResponse":{"type":"object","description":"Result of the background release-update check, driving the web console's\nupgrade banner. All optional fields are set together iff\n`update_available` is true.","required":["update_available","docs_url"],"properties":{"channel":{"type":["string","null"],"description":"Channel the install tracks: `stable` or `beta`."},"checked_at":{"type":["string","null"],"description":"When the check that found the update ran (ISO 8601, UTC)."},"current_version":{"type":["string","null"],"description":"Version tag of the running binary, e.g. `v0.1.0-beta.45`."},"docs_url":{"type":"string","description":"Docs page with upgrade instructions. Always present so the UI links\nthe same page regardless of update state."},"latest_version":{"type":["string","null"],"description":"Newest published tag on this install's channel."},"release_url":{"type":["string","null"],"description":"Release-notes page (GitHub release) for the newer version."},"update_available":{"type":"boolean","description":"True when a newer release than the running binary has been published\non this install's channel."}}},"UpdateTeamRequest":{"type":"object","properties":{"description":{"type":["string","null"]},"name":{"type":["string","null"]}}},"UpdateTokenRequest":{"type":"object","required":["access_token"],"properties":{"access_token":{"type":"string"},"refresh_token":{"type":["string","null"]}}},"UpdateTokenResponse":{"type":"object","required":["connection_id","message","is_active"],"properties":{"connection_id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"message":{"type":"string"}}},"UpdateUserRequest":{"type":"object","properties":{"email":{"type":["string","null"],"example":"john.doe@example.com"},"name":{"type":["string","null"],"example":"John Doe"}}},"UpdateWebhookProviderRequest":{"type":"object","required":["config"],"properties":{"config":{"$ref":"#/components/schemas/WebhookConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":["string","null"]}}},"UpdateWebhookRequestBody":{"type":"object","properties":{"enabled":{"type":["boolean","null"],"description":"Whether the webhook is enabled"},"events":{"type":["array","null"],"items":{"type":"string"},"description":"Event types to subscribe to"},"secret":{"type":["string","null"],"description":"Secret for HMAC signature verification"},"url":{"type":["string","null"],"description":"Target URL for webhook delivery"}}},"UpgradeExternalServiceRequest":{"type":"object","required":["docker_image"],"properties":{"docker_image":{"type":"string","description":"Docker image to upgrade to (e.g., \"gotempsh/postgres-walg:18-bookworm\")\nThis will trigger pg_upgrade for PostgreSQL or equivalent upgrade procedures for other services","example":"gotempsh/postgres-walg:18-bookworm"}}},"UpgradeRequest":{"type":"object","required":["image"],"properties":{"image":{"type":"string","description":"Image reference to pull and run (e.g.\n`ghcr.io/gotempsh/temps-preview-gateway:latest`). Empty resets to default."}}},"UpsertAgentRequest":{"type":"object","properties":{"ai_model":{"type":["string","null"],"description":"Preferred model identifier for the CLI. `Some(\"\")` clears the stored value."},"ai_provider":{"type":["string","null"]},"ai_provider_key_id":{"type":["integer","null"],"format":"int32"},"api_key":{"type":["string","null"],"description":"Plain-text API key — will be encrypted before storage"},"branch_prefix":{"type":["string","null"]},"config_repo_branch":{"type":["string","null"],"description":"Branch of the config repo to use (default: \"main\")."},"config_repo_url":{"type":["string","null"],"description":"Private config repo containing .claude/ directory (skills, MCP, plugins)."},"cooldown_minutes":{"type":["integer","null"],"format":"int32"},"daily_budget_cents":{"type":["integer","null"],"format":"int32"},"deliverable":{"type":["string","null"]},"description":{"type":["string","null"]},"enabled":{"type":["boolean","null"]},"max_turns":{"type":["integer","null"],"format":"int32"},"mcp_servers_config":{"description":"MCP servers config (Claude Code settings.json mcpServers format).\nCredential-bearing legacy inline objects are write-only: normal reads\nmask them, and updates must omit this field to preserve existing values."},"name":{"type":["string","null"]},"prompt":{"type":["string","null"]},"sandbox_enabled":{"type":["boolean","null"]},"skills_config":{"description":"Skills config as JSON array."},"slug":{"type":["string","null"]},"timeout_seconds":{"type":["integer","null"],"format":"int32"},"tools_config":{"description":"Tools config as JSON array. Custom-tool webhook URLs and headers are\nwrite-only; omit this field on update to preserve them."},"trigger_config":{"description":"Trigger configuration JSON: { \"error\": { \"new_issue\": true, \"regression\": true }, \"manual\": true }"}}},"UpsertSecretRequest":{"type":"object","required":["name","value"],"properties":{"description":{"type":["string","null"]},"mount_path":{"type":["string","null"],"description":"Required for \"file\" type secrets — absolute path inside the sandbox"},"name":{"type":"string"},"secret_type":{"type":"string","description":"\"env\" (environment variable) or \"file\" (written to mount_path)"},"value":{"type":"string"}}},"UptimeDataPoint":{"type":"object","required":["timestamp","status"],"properties":{"error_message":{"type":["string","null"]},"response_time_ms":{"type":["integer","null"],"format":"int32"},"status":{"type":"string"},"timestamp":{"type":"string","format":"date-time"}}},"UptimeHistoryResponse":{"type":"object","required":["monitor_id","uptime_data"],"properties":{"monitor_id":{"type":"integer","format":"int32"},"uptime_data":{"type":"array","items":{"$ref":"#/components/schemas/UptimeDataPoint"}}}},"UsageFilter":{"type":"object","description":"Filters for querying AI usage data.\n\nCost bounds are expressed in microcents (the unit stored in\n`estimated_cost_microcents`). At most one of `gte`/`gt` and one of\n`lte`/`lt` is meaningful per query; if both are set the stricter wins\nnaturally because they are ANDead together.","properties":{"conversation_id":{"type":["string","null"]},"cost_gt":{"type":["integer","null"],"format":"int64","description":"Cost strictly greater-than, in microcents."},"cost_gte":{"type":["integer","null"],"format":"int64","description":"Cost greater-than-or-equal, in microcents."},"cost_lt":{"type":["integer","null"],"format":"int64","description":"Cost strictly less-than, in microcents."},"cost_lte":{"type":["integer","null"],"format":"int64","description":"Cost less-than-or-equal, in microcents."},"model":{"type":["string","null"]},"provider":{"type":["string","null"]},"status":{"type":["integer","null"],"format":"int32","description":"Filter by HTTP status code (exact match)."},"tags":{"type":["string","null"],"description":"Comma-separated tags to filter by (AND logic)."},"tokens_gt":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) strictly greater-than."},"tokens_gte":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) greater-than-or-equal."},"tokens_lt":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) strictly less-than."},"tokens_lte":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) less-than-or-equal."},"user_id":{"type":["integer","null"],"format":"int32"}}},"UsageInfo":{"type":"object","required":["prompt_tokens","completion_tokens","total_tokens"],"properties":{"completion_tokens":{"type":"integer","format":"int64"},"prompt_tokens":{"type":"integer","format":"int64"},"total_tokens":{"type":"integer","format":"int64"}}},"UsageLogEntry":{"type":"object","required":["id","timestamp","provider","model","input_tokens","output_tokens","latency_ms","estimated_cost_microcents","status","is_streaming","is_byok","tags"],"properties":{"conversation_id":{"type":["string","null"]},"estimated_cost_microcents":{"type":"integer","format":"int64"},"id":{"type":"integer","format":"int64"},"input_tokens":{"type":"integer","format":"int64"},"is_byok":{"type":"boolean"},"is_streaming":{"type":"boolean"},"latency_ms":{"type":"integer","format":"int32"},"model":{"type":"string"},"output_tokens":{"type":"integer","format":"int64"},"provider":{"type":"string"},"request_id":{"type":["string","null"]},"status":{"type":"integer","format":"int32"},"tags":{"type":"array","items":{"type":"string"}},"timestamp":{"type":"string"},"trace_id":{"type":["string","null"]}}},"UsageLogPage":{"type":"object","description":"A page of recent usage log entries plus the total count for pagination.","required":["entries","total"],"properties":{"entries":{"type":"array","items":{"$ref":"#/components/schemas/UsageLogEntry"},"description":"The usage log entries for the requested page."},"total":{"type":"integer","format":"int64","description":"Total number of entries matching the filter (across all pages)."}}},"UsageQueryParams":{"type":"object","properties":{"conversation_id":{"type":["string","null"],"description":"Filter by conversation ID"},"from":{"type":["string","null"],"description":"ISO 8601 start time (defaults to 24h ago)"},"model":{"type":["string","null"],"description":"Filter by model name"},"provider":{"type":["string","null"],"description":"Filter by provider name"},"tags":{"type":["string","null"],"description":"Filter by tags (comma-separated, AND logic)"},"to":{"type":["string","null"],"description":"ISO 8601 end time (defaults to now)"},"user_id":{"type":["integer","null"],"format":"int32","description":"Filter by user ID"}}},"UsageSource":{"type":"string","description":"How the \"actual usage\" numbers were obtained","enum":["metrics-api","requests-only","unavailable"]},"UsageSummary":{"type":"object","required":["total_requests","total_input_tokens","total_output_tokens","total_tokens","avg_latency_ms","total_cost_microcents","error_count","streaming_count","byok_count"],"properties":{"avg_latency_ms":{"type":"number","format":"double"},"byok_count":{"type":"integer","format":"int64"},"error_count":{"type":"integer","format":"int64"},"streaming_count":{"type":"integer","format":"int64"},"total_cost_microcents":{"type":"integer","format":"int64"},"total_input_tokens":{"type":"integer","format":"int64"},"total_output_tokens":{"type":"integer","format":"int64"},"total_requests":{"type":"integer","format":"int64"},"total_tokens":{"type":"integer","format":"int64"}}},"UserResponse":{"type":"object","required":["id","username","name","avatar_url","mfa_enabled","role"],"properties":{"avatar_url":{"type":"string"},"email":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"mfa_enabled":{"type":"boolean"},"name":{"type":"string"},"role":{"type":"string","description":"User's role (e.g., \"admin\", \"user\", \"demo\")"},"username":{"type":"string"}}},"ValidateEmailRequest":{"type":"object","description":"Request body for validating an email address","required":["email"],"properties":{"email":{"type":"string","description":"Email address to validate","example":"someone@gmail.com"}},"additionalProperties":false},"ValidateEmailResponse":{"type":"object","description":"Complete email validation response","required":["email","is_reachable","syntax","mx","misc","smtp"],"properties":{"email":{"type":"string","description":"The email address that was validated","example":"someone@gmail.com"},"is_reachable":{"$ref":"#/components/schemas/ReachabilityStatus","description":"Overall reachability status: safe, risky, invalid, or unknown"},"misc":{"$ref":"#/components/schemas/MiscResult","description":"Miscellaneous validation result"},"mx":{"$ref":"#/components/schemas/MxResult","description":"MX record validation result"},"smtp":{"$ref":"#/components/schemas/SmtpResult","description":"SMTP validation result"},"syntax":{"$ref":"#/components/schemas/SyntaxResult","description":"Syntax validation result"}}},"ValidationLevel":{"type":"string","description":"Validation severity level","enum":["info","warning","error","critical"]},"ValidationReport":{"type":"object","description":"Complete validation report","required":["results","overall_status","summary"],"properties":{"overall_status":{"$ref":"#/components/schemas/ValidationStatus","description":"Overall status"},"results":{"type":"array","items":{"$ref":"#/components/schemas/ValidationResult"},"description":"All validation results"},"summary":{"$ref":"#/components/schemas/ValidationSummary","description":"Summary statistics"}}},"ValidationResponse":{"type":"object","required":["connection_id","is_valid","message"],"properties":{"connection_id":{"type":"integer","format":"int32"},"is_valid":{"type":"boolean"},"message":{"type":"string"}}},"ValidationResult":{"type":"object","description":"Result of a validation check","required":["rule_id","rule_name","level","passed","message","affected_resources"],"properties":{"affected_resources":{"type":"array","items":{"type":"string"},"description":"Affected resources/fields"},"level":{"$ref":"#/components/schemas/ValidationLevel","description":"Validation level"},"message":{"type":"string","description":"Message describing the result"},"passed":{"type":"boolean","description":"Whether the validation passed"},"remediation":{"type":["string","null"],"description":"Suggested remediation (if failed)"},"rule_id":{"type":"string","description":"Rule that was checked"},"rule_name":{"type":"string","description":"Human-readable rule name"}}},"ValidationStatus":{"type":"string","description":"Overall validation status","enum":["passed","passed-with-warnings","failed-with-warnings","failed"]},"ValidationSummary":{"type":"object","description":"Validation summary statistics","required":["total_count","passed_count","failed_count","info_count","warning_count","error_count","critical_count"],"properties":{"critical_count":{"type":"integer","description":"Critical-level results","minimum":0},"error_count":{"type":"integer","description":"Error-level results","minimum":0},"failed_count":{"type":"integer","description":"Validations that failed","minimum":0},"info_count":{"type":"integer","description":"Info-level results","minimum":0},"passed_count":{"type":"integer","description":"Validations that passed","minimum":0},"total_count":{"type":"integer","description":"Total validations run","minimum":0},"warning_count":{"type":"integer","description":"Warning-level results","minimum":0}}},"VerifyMfaRequest":{"type":"object","required":["code"],"properties":{"code":{"type":"string"}}},"VerifyStepUpRequest":{"type":"object","required":["code"],"properties":{"code":{"type":"string","description":"Current TOTP value or an unused recovery code."}}},"ViewItem":{"type":"object","required":["label","value"],"properties":{"label":{"type":"string","format":"date-time"},"value":{"type":"integer","format":"int64"}}},"ViewsOverTime":{"type":"object","required":["items","metric","present_index"],"properties":{"comparison_labels":{"type":["array","null"],"items":{"type":"string"}},"comparison_plot":{"type":["array","null"],"items":{"type":"integer","format":"int64"}},"full_intervals":{"type":["array","null"],"items":{"type":"string"}},"items":{"type":"array","items":{"$ref":"#/components/schemas/ViewItem"}},"metric":{"type":"string"},"present_index":{"type":"integer","minimum":0}}},"ViewsOverTimeQuery":{"type":"object","required":["start_date","end_date","project_id"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"VisitorDetails":{"type":"object","required":["id","visitor_id","project_id","environment_id","first_seen","last_seen","is_crawler"],"properties":{"city":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"crawler_name":{"type":["string","null"]},"custom_data":{},"environment_id":{"type":"integer","format":"int32"},"first_channel":{"type":["string","null"],"description":"Marketing channel from the first visit (e.g. \"Organic Search\", \"Direct\")"},"first_referrer":{"type":["string","null"],"description":"Full referrer URL from the visitor's first session"},"first_referrer_hostname":{"type":["string","null"],"description":"Hostname extracted from first_referrer"},"first_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"id":{"type":"integer","format":"int32"},"ip_address":{"type":["string","null"]},"ip_address_id":{"type":["integer","null"],"format":"int32"},"is_crawler":{"type":"boolean"},"is_eu":{"type":["boolean","null"]},"last_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"latitude":{"type":["number","null"],"format":"double"},"longitude":{"type":["number","null"],"format":"double"},"project_id":{"type":"integer","format":"int32"},"region":{"type":["string","null"]},"timezone":{"type":["string","null"]},"user_agent":{"type":["string","null"]},"visitor_id":{"type":"string"}}},"VisitorFacetValue":{"type":"object","description":"A single facet value with its visitor count. Used to populate filter\ndropdowns on the visitors page (e.g. \"Germany — 1,234 visitors\").","required":["value","count"],"properties":{"code":{"type":["string","null"],"description":"Optional secondary code for the value. Currently only populated for\nthe `country` facet, where it carries the 2-letter ISO country code\nso the UI can render a flag without re-mapping."},"count":{"type":"integer","format":"int64","description":"Distinct visitor count matching this value in the current segment."},"value":{"type":"string","description":"The dimension value (e.g. \"United States\", \"Chrome\", \"google.com\").\n`None` is encoded as the literal string \"Direct\" for referrer and as\nthe empty string for the rest."}}},"VisitorFacets":{"type":"object","description":"All filter dropdown contents in one response. Each list is the top N\nvalues for that dimension within the current date range and segment\n(excluding the dimension being queried so the dropdown still shows\nalternatives when a value is already selected).","required":["country","region","city","channel","referrer"],"properties":{"channel":{"type":"array","items":{"$ref":"#/components/schemas/VisitorFacetValue"}},"city":{"type":"array","items":{"$ref":"#/components/schemas/VisitorFacetValue"}},"country":{"type":"array","items":{"$ref":"#/components/schemas/VisitorFacetValue"}},"referrer":{"type":"array","items":{"$ref":"#/components/schemas/VisitorFacetValue"}},"region":{"type":"array","items":{"$ref":"#/components/schemas/VisitorFacetValue"}}}},"VisitorFacetsQuery":{"allOf":[{"$ref":"#/components/schemas/VisitorSegmentFilters"},{"type":"object","required":["start_date","end_date","project_id"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"has_activity_only":{"type":["boolean","null"]},"include_crawlers":{"type":["boolean","null"]},"per_facet_limit":{"type":["integer","null"],"format":"int32","description":"Maximum number of values returned per dimension (default: 50, max: 200)."},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}}],"description":"Query parameters for the visitor-facets endpoint. Mirrors the shape of\n`VisitorsListQuery` so the same segment filters apply — facet counts are\nalways computed against the *currently filtered* visitor pool, minus the\ndimension being aggregated."},"VisitorInfo":{"type":"object","required":["id","visitor_id","project_id","environment_id","first_seen","last_seen","is_crawler"],"properties":{"city":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"crawler_name":{"type":["string","null"]},"current_page":{"type":["string","null"],"description":"Most recent page path visited by this visitor"},"custom_data":{},"environment_id":{"type":"integer","format":"int32"},"first_channel":{"type":["string","null"],"description":"Marketing channel from the first visit (e.g. \"Organic Search\", \"Direct\")"},"first_referrer":{"type":["string","null"],"description":"Full referrer URL from the visitor's first session"},"first_referrer_hostname":{"type":["string","null"],"description":"Hostname extracted from first_referrer"},"first_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"id":{"type":"integer","format":"int32"},"ip_address":{"type":["string","null"]},"ip_address_id":{"type":["integer","null"],"format":"int32"},"is_crawler":{"type":"boolean"},"is_eu":{"type":["boolean","null"]},"last_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"latitude":{"type":["number","null"],"format":"double"},"longitude":{"type":["number","null"],"format":"double"},"project_id":{"type":"integer","format":"int32"},"region":{"type":["string","null"]},"timezone":{"type":["string","null"]},"user_agent":{"type":["string","null"]},"visitor_id":{"type":"string"}}},"VisitorJourneyQuery":{"type":"object","required":["project_id"],"properties":{"limit_sessions":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"}}},"VisitorJourneyResponse":{"type":"object","description":"Complete visitor journey response","required":["visitor_id","total_sessions","total_events","sessions"],"properties":{"sessions":{"type":"array","items":{"$ref":"#/components/schemas/JourneySession"},"description":"Sessions with their events, ordered newest first"},"total_events":{"type":"integer","format":"int64","description":"Total number of events across all sessions"},"total_sessions":{"type":"integer","format":"int64","description":"Total number of sessions"},"visitor_id":{"type":"integer","format":"int32","description":"Visitor internal ID"}}},"VisitorLocationsQuery":{"type":"object","required":["start_date","end_date","project_id"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"granularity":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/LocationGranularity"}]},"limit":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"VisitorRecord":{"type":"object","required":["id","visitor_id","project_id","created_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"custom_data":{},"id":{"type":"integer","format":"int32"},"project_id":{"type":"integer","format":"int32"},"visitor_id":{"type":"string"}}},"VisitorSegmentFilters":{"type":"object","description":"Optional segment filters for [`VisitorsListQuery`]. Each filter narrows the\nresult set to visitors who match the given dimension value within the date\nrange. All filters resolve against `visitor` / `ip_geolocations` — by\ndesign we never touch the events hypertable here so filtering stays fast\nregardless of event volume.","properties":{"filter_channel":{"type":["string","null"],"description":"First-touch marketing channel (matches `visitor.first_channel`)"},"filter_city":{"type":["string","null"],"description":"Geolocation city (matches `ip_geolocations.city`)"},"filter_country":{"type":["string","null"],"description":"Geolocation country (matches `ip_geolocations.country`)"},"filter_referrer":{"type":["string","null"],"description":"First-touch referrer hostname (matches `visitor.first_referrer_hostname`)"},"filter_region":{"type":["string","null"],"description":"Geolocation region (matches `ip_geolocations.region`)"}}},"VisitorSessionsQuery":{"type":"object","required":["project_id"],"properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"}}},"VisitorSessionsResponse":{"type":"object","required":["visitor_id","sessions","total_sessions"],"properties":{"sessions":{"type":"array","items":{"$ref":"#/components/schemas/SessionSummary"}},"total_sessions":{"type":"integer","format":"int64"},"visitor_id":{"type":"string"}}},"VisitorStats":{"type":"object","required":["visitor_id","first_seen","last_seen","total_sessions","total_page_views","total_events","average_session_duration","bounce_rate","engagement_rate","top_pages","top_referrers","devices_used","locations"],"properties":{"average_session_duration":{"type":"number","format":"double"},"bounce_rate":{"type":"number","format":"double"},"devices_used":{"type":"array","items":{"type":"string"}},"engagement_rate":{"type":"number","format":"double"},"first_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"last_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"locations":{"type":"array","items":{"$ref":"#/components/schemas/LocationInfo"}},"top_pages":{"type":"array","items":{"$ref":"#/components/schemas/PageVisit"}},"top_referrers":{"type":"array","items":{"type":"string"}},"total_events":{"type":"integer","format":"int64"},"total_page_views":{"type":"integer","format":"int64"},"total_sessions":{"type":"integer","format":"int64"},"visitor_id":{"type":"integer","format":"int32"}}},"VisitorWithGeolocation":{"type":"object","required":["id","visitor_id","project_id","environment_id","first_seen","last_seen","is_crawler"],"properties":{"city":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"crawler_name":{"type":["string","null"]},"custom_data":{},"environment_id":{"type":"integer","format":"int32"},"first_channel":{"type":["string","null"],"description":"Marketing channel from the first visit (e.g. \"Organic Search\", \"Direct\")"},"first_referrer":{"type":["string","null"],"description":"Full referrer URL from the visitor's first session"},"first_referrer_hostname":{"type":["string","null"],"description":"Hostname extracted from first_referrer"},"first_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"id":{"type":"integer","format":"int32"},"ip_address":{"type":["string","null"]},"is_crawler":{"type":"boolean"},"is_eu":{"type":["boolean","null"]},"last_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"latitude":{"type":["number","null"],"format":"double"},"longitude":{"type":["number","null"],"format":"double"},"project_id":{"type":"integer","format":"int32"},"region":{"type":["string","null"]},"timezone":{"type":["string","null"]},"user_agent":{"type":["string","null"]},"visitor_id":{"type":"string"}}},"VisitorsListQuery":{"allOf":[{"$ref":"#/components/schemas/VisitorSegmentFilters"},{"type":"object","required":["start_date","end_date","project_id"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"has_activity_only":{"type":["boolean","null"],"description":"Filter to only include visitors with recorded activity (events/sessions).\nWhen true, excludes \"ghost\" visitors that have no events."},"include_crawlers":{"type":["boolean","null"]},"limit":{"type":["integer","null"],"format":"int32"},"offset":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}}]},"VisitorsResponse":{"type":"object","required":["visitors","total_count","filtered_count"],"properties":{"filtered_count":{"type":"integer","format":"int64"},"total_count":{"type":"integer","format":"int64"},"visitors":{"type":"array","items":{"$ref":"#/components/schemas/VisitorInfo"}}}},"VolumeMount":{"type":"object","description":"Volume mount in deployment","required":["source","destination","read_only","type"],"properties":{"destination":{"type":"string","description":"Destination path in container"},"read_only":{"type":"boolean","description":"Read-only flag"},"source":{"type":"string","description":"Source (volume name or path)"},"type":{"$ref":"#/components/schemas/VolumeType","description":"Volume type"}}},"VolumeType":{"type":"string","description":"Volume type","enum":["bind","volume","tmpfs"]},"VulnerabilityResponse":{"type":"object","required":["id","scan_id","vulnerability_id","package_name","installed_version","severity","title","created_at"],"properties":{"class":{"type":["string","null"],"example":"os-pkgs"},"created_at":{"type":"string","example":"2025-12-08T12:15:47.609192Z"},"cvss_score":{"type":["number","null"],"format":"float"},"description":{"type":["string","null"]},"fixed_version":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"installed_version":{"type":"string"},"last_modified_date":{"type":["string","null"],"example":"2025-12-08T12:15:47.609192Z"},"package_name":{"type":"string"},"primary_url":{"type":["string","null"]},"published_date":{"type":["string","null"],"example":"2025-12-08T12:15:47.609192Z"},"references":{},"scan_id":{"type":"integer","format":"int32"},"severity":{"type":"string"},"target":{"type":["string","null"],"example":"alpine:3.18 (alpine 3.18.0)"},"title":{"type":"string"},"type":{"type":["string","null"],"example":"alpine"},"vulnerability_id":{"type":"string"}}},"WalWarning":{"oneOf":[{"type":"object","description":"`pg_wal` is significantly larger than `max_wal_size`.","required":["pg_wal_bytes","max_wal_size_bytes","ratio","kind"],"properties":{"kind":{"type":"string","enum":["wal_bloat"]},"max_wal_size_bytes":{"type":"integer","format":"int64"},"pg_wal_bytes":{"type":"integer","format":"int64"},"ratio":{"type":"number","format":"double"}}},{"type":"object","description":"A replication slot is holding WAL it's not consuming.","required":["slot_name","retained_bytes","active","kind"],"properties":{"active":{"type":"boolean"},"kind":{"type":"string","enum":["stale_slot"]},"retained_bytes":{"type":"integer","format":"int64"},"slot_name":{"type":"string"}}},{"type":"object","description":"`archive_status/*.ready` count exceeds threshold — `archive_command`\nis either failing or running slower than WAL generation.","required":["ready_count","kind"],"properties":{"kind":{"type":"string","enum":["archive_backlog"]},"ready_count":{"type":"integer","format":"int64"}}},{"type":"object","description":"`archive_mode = on` but `archive_command` is empty / `/bin/true`.\nWAL accumulates forever waiting for a destination that never accepts.","required":["kind"],"properties":{"kind":{"type":"string","enum":["archive_mode_without_command"]}}},{"type":"object","description":"Oldest WAL segment is older than `WAL_NOT_RECYCLED_AGE_SECS`.\nIndependent signal: something is blocking recycling even if total\nsize hasn't exploded yet.","required":["oldest_age_secs","kind"],"properties":{"kind":{"type":"string","enum":["wal_not_recycled"]},"oldest_age_secs":{"type":"integer","format":"int64"}}}],"description":"One actionable warning surfaced to the UI.\n\nEach variant carries the data needed to render a remediation hint without\nthe frontend re-querying anything."},"WalWarningSeverity":{"type":"string","enum":["warning","critical"]},"WebhookConfig":{"type":"object","description":"Configuration for a generic webhook notification provider","required":["url"],"properties":{"headers":{"type":"object","description":"Custom headers to include in the request (e.g., for authentication tokens)","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"},"example":{"Authorization":"Bearer your-token","X-Custom-Header":"custom-value"}},"method":{"type":"string","description":"HTTP method to use (POST, PUT, PATCH). Defaults to POST.","example":"POST"},"timeout_secs":{"type":"integer","format":"int64","description":"Request timeout in seconds. Defaults to 30.","example":30,"minimum":0},"url":{"type":"string","description":"The URL to send webhook requests to","example":"https://api.example.com/notifications"}}},"WebhookDeliveryResponse":{"type":"object","required":["id","webhook_id","event_type","event_id","payload","success","attempt_number","created_at"],"properties":{"attempt_number":{"type":"integer","format":"int32"},"created_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"delivered_at":{"type":["string","null"],"format":"date-time"},"error_message":{"type":["string","null"]},"event_id":{"type":"string"},"event_type":{"type":"string"},"id":{"type":"integer","format":"int32"},"payload":{"type":"string","description":"JSON payload that was sent to the webhook endpoint","example":{"event_type":"deployment.succeeded","data":{"deployment_id":123}}},"status_code":{"type":["integer","null"],"format":"int32"},"success":{"type":"boolean"},"webhook_id":{"type":"integer","format":"int32"}}},"WebhookResponse":{"type":"object","required":["id","project_id","url","events","enabled","has_secret","created_at","updated_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"enabled":{"type":"boolean"},"events":{"type":"array","items":{"type":"string"}},"has_secret":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"project_id":{"type":"integer","format":"int32"},"updated_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"url":{"type":"string"}}},"WebhookTriggerRequest":{"allOf":[{"description":"Arbitrary JSON payload from the caller. Passed to the agent as user_context."}]},"WebhookTriggerResponse":{"type":"object","required":["run_id","status"],"properties":{"run_id":{"type":"integer","format":"int32"},"status":{"type":"string"}}},"WorkflowDryRunRequest":{"type":"object","required":["yaml"],"properties":{"cpu_limit":{"type":["number","null"],"format":"double","description":"Optional CPU override applied after parsing YAML (clamped server-side).\nWhen `Some`, this takes precedence over `cpu_limit` inside the YAML —\nlets the CLI pass `--cpu` without rewriting the YAML text."},"error_group_id":{"type":["integer","null"],"format":"int32","description":"Optional error group to link this dry-run to. When set, the executor's\n`load_error_context` path injects `{{error_type}}` / `{{error_message}}`\n/ `{{stack_trace}}` into the prompt — same behaviour as a committed\nworkflow triggered with `trigger_source_type = \"error_group\"`. Must\nbelong to `project_id` (handler enforces)."},"memory_limit_mb":{"type":["integer","null"],"format":"int64","description":"Optional memory override in MB (clamped server-side). Same precedence\nrule as `cpu_limit`.","minimum":0},"user_context":{"type":["string","null"],"description":"Optional context appended to the prompt (e.g. \"test against staging\nonly\"). Mirrors `TriggerAgentRequest.user_context`."},"yaml":{"type":"string","description":"Full WorkflowYamlConfig as YAML text. Server validates and re-serializes\nbefore storing on the run row."}}},"WorkloadDescriptor":{"type":"object","description":"Brief descriptor for discovered workloads (used in listing)","required":["id","workload_type","status","labels"],"properties":{"created_at":{"type":["string","null"],"format":"date-time","description":"Creation timestamp"},"id":{"$ref":"#/components/schemas/WorkloadId","description":"Unique ID in source system"},"image":{"type":["string","null"],"description":"Image/build reference (for containers)"},"labels":{"type":"object","description":"Labels/tags from source system","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"name":{"type":["string","null"],"description":"Workload name (if any)"},"status":{"$ref":"#/components/schemas/WorkloadStatus","description":"Current status"},"workload_type":{"$ref":"#/components/schemas/WorkloadType","description":"Workload type (container, function, static-site, etc.)"}}},"WorkloadId":{"type":"string","description":"Unique identifier for a workload in the source system"},"WorkloadStatus":{"type":"string","description":"Workload status in source system","enum":["running","paused","stopped","exited","failed","deployed","building","unknown"]},"WorkloadType":{"type":"string","description":"Workload type","enum":["container","function","static-site","server-side-app","worker","database","message-queue","cache","cron-job","other"]},"WriteFileBody":{"type":"object","required":["path","contents_b64"],"properties":{"contents_b64":{"type":"string","description":"File contents, base64-encoded. Required — lets callers ship binary\ndata over JSON without charset games."},"mode":{"type":["integer","null"],"format":"int32","description":"Unix permission mask (e.g. 0o644). Defaults to 0o644 when absent.","minimum":0},"path":{"type":"string","description":"Absolute path inside the sandbox. Must start with `/`."}},"additionalProperties":false},"WriteFilesBody":{"type":"object","required":["files"],"properties":{"files":{"type":"array","items":{"$ref":"#/components/schemas/WriteFileBody"},"description":"List of files to write. Each entry must include an absolute\n`path` and base64-encoded `contents_b64`. Empty list is a no-op."}},"additionalProperties":false},"WriteFilesResponse":{"type":"object","required":["written"],"properties":{"written":{"type":"integer","description":"Number of files successfully written before the first failure\n(if any). On full success this equals `files.len()`.","minimum":0}}},"ZoneListResponse":{"type":"object","description":"Zone list response","required":["zones"],"properties":{"zones":{"type":"array","items":{"$ref":"#/components/schemas/DnsZone"}}}}},"securitySchemes":{"bearer_auth":{"type":"http","scheme":"bearer","description":"Bearer token authentication. Use format: `Bearer `. Supports API keys (starting with `tk_`), CLI tokens, and session tokens."}}},"tags":[{"name":"Events","description":"Analytics events tracking endpoints"},{"name":"Metrics","description":"Analytics metrics collection endpoints including performance web vitals"},{"name":"Funnels","description":"Funnel management endpoints"},{"name":"Analytics","description":"Analytics and session replay management"},{"name":"Performance","description":"Performance metrics management"},{"name":"geo","description":"Geolocation API endpoints"},{"name":"Platform","description":"Platform information and compatibility"},{"name":"Teams","description":"Teams and project-scoped access"},{"name":"Git Providers","description":"Git provider management endpoints"},{"name":"Repositories","description":"Repository management endpoints"},{"name":"Public Repositories","description":"Endpoints for accessing public repositories without authentication. Supports GitHub and GitLab."},{"name":"Notification Providers","description":"Notification provider management endpoints"},{"name":"Notification Preferences","description":"User notification preferences and settings"},{"name":"DNS Providers","description":"DNS provider management endpoints"},{"name":"Internal DNS","description":"Per-node DNS resolver sync (ADR-011)"},{"name":"Domains","description":"Domain management endpoints"},{"name":"Email Providers","description":"Email provider management endpoints"},{"name":"Email Domains","description":"Email domain management and verification"},{"name":"Emails","description":"Email sending and retrieval"},{"name":"Email Tracking","description":"Email open and click tracking"},{"name":"Email Validation","description":"Email address validation and verification"},{"name":"Webhooks","description":"Webhook management endpoints"},{"name":"Webhook Deliveries","description":"Webhook delivery history and retry endpoints"},{"name":"External Services","description":"External service integration endpoints"},{"name":"External Services - Query","description":"Data querying and exploration endpoints"},{"name":"Metrics","description":"Time-series metrics and alert rule endpoints"},{"name":"KV Store","description":"Key-Value storage operations"},{"name":"KV Management","description":"KV service management operations"},{"name":"Blob","description":"Blob storage operations"},{"name":"Blob Management","description":"Blob service management operations"},{"name":"Feature Flags","description":"Runtime configuration that changes without a redeploy"},{"name":"Environments","description":"Environment management operations"},{"name":"Secrets","description":"File-mounted secrets (/run/secrets/)"},{"name":"Projects","description":"Project management endpoints"},{"name":"Presets","description":"Available deployment presets"},{"name":"Templates","description":"Project template endpoints"},{"name":"Custom Domains","description":"Custom domain management for projects"},{"name":"error-tracking","description":"Error tracking data fetching endpoints"},{"name":"Vulnerability Scans","description":"Vulnerability scan management endpoints"},{"name":"Agents","description":"Autonomous AI agents, autofixer (interactive AI debugging), skills/MCP definitions, and preview gateway management."},{"name":"Crons","description":"Cron jobs management API"},{"name":"Sandboxes","description":"Standalone sandbox API (`/v1/sandboxes/*`) for running isolated containers."},{"name":"Logs","description":"Log search, context, live tail, and retention management"},{"name":"Imports","description":"Import workloads from external sources"},{"name":"Status Page","description":"Status page and monitoring endpoints"},{"name":"OTel Ingest","description":"OTLP/HTTP ingest endpoints (protobuf)"},{"name":"OTel","description":"Query endpoints for the monitoring UI"},{"name":"GenAI","description":"GenAI agent activity tracing endpoints"},{"name":"Alarms","description":"Unified alarm history — list, summarise, acknowledge, resolve"},{"name":"Authentication","description":"Authentication and authorization endpoints"},{"name":"Users","description":"User management endpoints"},{"name":"Backups","description":"Backup management endpoints"},{"name":"Restore","description":"External service restore operations"},{"name":"Revenue","description":"Per-project revenue tracking integrations and analytics"},{"name":"Observability","description":"Unified observability event stream — runtime logs, requests, spans, errors, revenue"},{"name":"AI Gateway","description":"OpenAI-compatible chat, embeddings, and model endpoints"},{"name":"AI Gateway Admin","description":"Provider key management endpoints"},{"name":"AI Gateway Usage","description":"Usage analytics and reporting endpoints"},{"name":"AI Gateway Pricing","description":"Model pricing endpoints"},{"name":"API Keys","description":"API key management endpoints"},{"name":"Load Balancer","description":"Load balancer management endpoints"},{"name":"IP Access Control","description":"IP access control management endpoints"},{"name":"Files","description":"Static file serving endpoints"},{"name":"External Plugins","description":"External plugin management and discovery"}]} diff --git a/apps/temps-cli/src/api/index.ts b/apps/temps-cli/src/api/index.ts index f4db984ac..d17e13d8a 100644 --- a/apps/temps-cli/src/api/index.ts +++ b/apps/temps-cli/src/api/index.ts @@ -1,4 +1,4 @@ // This file is auto-generated by @hey-api/openapi-ts -export { acknowledgeAlarm, activateAiProvider, activateApiKey, activateConnection, activateProvider, addClusterMember, addContext, addEnvironmentDomain, addEvents, addManagedDomain, addSessionReplayEvents, addTeamMember, adminDrainNode, adminDrainStatus, adminGetNode, adminListNodeContainers, adminListNodes, adminRemoveNode, adminUndrainNode, applyHostnameMode, archiveConversation, archiveFlag, assignRole, attachScheduleServices, blobCopy, blobDelete, blobDisable, blobDownload, blobEnable, blobHead, blobList, blobPut, blobStatus, blobUpdate, cancel, cancelBackup, cancelDeployment, cancelDomainOrder, cancelPgUpgrade, cancelRun, cancelScheduleRun, changePasswordSelf, changeProjectSource, chatCompletions, checkAnalyticsHasEvents, checkCommitExists, checkDomainStatus, checkExplorerSupport, checkIpBlocked, checkProviderDeletionSafety, chunkUploadOptions, cleanupExpiredBackups, clearPreviewPassword, cliDeviceApprove, cliDeviceDeny, cliDeviceLookup, cliDevicePoll, cliDeviceStart, cliLogout, cmd, cmdKill, cmdLogs, confirmPendingAction, containerMetricsGetHistory, createAgent, createAlert, createAlertRule, createApiKey, createBackupSchedule, createBitbucketProvider, createCloudflareProvider, createConversation, createCustomDomain, createDashboard, createDeploymentToken, createDnsProvider, createDomain, createDsn, createEmailDomain, createEmailProvider, createEnvironment, createEnvironmentVariable, createFlag, createFunnel, createGenericProvider, createGiteaPatProvider, createGithubPatProvider, createGitlabOauthProvider, createGitlabPatProvider, createGitProvider, createGlobalMcp, createGlobalSkill, createIncident, createIpAccessControl, createMcp, createMonitor, createNotificationEmailProvider, createNotificationProvider, createOidcProvider, createOidcRoleMapping, createOrRecreateOrder, createPlan, createPr, createProject, createProjectFromTemplate, createProjectRelease, createProjectSecret, createProviderKey, createRelease, createRoute, createS3Source, createSandbox, createService, createSkill, createSlackProvider, createTeam, createUser, createWebhook, createWebhookProvider, deactivateApiKey, deactivateConnection, deactivateProvider, deleteAgent, deleteAlert, deleteAlertRule, deleteApiKey, deleteBackup, deleteBackupSchedule, deleteConnection, deleteCustomDomain, deleteDashboard, deleteDeploymentToken, deleteDnsProvider, deleteDomain, deleteEmailDomain, deleteEmailProvider, deleteEnvironment, deleteEnvironmentDomain, deleteEnvironmentVariable, deleteExternalImage, deleteFunnel, deleteGitProvider, deleteGlobalMcp, deleteGlobalSkill, deleteIpAccessControl, deleteMcp, deleteMonitor, deleteNotificationProvider, deleteOidcProvider, deleteOidcRoleMapping, deletePreferences, deleteProject, deleteProjectSecret, deleteProviderKey, deleteProviderSafely, deleteReleaseSourceFiles, deleteReleaseSourceMaps, deleteRoute, deleteS3Source, deleteScan, deleteSecret, deleteService, deleteSessionReplay, deleteSkill, deleteSourceMap, deleteStaticBundle, deleteTeam, deleteUser, deleteWebhook, deployFromImage, deployFromImageUpload, deployFromStatic, deployFromUploadedSource, deploymentMetricsGetLatest, deploymentMetricsGetRange, deploymentMetricsToggle, destroySandbox, detachScheduleService, detectPublicPresets, disableBackupSchedule, disableMfa, discoverWorkloads, domain, downloadGlobalSkillArchive, downloadObject, downloadSkillArchive, emailStatus, embeddings, enableBackupSchedule, enrichVisitor, exec, execDetached, executeDeploymentOperation, executeImport, extendTimeout, externalServiceEnablePgStatStatements, externalServiceMetricsByDatabase, externalServiceMetricsCreateAlertRule, externalServiceMetricsDeleteAlertRule, externalServiceMetricsGetAlertRules, externalServiceMetricsGetLatest, externalServiceMetricsGetRange, externalServiceMetricsStatus, externalServiceMetricsToggle, externalServiceMetricsUpdateAlertRule, externalServiceResetPgStatStatements, finalizeOrder, finalizeProjectRelease, findConversation, generateJoinToken, generatePresetDockerfile, getAccessInfo, getActiveVisitors, getActivityGraph, getAdminGate, getAgent, getAggregatedBuckets, getAiAgentBreakdown, getAiAgentPages, getAiAgentTimeline, getAiPageBreakdown, getAiStatusBreakdown, getAlert, getAlertRule, getAllRepositoriesByName, getAnalyticsActiveVisitors, getAnalyticsEventsCount, getAnalyticsSessionEvents, getAnalyticsVisitorSessions, getApiKey, getApiKeyPermissions, getAuditLog, getBackup, getBackupSchedule, getBranchesByRepositoryId, getBucketedIncidents, getBucketedStatus, getChallengeToken, getChatReadiness, getCliStatus, getClusterHealth, getClusterMember, getCmd, getContainerDetail, getContainerEnvironmentVariable, getContainerInfo, getContainerLogs, getContainerLogsById, getContainerMetrics, getConversation, getConversationDetail, getConversations, getCronById, getCronExecutions, getCrossProjectTraceSiblings, getCurrentMonitorStatus, getCurrentUser, getCustomDomain, getDashboard, getDashboardProjectsAnalytics, getDelivery, getDeployment, getDeploymentContainerLogContent, getDeploymentJobLogs, getDeploymentJobs, getDeploymentOperations, getDeploymentOperationStatus, getDeploymentToken, getDiskStatus, getDnsChanges, getDnsProvider, getDomain, getDomainByHost, getDomainById, getDomainByName, getDomainDnsRecords, getDomainOrder, getEmail, getEmailEvents, getEmailLinks, getEmailProvider, getEmailStats, getEmailTracking, getEmailTrackingStatus, getEntityInfo, getEnvironment, getEnvironmentCrons, getEnvironmentDomains, getEnvironments, getEnvironmentVariables, getEnvironmentVariableValue, getErrorDashboardStats, getErrorEvent, getErrorGroup, getErrorStats, getErrorTimeSeries, getEventDetail, getEventEntries, getEventsCount, getEventsTimeline, getEventTypeBreakdown, getEventVisitors, getExternalImage, getFile, getFlag, getFlagSnapshot, getFunnelMetrics, getGenaiTrace, getGeneralStats, getGitProvider, getGlobalEvents, getGlobalEventStats, getGlobalMcp, getGlobalSandboxStatus, getGlobalSkill, getGroupedPageMetrics, getHealth, getHourlyVisits, getHttpChallengeDebug, getImportStatus, getIncident, getIncidentUpdates, getIpAccessControl, getIpGeolocation, getJoinTokenStatus, getLastDeployment, getLatestScan, getLatestScansPerEnvironment, getLiveVisitorsList, getLogContext, getMcp, getMetricsOverTime, getMonitor, getNotificationProvider, getOnDemandCertStatus, getOrCreateDsn, getPageFlow, getPageHourlySessions, getPagePathDetail, getPagePaths, getPagePathsSparklines, getPagePathVisitors, getPendingAction, getPerformanceMetrics, getPgUpgrade, getPgUpgradeLogs, getPipelineStats, getPlatformInfo, getPostgresWalHealth, getPreferences, getPreviewGatewayLogs, getPreviewGatewaySettings, getPreviewGatewayStatus, getPricing, getPrivateIp, getProject, getProjectAlarmsSummary, getProjectBySlug, getProjectDeployments, getProjects, getProjectServiceEnvironmentVariables, getProjectSessionReplays, getProjectsHealth, getProjectsMonitorHealth, getProjectStatistics, getProjectTemplate, getPropertyBreakdown, getPropertyTimeline, getProviderConnections, getProviderMetadata, getProvidersMetadata, getProxyLogById, getProxyLogByRequestId, getProxyLogs, getPublicBranches, getPublicIp, getPublicRepository, getQuota, getRecentActivity, getRemoteExternalImage, getRepositoryBranches, getRepositoryById, getRepositoryByName, getRepositoryPresetByName, getRepositoryPresetLive, getRepositoryTags, getResolvedEnvironmentVariables, getResolvedEnvironmentVariableValue, getRestoreCapabilities, getRestoreRun, getRoute, getRun, getRunWithLogs, getS3Credentials, getS3Source, getSandbox, getSandboxStatus, getScan, getScanByDeployment, getScanVulnerabilities, getService, getServiceBySlug, getServiceEnvironmentVariable, getServiceEnvironmentVariables, getServiceHealthStatus, getServicePreviewEnvironmentVariableNames, getServicePreviewEnvironmentVariablesMasked, getServiceRuntime, getServiceStats, getServiceTypeParameters, getServiceTypes, getSessionDetails, getSessionEvents, getSessionLogs, getSessionReplay, getSessionReplayEvents, getSettings, getSkill, getSlowQueries, getStaticBundle, getStatusOverview, getTagsByRepositoryId, getTeam, getTimeBucketStats, getTodayStats, getTrace, getUnifiedTrace, getUniqueCounts, getUniqueEvents, getUpdateStatus, getUptimeHistory, getUsageByProvider, getUsageRecent, getUsageSummary, getUsageTimeseries, getUsageTopModels, getVisitorByGuid, getVisitorById, getVisitorDetails, getVisitorFacets, getVisitorInfo, getVisitorJourney, getVisitors, getVisitorSessions, getVisitorStats, getWebhook, grantProjectAccess, handleGitProviderOauthCallback, hasAnalyticsEvents, hasErrorGroups, hasPerformanceMetrics, importExternalService, ingestLogs, ingestLogsByPath, ingestMetrics, ingestMetricsByPath, ingestSentryEnvelope, ingestSentryEvent, ingestTraces, ingestTracesByPath, initSessionReplay, inspectDropArchive, jobLogs, jobStatus, killJob, kvDel, kvDisable, kvEnable, kvExpire, kvGet, kvIncr, kvKeys, kvSet, kvStatus, kvTtl, kvUpdate, latestRunForSource, linkCustomDomainToCertificate, linkServiceToProject, listAgentRuns, listAgents, listAiProviders, listAlertRules, listAlerts, listAllConversations, listAllRuns, listApiKeys, listAuditLogs, listAvailableContainers, listBackupAlerts, listBackupChildren, listBackupSchedules, listBackupsForSchedule, listCommitsByRepositoryId, listConnections, listContainers, listContainersAtPath, listConversations, listCustomDomainsForProject, listDashboards, listDeliveries, listDeploymentContainerLogs, listDeploymentTokens, listDnsProviders, listDomains, listDsns, listEmailDomains, listEmailProviders, listEmails, listEnrollmentTokens, listEntities, listErrorEvents, listErrorGroups, listEvents, listEventTypes, listExternalImages, listExternalPlugins, listExternalServiceBackups, listFlags, listFunnels, listGitProviders, listGlobalMcps, listGlobalSkills, listIncidents, listInsights, listIpAccessControl, listJobs, listKnownAiAgents, listManagedDomains, listMcps, listMetricLabelKeys, listMetricLabelValues, listMetricNames, listModels, listMonitors, listNotificationProviders, listOidcProviders, listOidcProviderUsers, listOidcRoleMappings, listOnDemandCerts, listOrders, listPeers, listPendingActions, listPgUpgrades, listPresets, listProjectAccess, listProjectAlarms, listProjectScans, listProjectSecrets, listProjectServices, listProjectTemplates, listProjectTemplateTags, listProviderKeys, listProviderZones, listPublicProviders, listReleaseFiles, listReleases, listRemoteExternalImages, listRepositoriesByConnection, listRepositoriesByProvider, listRestoreRunsForService, listRootContainers, listRoutes, listS3Sources, listSandboxes, listScheduleRunJobs, listScheduleRuns, listScheduleServices, listSecrets, listServiceHealthStatuses, listServiceProjects, listServices, listServiceSchedules, listSkills, listSourceBackups, listSourceFiles, listSourceMaps, listSources, listStaticBundles, listSyncedRepositories, listTeamMembers, listTeamProjects, listTeams, listUsers, listWebhooks, login, logout, lookupDnsARecords, mintEnrollmentToken, mkdir, nodeHeartbeat, nodeMetricsGetRange, observabilityFullEvent, observabilityListEvents, oidcCallback, type Options, patchAdminGate, patchPreviewGatewaySettings, pauseDeployment, pauseSandbox, planRestore, postDnsAck, previewAlert, previewFunnelMetrics, previewHostnameMode, promoteClusterMember, promoteDeployment, provisionDomain, purgeProjectLogs, pushExternalImage, queryData, queryGenaiTraces, queryLogs, queryMetrics, queryTraces, queryTraceSummaries, readFile, reAnalyze, rebuildSandboxImage, recordConsoleEvent, recordEventMetrics, recordFlagExposure, recordSpeedMetrics, refreshRouteTable, regenerateDsn, registerExternalImage, registerNode, reinstallGitlabWebhook, rejectPendingAction, reloadPlugins, removeClusterMember, removeManagedDomain, removeRole, removeTeamMember, renameConversation, renewDomain, requestPasswordReset, resetPassword, resizeSandbox, resolveAlarm, restartContainer, restartPreviewGateway, restartSandbox, restoreFlag, restoreUser, resumeDeployment, resumeSandbox, retryCluster, retryDelivery, retryPgUpgrade, retryRun, revealGlobalMcpConfig, revealMcpConfig, revealNotificationProviderConfig, revealServiceParameter, revenueCreateIntegration, revenueDeleteIntegration, revenueGlobalEvents, revenueImportInvoicesCsv, revenueImportSubscriptionsCsv, revenueListIntegrations, revenueListProviders, revenueMetricsCustomers, revenueMetricsGlobalMrr, revenueMetricsGlobalSummary, revenueMetricsMrr, revenueMetricsSummary, revenueRecentEvents, revenueRotateToken, revenueUpdateConfig, revenueUpdateSecret, revokeDsn, revokeEnrollmentToken, revokeJoinToken, revokeProjectAccess, rollbackPgUpgrade, rollbackToDeployment, rootfsGc, rootfsReport, rotateApiKey, rotateDeploymentToken, runBackupForSource, runConnectionHealthCheck, runExternalServiceBackup, runScheduleNow, sandboxCreatePreviewLink, saveAgentToken, saveAiProviderCredential, searchLogs, sendEmail, sendMessage, setDefaultS3Source, setFlagEnvironment, setPreviewPassword, setupDns, setupDnsChallenge, setupEmailTracking, setupMfa, sleepEnvironment, smokeTestAgent, sourceSandbox, startAnalysis, startContainer, startFix, startGitProviderOauth, startOidcLoginBySlug, startPgUpgrade, startRestore, startService, statPath, stopContainer, stopSandbox, stopService, streamContainerMetrics, streamEvents, streamRunEvents, syncRepositories, tailDeploymentJobLogs, tailLogs, teardownDeployment, teardownEnvironment, testNotificationProvider, testOidcProvider, testProvider, testProviderConnection, testProviderKeyById, testProviderKeyInline, testS3ConnectionPreview, testS3SourceConnection, trackClick, trackOpen, triggerAgent, triggerProjectPipeline, triggerScan, triggerServiceHealthCheck, triggerWeeklyDigest, unlinkServiceFromProject, updateAgent, updateAiProvider, updateAlert, updateAlertRule, updateApiKey, updateAutomaticDeploy, updateBackupSchedule, updateCloudflareProvider, updateConnectionToken, updateCustomDomain, updateDashboard, updateDeploymentToken, updateEmailProvider, updateEnvironmentSettings, updateEnvironmentSubdomain, updateEnvironmentVariable, updateErrorGroup, updateFlag, updateFunnel, updateGitProviderCredentials, updateGitSettings, updateGlobalMcp, updateGlobalSkill, updateIncidentStatus, updateIpAccessControl, updateManagedDomain, updateMcp, updateNotificationEmailProvider, updateNotificationProvider, updateOidcProvider, updatePreferences, updateProject, updateProjectDeploymentConfig, updateProjectSecret, updateProjectSettings, updateProvider, updateProviderKey, updateRoute, updateS3Source, updateSelf, updateService, updateServiceResources, updateSessionDuration, updateSettings, updateSkill, updateSlackProvider, updateSpeedMetrics, updateTeam, updateTeamMemberRole, updateUser, updateWebhook, updateWebhookProvider, upgradePreviewGateway, upgradeService, uploadGlobalSkill, uploadReleaseFile, uploadSkill, uploadSourceFile, uploadSourceMap, uploadStaticBundle, upsertSecret, validateConnection, validateEmail, verifyAndEnableMfa, verifyDomain, verifyEmail, verifyManagedDomain, verifyMfaChallenge, verifyStepUp, wakeEnvironment, webhookTrigger, workflowDryRun, writeFile, writeFiles } from './sdk.gen'; -export type { AcknowledgeAlarmData, AcknowledgeAlarmErrors, AcknowledgeAlarmResponses, AcmeOrderResponse, ActivateAiProviderData, ActivateAiProviderErrors, ActivateAiProviderResponse, ActivateAiProviderResponses, ActivateApiKeyData, ActivateApiKeyErrors, ActivateApiKeyResponse, ActivateApiKeyResponses, ActivateConnectionData, ActivateConnectionErrors, ActivateConnectionResponses, ActivateProviderData, ActivateProviderErrors, ActivateProviderResponse, ActivateProviderResponses, ActiveVisitor, ActiveVisitorsQuery, ActiveVisitorsResponse, ActivityDay, ActivityEvent, ActivityGraphQuery, ActivityGraphResponse, AddClusterMemberData, AddClusterMemberErrors, AddClusterMemberRequest, AddClusterMemberResponse, AddClusterMemberResponses, AddContextData, AddContextErrors, AddContextRequest, AddContextResponses, AddEnvironmentDomainData, AddEnvironmentDomainErrors, AddEnvironmentDomainRequest, AddEnvironmentDomainResponse, AddEnvironmentDomainResponses, AddEventsData, AddEventsError, AddEventsErrors, AddEventsRequest, AddEventsResponse, AddEventsResponse2, AddEventsResponses, AddManagedDomainApiRequest, AddManagedDomainData, AddManagedDomainErrors, AddManagedDomainResponse, AddManagedDomainResponses, AddSessionReplayEventsData, AddSessionReplayEventsError, AddSessionReplayEventsErrors, AddSessionReplayEventsResponse, AddSessionReplayEventsResponses, AddTeamMemberData, AddTeamMemberErrors, AddTeamMemberResponse, AddTeamMemberResponses, AdminDrainNodeData, AdminDrainNodeErrors, AdminDrainNodeResponse, AdminDrainNodeResponses, AdminDrainStatusData, AdminDrainStatusErrors, AdminDrainStatusResponse, AdminDrainStatusResponses, AdminGateResponse, AdminGateSource, AdminGetNodeData, AdminGetNodeErrors, AdminGetNodeResponse, AdminGetNodeResponses, AdminListNodeContainersData, AdminListNodeContainersErrors, AdminListNodeContainersResponse, AdminListNodeContainersResponses, AdminListNodesData, AdminListNodesErrors, AdminListNodesResponse, AdminListNodesResponses, AdminRemoveNodeData, AdminRemoveNodeErrors, AdminRemoveNodeResponse, AdminRemoveNodeResponses, AdminUndrainNodeData, AdminUndrainNodeErrors, AdminUndrainNodeResponse, AdminUndrainNodeResponses, AgentConfigResponse, AgentRunLogResponse, AgentRunResponse, AgentRunWithLogsResponse, AgentSandboxSettings, AgentSandboxSettingsMasked, AggregatedBucketItem, AggregatedBucketsQuery, AggregatedBucketsResponse, AggregationLevel, AggregationTemporality, AiAgentBreakdownResponse, AiAgentBreakdownRow, AiAgentDescriptor, AiAgentPageRow, AiAgentPagesResponse, AiAgentTimelineResponse, AiAgentTimelineRow, AiChatLimitsSettings, AiConfigSettings, AiPageBreakdownResponse, AiPageBreakdownRow, AiStatusBreakdownResponse, AiStatusBreakdownRow, AlarmListResponse, AlarmResponse, AlarmSummaryResponse, AlertRuleResponse, AllocEntry, AnalyticsSessionEventsResponse, AnnotatedSpan, AnomalyAlgorithm, AnomalyParams, AnomalyPreviewPointResponse, AnomalyPreviewRequest, AnomalyPreviewResponse, ApiKeyListResponse, ApiKeyResponse, ApplyHostnameModeData, ApplyHostnameModeErrors, ApplyHostnameModeRequest, ApplyHostnameModeResponse, ApplyHostnameModeResponses, AppSettings, AppSettingsResponse, ArchiveConversationData, ArchiveConversationErrors, ArchiveConversationResponse, ArchiveConversationResponses, ArchiveFlagData, ArchiveFlagErrors, ArchiveFlagResponse, ArchiveFlagResponse2, ArchiveFlagResponses, ArchiveMode, AssignRoleData, AssignRoleErrors, AssignRoleRequest, AssignRoleResponses, AttachScheduleServicesData, AttachScheduleServicesError, AttachScheduleServicesErrors, AttachScheduleServicesRequest, AttachScheduleServicesResponse, AttachScheduleServicesResponse2, AttachScheduleServicesResponses, AuditLogIpInfo, AuditLogResponse, AuditLogUserInfo, AuthFlavorDto, AuthResponse, AuthStatusResponse, AuthTokenResponse, AutofixerRunResponse, AutofixerRunWithLogsResponse, AutofixRunConfig, AutoWatchParams, AvailableContainerInfo, AvailablePermissions, BackupAlertListResponse, BackupAlertResponse, BackupResponse, BackupScheduleResponse, BitbucketAuthInput, BlobCopyData, BlobCopyError, BlobCopyErrors, BlobCopyResponse, BlobCopyResponses, BlobDeleteData, BlobDeleteError, BlobDeleteErrors, BlobDeleteResponse, BlobDeleteResponses, BlobDisableData, BlobDisableErrors, BlobDisableResponse, BlobDisableResponses, BlobDownloadData, BlobDownloadError, BlobDownloadErrors, BlobDownloadResponses, BlobEnableData, BlobEnableErrors, BlobEnableResponse, BlobEnableResponses, BlobHeadData, BlobHeadError, BlobHeadErrors, BlobHeadResponses, BlobListData, BlobListError, BlobListErrors, BlobListResponse, BlobListResponses, BlobPutData, BlobPutError, BlobPutErrors, BlobPutResponse, BlobPutResponses, BlobResponse, BlobStatusData, BlobStatusErrors, BlobStatusResponse, BlobStatusResponse2, BlobStatusResponses, BlobUpdateData, BlobUpdateErrors, BlobUpdateResponse, BlobUpdateResponses, BranchInfo, BranchListResponse, BrowserCount, BrowsersQuery, BuildConfiguration, BuildLimitsSettings, CancelBackupData, CancelBackupError, CancelBackupErrors, CancelBackupResponse, CancelBackupResponse2, CancelBackupResponses, CancelData, CancelDeploymentData, CancelDeploymentErrors, CancelDeploymentResponse, CancelDeploymentResponses, CancelDomainOrderData, CancelDomainOrderErrors, CancelDomainOrderResponse, CancelDomainOrderResponses, CancelErrors, CancelPgUpgradeData, CancelPgUpgradeErrors, CancelPgUpgradeResponse, CancelPgUpgradeResponses, CancelResponses, CancelRunData, CancelRunErrors, CancelRunResponse, CancelRunResponses, CancelScheduleRunData, CancelScheduleRunError, CancelScheduleRunErrors, CancelScheduleRunResponse, CancelScheduleRunResponses, CertStatusResponse, ChallengeConfig, ChallengeError, ChallengeValidationStatus, ChangePasswordRequest, ChangePasswordSelfData, ChangePasswordSelfErrors, ChangePasswordSelfResponse, ChangePasswordSelfResponses, ChangeProjectSourceData, ChangeProjectSourceErrors, ChangeProjectSourceRequest, ChangeProjectSourceResponse, ChangeProjectSourceResponses, ChatCompletionChoice, ChatCompletionRequest, ChatCompletionResponse, ChatCompletionsData, ChatCompletionsError, ChatCompletionsErrors, ChatCompletionsResponse, ChatCompletionsResponses, ChatMessage, ChatReadinessResponse, CheckAnalyticsHasEventsData, CheckAnalyticsHasEventsErrors, CheckAnalyticsHasEventsResponse, CheckAnalyticsHasEventsResponses, CheckCommitExistsData, CheckCommitExistsErrors, CheckCommitExistsResponse, CheckCommitExistsResponses, CheckDomainStatusData, CheckDomainStatusErrors, CheckDomainStatusResponse, CheckDomainStatusResponses, CheckExplorerSupportData, CheckExplorerSupportErrors, CheckExplorerSupportResponse, CheckExplorerSupportResponses, CheckIpBlockedData, CheckIpBlockedError, CheckIpBlockedErrors, CheckIpBlockedResponses, CheckProviderDeletionSafetyData, CheckProviderDeletionSafetyErrors, CheckProviderDeletionSafetyResponse, CheckProviderDeletionSafetyResponses, ChildBackupEntryResponse, ChildBackupListResponse, ChunkUploadOptionsData, ChunkUploadOptionsResponse, ChunkUploadOptionsResponses, CleanupExpiredBackupsData, CleanupExpiredBackupsError, CleanupExpiredBackupsErrors, CleanupExpiredBackupsRequest, CleanupExpiredBackupsResponse, CleanupExpiredBackupsResponses, ClearPreviewPasswordData, ClearPreviewPasswordErrors, ClearPreviewPasswordResponse, ClearPreviewPasswordResponses, CliDeviceApproveData, CliDeviceApproveErrors, CliDeviceApproveRequest, CliDeviceApproveResponse, CliDeviceApproveResponse2, CliDeviceApproveResponses, CliDeviceDenyData, CliDeviceDenyErrors, CliDeviceDenyResponse, CliDeviceDenyResponses, CliDeviceLookupData, CliDeviceLookupErrors, CliDeviceLookupResponse, CliDeviceLookupResponse2, CliDeviceLookupResponses, CliDevicePollData, CliDevicePollErrors, CliDevicePollRequest, CliDevicePollResponse, CliDevicePollResponse2, CliDevicePollResponses, CliDeviceStartData, CliDeviceStartErrors, CliDeviceStartRequest, CliDeviceStartResponse, CliDeviceStartResponse2, CliDeviceStartResponses, ClientOptions, CliLoginRequest, CliLogoutData, CliLogoutErrors, CliLogoutResponse, CliLogoutResponses, CloudflareConfig, CloudProvider, ClusterCapacity, ClusterDnsSettings, ClusterHealthReportResponse, ClusterMemberHealthResponse, ClusterMemberRequest, CmdBody, CmdData, CmdErrors, CmdInner, CmdKillBody, CmdKillData, CmdKillErrors, CmdKillResponse, CmdKillResponses, CmdLogsData, CmdLogsErrors, CmdLogsResponses, CmdResponse, CmdResponse2, CmdResponses, CommitExistsResponse, CommitInfo, CommitListResponse, Comparator, ComposePublicPort, ConfirmPendingActionData, ConfirmPendingActionErrors, ConfirmPendingActionResponse, ConfirmPendingActionResponses, ConnectionListQuery, ConnectionListResponse, ConnectionResponse, ConnectionTestResult, ConsoleEventPayload, ContainerActionResponse, ContainerDetailResponse, ContainerEnvironmentVariableValueResponse, ContainerInfoResponse, ContainerInventoryItem, ContainerListResponse, ContainerLogSettings, ContainerLogsQuery, ContainerMetricHistoryPoint, ContainerMetricsGetHistoryData, ContainerMetricsGetHistoryErrors, ContainerMetricsGetHistoryResponse, ContainerMetricsGetHistoryResponses, ContainerMetricsHistoryQuery, ContainerMetricsResponse, ContainerResponse, ContainerRuntimeInfo, ContainerStatsSample, ContentPart, ContextLine, ContextLogsRequest, ContextLogsResponse, ConversationDetailResponse, ConversationResponse, ConversationsQueryParams, ConversationSummary, CopyBlobRequest, CostAnalysis, CreateAgentData, CreateAgentErrors, CreateAgentResponse, CreateAgentResponses, CreateAlertData, CreateAlertError, CreateAlertErrors, CreateAlertResponse, CreateAlertResponses, CreateAlertRuleData, CreateAlertRuleErrors, CreateAlertRuleRequest, CreateAlertRuleResponse, CreateAlertRuleResponses, CreateApiKeyData, CreateApiKeyErrors, CreateApiKeyRequest, CreateApiKeyResponse, CreateApiKeyResponse2, CreateApiKeyResponses, CreateBackupScheduleData, CreateBackupScheduleError, CreateBackupScheduleErrors, CreateBackupScheduleRequest, CreateBackupScheduleResponse, CreateBackupScheduleResponses, CreateBitbucketProviderData, CreateBitbucketProviderErrors, CreateBitbucketProviderResponse, CreateBitbucketProviderResponses, CreateBitbucketRequest, CreateCloudflareProviderData, CreateCloudflareProviderErrors, CreateCloudflareProviderRequest, CreateCloudflareProviderResponse, CreateCloudflareProviderResponses, CreateConversationData, CreateConversationErrors, CreateConversationRequest, CreateConversationResponse, CreateConversationResponses, CreateCustomDomainData, CreateCustomDomainErrors, CreateCustomDomainResponse, CreateCustomDomainResponses, CreateDashboardData, CreateDashboardError, CreateDashboardErrors, CreateDashboardRequest, CreateDashboardResponse, CreateDashboardResponses, CreateDeploymentTokenData, CreateDeploymentTokenErrors, CreateDeploymentTokenRequest, CreateDeploymentTokenResponse, CreateDeploymentTokenResponse2, CreateDeploymentTokenResponses, CreateDnsProviderData, CreateDnsProviderErrors, CreateDnsProviderRequest, CreateDnsProviderResponse, CreateDnsProviderResponses, CreateDomainData, CreateDomainErrors, CreateDomainRequest, CreateDomainResponse, CreateDomainResponses, CreatedResource, CreateDsnData, CreateDsnErrors, CreateDsnRequest, CreateDsnResponse, CreateDsnResponses, CreateEmailDomainData, CreateEmailDomainErrors, CreateEmailDomainRequest, CreateEmailDomainResponse, CreateEmailDomainResponses, CreateEmailProviderData, CreateEmailProviderErrors, CreateEmailProviderRequest, CreateEmailProviderResponse, CreateEmailProviderResponses, CreateEnvironmentData, CreateEnvironmentErrors, CreateEnvironmentRequest, CreateEnvironmentResponse, CreateEnvironmentResponses, CreateEnvironmentVariableData, CreateEnvironmentVariableErrors, CreateEnvironmentVariableRequest, CreateEnvironmentVariableResponse, CreateEnvironmentVariableResponses, CreateExternalServiceRequest, CreateFlagData, CreateFlagErrors, CreateFlagRequest, CreateFlagResponse, CreateFlagResponses, CreateFunnelData, CreateFunnelErrors, CreateFunnelRequest, CreateFunnelResponse, CreateFunnelResponse2, CreateFunnelResponses, CreateFunnelStep, CreateGenericProviderData, CreateGenericProviderErrors, CreateGenericProviderResponse, CreateGenericProviderResponses, CreateGenericRequest, CreateGiteaPatProviderData, CreateGiteaPatProviderErrors, CreateGiteaPatProviderResponse, CreateGiteaPatProviderResponses, CreateGiteaPatRequest, CreateGithubPatProviderData, CreateGithubPatProviderErrors, CreateGithubPatProviderResponse, CreateGithubPatProviderResponses, CreateGitHubPatRequest, CreateGitlabOauthProviderData, CreateGitlabOauthProviderErrors, CreateGitlabOauthProviderResponse, CreateGitlabOauthProviderResponses, CreateGitLabOAuthRequest, CreateGitlabPatProviderData, CreateGitlabPatProviderErrors, CreateGitlabPatProviderResponse, CreateGitlabPatProviderResponses, CreateGitLabPatRequest, CreateGitProviderData, CreateGitProviderErrors, CreateGitProviderResponse, CreateGitProviderResponses, CreateGlobalMcpData, CreateGlobalMcpErrors, CreateGlobalMcpResponse, CreateGlobalMcpResponses, CreateGlobalSkillData, CreateGlobalSkillErrors, CreateGlobalSkillResponse, CreateGlobalSkillResponses, CreateIncidentData, CreateIncidentErrors, CreateIncidentRequest, CreateIncidentResponse, CreateIncidentResponses, CreateIntegrationBody, CreateIpAccessControlData, CreateIpAccessControlError, CreateIpAccessControlErrors, CreateIpAccessControlRequest, CreateIpAccessControlResponse, CreateIpAccessControlResponses, CreateMcpData, CreateMcpErrors, CreateMcpRequest, CreateMcpResponse, CreateMcpResponses, CreateMetricAlertRequest, CreateMonitorData, CreateMonitorErrors, CreateMonitorRequest, CreateMonitorResponse, CreateMonitorResponses, CreateNotificationEmailProviderData, CreateNotificationEmailProviderErrors, CreateNotificationEmailProviderRequest, CreateNotificationEmailProviderResponse, CreateNotificationEmailProviderResponses, CreateNotificationProviderData, CreateNotificationProviderErrors, CreateNotificationProviderResponse, CreateNotificationProviderResponses, CreateOidcProviderData, CreateOidcProviderErrors, CreateOidcProviderRequest, CreateOidcProviderResponse, CreateOidcProviderResponses, CreateOidcRoleMappingData, CreateOidcRoleMappingRequest, CreateOidcRoleMappingResponse, CreateOidcRoleMappingResponses, CreateOrRecreateOrderData, CreateOrRecreateOrderErrors, CreateOrRecreateOrderResponse, CreateOrRecreateOrderResponses, CreatePlanData, CreatePlanErrors, CreatePlanRequest, CreatePlanResponse, CreatePlanResponse2, CreatePlanResponses, CreatePrData, CreatePrErrors, CreateProjectAccessRequest, CreateProjectData, CreateProjectErrors, CreateProjectFromTemplateData, CreateProjectFromTemplateErrors, CreateProjectFromTemplateRequest, CreateProjectFromTemplateResponse, CreateProjectFromTemplateResponse2, CreateProjectFromTemplateResponses, CreateProjectReleaseData, CreateProjectReleaseErrors, CreateProjectReleaseResponse, CreateProjectReleaseResponses, CreateProjectRequest, CreateProjectResponse, CreateProjectResponses, CreateProjectSecretData, CreateProjectSecretErrors, CreateProjectSecretRequest, CreateProjectSecretResponse, CreateProjectSecretResponses, CreateProviderKeyData, CreateProviderKeyError, CreateProviderKeyErrors, CreateProviderKeyRequest, CreateProviderKeyResponse, CreateProviderKeyResponses, CreateProviderRequest, CreatePrResponse, CreatePrResponse2, CreatePrResponses, CreateReleaseData, CreateReleaseErrors, CreateReleaseResponse, CreateReleaseResponses, CreateRouteData, CreateRouteErrors, CreateRouteRequest, CreateRouteResponse, CreateRouteResponses, CreateS3SourceData, CreateS3SourceError, CreateS3SourceErrors, CreateS3SourceRequest, CreateS3SourceResponse, CreateS3SourceResponses, CreateSandboxBody, CreateSandboxData, CreateSandboxErrors, CreateSandboxResponse, CreateSandboxResponses, CreateServiceData, CreateServiceErrors, CreateServiceResponse, CreateServiceResponses, CreateSkillData, CreateSkillErrors, CreateSkillRequest, CreateSkillResponse, CreateSkillResponses, CreateSlackProviderData, CreateSlackProviderErrors, CreateSlackProviderRequest, CreateSlackProviderResponse, CreateSlackProviderResponses, CreateTeamData, CreateTeamErrors, CreateTeamMemberRequest, CreateTeamRequest, CreateTeamResponse, CreateTeamResponses, CreateUserData, CreateUserErrors, CreateUserRequest, CreateUserResponse, CreateUserResponses, CreateWebhookData, CreateWebhookErrors, CreateWebhookProviderData, CreateWebhookProviderErrors, CreateWebhookProviderRequest, CreateWebhookProviderResponse, CreateWebhookProviderResponses, CreateWebhookRequestBody, CreateWebhookResponse, CreateWebhookResponses, CronExecutionInfo, CronInfo, CrossProjectSiblingRef, CrossProjectTraceResponse, CurrentStatusResponse, CustomDomainRequest, CustomDomainResponse, CustomerMovementResponse, DashboardLayout, DashboardProjectsAnalyticsQuery, DashboardProjectsAnalyticsResponse, DashboardSection, DashboardTile, DatabaseMetricsResponse, DatabaseMetricsRow, DataImplication, DataImplicationSeverity, DeactivateApiKeyData, DeactivateApiKeyErrors, DeactivateApiKeyResponse, DeactivateApiKeyResponses, DeactivateConnectionData, DeactivateConnectionErrors, DeactivateConnectionResponses, DeactivateProviderData, DeactivateProviderErrors, DeactivateProviderResponses, DeleteAgentData, DeleteAgentErrors, DeleteAgentResponse, DeleteAgentResponses, DeleteAlertData, DeleteAlertError, DeleteAlertErrors, DeleteAlertResponse, DeleteAlertResponses, DeleteAlertRuleData, DeleteAlertRuleErrors, DeleteAlertRuleResponse, DeleteAlertRuleResponses, DeleteApiKeyData, DeleteApiKeyErrors, DeleteApiKeyResponse, DeleteApiKeyResponses, DeleteBackupData, DeleteBackupError, DeleteBackupErrors, DeleteBackupResponse, DeleteBackupResponses, DeleteBackupScheduleData, DeleteBackupScheduleError, DeleteBackupScheduleErrors, DeleteBackupScheduleResponse, DeleteBackupScheduleResponses, DeleteBlobRequest, DeleteBlobResponse, DeleteConnectionData, DeleteConnectionErrors, DeleteConnectionResponse, DeleteConnectionResponses, DeleteCustomDomainData, DeleteCustomDomainErrors, DeleteCustomDomainResponse, DeleteCustomDomainResponses, DeleteDashboardData, DeleteDashboardError, DeleteDashboardErrors, DeleteDashboardResponse, DeleteDashboardResponses, DeleteDeploymentTokenData, DeleteDeploymentTokenErrors, DeleteDeploymentTokenResponse, DeleteDeploymentTokenResponses, DeleteDnsProviderData, DeleteDnsProviderErrors, DeleteDnsProviderResponse, DeleteDnsProviderResponses, DeleteDomainData, DeleteDomainErrors, DeleteDomainResponse, DeleteDomainResponses, DeleteEmailDomainData, DeleteEmailDomainErrors, DeleteEmailDomainResponse, DeleteEmailDomainResponses, DeleteEmailProviderData, DeleteEmailProviderErrors, DeleteEmailProviderResponse, DeleteEmailProviderResponses, DeleteEnvironmentData, DeleteEnvironmentDomainData, DeleteEnvironmentDomainErrors, DeleteEnvironmentDomainResponse, DeleteEnvironmentDomainResponses, DeleteEnvironmentErrors, DeleteEnvironmentResponse, DeleteEnvironmentResponses, DeleteEnvironmentVariableData, DeleteEnvironmentVariableErrors, DeleteEnvironmentVariableResponse, DeleteEnvironmentVariableResponses, DeleteExternalImageData, DeleteExternalImageErrors, DeleteExternalImageResponse, DeleteExternalImageResponses, DeleteFunnelData, DeleteFunnelErrors, DeleteFunnelResponses, DeleteGitProviderData, DeleteGitProviderErrors, DeleteGitProviderResponse, DeleteGitProviderResponses, DeleteGlobalMcpData, DeleteGlobalMcpErrors, DeleteGlobalMcpResponse, DeleteGlobalMcpResponses, DeleteGlobalSkillData, DeleteGlobalSkillErrors, DeleteGlobalSkillResponse, DeleteGlobalSkillResponses, DeleteIpAccessControlData, DeleteIpAccessControlError, DeleteIpAccessControlErrors, DeleteIpAccessControlResponse, DeleteIpAccessControlResponses, DeleteMcpData, DeleteMcpErrors, DeleteMcpResponse, DeleteMcpResponses, DeleteMonitorData, DeleteMonitorErrors, DeleteMonitorResponse, DeleteMonitorResponses, DeleteNotificationProviderData, DeleteNotificationProviderErrors, DeleteNotificationProviderResponse, DeleteNotificationProviderResponses, DeleteOidcProviderData, DeleteOidcProviderResponse, DeleteOidcProviderResponses, DeleteOidcRoleMappingData, DeleteOidcRoleMappingResponse, DeleteOidcRoleMappingResponses, DeletePreferencesData, DeletePreferencesErrors, DeletePreferencesResponse, DeletePreferencesResponses, DeleteProjectData, DeleteProjectErrors, DeleteProjectResponse, DeleteProjectResponses, DeleteProjectSecretData, DeleteProjectSecretErrors, DeleteProjectSecretResponse, DeleteProjectSecretResponses, DeleteProviderKeyData, DeleteProviderKeyError, DeleteProviderKeyErrors, DeleteProviderKeyResponse, DeleteProviderKeyResponses, DeleteProviderSafelyData, DeleteProviderSafelyErrors, DeleteProviderSafelyResponse, DeleteProviderSafelyResponses, DeleteReleaseSourceFilesData, DeleteReleaseSourceFilesErrors, DeleteReleaseSourceFilesResponse, DeleteReleaseSourceFilesResponses, DeleteReleaseSourceMapsData, DeleteReleaseSourceMapsErrors, DeleteReleaseSourceMapsResponse, DeleteReleaseSourceMapsResponses, DeleteResponse, DeleteRouteData, DeleteRouteErrors, DeleteRouteResponse, DeleteRouteResponses, DeleteS3SourceData, DeleteS3SourceError, DeleteS3SourceErrors, DeleteS3SourceResponse, DeleteS3SourceResponses, DeleteScanData, DeleteScanError, DeleteScanErrors, DeleteScanResponse, DeleteScanResponses, DeleteSecretData, DeleteSecretErrors, DeleteSecretResponse, DeleteSecretResponses, DeleteServiceData, DeleteServiceErrors, DeleteServiceResponse, DeleteServiceResponses, DeleteSessionReplayData, DeleteSessionReplayError, DeleteSessionReplayErrors, DeleteSessionReplayResponses, DeleteSkillData, DeleteSkillErrors, DeleteSkillResponse, DeleteSkillResponses, DeleteSourceMapData, DeleteSourceMapErrors, DeleteSourceMapResponse, DeleteSourceMapResponses, DeleteStaticBundleData, DeleteStaticBundleErrors, DeleteStaticBundleResponse, DeleteStaticBundleResponses, DeleteTeamData, DeleteTeamErrors, DeleteTeamResponse, DeleteTeamResponses, DeleteUserData, DeleteUserErrors, DeleteUserResponse, DeleteUserResponses, DeleteWebhookData, DeleteWebhookErrors, DeleteWebhookResponse, DeleteWebhookResponses, DelRequest, DelResponse, DeployFromImageData, DeployFromImageErrors, DeployFromImageRequest, DeployFromImageResponse, DeployFromImageResponses, DeployFromImageUploadData, DeployFromImageUploadErrors, DeployFromImageUploadQuery, DeployFromImageUploadResponse, DeployFromImageUploadResponses, DeployFromStaticData, DeployFromStaticErrors, DeployFromStaticRequest, DeployFromStaticResponse, DeployFromStaticResponses, DeployFromUploadedSourceData, DeployFromUploadedSourceErrors, DeployFromUploadedSourceResponse, DeployFromUploadedSourceResponses, DeploymentConfig, DeploymentConfigSnapshot, DeploymentConfiguration, DeploymentContainerLogContentResponse, DeploymentContainerLogResponse, DeploymentContainerLogsListResponse, DeploymentEnvironmentResponse, DeploymentJobResponse, DeploymentJobsResponse, DeploymentListResponse, DeploymentMetadata, DeploymentMetricsGetLatestData, DeploymentMetricsGetLatestErrors, DeploymentMetricsGetLatestResponse, DeploymentMetricsGetLatestResponses, DeploymentMetricsGetRangeData, DeploymentMetricsGetRangeErrors, DeploymentMetricsGetRangeResponse, DeploymentMetricsGetRangeResponses, DeploymentMetricsToggleData, DeploymentMetricsToggleErrors, DeploymentMetricsToggleResponses, DeploymentResponse, DeploymentStateResponse, DeploymentStrategy, DeploymentTokenListResponse, DeploymentTokenResponse, DestroySandboxData, DestroySandboxErrors, DestroySandboxResponse, DestroySandboxResponses, DetachScheduleServiceData, DetachScheduleServiceError, DetachScheduleServiceErrors, DetachScheduleServiceResponse, DetachScheduleServiceResponses, DetectionConfig, DetectPublicPresetsData, DetectPublicPresetsErrors, DetectPublicPresetsResponse, DetectPublicPresetsResponses, DeviceCount, DigestSections, Direction, DisableBackupScheduleData, DisableBackupScheduleErrors, DisableBackupScheduleResponse, DisableBackupScheduleResponses, DisableBlobResponse, DisableKvResponse, DisableMfaData, DisableMfaErrors, DisableMfaRequest, DisableMfaResponse, DisableMfaResponses, DiscoverRequest, DiscoverResponse, DiscoverWorkloadsData, DiscoverWorkloadsErrors, DiscoverWorkloadsResponse, DiscoverWorkloadsResponses, DiskInfo, DiskSpaceAlert, DiskSpaceAlertSettings, DiskSpaceCheckResult, DnsAckRequest, DnsAckResponse, DnsChallengeRecordResult, DnsChangesResponse, DnsCompletionResponse, DnsLookupError, DnsLookupRequest, DnsLookupResponse, DnsProviderCredentials, DnsProviderResponse, DnsProviderSettings, DnsProviderSettingsMasked, DnsProviderType, DnsRecord, DnsRecordChange, DnsRecordContent, DnsRecordResponse, DnsRecordSetupResult, DnsRecordStatusResponse, DnsZone, DockerComposePresetConfig, DockerfilePresetConfig, DockerfileVariant, DockerRegistrySettings, DockerRegistrySettingsMasked, DomainAction, DomainChallengeResponse, DomainData, DomainEnvironmentResponse, DomainError, DomainErrors, DomainPlan, DomainResponse, DomainResponse2, DomainResponses, DownloadGlobalSkillArchiveData, DownloadGlobalSkillArchiveErrors, DownloadGlobalSkillArchiveResponse, DownloadGlobalSkillArchiveResponses, DownloadObjectData, DownloadObjectErrors, DownloadObjectResponse, DownloadObjectResponses, DownloadSkillArchiveData, DownloadSkillArchiveErrors, DownloadSkillArchiveResponse, DownloadSkillArchiveResponses, DrainNodeResponse, DrainStatusResponse, DropArchiveUpload, DropInspectionResponse, DropOffPoint, DropPresetCandidate, EmailConfig, EmailDomainResponse, EmailDomainWithDnsResponse, EmailProviderResponse, EmailProviderTypeRoute, EmailRequest, EmailResponse, EmailStatsResponse, EmailStatusData, EmailStatusErrors, EmailStatusResponse, EmailStatusResponse2, EmailStatusResponses, EmailTrackingResponse, EmailTrackingSetupResponse, EmailTrackingStatusResponse, EmbeddingData, EmbeddingInput, EmbeddingRequest, EmbeddingResponse, EmbeddingsData, EmbeddingsError, EmbeddingsErrors, EmbeddingsResponse, EmbeddingsResponses, EmbeddingUsage, EnableBackupScheduleData, EnableBackupScheduleErrors, EnableBackupScheduleResponse, EnableBackupScheduleResponses, EnableBlobRequest, EnableBlobResponse, EnableKvRequest, EnableKvResponse, EnablePgStatStatementsResponse, EndpointDto, EnqueuedJob, EnrichVisitorData, EnrichVisitorErrors, EnrichVisitorRequest, EnrichVisitorResponse, EnrichVisitorResponse2, EnrichVisitorResponses, EnrollmentTokenInfo, EnrollmentTokenListResponse, EntityInfoResponse, EntityResponse, EnvironmentConfiguration, EnvironmentDomainResponse, EnvironmentInfo, EnvironmentResponse, EnvironmentVariable, EnvironmentVariableInfo, EnvironmentVariableResponse, EnvironmentVariableValueResponse, EnvVarInput, EnvVarIntegrationInfo, EnvVarResponse, EnvVarTemplateResponse, ErrorDashboardStatsQuery, ErrorDashboardStatsResponse, ErrorEventResponse, ErrorGroupResponse, ErrorGroupStatsResponse, ErrorResponse, ErrorRow, ErrorTimeSeriesDataResponse, ErrorTimeSeriesQuery, EventActivityBucket, EventBreakdown, EventBrowserStats, EventCount, EventCountryStats, EventDetailQuery, EventDetailResponse, EventEntriesQuery, EventEntriesResponse, EventEntryInfo, EventKind, EventMetricsPayload, EventReferrerStats, EventsCountQuery, EventsResponse, EventTimeline, EventTimelineQuery, EventType, EventTypeBreakdown, EventTypeBreakdownQuery, EventTypeResponse, EventTypesResponse, EventVisitorInfo, EventVisitorsQuery, EventVisitorsResponse, ExecBody, ExecData, ExecDetachedData, ExecDetachedErrors, ExecDetachedResponse, ExecDetachedResponse2, ExecDetachedResponses, ExecErrors, ExecResponse, ExecResponse2, ExecResponses, ExecuteDeploymentOperationData, ExecuteDeploymentOperationErrors, ExecuteDeploymentOperationResponse, ExecuteDeploymentOperationResponses, ExecuteImportData, ExecuteImportErrors, ExecuteImportRequest, ExecuteImportResponse, ExecuteImportResponse2, ExecuteImportResponses, ExecuteOperationRequest, ExpireRequest, ExpireResponse, ExplorerSupportResponse, ExtendTimeoutBody, ExtendTimeoutData, ExtendTimeoutErrors, ExtendTimeoutResponse, ExtendTimeoutResponses, ExternalImageResponse, ExternalServiceBackupResponse, ExternalServiceDetails, ExternalServiceEnablePgStatStatementsData, ExternalServiceEnablePgStatStatementsErrors, ExternalServiceEnablePgStatStatementsResponse, ExternalServiceEnablePgStatStatementsResponses, ExternalServiceInfo, ExternalServiceMetricsByDatabaseData, ExternalServiceMetricsByDatabaseErrors, ExternalServiceMetricsByDatabaseResponse, ExternalServiceMetricsByDatabaseResponses, ExternalServiceMetricsCreateAlertRuleData, ExternalServiceMetricsCreateAlertRuleErrors, ExternalServiceMetricsCreateAlertRuleResponse, ExternalServiceMetricsCreateAlertRuleResponses, ExternalServiceMetricsDeleteAlertRuleData, ExternalServiceMetricsDeleteAlertRuleErrors, ExternalServiceMetricsDeleteAlertRuleResponse, ExternalServiceMetricsDeleteAlertRuleResponses, ExternalServiceMetricsGetAlertRulesData, ExternalServiceMetricsGetAlertRulesErrors, ExternalServiceMetricsGetAlertRulesResponse, ExternalServiceMetricsGetAlertRulesResponses, ExternalServiceMetricsGetLatestData, ExternalServiceMetricsGetLatestErrors, ExternalServiceMetricsGetLatestResponse, ExternalServiceMetricsGetLatestResponses, ExternalServiceMetricsGetRangeData, ExternalServiceMetricsGetRangeErrors, ExternalServiceMetricsGetRangeResponse, ExternalServiceMetricsGetRangeResponses, ExternalServiceMetricsStatusData, ExternalServiceMetricsStatusErrors, ExternalServiceMetricsStatusResponse, ExternalServiceMetricsStatusResponses, ExternalServiceMetricsToggleData, ExternalServiceMetricsToggleErrors, ExternalServiceMetricsToggleResponses, ExternalServiceMetricsUpdateAlertRuleData, ExternalServiceMetricsUpdateAlertRuleErrors, ExternalServiceMetricsUpdateAlertRuleResponse, ExternalServiceMetricsUpdateAlertRuleResponses, ExternalServiceResetPgStatStatementsData, ExternalServiceResetPgStatStatementsErrors, ExternalServiceResetPgStatStatementsResponse, ExternalServiceResetPgStatStatementsResponses, ExternalServiceSummary, FieldResponse, FinalizeOrderData, FinalizeOrderErrors, FinalizeOrderResponse, FinalizeOrderResponses, FinalizeProjectReleaseData, FinalizeProjectReleaseErrors, FinalizeProjectReleaseResponse, FinalizeProjectReleaseResponses, FindConversationData, FindConversationErrors, FindConversationResponse, FindConversationResponses, FiringSeriesEntry, FlagEnvironmentResponse, FlagListResponse, FlagResponse, FlagSnapshot, FlagSnapshotResponse, FlagValueType, ForecastAlgorithm, ForecastParams, FullError, FullEvent, FullRequest, FunnelMetricsResponse, FunnelResponse, GatewayStatus, GenAiEvent, GenAiSpanDetail, GenAiTraceDetailResponse, GenAiTraceSummariesResponse, GenAiTraceSummary, GeneralStatsQuery, GeneralStatsResponse, GenerateDockerfileRequest, GenerateDockerfileResponse, GenerateJoinTokenData, GenerateJoinTokenErrors, GenerateJoinTokenResponse, GenerateJoinTokenResponse2, GenerateJoinTokenResponses, GeneratePresetDockerfileData, GeneratePresetDockerfileErrors, GeneratePresetDockerfileResponse, GeneratePresetDockerfileResponses, GeoLocationResponse, GeoRestrictionsConfig, GetAccessInfoData, GetAccessInfoErrors, GetAccessInfoResponse, GetAccessInfoResponses, GetActiveVisitorsData, GetActiveVisitorsErrors, GetActiveVisitorsResponse, GetActiveVisitorsResponses, GetActivityGraphData, GetActivityGraphErrors, GetActivityGraphResponse, GetActivityGraphResponses, GetAdminGateData, GetAdminGateErrors, GetAdminGateResponse, GetAdminGateResponses, GetAgentData, GetAgentErrors, GetAgentResponse, GetAgentResponses, GetAggregatedBucketsData, GetAggregatedBucketsErrors, GetAggregatedBucketsResponse, GetAggregatedBucketsResponses, GetAiAgentBreakdownData, GetAiAgentBreakdownError, GetAiAgentBreakdownErrors, GetAiAgentBreakdownResponse, GetAiAgentBreakdownResponses, GetAiAgentPagesData, GetAiAgentPagesError, GetAiAgentPagesErrors, GetAiAgentPagesResponse, GetAiAgentPagesResponses, GetAiAgentTimelineData, GetAiAgentTimelineError, GetAiAgentTimelineErrors, GetAiAgentTimelineResponse, GetAiAgentTimelineResponses, GetAiPageBreakdownData, GetAiPageBreakdownError, GetAiPageBreakdownErrors, GetAiPageBreakdownResponse, GetAiPageBreakdownResponses, GetAiStatusBreakdownData, GetAiStatusBreakdownError, GetAiStatusBreakdownErrors, GetAiStatusBreakdownResponse, GetAiStatusBreakdownResponses, GetAlertData, GetAlertError, GetAlertErrors, GetAlertResponse, GetAlertResponses, GetAlertRuleData, GetAlertRuleErrors, GetAlertRuleResponse, GetAlertRuleResponses, GetAllRepositoriesByNameData, GetAllRepositoriesByNameErrors, GetAllRepositoriesByNameResponse, GetAllRepositoriesByNameResponses, GetAnalyticsActiveVisitorsData, GetAnalyticsActiveVisitorsErrors, GetAnalyticsActiveVisitorsResponse, GetAnalyticsActiveVisitorsResponses, GetAnalyticsEventsCountData, GetAnalyticsEventsCountErrors, GetAnalyticsEventsCountResponse, GetAnalyticsEventsCountResponses, GetAnalyticsSessionEventsData, GetAnalyticsSessionEventsErrors, GetAnalyticsSessionEventsResponse, GetAnalyticsSessionEventsResponses, GetAnalyticsVisitorSessionsData, GetAnalyticsVisitorSessionsErrors, GetAnalyticsVisitorSessionsResponse, GetAnalyticsVisitorSessionsResponses, GetApiKeyData, GetApiKeyErrors, GetApiKeyPermissionsData, GetApiKeyPermissionsErrors, GetApiKeyPermissionsResponse, GetApiKeyPermissionsResponses, GetApiKeyResponse, GetApiKeyResponses, GetAuditLogData, GetAuditLogErrors, GetAuditLogResponse, GetAuditLogResponses, GetBackupData, GetBackupError, GetBackupErrors, GetBackupResponse, GetBackupResponses, GetBackupScheduleData, GetBackupScheduleErrors, GetBackupScheduleResponse, GetBackupScheduleResponses, GetBranchesByRepositoryIdData, GetBranchesByRepositoryIdErrors, GetBranchesByRepositoryIdResponse, GetBranchesByRepositoryIdResponses, GetBucketedIncidentsData, GetBucketedIncidentsErrors, GetBucketedIncidentsResponse, GetBucketedIncidentsResponses, GetBucketedStatusData, GetBucketedStatusErrors, GetBucketedStatusResponse, GetBucketedStatusResponses, GetChallengeTokenData, GetChallengeTokenErrors, GetChallengeTokenResponse, GetChallengeTokenResponses, GetChatReadinessData, GetChatReadinessErrors, GetChatReadinessResponse, GetChatReadinessResponses, GetCliStatusData, GetCliStatusErrors, GetCliStatusResponses, GetClusterHealthData, GetClusterHealthErrors, GetClusterHealthResponse, GetClusterHealthResponses, GetClusterMemberData, GetClusterMemberErrors, GetClusterMemberResponse, GetClusterMemberResponses, GetCmdData, GetCmdErrors, GetCmdResponse, GetCmdResponses, GetContainerDetailData, GetContainerDetailErrors, GetContainerDetailResponse, GetContainerDetailResponses, GetContainerEnvironmentVariableData, GetContainerEnvironmentVariableErrors, GetContainerEnvironmentVariableResponse, GetContainerEnvironmentVariableResponses, GetContainerInfoData, GetContainerInfoErrors, GetContainerInfoResponse, GetContainerInfoResponses, GetContainerLogsByIdData, GetContainerLogsByIdErrors, GetContainerLogsData, GetContainerLogsErrors, GetContainerMetricsData, GetContainerMetricsErrors, GetContainerMetricsResponse, GetContainerMetricsResponses, GetConversationData, GetConversationDetailData, GetConversationDetailError, GetConversationDetailErrors, GetConversationDetailResponse, GetConversationDetailResponses, GetConversationErrors, GetConversationResponse, GetConversationResponses, GetConversationsData, GetConversationsError, GetConversationsErrors, GetConversationsResponse, GetConversationsResponses, GetCronByIdData, GetCronByIdErrors, GetCronByIdResponse, GetCronByIdResponses, GetCronExecutionsData, GetCronExecutionsErrors, GetCronExecutionsResponse, GetCronExecutionsResponses, GetCrossProjectTraceSiblingsData, GetCrossProjectTraceSiblingsError, GetCrossProjectTraceSiblingsErrors, GetCrossProjectTraceSiblingsResponse, GetCrossProjectTraceSiblingsResponses, GetCurrentMonitorStatusData, GetCurrentMonitorStatusErrors, GetCurrentMonitorStatusResponse, GetCurrentMonitorStatusResponses, GetCurrentUserData, GetCurrentUserErrors, GetCurrentUserResponse, GetCurrentUserResponses, GetCustomDomainData, GetCustomDomainErrors, GetCustomDomainResponse, GetCustomDomainResponses, GetDashboardData, GetDashboardError, GetDashboardErrors, GetDashboardProjectsAnalyticsData, GetDashboardProjectsAnalyticsErrors, GetDashboardProjectsAnalyticsResponse, GetDashboardProjectsAnalyticsResponses, GetDashboardResponse, GetDashboardResponses, GetDeliveryData, GetDeliveryErrors, GetDeliveryResponse, GetDeliveryResponses, GetDeploymentContainerLogContentData, GetDeploymentContainerLogContentErrors, GetDeploymentContainerLogContentResponse, GetDeploymentContainerLogContentResponses, GetDeploymentData, GetDeploymentErrors, GetDeploymentJobLogsData, GetDeploymentJobLogsErrors, GetDeploymentJobLogsResponse, GetDeploymentJobLogsResponses, GetDeploymentJobsData, GetDeploymentJobsErrors, GetDeploymentJobsResponse, GetDeploymentJobsResponses, GetDeploymentOperationsData, GetDeploymentOperationsErrors, GetDeploymentOperationsResponse, GetDeploymentOperationsResponses, GetDeploymentOperationStatusData, GetDeploymentOperationStatusErrors, GetDeploymentOperationStatusResponse, GetDeploymentOperationStatusResponses, GetDeploymentResponse, GetDeploymentResponses, GetDeploymentsParams, GetDeploymentTokenData, GetDeploymentTokenErrors, GetDeploymentTokenResponse, GetDeploymentTokenResponses, GetDiskStatusData, GetDiskStatusErrors, GetDiskStatusResponse, GetDiskStatusResponses, GetDnsChangesData, GetDnsChangesErrors, GetDnsChangesResponse, GetDnsChangesResponses, GetDnsProviderData, GetDnsProviderErrors, GetDnsProviderResponse, GetDnsProviderResponses, GetDomainByHostData, GetDomainByHostErrors, GetDomainByHostResponse, GetDomainByHostResponses, GetDomainByIdData, GetDomainByIdErrors, GetDomainByIdResponse, GetDomainByIdResponses, GetDomainByNameData, GetDomainByNameErrors, GetDomainByNameResponse, GetDomainByNameResponses, GetDomainData, GetDomainDnsRecordsData, GetDomainDnsRecordsErrors, GetDomainDnsRecordsResponse, GetDomainDnsRecordsResponses, GetDomainErrors, GetDomainOrderData, GetDomainOrderErrors, GetDomainOrderResponse, GetDomainOrderResponses, GetDomainResponse, GetDomainResponses, GetEmailData, GetEmailErrors, GetEmailEventsData, GetEmailEventsErrors, GetEmailEventsResponse, GetEmailEventsResponses, GetEmailLinksData, GetEmailLinksErrors, GetEmailLinksResponse, GetEmailLinksResponses, GetEmailProviderData, GetEmailProviderErrors, GetEmailProviderResponse, GetEmailProviderResponses, GetEmailResponse, GetEmailResponses, GetEmailStatsData, GetEmailStatsErrors, GetEmailStatsResponse, GetEmailStatsResponses, GetEmailTrackingData, GetEmailTrackingErrors, GetEmailTrackingResponse, GetEmailTrackingResponses, GetEmailTrackingStatusData, GetEmailTrackingStatusErrors, GetEmailTrackingStatusResponse, GetEmailTrackingStatusResponses, GetEntityInfoData, GetEntityInfoErrors, GetEntityInfoResponse, GetEntityInfoResponses, GetEnvironmentCronsData, GetEnvironmentCronsErrors, GetEnvironmentCronsResponse, GetEnvironmentCronsResponses, GetEnvironmentData, GetEnvironmentDomainsData, GetEnvironmentDomainsErrors, GetEnvironmentDomainsResponse, GetEnvironmentDomainsResponses, GetEnvironmentErrors, GetEnvironmentResponse, GetEnvironmentResponses, GetEnvironmentsData, GetEnvironmentsErrors, GetEnvironmentsResponse, GetEnvironmentsResponses, GetEnvironmentVariablesData, GetEnvironmentVariablesErrors, GetEnvironmentVariablesQuery, GetEnvironmentVariablesResponse, GetEnvironmentVariablesResponses, GetEnvironmentVariableValueData, GetEnvironmentVariableValueErrors, GetEnvironmentVariableValueResponse, GetEnvironmentVariableValueResponses, GetErrorDashboardStatsData, GetErrorDashboardStatsErrors, GetErrorDashboardStatsResponse, GetErrorDashboardStatsResponses, GetErrorEventData, GetErrorEventErrors, GetErrorEventResponse, GetErrorEventResponses, GetErrorGroupData, GetErrorGroupErrors, GetErrorGroupResponse, GetErrorGroupResponses, GetErrorStatsData, GetErrorStatsErrors, GetErrorStatsResponse, GetErrorStatsResponses, GetErrorTimeSeriesData, GetErrorTimeSeriesErrors, GetErrorTimeSeriesResponse, GetErrorTimeSeriesResponses, GetEventDetailData, GetEventDetailErrors, GetEventDetailResponse, GetEventDetailResponses, GetEventEntriesData, GetEventEntriesErrors, GetEventEntriesResponse, GetEventEntriesResponses, GetEventsCountData, GetEventsCountErrors, GetEventsCountResponse, GetEventsCountResponses, GetEventsTimelineData, GetEventsTimelineErrors, GetEventsTimelineResponse, GetEventsTimelineResponses, GetEventTypeBreakdownData, GetEventTypeBreakdownErrors, GetEventTypeBreakdownResponse, GetEventTypeBreakdownResponses, GetEventVisitorsData, GetEventVisitorsErrors, GetEventVisitorsResponse, GetEventVisitorsResponses, GetExternalImageData, GetExternalImageErrors, GetExternalImageResponse, GetExternalImageResponses, GetFileData, GetFileErrors, GetFileResponse, GetFileResponses, GetFlagData, GetFlagErrors, GetFlagResponse, GetFlagResponses, GetFlagSnapshotData, GetFlagSnapshotErrors, GetFlagSnapshotResponse, GetFlagSnapshotResponses, GetFunnelMetricsData, GetFunnelMetricsErrors, GetFunnelMetricsQuery, GetFunnelMetricsResponse, GetFunnelMetricsResponses, GetGenaiTraceData, GetGenaiTraceError, GetGenaiTraceErrors, GetGenaiTraceResponse, GetGenaiTraceResponses, GetGeneralStatsData, GetGeneralStatsErrors, GetGeneralStatsResponse, GetGeneralStatsResponses, GetGitProviderData, GetGitProviderErrors, GetGitProviderResponse, GetGitProviderResponses, GetGlobalEventsData, GetGlobalEventsErrors, GetGlobalEventsResponse, GetGlobalEventsResponses, GetGlobalEventStatsData, GetGlobalEventStatsErrors, GetGlobalEventStatsResponse, GetGlobalEventStatsResponses, GetGlobalMcpData, GetGlobalMcpErrors, GetGlobalMcpResponse, GetGlobalMcpResponses, GetGlobalSandboxStatusData, GetGlobalSandboxStatusErrors, GetGlobalSandboxStatusResponse, GetGlobalSandboxStatusResponses, GetGlobalSkillData, GetGlobalSkillErrors, GetGlobalSkillResponse, GetGlobalSkillResponses, GetGroupedPageMetricsData, GetGroupedPageMetricsError, GetGroupedPageMetricsErrors, GetGroupedPageMetricsResponse, GetGroupedPageMetricsResponses, GetHealthData, GetHealthError, GetHealthErrors, GetHealthResponse, GetHealthResponses, GetHourlyVisitsData, GetHourlyVisitsErrors, GetHourlyVisitsResponse, GetHourlyVisitsResponses, GetHttpChallengeDebugData, GetHttpChallengeDebugErrors, GetHttpChallengeDebugResponse, GetHttpChallengeDebugResponses, GetImportStatusData, GetImportStatusErrors, GetImportStatusResponse, GetImportStatusResponses, GetIncidentData, GetIncidentErrors, GetIncidentResponse, GetIncidentResponses, GetIncidentUpdatesData, GetIncidentUpdatesErrors, GetIncidentUpdatesResponse, GetIncidentUpdatesResponses, GetIpAccessControlData, GetIpAccessControlError, GetIpAccessControlErrors, GetIpAccessControlResponse, GetIpAccessControlResponses, GetIpGeolocationData, GetIpGeolocationError, GetIpGeolocationErrors, GetIpGeolocationResponse, GetIpGeolocationResponses, GetJoinTokenStatusData, GetJoinTokenStatusErrors, GetJoinTokenStatusResponse, GetJoinTokenStatusResponses, GetLastDeploymentData, GetLastDeploymentErrors, GetLastDeploymentResponse, GetLastDeploymentResponses, GetLatestScanData, GetLatestScanError, GetLatestScanErrors, GetLatestScanResponse, GetLatestScanResponses, GetLatestScansPerEnvironmentData, GetLatestScansPerEnvironmentError, GetLatestScansPerEnvironmentErrors, GetLatestScansPerEnvironmentResponse, GetLatestScansPerEnvironmentResponses, GetLiveVisitorsListData, GetLiveVisitorsListErrors, GetLiveVisitorsListResponse, GetLiveVisitorsListResponses, GetLogContextData, GetLogContextError, GetLogContextErrors, GetLogContextResponse, GetLogContextResponses, GetMcpData, GetMcpErrors, GetMcpResponse, GetMcpResponses, GetMetricsOverTimeData, GetMetricsOverTimeError, GetMetricsOverTimeErrors, GetMetricsOverTimeResponse, GetMetricsOverTimeResponses, GetMonitorData, GetMonitorErrors, GetMonitorResponse, GetMonitorResponses, GetNotificationProviderData, GetNotificationProviderErrors, GetNotificationProviderResponse, GetNotificationProviderResponses, GetOnDemandCertStatusData, GetOnDemandCertStatusErrors, GetOnDemandCertStatusResponse, GetOnDemandCertStatusResponses, GetOrCreateDsnData, GetOrCreateDsnErrors, GetOrCreateDsnRequest, GetOrCreateDsnResponse, GetOrCreateDsnResponses, GetPageFlowData, GetPageFlowErrors, GetPageFlowResponse, GetPageFlowResponses, GetPageHourlySessionsData, GetPageHourlySessionsErrors, GetPageHourlySessionsResponse, GetPageHourlySessionsResponses, GetPagePathDetailData, GetPagePathDetailErrors, GetPagePathDetailResponse, GetPagePathDetailResponses, GetPagePathsData, GetPagePathsErrors, GetPagePathsResponse, GetPagePathsResponses, GetPagePathsSparklinesData, GetPagePathsSparklinesErrors, GetPagePathsSparklinesResponse, GetPagePathsSparklinesResponses, GetPagePathVisitorsData, GetPagePathVisitorsErrors, GetPagePathVisitorsResponse, GetPagePathVisitorsResponses, GetPendingActionData, GetPendingActionErrors, GetPendingActionResponse, GetPendingActionResponses, GetPerformanceMetricsData, GetPerformanceMetricsError, GetPerformanceMetricsErrors, GetPerformanceMetricsResponse, GetPerformanceMetricsResponses, GetPgUpgradeData, GetPgUpgradeErrors, GetPgUpgradeLogsData, GetPgUpgradeLogsErrors, GetPgUpgradeLogsResponse, GetPgUpgradeLogsResponses, GetPgUpgradeResponse, GetPgUpgradeResponses, GetPipelineStatsData, GetPipelineStatsError, GetPipelineStatsErrors, GetPipelineStatsResponse, GetPipelineStatsResponses, GetPlatformInfoData, GetPlatformInfoErrors, GetPlatformInfoResponse, GetPlatformInfoResponses, GetPostgresWalHealthData, GetPostgresWalHealthErrors, GetPostgresWalHealthResponse, GetPostgresWalHealthResponses, GetPreferencesData, GetPreferencesErrors, GetPreferencesResponse, GetPreferencesResponses, GetPreviewGatewayLogsData, GetPreviewGatewayLogsResponse, GetPreviewGatewayLogsResponses, GetPreviewGatewaySettingsData, GetPreviewGatewaySettingsResponse, GetPreviewGatewaySettingsResponses, GetPreviewGatewayStatusData, GetPreviewGatewayStatusResponse, GetPreviewGatewayStatusResponses, GetPricingData, GetPricingError, GetPricingErrors, GetPricingResponse, GetPricingResponses, GetPrivateIpData, GetPrivateIpErrors, GetPrivateIpResponses, GetProjectAlarmsSummaryData, GetProjectAlarmsSummaryErrors, GetProjectAlarmsSummaryResponse, GetProjectAlarmsSummaryResponses, GetProjectBySlugData, GetProjectBySlugErrors, GetProjectBySlugResponse, GetProjectBySlugResponses, GetProjectData, GetProjectDeploymentsData, GetProjectDeploymentsErrors, GetProjectDeploymentsResponse, GetProjectDeploymentsResponses, GetProjectErrors, GetProjectResponse, GetProjectResponses, GetProjectsData, GetProjectSecretsQuery, GetProjectsErrors, GetProjectServiceEnvironmentVariablesData, GetProjectServiceEnvironmentVariablesErrors, GetProjectServiceEnvironmentVariablesResponse, GetProjectServiceEnvironmentVariablesResponses, GetProjectSessionReplaysData, GetProjectSessionReplaysError, GetProjectSessionReplaysErrors, GetProjectSessionReplaysQuery, GetProjectSessionReplaysResponse, GetProjectSessionReplaysResponse2, GetProjectSessionReplaysResponses, GetProjectsHealthData, GetProjectsHealthError, GetProjectsHealthErrors, GetProjectsHealthResponse, GetProjectsHealthResponses, GetProjectsMonitorHealthData, GetProjectsMonitorHealthErrors, GetProjectsMonitorHealthResponse, GetProjectsMonitorHealthResponses, GetProjectsResponse, GetProjectsResponses, GetProjectStatisticsData, GetProjectStatisticsErrors, GetProjectStatisticsResponse, GetProjectStatisticsResponses, GetProjectTemplateData, GetProjectTemplateErrors, GetProjectTemplateResponse, GetProjectTemplateResponses, GetPropertyBreakdownData, GetPropertyBreakdownErrors, GetPropertyBreakdownResponse, GetPropertyBreakdownResponses, GetPropertyTimelineData, GetPropertyTimelineErrors, GetPropertyTimelineResponse, GetPropertyTimelineResponses, GetProviderConnectionsData, GetProviderConnectionsErrors, GetProviderConnectionsResponse, GetProviderConnectionsResponses, GetProviderMetadataData, GetProviderMetadataErrors, GetProviderMetadataResponse, GetProviderMetadataResponses, GetProvidersMetadataData, GetProvidersMetadataErrors, GetProvidersMetadataResponse, GetProvidersMetadataResponses, GetProxyLogByIdData, GetProxyLogByIdError, GetProxyLogByIdErrors, GetProxyLogByIdResponse, GetProxyLogByIdResponses, GetProxyLogByRequestIdData, GetProxyLogByRequestIdError, GetProxyLogByRequestIdErrors, GetProxyLogByRequestIdResponse, GetProxyLogByRequestIdResponses, GetProxyLogsData, GetProxyLogsError, GetProxyLogsErrors, GetProxyLogsResponse, GetProxyLogsResponses, GetPublicBranchesData, GetPublicBranchesErrors, GetPublicBranchesResponse, GetPublicBranchesResponses, GetPublicIpData, GetPublicIpErrors, GetPublicIpResponses, GetPublicRepositoryData, GetPublicRepositoryErrors, GetPublicRepositoryResponse, GetPublicRepositoryResponses, GetQuotaData, GetQuotaError, GetQuotaErrors, GetQuotaResponse, GetQuotaResponses, GetRecentActivityData, GetRecentActivityErrors, GetRecentActivityResponse, GetRecentActivityResponses, GetRemoteExternalImageData, GetRemoteExternalImageErrors, GetRemoteExternalImageResponse, GetRemoteExternalImageResponses, GetRepositoryBranchesData, GetRepositoryBranchesErrors, GetRepositoryBranchesResponse, GetRepositoryBranchesResponses, GetRepositoryByIdData, GetRepositoryByIdErrors, GetRepositoryByIdResponse, GetRepositoryByIdResponses, GetRepositoryByNameData, GetRepositoryByNameErrors, GetRepositoryByNameResponse, GetRepositoryByNameResponses, GetRepositoryPresetByNameData, GetRepositoryPresetByNameErrors, GetRepositoryPresetByNameResponse, GetRepositoryPresetByNameResponses, GetRepositoryPresetLiveData, GetRepositoryPresetLiveErrors, GetRepositoryPresetLiveResponse, GetRepositoryPresetLiveResponses, GetRepositoryTagsData, GetRepositoryTagsErrors, GetRepositoryTagsResponse, GetRepositoryTagsResponses, GetRequest, GetResolvedEnvironmentVariablesData, GetResolvedEnvironmentVariablesErrors, GetResolvedEnvironmentVariablesResponse, GetResolvedEnvironmentVariablesResponses, GetResolvedEnvironmentVariableValueData, GetResolvedEnvironmentVariableValueErrors, GetResolvedEnvironmentVariableValueResponse, GetResolvedEnvironmentVariableValueResponses, GetResponse, GetRestoreCapabilitiesData, GetRestoreCapabilitiesError, GetRestoreCapabilitiesErrors, GetRestoreCapabilitiesResponse, GetRestoreCapabilitiesResponses, GetRestoreRunData, GetRestoreRunError, GetRestoreRunErrors, GetRestoreRunResponse, GetRestoreRunResponses, GetRouteData, GetRouteErrors, GetRouteResponse, GetRouteResponses, GetRunData, GetRunErrors, GetRunResponse, GetRunResponses, GetRunWithLogsData, GetRunWithLogsErrors, GetRunWithLogsResponse, GetRunWithLogsResponses, GetS3CredentialsData, GetS3CredentialsErrors, GetS3CredentialsResponse, GetS3CredentialsResponses, GetS3SourceData, GetS3SourceError, GetS3SourceErrors, GetS3SourceResponse, GetS3SourceResponses, GetSandboxData, GetSandboxErrors, GetSandboxResponse, GetSandboxResponses, GetSandboxStatusData, GetSandboxStatusErrors, GetSandboxStatusResponse, GetSandboxStatusResponses, GetScanByDeploymentData, GetScanByDeploymentError, GetScanByDeploymentErrors, GetScanByDeploymentResponse, GetScanByDeploymentResponses, GetScanData, GetScanError, GetScanErrors, GetScanResponse, GetScanResponses, GetScanVulnerabilitiesData, GetScanVulnerabilitiesError, GetScanVulnerabilitiesErrors, GetScanVulnerabilitiesResponse, GetScanVulnerabilitiesResponses, GetServiceBySlugData, GetServiceBySlugErrors, GetServiceBySlugResponse, GetServiceBySlugResponses, GetServiceData, GetServiceEnvironmentVariableData, GetServiceEnvironmentVariableErrors, GetServiceEnvironmentVariableResponse, GetServiceEnvironmentVariableResponses, GetServiceEnvironmentVariablesData, GetServiceEnvironmentVariablesErrors, GetServiceEnvironmentVariablesResponse, GetServiceEnvironmentVariablesResponses, GetServiceErrors, GetServiceHealthStatusData, GetServiceHealthStatusErrors, GetServiceHealthStatusResponse, GetServiceHealthStatusResponses, GetServicePreviewEnvironmentVariableNamesData, GetServicePreviewEnvironmentVariableNamesErrors, GetServicePreviewEnvironmentVariableNamesResponse, GetServicePreviewEnvironmentVariableNamesResponses, GetServicePreviewEnvironmentVariablesMaskedData, GetServicePreviewEnvironmentVariablesMaskedErrors, GetServicePreviewEnvironmentVariablesMaskedResponse, GetServicePreviewEnvironmentVariablesMaskedResponses, GetServiceResponse, GetServiceResponses, GetServiceRuntimeData, GetServiceRuntimeErrors, GetServiceRuntimeResponse, GetServiceRuntimeResponses, GetServiceStatsData, GetServiceStatsErrors, GetServiceStatsResponse, GetServiceStatsResponses, GetServiceTypeParametersData, GetServiceTypeParametersErrors, GetServiceTypeParametersResponses, GetServiceTypesData, GetServiceTypesErrors, GetServiceTypesResponse, GetServiceTypesResponses, GetSessionDetailsData, GetSessionDetailsErrors, GetSessionDetailsResponse, GetSessionDetailsResponses, GetSessionEventsData, GetSessionEventsErrors, GetSessionEventsResponse, GetSessionEventsResponses, GetSessionLogsData, GetSessionLogsErrors, GetSessionLogsResponse, GetSessionLogsResponses, GetSessionReplayData, GetSessionReplayError, GetSessionReplayErrors, GetSessionReplayEventsData, GetSessionReplayEventsError, GetSessionReplayEventsErrors, GetSessionReplayEventsResponse, GetSessionReplayEventsResponses, GetSessionReplayResponse, GetSessionReplayResponse2, GetSessionReplayResponses, GetSettingsData, GetSettingsErrors, GetSettingsResponse, GetSettingsResponses, GetSkillData, GetSkillErrors, GetSkillResponse, GetSkillResponses, GetSlowQueriesData, GetSlowQueriesErrors, GetSlowQueriesResponse, GetSlowQueriesResponses, GetStaticBundleData, GetStaticBundleErrors, GetStaticBundleResponse, GetStaticBundleResponses, GetStatusOverviewData, GetStatusOverviewErrors, GetStatusOverviewResponse, GetStatusOverviewResponses, GetTagsByRepositoryIdData, GetTagsByRepositoryIdErrors, GetTagsByRepositoryIdResponse, GetTagsByRepositoryIdResponses, GetTeamData, GetTeamErrors, GetTeamResponse, GetTeamResponses, GetTimeBucketStatsData, GetTimeBucketStatsError, GetTimeBucketStatsErrors, GetTimeBucketStatsResponse, GetTimeBucketStatsResponses, GetTodayStatsData, GetTodayStatsError, GetTodayStatsErrors, GetTodayStatsResponse, GetTodayStatsResponses, GetTraceData, GetTraceError, GetTraceErrors, GetTraceResponse, GetTraceResponses, GetUnifiedTraceData, GetUnifiedTraceError, GetUnifiedTraceErrors, GetUnifiedTraceResponse, GetUnifiedTraceResponses, GetUniqueCountsData, GetUniqueCountsErrors, GetUniqueCountsResponse, GetUniqueCountsResponses, GetUniqueEventsData, GetUniqueEventsErrors, GetUniqueEventsQuery, GetUniqueEventsResponse, GetUniqueEventsResponses, GetUpdateStatusData, GetUpdateStatusErrors, GetUpdateStatusResponse, GetUpdateStatusResponses, GetUptimeHistoryData, GetUptimeHistoryErrors, GetUptimeHistoryResponse, GetUptimeHistoryResponses, GetUsageByProviderData, GetUsageByProviderError, GetUsageByProviderErrors, GetUsageByProviderResponse, GetUsageByProviderResponses, GetUsageRecentData, GetUsageRecentError, GetUsageRecentErrors, GetUsageRecentResponse, GetUsageRecentResponses, GetUsageSummaryData, GetUsageSummaryError, GetUsageSummaryErrors, GetUsageSummaryResponse, GetUsageSummaryResponses, GetUsageTimeseriesData, GetUsageTimeseriesError, GetUsageTimeseriesErrors, GetUsageTimeseriesResponse, GetUsageTimeseriesResponses, GetUsageTopModelsData, GetUsageTopModelsError, GetUsageTopModelsErrors, GetUsageTopModelsResponse, GetUsageTopModelsResponses, GetVisitorByGuidData, GetVisitorByGuidErrors, GetVisitorByGuidResponse, GetVisitorByGuidResponses, GetVisitorByIdData, GetVisitorByIdErrors, GetVisitorByIdResponse, GetVisitorByIdResponses, GetVisitorDetailsData, GetVisitorDetailsErrors, GetVisitorDetailsResponse, GetVisitorDetailsResponses, GetVisitorFacetsData, GetVisitorFacetsErrors, GetVisitorFacetsResponse, GetVisitorFacetsResponses, GetVisitorInfoData, GetVisitorInfoErrors, GetVisitorInfoResponse, GetVisitorInfoResponses, GetVisitorJourneyData, GetVisitorJourneyErrors, GetVisitorJourneyResponse, GetVisitorJourneyResponses, GetVisitorsData, GetVisitorsErrors, GetVisitorSessionsData, GetVisitorSessionsError, GetVisitorSessionsErrors, GetVisitorSessionsQuery, GetVisitorSessionsResponse, GetVisitorSessionsResponse2, GetVisitorSessionsResponses, GetVisitorsResponse, GetVisitorsResponses, GetVisitorStatsData, GetVisitorStatsErrors, GetVisitorStatsResponse, GetVisitorStatsResponses, GetWebhookData, GetWebhookErrors, GetWebhookResponse, GetWebhookResponses, GitPushEvent, GitRefResponse, GitSourcePlan, GlobalConversationResponse, GlobalEventStatsResponse, GlobalMrrResponse, GlobalRecentEventResponse, GlobalRevenueSummaryResponse, GrantProjectAccessData, GrantProjectAccessErrors, GrantProjectAccessResponse, GrantProjectAccessResponses, GroupedPageMetric, GroupedPageMetricsQuery, GroupedPageMetricsResponse, HandleGitProviderOauthCallbackData, HandleGitProviderOauthCallbackErrors, HasAnalyticsEventsData, HasAnalyticsEventsErrors, HasAnalyticsEventsResponse, HasAnalyticsEventsResponse2, HasAnalyticsEventsResponses, HasErrorGroupsData, HasErrorGroupsErrors, HasErrorGroupsResponse, HasErrorGroupsResponse2, HasErrorGroupsResponses, HasEventsQuery, HasEventsResponse, HasMetricsQuery, HasMetricsResponse, HasPerformanceMetricsData, HasPerformanceMetricsError, HasPerformanceMetricsErrors, HasPerformanceMetricsResponse, HasPerformanceMetricsResponses, HealthCheckConfiguration, HealthCheckEntryResponse, HealthResponse, HealthStatus, HealthSummary, HeartbeatApiRequest, HeartbeatResponse, HierarchyLevel, HistogramSummary, HostnameChange, HostnamePreviewResponse, HourlyPageSessions, HourlyVisitsQuery, HttpChallengeDebugResponse, ImportCredentials, ImportExecutionStatus, ImportExternalServiceData, ImportExternalServiceErrors, ImportExternalServiceRequest, ImportExternalServiceResponse, ImportExternalServiceResponses, ImportOutcomeResponse, ImportPlan, ImportRowErrorResponse, ImportSelector, ImportSource, ImportSourceCapabilities, ImportSourceInfo, ImportStatusResponse, IncidentBucket, IncidentBucketedResponse, IncidentResponse, IncidentUpdateResponse, IncrRequest, IncrResponse, IngestLogsByPathData, IngestLogsByPathError, IngestLogsByPathErrors, IngestLogsByPathResponses, IngestLogsData, IngestLogsError, IngestLogsErrors, IngestLogsResponses, IngestMetricsByPathData, IngestMetricsByPathError, IngestMetricsByPathErrors, IngestMetricsByPathResponses, IngestMetricsData, IngestMetricsError, IngestMetricsErrors, IngestMetricsResponses, IngestSentryEnvelopeData, IngestSentryEnvelopeErrors, IngestSentryEnvelopeResponses, IngestSentryEventData, IngestSentryEventErrors, IngestSentryEventResponse, IngestSentryEventResponses, IngestTracesByPathData, IngestTracesByPathError, IngestTracesByPathErrors, IngestTracesByPathResponses, IngestTracesData, IngestTracesError, IngestTracesErrors, IngestTracesResponses, InitAuthResponse, InitSessionReplayData, InitSessionReplayError, InitSessionReplayErrors, InitSessionReplayResponse, InitSessionReplayResponses, Insight, InsightSeverity, InsightsResponse, InsightStatus, InspectDropArchiveData, InspectDropArchiveErrors, InspectDropArchiveResponse, InspectDropArchiveResponses, IntegrationResponse, IpAccessControlQuery, IpAccessControlResponse, JobLogsData, JobLogsErrors, JobLogsResponses, JobStatusData, JobStatusErrors, JobStatusResponse, JobStatusResponse2, JobStatusResponses, JobSummaryResponse, JoinTokenStatusResponse, JourneyEvent, JourneySession, KeysRequest, KeysResponse, KillJobBody, KillJobData, KillJobErrors, KillJobResponse, KillJobResponses, KnownAiAgentsResponse, KvDelData, KvDelErrors, KvDelResponse, KvDelResponses, KvDisableData, KvDisableErrors, KvDisableResponse, KvDisableResponses, KvEnableData, KvEnableErrors, KvEnableResponse, KvEnableResponses, KvExpireData, KvExpireErrors, KvExpireResponse, KvExpireResponses, KvGetData, KvGetErrors, KvGetResponse, KvGetResponses, KvIncrData, KvIncrErrors, KvIncrResponse, KvIncrResponses, KvKeysData, KvKeysErrors, KvKeysResponse, KvKeysResponses, KvSetData, KvSetErrors, KvSetResponse, KvSetResponses, KvStatusData, KvStatusErrors, KvStatusResponse, KvStatusResponse2, KvStatusResponses, KvTtlData, KvTtlErrors, KvTtlResponse, KvTtlResponses, KvUpdateData, KvUpdateErrors, KvUpdateResponse, KvUpdateResponses, LatestRunForSourceData, LatestRunForSourceErrors, LatestRunForSourceResponse, LatestRunForSourceResponses, LemonSqueezyConfig, LetsEncryptSettings, LineContext, LinkCustomDomainToCertificateData, LinkCustomDomainToCertificateErrors, LinkCustomDomainToCertificateResponse, LinkCustomDomainToCertificateResponses, LinkServiceRequest, LinkServiceToProjectData, LinkServiceToProjectErrors, LinkServiceToProjectResponse, LinkServiceToProjectResponses, ListAgentRunsData, ListAgentRunsErrors, ListAgentRunsResponse, ListAgentRunsResponses, ListAgentsData, ListAgentsErrors, ListAgentsResponse, ListAgentsResponse2, ListAgentsResponses, ListAiProvidersData, ListAiProvidersErrors, ListAiProvidersResponse, ListAiProvidersResponses, ListAlertRulesData, ListAlertRulesErrors, ListAlertRulesResponse, ListAlertRulesResponses, ListAlertsData, ListAlertsError, ListAlertsErrors, ListAlertsResponse, ListAlertsResponses, ListAllConversationsData, ListAllConversationsErrors, ListAllConversationsResponse, ListAllConversationsResponses, ListAllRunsData, ListAllRunsErrors, ListAllRunsResponse, ListAllRunsResponses, ListApiKeysData, ListApiKeysErrors, ListApiKeysQuery, ListApiKeysResponse, ListApiKeysResponses, ListAuditLogsData, ListAuditLogsErrors, ListAuditLogsQuery, ListAuditLogsResponse, ListAuditLogsResponses, ListAvailableContainersData, ListAvailableContainersErrors, ListAvailableContainersResponse, ListAvailableContainersResponses, ListBackupAlertsData, ListBackupAlertsError, ListBackupAlertsErrors, ListBackupAlertsResponse, ListBackupAlertsResponses, ListBackupChildrenData, ListBackupChildrenError, ListBackupChildrenErrors, ListBackupChildrenResponse, ListBackupChildrenResponses, ListBackupSchedulesData, ListBackupSchedulesError, ListBackupSchedulesErrors, ListBackupSchedulesResponse, ListBackupSchedulesResponses, ListBackupsForScheduleData, ListBackupsForScheduleErrors, ListBackupsForScheduleResponse, ListBackupsForScheduleResponses, ListBlobsQuery, ListBlobsResponse, ListCommitsByRepositoryIdData, ListCommitsByRepositoryIdErrors, ListCommitsByRepositoryIdResponse, ListCommitsByRepositoryIdResponses, ListConnectionsData, ListConnectionsErrors, ListConnectionsResponse, ListConnectionsResponses, ListContainersAtPathData, ListContainersAtPathErrors, ListContainersAtPathResponse, ListContainersAtPathResponses, ListContainersData, ListContainersErrors, ListContainersResponse, ListContainersResponses, ListConversationsData, ListConversationsErrors, ListConversationsResponse, ListConversationsResponses, ListCustomDomainsForProjectData, ListCustomDomainsForProjectErrors, ListCustomDomainsForProjectResponse, ListCustomDomainsForProjectResponses, ListCustomDomainsResponse, ListDashboardsData, ListDashboardsError, ListDashboardsErrors, ListDashboardsResponse, ListDashboardsResponses, ListDeliveriesData, ListDeliveriesErrors, ListDeliveriesResponse, ListDeliveriesResponses, ListDeploymentContainerLogsData, ListDeploymentContainerLogsErrors, ListDeploymentContainerLogsResponse, ListDeploymentContainerLogsResponses, ListDeploymentTokensData, ListDeploymentTokensErrors, ListDeploymentTokensQuery, ListDeploymentTokensResponse, ListDeploymentTokensResponses, ListDnsProvidersData, ListDnsProvidersErrors, ListDnsProvidersResponse, ListDnsProvidersResponses, ListDomainsData, ListDomainsErrors, ListDomainsResponse, ListDomainsResponse2, ListDomainsResponses, ListDsnsData, ListDsnsErrors, ListDsnsResponse, ListDsnsResponses, ListEmailDomainsData, ListEmailDomainsErrors, ListEmailDomainsResponse, ListEmailDomainsResponses, ListEmailProvidersData, ListEmailProvidersErrors, ListEmailProvidersResponse, ListEmailProvidersResponses, ListEmailsData, ListEmailsErrors, ListEmailsResponse, ListEmailsResponses, ListEnrollmentTokensData, ListEnrollmentTokensErrors, ListEnrollmentTokensResponse, ListEnrollmentTokensResponses, ListEntitiesData, ListEntitiesErrors, ListEntitiesQuery, ListEntitiesResponse, ListEntitiesResponses, ListErrorEventsData, ListErrorEventsErrors, ListErrorEventsQuery, ListErrorEventsResponse, ListErrorEventsResponses, ListErrorGroupsData, ListErrorGroupsErrors, ListErrorGroupsQuery, ListErrorGroupsResponse, ListErrorGroupsResponses, ListEventsData, ListEventsResponse, ListEventsResponses, ListEventTypesData, ListEventTypesResponse, ListEventTypesResponses, ListExternalImagesData, ListExternalImagesErrors, ListExternalImagesResponse, ListExternalImagesResponses, ListExternalPluginsData, ListExternalPluginsErrors, ListExternalPluginsResponse, ListExternalPluginsResponses, ListExternalServiceBackupsData, ListExternalServiceBackupsError, ListExternalServiceBackupsErrors, ListExternalServiceBackupsResponse, ListExternalServiceBackupsResponses, ListFlagsData, ListFlagsErrors, ListFlagsResponse, ListFlagsResponses, ListFunnelsData, ListFunnelsErrors, ListFunnelsResponse, ListFunnelsResponses, ListGitProvidersData, ListGitProvidersErrors, ListGitProvidersResponse, ListGitProvidersResponses, ListGlobalMcpsData, ListGlobalMcpsErrors, ListGlobalMcpsResponse, ListGlobalMcpsResponses, ListGlobalSkillsData, ListGlobalSkillsErrors, ListGlobalSkillsResponse, ListGlobalSkillsResponses, ListIncidentsData, ListIncidentsErrors, ListIncidentsResponses, ListInsightsData, ListInsightsError, ListInsightsErrors, ListInsightsResponse, ListInsightsResponses, ListIpAccessControlData, ListIpAccessControlError, ListIpAccessControlErrors, ListIpAccessControlResponse, ListIpAccessControlResponses, ListJobsData, ListJobsErrors, ListJobsResponse, ListJobsResponse2, ListJobsResponses, ListKnownAiAgentsData, ListKnownAiAgentsError, ListKnownAiAgentsErrors, ListKnownAiAgentsResponse, ListKnownAiAgentsResponses, ListManagedDomainsData, ListManagedDomainsErrors, ListManagedDomainsResponse, ListManagedDomainsResponses, ListMcpsData, ListMcpsErrors, ListMcpsResponse, ListMcpsResponse2, ListMcpsResponses, ListMetricLabelKeysData, ListMetricLabelKeysError, ListMetricLabelKeysErrors, ListMetricLabelKeysResponse, ListMetricLabelKeysResponses, ListMetricLabelValuesData, ListMetricLabelValuesError, ListMetricLabelValuesErrors, ListMetricLabelValuesResponse, ListMetricLabelValuesResponses, ListMetricNamesData, ListMetricNamesError, ListMetricNamesErrors, ListMetricNamesResponse, ListMetricNamesResponses, ListModelsData, ListModelsError, ListModelsErrors, ListModelsResponse, ListModelsResponses, ListMonitorsData, ListMonitorsErrors, ListMonitorsResponse, ListMonitorsResponses, ListNotificationProvidersData, ListNotificationProvidersErrors, ListNotificationProvidersResponse, ListNotificationProvidersResponses, ListOidcProvidersData, ListOidcProvidersResponse, ListOidcProvidersResponses, ListOidcProviderUsersData, ListOidcProviderUsersErrors, ListOidcProviderUsersResponse, ListOidcProviderUsersResponses, ListOidcRoleMappingsData, ListOidcRoleMappingsResponse, ListOidcRoleMappingsResponses, ListOnDemandCertsData, ListOnDemandCertsErrors, ListOnDemandCertsResponse, ListOnDemandCertsResponse2, ListOnDemandCertsResponses, ListOrdersData, ListOrdersErrors, ListOrdersResponse, ListOrdersResponse2, ListOrdersResponses, ListPeersData, ListPeersErrors, ListPeersResponse, ListPeersResponses, ListPendingActionsData, ListPendingActionsErrors, ListPendingActionsResponse, ListPendingActionsResponses, ListPgUpgradesData, ListPgUpgradesErrors, ListPgUpgradesResponse, ListPgUpgradesResponses, ListPresetsData, ListPresetsErrors, ListPresetsResponse, ListPresetsResponse2, ListPresetsResponses, ListProjectAccessData, ListProjectAccessErrors, ListProjectAccessResponse, ListProjectAccessResponses, ListProjectAlarmsData, ListProjectAlarmsErrors, ListProjectAlarmsResponse, ListProjectAlarmsResponses, ListProjectScansData, ListProjectScansError, ListProjectScansErrors, ListProjectScansResponse, ListProjectScansResponses, ListProjectSecretsData, ListProjectSecretsErrors, ListProjectSecretsResponse, ListProjectSecretsResponses, ListProjectServicesData, ListProjectServicesErrors, ListProjectServicesResponse, ListProjectServicesResponses, ListProjectTemplatesData, ListProjectTemplatesErrors, ListProjectTemplatesResponse, ListProjectTemplatesResponses, ListProjectTemplateTagsData, ListProjectTemplateTagsErrors, ListProjectTemplateTagsResponse, ListProjectTemplateTagsResponses, ListProviderKeysData, ListProviderKeysError, ListProviderKeysErrors, ListProviderKeysResponse, ListProviderKeysResponses, ListProviderZonesData, ListProviderZonesErrors, ListProviderZonesResponse, ListProviderZonesResponses, ListPublicProvidersData, ListPublicProvidersResponse, ListPublicProvidersResponses, ListReleaseFilesData, ListReleaseFilesErrors, ListReleaseFilesResponse, ListReleaseFilesResponses, ListReleasesData, ListReleasesErrors, ListReleasesResponse, ListReleasesResponses, ListRemoteExternalImagesData, ListRemoteExternalImagesErrors, ListRemoteExternalImagesResponse, ListRemoteExternalImagesResponses, ListRepositoriesByConnectionData, ListRepositoriesByConnectionErrors, ListRepositoriesByConnectionResponse, ListRepositoriesByConnectionResponses, ListRepositoriesByProviderData, ListRepositoriesByProviderErrors, ListRepositoriesByProviderResponse, ListRepositoriesByProviderResponses, ListRestoreRunsForServiceData, ListRestoreRunsForServiceResponse, ListRestoreRunsForServiceResponses, ListRootContainersData, ListRootContainersErrors, ListRootContainersResponse, ListRootContainersResponses, ListRoutesData, ListRoutesErrors, ListRoutesResponse, ListRoutesResponses, ListRunsResponse, ListS3SourcesData, ListS3SourcesError, ListS3SourcesErrors, ListS3SourcesResponse, ListS3SourcesResponses, ListSandboxesData, ListSandboxesResponse, ListSandboxesResponse2, ListSandboxesResponses, ListScansQuery, ListScheduleRunJobsData, ListScheduleRunJobsError, ListScheduleRunJobsErrors, ListScheduleRunJobsResponse, ListScheduleRunJobsResponses, ListScheduleRunsData, ListScheduleRunsError, ListScheduleRunsErrors, ListScheduleRunsResponse, ListScheduleRunsResponses, ListScheduleServicesData, ListScheduleServicesError, ListScheduleServicesErrors, ListScheduleServicesResponse, ListScheduleServicesResponses, ListSecretsData, ListSecretsErrors, ListSecretsResponse, ListSecretsResponse2, ListSecretsResponses, ListServiceHealthStatusesData, ListServiceHealthStatusesErrors, ListServiceHealthStatusesResponse, ListServiceHealthStatusesResponses, ListServiceProjectsData, ListServiceProjectsErrors, ListServiceProjectsResponse, ListServiceProjectsResponses, ListServiceSchedulesData, ListServiceSchedulesError, ListServiceSchedulesErrors, ListServiceSchedulesResponse, ListServiceSchedulesResponses, ListServicesData, ListServicesErrors, ListServicesResponse, ListServicesResponses, ListSkillsData, ListSkillsErrors, ListSkillsResponse, ListSkillsResponse2, ListSkillsResponses, ListSourceBackupsData, ListSourceBackupsError, ListSourceBackupsErrors, ListSourceBackupsResponse, ListSourceBackupsResponses, ListSourceFilesData, ListSourceFilesErrors, ListSourceFilesResponse, ListSourceFilesResponses, ListSourceMapsData, ListSourceMapsErrors, ListSourceMapsResponse, ListSourceMapsResponses, ListSourcesData, ListSourcesErrors, ListSourcesResponse, ListSourcesResponses, ListStaticBundlesData, ListStaticBundlesErrors, ListStaticBundlesResponse, ListStaticBundlesResponses, ListSyncedRepositoriesData, ListSyncedRepositoriesErrors, ListSyncedRepositoriesResponse, ListSyncedRepositoriesResponses, ListTagsResponse, ListTeamMembersData, ListTeamMembersErrors, ListTeamMembersResponse, ListTeamMembersResponses, ListTeamProjectsData, ListTeamProjectsErrors, ListTeamProjectsResponse, ListTeamProjectsResponses, ListTeamsData, ListTeamsErrors, ListTeamsResponse, ListTeamsResponses, ListTemplatesQuery, ListTemplatesResponse, ListUsersData, ListUsersErrors, ListUsersResponse, ListUsersResponses, ListVulnerabilitiesQuery, ListWebhooksData, ListWebhooksErrors, ListWebhooksResponse, ListWebhooksResponses, LiveVisitorInfo, LiveVisitorsListResponse, LocationCount, LocationGranularity, LocationInfo, LoginData, LoginErrors, LoginRequest, LoginResponse, LoginResponses, LogLevel, LogoutData, LogoutErrors, LogoutResponses, LogRecord, LogSearchLine, LogSeverity, LogSource, LogsQuery, LogsResponse, LogStream, LookupDnsARecordsData, LookupDnsARecordsError, LookupDnsARecordsErrors, LookupDnsARecordsResponse, LookupDnsARecordsResponses, ManagedDomainResponse, ManualAction, ManualActionTiming, McpDefinitionResponse, MessageContent, MessagePart, MessageResponse, MeteredMode, MetricAggregation, MetricBucket, MetricDataPoint, MetricsOverTimeResponse, MetricsQuery, MetricsRangeQuery, MetricsStatusResponse, MetricsStoreKind, MetricsSummaryResponse, MetricType, MfaRequiredResponse, MfaSetupResponse, MfaVerificationRequest, MigrationStep, MigrationSummary, MintEnrollmentTokenData, MintEnrollmentTokenErrors, MintEnrollmentTokenRequest, MintEnrollmentTokenResponse, MintEnrollmentTokenResponse2, MintEnrollmentTokenResponses, MiscResult, MkdirBody, MkdirData, MkdirErrors, MkdirResponse, MkdirResponses, ModelInfo, ModelListResponse, ModelPricing, ModelUsage, MonitoringSettings, MonitoringSettingsMasked, MonitorResponse, MonitorStatus, MrrBucketResponse, MultiNodeSettings, MultiNodeSettingsMasked, MxResult, NavEntry, NavSection, NetworkConfiguration, NetworkMode, NixpacksPresetConfig, NixpacksProvider, NodeContainerListResponse, NodeContainerResponse, NodeCostInfo, NodeHeartbeatData, NodeHeartbeatErrors, NodeHeartbeatResponse, NodeHeartbeatResponses, NodeInfoResponse, NodeListResponse, NodeMetricsGetRangeData, NodeMetricsGetRangeErrors, NodeMetricsGetRangeResponse, NodeMetricsGetRangeResponses, NotificationPreferencesResponse, NotificationProviderResponse, ObservabilityCompressionSettings, ObservabilityEvent, ObservabilityFullEventData, ObservabilityFullEventError, ObservabilityFullEventErrors, ObservabilityFullEventResponse, ObservabilityFullEventResponses, ObservabilityListEventsData, ObservabilityListEventsError, ObservabilityListEventsErrors, ObservabilityListEventsResponse, ObservabilityListEventsResponses, ObservabilityRetentionSettings, OidcCallbackData, OidcProviderResponse, OidcProvidersListResponse, OidcProviderSummary, OidcProviderUserResponse, OidcRoleMappingResponse, OidcTestConnectionResponse, OnDemandCertAttemptResponse, OnDemandCertRow, OnDemandTlsSettings, OpenAiError, OpenAiErrorResponse, OperatingSystemCount, OperationResultResponse, OperationResultsResponse, OtelDashboardResponse, OtelDashboardsResponse, OtelMetricAlertRuleResponse, OtelMetricAlertsResponse, OtelMetricLabelKeysResponse, OtelMetricLabelValuesResponse, OtelMetricNamesResponse, OtelMetricsResponse, OutlierAlgorithm, OutlierParams, OverprovisioningAssessment, OverprovisioningVerdict, PageActivityBucket, PageCountryStats, PageFlowEntry, PageFlowQuery, PageFlowResponse, PageHourlySessionsQuery, PageHourlySessionsResponse, PagePathDetailQuery, PagePathDetailResponse, PagePathInfo, PagePathSparkline, PagePathSparklinePoint, PagePathsQuery, PagePathsResponse, PagePathsSparklineQuery, PagePathsSparklineResponse, PagePathVisitorsQuery, PagePathVisitorsResponse, PageReferrerStats, PagesComparisonResponse, PageSessionComparison, PageSessionStats, PageSessionStatsQuery, PageTransition, PageVisit, PageVisitorSession, PaginatedEmailsResponse, PaginatedEntitiesResponse, PaginatedErrorEventsResponse, PaginatedErrorGroupsResponse, PaginatedEventsResponse, PaginatedExternalImagesResponse, PaginatedProjectList, PaginatedStaticBundlesResponse, Pagination, PaginationMeta, PaginationParams, PasswordProtectionConfig, PatchAdminGateData, PatchAdminGateErrors, PatchAdminGateResponse, PatchAdminGateResponses, PatchPreviewGatewaySettingsData, PatchPreviewGatewaySettingsResponse, PatchPreviewGatewaySettingsResponses, PatchSettingsRequest, PathVisitors, PathVisitorsAnalyticsQuery, PathVisitorsResponse, PauseDeploymentData, PauseDeploymentErrors, PauseDeploymentResponse, PauseDeploymentResponses, PauseSandboxData, PauseSandboxErrors, PauseSandboxResponse, PauseSandboxResponses, PeerEntry, PeerListResponse, PendingActionResponse, PerformanceMetricsQuery, PerformanceMetricsResponse, PermissionInfo, PgUpgradeLogResponse, PgUpgradeResponse, PipelineStats, PipelineStatsResponse, PlanComplexity, PlanMetadata, PlanRestoreData, PlanRestoreError, PlanRestoreErrors, PlanRestoreResponse, PlanRestoreResponses, PlanSourceBackup, PlanTarget, PlatformInfo, PluginManifest, PortMapping, PostDnsAckData, PostDnsAckErrors, PostDnsAckResponse, PostDnsAckResponses, PostgresWalHealth, PresetConfigSchema, PresetInfo, PresetResponse, PreviewAlertData, PreviewAlertError, PreviewAlertErrors, PreviewAlertResponse, PreviewAlertResponses, PreviewFunnelMetricsData, PreviewFunnelMetricsErrors, PreviewFunnelMetricsResponse, PreviewFunnelMetricsResponses, PreviewGatewaySettings, PreviewGatewaySettingsMasked, PreviewGatewaySettingsResponse, PreviewHostnameModeData, PreviewHostnameModeErrors, PreviewHostnameModeResponse, PreviewHostnameModeResponses, PreviewShareLinkBody, PreviewShareLinkResponse, PricingResponse, ProblemDetails, ProjectAccessResponse, ProjectConfiguration, ProjectDashboardAnalytics, ProjectDsnResponse, ProjectHealthSummary, ProjectInfo, ProjectMonitorHealth, ProjectPresetResponse, ProjectQuery, ProjectRef, ProjectResponse, ProjectSecretEnvironmentInfo, ProjectSecretResponse, ProjectServiceInfo, ProjectsHealthResponse, ProjectsMonitorHealthResponse, ProjectStatisticsResponse, ProjectStatsBreakdown, ProjectType, ProjectUsageInfoResponse, PromoteClusterMemberData, PromoteClusterMemberErrors, PromoteClusterMemberResponses, PromoteDeploymentData, PromoteDeploymentErrors, PromoteDeploymentRequest, PromoteDeploymentResponse, PromoteDeploymentResponses, PropertyBreakdownItem, PropertyBreakdownQuery, PropertyBreakdownResponse, PropertyColumn, PropertyTimelineItem, PropertyTimelineQuery, PropertyTimelineResponse, Protocol, ProviderCatalogDto, ProviderCatalogResponse, ProviderConfig, ProviderConfigMasked, ProviderDeletionCheckResponse, ProviderDescriptor, ProviderKeyResponse, ProviderMetadata, ProviderResponse, ProviderUsage, ProvisionDomainData, ProvisionDomainErrors, ProvisionDomainResponse, ProvisionDomainResponses, ProvisionResponse, ProxyLogResponse, ProxyLogsPaginatedResponse, PublicHostnameStrategy, PublicPresetResponse, PublicRepositoryInfo, PurgeLogsRequest, PurgeProjectLogsData, PurgeProjectLogsError, PurgeProjectLogsErrors, PurgeProjectLogsResponses, PushedExternalImageResponse, PushExternalImageData, PushExternalImageErrors, PushExternalImageResponse, PushExternalImageResponses, PushImageRequest, QueryDataData, QueryDataErrors, QueryDataRequest, QueryDataResponse, QueryDataResponse2, QueryDataResponses, QueryGenaiTracesData, QueryGenaiTracesError, QueryGenaiTracesErrors, QueryGenaiTracesResponse, QueryGenaiTracesResponses, QueryLogsData, QueryLogsError, QueryLogsErrors, QueryLogsResponse, QueryLogsResponses, QueryMetricsData, QueryMetricsError, QueryMetricsErrors, QueryMetricsResponse, QueryMetricsResponses, QueryTracesData, QueryTracesError, QueryTracesErrors, QueryTracesResponse, QueryTracesResponses, QueryTraceSummariesData, QueryTraceSummariesError, QueryTraceSummariesErrors, QueryTraceSummariesResponse, QueryTraceSummariesResponses, QuotaResponse, RateLimitConfig, RateLimitSettings, ReachabilityStatus, ReadFileData, ReadFileErrors, ReadFileResponse, ReadFileResponse2, ReadFileResponses, ReAnalyzeData, ReAnalyzeErrors, ReAnalyzeResponses, RebuildSandboxImageData, RebuildSandboxImageErrors, RebuildSandboxImageResponses, RecentActivityQuery, RecentActivityResponse, RecentEventResponse, RecentQueryParams, RecordConsoleEventData, RecordConsoleEventErrors, RecordConsoleEventResponses, RecordEventMetricsData, RecordEventMetricsErrors, RecordEventMetricsResponse, RecordEventMetricsResponses, RecordExposureRequest, RecordExposureResponse, RecordFlagExposureData, RecordFlagExposureErrors, RecordFlagExposureResponse, RecordFlagExposureResponses, RecordListResponse, RecordSpeedMetricsData, RecordSpeedMetricsError, RecordSpeedMetricsErrors, RecordSpeedMetricsResponse, RecordSpeedMetricsResponses, RecoveryTarget, ReferrerCount, ReferrersAnalyticsQuery, RefreshRouteTableData, RefreshRouteTableErrors, RefreshRouteTableResponse, RefreshRouteTableResponses, RegenerateDsnData, RegenerateDsnErrors, RegenerateDsnRequest, RegenerateDsnResponse, RegenerateDsnResponses, RegisterExternalImageData, RegisterExternalImageErrors, RegisterExternalImageResponse, RegisterExternalImageResponses, RegisterImageRequest, RegisterNodeApiRequest, RegisterNodeData, RegisterNodeErrors, RegisterNodeResponse, RegisterNodeResponse2, RegisterNodeResponses, RegisterRequest, ReinstallGitlabWebhookData, ReinstallGitlabWebhookErrors, ReinstallGitlabWebhookResponse, ReinstallGitlabWebhookResponses, ReinstallWebhookResponse, RejectPendingActionData, RejectPendingActionErrors, RejectPendingActionResponse, RejectPendingActionResponses, ReleaseListResponse, ReloadPluginsData, ReloadPluginsErrors, ReloadPluginsResponse, ReloadPluginsResponses, ReloadResponse, RemoteDeploymentResponse, RemoveClusterMemberData, RemoveClusterMemberErrors, RemoveClusterMemberResponse, RemoveClusterMemberResponses, RemoveManagedDomainData, RemoveManagedDomainErrors, RemoveManagedDomainResponse, RemoveManagedDomainResponses, RemoveNodeResponse, RemoveRoleData, RemoveRoleErrors, RemoveRoleResponse, RemoveRoleResponses, RemoveTeamMemberData, RemoveTeamMemberErrors, RemoveTeamMemberResponse, RemoveTeamMemberResponses, RenameConversationData, RenameConversationErrors, RenameConversationRequest, RenameConversationResponse, RenameConversationResponses, RenewDomainData, RenewDomainErrors, RenewDomainResponse, RenewDomainResponses, RepositoryListQuery, RepositoryListResponse, RepositoryPresetResponse, RepositoryResponse, RepositorySyncStartedResponse, RequestPasswordResetData, RequestPasswordResetErrors, RequestPasswordResetResponse, RequestPasswordResetResponses, RequestRow, ResetPasswordData, ResetPasswordErrors, ResetPasswordRequest, ResetPasswordResponse, ResetPasswordResponses, ResetPgStatStatementsRequest, ResetPgStatStatementsResponse, ResizeSandboxBody, ResizeSandboxData, ResizeSandboxErrors, ResizeSandboxResponse, ResizeSandboxResponses, ResolveAlarmData, ResolveAlarmErrors, ResolveAlarmResponses, ResolvedEnvVarResponse, ResolvedEnvVarSource, ResourceCounts, ResourceFootprint, ResourceInfo, ResourceLimitApplyResult, ResourceLimits, ResourceLimitsResponse, ResourceLimitsUpdateResponse, ResourcesBody, RestartContainerData, RestartContainerErrors, RestartContainerResponse, RestartContainerResponses, RestartPreviewGatewayData, RestartPreviewGatewayResponse, RestartPreviewGatewayResponses, RestartSandboxData, RestartSandboxErrors, RestartSandboxResponse, RestartSandboxResponses, RestoreCapabilities, RestoreCapabilitiesResponse, RestoreFlagData, RestoreFlagErrors, RestoreFlagResponse, RestoreFlagResponses, RestorePlan, RestoreRequestMode, RestoreRunView, RestoreUserData, RestoreUserErrors, RestoreUserResponse, RestoreUserResponses, ResumeDeploymentData, ResumeDeploymentErrors, ResumeDeploymentResponse, ResumeDeploymentResponses, ResumeSandboxData, ResumeSandboxErrors, ResumeSandboxResponse, ResumeSandboxResponses, RetentionCleanupFailure, RetentionCleanupReport, RetryClusterData, RetryClusterErrors, RetryClusterRequest, RetryClusterResponse, RetryClusterResponses, RetryDeliveryData, RetryDeliveryErrors, RetryDeliveryResponse, RetryDeliveryResponses, RetryPgUpgradeData, RetryPgUpgradeErrors, RetryPgUpgradeResponse, RetryPgUpgradeResponses, RetryRunData, RetryRunErrors, RetryRunResponse, RetryRunResponses, RevealGlobalMcpConfigData, RevealGlobalMcpConfigErrors, RevealGlobalMcpConfigResponse, RevealGlobalMcpConfigResponses, RevealMcpConfigData, RevealMcpConfigErrors, RevealMcpConfigResponse, RevealMcpConfigResponses, RevealNotificationProviderConfigData, RevealNotificationProviderConfigErrors, RevealNotificationProviderConfigResponse, RevealNotificationProviderConfigResponses, RevealServiceParameterData, RevealServiceParameterErrors, RevealServiceParameterResponse, RevealServiceParameterResponses, RevenueCreateIntegrationData, RevenueCreateIntegrationErrors, RevenueCreateIntegrationResponse, RevenueCreateIntegrationResponses, RevenueDeleteIntegrationData, RevenueDeleteIntegrationResponse, RevenueDeleteIntegrationResponses, RevenueGlobalEventsData, RevenueGlobalEventsResponse, RevenueGlobalEventsResponses, RevenueImportInvoicesCsvData, RevenueImportInvoicesCsvErrors, RevenueImportInvoicesCsvResponse, RevenueImportInvoicesCsvResponses, RevenueImportSubscriptionsCsvData, RevenueImportSubscriptionsCsvErrors, RevenueImportSubscriptionsCsvResponse, RevenueImportSubscriptionsCsvResponses, RevenueListIntegrationsData, RevenueListIntegrationsResponse, RevenueListIntegrationsResponses, RevenueListProvidersData, RevenueListProvidersResponse, RevenueListProvidersResponses, RevenueMetricsCustomersData, RevenueMetricsCustomersResponse, RevenueMetricsCustomersResponses, RevenueMetricsGlobalMrrData, RevenueMetricsGlobalMrrResponse, RevenueMetricsGlobalMrrResponses, RevenueMetricsGlobalSummaryData, RevenueMetricsGlobalSummaryResponse, RevenueMetricsGlobalSummaryResponses, RevenueMetricsMrrData, RevenueMetricsMrrResponse, RevenueMetricsMrrResponses, RevenueMetricsSummaryData, RevenueMetricsSummaryResponse, RevenueMetricsSummaryResponses, RevenueRecentEventsData, RevenueRecentEventsResponse, RevenueRecentEventsResponses, RevenueRotateTokenData, RevenueRotateTokenResponse, RevenueRotateTokenResponses, RevenueRow, RevenueUpdateConfigData, RevenueUpdateConfigErrors, RevenueUpdateConfigResponse, RevenueUpdateConfigResponses, RevenueUpdateSecretData, RevenueUpdateSecretErrors, RevenueUpdateSecretResponse, RevenueUpdateSecretResponses, RevokeDsnData, RevokeDsnErrors, RevokeDsnResponse, RevokeDsnResponses, RevokeEnrollmentTokenData, RevokeEnrollmentTokenErrors, RevokeEnrollmentTokenResponse, RevokeEnrollmentTokenResponses, RevokeJoinTokenData, RevokeJoinTokenErrors, RevokeJoinTokenResponse, RevokeJoinTokenResponses, RevokeProjectAccessData, RevokeProjectAccessErrors, RevokeProjectAccessResponse, RevokeProjectAccessResponses, RiskLevel, RoleInfo, RollbackPgUpgradeData, RollbackPgUpgradeErrors, RollbackPgUpgradeResponse, RollbackPgUpgradeResponses, RollbackToDeploymentData, RollbackToDeploymentErrors, RollbackToDeploymentResponse, RollbackToDeploymentResponses, RootfsCacheEntry, RootfsGcData, RootfsGcReport, RootfsGcResponses, RootfsReport, RootfsReportData, RootfsReportResponses, RootfsVmEntry, RotateApiKeyData, RotateApiKeyErrors, RotateApiKeyResponse, RotateApiKeyResponses, RotateDeploymentTokenData, RotateDeploymentTokenErrors, RotateDeploymentTokenResponse, RotateDeploymentTokenResponses, RouteRefreshResponse, RouteResponse, RouteRole, RouteUser, RouteUserWithRoles, RunBackupForSourceData, RunBackupForSourceError, RunBackupForSourceErrors, RunBackupForSourceResponse, RunBackupForSourceResponses, RunBackupRequest, RunConnectionHealthCheckData, RunConnectionHealthCheckErrors, RunConnectionHealthCheckResponse, RunConnectionHealthCheckResponses, RunExternalServiceBackupData, RunExternalServiceBackupError, RunExternalServiceBackupErrors, RunExternalServiceBackupRequest, RunExternalServiceBackupResponse, RunExternalServiceBackupResponses, RunScheduleNowData, RunScheduleNowError, RunScheduleNowErrors, RunScheduleNowResponse, RunScheduleNowResponses, S3ConnectionTestResponse, S3CredentialsResponse, S3SourceResponse, S3SourceResponseWritable, SandboxCreatePreviewLinkData, SandboxCreatePreviewLinkErrors, SandboxCreatePreviewLinkResponse, SandboxCreatePreviewLinkResponses, SandboxDomainResponse, SandboxEvent, SandboxEventsResponse, SandboxInner, SandboxResponse, SandboxRoute, SandboxStatusResponse, SaveAgentTokenData, SaveAgentTokenErrors, SaveAgentTokenRequest, SaveAgentTokenResponse, SaveAgentTokenResponse2, SaveAgentTokenResponses, SaveAiProviderCredentialData, SaveAiProviderCredentialErrors, SaveAiProviderCredentialResponse, SaveAiProviderCredentialResponses, SaveCredentialRequest, SaveCredentialResponse, ScalewayCredentialsRequest, ScanResponse, ScheduleRunEntry, ScheduleRunJobEntry, ScheduleRunListResponse, ScheduleRunResponse, ScheduleRunSummary, ScheduleRunSummaryList, ScreenshotSettings, SearchLogsData, SearchLogsError, SearchLogsErrors, SearchLogsRequest, SearchLogsResponse, SearchLogsResponse2, SearchLogsResponses, SearchMode, Seasonality, SecretResponse, SecurityConfig, SecurityHeadersConfig, SecurityHeadersSettings, SendEmailData, SendEmailErrors, SendEmailRequestBody, SendEmailResponse, SendEmailResponseBody, SendEmailResponses, SendMessageData, SendMessageErrors, SendMessageRequest, SendMessageResponses, SensitiveConfigValueResponse, SensitiveMcpConfigValueResponse, SensitiveValueResponse, SentryChunkUploadResponse, SentryCreateReleaseRequest, SentryEventRequest, SentryEventResponse, SentryReleaseFileResponse, SentryReleaseProjectRef, SentryReleaseResponse, SeriesStateEntry, ServiceAccessInfo, ServiceAction, ServiceAlertRuleResponse, ServiceBackupEntryResponse, ServiceBackupListResponse, ServiceCreateAlertRuleRequest, ServiceHealthResponse, ServiceHealthStatusBatchResponse, ServiceHealthStatusEntryResponse, ServiceMemberInfo, ServiceParameter, ServicePlan, ServiceResourceLimits, ServiceRuntimeReport, ServiceStatsReport, ServiceTypeInfo, ServiceTypeRoute, ServiceUpdateAlertRuleRequest, SesCredentialsRequest, SessionDetails, SessionDetailsQuery, SessionEvent, SessionEventDto, SessionEventsQuery, SessionEventsResponse, SessionLogsQuery, SessionLogsResponse, SessionReplayEventsRequest, SessionReplayInfoDto, SessionReplayInitRequest, SessionReplayInitResponse, SessionReplayWithEventsDto, SessionReplayWithVisitorDto, SessionRequestLog, SessionSummary, SetDefaultS3SourceData, SetDefaultS3SourceError, SetDefaultS3SourceErrors, SetDefaultS3SourceResponse, SetDefaultS3SourceResponses, SetFlagEnvironmentData, SetFlagEnvironmentErrors, SetFlagEnvironmentRequest, SetFlagEnvironmentResponse, SetFlagEnvironmentResponses, SetPreviewPasswordBody, SetPreviewPasswordData, SetPreviewPasswordErrors, SetPreviewPasswordResponse, SetPreviewPasswordResponse2, SetPreviewPasswordResponses, SetRequest, SetResponse, SettingsUpdateResponse, SetupDnsChallengeData, SetupDnsChallengeErrors, SetupDnsChallengeRequest, SetupDnsChallengeResponse, SetupDnsChallengeResponse2, SetupDnsChallengeResponses, SetupDnsData, SetupDnsErrors, SetupDnsRequest, SetupDnsResponse, SetupDnsResponse2, SetupDnsResponses, SetupEmailTrackingData, SetupEmailTrackingErrors, SetupEmailTrackingResponse, SetupEmailTrackingResponses, SetupMfaData, SetupMfaErrors, SetupMfaResponse, SetupMfaResponses, SiblingRef, SkillDefinitionResponse, SlackConfig, SleepEnvironmentData, SleepEnvironmentErrors, SleepEnvironmentResponse, SleepEnvironmentResponses, SlowQueriesResponse, SlowQueryRow, SmartFilter, SmokeTestAgentData, SmokeTestAgentErrors, SmokeTestAgentResponse, SmokeTestAgentResponses, SmokeTestResponse, SmtpCredentialsRequest, SmtpEncryptionRoute, SmtpResult, SourceArchiveUpload, SourceBackupEntry, SourceBackupIndexResponse, SourceBody, SourceFileListResponse, SourceFileResponse, SourceMapListResponse, SourceMapResponse, SourceSandboxData, SourceSandboxErrors, SourceSandboxResponse, SourceSandboxResponses, SourceType, SpanEvent, SpanKind, SpanRecord, SpanRow, SpanStatusCode, SpeedMetricsPayload, SpeedSegmentFilters, StaleSlot, StartAnalysisData, StartAnalysisErrors, StartAnalysisRequest, StartAnalysisResponse, StartAnalysisResponses, StartContainerData, StartContainerErrors, StartContainerResponse, StartContainerResponses, StartFixData, StartFixErrors, StartFixResponses, StartGitProviderOauthData, StartGitProviderOauthErrors, StartOidcLoginBySlugData, StartOidcLoginBySlugErrors, StartPgUpgradeData, StartPgUpgradeErrors, StartPgUpgradeRequest, StartPgUpgradeResponse, StartPgUpgradeResponses, StartRestoreData, StartRestoreError, StartRestoreErrors, StartRestoreRequest, StartRestoreResponse, StartRestoreResponses, StartServiceData, StartServiceErrors, StartServiceResponse, StartServiceResponses, StaticBundleResponse, StaticParams, StaticPresetConfig, StatPathData, StatPathErrors, StatPathResponse, StatPathResponses, StatResponse, StatsFilters, StatusBucket, StatusBucketedResponse, StatusCodeCount, StatusCodesQuery, StatusPageOverview, StepConversionResponse, StepResourceType, StepResult, StepUpResponse, StopContainerData, StopContainerErrors, StopContainerResponse, StopContainerResponses, StopSandboxData, StopSandboxErrors, StopSandboxResponse, StopSandboxResponses, StopSequence, StopServiceData, StopServiceErrors, StopServiceResponse, StopServiceResponses, StorageQuota, StreamContainerMetricsData, StreamContainerMetricsErrors, StreamContainerMetricsResponses, StreamEventsData, StreamEventsErrors, StreamEventsResponses, StreamRunEventsData, StreamRunEventsErrors, StreamRunEventsResponses, StripeConfig, SyncedRepositoryListQuery, SyncRepositoriesData, SyncRepositoriesErrors, SyncRepositoriesResponse, SyncRepositoriesResponses, SyntaxResult, TagInfo, TagListResponse, TailDeploymentJobLogsData, TailDeploymentJobLogsErrors, TailLogsData, TailLogsError, TailLogsErrors, TailLogsRequest, TailLogsResponses, TargetRecommendation, TeamListResponse, TeamMemberResponse, TeamResponse, TeamRole, TeardownDeploymentData, TeardownDeploymentErrors, TeardownDeploymentResponse, TeardownDeploymentResponses, TeardownEnvironmentData, TeardownEnvironmentErrors, TeardownEnvironmentResponse, TeardownEnvironmentResponses, TemplateResponse, TestEmailRequest, TestEmailResponse, TestNotificationProviderData, TestNotificationProviderErrors, TestNotificationProviderResponse, TestNotificationProviderResponses, TestOidcProviderData, TestOidcProviderResponse, TestOidcProviderResponses, TestProviderConnectionData, TestProviderConnectionErrors, TestProviderConnectionResponse, TestProviderConnectionResponses, TestProviderData, TestProviderErrors, TestProviderKeyByIdData, TestProviderKeyByIdError, TestProviderKeyByIdErrors, TestProviderKeyByIdResponse, TestProviderKeyByIdResponses, TestProviderKeyInlineData, TestProviderKeyInlineError, TestProviderKeyInlineErrors, TestProviderKeyInlineResponse, TestProviderKeyInlineResponses, TestProviderKeyRequest, TestProviderKeyResponse, TestProviderResponse, TestProviderResponse2, TestProviderResponses, TestS3ConnectionPreviewData, TestS3ConnectionPreviewError, TestS3ConnectionPreviewErrors, TestS3ConnectionPreviewResponse, TestS3ConnectionPreviewResponses, TestS3SourceConnectionData, TestS3SourceConnectionError, TestS3SourceConnectionErrors, TestS3SourceConnectionResponse, TestS3SourceConnectionResponses, TimeBucketStats, TimeBucketStatsResponse, TimeseriesBucket, TimeseriesQueryParams, TlsMode, TodayStatsResponse, ToggleDeploymentMetricsRequest, ToggleServiceMetricsRequest, TokenRenewalRequest, ToolCallEvent, ToolInfo, ToolResultEvent, TopModelsQueryParams, TraceProjectRef, TracesResponse, TraceSummariesResponse, TraceSummary, TrackClickData, TrackClickErrors, TrackedLinkResponse, TrackingEventResponse, TrackOpenData, TrackOpenErrors, TrackOpenResponses, TriggerAgentData, TriggerAgentErrors, TriggerAgentRequest, TriggerAgentResponse, TriggerAgentResponses, TriggerDigestResponse, TriggerPipelinePayload, TriggerPipelineResponse, TriggerProjectPipelineData, TriggerProjectPipelineErrors, TriggerProjectPipelineResponse, TriggerProjectPipelineResponses, TriggerScanData, TriggerScanError, TriggerScanErrors, TriggerScanRequest, TriggerScanResponse, TriggerScanResponse2, TriggerScanResponses, TriggerServiceHealthCheckData, TriggerServiceHealthCheckErrors, TriggerServiceHealthCheckResponse, TriggerServiceHealthCheckResponses, TriggerWeeklyDigestData, TriggerWeeklyDigestErrors, TriggerWeeklyDigestResponse, TriggerWeeklyDigestResponses, TtlRequest, TtlResponse, TxtRecord, UiManifest, UiRoute, UndrainNodeResponse, UnifiedTrace, UniqueCountsQuery, UniqueCountsResponse, UnlinkServiceFromProjectData, UnlinkServiceFromProjectErrors, UnlinkServiceFromProjectResponse, UnlinkServiceFromProjectResponses, UnsupportedFeature, UpdateAdminGateRequest, UpdateAgentData, UpdateAgentErrors, UpdateAgentResponse, UpdateAgentResponses, UpdateAiProviderData, UpdateAiProviderErrors, UpdateAiProviderRequest, UpdateAiProviderResponse, UpdateAiProviderResponse2, UpdateAiProviderResponses, UpdateAlertData, UpdateAlertError, UpdateAlertErrors, UpdateAlertResponse, UpdateAlertResponses, UpdateAlertRuleData, UpdateAlertRuleErrors, UpdateAlertRuleRequest, UpdateAlertRuleResponse, UpdateAlertRuleResponses, UpdateApiKeyData, UpdateApiKeyErrors, UpdateApiKeyRequest, UpdateApiKeyResponse, UpdateApiKeyResponses, UpdateAutomaticDeployData, UpdateAutomaticDeployErrors, UpdateAutomaticDeployRequest, UpdateAutomaticDeployResponse, UpdateAutomaticDeployResponses, UpdateBackupScheduleData, UpdateBackupScheduleError, UpdateBackupScheduleErrors, UpdateBackupScheduleRequest, UpdateBackupScheduleResponse, UpdateBackupScheduleResponses, UpdateBlobRequest, UpdateBlobResponse, UpdateCloudflareProviderData, UpdateCloudflareProviderErrors, UpdateCloudflareProviderRequest, UpdateCloudflareProviderResponse, UpdateCloudflareProviderResponses, UpdateConfigBody, UpdateConnectionTokenData, UpdateConnectionTokenErrors, UpdateConnectionTokenResponse, UpdateConnectionTokenResponses, UpdateCustomDomainData, UpdateCustomDomainErrors, UpdateCustomDomainRequest, UpdateCustomDomainResponse, UpdateCustomDomainResponses, UpdateDashboardData, UpdateDashboardError, UpdateDashboardErrors, UpdateDashboardRequest, UpdateDashboardResponse, UpdateDashboardResponses, UpdateDeploymentConfigRequest, UpdateDeploymentTokenData, UpdateDeploymentTokenErrors, UpdateDeploymentTokenRequest, UpdateDeploymentTokenResponse, UpdateDeploymentTokenResponses, UpdateDnsProviderRequest, UpdateEmailProviderData, UpdateEmailProviderErrors, UpdateEmailProviderRequest, UpdateEmailProviderResponse, UpdateEmailProviderResponses, UpdateEnvironmentSettingsData, UpdateEnvironmentSettingsErrors, UpdateEnvironmentSettingsRequest, UpdateEnvironmentSettingsResponse, UpdateEnvironmentSettingsResponses, UpdateEnvironmentSubdomainData, UpdateEnvironmentSubdomainErrors, UpdateEnvironmentSubdomainRequest, UpdateEnvironmentSubdomainResponse, UpdateEnvironmentSubdomainResponses, UpdateEnvironmentVariableData, UpdateEnvironmentVariableErrors, UpdateEnvironmentVariableRequest, UpdateEnvironmentVariableResponse, UpdateEnvironmentVariableResponses, UpdateErrorGroupData, UpdateErrorGroupErrors, UpdateErrorGroupRequest, UpdateErrorGroupResponses, UpdateExternalServiceRequest, UpdateFlagData, UpdateFlagErrors, UpdateFlagRequest, UpdateFlagResponse, UpdateFlagResponses, UpdateFunnelData, UpdateFunnelErrors, UpdateFunnelResponses, UpdateGitProviderCredentialsData, UpdateGitProviderCredentialsErrors, UpdateGitProviderCredentialsResponse, UpdateGitProviderCredentialsResponses, UpdateGitSettingsData, UpdateGitSettingsErrors, UpdateGitSettingsRequest, UpdateGitSettingsResponse, UpdateGitSettingsResponses, UpdateGlobalMcpData, UpdateGlobalMcpErrors, UpdateGlobalMcpResponse, UpdateGlobalMcpResponses, UpdateGlobalSkillData, UpdateGlobalSkillErrors, UpdateGlobalSkillResponse, UpdateGlobalSkillResponses, UpdateIncidentStatusData, UpdateIncidentStatusErrors, UpdateIncidentStatusRequest, UpdateIncidentStatusResponse, UpdateIncidentStatusResponses, UpdateIpAccessControlData, UpdateIpAccessControlError, UpdateIpAccessControlErrors, UpdateIpAccessControlRequest, UpdateIpAccessControlResponse, UpdateIpAccessControlResponses, UpdateKvRequest, UpdateKvResponse, UpdateManagedDomainApiRequest, UpdateManagedDomainData, UpdateManagedDomainErrors, UpdateManagedDomainResponse, UpdateManagedDomainResponses, UpdateMcpData, UpdateMcpErrors, UpdateMcpRequest, UpdateMcpResponse, UpdateMcpResponses, UpdateMemberRoleRequest, UpdateMetricAlertRequest, UpdateNotificationEmailProviderData, UpdateNotificationEmailProviderErrors, UpdateNotificationEmailProviderRequest, UpdateNotificationEmailProviderResponse, UpdateNotificationEmailProviderResponses, UpdateNotificationProviderData, UpdateNotificationProviderErrors, UpdateNotificationProviderResponse, UpdateNotificationProviderResponses, UpdateOidcProviderData, UpdateOidcProviderRequest, UpdateOidcProviderResponse, UpdateOidcProviderResponses, UpdatePreferencesData, UpdatePreferencesErrors, UpdatePreferencesRequest, UpdatePreferencesResponse, UpdatePreferencesResponses, UpdateProjectData, UpdateProjectDeploymentConfigData, UpdateProjectDeploymentConfigErrors, UpdateProjectDeploymentConfigResponse, UpdateProjectDeploymentConfigResponses, UpdateProjectErrors, UpdateProjectResponse, UpdateProjectResponses, UpdateProjectSecretData, UpdateProjectSecretErrors, UpdateProjectSecretRequest, UpdateProjectSecretResponse, UpdateProjectSecretResponses, UpdateProjectSettingsData, UpdateProjectSettingsErrors, UpdateProjectSettingsRequest, UpdateProjectSettingsResponse, UpdateProjectSettingsResponses, UpdateProviderCredentialsRequest, UpdateProviderData, UpdateProviderErrors, UpdateProviderKeyData, UpdateProviderKeyError, UpdateProviderKeyErrors, UpdateProviderKeyRequest, UpdateProviderKeyResponse, UpdateProviderKeyResponses, UpdateProviderRequest, UpdateProviderResponse, UpdateProviderResponses, UpdateRouteData, UpdateRouteErrors, UpdateRouteRequest, UpdateRouteResponse, UpdateRouteResponses, UpdateS3SourceData, UpdateS3SourceError, UpdateS3SourceErrors, UpdateS3SourceRequest, UpdateS3SourceResponse, UpdateS3SourceResponses, UpdateSecretBody, UpdateSelfData, UpdateSelfErrors, UpdateSelfRequest, UpdateSelfResponse, UpdateSelfResponses, UpdateServiceData, UpdateServiceErrors, UpdateServiceResourcesData, UpdateServiceResourcesErrors, UpdateServiceResourcesResponse, UpdateServiceResourcesResponses, UpdateServiceResponse, UpdateServiceResponses, UpdateSessionDurationData, UpdateSessionDurationError, UpdateSessionDurationErrors, UpdateSessionDurationRequest, UpdateSessionDurationResponse, UpdateSessionDurationResponse2, UpdateSessionDurationResponses, UpdateSettingsData, UpdateSettingsErrors, UpdateSettingsResponse, UpdateSettingsResponses, UpdateSkillData, UpdateSkillErrors, UpdateSkillRequest, UpdateSkillResponse, UpdateSkillResponses, UpdateSlackProviderData, UpdateSlackProviderErrors, UpdateSlackProviderRequest, UpdateSlackProviderResponse, UpdateSlackProviderResponses, UpdateSpeedMetricsData, UpdateSpeedMetricsError, UpdateSpeedMetricsErrors, UpdateSpeedMetricsPayload, UpdateSpeedMetricsResponse, UpdateSpeedMetricsResponses, UpdateStatusResponse, UpdateTeamData, UpdateTeamErrors, UpdateTeamMemberRoleData, UpdateTeamMemberRoleErrors, UpdateTeamMemberRoleResponse, UpdateTeamMemberRoleResponses, UpdateTeamRequest, UpdateTeamResponse, UpdateTeamResponses, UpdateTokenRequest, UpdateTokenResponse, UpdateUserData, UpdateUserErrors, UpdateUserRequest, UpdateUserResponse, UpdateUserResponses, UpdateWebhookData, UpdateWebhookErrors, UpdateWebhookProviderData, UpdateWebhookProviderErrors, UpdateWebhookProviderRequest, UpdateWebhookProviderResponse, UpdateWebhookProviderResponses, UpdateWebhookRequestBody, UpdateWebhookResponse, UpdateWebhookResponses, UpgradeExternalServiceRequest, UpgradePreviewGatewayData, UpgradePreviewGatewayResponse, UpgradePreviewGatewayResponses, UpgradeRequest, UpgradeServiceData, UpgradeServiceErrors, UpgradeServiceResponse, UpgradeServiceResponses, UploadGlobalSkillData, UploadGlobalSkillErrors, UploadGlobalSkillResponse, UploadGlobalSkillResponses, UploadReleaseFileData, UploadReleaseFileErrors, UploadReleaseFileResponse, UploadReleaseFileResponses, UploadSkillData, UploadSkillErrors, UploadSkillResponse, UploadSkillResponses, UploadSourceFileData, UploadSourceFileErrors, UploadSourceFileResponse, UploadSourceFileResponses, UploadSourceMapData, UploadSourceMapErrors, UploadSourceMapResponse, UploadSourceMapResponses, UploadStaticBundleData, UploadStaticBundleErrors, UploadStaticBundleResponse, UploadStaticBundleResponses, UpsertAgentRequest, UpsertSecretData, UpsertSecretErrors, UpsertSecretRequest, UpsertSecretResponse, UpsertSecretResponses, UptimeDataPoint, UptimeHistoryResponse, UsageFilter, UsageInfo, UsageLogEntry, UsageLogPage, UsageQueryParams, UsageSource, UsageSummary, UserResponse, ValidateConnectionData, ValidateConnectionErrors, ValidateConnectionResponse, ValidateConnectionResponses, ValidateEmailData, ValidateEmailErrors, ValidateEmailRequest, ValidateEmailResponse, ValidateEmailResponse2, ValidateEmailResponses, ValidationLevel, ValidationReport, ValidationResponse, ValidationResult, ValidationStatus, ValidationSummary, VerifyAndEnableMfaData, VerifyAndEnableMfaErrors, VerifyAndEnableMfaResponse, VerifyAndEnableMfaResponses, VerifyDomainData, VerifyDomainErrors, VerifyDomainResponse, VerifyDomainResponses, VerifyEmailData, VerifyEmailErrors, VerifyEmailResponse, VerifyEmailResponses, VerifyManagedDomainData, VerifyManagedDomainErrors, VerifyManagedDomainResponse, VerifyManagedDomainResponses, VerifyMfaChallengeData, VerifyMfaChallengeErrors, VerifyMfaChallengeResponse, VerifyMfaChallengeResponses, VerifyMfaRequest, VerifyStepUpData, VerifyStepUpErrors, VerifyStepUpRequest, VerifyStepUpResponse, VerifyStepUpResponses, ViewItem, ViewsOverTime, ViewsOverTimeQuery, VisitorDetails, VisitorFacets, VisitorFacetsQuery, VisitorFacetValue, VisitorInfo, VisitorJourneyQuery, VisitorJourneyResponse, VisitorLocationsQuery, VisitorRecord, VisitorSegmentFilters, VisitorSessionsQuery, VisitorSessionsResponse, VisitorsListQuery, VisitorsResponse, VisitorStats, VisitorWithGeolocation, VolumeMount, VolumeType, VulnerabilityResponse, WakeEnvironmentData, WakeEnvironmentErrors, WakeEnvironmentResponse, WakeEnvironmentResponses, WalWarning, WalWarningSeverity, WebhookConfig, WebhookDeliveryResponse, WebhookResponse, WebhookTriggerData, WebhookTriggerErrors, WebhookTriggerRequest, WebhookTriggerResponse, WebhookTriggerResponse2, WebhookTriggerResponses, WorkflowDryRunData, WorkflowDryRunErrors, WorkflowDryRunRequest, WorkflowDryRunResponse, WorkflowDryRunResponses, WorkloadDescriptor, WorkloadId, WorkloadStatus, WorkloadType, WriteFileBody, WriteFileData, WriteFileErrors, WriteFileResponse, WriteFileResponses, WriteFilesBody, WriteFilesData, WriteFilesErrors, WriteFilesResponse, WriteFilesResponse2, WriteFilesResponses, ZoneListResponse } from './types.gen'; +export { acknowledgeAlarm, activateAiProvider, activateApiKey, activateConnection, activateProvider, addClusterMember, addContext, addEnvironmentDomain, addEvents, addManagedDomain, addSessionReplayEvents, addTeamMember, adminDrainNode, adminDrainStatus, adminGetNode, adminListNodeContainers, adminListNodes, adminRemoveNode, adminUndrainNode, applyHostnameMode, archiveConversation, archiveFlag, assignRole, attachScheduleServices, blobCopy, blobDelete, blobDisable, blobDownload, blobEnable, blobHead, blobList, blobPut, blobStatus, blobUpdate, cancel, cancelBackup, cancelDeployment, cancelDomainOrder, cancelPgUpgrade, cancelRun, cancelScheduleRun, changePasswordSelf, changeProjectSource, changeRequiredPassword, chatCompletions, checkAnalyticsHasEvents, checkCommitExists, checkDomainStatus, checkExplorerSupport, checkIpBlocked, checkProviderDeletionSafety, chunkUploadOptions, cleanupExpiredBackups, clearPreviewPassword, cliDeviceApprove, cliDeviceDeny, cliDeviceLookup, cliDevicePoll, cliDeviceStart, cliLogout, cmd, cmdKill, cmdLogs, confirmPendingAction, containerMetricsGetHistory, createAgent, createAlert, createAlertRule, createApiKey, createBackupSchedule, createBitbucketProvider, createCloudflareProvider, createConversation, createCustomDomain, createDashboard, createDeploymentToken, createDnsProvider, createDomain, createDsn, createEmailDomain, createEmailProvider, createEnvironment, createEnvironmentVariable, createFlag, createFunnel, createGenericProvider, createGiteaPatProvider, createGithubPatProvider, createGitlabOauthProvider, createGitlabPatProvider, createGitProvider, createGlobalMcp, createGlobalSkill, createIncident, createIpAccessControl, createMcp, createMonitor, createNotificationEmailProvider, createNotificationProvider, createOidcProvider, createOidcRoleMapping, createOrRecreateOrder, createPlan, createPr, createProject, createProjectFromTemplate, createProjectRelease, createProjectSecret, createProviderKey, createRelease, createRoute, createS3Source, createSandbox, createService, createSkill, createSlackProvider, createTeam, createUser, createWebhook, createWebhookProvider, deactivateApiKey, deactivateConnection, deactivateProvider, deleteAgent, deleteAlert, deleteAlertRule, deleteApiKey, deleteBackup, deleteBackupSchedule, deleteConnection, deleteCustomDomain, deleteDashboard, deleteDeploymentToken, deleteDnsProvider, deleteDomain, deleteEmailDomain, deleteEmailProvider, deleteEnvironment, deleteEnvironmentDomain, deleteEnvironmentVariable, deleteExternalImage, deleteFunnel, deleteGitProvider, deleteGlobalMcp, deleteGlobalSkill, deleteIpAccessControl, deleteMcp, deleteMonitor, deleteNotificationProvider, deleteOidcProvider, deleteOidcRoleMapping, deletePreferences, deleteProject, deleteProjectSecret, deleteProviderKey, deleteProviderSafely, deleteReleaseSourceFiles, deleteReleaseSourceMaps, deleteRoute, deleteS3Source, deleteScan, deleteSecret, deleteService, deleteSessionReplay, deleteSkill, deleteSourceMap, deleteStaticBundle, deleteTeam, deleteUser, deleteWebhook, deployFromImage, deployFromImageUpload, deployFromStatic, deployFromUploadedSource, deploymentMetricsGetLatest, deploymentMetricsGetRange, deploymentMetricsToggle, destroySandbox, detachScheduleService, detectPublicPresets, disableBackupSchedule, disableMfa, discoverWorkloads, domain, downloadGlobalSkillArchive, downloadObject, downloadSkillArchive, emailStatus, embeddings, enableBackupSchedule, enrichVisitor, exec, execDetached, executeDeploymentOperation, executeImport, extendTimeout, externalServiceEnablePgStatStatements, externalServiceMetricsByDatabase, externalServiceMetricsCreateAlertRule, externalServiceMetricsDeleteAlertRule, externalServiceMetricsGetAlertRules, externalServiceMetricsGetLatest, externalServiceMetricsGetRange, externalServiceMetricsStatus, externalServiceMetricsToggle, externalServiceMetricsUpdateAlertRule, externalServiceResetPgStatStatements, finalizeOrder, finalizeProjectRelease, findConversation, generateJoinToken, generatePresetDockerfile, getAccessInfo, getActiveVisitors, getActivityGraph, getAdminGate, getAgent, getAggregatedBuckets, getAiAgentBreakdown, getAiAgentPages, getAiAgentTimeline, getAiPageBreakdown, getAiStatusBreakdown, getAlert, getAlertRule, getAllRepositoriesByName, getAnalyticsActiveVisitors, getAnalyticsEventsCount, getAnalyticsSessionEvents, getAnalyticsVisitorSessions, getApiKey, getApiKeyPermissions, getAuditLog, getBackup, getBackupSchedule, getBranchesByRepositoryId, getBucketedIncidents, getBucketedStatus, getChallengeToken, getChatReadiness, getCliStatus, getClusterHealth, getClusterMember, getCmd, getContainerDetail, getContainerEnvironmentVariable, getContainerInfo, getContainerLogs, getContainerLogsById, getContainerMetrics, getConversation, getConversationDetail, getConversations, getCronById, getCronExecutions, getCrossProjectTraceSiblings, getCurrentMonitorStatus, getCurrentUser, getCustomDomain, getDashboard, getDashboardProjectsAnalytics, getDelivery, getDeployment, getDeploymentContainerLogContent, getDeploymentJobLogs, getDeploymentJobs, getDeploymentOperations, getDeploymentOperationStatus, getDeploymentToken, getDiskStatus, getDnsChanges, getDnsProvider, getDomain, getDomainByHost, getDomainById, getDomainByName, getDomainDnsRecords, getDomainOrder, getEmail, getEmailEvents, getEmailLinks, getEmailProvider, getEmailStats, getEmailTracking, getEmailTrackingStatus, getEntityInfo, getEnvironment, getEnvironmentCrons, getEnvironmentDomains, getEnvironments, getEnvironmentVariables, getEnvironmentVariableValue, getErrorDashboardStats, getErrorEvent, getErrorGroup, getErrorStats, getErrorTimeSeries, getEventDetail, getEventEntries, getEventsCount, getEventsTimeline, getEventTypeBreakdown, getEventVisitors, getExternalImage, getFile, getFlag, getFlagSnapshot, getFunnelMetrics, getGenaiTrace, getGeneralStats, getGitProvider, getGlobalEvents, getGlobalEventStats, getGlobalMcp, getGlobalSandboxStatus, getGlobalSkill, getGroupedPageMetrics, getHealth, getHourlyVisits, getHttpChallengeDebug, getImportStatus, getIncident, getIncidentUpdates, getIpAccessControl, getIpGeolocation, getJoinTokenStatus, getLastDeployment, getLatestScan, getLatestScansPerEnvironment, getLiveVisitorsList, getLogContext, getMcp, getMetricsOverTime, getMonitor, getNotificationProvider, getOnDemandCertStatus, getOrCreateDsn, getPageFlow, getPageHourlySessions, getPagePathDetail, getPagePaths, getPagePathsSparklines, getPagePathVisitors, getPendingAction, getPerformanceMetrics, getPgUpgrade, getPgUpgradeLogs, getPipelineStats, getPlatformInfo, getPostgresWalHealth, getPreferences, getPreviewGatewayLogs, getPreviewGatewaySettings, getPreviewGatewayStatus, getPricing, getPrivateIp, getProject, getProjectAlarmsSummary, getProjectBySlug, getProjectDeployments, getProjects, getProjectServiceEnvironmentVariables, getProjectSessionReplays, getProjectsHealth, getProjectsMonitorHealth, getProjectStatistics, getProjectTemplate, getPropertyBreakdown, getPropertyTimeline, getProviderConnections, getProviderMetadata, getProvidersMetadata, getProxyLogById, getProxyLogByRequestId, getProxyLogs, getPublicBranches, getPublicIp, getPublicRepository, getQuota, getRecentActivity, getRemoteExternalImage, getRepositoryBranches, getRepositoryById, getRepositoryByName, getRepositoryPresetByName, getRepositoryPresetLive, getRepositoryTags, getResolvedEnvironmentVariables, getResolvedEnvironmentVariableValue, getRestoreCapabilities, getRestoreRun, getRoute, getRun, getRunWithLogs, getS3Credentials, getS3Source, getSandbox, getSandboxStatus, getScan, getScanByDeployment, getScanVulnerabilities, getService, getServiceBySlug, getServiceEnvironmentVariable, getServiceEnvironmentVariables, getServiceHealthStatus, getServicePreviewEnvironmentVariableNames, getServicePreviewEnvironmentVariablesMasked, getServiceRuntime, getServiceStats, getServiceTypeParameters, getServiceTypes, getSessionDetails, getSessionEvents, getSessionLogs, getSessionReplay, getSessionReplayEvents, getSettings, getSkill, getSlowQueries, getStaticBundle, getStatusOverview, getTagsByRepositoryId, getTeam, getTimeBucketStats, getTodayStats, getTrace, getUnifiedTrace, getUniqueCounts, getUniqueEvents, getUpdateCapability, getUpdateStatus, getUptimeHistory, getUsageByProvider, getUsageRecent, getUsageSummary, getUsageTimeseries, getUsageTopModels, getVisitorByGuid, getVisitorById, getVisitorDetails, getVisitorFacets, getVisitorInfo, getVisitorJourney, getVisitors, getVisitorSessions, getVisitorStats, getWebhook, grantProjectAccess, handleGitProviderOauthCallback, hasAnalyticsEvents, hasErrorGroups, hasPerformanceMetrics, importExternalService, ingestLogs, ingestLogsByPath, ingestMetrics, ingestMetricsByPath, ingestSentryEnvelope, ingestSentryEvent, ingestTraces, ingestTracesByPath, initSessionReplay, inspectDropArchive, jobLogs, jobStatus, killJob, kvDel, kvDisable, kvEnable, kvExpire, kvGet, kvIncr, kvKeys, kvSet, kvStatus, kvTtl, kvUpdate, latestRunForSource, linkCustomDomainToCertificate, linkServiceToProject, listAgentRuns, listAgents, listAiProviders, listAlertRules, listAlerts, listAllConversations, listAllRuns, listApiKeys, listAuditLogs, listAvailableContainers, listBackupAlerts, listBackupChildren, listBackupSchedules, listBackupsForSchedule, listCommitsByRepositoryId, listConnections, listContainers, listContainersAtPath, listConversations, listCustomDomainsForProject, listDashboards, listDeliveries, listDeploymentContainerLogs, listDeploymentTokens, listDnsProviders, listDomains, listDsns, listEmailDomains, listEmailProviders, listEmails, listEnrollmentTokens, listEntities, listErrorEvents, listErrorGroups, listEvents, listEventTypes, listExternalImages, listExternalPlugins, listExternalServiceBackups, listFlags, listFunnels, listGitProviders, listGlobalMcps, listGlobalSkills, listIncidents, listInsights, listIpAccessControl, listJobs, listKnownAiAgents, listManagedDomains, listMcps, listMetricLabelKeys, listMetricLabelValues, listMetricNames, listModels, listMonitors, listNotificationProviders, listOidcProviders, listOidcProviderUsers, listOidcRoleMappings, listOnDemandCerts, listOrders, listPeers, listPendingActions, listPgUpgrades, listPresets, listProjectAccess, listProjectAlarms, listProjectScans, listProjectSecrets, listProjectServices, listProjectTemplates, listProjectTemplateTags, listProviderKeys, listProviderZones, listPublicProviders, listReleaseFiles, listReleases, listRemoteExternalImages, listRepositoriesByConnection, listRepositoriesByProvider, listRestoreRunsForService, listRootContainers, listRoutes, listS3Sources, listSandboxes, listScheduleRunJobs, listScheduleRuns, listScheduleServices, listSecrets, listServiceHealthStatuses, listServiceProjects, listServices, listServiceSchedules, listSkills, listSourceBackups, listSourceFiles, listSourceMaps, listSources, listStaticBundles, listSyncedRepositories, listTeamMembers, listTeamProjects, listTeams, listUsers, listWebhooks, login, logout, lookupDnsARecords, mintEnrollmentToken, mkdir, nodeHeartbeat, nodeMetricsGetRange, observabilityFullEvent, observabilityListEvents, oidcCallback, type Options, patchAdminGate, patchPreviewGatewaySettings, pauseDeployment, pauseSandbox, planRestore, postDnsAck, previewAlert, previewFunnelMetrics, previewHostnameMode, promoteClusterMember, promoteDeployment, provisionDomain, purgeProjectLogs, pushExternalImage, queryData, queryGenaiTraces, queryLogs, queryMetrics, queryTraces, queryTraceSummaries, readFile, reAnalyze, rebuildSandboxImage, recordConsoleEvent, recordEventMetrics, recordFlagExposure, recordSpeedMetrics, refreshRouteTable, regenerateDsn, registerExternalImage, registerNode, reinstallGitlabWebhook, rejectPendingAction, reloadPlugins, removeClusterMember, removeManagedDomain, removeRole, removeTeamMember, renameConversation, renewDomain, requestPasswordReset, resetPassword, resizeSandbox, resolveAlarm, restartContainer, restartPreviewGateway, restartSandbox, restoreFlag, restoreUser, resumeDeployment, resumeSandbox, retryCluster, retryDelivery, retryPgUpgrade, retryRun, revealGlobalMcpConfig, revealMcpConfig, revealNotificationProviderConfig, revealServiceParameter, revenueCreateIntegration, revenueDeleteIntegration, revenueGlobalEvents, revenueImportInvoicesCsv, revenueImportSubscriptionsCsv, revenueListIntegrations, revenueListProviders, revenueMetricsCustomers, revenueMetricsGlobalMrr, revenueMetricsGlobalSummary, revenueMetricsMrr, revenueMetricsSummary, revenueRecentEvents, revenueRotateToken, revenueUpdateConfig, revenueUpdateSecret, revokeDsn, revokeEnrollmentToken, revokeJoinToken, revokeProjectAccess, rollbackPgUpgrade, rollbackToDeployment, rootfsGc, rootfsReport, rotateApiKey, rotateDeploymentToken, runBackupForSource, runConnectionHealthCheck, runExternalServiceBackup, runScheduleNow, sandboxCreatePreviewLink, saveAgentToken, saveAiProviderCredential, searchLogs, sendEmail, sendMessage, setDefaultS3Source, setFlagEnvironment, setPreviewPassword, setupDns, setupDnsChallenge, setupEmailTracking, setupMfa, sleepEnvironment, smokeTestAgent, sourceSandbox, startAnalysis, startContainer, startFix, startGitProviderOauth, startOidcLoginBySlug, startPgUpgrade, startRestore, startService, startUpdate, statPath, stopContainer, stopSandbox, stopService, streamContainerMetrics, streamEvents, streamRunEvents, syncRepositories, tailDeploymentJobLogs, tailLogs, teardownDeployment, teardownEnvironment, testNotificationProvider, testOidcProvider, testProvider, testProviderConnection, testProviderKeyById, testProviderKeyInline, testS3ConnectionPreview, testS3SourceConnection, trackClick, trackOpen, triggerAgent, triggerProjectPipeline, triggerScan, triggerServiceHealthCheck, triggerWeeklyDigest, unlinkServiceFromProject, updateAgent, updateAiProvider, updateAlert, updateAlertRule, updateApiKey, updateAutomaticDeploy, updateBackupSchedule, updateCloudflareProvider, updateConnectionToken, updateCustomDomain, updateDashboard, updateDeploymentToken, updateEmailProvider, updateEnvironmentSettings, updateEnvironmentSubdomain, updateEnvironmentVariable, updateErrorGroup, updateFlag, updateFunnel, updateGitProviderCredentials, updateGitSettings, updateGlobalMcp, updateGlobalSkill, updateIncidentStatus, updateIpAccessControl, updateManagedDomain, updateMcp, updateNotificationEmailProvider, updateNotificationProvider, updateOidcProvider, updatePreferences, updateProject, updateProjectDeploymentConfig, updateProjectSecret, updateProjectSettings, updateProvider, updateProviderKey, updateRoute, updateS3Source, updateSelf, updateService, updateServiceResources, updateSessionDuration, updateSettings, updateSkill, updateSlackProvider, updateSpeedMetrics, updateTeam, updateTeamMemberRole, updateUser, updateWebhook, updateWebhookProvider, upgradePreviewGateway, upgradeService, uploadGlobalSkill, uploadReleaseFile, uploadSkill, uploadSourceFile, uploadSourceMap, uploadStaticBundle, upsertSecret, validateConnection, validateEmail, verifyAndEnableMfa, verifyDomain, verifyEmail, verifyManagedDomain, verifyMfaChallenge, verifyStepUp, wakeEnvironment, webhookTrigger, workflowDryRun, writeFile, writeFiles } from './sdk.gen'; +export type { AcknowledgeAlarmData, AcknowledgeAlarmErrors, AcknowledgeAlarmResponses, AcmeOrderResponse, ActivateAiProviderData, ActivateAiProviderErrors, ActivateAiProviderResponse, ActivateAiProviderResponses, ActivateApiKeyData, ActivateApiKeyErrors, ActivateApiKeyResponse, ActivateApiKeyResponses, ActivateConnectionData, ActivateConnectionErrors, ActivateConnectionResponses, ActivateProviderData, ActivateProviderErrors, ActivateProviderResponse, ActivateProviderResponses, ActiveVisitor, ActiveVisitorsQuery, ActiveVisitorsResponse, ActivityDay, ActivityEvent, ActivityGraphQuery, ActivityGraphResponse, AddClusterMemberData, AddClusterMemberErrors, AddClusterMemberRequest, AddClusterMemberResponse, AddClusterMemberResponses, AddContextData, AddContextErrors, AddContextRequest, AddContextResponses, AddEnvironmentDomainData, AddEnvironmentDomainErrors, AddEnvironmentDomainRequest, AddEnvironmentDomainResponse, AddEnvironmentDomainResponses, AddEventsData, AddEventsError, AddEventsErrors, AddEventsRequest, AddEventsResponse, AddEventsResponse2, AddEventsResponses, AddManagedDomainApiRequest, AddManagedDomainData, AddManagedDomainErrors, AddManagedDomainResponse, AddManagedDomainResponses, AddSessionReplayEventsData, AddSessionReplayEventsError, AddSessionReplayEventsErrors, AddSessionReplayEventsResponse, AddSessionReplayEventsResponses, AddTeamMemberData, AddTeamMemberErrors, AddTeamMemberResponse, AddTeamMemberResponses, AdminDrainNodeData, AdminDrainNodeErrors, AdminDrainNodeResponse, AdminDrainNodeResponses, AdminDrainStatusData, AdminDrainStatusErrors, AdminDrainStatusResponse, AdminDrainStatusResponses, AdminGateResponse, AdminGateSource, AdminGetNodeData, AdminGetNodeErrors, AdminGetNodeResponse, AdminGetNodeResponses, AdminListNodeContainersData, AdminListNodeContainersErrors, AdminListNodeContainersResponse, AdminListNodeContainersResponses, AdminListNodesData, AdminListNodesErrors, AdminListNodesResponse, AdminListNodesResponses, AdminRemoveNodeData, AdminRemoveNodeErrors, AdminRemoveNodeResponse, AdminRemoveNodeResponses, AdminUndrainNodeData, AdminUndrainNodeErrors, AdminUndrainNodeResponse, AdminUndrainNodeResponses, AgentConfigResponse, AgentRunLogResponse, AgentRunResponse, AgentRunWithLogsResponse, AgentSandboxSettings, AgentSandboxSettingsMasked, AggregatedBucketItem, AggregatedBucketsQuery, AggregatedBucketsResponse, AggregationLevel, AggregationTemporality, AiAgentBreakdownResponse, AiAgentBreakdownRow, AiAgentDescriptor, AiAgentPageRow, AiAgentPagesResponse, AiAgentTimelineResponse, AiAgentTimelineRow, AiChatLimitsSettings, AiConfigSettings, AiPageBreakdownResponse, AiPageBreakdownRow, AiStatusBreakdownResponse, AiStatusBreakdownRow, AlarmListResponse, AlarmResponse, AlarmSummaryResponse, AlertRuleResponse, AllocEntry, AnalyticsSessionEventsResponse, AnnotatedSpan, AnomalyAlgorithm, AnomalyParams, AnomalyPreviewPointResponse, AnomalyPreviewRequest, AnomalyPreviewResponse, ApiKeyListResponse, ApiKeyResponse, ApplyHostnameModeData, ApplyHostnameModeErrors, ApplyHostnameModeRequest, ApplyHostnameModeResponse, ApplyHostnameModeResponses, AppSettings, AppSettingsResponse, ArchiveConversationData, ArchiveConversationErrors, ArchiveConversationResponse, ArchiveConversationResponses, ArchiveFlagData, ArchiveFlagErrors, ArchiveFlagResponse, ArchiveFlagResponse2, ArchiveFlagResponses, ArchiveMode, AssignRoleData, AssignRoleErrors, AssignRoleRequest, AssignRoleResponses, AttachScheduleServicesData, AttachScheduleServicesError, AttachScheduleServicesErrors, AttachScheduleServicesRequest, AttachScheduleServicesResponse, AttachScheduleServicesResponse2, AttachScheduleServicesResponses, AuditLogIpInfo, AuditLogResponse, AuditLogUserInfo, AuthFlavorDto, AuthResponse, AuthStatusResponse, AuthTokenResponse, AutofixerRunResponse, AutofixerRunWithLogsResponse, AutofixRunConfig, AutoWatchParams, AvailableContainerInfo, AvailablePermissions, BackupAlertListResponse, BackupAlertResponse, BackupResponse, BackupScheduleResponse, BitbucketAuthInput, BlobCopyData, BlobCopyError, BlobCopyErrors, BlobCopyResponse, BlobCopyResponses, BlobDeleteData, BlobDeleteError, BlobDeleteErrors, BlobDeleteResponse, BlobDeleteResponses, BlobDisableData, BlobDisableErrors, BlobDisableResponse, BlobDisableResponses, BlobDownloadData, BlobDownloadError, BlobDownloadErrors, BlobDownloadResponses, BlobEnableData, BlobEnableErrors, BlobEnableResponse, BlobEnableResponses, BlobHeadData, BlobHeadError, BlobHeadErrors, BlobHeadResponses, BlobListData, BlobListError, BlobListErrors, BlobListResponse, BlobListResponses, BlobPutData, BlobPutError, BlobPutErrors, BlobPutResponse, BlobPutResponses, BlobResponse, BlobStatusData, BlobStatusErrors, BlobStatusResponse, BlobStatusResponse2, BlobStatusResponses, BlobUpdateData, BlobUpdateErrors, BlobUpdateResponse, BlobUpdateResponses, BranchInfo, BranchListResponse, BrowserCount, BrowsersQuery, BuildConfiguration, BuildLimitsSettings, CancelBackupData, CancelBackupError, CancelBackupErrors, CancelBackupResponse, CancelBackupResponse2, CancelBackupResponses, CancelData, CancelDeploymentData, CancelDeploymentErrors, CancelDeploymentResponse, CancelDeploymentResponses, CancelDomainOrderData, CancelDomainOrderErrors, CancelDomainOrderResponse, CancelDomainOrderResponses, CancelErrors, CancelPgUpgradeData, CancelPgUpgradeErrors, CancelPgUpgradeResponse, CancelPgUpgradeResponses, CancelResponses, CancelRunData, CancelRunErrors, CancelRunResponse, CancelRunResponses, CancelScheduleRunData, CancelScheduleRunError, CancelScheduleRunErrors, CancelScheduleRunResponse, CancelScheduleRunResponses, CertStatusResponse, ChallengeConfig, ChallengeError, ChallengeValidationStatus, ChangePasswordRequest, ChangePasswordSelfData, ChangePasswordSelfErrors, ChangePasswordSelfResponse, ChangePasswordSelfResponses, ChangeProjectSourceData, ChangeProjectSourceErrors, ChangeProjectSourceRequest, ChangeProjectSourceResponse, ChangeProjectSourceResponses, ChangeRequiredPasswordData, ChangeRequiredPasswordErrors, ChangeRequiredPasswordResponse, ChangeRequiredPasswordResponses, ChatCompletionChoice, ChatCompletionRequest, ChatCompletionResponse, ChatCompletionsData, ChatCompletionsError, ChatCompletionsErrors, ChatCompletionsResponse, ChatCompletionsResponses, ChatMessage, ChatReadinessResponse, CheckAnalyticsHasEventsData, CheckAnalyticsHasEventsErrors, CheckAnalyticsHasEventsResponse, CheckAnalyticsHasEventsResponses, CheckCommitExistsData, CheckCommitExistsErrors, CheckCommitExistsResponse, CheckCommitExistsResponses, CheckDomainStatusData, CheckDomainStatusErrors, CheckDomainStatusResponse, CheckDomainStatusResponses, CheckExplorerSupportData, CheckExplorerSupportErrors, CheckExplorerSupportResponse, CheckExplorerSupportResponses, CheckIpBlockedData, CheckIpBlockedError, CheckIpBlockedErrors, CheckIpBlockedResponses, CheckProviderDeletionSafetyData, CheckProviderDeletionSafetyErrors, CheckProviderDeletionSafetyResponse, CheckProviderDeletionSafetyResponses, ChildBackupEntryResponse, ChildBackupListResponse, ChunkUploadOptionsData, ChunkUploadOptionsResponse, ChunkUploadOptionsResponses, CleanupExpiredBackupsData, CleanupExpiredBackupsError, CleanupExpiredBackupsErrors, CleanupExpiredBackupsRequest, CleanupExpiredBackupsResponse, CleanupExpiredBackupsResponses, ClearPreviewPasswordData, ClearPreviewPasswordErrors, ClearPreviewPasswordResponse, ClearPreviewPasswordResponses, CliDeviceApproveData, CliDeviceApproveErrors, CliDeviceApproveRequest, CliDeviceApproveResponse, CliDeviceApproveResponse2, CliDeviceApproveResponses, CliDeviceDenyData, CliDeviceDenyErrors, CliDeviceDenyResponse, CliDeviceDenyResponses, CliDeviceLookupData, CliDeviceLookupErrors, CliDeviceLookupResponse, CliDeviceLookupResponse2, CliDeviceLookupResponses, CliDevicePollData, CliDevicePollErrors, CliDevicePollRequest, CliDevicePollResponse, CliDevicePollResponse2, CliDevicePollResponses, CliDeviceStartData, CliDeviceStartErrors, CliDeviceStartRequest, CliDeviceStartResponse, CliDeviceStartResponse2, CliDeviceStartResponses, ClientOptions, CliLoginRequest, CliLogoutData, CliLogoutErrors, CliLogoutResponse, CliLogoutResponses, CloudflareConfig, CloudProvider, ClusterCapacity, ClusterDnsSettings, ClusterHealthReportResponse, ClusterMemberHealthResponse, ClusterMemberRequest, CmdBody, CmdData, CmdErrors, CmdInner, CmdKillBody, CmdKillData, CmdKillErrors, CmdKillResponse, CmdKillResponses, CmdLogsData, CmdLogsErrors, CmdLogsResponses, CmdResponse, CmdResponse2, CmdResponses, CommitExistsResponse, CommitInfo, CommitListResponse, Comparator, ComposePublicPort, ConfirmPendingActionData, ConfirmPendingActionErrors, ConfirmPendingActionResponse, ConfirmPendingActionResponses, ConnectionListQuery, ConnectionListResponse, ConnectionResponse, ConnectionTestResult, ConsoleEventPayload, ContainerActionResponse, ContainerDetailResponse, ContainerEnvironmentVariableValueResponse, ContainerInfoResponse, ContainerInventoryItem, ContainerListResponse, ContainerLogSettings, ContainerLogsQuery, ContainerMetricHistoryPoint, ContainerMetricsGetHistoryData, ContainerMetricsGetHistoryErrors, ContainerMetricsGetHistoryResponse, ContainerMetricsGetHistoryResponses, ContainerMetricsHistoryQuery, ContainerMetricsResponse, ContainerResponse, ContainerRuntimeInfo, ContainerStatsSample, ContentPart, ContextLine, ContextLogsRequest, ContextLogsResponse, ConversationDetailResponse, ConversationResponse, ConversationsQueryParams, ConversationSummary, CopyBlobRequest, CostAnalysis, CreateAgentData, CreateAgentErrors, CreateAgentResponse, CreateAgentResponses, CreateAlertData, CreateAlertError, CreateAlertErrors, CreateAlertResponse, CreateAlertResponses, CreateAlertRuleData, CreateAlertRuleErrors, CreateAlertRuleRequest, CreateAlertRuleResponse, CreateAlertRuleResponses, CreateApiKeyData, CreateApiKeyErrors, CreateApiKeyRequest, CreateApiKeyResponse, CreateApiKeyResponse2, CreateApiKeyResponses, CreateBackupScheduleData, CreateBackupScheduleError, CreateBackupScheduleErrors, CreateBackupScheduleRequest, CreateBackupScheduleResponse, CreateBackupScheduleResponses, CreateBitbucketProviderData, CreateBitbucketProviderErrors, CreateBitbucketProviderResponse, CreateBitbucketProviderResponses, CreateBitbucketRequest, CreateCloudflareProviderData, CreateCloudflareProviderErrors, CreateCloudflareProviderRequest, CreateCloudflareProviderResponse, CreateCloudflareProviderResponses, CreateConversationData, CreateConversationErrors, CreateConversationRequest, CreateConversationResponse, CreateConversationResponses, CreateCustomDomainData, CreateCustomDomainErrors, CreateCustomDomainResponse, CreateCustomDomainResponses, CreateDashboardData, CreateDashboardError, CreateDashboardErrors, CreateDashboardRequest, CreateDashboardResponse, CreateDashboardResponses, CreateDeploymentTokenData, CreateDeploymentTokenErrors, CreateDeploymentTokenRequest, CreateDeploymentTokenResponse, CreateDeploymentTokenResponse2, CreateDeploymentTokenResponses, CreateDnsProviderData, CreateDnsProviderErrors, CreateDnsProviderRequest, CreateDnsProviderResponse, CreateDnsProviderResponses, CreateDomainData, CreateDomainErrors, CreateDomainRequest, CreateDomainResponse, CreateDomainResponses, CreatedResource, CreateDsnData, CreateDsnErrors, CreateDsnRequest, CreateDsnResponse, CreateDsnResponses, CreateEmailDomainData, CreateEmailDomainErrors, CreateEmailDomainRequest, CreateEmailDomainResponse, CreateEmailDomainResponses, CreateEmailProviderData, CreateEmailProviderErrors, CreateEmailProviderRequest, CreateEmailProviderResponse, CreateEmailProviderResponses, CreateEnvironmentData, CreateEnvironmentErrors, CreateEnvironmentRequest, CreateEnvironmentResponse, CreateEnvironmentResponses, CreateEnvironmentVariableData, CreateEnvironmentVariableErrors, CreateEnvironmentVariableRequest, CreateEnvironmentVariableResponse, CreateEnvironmentVariableResponses, CreateExternalServiceRequest, CreateFlagData, CreateFlagErrors, CreateFlagRequest, CreateFlagResponse, CreateFlagResponses, CreateFunnelData, CreateFunnelErrors, CreateFunnelRequest, CreateFunnelResponse, CreateFunnelResponse2, CreateFunnelResponses, CreateFunnelStep, CreateGenericProviderData, CreateGenericProviderErrors, CreateGenericProviderResponse, CreateGenericProviderResponses, CreateGenericRequest, CreateGiteaPatProviderData, CreateGiteaPatProviderErrors, CreateGiteaPatProviderResponse, CreateGiteaPatProviderResponses, CreateGiteaPatRequest, CreateGithubPatProviderData, CreateGithubPatProviderErrors, CreateGithubPatProviderResponse, CreateGithubPatProviderResponses, CreateGitHubPatRequest, CreateGitlabOauthProviderData, CreateGitlabOauthProviderErrors, CreateGitlabOauthProviderResponse, CreateGitlabOauthProviderResponses, CreateGitLabOAuthRequest, CreateGitlabPatProviderData, CreateGitlabPatProviderErrors, CreateGitlabPatProviderResponse, CreateGitlabPatProviderResponses, CreateGitLabPatRequest, CreateGitProviderData, CreateGitProviderErrors, CreateGitProviderResponse, CreateGitProviderResponses, CreateGlobalMcpData, CreateGlobalMcpErrors, CreateGlobalMcpResponse, CreateGlobalMcpResponses, CreateGlobalSkillData, CreateGlobalSkillErrors, CreateGlobalSkillResponse, CreateGlobalSkillResponses, CreateIncidentData, CreateIncidentErrors, CreateIncidentRequest, CreateIncidentResponse, CreateIncidentResponses, CreateIntegrationBody, CreateIpAccessControlData, CreateIpAccessControlError, CreateIpAccessControlErrors, CreateIpAccessControlRequest, CreateIpAccessControlResponse, CreateIpAccessControlResponses, CreateMcpData, CreateMcpErrors, CreateMcpRequest, CreateMcpResponse, CreateMcpResponses, CreateMetricAlertRequest, CreateMonitorData, CreateMonitorErrors, CreateMonitorRequest, CreateMonitorResponse, CreateMonitorResponses, CreateNotificationEmailProviderData, CreateNotificationEmailProviderErrors, CreateNotificationEmailProviderRequest, CreateNotificationEmailProviderResponse, CreateNotificationEmailProviderResponses, CreateNotificationProviderData, CreateNotificationProviderErrors, CreateNotificationProviderResponse, CreateNotificationProviderResponses, CreateOidcProviderData, CreateOidcProviderErrors, CreateOidcProviderRequest, CreateOidcProviderResponse, CreateOidcProviderResponses, CreateOidcRoleMappingData, CreateOidcRoleMappingRequest, CreateOidcRoleMappingResponse, CreateOidcRoleMappingResponses, CreateOrRecreateOrderData, CreateOrRecreateOrderErrors, CreateOrRecreateOrderResponse, CreateOrRecreateOrderResponses, CreatePlanData, CreatePlanErrors, CreatePlanRequest, CreatePlanResponse, CreatePlanResponse2, CreatePlanResponses, CreatePrData, CreatePrErrors, CreateProjectAccessRequest, CreateProjectData, CreateProjectErrors, CreateProjectFromTemplateData, CreateProjectFromTemplateErrors, CreateProjectFromTemplateRequest, CreateProjectFromTemplateResponse, CreateProjectFromTemplateResponse2, CreateProjectFromTemplateResponses, CreateProjectReleaseData, CreateProjectReleaseErrors, CreateProjectReleaseResponse, CreateProjectReleaseResponses, CreateProjectRequest, CreateProjectResponse, CreateProjectResponses, CreateProjectSecretData, CreateProjectSecretErrors, CreateProjectSecretRequest, CreateProjectSecretResponse, CreateProjectSecretResponses, CreateProviderKeyData, CreateProviderKeyError, CreateProviderKeyErrors, CreateProviderKeyRequest, CreateProviderKeyResponse, CreateProviderKeyResponses, CreateProviderRequest, CreatePrResponse, CreatePrResponse2, CreatePrResponses, CreateReleaseData, CreateReleaseErrors, CreateReleaseResponse, CreateReleaseResponses, CreateRouteData, CreateRouteErrors, CreateRouteRequest, CreateRouteResponse, CreateRouteResponses, CreateS3SourceData, CreateS3SourceError, CreateS3SourceErrors, CreateS3SourceRequest, CreateS3SourceResponse, CreateS3SourceResponses, CreateSandboxBody, CreateSandboxData, CreateSandboxErrors, CreateSandboxResponse, CreateSandboxResponses, CreateServiceData, CreateServiceErrors, CreateServiceResponse, CreateServiceResponses, CreateSkillData, CreateSkillErrors, CreateSkillRequest, CreateSkillResponse, CreateSkillResponses, CreateSlackProviderData, CreateSlackProviderErrors, CreateSlackProviderRequest, CreateSlackProviderResponse, CreateSlackProviderResponses, CreateTeamData, CreateTeamErrors, CreateTeamMemberRequest, CreateTeamRequest, CreateTeamResponse, CreateTeamResponses, CreateUserData, CreateUserErrors, CreateUserRequest, CreateUserResponse, CreateUserResponses, CreateWebhookData, CreateWebhookErrors, CreateWebhookProviderData, CreateWebhookProviderErrors, CreateWebhookProviderRequest, CreateWebhookProviderResponse, CreateWebhookProviderResponses, CreateWebhookRequestBody, CreateWebhookResponse, CreateWebhookResponses, CronExecutionInfo, CronInfo, CrossProjectSiblingRef, CrossProjectTraceResponse, CurrentStatusResponse, CustomDomainRequest, CustomDomainResponse, CustomerMovementResponse, DashboardLayout, DashboardProjectsAnalyticsQuery, DashboardProjectsAnalyticsResponse, DashboardSection, DashboardTile, DatabaseMetricsResponse, DatabaseMetricsRow, DataImplication, DataImplicationSeverity, DeactivateApiKeyData, DeactivateApiKeyErrors, DeactivateApiKeyResponse, DeactivateApiKeyResponses, DeactivateConnectionData, DeactivateConnectionErrors, DeactivateConnectionResponses, DeactivateProviderData, DeactivateProviderErrors, DeactivateProviderResponses, DeleteAgentData, DeleteAgentErrors, DeleteAgentResponse, DeleteAgentResponses, DeleteAlertData, DeleteAlertError, DeleteAlertErrors, DeleteAlertResponse, DeleteAlertResponses, DeleteAlertRuleData, DeleteAlertRuleErrors, DeleteAlertRuleResponse, DeleteAlertRuleResponses, DeleteApiKeyData, DeleteApiKeyErrors, DeleteApiKeyResponse, DeleteApiKeyResponses, DeleteBackupData, DeleteBackupError, DeleteBackupErrors, DeleteBackupResponse, DeleteBackupResponses, DeleteBackupScheduleData, DeleteBackupScheduleError, DeleteBackupScheduleErrors, DeleteBackupScheduleResponse, DeleteBackupScheduleResponses, DeleteBlobRequest, DeleteBlobResponse, DeleteConnectionData, DeleteConnectionErrors, DeleteConnectionResponse, DeleteConnectionResponses, DeleteCustomDomainData, DeleteCustomDomainErrors, DeleteCustomDomainResponse, DeleteCustomDomainResponses, DeleteDashboardData, DeleteDashboardError, DeleteDashboardErrors, DeleteDashboardResponse, DeleteDashboardResponses, DeleteDeploymentTokenData, DeleteDeploymentTokenErrors, DeleteDeploymentTokenResponse, DeleteDeploymentTokenResponses, DeleteDnsProviderData, DeleteDnsProviderErrors, DeleteDnsProviderResponse, DeleteDnsProviderResponses, DeleteDomainData, DeleteDomainErrors, DeleteDomainResponse, DeleteDomainResponses, DeleteEmailDomainData, DeleteEmailDomainErrors, DeleteEmailDomainResponse, DeleteEmailDomainResponses, DeleteEmailProviderData, DeleteEmailProviderErrors, DeleteEmailProviderResponse, DeleteEmailProviderResponses, DeleteEnvironmentData, DeleteEnvironmentDomainData, DeleteEnvironmentDomainErrors, DeleteEnvironmentDomainResponse, DeleteEnvironmentDomainResponses, DeleteEnvironmentErrors, DeleteEnvironmentResponse, DeleteEnvironmentResponses, DeleteEnvironmentVariableData, DeleteEnvironmentVariableErrors, DeleteEnvironmentVariableResponse, DeleteEnvironmentVariableResponses, DeleteExternalImageData, DeleteExternalImageErrors, DeleteExternalImageResponse, DeleteExternalImageResponses, DeleteFunnelData, DeleteFunnelErrors, DeleteFunnelResponses, DeleteGitProviderData, DeleteGitProviderErrors, DeleteGitProviderResponse, DeleteGitProviderResponses, DeleteGlobalMcpData, DeleteGlobalMcpErrors, DeleteGlobalMcpResponse, DeleteGlobalMcpResponses, DeleteGlobalSkillData, DeleteGlobalSkillErrors, DeleteGlobalSkillResponse, DeleteGlobalSkillResponses, DeleteIpAccessControlData, DeleteIpAccessControlError, DeleteIpAccessControlErrors, DeleteIpAccessControlResponse, DeleteIpAccessControlResponses, DeleteMcpData, DeleteMcpErrors, DeleteMcpResponse, DeleteMcpResponses, DeleteMonitorData, DeleteMonitorErrors, DeleteMonitorResponse, DeleteMonitorResponses, DeleteNotificationProviderData, DeleteNotificationProviderErrors, DeleteNotificationProviderResponse, DeleteNotificationProviderResponses, DeleteOidcProviderData, DeleteOidcProviderResponse, DeleteOidcProviderResponses, DeleteOidcRoleMappingData, DeleteOidcRoleMappingResponse, DeleteOidcRoleMappingResponses, DeletePreferencesData, DeletePreferencesErrors, DeletePreferencesResponse, DeletePreferencesResponses, DeleteProjectData, DeleteProjectErrors, DeleteProjectResponse, DeleteProjectResponses, DeleteProjectSecretData, DeleteProjectSecretErrors, DeleteProjectSecretResponse, DeleteProjectSecretResponses, DeleteProviderKeyData, DeleteProviderKeyError, DeleteProviderKeyErrors, DeleteProviderKeyResponse, DeleteProviderKeyResponses, DeleteProviderSafelyData, DeleteProviderSafelyErrors, DeleteProviderSafelyResponse, DeleteProviderSafelyResponses, DeleteReleaseSourceFilesData, DeleteReleaseSourceFilesErrors, DeleteReleaseSourceFilesResponse, DeleteReleaseSourceFilesResponses, DeleteReleaseSourceMapsData, DeleteReleaseSourceMapsErrors, DeleteReleaseSourceMapsResponse, DeleteReleaseSourceMapsResponses, DeleteResponse, DeleteRouteData, DeleteRouteErrors, DeleteRouteResponse, DeleteRouteResponses, DeleteS3SourceData, DeleteS3SourceError, DeleteS3SourceErrors, DeleteS3SourceResponse, DeleteS3SourceResponses, DeleteScanData, DeleteScanError, DeleteScanErrors, DeleteScanResponse, DeleteScanResponses, DeleteSecretData, DeleteSecretErrors, DeleteSecretResponse, DeleteSecretResponses, DeleteServiceData, DeleteServiceErrors, DeleteServiceResponse, DeleteServiceResponses, DeleteSessionReplayData, DeleteSessionReplayError, DeleteSessionReplayErrors, DeleteSessionReplayResponses, DeleteSkillData, DeleteSkillErrors, DeleteSkillResponse, DeleteSkillResponses, DeleteSourceMapData, DeleteSourceMapErrors, DeleteSourceMapResponse, DeleteSourceMapResponses, DeleteStaticBundleData, DeleteStaticBundleErrors, DeleteStaticBundleResponse, DeleteStaticBundleResponses, DeleteTeamData, DeleteTeamErrors, DeleteTeamResponse, DeleteTeamResponses, DeleteUserData, DeleteUserErrors, DeleteUserResponse, DeleteUserResponses, DeleteWebhookData, DeleteWebhookErrors, DeleteWebhookResponse, DeleteWebhookResponses, DelRequest, DelResponse, DeployFromImageData, DeployFromImageErrors, DeployFromImageRequest, DeployFromImageResponse, DeployFromImageResponses, DeployFromImageUploadData, DeployFromImageUploadErrors, DeployFromImageUploadQuery, DeployFromImageUploadResponse, DeployFromImageUploadResponses, DeployFromStaticData, DeployFromStaticErrors, DeployFromStaticRequest, DeployFromStaticResponse, DeployFromStaticResponses, DeployFromUploadedSourceData, DeployFromUploadedSourceErrors, DeployFromUploadedSourceResponse, DeployFromUploadedSourceResponses, DeploymentConfig, DeploymentConfigSnapshot, DeploymentConfiguration, DeploymentContainerLogContentResponse, DeploymentContainerLogResponse, DeploymentContainerLogsListResponse, DeploymentEnvironmentResponse, DeploymentJobResponse, DeploymentJobsResponse, DeploymentListResponse, DeploymentMetadata, DeploymentMetricsGetLatestData, DeploymentMetricsGetLatestErrors, DeploymentMetricsGetLatestResponse, DeploymentMetricsGetLatestResponses, DeploymentMetricsGetRangeData, DeploymentMetricsGetRangeErrors, DeploymentMetricsGetRangeResponse, DeploymentMetricsGetRangeResponses, DeploymentMetricsToggleData, DeploymentMetricsToggleErrors, DeploymentMetricsToggleResponses, DeploymentResponse, DeploymentStateResponse, DeploymentStrategy, DeploymentTokenListResponse, DeploymentTokenResponse, DestroySandboxData, DestroySandboxErrors, DestroySandboxResponse, DestroySandboxResponses, DetachScheduleServiceData, DetachScheduleServiceError, DetachScheduleServiceErrors, DetachScheduleServiceResponse, DetachScheduleServiceResponses, DetectionConfig, DetectPublicPresetsData, DetectPublicPresetsErrors, DetectPublicPresetsResponse, DetectPublicPresetsResponses, DeviceCount, DigestSections, Direction, DisableBackupScheduleData, DisableBackupScheduleErrors, DisableBackupScheduleResponse, DisableBackupScheduleResponses, DisableBlobResponse, DisableKvResponse, DisableMfaData, DisableMfaErrors, DisableMfaRequest, DisableMfaResponse, DisableMfaResponses, DiscoverRequest, DiscoverResponse, DiscoverWorkloadsData, DiscoverWorkloadsErrors, DiscoverWorkloadsResponse, DiscoverWorkloadsResponses, DiskInfo, DiskSpaceAlert, DiskSpaceAlertSettings, DiskSpaceCheckResult, DnsAckRequest, DnsAckResponse, DnsChallengeRecordResult, DnsChangesResponse, DnsCompletionResponse, DnsLookupError, DnsLookupRequest, DnsLookupResponse, DnsProviderCredentials, DnsProviderResponse, DnsProviderSettings, DnsProviderSettingsMasked, DnsProviderType, DnsRecord, DnsRecordChange, DnsRecordContent, DnsRecordResponse, DnsRecordSetupResult, DnsRecordStatusResponse, DnsZone, DockerComposePresetConfig, DockerfilePresetConfig, DockerfileVariant, DockerRegistrySettings, DockerRegistrySettingsMasked, DomainAction, DomainChallengeResponse, DomainData, DomainEnvironmentResponse, DomainError, DomainErrors, DomainPlan, DomainResponse, DomainResponse2, DomainResponses, DownloadGlobalSkillArchiveData, DownloadGlobalSkillArchiveErrors, DownloadGlobalSkillArchiveResponse, DownloadGlobalSkillArchiveResponses, DownloadObjectData, DownloadObjectErrors, DownloadObjectResponse, DownloadObjectResponses, DownloadSkillArchiveData, DownloadSkillArchiveErrors, DownloadSkillArchiveResponse, DownloadSkillArchiveResponses, DrainNodeResponse, DrainStatusResponse, DropArchiveUpload, DropInspectionResponse, DropOffPoint, DropPresetCandidate, EmailConfig, EmailDomainResponse, EmailDomainWithDnsResponse, EmailProviderResponse, EmailProviderTypeRoute, EmailRequest, EmailResponse, EmailStatsResponse, EmailStatusData, EmailStatusErrors, EmailStatusResponse, EmailStatusResponse2, EmailStatusResponses, EmailTrackingResponse, EmailTrackingSetupResponse, EmailTrackingStatusResponse, EmbeddingData, EmbeddingInput, EmbeddingRequest, EmbeddingResponse, EmbeddingsData, EmbeddingsError, EmbeddingsErrors, EmbeddingsResponse, EmbeddingsResponses, EmbeddingUsage, EnableBackupScheduleData, EnableBackupScheduleErrors, EnableBackupScheduleResponse, EnableBackupScheduleResponses, EnableBlobRequest, EnableBlobResponse, EnableKvRequest, EnableKvResponse, EnablePgStatStatementsResponse, EndpointDto, EnqueuedJob, EnrichVisitorData, EnrichVisitorErrors, EnrichVisitorRequest, EnrichVisitorResponse, EnrichVisitorResponse2, EnrichVisitorResponses, EnrollmentTokenInfo, EnrollmentTokenListResponse, EntityInfoResponse, EntityResponse, EnvironmentConfiguration, EnvironmentDomainResponse, EnvironmentInfo, EnvironmentResponse, EnvironmentVariable, EnvironmentVariableInfo, EnvironmentVariableResponse, EnvironmentVariableValueResponse, EnvVarInput, EnvVarIntegrationInfo, EnvVarResponse, EnvVarTemplateResponse, ErrorDashboardStatsQuery, ErrorDashboardStatsResponse, ErrorEventResponse, ErrorGroupResponse, ErrorGroupStatsResponse, ErrorResponse, ErrorRow, ErrorTimeSeriesDataResponse, ErrorTimeSeriesQuery, EventActivityBucket, EventBreakdown, EventBrowserStats, EventCount, EventCountryStats, EventDetailQuery, EventDetailResponse, EventEntriesQuery, EventEntriesResponse, EventEntryInfo, EventKind, EventMetricsPayload, EventReferrerStats, EventsCountQuery, EventsResponse, EventTimeline, EventTimelineQuery, EventType, EventTypeBreakdown, EventTypeBreakdownQuery, EventTypeResponse, EventTypesResponse, EventVisitorInfo, EventVisitorsQuery, EventVisitorsResponse, ExecBody, ExecData, ExecDetachedData, ExecDetachedErrors, ExecDetachedResponse, ExecDetachedResponse2, ExecDetachedResponses, ExecErrors, ExecResponse, ExecResponse2, ExecResponses, ExecuteDeploymentOperationData, ExecuteDeploymentOperationErrors, ExecuteDeploymentOperationResponse, ExecuteDeploymentOperationResponses, ExecuteImportData, ExecuteImportErrors, ExecuteImportRequest, ExecuteImportResponse, ExecuteImportResponse2, ExecuteImportResponses, ExecuteOperationRequest, ExpireRequest, ExpireResponse, ExplorerSupportResponse, ExtendTimeoutBody, ExtendTimeoutData, ExtendTimeoutErrors, ExtendTimeoutResponse, ExtendTimeoutResponses, ExternalImageResponse, ExternalServiceBackupResponse, ExternalServiceDetails, ExternalServiceEnablePgStatStatementsData, ExternalServiceEnablePgStatStatementsErrors, ExternalServiceEnablePgStatStatementsResponse, ExternalServiceEnablePgStatStatementsResponses, ExternalServiceInfo, ExternalServiceMetricsByDatabaseData, ExternalServiceMetricsByDatabaseErrors, ExternalServiceMetricsByDatabaseResponse, ExternalServiceMetricsByDatabaseResponses, ExternalServiceMetricsCreateAlertRuleData, ExternalServiceMetricsCreateAlertRuleErrors, ExternalServiceMetricsCreateAlertRuleResponse, ExternalServiceMetricsCreateAlertRuleResponses, ExternalServiceMetricsDeleteAlertRuleData, ExternalServiceMetricsDeleteAlertRuleErrors, ExternalServiceMetricsDeleteAlertRuleResponse, ExternalServiceMetricsDeleteAlertRuleResponses, ExternalServiceMetricsGetAlertRulesData, ExternalServiceMetricsGetAlertRulesErrors, ExternalServiceMetricsGetAlertRulesResponse, ExternalServiceMetricsGetAlertRulesResponses, ExternalServiceMetricsGetLatestData, ExternalServiceMetricsGetLatestErrors, ExternalServiceMetricsGetLatestResponse, ExternalServiceMetricsGetLatestResponses, ExternalServiceMetricsGetRangeData, ExternalServiceMetricsGetRangeErrors, ExternalServiceMetricsGetRangeResponse, ExternalServiceMetricsGetRangeResponses, ExternalServiceMetricsStatusData, ExternalServiceMetricsStatusErrors, ExternalServiceMetricsStatusResponse, ExternalServiceMetricsStatusResponses, ExternalServiceMetricsToggleData, ExternalServiceMetricsToggleErrors, ExternalServiceMetricsToggleResponses, ExternalServiceMetricsUpdateAlertRuleData, ExternalServiceMetricsUpdateAlertRuleErrors, ExternalServiceMetricsUpdateAlertRuleResponse, ExternalServiceMetricsUpdateAlertRuleResponses, ExternalServiceResetPgStatStatementsData, ExternalServiceResetPgStatStatementsErrors, ExternalServiceResetPgStatStatementsResponse, ExternalServiceResetPgStatStatementsResponses, ExternalServiceSummary, FieldResponse, FinalizeOrderData, FinalizeOrderErrors, FinalizeOrderResponse, FinalizeOrderResponses, FinalizeProjectReleaseData, FinalizeProjectReleaseErrors, FinalizeProjectReleaseResponse, FinalizeProjectReleaseResponses, FindConversationData, FindConversationErrors, FindConversationResponse, FindConversationResponses, FiringSeriesEntry, FlagEnvironmentResponse, FlagListResponse, FlagResponse, FlagSnapshot, FlagSnapshotResponse, FlagValueType, ForecastAlgorithm, ForecastParams, FullError, FullEvent, FullRequest, FunnelMetricsResponse, FunnelResponse, GatewayStatus, GenAiEvent, GenAiSpanDetail, GenAiTraceDetailResponse, GenAiTraceSummariesResponse, GenAiTraceSummary, GeneralStatsQuery, GeneralStatsResponse, GenerateDockerfileRequest, GenerateDockerfileResponse, GenerateJoinTokenData, GenerateJoinTokenErrors, GenerateJoinTokenResponse, GenerateJoinTokenResponse2, GenerateJoinTokenResponses, GeneratePresetDockerfileData, GeneratePresetDockerfileErrors, GeneratePresetDockerfileResponse, GeneratePresetDockerfileResponses, GeoLocationResponse, GeoRestrictionsConfig, GetAccessInfoData, GetAccessInfoErrors, GetAccessInfoResponse, GetAccessInfoResponses, GetActiveVisitorsData, GetActiveVisitorsErrors, GetActiveVisitorsResponse, GetActiveVisitorsResponses, GetActivityGraphData, GetActivityGraphErrors, GetActivityGraphResponse, GetActivityGraphResponses, GetAdminGateData, GetAdminGateErrors, GetAdminGateResponse, GetAdminGateResponses, GetAgentData, GetAgentErrors, GetAgentResponse, GetAgentResponses, GetAggregatedBucketsData, GetAggregatedBucketsErrors, GetAggregatedBucketsResponse, GetAggregatedBucketsResponses, GetAiAgentBreakdownData, GetAiAgentBreakdownError, GetAiAgentBreakdownErrors, GetAiAgentBreakdownResponse, GetAiAgentBreakdownResponses, GetAiAgentPagesData, GetAiAgentPagesError, GetAiAgentPagesErrors, GetAiAgentPagesResponse, GetAiAgentPagesResponses, GetAiAgentTimelineData, GetAiAgentTimelineError, GetAiAgentTimelineErrors, GetAiAgentTimelineResponse, GetAiAgentTimelineResponses, GetAiPageBreakdownData, GetAiPageBreakdownError, GetAiPageBreakdownErrors, GetAiPageBreakdownResponse, GetAiPageBreakdownResponses, GetAiStatusBreakdownData, GetAiStatusBreakdownError, GetAiStatusBreakdownErrors, GetAiStatusBreakdownResponse, GetAiStatusBreakdownResponses, GetAlertData, GetAlertError, GetAlertErrors, GetAlertResponse, GetAlertResponses, GetAlertRuleData, GetAlertRuleErrors, GetAlertRuleResponse, GetAlertRuleResponses, GetAllRepositoriesByNameData, GetAllRepositoriesByNameErrors, GetAllRepositoriesByNameResponse, GetAllRepositoriesByNameResponses, GetAnalyticsActiveVisitorsData, GetAnalyticsActiveVisitorsErrors, GetAnalyticsActiveVisitorsResponse, GetAnalyticsActiveVisitorsResponses, GetAnalyticsEventsCountData, GetAnalyticsEventsCountErrors, GetAnalyticsEventsCountResponse, GetAnalyticsEventsCountResponses, GetAnalyticsSessionEventsData, GetAnalyticsSessionEventsErrors, GetAnalyticsSessionEventsResponse, GetAnalyticsSessionEventsResponses, GetAnalyticsVisitorSessionsData, GetAnalyticsVisitorSessionsErrors, GetAnalyticsVisitorSessionsResponse, GetAnalyticsVisitorSessionsResponses, GetApiKeyData, GetApiKeyErrors, GetApiKeyPermissionsData, GetApiKeyPermissionsErrors, GetApiKeyPermissionsResponse, GetApiKeyPermissionsResponses, GetApiKeyResponse, GetApiKeyResponses, GetAuditLogData, GetAuditLogErrors, GetAuditLogResponse, GetAuditLogResponses, GetBackupData, GetBackupError, GetBackupErrors, GetBackupResponse, GetBackupResponses, GetBackupScheduleData, GetBackupScheduleErrors, GetBackupScheduleResponse, GetBackupScheduleResponses, GetBranchesByRepositoryIdData, GetBranchesByRepositoryIdErrors, GetBranchesByRepositoryIdResponse, GetBranchesByRepositoryIdResponses, GetBucketedIncidentsData, GetBucketedIncidentsErrors, GetBucketedIncidentsResponse, GetBucketedIncidentsResponses, GetBucketedStatusData, GetBucketedStatusErrors, GetBucketedStatusResponse, GetBucketedStatusResponses, GetChallengeTokenData, GetChallengeTokenErrors, GetChallengeTokenResponse, GetChallengeTokenResponses, GetChatReadinessData, GetChatReadinessErrors, GetChatReadinessResponse, GetChatReadinessResponses, GetCliStatusData, GetCliStatusErrors, GetCliStatusResponses, GetClusterHealthData, GetClusterHealthErrors, GetClusterHealthResponse, GetClusterHealthResponses, GetClusterMemberData, GetClusterMemberErrors, GetClusterMemberResponse, GetClusterMemberResponses, GetCmdData, GetCmdErrors, GetCmdResponse, GetCmdResponses, GetContainerDetailData, GetContainerDetailErrors, GetContainerDetailResponse, GetContainerDetailResponses, GetContainerEnvironmentVariableData, GetContainerEnvironmentVariableErrors, GetContainerEnvironmentVariableResponse, GetContainerEnvironmentVariableResponses, GetContainerInfoData, GetContainerInfoErrors, GetContainerInfoResponse, GetContainerInfoResponses, GetContainerLogsByIdData, GetContainerLogsByIdErrors, GetContainerLogsData, GetContainerLogsErrors, GetContainerMetricsData, GetContainerMetricsErrors, GetContainerMetricsResponse, GetContainerMetricsResponses, GetConversationData, GetConversationDetailData, GetConversationDetailError, GetConversationDetailErrors, GetConversationDetailResponse, GetConversationDetailResponses, GetConversationErrors, GetConversationResponse, GetConversationResponses, GetConversationsData, GetConversationsError, GetConversationsErrors, GetConversationsResponse, GetConversationsResponses, GetCronByIdData, GetCronByIdErrors, GetCronByIdResponse, GetCronByIdResponses, GetCronExecutionsData, GetCronExecutionsErrors, GetCronExecutionsResponse, GetCronExecutionsResponses, GetCrossProjectTraceSiblingsData, GetCrossProjectTraceSiblingsError, GetCrossProjectTraceSiblingsErrors, GetCrossProjectTraceSiblingsResponse, GetCrossProjectTraceSiblingsResponses, GetCurrentMonitorStatusData, GetCurrentMonitorStatusErrors, GetCurrentMonitorStatusResponse, GetCurrentMonitorStatusResponses, GetCurrentUserData, GetCurrentUserErrors, GetCurrentUserResponse, GetCurrentUserResponses, GetCustomDomainData, GetCustomDomainErrors, GetCustomDomainResponse, GetCustomDomainResponses, GetDashboardData, GetDashboardError, GetDashboardErrors, GetDashboardProjectsAnalyticsData, GetDashboardProjectsAnalyticsErrors, GetDashboardProjectsAnalyticsResponse, GetDashboardProjectsAnalyticsResponses, GetDashboardResponse, GetDashboardResponses, GetDeliveryData, GetDeliveryErrors, GetDeliveryResponse, GetDeliveryResponses, GetDeploymentContainerLogContentData, GetDeploymentContainerLogContentErrors, GetDeploymentContainerLogContentResponse, GetDeploymentContainerLogContentResponses, GetDeploymentData, GetDeploymentErrors, GetDeploymentJobLogsData, GetDeploymentJobLogsErrors, GetDeploymentJobLogsResponse, GetDeploymentJobLogsResponses, GetDeploymentJobsData, GetDeploymentJobsErrors, GetDeploymentJobsResponse, GetDeploymentJobsResponses, GetDeploymentOperationsData, GetDeploymentOperationsErrors, GetDeploymentOperationsResponse, GetDeploymentOperationsResponses, GetDeploymentOperationStatusData, GetDeploymentOperationStatusErrors, GetDeploymentOperationStatusResponse, GetDeploymentOperationStatusResponses, GetDeploymentResponse, GetDeploymentResponses, GetDeploymentsParams, GetDeploymentTokenData, GetDeploymentTokenErrors, GetDeploymentTokenResponse, GetDeploymentTokenResponses, GetDiskStatusData, GetDiskStatusErrors, GetDiskStatusResponse, GetDiskStatusResponses, GetDnsChangesData, GetDnsChangesErrors, GetDnsChangesResponse, GetDnsChangesResponses, GetDnsProviderData, GetDnsProviderErrors, GetDnsProviderResponse, GetDnsProviderResponses, GetDomainByHostData, GetDomainByHostErrors, GetDomainByHostResponse, GetDomainByHostResponses, GetDomainByIdData, GetDomainByIdErrors, GetDomainByIdResponse, GetDomainByIdResponses, GetDomainByNameData, GetDomainByNameErrors, GetDomainByNameResponse, GetDomainByNameResponses, GetDomainData, GetDomainDnsRecordsData, GetDomainDnsRecordsErrors, GetDomainDnsRecordsResponse, GetDomainDnsRecordsResponses, GetDomainErrors, GetDomainOrderData, GetDomainOrderErrors, GetDomainOrderResponse, GetDomainOrderResponses, GetDomainResponse, GetDomainResponses, GetEmailData, GetEmailErrors, GetEmailEventsData, GetEmailEventsErrors, GetEmailEventsResponse, GetEmailEventsResponses, GetEmailLinksData, GetEmailLinksErrors, GetEmailLinksResponse, GetEmailLinksResponses, GetEmailProviderData, GetEmailProviderErrors, GetEmailProviderResponse, GetEmailProviderResponses, GetEmailResponse, GetEmailResponses, GetEmailStatsData, GetEmailStatsErrors, GetEmailStatsResponse, GetEmailStatsResponses, GetEmailTrackingData, GetEmailTrackingErrors, GetEmailTrackingResponse, GetEmailTrackingResponses, GetEmailTrackingStatusData, GetEmailTrackingStatusErrors, GetEmailTrackingStatusResponse, GetEmailTrackingStatusResponses, GetEntityInfoData, GetEntityInfoErrors, GetEntityInfoResponse, GetEntityInfoResponses, GetEnvironmentCronsData, GetEnvironmentCronsErrors, GetEnvironmentCronsResponse, GetEnvironmentCronsResponses, GetEnvironmentData, GetEnvironmentDomainsData, GetEnvironmentDomainsErrors, GetEnvironmentDomainsResponse, GetEnvironmentDomainsResponses, GetEnvironmentErrors, GetEnvironmentResponse, GetEnvironmentResponses, GetEnvironmentsData, GetEnvironmentsErrors, GetEnvironmentsResponse, GetEnvironmentsResponses, GetEnvironmentVariablesData, GetEnvironmentVariablesErrors, GetEnvironmentVariablesQuery, GetEnvironmentVariablesResponse, GetEnvironmentVariablesResponses, GetEnvironmentVariableValueData, GetEnvironmentVariableValueErrors, GetEnvironmentVariableValueResponse, GetEnvironmentVariableValueResponses, GetErrorDashboardStatsData, GetErrorDashboardStatsErrors, GetErrorDashboardStatsResponse, GetErrorDashboardStatsResponses, GetErrorEventData, GetErrorEventErrors, GetErrorEventResponse, GetErrorEventResponses, GetErrorGroupData, GetErrorGroupErrors, GetErrorGroupResponse, GetErrorGroupResponses, GetErrorStatsData, GetErrorStatsErrors, GetErrorStatsResponse, GetErrorStatsResponses, GetErrorTimeSeriesData, GetErrorTimeSeriesErrors, GetErrorTimeSeriesResponse, GetErrorTimeSeriesResponses, GetEventDetailData, GetEventDetailErrors, GetEventDetailResponse, GetEventDetailResponses, GetEventEntriesData, GetEventEntriesErrors, GetEventEntriesResponse, GetEventEntriesResponses, GetEventsCountData, GetEventsCountErrors, GetEventsCountResponse, GetEventsCountResponses, GetEventsTimelineData, GetEventsTimelineErrors, GetEventsTimelineResponse, GetEventsTimelineResponses, GetEventTypeBreakdownData, GetEventTypeBreakdownErrors, GetEventTypeBreakdownResponse, GetEventTypeBreakdownResponses, GetEventVisitorsData, GetEventVisitorsErrors, GetEventVisitorsResponse, GetEventVisitorsResponses, GetExternalImageData, GetExternalImageErrors, GetExternalImageResponse, GetExternalImageResponses, GetFileData, GetFileErrors, GetFileResponse, GetFileResponses, GetFlagData, GetFlagErrors, GetFlagResponse, GetFlagResponses, GetFlagSnapshotData, GetFlagSnapshotErrors, GetFlagSnapshotResponse, GetFlagSnapshotResponses, GetFunnelMetricsData, GetFunnelMetricsErrors, GetFunnelMetricsQuery, GetFunnelMetricsResponse, GetFunnelMetricsResponses, GetGenaiTraceData, GetGenaiTraceError, GetGenaiTraceErrors, GetGenaiTraceResponse, GetGenaiTraceResponses, GetGeneralStatsData, GetGeneralStatsErrors, GetGeneralStatsResponse, GetGeneralStatsResponses, GetGitProviderData, GetGitProviderErrors, GetGitProviderResponse, GetGitProviderResponses, GetGlobalEventsData, GetGlobalEventsErrors, GetGlobalEventsResponse, GetGlobalEventsResponses, GetGlobalEventStatsData, GetGlobalEventStatsErrors, GetGlobalEventStatsResponse, GetGlobalEventStatsResponses, GetGlobalMcpData, GetGlobalMcpErrors, GetGlobalMcpResponse, GetGlobalMcpResponses, GetGlobalSandboxStatusData, GetGlobalSandboxStatusErrors, GetGlobalSandboxStatusResponse, GetGlobalSandboxStatusResponses, GetGlobalSkillData, GetGlobalSkillErrors, GetGlobalSkillResponse, GetGlobalSkillResponses, GetGroupedPageMetricsData, GetGroupedPageMetricsError, GetGroupedPageMetricsErrors, GetGroupedPageMetricsResponse, GetGroupedPageMetricsResponses, GetHealthData, GetHealthError, GetHealthErrors, GetHealthResponse, GetHealthResponses, GetHourlyVisitsData, GetHourlyVisitsErrors, GetHourlyVisitsResponse, GetHourlyVisitsResponses, GetHttpChallengeDebugData, GetHttpChallengeDebugErrors, GetHttpChallengeDebugResponse, GetHttpChallengeDebugResponses, GetImportStatusData, GetImportStatusErrors, GetImportStatusResponse, GetImportStatusResponses, GetIncidentData, GetIncidentErrors, GetIncidentResponse, GetIncidentResponses, GetIncidentUpdatesData, GetIncidentUpdatesErrors, GetIncidentUpdatesResponse, GetIncidentUpdatesResponses, GetIpAccessControlData, GetIpAccessControlError, GetIpAccessControlErrors, GetIpAccessControlResponse, GetIpAccessControlResponses, GetIpGeolocationData, GetIpGeolocationError, GetIpGeolocationErrors, GetIpGeolocationResponse, GetIpGeolocationResponses, GetJoinTokenStatusData, GetJoinTokenStatusErrors, GetJoinTokenStatusResponse, GetJoinTokenStatusResponses, GetLastDeploymentData, GetLastDeploymentErrors, GetLastDeploymentResponse, GetLastDeploymentResponses, GetLatestScanData, GetLatestScanError, GetLatestScanErrors, GetLatestScanResponse, GetLatestScanResponses, GetLatestScansPerEnvironmentData, GetLatestScansPerEnvironmentError, GetLatestScansPerEnvironmentErrors, GetLatestScansPerEnvironmentResponse, GetLatestScansPerEnvironmentResponses, GetLiveVisitorsListData, GetLiveVisitorsListErrors, GetLiveVisitorsListResponse, GetLiveVisitorsListResponses, GetLogContextData, GetLogContextError, GetLogContextErrors, GetLogContextResponse, GetLogContextResponses, GetMcpData, GetMcpErrors, GetMcpResponse, GetMcpResponses, GetMetricsOverTimeData, GetMetricsOverTimeError, GetMetricsOverTimeErrors, GetMetricsOverTimeResponse, GetMetricsOverTimeResponses, GetMonitorData, GetMonitorErrors, GetMonitorResponse, GetMonitorResponses, GetNotificationProviderData, GetNotificationProviderErrors, GetNotificationProviderResponse, GetNotificationProviderResponses, GetOnDemandCertStatusData, GetOnDemandCertStatusErrors, GetOnDemandCertStatusResponse, GetOnDemandCertStatusResponses, GetOrCreateDsnData, GetOrCreateDsnErrors, GetOrCreateDsnRequest, GetOrCreateDsnResponse, GetOrCreateDsnResponses, GetPageFlowData, GetPageFlowErrors, GetPageFlowResponse, GetPageFlowResponses, GetPageHourlySessionsData, GetPageHourlySessionsErrors, GetPageHourlySessionsResponse, GetPageHourlySessionsResponses, GetPagePathDetailData, GetPagePathDetailErrors, GetPagePathDetailResponse, GetPagePathDetailResponses, GetPagePathsData, GetPagePathsErrors, GetPagePathsResponse, GetPagePathsResponses, GetPagePathsSparklinesData, GetPagePathsSparklinesErrors, GetPagePathsSparklinesResponse, GetPagePathsSparklinesResponses, GetPagePathVisitorsData, GetPagePathVisitorsErrors, GetPagePathVisitorsResponse, GetPagePathVisitorsResponses, GetPendingActionData, GetPendingActionErrors, GetPendingActionResponse, GetPendingActionResponses, GetPerformanceMetricsData, GetPerformanceMetricsError, GetPerformanceMetricsErrors, GetPerformanceMetricsResponse, GetPerformanceMetricsResponses, GetPgUpgradeData, GetPgUpgradeErrors, GetPgUpgradeLogsData, GetPgUpgradeLogsErrors, GetPgUpgradeLogsResponse, GetPgUpgradeLogsResponses, GetPgUpgradeResponse, GetPgUpgradeResponses, GetPipelineStatsData, GetPipelineStatsError, GetPipelineStatsErrors, GetPipelineStatsResponse, GetPipelineStatsResponses, GetPlatformInfoData, GetPlatformInfoErrors, GetPlatformInfoResponse, GetPlatformInfoResponses, GetPostgresWalHealthData, GetPostgresWalHealthErrors, GetPostgresWalHealthResponse, GetPostgresWalHealthResponses, GetPreferencesData, GetPreferencesErrors, GetPreferencesResponse, GetPreferencesResponses, GetPreviewGatewayLogsData, GetPreviewGatewayLogsResponse, GetPreviewGatewayLogsResponses, GetPreviewGatewaySettingsData, GetPreviewGatewaySettingsResponse, GetPreviewGatewaySettingsResponses, GetPreviewGatewayStatusData, GetPreviewGatewayStatusResponse, GetPreviewGatewayStatusResponses, GetPricingData, GetPricingError, GetPricingErrors, GetPricingResponse, GetPricingResponses, GetPrivateIpData, GetPrivateIpErrors, GetPrivateIpResponses, GetProjectAlarmsSummaryData, GetProjectAlarmsSummaryErrors, GetProjectAlarmsSummaryResponse, GetProjectAlarmsSummaryResponses, GetProjectBySlugData, GetProjectBySlugErrors, GetProjectBySlugResponse, GetProjectBySlugResponses, GetProjectData, GetProjectDeploymentsData, GetProjectDeploymentsErrors, GetProjectDeploymentsResponse, GetProjectDeploymentsResponses, GetProjectErrors, GetProjectResponse, GetProjectResponses, GetProjectsData, GetProjectSecretsQuery, GetProjectsErrors, GetProjectServiceEnvironmentVariablesData, GetProjectServiceEnvironmentVariablesErrors, GetProjectServiceEnvironmentVariablesResponse, GetProjectServiceEnvironmentVariablesResponses, GetProjectSessionReplaysData, GetProjectSessionReplaysError, GetProjectSessionReplaysErrors, GetProjectSessionReplaysQuery, GetProjectSessionReplaysResponse, GetProjectSessionReplaysResponse2, GetProjectSessionReplaysResponses, GetProjectsHealthData, GetProjectsHealthError, GetProjectsHealthErrors, GetProjectsHealthResponse, GetProjectsHealthResponses, GetProjectsMonitorHealthData, GetProjectsMonitorHealthErrors, GetProjectsMonitorHealthResponse, GetProjectsMonitorHealthResponses, GetProjectsResponse, GetProjectsResponses, GetProjectStatisticsData, GetProjectStatisticsErrors, GetProjectStatisticsResponse, GetProjectStatisticsResponses, GetProjectTemplateData, GetProjectTemplateErrors, GetProjectTemplateResponse, GetProjectTemplateResponses, GetPropertyBreakdownData, GetPropertyBreakdownErrors, GetPropertyBreakdownResponse, GetPropertyBreakdownResponses, GetPropertyTimelineData, GetPropertyTimelineErrors, GetPropertyTimelineResponse, GetPropertyTimelineResponses, GetProviderConnectionsData, GetProviderConnectionsErrors, GetProviderConnectionsResponse, GetProviderConnectionsResponses, GetProviderMetadataData, GetProviderMetadataErrors, GetProviderMetadataResponse, GetProviderMetadataResponses, GetProvidersMetadataData, GetProvidersMetadataErrors, GetProvidersMetadataResponse, GetProvidersMetadataResponses, GetProxyLogByIdData, GetProxyLogByIdError, GetProxyLogByIdErrors, GetProxyLogByIdResponse, GetProxyLogByIdResponses, GetProxyLogByRequestIdData, GetProxyLogByRequestIdError, GetProxyLogByRequestIdErrors, GetProxyLogByRequestIdResponse, GetProxyLogByRequestIdResponses, GetProxyLogsData, GetProxyLogsError, GetProxyLogsErrors, GetProxyLogsResponse, GetProxyLogsResponses, GetPublicBranchesData, GetPublicBranchesErrors, GetPublicBranchesResponse, GetPublicBranchesResponses, GetPublicIpData, GetPublicIpErrors, GetPublicIpResponses, GetPublicRepositoryData, GetPublicRepositoryErrors, GetPublicRepositoryResponse, GetPublicRepositoryResponses, GetQuotaData, GetQuotaError, GetQuotaErrors, GetQuotaResponse, GetQuotaResponses, GetRecentActivityData, GetRecentActivityErrors, GetRecentActivityResponse, GetRecentActivityResponses, GetRemoteExternalImageData, GetRemoteExternalImageErrors, GetRemoteExternalImageResponse, GetRemoteExternalImageResponses, GetRepositoryBranchesData, GetRepositoryBranchesErrors, GetRepositoryBranchesResponse, GetRepositoryBranchesResponses, GetRepositoryByIdData, GetRepositoryByIdErrors, GetRepositoryByIdResponse, GetRepositoryByIdResponses, GetRepositoryByNameData, GetRepositoryByNameErrors, GetRepositoryByNameResponse, GetRepositoryByNameResponses, GetRepositoryPresetByNameData, GetRepositoryPresetByNameErrors, GetRepositoryPresetByNameResponse, GetRepositoryPresetByNameResponses, GetRepositoryPresetLiveData, GetRepositoryPresetLiveErrors, GetRepositoryPresetLiveResponse, GetRepositoryPresetLiveResponses, GetRepositoryTagsData, GetRepositoryTagsErrors, GetRepositoryTagsResponse, GetRepositoryTagsResponses, GetRequest, GetResolvedEnvironmentVariablesData, GetResolvedEnvironmentVariablesErrors, GetResolvedEnvironmentVariablesResponse, GetResolvedEnvironmentVariablesResponses, GetResolvedEnvironmentVariableValueData, GetResolvedEnvironmentVariableValueErrors, GetResolvedEnvironmentVariableValueResponse, GetResolvedEnvironmentVariableValueResponses, GetResponse, GetRestoreCapabilitiesData, GetRestoreCapabilitiesError, GetRestoreCapabilitiesErrors, GetRestoreCapabilitiesResponse, GetRestoreCapabilitiesResponses, GetRestoreRunData, GetRestoreRunError, GetRestoreRunErrors, GetRestoreRunResponse, GetRestoreRunResponses, GetRouteData, GetRouteErrors, GetRouteResponse, GetRouteResponses, GetRunData, GetRunErrors, GetRunResponse, GetRunResponses, GetRunWithLogsData, GetRunWithLogsErrors, GetRunWithLogsResponse, GetRunWithLogsResponses, GetS3CredentialsData, GetS3CredentialsErrors, GetS3CredentialsResponse, GetS3CredentialsResponses, GetS3SourceData, GetS3SourceError, GetS3SourceErrors, GetS3SourceResponse, GetS3SourceResponses, GetSandboxData, GetSandboxErrors, GetSandboxResponse, GetSandboxResponses, GetSandboxStatusData, GetSandboxStatusErrors, GetSandboxStatusResponse, GetSandboxStatusResponses, GetScanByDeploymentData, GetScanByDeploymentError, GetScanByDeploymentErrors, GetScanByDeploymentResponse, GetScanByDeploymentResponses, GetScanData, GetScanError, GetScanErrors, GetScanResponse, GetScanResponses, GetScanVulnerabilitiesData, GetScanVulnerabilitiesError, GetScanVulnerabilitiesErrors, GetScanVulnerabilitiesResponse, GetScanVulnerabilitiesResponses, GetServiceBySlugData, GetServiceBySlugErrors, GetServiceBySlugResponse, GetServiceBySlugResponses, GetServiceData, GetServiceEnvironmentVariableData, GetServiceEnvironmentVariableErrors, GetServiceEnvironmentVariableResponse, GetServiceEnvironmentVariableResponses, GetServiceEnvironmentVariablesData, GetServiceEnvironmentVariablesErrors, GetServiceEnvironmentVariablesResponse, GetServiceEnvironmentVariablesResponses, GetServiceErrors, GetServiceHealthStatusData, GetServiceHealthStatusErrors, GetServiceHealthStatusResponse, GetServiceHealthStatusResponses, GetServicePreviewEnvironmentVariableNamesData, GetServicePreviewEnvironmentVariableNamesErrors, GetServicePreviewEnvironmentVariableNamesResponse, GetServicePreviewEnvironmentVariableNamesResponses, GetServicePreviewEnvironmentVariablesMaskedData, GetServicePreviewEnvironmentVariablesMaskedErrors, GetServicePreviewEnvironmentVariablesMaskedResponse, GetServicePreviewEnvironmentVariablesMaskedResponses, GetServiceResponse, GetServiceResponses, GetServiceRuntimeData, GetServiceRuntimeErrors, GetServiceRuntimeResponse, GetServiceRuntimeResponses, GetServiceStatsData, GetServiceStatsErrors, GetServiceStatsResponse, GetServiceStatsResponses, GetServiceTypeParametersData, GetServiceTypeParametersErrors, GetServiceTypeParametersResponses, GetServiceTypesData, GetServiceTypesErrors, GetServiceTypesResponse, GetServiceTypesResponses, GetSessionDetailsData, GetSessionDetailsErrors, GetSessionDetailsResponse, GetSessionDetailsResponses, GetSessionEventsData, GetSessionEventsErrors, GetSessionEventsResponse, GetSessionEventsResponses, GetSessionLogsData, GetSessionLogsErrors, GetSessionLogsResponse, GetSessionLogsResponses, GetSessionReplayData, GetSessionReplayError, GetSessionReplayErrors, GetSessionReplayEventsData, GetSessionReplayEventsError, GetSessionReplayEventsErrors, GetSessionReplayEventsResponse, GetSessionReplayEventsResponses, GetSessionReplayResponse, GetSessionReplayResponse2, GetSessionReplayResponses, GetSettingsData, GetSettingsErrors, GetSettingsResponse, GetSettingsResponses, GetSkillData, GetSkillErrors, GetSkillResponse, GetSkillResponses, GetSlowQueriesData, GetSlowQueriesErrors, GetSlowQueriesResponse, GetSlowQueriesResponses, GetStaticBundleData, GetStaticBundleErrors, GetStaticBundleResponse, GetStaticBundleResponses, GetStatusOverviewData, GetStatusOverviewErrors, GetStatusOverviewResponse, GetStatusOverviewResponses, GetTagsByRepositoryIdData, GetTagsByRepositoryIdErrors, GetTagsByRepositoryIdResponse, GetTagsByRepositoryIdResponses, GetTeamData, GetTeamErrors, GetTeamResponse, GetTeamResponses, GetTimeBucketStatsData, GetTimeBucketStatsError, GetTimeBucketStatsErrors, GetTimeBucketStatsResponse, GetTimeBucketStatsResponses, GetTodayStatsData, GetTodayStatsError, GetTodayStatsErrors, GetTodayStatsResponse, GetTodayStatsResponses, GetTraceData, GetTraceError, GetTraceErrors, GetTraceResponse, GetTraceResponses, GetUnifiedTraceData, GetUnifiedTraceError, GetUnifiedTraceErrors, GetUnifiedTraceResponse, GetUnifiedTraceResponses, GetUniqueCountsData, GetUniqueCountsErrors, GetUniqueCountsResponse, GetUniqueCountsResponses, GetUniqueEventsData, GetUniqueEventsErrors, GetUniqueEventsQuery, GetUniqueEventsResponse, GetUniqueEventsResponses, GetUpdateCapabilityData, GetUpdateCapabilityErrors, GetUpdateCapabilityResponse, GetUpdateCapabilityResponses, GetUpdateStatusData, GetUpdateStatusErrors, GetUpdateStatusResponse, GetUpdateStatusResponses, GetUptimeHistoryData, GetUptimeHistoryErrors, GetUptimeHistoryResponse, GetUptimeHistoryResponses, GetUsageByProviderData, GetUsageByProviderError, GetUsageByProviderErrors, GetUsageByProviderResponse, GetUsageByProviderResponses, GetUsageRecentData, GetUsageRecentError, GetUsageRecentErrors, GetUsageRecentResponse, GetUsageRecentResponses, GetUsageSummaryData, GetUsageSummaryError, GetUsageSummaryErrors, GetUsageSummaryResponse, GetUsageSummaryResponses, GetUsageTimeseriesData, GetUsageTimeseriesError, GetUsageTimeseriesErrors, GetUsageTimeseriesResponse, GetUsageTimeseriesResponses, GetUsageTopModelsData, GetUsageTopModelsError, GetUsageTopModelsErrors, GetUsageTopModelsResponse, GetUsageTopModelsResponses, GetVisitorByGuidData, GetVisitorByGuidErrors, GetVisitorByGuidResponse, GetVisitorByGuidResponses, GetVisitorByIdData, GetVisitorByIdErrors, GetVisitorByIdResponse, GetVisitorByIdResponses, GetVisitorDetailsData, GetVisitorDetailsErrors, GetVisitorDetailsResponse, GetVisitorDetailsResponses, GetVisitorFacetsData, GetVisitorFacetsErrors, GetVisitorFacetsResponse, GetVisitorFacetsResponses, GetVisitorInfoData, GetVisitorInfoErrors, GetVisitorInfoResponse, GetVisitorInfoResponses, GetVisitorJourneyData, GetVisitorJourneyErrors, GetVisitorJourneyResponse, GetVisitorJourneyResponses, GetVisitorsData, GetVisitorsErrors, GetVisitorSessionsData, GetVisitorSessionsError, GetVisitorSessionsErrors, GetVisitorSessionsQuery, GetVisitorSessionsResponse, GetVisitorSessionsResponse2, GetVisitorSessionsResponses, GetVisitorsResponse, GetVisitorsResponses, GetVisitorStatsData, GetVisitorStatsErrors, GetVisitorStatsResponse, GetVisitorStatsResponses, GetWebhookData, GetWebhookErrors, GetWebhookResponse, GetWebhookResponses, GitPushEvent, GitRefResponse, GitSourcePlan, GlobalConversationResponse, GlobalEventStatsResponse, GlobalMrrResponse, GlobalRecentEventResponse, GlobalRevenueSummaryResponse, GrantProjectAccessData, GrantProjectAccessErrors, GrantProjectAccessResponse, GrantProjectAccessResponses, GroupedPageMetric, GroupedPageMetricsQuery, GroupedPageMetricsResponse, HandleGitProviderOauthCallbackData, HandleGitProviderOauthCallbackErrors, HasAnalyticsEventsData, HasAnalyticsEventsErrors, HasAnalyticsEventsResponse, HasAnalyticsEventsResponse2, HasAnalyticsEventsResponses, HasErrorGroupsData, HasErrorGroupsErrors, HasErrorGroupsResponse, HasErrorGroupsResponse2, HasErrorGroupsResponses, HasEventsQuery, HasEventsResponse, HasMetricsQuery, HasMetricsResponse, HasPerformanceMetricsData, HasPerformanceMetricsError, HasPerformanceMetricsErrors, HasPerformanceMetricsResponse, HasPerformanceMetricsResponses, HealthCheckConfiguration, HealthCheckEntryResponse, HealthResponse, HealthStatus, HealthSummary, HeartbeatApiRequest, HeartbeatResponse, HierarchyLevel, HistogramSummary, HostnameChange, HostnamePreviewResponse, HourlyPageSessions, HourlyVisitsQuery, HttpChallengeDebugResponse, ImportCredentials, ImportExecutionStatus, ImportExternalServiceData, ImportExternalServiceErrors, ImportExternalServiceRequest, ImportExternalServiceResponse, ImportExternalServiceResponses, ImportOutcomeResponse, ImportPlan, ImportRowErrorResponse, ImportSelector, ImportSource, ImportSourceCapabilities, ImportSourceInfo, ImportStatusResponse, IncidentBucket, IncidentBucketedResponse, IncidentResponse, IncidentUpdateResponse, IncrRequest, IncrResponse, IngestLogsByPathData, IngestLogsByPathError, IngestLogsByPathErrors, IngestLogsByPathResponses, IngestLogsData, IngestLogsError, IngestLogsErrors, IngestLogsResponses, IngestMetricsByPathData, IngestMetricsByPathError, IngestMetricsByPathErrors, IngestMetricsByPathResponses, IngestMetricsData, IngestMetricsError, IngestMetricsErrors, IngestMetricsResponses, IngestSentryEnvelopeData, IngestSentryEnvelopeErrors, IngestSentryEnvelopeResponses, IngestSentryEventData, IngestSentryEventErrors, IngestSentryEventResponse, IngestSentryEventResponses, IngestTracesByPathData, IngestTracesByPathError, IngestTracesByPathErrors, IngestTracesByPathResponses, IngestTracesData, IngestTracesError, IngestTracesErrors, IngestTracesResponses, InitAuthResponse, InitSessionReplayData, InitSessionReplayError, InitSessionReplayErrors, InitSessionReplayResponse, InitSessionReplayResponses, Insight, InsightSeverity, InsightsResponse, InsightStatus, InspectDropArchiveData, InspectDropArchiveErrors, InspectDropArchiveResponse, InspectDropArchiveResponses, IntegrationResponse, IpAccessControlQuery, IpAccessControlResponse, JobLogsData, JobLogsErrors, JobLogsResponses, JobStatusData, JobStatusErrors, JobStatusResponse, JobStatusResponse2, JobStatusResponses, JobSummaryResponse, JoinTokenStatusResponse, JourneyEvent, JourneySession, KeysRequest, KeysResponse, KillJobBody, KillJobData, KillJobErrors, KillJobResponse, KillJobResponses, KnownAiAgentsResponse, KvDelData, KvDelErrors, KvDelResponse, KvDelResponses, KvDisableData, KvDisableErrors, KvDisableResponse, KvDisableResponses, KvEnableData, KvEnableErrors, KvEnableResponse, KvEnableResponses, KvExpireData, KvExpireErrors, KvExpireResponse, KvExpireResponses, KvGetData, KvGetErrors, KvGetResponse, KvGetResponses, KvIncrData, KvIncrErrors, KvIncrResponse, KvIncrResponses, KvKeysData, KvKeysErrors, KvKeysResponse, KvKeysResponses, KvSetData, KvSetErrors, KvSetResponse, KvSetResponses, KvStatusData, KvStatusErrors, KvStatusResponse, KvStatusResponse2, KvStatusResponses, KvTtlData, KvTtlErrors, KvTtlResponse, KvTtlResponses, KvUpdateData, KvUpdateErrors, KvUpdateResponse, KvUpdateResponses, LatestRunForSourceData, LatestRunForSourceErrors, LatestRunForSourceResponse, LatestRunForSourceResponses, LemonSqueezyConfig, LetsEncryptSettings, LineContext, LinkCustomDomainToCertificateData, LinkCustomDomainToCertificateErrors, LinkCustomDomainToCertificateResponse, LinkCustomDomainToCertificateResponses, LinkServiceRequest, LinkServiceToProjectData, LinkServiceToProjectErrors, LinkServiceToProjectResponse, LinkServiceToProjectResponses, ListAgentRunsData, ListAgentRunsErrors, ListAgentRunsResponse, ListAgentRunsResponses, ListAgentsData, ListAgentsErrors, ListAgentsResponse, ListAgentsResponse2, ListAgentsResponses, ListAiProvidersData, ListAiProvidersErrors, ListAiProvidersResponse, ListAiProvidersResponses, ListAlertRulesData, ListAlertRulesErrors, ListAlertRulesResponse, ListAlertRulesResponses, ListAlertsData, ListAlertsError, ListAlertsErrors, ListAlertsResponse, ListAlertsResponses, ListAllConversationsData, ListAllConversationsErrors, ListAllConversationsResponse, ListAllConversationsResponses, ListAllRunsData, ListAllRunsErrors, ListAllRunsResponse, ListAllRunsResponses, ListApiKeysData, ListApiKeysErrors, ListApiKeysQuery, ListApiKeysResponse, ListApiKeysResponses, ListAuditLogsData, ListAuditLogsErrors, ListAuditLogsQuery, ListAuditLogsResponse, ListAuditLogsResponses, ListAvailableContainersData, ListAvailableContainersErrors, ListAvailableContainersResponse, ListAvailableContainersResponses, ListBackupAlertsData, ListBackupAlertsError, ListBackupAlertsErrors, ListBackupAlertsResponse, ListBackupAlertsResponses, ListBackupChildrenData, ListBackupChildrenError, ListBackupChildrenErrors, ListBackupChildrenResponse, ListBackupChildrenResponses, ListBackupSchedulesData, ListBackupSchedulesError, ListBackupSchedulesErrors, ListBackupSchedulesResponse, ListBackupSchedulesResponses, ListBackupsForScheduleData, ListBackupsForScheduleErrors, ListBackupsForScheduleResponse, ListBackupsForScheduleResponses, ListBlobsQuery, ListBlobsResponse, ListCommitsByRepositoryIdData, ListCommitsByRepositoryIdErrors, ListCommitsByRepositoryIdResponse, ListCommitsByRepositoryIdResponses, ListConnectionsData, ListConnectionsErrors, ListConnectionsResponse, ListConnectionsResponses, ListContainersAtPathData, ListContainersAtPathErrors, ListContainersAtPathResponse, ListContainersAtPathResponses, ListContainersData, ListContainersErrors, ListContainersResponse, ListContainersResponses, ListConversationsData, ListConversationsErrors, ListConversationsResponse, ListConversationsResponses, ListCustomDomainsForProjectData, ListCustomDomainsForProjectErrors, ListCustomDomainsForProjectResponse, ListCustomDomainsForProjectResponses, ListCustomDomainsResponse, ListDashboardsData, ListDashboardsError, ListDashboardsErrors, ListDashboardsResponse, ListDashboardsResponses, ListDeliveriesData, ListDeliveriesErrors, ListDeliveriesResponse, ListDeliveriesResponses, ListDeploymentContainerLogsData, ListDeploymentContainerLogsErrors, ListDeploymentContainerLogsResponse, ListDeploymentContainerLogsResponses, ListDeploymentTokensData, ListDeploymentTokensErrors, ListDeploymentTokensQuery, ListDeploymentTokensResponse, ListDeploymentTokensResponses, ListDnsProvidersData, ListDnsProvidersErrors, ListDnsProvidersResponse, ListDnsProvidersResponses, ListDomainsData, ListDomainsErrors, ListDomainsResponse, ListDomainsResponse2, ListDomainsResponses, ListDsnsData, ListDsnsErrors, ListDsnsResponse, ListDsnsResponses, ListEmailDomainsData, ListEmailDomainsErrors, ListEmailDomainsResponse, ListEmailDomainsResponses, ListEmailProvidersData, ListEmailProvidersErrors, ListEmailProvidersResponse, ListEmailProvidersResponses, ListEmailsData, ListEmailsErrors, ListEmailsResponse, ListEmailsResponses, ListEnrollmentTokensData, ListEnrollmentTokensErrors, ListEnrollmentTokensResponse, ListEnrollmentTokensResponses, ListEntitiesData, ListEntitiesErrors, ListEntitiesQuery, ListEntitiesResponse, ListEntitiesResponses, ListErrorEventsData, ListErrorEventsErrors, ListErrorEventsQuery, ListErrorEventsResponse, ListErrorEventsResponses, ListErrorGroupsData, ListErrorGroupsErrors, ListErrorGroupsQuery, ListErrorGroupsResponse, ListErrorGroupsResponses, ListEventsData, ListEventsResponse, ListEventsResponses, ListEventTypesData, ListEventTypesResponse, ListEventTypesResponses, ListExternalImagesData, ListExternalImagesErrors, ListExternalImagesResponse, ListExternalImagesResponses, ListExternalPluginsData, ListExternalPluginsErrors, ListExternalPluginsResponse, ListExternalPluginsResponses, ListExternalServiceBackupsData, ListExternalServiceBackupsError, ListExternalServiceBackupsErrors, ListExternalServiceBackupsResponse, ListExternalServiceBackupsResponses, ListFlagsData, ListFlagsErrors, ListFlagsResponse, ListFlagsResponses, ListFunnelsData, ListFunnelsErrors, ListFunnelsResponse, ListFunnelsResponses, ListGitProvidersData, ListGitProvidersErrors, ListGitProvidersResponse, ListGitProvidersResponses, ListGlobalMcpsData, ListGlobalMcpsErrors, ListGlobalMcpsResponse, ListGlobalMcpsResponses, ListGlobalSkillsData, ListGlobalSkillsErrors, ListGlobalSkillsResponse, ListGlobalSkillsResponses, ListIncidentsData, ListIncidentsErrors, ListIncidentsResponses, ListInsightsData, ListInsightsError, ListInsightsErrors, ListInsightsResponse, ListInsightsResponses, ListIpAccessControlData, ListIpAccessControlError, ListIpAccessControlErrors, ListIpAccessControlResponse, ListIpAccessControlResponses, ListJobsData, ListJobsErrors, ListJobsResponse, ListJobsResponse2, ListJobsResponses, ListKnownAiAgentsData, ListKnownAiAgentsError, ListKnownAiAgentsErrors, ListKnownAiAgentsResponse, ListKnownAiAgentsResponses, ListManagedDomainsData, ListManagedDomainsErrors, ListManagedDomainsResponse, ListManagedDomainsResponses, ListMcpsData, ListMcpsErrors, ListMcpsResponse, ListMcpsResponse2, ListMcpsResponses, ListMetricLabelKeysData, ListMetricLabelKeysError, ListMetricLabelKeysErrors, ListMetricLabelKeysResponse, ListMetricLabelKeysResponses, ListMetricLabelValuesData, ListMetricLabelValuesError, ListMetricLabelValuesErrors, ListMetricLabelValuesResponse, ListMetricLabelValuesResponses, ListMetricNamesData, ListMetricNamesError, ListMetricNamesErrors, ListMetricNamesResponse, ListMetricNamesResponses, ListModelsData, ListModelsError, ListModelsErrors, ListModelsResponse, ListModelsResponses, ListMonitorsData, ListMonitorsErrors, ListMonitorsResponse, ListMonitorsResponses, ListNotificationProvidersData, ListNotificationProvidersErrors, ListNotificationProvidersResponse, ListNotificationProvidersResponses, ListOidcProvidersData, ListOidcProvidersResponse, ListOidcProvidersResponses, ListOidcProviderUsersData, ListOidcProviderUsersErrors, ListOidcProviderUsersResponse, ListOidcProviderUsersResponses, ListOidcRoleMappingsData, ListOidcRoleMappingsResponse, ListOidcRoleMappingsResponses, ListOnDemandCertsData, ListOnDemandCertsErrors, ListOnDemandCertsResponse, ListOnDemandCertsResponse2, ListOnDemandCertsResponses, ListOrdersData, ListOrdersErrors, ListOrdersResponse, ListOrdersResponse2, ListOrdersResponses, ListPeersData, ListPeersErrors, ListPeersResponse, ListPeersResponses, ListPendingActionsData, ListPendingActionsErrors, ListPendingActionsResponse, ListPendingActionsResponses, ListPgUpgradesData, ListPgUpgradesErrors, ListPgUpgradesResponse, ListPgUpgradesResponses, ListPresetsData, ListPresetsErrors, ListPresetsResponse, ListPresetsResponse2, ListPresetsResponses, ListProjectAccessData, ListProjectAccessErrors, ListProjectAccessResponse, ListProjectAccessResponses, ListProjectAlarmsData, ListProjectAlarmsErrors, ListProjectAlarmsResponse, ListProjectAlarmsResponses, ListProjectScansData, ListProjectScansError, ListProjectScansErrors, ListProjectScansResponse, ListProjectScansResponses, ListProjectSecretsData, ListProjectSecretsErrors, ListProjectSecretsResponse, ListProjectSecretsResponses, ListProjectServicesData, ListProjectServicesErrors, ListProjectServicesResponse, ListProjectServicesResponses, ListProjectTemplatesData, ListProjectTemplatesErrors, ListProjectTemplatesResponse, ListProjectTemplatesResponses, ListProjectTemplateTagsData, ListProjectTemplateTagsErrors, ListProjectTemplateTagsResponse, ListProjectTemplateTagsResponses, ListProviderKeysData, ListProviderKeysError, ListProviderKeysErrors, ListProviderKeysResponse, ListProviderKeysResponses, ListProviderZonesData, ListProviderZonesErrors, ListProviderZonesResponse, ListProviderZonesResponses, ListPublicProvidersData, ListPublicProvidersResponse, ListPublicProvidersResponses, ListReleaseFilesData, ListReleaseFilesErrors, ListReleaseFilesResponse, ListReleaseFilesResponses, ListReleasesData, ListReleasesErrors, ListReleasesResponse, ListReleasesResponses, ListRemoteExternalImagesData, ListRemoteExternalImagesErrors, ListRemoteExternalImagesResponse, ListRemoteExternalImagesResponses, ListRepositoriesByConnectionData, ListRepositoriesByConnectionErrors, ListRepositoriesByConnectionResponse, ListRepositoriesByConnectionResponses, ListRepositoriesByProviderData, ListRepositoriesByProviderErrors, ListRepositoriesByProviderResponse, ListRepositoriesByProviderResponses, ListRestoreRunsForServiceData, ListRestoreRunsForServiceResponse, ListRestoreRunsForServiceResponses, ListRootContainersData, ListRootContainersErrors, ListRootContainersResponse, ListRootContainersResponses, ListRoutesData, ListRoutesErrors, ListRoutesResponse, ListRoutesResponses, ListRunsResponse, ListS3SourcesData, ListS3SourcesError, ListS3SourcesErrors, ListS3SourcesResponse, ListS3SourcesResponses, ListSandboxesData, ListSandboxesResponse, ListSandboxesResponse2, ListSandboxesResponses, ListScansQuery, ListScheduleRunJobsData, ListScheduleRunJobsError, ListScheduleRunJobsErrors, ListScheduleRunJobsResponse, ListScheduleRunJobsResponses, ListScheduleRunsData, ListScheduleRunsError, ListScheduleRunsErrors, ListScheduleRunsResponse, ListScheduleRunsResponses, ListScheduleServicesData, ListScheduleServicesError, ListScheduleServicesErrors, ListScheduleServicesResponse, ListScheduleServicesResponses, ListSecretsData, ListSecretsErrors, ListSecretsResponse, ListSecretsResponse2, ListSecretsResponses, ListServiceHealthStatusesData, ListServiceHealthStatusesErrors, ListServiceHealthStatusesResponse, ListServiceHealthStatusesResponses, ListServiceProjectsData, ListServiceProjectsErrors, ListServiceProjectsResponse, ListServiceProjectsResponses, ListServiceSchedulesData, ListServiceSchedulesError, ListServiceSchedulesErrors, ListServiceSchedulesResponse, ListServiceSchedulesResponses, ListServicesData, ListServicesErrors, ListServicesResponse, ListServicesResponses, ListSkillsData, ListSkillsErrors, ListSkillsResponse, ListSkillsResponse2, ListSkillsResponses, ListSourceBackupsData, ListSourceBackupsError, ListSourceBackupsErrors, ListSourceBackupsResponse, ListSourceBackupsResponses, ListSourceFilesData, ListSourceFilesErrors, ListSourceFilesResponse, ListSourceFilesResponses, ListSourceMapsData, ListSourceMapsErrors, ListSourceMapsResponse, ListSourceMapsResponses, ListSourcesData, ListSourcesErrors, ListSourcesResponse, ListSourcesResponses, ListStaticBundlesData, ListStaticBundlesErrors, ListStaticBundlesResponse, ListStaticBundlesResponses, ListSyncedRepositoriesData, ListSyncedRepositoriesErrors, ListSyncedRepositoriesResponse, ListSyncedRepositoriesResponses, ListTagsResponse, ListTeamMembersData, ListTeamMembersErrors, ListTeamMembersResponse, ListTeamMembersResponses, ListTeamProjectsData, ListTeamProjectsErrors, ListTeamProjectsResponse, ListTeamProjectsResponses, ListTeamsData, ListTeamsErrors, ListTeamsResponse, ListTeamsResponses, ListTemplatesQuery, ListTemplatesResponse, ListUsersData, ListUsersErrors, ListUsersResponse, ListUsersResponses, ListVulnerabilitiesQuery, ListWebhooksData, ListWebhooksErrors, ListWebhooksResponse, ListWebhooksResponses, LiveVisitorInfo, LiveVisitorsListResponse, LocationCount, LocationGranularity, LocationInfo, LoginData, LoginErrors, LoginRequest, LoginResponse, LoginResponses, LogLevel, LogoutData, LogoutErrors, LogoutResponses, LogRecord, LogSearchLine, LogSeverity, LogSource, LogsQuery, LogsResponse, LogStream, LookupDnsARecordsData, LookupDnsARecordsError, LookupDnsARecordsErrors, LookupDnsARecordsResponse, LookupDnsARecordsResponses, ManagedDomainResponse, ManualAction, ManualActionTiming, McpDefinitionResponse, MessageContent, MessagePart, MessageResponse, MeteredMode, MetricAggregation, MetricBucket, MetricDataPoint, MetricsOverTimeResponse, MetricsQuery, MetricsRangeQuery, MetricsStatusResponse, MetricsStoreKind, MetricsSummaryResponse, MetricType, MfaRequiredResponse, MfaSetupResponse, MfaVerificationRequest, MigrationStep, MigrationSummary, MintEnrollmentTokenData, MintEnrollmentTokenErrors, MintEnrollmentTokenRequest, MintEnrollmentTokenResponse, MintEnrollmentTokenResponse2, MintEnrollmentTokenResponses, MiscResult, MkdirBody, MkdirData, MkdirErrors, MkdirResponse, MkdirResponses, ModelInfo, ModelListResponse, ModelPricing, ModelUsage, MonitoringSettings, MonitoringSettingsMasked, MonitorResponse, MonitorStatus, MrrBucketResponse, MultiNodeSettings, MultiNodeSettingsMasked, MxResult, NavEntry, NavSection, NetworkConfiguration, NetworkMode, NixpacksPresetConfig, NixpacksProvider, NodeContainerListResponse, NodeContainerResponse, NodeCostInfo, NodeHeartbeatData, NodeHeartbeatErrors, NodeHeartbeatResponse, NodeHeartbeatResponses, NodeInfoResponse, NodeListResponse, NodeMetricsGetRangeData, NodeMetricsGetRangeErrors, NodeMetricsGetRangeResponse, NodeMetricsGetRangeResponses, NotificationPreferencesResponse, NotificationProviderResponse, ObservabilityCompressionSettings, ObservabilityEvent, ObservabilityFullEventData, ObservabilityFullEventError, ObservabilityFullEventErrors, ObservabilityFullEventResponse, ObservabilityFullEventResponses, ObservabilityListEventsData, ObservabilityListEventsError, ObservabilityListEventsErrors, ObservabilityListEventsResponse, ObservabilityListEventsResponses, ObservabilityRetentionSettings, OidcCallbackData, OidcProviderResponse, OidcProvidersListResponse, OidcProviderSummary, OidcProviderUserResponse, OidcRoleMappingResponse, OidcTestConnectionResponse, OnDemandCertAttemptResponse, OnDemandCertRow, OnDemandTlsSettings, OpenAiError, OpenAiErrorResponse, OperatingSystemCount, OperationResultResponse, OperationResultsResponse, OtelDashboardResponse, OtelDashboardsResponse, OtelMetricAlertRuleResponse, OtelMetricAlertsResponse, OtelMetricLabelKeysResponse, OtelMetricLabelValuesResponse, OtelMetricNamesResponse, OtelMetricsResponse, OutlierAlgorithm, OutlierParams, OverprovisioningAssessment, OverprovisioningVerdict, PageActivityBucket, PageCountryStats, PageFlowEntry, PageFlowQuery, PageFlowResponse, PageHourlySessionsQuery, PageHourlySessionsResponse, PagePathDetailQuery, PagePathDetailResponse, PagePathInfo, PagePathSparkline, PagePathSparklinePoint, PagePathsQuery, PagePathsResponse, PagePathsSparklineQuery, PagePathsSparklineResponse, PagePathVisitorsQuery, PagePathVisitorsResponse, PageReferrerStats, PagesComparisonResponse, PageSessionComparison, PageSessionStats, PageSessionStatsQuery, PageTransition, PageVisit, PageVisitorSession, PaginatedEmailsResponse, PaginatedEntitiesResponse, PaginatedErrorEventsResponse, PaginatedErrorGroupsResponse, PaginatedEventsResponse, PaginatedExternalImagesResponse, PaginatedProjectList, PaginatedStaticBundlesResponse, Pagination, PaginationMeta, PaginationParams, PasswordProtectionConfig, PatchAdminGateData, PatchAdminGateErrors, PatchAdminGateResponse, PatchAdminGateResponses, PatchPreviewGatewaySettingsData, PatchPreviewGatewaySettingsResponse, PatchPreviewGatewaySettingsResponses, PatchSettingsRequest, PathVisitors, PathVisitorsAnalyticsQuery, PathVisitorsResponse, PauseDeploymentData, PauseDeploymentErrors, PauseDeploymentResponse, PauseDeploymentResponses, PauseSandboxData, PauseSandboxErrors, PauseSandboxResponse, PauseSandboxResponses, PeerEntry, PeerListResponse, PendingActionResponse, PerformanceMetricsQuery, PerformanceMetricsResponse, PermissionInfo, PgUpgradeLogResponse, PgUpgradeResponse, PipelineStats, PipelineStatsResponse, PlanComplexity, PlanMetadata, PlanRestoreData, PlanRestoreError, PlanRestoreErrors, PlanRestoreResponse, PlanRestoreResponses, PlanSourceBackup, PlanTarget, PlatformInfo, PluginManifest, PortMapping, PostDnsAckData, PostDnsAckErrors, PostDnsAckResponse, PostDnsAckResponses, PostgresWalHealth, PresetConfigSchema, PresetInfo, PresetResponse, PreviewAlertData, PreviewAlertError, PreviewAlertErrors, PreviewAlertResponse, PreviewAlertResponses, PreviewFunnelMetricsData, PreviewFunnelMetricsErrors, PreviewFunnelMetricsResponse, PreviewFunnelMetricsResponses, PreviewGatewaySettings, PreviewGatewaySettingsMasked, PreviewGatewaySettingsResponse, PreviewHostnameModeData, PreviewHostnameModeErrors, PreviewHostnameModeResponse, PreviewHostnameModeResponses, PreviewShareLinkBody, PreviewShareLinkResponse, PricingResponse, ProblemDetails, ProjectAccessResponse, ProjectConfiguration, ProjectDashboardAnalytics, ProjectDsnResponse, ProjectHealthSummary, ProjectInfo, ProjectMonitorHealth, ProjectPresetResponse, ProjectQuery, ProjectRef, ProjectResponse, ProjectSecretEnvironmentInfo, ProjectSecretResponse, ProjectServiceInfo, ProjectsHealthResponse, ProjectsMonitorHealthResponse, ProjectStatisticsResponse, ProjectStatsBreakdown, ProjectType, ProjectUsageInfoResponse, PromoteClusterMemberData, PromoteClusterMemberErrors, PromoteClusterMemberResponses, PromoteDeploymentData, PromoteDeploymentErrors, PromoteDeploymentRequest, PromoteDeploymentResponse, PromoteDeploymentResponses, PropertyBreakdownItem, PropertyBreakdownQuery, PropertyBreakdownResponse, PropertyColumn, PropertyTimelineItem, PropertyTimelineQuery, PropertyTimelineResponse, Protocol, ProviderCatalogDto, ProviderCatalogResponse, ProviderConfig, ProviderConfigMasked, ProviderDeletionCheckResponse, ProviderDescriptor, ProviderKeyResponse, ProviderMetadata, ProviderResponse, ProviderUsage, ProvisionDomainData, ProvisionDomainErrors, ProvisionDomainResponse, ProvisionDomainResponses, ProvisionResponse, ProxyLogResponse, ProxyLogsPaginatedResponse, PublicHostnameStrategy, PublicPresetResponse, PublicRepositoryInfo, PurgeLogsRequest, PurgeProjectLogsData, PurgeProjectLogsError, PurgeProjectLogsErrors, PurgeProjectLogsResponses, PushedExternalImageResponse, PushExternalImageData, PushExternalImageErrors, PushExternalImageResponse, PushExternalImageResponses, PushImageRequest, QueryDataData, QueryDataErrors, QueryDataRequest, QueryDataResponse, QueryDataResponse2, QueryDataResponses, QueryGenaiTracesData, QueryGenaiTracesError, QueryGenaiTracesErrors, QueryGenaiTracesResponse, QueryGenaiTracesResponses, QueryLogsData, QueryLogsError, QueryLogsErrors, QueryLogsResponse, QueryLogsResponses, QueryMetricsData, QueryMetricsError, QueryMetricsErrors, QueryMetricsResponse, QueryMetricsResponses, QueryTracesData, QueryTracesError, QueryTracesErrors, QueryTracesResponse, QueryTracesResponses, QueryTraceSummariesData, QueryTraceSummariesError, QueryTraceSummariesErrors, QueryTraceSummariesResponse, QueryTraceSummariesResponses, QuotaResponse, RateLimitConfig, RateLimitSettings, ReachabilityStatus, ReadFileData, ReadFileErrors, ReadFileResponse, ReadFileResponse2, ReadFileResponses, ReAnalyzeData, ReAnalyzeErrors, ReAnalyzeResponses, RebuildSandboxImageData, RebuildSandboxImageErrors, RebuildSandboxImageResponses, RecentActivityQuery, RecentActivityResponse, RecentEventResponse, RecentQueryParams, RecordConsoleEventData, RecordConsoleEventErrors, RecordConsoleEventResponses, RecordEventMetricsData, RecordEventMetricsErrors, RecordEventMetricsResponse, RecordEventMetricsResponses, RecordExposureRequest, RecordExposureResponse, RecordFlagExposureData, RecordFlagExposureErrors, RecordFlagExposureResponse, RecordFlagExposureResponses, RecordListResponse, RecordSpeedMetricsData, RecordSpeedMetricsError, RecordSpeedMetricsErrors, RecordSpeedMetricsResponse, RecordSpeedMetricsResponses, RecoveryTarget, ReferrerCount, ReferrersAnalyticsQuery, RefreshRouteTableData, RefreshRouteTableErrors, RefreshRouteTableResponse, RefreshRouteTableResponses, RegenerateDsnData, RegenerateDsnErrors, RegenerateDsnRequest, RegenerateDsnResponse, RegenerateDsnResponses, RegisterExternalImageData, RegisterExternalImageErrors, RegisterExternalImageResponse, RegisterExternalImageResponses, RegisterImageRequest, RegisterNodeApiRequest, RegisterNodeData, RegisterNodeErrors, RegisterNodeResponse, RegisterNodeResponse2, RegisterNodeResponses, RegisterRequest, ReinstallGitlabWebhookData, ReinstallGitlabWebhookErrors, ReinstallGitlabWebhookResponse, ReinstallGitlabWebhookResponses, ReinstallWebhookResponse, RejectPendingActionData, RejectPendingActionErrors, RejectPendingActionResponse, RejectPendingActionResponses, ReleaseListResponse, ReloadPluginsData, ReloadPluginsErrors, ReloadPluginsResponse, ReloadPluginsResponses, ReloadResponse, RemoteDeploymentResponse, RemoveClusterMemberData, RemoveClusterMemberErrors, RemoveClusterMemberResponse, RemoveClusterMemberResponses, RemoveManagedDomainData, RemoveManagedDomainErrors, RemoveManagedDomainResponse, RemoveManagedDomainResponses, RemoveNodeResponse, RemoveRoleData, RemoveRoleErrors, RemoveRoleResponse, RemoveRoleResponses, RemoveTeamMemberData, RemoveTeamMemberErrors, RemoveTeamMemberResponse, RemoveTeamMemberResponses, RenameConversationData, RenameConversationErrors, RenameConversationRequest, RenameConversationResponse, RenameConversationResponses, RenewDomainData, RenewDomainErrors, RenewDomainResponse, RenewDomainResponses, RepositoryListQuery, RepositoryListResponse, RepositoryPresetResponse, RepositoryResponse, RepositorySyncStartedResponse, RequestPasswordResetData, RequestPasswordResetErrors, RequestPasswordResetResponse, RequestPasswordResetResponses, RequestRow, RequiredPasswordChangeRequest, RequiredPasswordChangeResponse, ResetPasswordData, ResetPasswordErrors, ResetPasswordRequest, ResetPasswordResponse, ResetPasswordResponses, ResetPgStatStatementsRequest, ResetPgStatStatementsResponse, ResizeSandboxBody, ResizeSandboxData, ResizeSandboxErrors, ResizeSandboxResponse, ResizeSandboxResponses, ResolveAlarmData, ResolveAlarmErrors, ResolveAlarmResponses, ResolvedEnvVarResponse, ResolvedEnvVarSource, ResourceCounts, ResourceFootprint, ResourceInfo, ResourceLimitApplyResult, ResourceLimits, ResourceLimitsResponse, ResourceLimitsUpdateResponse, ResourcesBody, RestartContainerData, RestartContainerErrors, RestartContainerResponse, RestartContainerResponses, RestartPreviewGatewayData, RestartPreviewGatewayResponse, RestartPreviewGatewayResponses, RestartSandboxData, RestartSandboxErrors, RestartSandboxResponse, RestartSandboxResponses, RestoreCapabilities, RestoreCapabilitiesResponse, RestoreFlagData, RestoreFlagErrors, RestoreFlagResponse, RestoreFlagResponses, RestorePlan, RestoreRequestMode, RestoreRunView, RestoreUserData, RestoreUserErrors, RestoreUserResponse, RestoreUserResponses, ResumeDeploymentData, ResumeDeploymentErrors, ResumeDeploymentResponse, ResumeDeploymentResponses, ResumeSandboxData, ResumeSandboxErrors, ResumeSandboxResponse, ResumeSandboxResponses, RetentionCleanupFailure, RetentionCleanupReport, RetryClusterData, RetryClusterErrors, RetryClusterRequest, RetryClusterResponse, RetryClusterResponses, RetryDeliveryData, RetryDeliveryErrors, RetryDeliveryResponse, RetryDeliveryResponses, RetryPgUpgradeData, RetryPgUpgradeErrors, RetryPgUpgradeResponse, RetryPgUpgradeResponses, RetryRunData, RetryRunErrors, RetryRunResponse, RetryRunResponses, RevealGlobalMcpConfigData, RevealGlobalMcpConfigErrors, RevealGlobalMcpConfigResponse, RevealGlobalMcpConfigResponses, RevealMcpConfigData, RevealMcpConfigErrors, RevealMcpConfigResponse, RevealMcpConfigResponses, RevealNotificationProviderConfigData, RevealNotificationProviderConfigErrors, RevealNotificationProviderConfigResponse, RevealNotificationProviderConfigResponses, RevealServiceParameterData, RevealServiceParameterErrors, RevealServiceParameterResponse, RevealServiceParameterResponses, RevenueCreateIntegrationData, RevenueCreateIntegrationErrors, RevenueCreateIntegrationResponse, RevenueCreateIntegrationResponses, RevenueDeleteIntegrationData, RevenueDeleteIntegrationResponse, RevenueDeleteIntegrationResponses, RevenueGlobalEventsData, RevenueGlobalEventsResponse, RevenueGlobalEventsResponses, RevenueImportInvoicesCsvData, RevenueImportInvoicesCsvErrors, RevenueImportInvoicesCsvResponse, RevenueImportInvoicesCsvResponses, RevenueImportSubscriptionsCsvData, RevenueImportSubscriptionsCsvErrors, RevenueImportSubscriptionsCsvResponse, RevenueImportSubscriptionsCsvResponses, RevenueListIntegrationsData, RevenueListIntegrationsResponse, RevenueListIntegrationsResponses, RevenueListProvidersData, RevenueListProvidersResponse, RevenueListProvidersResponses, RevenueMetricsCustomersData, RevenueMetricsCustomersResponse, RevenueMetricsCustomersResponses, RevenueMetricsGlobalMrrData, RevenueMetricsGlobalMrrResponse, RevenueMetricsGlobalMrrResponses, RevenueMetricsGlobalSummaryData, RevenueMetricsGlobalSummaryResponse, RevenueMetricsGlobalSummaryResponses, RevenueMetricsMrrData, RevenueMetricsMrrResponse, RevenueMetricsMrrResponses, RevenueMetricsSummaryData, RevenueMetricsSummaryResponse, RevenueMetricsSummaryResponses, RevenueRecentEventsData, RevenueRecentEventsResponse, RevenueRecentEventsResponses, RevenueRotateTokenData, RevenueRotateTokenResponse, RevenueRotateTokenResponses, RevenueRow, RevenueUpdateConfigData, RevenueUpdateConfigErrors, RevenueUpdateConfigResponse, RevenueUpdateConfigResponses, RevenueUpdateSecretData, RevenueUpdateSecretErrors, RevenueUpdateSecretResponse, RevenueUpdateSecretResponses, RevokeDsnData, RevokeDsnErrors, RevokeDsnResponse, RevokeDsnResponses, RevokeEnrollmentTokenData, RevokeEnrollmentTokenErrors, RevokeEnrollmentTokenResponse, RevokeEnrollmentTokenResponses, RevokeJoinTokenData, RevokeJoinTokenErrors, RevokeJoinTokenResponse, RevokeJoinTokenResponses, RevokeProjectAccessData, RevokeProjectAccessErrors, RevokeProjectAccessResponse, RevokeProjectAccessResponses, RiskLevel, RoleInfo, RollbackPgUpgradeData, RollbackPgUpgradeErrors, RollbackPgUpgradeResponse, RollbackPgUpgradeResponses, RollbackToDeploymentData, RollbackToDeploymentErrors, RollbackToDeploymentResponse, RollbackToDeploymentResponses, RootfsCacheEntry, RootfsGcData, RootfsGcReport, RootfsGcResponses, RootfsReport, RootfsReportData, RootfsReportResponses, RootfsVmEntry, RotateApiKeyData, RotateApiKeyErrors, RotateApiKeyResponse, RotateApiKeyResponses, RotateDeploymentTokenData, RotateDeploymentTokenErrors, RotateDeploymentTokenResponse, RotateDeploymentTokenResponses, RouteRefreshResponse, RouteResponse, RouteRole, RouteUser, RouteUserWithRoles, RunBackupForSourceData, RunBackupForSourceError, RunBackupForSourceErrors, RunBackupForSourceResponse, RunBackupForSourceResponses, RunBackupRequest, RunConnectionHealthCheckData, RunConnectionHealthCheckErrors, RunConnectionHealthCheckResponse, RunConnectionHealthCheckResponses, RunExternalServiceBackupData, RunExternalServiceBackupError, RunExternalServiceBackupErrors, RunExternalServiceBackupRequest, RunExternalServiceBackupResponse, RunExternalServiceBackupResponses, RunScheduleNowData, RunScheduleNowError, RunScheduleNowErrors, RunScheduleNowResponse, RunScheduleNowResponses, S3ConnectionTestResponse, S3CredentialsResponse, S3SourceResponse, S3SourceResponseWritable, SandboxCreatePreviewLinkData, SandboxCreatePreviewLinkErrors, SandboxCreatePreviewLinkResponse, SandboxCreatePreviewLinkResponses, SandboxDomainResponse, SandboxEvent, SandboxEventsResponse, SandboxInner, SandboxResponse, SandboxRoute, SandboxStatusResponse, SaveAgentTokenData, SaveAgentTokenErrors, SaveAgentTokenRequest, SaveAgentTokenResponse, SaveAgentTokenResponse2, SaveAgentTokenResponses, SaveAiProviderCredentialData, SaveAiProviderCredentialErrors, SaveAiProviderCredentialResponse, SaveAiProviderCredentialResponses, SaveCredentialRequest, SaveCredentialResponse, ScalewayCredentialsRequest, ScanResponse, ScheduleRunEntry, ScheduleRunJobEntry, ScheduleRunListResponse, ScheduleRunResponse, ScheduleRunSummary, ScheduleRunSummaryList, ScreenshotSettings, SearchLogsData, SearchLogsError, SearchLogsErrors, SearchLogsRequest, SearchLogsResponse, SearchLogsResponse2, SearchLogsResponses, SearchMode, Seasonality, SecretResponse, SecurityConfig, SecurityHeadersConfig, SecurityHeadersSettings, SelfUpdateAttempt, SelfUpdateBlocker, SelfUpdatePhase, SelfUpdateSettings, SelfUpdateStatus, SendEmailData, SendEmailErrors, SendEmailRequestBody, SendEmailResponse, SendEmailResponseBody, SendEmailResponses, SendMessageData, SendMessageErrors, SendMessageRequest, SendMessageResponses, SensitiveConfigValueResponse, SensitiveMcpConfigValueResponse, SensitiveValueResponse, SentryChunkUploadResponse, SentryCreateReleaseRequest, SentryEventRequest, SentryEventResponse, SentryReleaseFileResponse, SentryReleaseProjectRef, SentryReleaseResponse, SeriesStateEntry, ServiceAccessInfo, ServiceAction, ServiceAlertRuleResponse, ServiceBackupEntryResponse, ServiceBackupListResponse, ServiceCreateAlertRuleRequest, ServiceHealthResponse, ServiceHealthStatusBatchResponse, ServiceHealthStatusEntryResponse, ServiceMemberInfo, ServiceParameter, ServicePlan, ServiceResourceLimits, ServiceRuntimeReport, ServiceStatsReport, ServiceTypeInfo, ServiceTypeRoute, ServiceUpdateAlertRuleRequest, SesCredentialsRequest, SessionDetails, SessionDetailsQuery, SessionEvent, SessionEventDto, SessionEventsQuery, SessionEventsResponse, SessionLogsQuery, SessionLogsResponse, SessionReplayEventsRequest, SessionReplayInfoDto, SessionReplayInitRequest, SessionReplayInitResponse, SessionReplayWithEventsDto, SessionReplayWithVisitorDto, SessionRequestLog, SessionSummary, SetDefaultS3SourceData, SetDefaultS3SourceError, SetDefaultS3SourceErrors, SetDefaultS3SourceResponse, SetDefaultS3SourceResponses, SetFlagEnvironmentData, SetFlagEnvironmentErrors, SetFlagEnvironmentRequest, SetFlagEnvironmentResponse, SetFlagEnvironmentResponses, SetPreviewPasswordBody, SetPreviewPasswordData, SetPreviewPasswordErrors, SetPreviewPasswordResponse, SetPreviewPasswordResponse2, SetPreviewPasswordResponses, SetRequest, SetResponse, SettingsUpdateResponse, SetupDnsChallengeData, SetupDnsChallengeErrors, SetupDnsChallengeRequest, SetupDnsChallengeResponse, SetupDnsChallengeResponse2, SetupDnsChallengeResponses, SetupDnsData, SetupDnsErrors, SetupDnsRequest, SetupDnsResponse, SetupDnsResponse2, SetupDnsResponses, SetupEmailTrackingData, SetupEmailTrackingErrors, SetupEmailTrackingResponse, SetupEmailTrackingResponses, SetupMfaData, SetupMfaErrors, SetupMfaResponse, SetupMfaResponses, SiblingRef, SkillDefinitionResponse, SlackConfig, SleepEnvironmentData, SleepEnvironmentErrors, SleepEnvironmentResponse, SleepEnvironmentResponses, SlowQueriesResponse, SlowQueryRow, SmartFilter, SmokeTestAgentData, SmokeTestAgentErrors, SmokeTestAgentResponse, SmokeTestAgentResponses, SmokeTestResponse, SmtpCredentialsRequest, SmtpEncryptionRoute, SmtpResult, SourceArchiveUpload, SourceBackupEntry, SourceBackupIndexResponse, SourceBody, SourceFileListResponse, SourceFileResponse, SourceMapListResponse, SourceMapResponse, SourceSandboxData, SourceSandboxErrors, SourceSandboxResponse, SourceSandboxResponses, SourceType, SpanEvent, SpanKind, SpanRecord, SpanRow, SpanStatusCode, SpeedMetricsPayload, SpeedSegmentFilters, StaleSlot, StartAnalysisData, StartAnalysisErrors, StartAnalysisRequest, StartAnalysisResponse, StartAnalysisResponses, StartContainerData, StartContainerErrors, StartContainerResponse, StartContainerResponses, StartFixData, StartFixErrors, StartFixResponses, StartGitProviderOauthData, StartGitProviderOauthErrors, StartOidcLoginBySlugData, StartOidcLoginBySlugErrors, StartPgUpgradeData, StartPgUpgradeErrors, StartPgUpgradeRequest, StartPgUpgradeResponse, StartPgUpgradeResponses, StartRestoreData, StartRestoreError, StartRestoreErrors, StartRestoreRequest, StartRestoreResponse, StartRestoreResponses, StartServiceData, StartServiceErrors, StartServiceResponse, StartServiceResponses, StartUpdateData, StartUpdateError, StartUpdateErrors, StartUpdateRequest, StartUpdateResponse, StartUpdateResponse2, StartUpdateResponses, StaticBundleResponse, StaticParams, StaticPresetConfig, StatPathData, StatPathErrors, StatPathResponse, StatPathResponses, StatResponse, StatsFilters, StatusBucket, StatusBucketedResponse, StatusCodeCount, StatusCodesQuery, StatusPageOverview, StepConversionResponse, StepResourceType, StepResult, StepUpResponse, StopContainerData, StopContainerErrors, StopContainerResponse, StopContainerResponses, StopSandboxData, StopSandboxErrors, StopSandboxResponse, StopSandboxResponses, StopSequence, StopServiceData, StopServiceErrors, StopServiceResponse, StopServiceResponses, StorageQuota, StreamContainerMetricsData, StreamContainerMetricsErrors, StreamContainerMetricsResponses, StreamEventsData, StreamEventsErrors, StreamEventsResponses, StreamRunEventsData, StreamRunEventsErrors, StreamRunEventsResponses, StripeConfig, SupervisorKind, SyncedRepositoryListQuery, SyncRepositoriesData, SyncRepositoriesErrors, SyncRepositoriesResponse, SyncRepositoriesResponses, SyntaxResult, TagInfo, TagListResponse, TailDeploymentJobLogsData, TailDeploymentJobLogsErrors, TailLogsData, TailLogsError, TailLogsErrors, TailLogsRequest, TailLogsResponses, TargetRecommendation, TeamListResponse, TeamMemberResponse, TeamResponse, TeamRole, TeardownDeploymentData, TeardownDeploymentErrors, TeardownDeploymentResponse, TeardownDeploymentResponses, TeardownEnvironmentData, TeardownEnvironmentErrors, TeardownEnvironmentResponse, TeardownEnvironmentResponses, TemplateResponse, TestEmailRequest, TestEmailResponse, TestNotificationProviderData, TestNotificationProviderErrors, TestNotificationProviderResponse, TestNotificationProviderResponses, TestOidcProviderData, TestOidcProviderResponse, TestOidcProviderResponses, TestProviderConnectionData, TestProviderConnectionErrors, TestProviderConnectionResponse, TestProviderConnectionResponses, TestProviderData, TestProviderErrors, TestProviderKeyByIdData, TestProviderKeyByIdError, TestProviderKeyByIdErrors, TestProviderKeyByIdResponse, TestProviderKeyByIdResponses, TestProviderKeyInlineData, TestProviderKeyInlineError, TestProviderKeyInlineErrors, TestProviderKeyInlineResponse, TestProviderKeyInlineResponses, TestProviderKeyRequest, TestProviderKeyResponse, TestProviderResponse, TestProviderResponse2, TestProviderResponses, TestS3ConnectionPreviewData, TestS3ConnectionPreviewError, TestS3ConnectionPreviewErrors, TestS3ConnectionPreviewResponse, TestS3ConnectionPreviewResponses, TestS3SourceConnectionData, TestS3SourceConnectionError, TestS3SourceConnectionErrors, TestS3SourceConnectionResponse, TestS3SourceConnectionResponses, TimeBucketStats, TimeBucketStatsResponse, TimeseriesBucket, TimeseriesQueryParams, TlsMode, TodayStatsResponse, ToggleDeploymentMetricsRequest, ToggleServiceMetricsRequest, TokenRenewalRequest, ToolCallEvent, ToolInfo, ToolResultEvent, TopModelsQueryParams, TraceProjectRef, TracesResponse, TraceSummariesResponse, TraceSummary, TrackClickData, TrackClickErrors, TrackedLinkResponse, TrackingEventResponse, TrackOpenData, TrackOpenErrors, TrackOpenResponses, TriggerAgentData, TriggerAgentErrors, TriggerAgentRequest, TriggerAgentResponse, TriggerAgentResponses, TriggerDigestResponse, TriggerPipelinePayload, TriggerPipelineResponse, TriggerProjectPipelineData, TriggerProjectPipelineErrors, TriggerProjectPipelineResponse, TriggerProjectPipelineResponses, TriggerScanData, TriggerScanError, TriggerScanErrors, TriggerScanRequest, TriggerScanResponse, TriggerScanResponse2, TriggerScanResponses, TriggerServiceHealthCheckData, TriggerServiceHealthCheckErrors, TriggerServiceHealthCheckResponse, TriggerServiceHealthCheckResponses, TriggerWeeklyDigestData, TriggerWeeklyDigestErrors, TriggerWeeklyDigestResponse, TriggerWeeklyDigestResponses, TtlRequest, TtlResponse, TxtRecord, UiManifest, UiRoute, UndrainNodeResponse, UnifiedTrace, UniqueCountsQuery, UniqueCountsResponse, UnlinkServiceFromProjectData, UnlinkServiceFromProjectErrors, UnlinkServiceFromProjectResponse, UnlinkServiceFromProjectResponses, UnsupportedFeature, UpdateAdminGateRequest, UpdateAgentData, UpdateAgentErrors, UpdateAgentResponse, UpdateAgentResponses, UpdateAiProviderData, UpdateAiProviderErrors, UpdateAiProviderRequest, UpdateAiProviderResponse, UpdateAiProviderResponse2, UpdateAiProviderResponses, UpdateAlertData, UpdateAlertError, UpdateAlertErrors, UpdateAlertResponse, UpdateAlertResponses, UpdateAlertRuleData, UpdateAlertRuleErrors, UpdateAlertRuleRequest, UpdateAlertRuleResponse, UpdateAlertRuleResponses, UpdateApiKeyData, UpdateApiKeyErrors, UpdateApiKeyRequest, UpdateApiKeyResponse, UpdateApiKeyResponses, UpdateAutomaticDeployData, UpdateAutomaticDeployErrors, UpdateAutomaticDeployRequest, UpdateAutomaticDeployResponse, UpdateAutomaticDeployResponses, UpdateBackupScheduleData, UpdateBackupScheduleError, UpdateBackupScheduleErrors, UpdateBackupScheduleRequest, UpdateBackupScheduleResponse, UpdateBackupScheduleResponses, UpdateBlobRequest, UpdateBlobResponse, UpdateCapabilityResponse, UpdateCloudflareProviderData, UpdateCloudflareProviderErrors, UpdateCloudflareProviderRequest, UpdateCloudflareProviderResponse, UpdateCloudflareProviderResponses, UpdateConfigBody, UpdateConnectionTokenData, UpdateConnectionTokenErrors, UpdateConnectionTokenResponse, UpdateConnectionTokenResponses, UpdateCustomDomainData, UpdateCustomDomainErrors, UpdateCustomDomainRequest, UpdateCustomDomainResponse, UpdateCustomDomainResponses, UpdateDashboardData, UpdateDashboardError, UpdateDashboardErrors, UpdateDashboardRequest, UpdateDashboardResponse, UpdateDashboardResponses, UpdateDeploymentConfigRequest, UpdateDeploymentTokenData, UpdateDeploymentTokenErrors, UpdateDeploymentTokenRequest, UpdateDeploymentTokenResponse, UpdateDeploymentTokenResponses, UpdateDnsProviderRequest, UpdateEmailProviderData, UpdateEmailProviderErrors, UpdateEmailProviderRequest, UpdateEmailProviderResponse, UpdateEmailProviderResponses, UpdateEnvironmentSettingsData, UpdateEnvironmentSettingsErrors, UpdateEnvironmentSettingsRequest, UpdateEnvironmentSettingsResponse, UpdateEnvironmentSettingsResponses, UpdateEnvironmentSubdomainData, UpdateEnvironmentSubdomainErrors, UpdateEnvironmentSubdomainRequest, UpdateEnvironmentSubdomainResponse, UpdateEnvironmentSubdomainResponses, UpdateEnvironmentVariableData, UpdateEnvironmentVariableErrors, UpdateEnvironmentVariableRequest, UpdateEnvironmentVariableResponse, UpdateEnvironmentVariableResponses, UpdateErrorGroupData, UpdateErrorGroupErrors, UpdateErrorGroupRequest, UpdateErrorGroupResponses, UpdateExternalServiceRequest, UpdateFlagData, UpdateFlagErrors, UpdateFlagRequest, UpdateFlagResponse, UpdateFlagResponses, UpdateFunnelData, UpdateFunnelErrors, UpdateFunnelResponses, UpdateGitProviderCredentialsData, UpdateGitProviderCredentialsErrors, UpdateGitProviderCredentialsResponse, UpdateGitProviderCredentialsResponses, UpdateGitSettingsData, UpdateGitSettingsErrors, UpdateGitSettingsRequest, UpdateGitSettingsResponse, UpdateGitSettingsResponses, UpdateGlobalMcpData, UpdateGlobalMcpErrors, UpdateGlobalMcpResponse, UpdateGlobalMcpResponses, UpdateGlobalSkillData, UpdateGlobalSkillErrors, UpdateGlobalSkillResponse, UpdateGlobalSkillResponses, UpdateIncidentStatusData, UpdateIncidentStatusErrors, UpdateIncidentStatusRequest, UpdateIncidentStatusResponse, UpdateIncidentStatusResponses, UpdateIpAccessControlData, UpdateIpAccessControlError, UpdateIpAccessControlErrors, UpdateIpAccessControlRequest, UpdateIpAccessControlResponse, UpdateIpAccessControlResponses, UpdateKvRequest, UpdateKvResponse, UpdateManagedDomainApiRequest, UpdateManagedDomainData, UpdateManagedDomainErrors, UpdateManagedDomainResponse, UpdateManagedDomainResponses, UpdateMcpData, UpdateMcpErrors, UpdateMcpRequest, UpdateMcpResponse, UpdateMcpResponses, UpdateMemberRoleRequest, UpdateMetricAlertRequest, UpdateNotificationEmailProviderData, UpdateNotificationEmailProviderErrors, UpdateNotificationEmailProviderRequest, UpdateNotificationEmailProviderResponse, UpdateNotificationEmailProviderResponses, UpdateNotificationProviderData, UpdateNotificationProviderErrors, UpdateNotificationProviderResponse, UpdateNotificationProviderResponses, UpdateOidcProviderData, UpdateOidcProviderRequest, UpdateOidcProviderResponse, UpdateOidcProviderResponses, UpdatePreferencesData, UpdatePreferencesErrors, UpdatePreferencesRequest, UpdatePreferencesResponse, UpdatePreferencesResponses, UpdateProjectData, UpdateProjectDeploymentConfigData, UpdateProjectDeploymentConfigErrors, UpdateProjectDeploymentConfigResponse, UpdateProjectDeploymentConfigResponses, UpdateProjectErrors, UpdateProjectResponse, UpdateProjectResponses, UpdateProjectSecretData, UpdateProjectSecretErrors, UpdateProjectSecretRequest, UpdateProjectSecretResponse, UpdateProjectSecretResponses, UpdateProjectSettingsData, UpdateProjectSettingsErrors, UpdateProjectSettingsRequest, UpdateProjectSettingsResponse, UpdateProjectSettingsResponses, UpdateProviderCredentialsRequest, UpdateProviderData, UpdateProviderErrors, UpdateProviderKeyData, UpdateProviderKeyError, UpdateProviderKeyErrors, UpdateProviderKeyRequest, UpdateProviderKeyResponse, UpdateProviderKeyResponses, UpdateProviderRequest, UpdateProviderResponse, UpdateProviderResponses, UpdateRouteData, UpdateRouteErrors, UpdateRouteRequest, UpdateRouteResponse, UpdateRouteResponses, UpdateS3SourceData, UpdateS3SourceError, UpdateS3SourceErrors, UpdateS3SourceRequest, UpdateS3SourceResponse, UpdateS3SourceResponses, UpdateSecretBody, UpdateSelfData, UpdateSelfErrors, UpdateSelfRequest, UpdateSelfResponse, UpdateSelfResponses, UpdateServiceData, UpdateServiceErrors, UpdateServiceResourcesData, UpdateServiceResourcesErrors, UpdateServiceResourcesResponse, UpdateServiceResourcesResponses, UpdateServiceResponse, UpdateServiceResponses, UpdateSessionDurationData, UpdateSessionDurationError, UpdateSessionDurationErrors, UpdateSessionDurationRequest, UpdateSessionDurationResponse, UpdateSessionDurationResponse2, UpdateSessionDurationResponses, UpdateSettingsData, UpdateSettingsErrors, UpdateSettingsResponse, UpdateSettingsResponses, UpdateSkillData, UpdateSkillErrors, UpdateSkillRequest, UpdateSkillResponse, UpdateSkillResponses, UpdateSlackProviderData, UpdateSlackProviderErrors, UpdateSlackProviderRequest, UpdateSlackProviderResponse, UpdateSlackProviderResponses, UpdateSpeedMetricsData, UpdateSpeedMetricsError, UpdateSpeedMetricsErrors, UpdateSpeedMetricsPayload, UpdateSpeedMetricsResponse, UpdateSpeedMetricsResponses, UpdateStatusResponse, UpdateTeamData, UpdateTeamErrors, UpdateTeamMemberRoleData, UpdateTeamMemberRoleErrors, UpdateTeamMemberRoleResponse, UpdateTeamMemberRoleResponses, UpdateTeamRequest, UpdateTeamResponse, UpdateTeamResponses, UpdateTokenRequest, UpdateTokenResponse, UpdateUserData, UpdateUserErrors, UpdateUserRequest, UpdateUserResponse, UpdateUserResponses, UpdateWebhookData, UpdateWebhookErrors, UpdateWebhookProviderData, UpdateWebhookProviderErrors, UpdateWebhookProviderRequest, UpdateWebhookProviderResponse, UpdateWebhookProviderResponses, UpdateWebhookRequestBody, UpdateWebhookResponse, UpdateWebhookResponses, UpgradeExternalServiceRequest, UpgradePreviewGatewayData, UpgradePreviewGatewayResponse, UpgradePreviewGatewayResponses, UpgradeRequest, UpgradeServiceData, UpgradeServiceErrors, UpgradeServiceResponse, UpgradeServiceResponses, UploadGlobalSkillData, UploadGlobalSkillErrors, UploadGlobalSkillResponse, UploadGlobalSkillResponses, UploadReleaseFileData, UploadReleaseFileErrors, UploadReleaseFileResponse, UploadReleaseFileResponses, UploadSkillData, UploadSkillErrors, UploadSkillResponse, UploadSkillResponses, UploadSourceFileData, UploadSourceFileErrors, UploadSourceFileResponse, UploadSourceFileResponses, UploadSourceMapData, UploadSourceMapErrors, UploadSourceMapResponse, UploadSourceMapResponses, UploadStaticBundleData, UploadStaticBundleErrors, UploadStaticBundleResponse, UploadStaticBundleResponses, UpsertAgentRequest, UpsertSecretData, UpsertSecretErrors, UpsertSecretRequest, UpsertSecretResponse, UpsertSecretResponses, UptimeDataPoint, UptimeHistoryResponse, UsageFilter, UsageInfo, UsageLogEntry, UsageLogPage, UsageQueryParams, UsageSource, UsageSummary, UserResponse, ValidateConnectionData, ValidateConnectionErrors, ValidateConnectionResponse, ValidateConnectionResponses, ValidateEmailData, ValidateEmailErrors, ValidateEmailRequest, ValidateEmailResponse, ValidateEmailResponse2, ValidateEmailResponses, ValidationLevel, ValidationReport, ValidationResponse, ValidationResult, ValidationStatus, ValidationSummary, VerifyAndEnableMfaData, VerifyAndEnableMfaErrors, VerifyAndEnableMfaResponse, VerifyAndEnableMfaResponses, VerifyDomainData, VerifyDomainErrors, VerifyDomainResponse, VerifyDomainResponses, VerifyEmailData, VerifyEmailErrors, VerifyEmailResponse, VerifyEmailResponses, VerifyManagedDomainData, VerifyManagedDomainErrors, VerifyManagedDomainResponse, VerifyManagedDomainResponses, VerifyMfaChallengeData, VerifyMfaChallengeErrors, VerifyMfaChallengeResponse, VerifyMfaChallengeResponses, VerifyMfaRequest, VerifyStepUpData, VerifyStepUpErrors, VerifyStepUpRequest, VerifyStepUpResponse, VerifyStepUpResponses, ViewItem, ViewsOverTime, ViewsOverTimeQuery, VisitorDetails, VisitorFacets, VisitorFacetsQuery, VisitorFacetValue, VisitorInfo, VisitorJourneyQuery, VisitorJourneyResponse, VisitorLocationsQuery, VisitorRecord, VisitorSegmentFilters, VisitorSessionsQuery, VisitorSessionsResponse, VisitorsListQuery, VisitorsResponse, VisitorStats, VisitorWithGeolocation, VolumeMount, VolumeType, VulnerabilityResponse, WakeEnvironmentData, WakeEnvironmentErrors, WakeEnvironmentResponse, WakeEnvironmentResponses, WalWarning, WalWarningSeverity, WebhookConfig, WebhookDeliveryResponse, WebhookResponse, WebhookTriggerData, WebhookTriggerErrors, WebhookTriggerRequest, WebhookTriggerResponse, WebhookTriggerResponse2, WebhookTriggerResponses, WorkflowDryRunData, WorkflowDryRunErrors, WorkflowDryRunRequest, WorkflowDryRunResponse, WorkflowDryRunResponses, WorkloadDescriptor, WorkloadId, WorkloadStatus, WorkloadType, WriteFileBody, WriteFileData, WriteFileErrors, WriteFileResponse, WriteFileResponses, WriteFilesBody, WriteFilesData, WriteFilesErrors, WriteFilesResponse, WriteFilesResponse2, WriteFilesResponses, ZoneListResponse } from './types.gen'; diff --git a/apps/temps-cli/src/api/sdk.gen.ts b/apps/temps-cli/src/api/sdk.gen.ts index 0fb6aa08b..f68ed82c5 100644 --- a/apps/temps-cli/src/api/sdk.gen.ts +++ b/apps/temps-cli/src/api/sdk.gen.ts @@ -2,7 +2,7 @@ import { type Client, type ClientMeta, formDataBodySerializer, type Options as Options2, type RequestResult, type ServerSentEventsResult, type TDataShape } from './client'; import { client } from './client.gen'; -import type { AcknowledgeAlarmData, AcknowledgeAlarmErrors, AcknowledgeAlarmResponses, ActivateAiProviderData, ActivateAiProviderErrors, ActivateAiProviderResponses, ActivateApiKeyData, ActivateApiKeyErrors, ActivateApiKeyResponses, ActivateConnectionData, ActivateConnectionErrors, ActivateConnectionResponses, ActivateProviderData, ActivateProviderErrors, ActivateProviderResponses, AddClusterMemberData, AddClusterMemberErrors, AddClusterMemberResponses, AddContextData, AddContextErrors, AddContextResponses, AddEnvironmentDomainData, AddEnvironmentDomainErrors, AddEnvironmentDomainResponses, AddEventsData, AddEventsErrors, AddEventsResponses, AddManagedDomainData, AddManagedDomainErrors, AddManagedDomainResponses, AddSessionReplayEventsData, AddSessionReplayEventsErrors, AddSessionReplayEventsResponses, AddTeamMemberData, AddTeamMemberErrors, AddTeamMemberResponses, AdminDrainNodeData, AdminDrainNodeErrors, AdminDrainNodeResponses, AdminDrainStatusData, AdminDrainStatusErrors, AdminDrainStatusResponses, AdminGetNodeData, AdminGetNodeErrors, AdminGetNodeResponses, AdminListNodeContainersData, AdminListNodeContainersErrors, AdminListNodeContainersResponses, AdminListNodesData, AdminListNodesErrors, AdminListNodesResponses, AdminRemoveNodeData, AdminRemoveNodeErrors, AdminRemoveNodeResponses, AdminUndrainNodeData, AdminUndrainNodeErrors, AdminUndrainNodeResponses, ApplyHostnameModeData, ApplyHostnameModeErrors, ApplyHostnameModeResponses, ArchiveConversationData, ArchiveConversationErrors, ArchiveConversationResponses, ArchiveFlagData, ArchiveFlagErrors, ArchiveFlagResponses, AssignRoleData, AssignRoleErrors, AssignRoleResponses, AttachScheduleServicesData, AttachScheduleServicesErrors, AttachScheduleServicesResponses, BlobCopyData, BlobCopyErrors, BlobCopyResponses, BlobDeleteData, BlobDeleteErrors, BlobDeleteResponses, BlobDisableData, BlobDisableErrors, BlobDisableResponses, BlobDownloadData, BlobDownloadErrors, BlobDownloadResponses, BlobEnableData, BlobEnableErrors, BlobEnableResponses, BlobHeadData, BlobHeadErrors, BlobHeadResponses, BlobListData, BlobListErrors, BlobListResponses, BlobPutData, BlobPutErrors, BlobPutResponses, BlobStatusData, BlobStatusErrors, BlobStatusResponses, BlobUpdateData, BlobUpdateErrors, BlobUpdateResponses, CancelBackupData, CancelBackupErrors, CancelBackupResponses, CancelData, CancelDeploymentData, CancelDeploymentErrors, CancelDeploymentResponses, CancelDomainOrderData, CancelDomainOrderErrors, CancelDomainOrderResponses, CancelErrors, CancelPgUpgradeData, CancelPgUpgradeErrors, CancelPgUpgradeResponses, CancelResponses, CancelRunData, CancelRunErrors, CancelRunResponses, CancelScheduleRunData, CancelScheduleRunErrors, CancelScheduleRunResponses, ChangePasswordSelfData, ChangePasswordSelfErrors, ChangePasswordSelfResponses, ChangeProjectSourceData, ChangeProjectSourceErrors, ChangeProjectSourceResponses, ChatCompletionsData, ChatCompletionsErrors, ChatCompletionsResponses, CheckAnalyticsHasEventsData, CheckAnalyticsHasEventsErrors, CheckAnalyticsHasEventsResponses, CheckCommitExistsData, CheckCommitExistsErrors, CheckCommitExistsResponses, CheckDomainStatusData, CheckDomainStatusErrors, CheckDomainStatusResponses, CheckExplorerSupportData, CheckExplorerSupportErrors, CheckExplorerSupportResponses, CheckIpBlockedData, CheckIpBlockedErrors, CheckIpBlockedResponses, CheckProviderDeletionSafetyData, CheckProviderDeletionSafetyErrors, CheckProviderDeletionSafetyResponses, ChunkUploadOptionsData, ChunkUploadOptionsResponses, CleanupExpiredBackupsData, CleanupExpiredBackupsErrors, CleanupExpiredBackupsResponses, ClearPreviewPasswordData, ClearPreviewPasswordErrors, ClearPreviewPasswordResponses, CliDeviceApproveData, CliDeviceApproveErrors, CliDeviceApproveResponses, CliDeviceDenyData, CliDeviceDenyErrors, CliDeviceDenyResponses, CliDeviceLookupData, CliDeviceLookupErrors, CliDeviceLookupResponses, CliDevicePollData, CliDevicePollErrors, CliDevicePollResponses, CliDeviceStartData, CliDeviceStartErrors, CliDeviceStartResponses, CliLogoutData, CliLogoutErrors, CliLogoutResponses, CmdData, CmdErrors, CmdKillData, CmdKillErrors, CmdKillResponses, CmdLogsData, CmdLogsErrors, CmdLogsResponses, CmdResponses, ConfirmPendingActionData, ConfirmPendingActionErrors, ConfirmPendingActionResponses, ContainerMetricsGetHistoryData, ContainerMetricsGetHistoryErrors, ContainerMetricsGetHistoryResponses, CreateAgentData, CreateAgentErrors, CreateAgentResponses, CreateAlertData, CreateAlertErrors, CreateAlertResponses, CreateAlertRuleData, CreateAlertRuleErrors, CreateAlertRuleResponses, CreateApiKeyData, CreateApiKeyErrors, CreateApiKeyResponses, CreateBackupScheduleData, CreateBackupScheduleErrors, CreateBackupScheduleResponses, CreateBitbucketProviderData, CreateBitbucketProviderErrors, CreateBitbucketProviderResponses, CreateCloudflareProviderData, CreateCloudflareProviderErrors, CreateCloudflareProviderResponses, CreateConversationData, CreateConversationErrors, CreateConversationResponses, CreateCustomDomainData, CreateCustomDomainErrors, CreateCustomDomainResponses, CreateDashboardData, CreateDashboardErrors, CreateDashboardResponses, CreateDeploymentTokenData, CreateDeploymentTokenErrors, CreateDeploymentTokenResponses, CreateDnsProviderData, CreateDnsProviderErrors, CreateDnsProviderResponses, CreateDomainData, CreateDomainErrors, CreateDomainResponses, CreateDsnData, CreateDsnErrors, CreateDsnResponses, CreateEmailDomainData, CreateEmailDomainErrors, CreateEmailDomainResponses, CreateEmailProviderData, CreateEmailProviderErrors, CreateEmailProviderResponses, CreateEnvironmentData, CreateEnvironmentErrors, CreateEnvironmentResponses, CreateEnvironmentVariableData, CreateEnvironmentVariableErrors, CreateEnvironmentVariableResponses, CreateFlagData, CreateFlagErrors, CreateFlagResponses, CreateFunnelData, CreateFunnelErrors, CreateFunnelResponses, CreateGenericProviderData, CreateGenericProviderErrors, CreateGenericProviderResponses, CreateGiteaPatProviderData, CreateGiteaPatProviderErrors, CreateGiteaPatProviderResponses, CreateGithubPatProviderData, CreateGithubPatProviderErrors, CreateGithubPatProviderResponses, CreateGitlabOauthProviderData, CreateGitlabOauthProviderErrors, CreateGitlabOauthProviderResponses, CreateGitlabPatProviderData, CreateGitlabPatProviderErrors, CreateGitlabPatProviderResponses, CreateGitProviderData, CreateGitProviderErrors, CreateGitProviderResponses, CreateGlobalMcpData, CreateGlobalMcpErrors, CreateGlobalMcpResponses, CreateGlobalSkillData, CreateGlobalSkillErrors, CreateGlobalSkillResponses, CreateIncidentData, CreateIncidentErrors, CreateIncidentResponses, CreateIpAccessControlData, CreateIpAccessControlErrors, CreateIpAccessControlResponses, CreateMcpData, CreateMcpErrors, CreateMcpResponses, CreateMonitorData, CreateMonitorErrors, CreateMonitorResponses, CreateNotificationEmailProviderData, CreateNotificationEmailProviderErrors, CreateNotificationEmailProviderResponses, CreateNotificationProviderData, CreateNotificationProviderErrors, CreateNotificationProviderResponses, CreateOidcProviderData, CreateOidcProviderErrors, CreateOidcProviderResponses, CreateOidcRoleMappingData, CreateOidcRoleMappingResponses, CreateOrRecreateOrderData, CreateOrRecreateOrderErrors, CreateOrRecreateOrderResponses, CreatePlanData, CreatePlanErrors, CreatePlanResponses, CreatePrData, CreatePrErrors, CreateProjectData, CreateProjectErrors, CreateProjectFromTemplateData, CreateProjectFromTemplateErrors, CreateProjectFromTemplateResponses, CreateProjectReleaseData, CreateProjectReleaseErrors, CreateProjectReleaseResponses, CreateProjectResponses, CreateProjectSecretData, CreateProjectSecretErrors, CreateProjectSecretResponses, CreateProviderKeyData, CreateProviderKeyErrors, CreateProviderKeyResponses, CreatePrResponses, CreateReleaseData, CreateReleaseErrors, CreateReleaseResponses, CreateRouteData, CreateRouteErrors, CreateRouteResponses, CreateS3SourceData, CreateS3SourceErrors, CreateS3SourceResponses, CreateSandboxData, CreateSandboxErrors, CreateSandboxResponses, CreateServiceData, CreateServiceErrors, CreateServiceResponses, CreateSkillData, CreateSkillErrors, CreateSkillResponses, CreateSlackProviderData, CreateSlackProviderErrors, CreateSlackProviderResponses, CreateTeamData, CreateTeamErrors, CreateTeamResponses, CreateUserData, CreateUserErrors, CreateUserResponses, CreateWebhookData, CreateWebhookErrors, CreateWebhookProviderData, CreateWebhookProviderErrors, CreateWebhookProviderResponses, CreateWebhookResponses, DeactivateApiKeyData, DeactivateApiKeyErrors, DeactivateApiKeyResponses, DeactivateConnectionData, DeactivateConnectionErrors, DeactivateConnectionResponses, DeactivateProviderData, DeactivateProviderErrors, DeactivateProviderResponses, DeleteAgentData, DeleteAgentErrors, DeleteAgentResponses, DeleteAlertData, DeleteAlertErrors, DeleteAlertResponses, DeleteAlertRuleData, DeleteAlertRuleErrors, DeleteAlertRuleResponses, DeleteApiKeyData, DeleteApiKeyErrors, DeleteApiKeyResponses, DeleteBackupData, DeleteBackupErrors, DeleteBackupResponses, DeleteBackupScheduleData, DeleteBackupScheduleErrors, DeleteBackupScheduleResponses, DeleteConnectionData, DeleteConnectionErrors, DeleteConnectionResponses, DeleteCustomDomainData, DeleteCustomDomainErrors, DeleteCustomDomainResponses, DeleteDashboardData, DeleteDashboardErrors, DeleteDashboardResponses, DeleteDeploymentTokenData, DeleteDeploymentTokenErrors, DeleteDeploymentTokenResponses, DeleteDnsProviderData, DeleteDnsProviderErrors, DeleteDnsProviderResponses, DeleteDomainData, DeleteDomainErrors, DeleteDomainResponses, DeleteEmailDomainData, DeleteEmailDomainErrors, DeleteEmailDomainResponses, DeleteEmailProviderData, DeleteEmailProviderErrors, DeleteEmailProviderResponses, DeleteEnvironmentData, DeleteEnvironmentDomainData, DeleteEnvironmentDomainErrors, DeleteEnvironmentDomainResponses, DeleteEnvironmentErrors, DeleteEnvironmentResponses, DeleteEnvironmentVariableData, DeleteEnvironmentVariableErrors, DeleteEnvironmentVariableResponses, DeleteExternalImageData, DeleteExternalImageErrors, DeleteExternalImageResponses, DeleteFunnelData, DeleteFunnelErrors, DeleteFunnelResponses, DeleteGitProviderData, DeleteGitProviderErrors, DeleteGitProviderResponses, DeleteGlobalMcpData, DeleteGlobalMcpErrors, DeleteGlobalMcpResponses, DeleteGlobalSkillData, DeleteGlobalSkillErrors, DeleteGlobalSkillResponses, DeleteIpAccessControlData, DeleteIpAccessControlErrors, DeleteIpAccessControlResponses, DeleteMcpData, DeleteMcpErrors, DeleteMcpResponses, DeleteMonitorData, DeleteMonitorErrors, DeleteMonitorResponses, DeleteNotificationProviderData, DeleteNotificationProviderErrors, DeleteNotificationProviderResponses, DeleteOidcProviderData, DeleteOidcProviderResponses, DeleteOidcRoleMappingData, DeleteOidcRoleMappingResponses, DeletePreferencesData, DeletePreferencesErrors, DeletePreferencesResponses, DeleteProjectData, DeleteProjectErrors, DeleteProjectResponses, DeleteProjectSecretData, DeleteProjectSecretErrors, DeleteProjectSecretResponses, DeleteProviderKeyData, DeleteProviderKeyErrors, DeleteProviderKeyResponses, DeleteProviderSafelyData, DeleteProviderSafelyErrors, DeleteProviderSafelyResponses, DeleteReleaseSourceFilesData, DeleteReleaseSourceFilesErrors, DeleteReleaseSourceFilesResponses, DeleteReleaseSourceMapsData, DeleteReleaseSourceMapsErrors, DeleteReleaseSourceMapsResponses, DeleteRouteData, DeleteRouteErrors, DeleteRouteResponses, DeleteS3SourceData, DeleteS3SourceErrors, DeleteS3SourceResponses, DeleteScanData, DeleteScanErrors, DeleteScanResponses, DeleteSecretData, DeleteSecretErrors, DeleteSecretResponses, DeleteServiceData, DeleteServiceErrors, DeleteServiceResponses, DeleteSessionReplayData, DeleteSessionReplayErrors, DeleteSessionReplayResponses, DeleteSkillData, DeleteSkillErrors, DeleteSkillResponses, DeleteSourceMapData, DeleteSourceMapErrors, DeleteSourceMapResponses, DeleteStaticBundleData, DeleteStaticBundleErrors, DeleteStaticBundleResponses, DeleteTeamData, DeleteTeamErrors, DeleteTeamResponses, DeleteUserData, DeleteUserErrors, DeleteUserResponses, DeleteWebhookData, DeleteWebhookErrors, DeleteWebhookResponses, DeployFromImageData, DeployFromImageErrors, DeployFromImageResponses, DeployFromImageUploadData, DeployFromImageUploadErrors, DeployFromImageUploadResponses, DeployFromStaticData, DeployFromStaticErrors, DeployFromStaticResponses, DeployFromUploadedSourceData, DeployFromUploadedSourceErrors, DeployFromUploadedSourceResponses, DeploymentMetricsGetLatestData, DeploymentMetricsGetLatestErrors, DeploymentMetricsGetLatestResponses, DeploymentMetricsGetRangeData, DeploymentMetricsGetRangeErrors, DeploymentMetricsGetRangeResponses, DeploymentMetricsToggleData, DeploymentMetricsToggleErrors, DeploymentMetricsToggleResponses, DestroySandboxData, DestroySandboxErrors, DestroySandboxResponses, DetachScheduleServiceData, DetachScheduleServiceErrors, DetachScheduleServiceResponses, DetectPublicPresetsData, DetectPublicPresetsErrors, DetectPublicPresetsResponses, DisableBackupScheduleData, DisableBackupScheduleErrors, DisableBackupScheduleResponses, DisableMfaData, DisableMfaErrors, DisableMfaResponses, DiscoverWorkloadsData, DiscoverWorkloadsErrors, DiscoverWorkloadsResponses, DomainData, DomainErrors, DomainResponses, DownloadGlobalSkillArchiveData, DownloadGlobalSkillArchiveErrors, DownloadGlobalSkillArchiveResponses, DownloadObjectData, DownloadObjectErrors, DownloadObjectResponses, DownloadSkillArchiveData, DownloadSkillArchiveErrors, DownloadSkillArchiveResponses, EmailStatusData, EmailStatusErrors, EmailStatusResponses, EmbeddingsData, EmbeddingsErrors, EmbeddingsResponses, EnableBackupScheduleData, EnableBackupScheduleErrors, EnableBackupScheduleResponses, EnrichVisitorData, EnrichVisitorErrors, EnrichVisitorResponses, ExecData, ExecDetachedData, ExecDetachedErrors, ExecDetachedResponses, ExecErrors, ExecResponses, ExecuteDeploymentOperationData, ExecuteDeploymentOperationErrors, ExecuteDeploymentOperationResponses, ExecuteImportData, ExecuteImportErrors, ExecuteImportResponses, ExtendTimeoutData, ExtendTimeoutErrors, ExtendTimeoutResponses, ExternalServiceEnablePgStatStatementsData, ExternalServiceEnablePgStatStatementsErrors, ExternalServiceEnablePgStatStatementsResponses, ExternalServiceMetricsByDatabaseData, ExternalServiceMetricsByDatabaseErrors, ExternalServiceMetricsByDatabaseResponses, ExternalServiceMetricsCreateAlertRuleData, ExternalServiceMetricsCreateAlertRuleErrors, ExternalServiceMetricsCreateAlertRuleResponses, ExternalServiceMetricsDeleteAlertRuleData, ExternalServiceMetricsDeleteAlertRuleErrors, ExternalServiceMetricsDeleteAlertRuleResponses, ExternalServiceMetricsGetAlertRulesData, ExternalServiceMetricsGetAlertRulesErrors, ExternalServiceMetricsGetAlertRulesResponses, ExternalServiceMetricsGetLatestData, ExternalServiceMetricsGetLatestErrors, ExternalServiceMetricsGetLatestResponses, ExternalServiceMetricsGetRangeData, ExternalServiceMetricsGetRangeErrors, ExternalServiceMetricsGetRangeResponses, ExternalServiceMetricsStatusData, ExternalServiceMetricsStatusErrors, ExternalServiceMetricsStatusResponses, ExternalServiceMetricsToggleData, ExternalServiceMetricsToggleErrors, ExternalServiceMetricsToggleResponses, ExternalServiceMetricsUpdateAlertRuleData, ExternalServiceMetricsUpdateAlertRuleErrors, ExternalServiceMetricsUpdateAlertRuleResponses, ExternalServiceResetPgStatStatementsData, ExternalServiceResetPgStatStatementsErrors, ExternalServiceResetPgStatStatementsResponses, FinalizeOrderData, FinalizeOrderErrors, FinalizeOrderResponses, FinalizeProjectReleaseData, FinalizeProjectReleaseErrors, FinalizeProjectReleaseResponses, FindConversationData, FindConversationErrors, FindConversationResponses, GenerateJoinTokenData, GenerateJoinTokenErrors, GenerateJoinTokenResponses, GeneratePresetDockerfileData, GeneratePresetDockerfileErrors, GeneratePresetDockerfileResponses, GetAccessInfoData, GetAccessInfoErrors, GetAccessInfoResponses, GetActiveVisitorsData, GetActiveVisitorsErrors, GetActiveVisitorsResponses, GetActivityGraphData, GetActivityGraphErrors, GetActivityGraphResponses, GetAdminGateData, GetAdminGateErrors, GetAdminGateResponses, GetAgentData, GetAgentErrors, GetAgentResponses, GetAggregatedBucketsData, GetAggregatedBucketsErrors, GetAggregatedBucketsResponses, GetAiAgentBreakdownData, GetAiAgentBreakdownErrors, GetAiAgentBreakdownResponses, GetAiAgentPagesData, GetAiAgentPagesErrors, GetAiAgentPagesResponses, GetAiAgentTimelineData, GetAiAgentTimelineErrors, GetAiAgentTimelineResponses, GetAiPageBreakdownData, GetAiPageBreakdownErrors, GetAiPageBreakdownResponses, GetAiStatusBreakdownData, GetAiStatusBreakdownErrors, GetAiStatusBreakdownResponses, GetAlertData, GetAlertErrors, GetAlertResponses, GetAlertRuleData, GetAlertRuleErrors, GetAlertRuleResponses, GetAllRepositoriesByNameData, GetAllRepositoriesByNameErrors, GetAllRepositoriesByNameResponses, GetAnalyticsActiveVisitorsData, GetAnalyticsActiveVisitorsErrors, GetAnalyticsActiveVisitorsResponses, GetAnalyticsEventsCountData, GetAnalyticsEventsCountErrors, GetAnalyticsEventsCountResponses, GetAnalyticsSessionEventsData, GetAnalyticsSessionEventsErrors, GetAnalyticsSessionEventsResponses, GetAnalyticsVisitorSessionsData, GetAnalyticsVisitorSessionsErrors, GetAnalyticsVisitorSessionsResponses, GetApiKeyData, GetApiKeyErrors, GetApiKeyPermissionsData, GetApiKeyPermissionsErrors, GetApiKeyPermissionsResponses, GetApiKeyResponses, GetAuditLogData, GetAuditLogErrors, GetAuditLogResponses, GetBackupData, GetBackupErrors, GetBackupResponses, GetBackupScheduleData, GetBackupScheduleErrors, GetBackupScheduleResponses, GetBranchesByRepositoryIdData, GetBranchesByRepositoryIdErrors, GetBranchesByRepositoryIdResponses, GetBucketedIncidentsData, GetBucketedIncidentsErrors, GetBucketedIncidentsResponses, GetBucketedStatusData, GetBucketedStatusErrors, GetBucketedStatusResponses, GetChallengeTokenData, GetChallengeTokenErrors, GetChallengeTokenResponses, GetChatReadinessData, GetChatReadinessErrors, GetChatReadinessResponses, GetCliStatusData, GetCliStatusErrors, GetCliStatusResponses, GetClusterHealthData, GetClusterHealthErrors, GetClusterHealthResponses, GetClusterMemberData, GetClusterMemberErrors, GetClusterMemberResponses, GetCmdData, GetCmdErrors, GetCmdResponses, GetContainerDetailData, GetContainerDetailErrors, GetContainerDetailResponses, GetContainerEnvironmentVariableData, GetContainerEnvironmentVariableErrors, GetContainerEnvironmentVariableResponses, GetContainerInfoData, GetContainerInfoErrors, GetContainerInfoResponses, GetContainerLogsByIdData, GetContainerLogsByIdErrors, GetContainerLogsData, GetContainerLogsErrors, GetContainerMetricsData, GetContainerMetricsErrors, GetContainerMetricsResponses, GetConversationData, GetConversationDetailData, GetConversationDetailErrors, GetConversationDetailResponses, GetConversationErrors, GetConversationResponses, GetConversationsData, GetConversationsErrors, GetConversationsResponses, GetCronByIdData, GetCronByIdErrors, GetCronByIdResponses, GetCronExecutionsData, GetCronExecutionsErrors, GetCronExecutionsResponses, GetCrossProjectTraceSiblingsData, GetCrossProjectTraceSiblingsErrors, GetCrossProjectTraceSiblingsResponses, GetCurrentMonitorStatusData, GetCurrentMonitorStatusErrors, GetCurrentMonitorStatusResponses, GetCurrentUserData, GetCurrentUserErrors, GetCurrentUserResponses, GetCustomDomainData, GetCustomDomainErrors, GetCustomDomainResponses, GetDashboardData, GetDashboardErrors, GetDashboardProjectsAnalyticsData, GetDashboardProjectsAnalyticsErrors, GetDashboardProjectsAnalyticsResponses, GetDashboardResponses, GetDeliveryData, GetDeliveryErrors, GetDeliveryResponses, GetDeploymentContainerLogContentData, GetDeploymentContainerLogContentErrors, GetDeploymentContainerLogContentResponses, GetDeploymentData, GetDeploymentErrors, GetDeploymentJobLogsData, GetDeploymentJobLogsErrors, GetDeploymentJobLogsResponses, GetDeploymentJobsData, GetDeploymentJobsErrors, GetDeploymentJobsResponses, GetDeploymentOperationsData, GetDeploymentOperationsErrors, GetDeploymentOperationsResponses, GetDeploymentOperationStatusData, GetDeploymentOperationStatusErrors, GetDeploymentOperationStatusResponses, GetDeploymentResponses, GetDeploymentTokenData, GetDeploymentTokenErrors, GetDeploymentTokenResponses, GetDiskStatusData, GetDiskStatusErrors, GetDiskStatusResponses, GetDnsChangesData, GetDnsChangesErrors, GetDnsChangesResponses, GetDnsProviderData, GetDnsProviderErrors, GetDnsProviderResponses, GetDomainByHostData, GetDomainByHostErrors, GetDomainByHostResponses, GetDomainByIdData, GetDomainByIdErrors, GetDomainByIdResponses, GetDomainByNameData, GetDomainByNameErrors, GetDomainByNameResponses, GetDomainData, GetDomainDnsRecordsData, GetDomainDnsRecordsErrors, GetDomainDnsRecordsResponses, GetDomainErrors, GetDomainOrderData, GetDomainOrderErrors, GetDomainOrderResponses, GetDomainResponses, GetEmailData, GetEmailErrors, GetEmailEventsData, GetEmailEventsErrors, GetEmailEventsResponses, GetEmailLinksData, GetEmailLinksErrors, GetEmailLinksResponses, GetEmailProviderData, GetEmailProviderErrors, GetEmailProviderResponses, GetEmailResponses, GetEmailStatsData, GetEmailStatsErrors, GetEmailStatsResponses, GetEmailTrackingData, GetEmailTrackingErrors, GetEmailTrackingResponses, GetEmailTrackingStatusData, GetEmailTrackingStatusErrors, GetEmailTrackingStatusResponses, GetEntityInfoData, GetEntityInfoErrors, GetEntityInfoResponses, GetEnvironmentCronsData, GetEnvironmentCronsErrors, GetEnvironmentCronsResponses, GetEnvironmentData, GetEnvironmentDomainsData, GetEnvironmentDomainsErrors, GetEnvironmentDomainsResponses, GetEnvironmentErrors, GetEnvironmentResponses, GetEnvironmentsData, GetEnvironmentsErrors, GetEnvironmentsResponses, GetEnvironmentVariablesData, GetEnvironmentVariablesErrors, GetEnvironmentVariablesResponses, GetEnvironmentVariableValueData, GetEnvironmentVariableValueErrors, GetEnvironmentVariableValueResponses, GetErrorDashboardStatsData, GetErrorDashboardStatsErrors, GetErrorDashboardStatsResponses, GetErrorEventData, GetErrorEventErrors, GetErrorEventResponses, GetErrorGroupData, GetErrorGroupErrors, GetErrorGroupResponses, GetErrorStatsData, GetErrorStatsErrors, GetErrorStatsResponses, GetErrorTimeSeriesData, GetErrorTimeSeriesErrors, GetErrorTimeSeriesResponses, GetEventDetailData, GetEventDetailErrors, GetEventDetailResponses, GetEventEntriesData, GetEventEntriesErrors, GetEventEntriesResponses, GetEventsCountData, GetEventsCountErrors, GetEventsCountResponses, GetEventsTimelineData, GetEventsTimelineErrors, GetEventsTimelineResponses, GetEventTypeBreakdownData, GetEventTypeBreakdownErrors, GetEventTypeBreakdownResponses, GetEventVisitorsData, GetEventVisitorsErrors, GetEventVisitorsResponses, GetExternalImageData, GetExternalImageErrors, GetExternalImageResponses, GetFileData, GetFileErrors, GetFileResponses, GetFlagData, GetFlagErrors, GetFlagResponses, GetFlagSnapshotData, GetFlagSnapshotErrors, GetFlagSnapshotResponses, GetFunnelMetricsData, GetFunnelMetricsErrors, GetFunnelMetricsResponses, GetGenaiTraceData, GetGenaiTraceErrors, GetGenaiTraceResponses, GetGeneralStatsData, GetGeneralStatsErrors, GetGeneralStatsResponses, GetGitProviderData, GetGitProviderErrors, GetGitProviderResponses, GetGlobalEventsData, GetGlobalEventsErrors, GetGlobalEventsResponses, GetGlobalEventStatsData, GetGlobalEventStatsErrors, GetGlobalEventStatsResponses, GetGlobalMcpData, GetGlobalMcpErrors, GetGlobalMcpResponses, GetGlobalSandboxStatusData, GetGlobalSandboxStatusErrors, GetGlobalSandboxStatusResponses, GetGlobalSkillData, GetGlobalSkillErrors, GetGlobalSkillResponses, GetGroupedPageMetricsData, GetGroupedPageMetricsErrors, GetGroupedPageMetricsResponses, GetHealthData, GetHealthErrors, GetHealthResponses, GetHourlyVisitsData, GetHourlyVisitsErrors, GetHourlyVisitsResponses, GetHttpChallengeDebugData, GetHttpChallengeDebugErrors, GetHttpChallengeDebugResponses, GetImportStatusData, GetImportStatusErrors, GetImportStatusResponses, GetIncidentData, GetIncidentErrors, GetIncidentResponses, GetIncidentUpdatesData, GetIncidentUpdatesErrors, GetIncidentUpdatesResponses, GetIpAccessControlData, GetIpAccessControlErrors, GetIpAccessControlResponses, GetIpGeolocationData, GetIpGeolocationErrors, GetIpGeolocationResponses, GetJoinTokenStatusData, GetJoinTokenStatusErrors, GetJoinTokenStatusResponses, GetLastDeploymentData, GetLastDeploymentErrors, GetLastDeploymentResponses, GetLatestScanData, GetLatestScanErrors, GetLatestScanResponses, GetLatestScansPerEnvironmentData, GetLatestScansPerEnvironmentErrors, GetLatestScansPerEnvironmentResponses, GetLiveVisitorsListData, GetLiveVisitorsListErrors, GetLiveVisitorsListResponses, GetLogContextData, GetLogContextErrors, GetLogContextResponses, GetMcpData, GetMcpErrors, GetMcpResponses, GetMetricsOverTimeData, GetMetricsOverTimeErrors, GetMetricsOverTimeResponses, GetMonitorData, GetMonitorErrors, GetMonitorResponses, GetNotificationProviderData, GetNotificationProviderErrors, GetNotificationProviderResponses, GetOnDemandCertStatusData, GetOnDemandCertStatusErrors, GetOnDemandCertStatusResponses, GetOrCreateDsnData, GetOrCreateDsnErrors, GetOrCreateDsnResponses, GetPageFlowData, GetPageFlowErrors, GetPageFlowResponses, GetPageHourlySessionsData, GetPageHourlySessionsErrors, GetPageHourlySessionsResponses, GetPagePathDetailData, GetPagePathDetailErrors, GetPagePathDetailResponses, GetPagePathsData, GetPagePathsErrors, GetPagePathsResponses, GetPagePathsSparklinesData, GetPagePathsSparklinesErrors, GetPagePathsSparklinesResponses, GetPagePathVisitorsData, GetPagePathVisitorsErrors, GetPagePathVisitorsResponses, GetPendingActionData, GetPendingActionErrors, GetPendingActionResponses, GetPerformanceMetricsData, GetPerformanceMetricsErrors, GetPerformanceMetricsResponses, GetPgUpgradeData, GetPgUpgradeErrors, GetPgUpgradeLogsData, GetPgUpgradeLogsErrors, GetPgUpgradeLogsResponses, GetPgUpgradeResponses, GetPipelineStatsData, GetPipelineStatsErrors, GetPipelineStatsResponses, GetPlatformInfoData, GetPlatformInfoErrors, GetPlatformInfoResponses, GetPostgresWalHealthData, GetPostgresWalHealthErrors, GetPostgresWalHealthResponses, GetPreferencesData, GetPreferencesErrors, GetPreferencesResponses, GetPreviewGatewayLogsData, GetPreviewGatewayLogsResponses, GetPreviewGatewaySettingsData, GetPreviewGatewaySettingsResponses, GetPreviewGatewayStatusData, GetPreviewGatewayStatusResponses, GetPricingData, GetPricingErrors, GetPricingResponses, GetPrivateIpData, GetPrivateIpErrors, GetPrivateIpResponses, GetProjectAlarmsSummaryData, GetProjectAlarmsSummaryErrors, GetProjectAlarmsSummaryResponses, GetProjectBySlugData, GetProjectBySlugErrors, GetProjectBySlugResponses, GetProjectData, GetProjectDeploymentsData, GetProjectDeploymentsErrors, GetProjectDeploymentsResponses, GetProjectErrors, GetProjectResponses, GetProjectsData, GetProjectsErrors, GetProjectServiceEnvironmentVariablesData, GetProjectServiceEnvironmentVariablesErrors, GetProjectServiceEnvironmentVariablesResponses, GetProjectSessionReplaysData, GetProjectSessionReplaysErrors, GetProjectSessionReplaysResponses, GetProjectsHealthData, GetProjectsHealthErrors, GetProjectsHealthResponses, GetProjectsMonitorHealthData, GetProjectsMonitorHealthErrors, GetProjectsMonitorHealthResponses, GetProjectsResponses, GetProjectStatisticsData, GetProjectStatisticsErrors, GetProjectStatisticsResponses, GetProjectTemplateData, GetProjectTemplateErrors, GetProjectTemplateResponses, GetPropertyBreakdownData, GetPropertyBreakdownErrors, GetPropertyBreakdownResponses, GetPropertyTimelineData, GetPropertyTimelineErrors, GetPropertyTimelineResponses, GetProviderConnectionsData, GetProviderConnectionsErrors, GetProviderConnectionsResponses, GetProviderMetadataData, GetProviderMetadataErrors, GetProviderMetadataResponses, GetProvidersMetadataData, GetProvidersMetadataErrors, GetProvidersMetadataResponses, GetProxyLogByIdData, GetProxyLogByIdErrors, GetProxyLogByIdResponses, GetProxyLogByRequestIdData, GetProxyLogByRequestIdErrors, GetProxyLogByRequestIdResponses, GetProxyLogsData, GetProxyLogsErrors, GetProxyLogsResponses, GetPublicBranchesData, GetPublicBranchesErrors, GetPublicBranchesResponses, GetPublicIpData, GetPublicIpErrors, GetPublicIpResponses, GetPublicRepositoryData, GetPublicRepositoryErrors, GetPublicRepositoryResponses, GetQuotaData, GetQuotaErrors, GetQuotaResponses, GetRecentActivityData, GetRecentActivityErrors, GetRecentActivityResponses, GetRemoteExternalImageData, GetRemoteExternalImageErrors, GetRemoteExternalImageResponses, GetRepositoryBranchesData, GetRepositoryBranchesErrors, GetRepositoryBranchesResponses, GetRepositoryByIdData, GetRepositoryByIdErrors, GetRepositoryByIdResponses, GetRepositoryByNameData, GetRepositoryByNameErrors, GetRepositoryByNameResponses, GetRepositoryPresetByNameData, GetRepositoryPresetByNameErrors, GetRepositoryPresetByNameResponses, GetRepositoryPresetLiveData, GetRepositoryPresetLiveErrors, GetRepositoryPresetLiveResponses, GetRepositoryTagsData, GetRepositoryTagsErrors, GetRepositoryTagsResponses, GetResolvedEnvironmentVariablesData, GetResolvedEnvironmentVariablesErrors, GetResolvedEnvironmentVariablesResponses, GetResolvedEnvironmentVariableValueData, GetResolvedEnvironmentVariableValueErrors, GetResolvedEnvironmentVariableValueResponses, GetRestoreCapabilitiesData, GetRestoreCapabilitiesErrors, GetRestoreCapabilitiesResponses, GetRestoreRunData, GetRestoreRunErrors, GetRestoreRunResponses, GetRouteData, GetRouteErrors, GetRouteResponses, GetRunData, GetRunErrors, GetRunResponses, GetRunWithLogsData, GetRunWithLogsErrors, GetRunWithLogsResponses, GetS3CredentialsData, GetS3CredentialsErrors, GetS3CredentialsResponses, GetS3SourceData, GetS3SourceErrors, GetS3SourceResponses, GetSandboxData, GetSandboxErrors, GetSandboxResponses, GetSandboxStatusData, GetSandboxStatusErrors, GetSandboxStatusResponses, GetScanByDeploymentData, GetScanByDeploymentErrors, GetScanByDeploymentResponses, GetScanData, GetScanErrors, GetScanResponses, GetScanVulnerabilitiesData, GetScanVulnerabilitiesErrors, GetScanVulnerabilitiesResponses, GetServiceBySlugData, GetServiceBySlugErrors, GetServiceBySlugResponses, GetServiceData, GetServiceEnvironmentVariableData, GetServiceEnvironmentVariableErrors, GetServiceEnvironmentVariableResponses, GetServiceEnvironmentVariablesData, GetServiceEnvironmentVariablesErrors, GetServiceEnvironmentVariablesResponses, GetServiceErrors, GetServiceHealthStatusData, GetServiceHealthStatusErrors, GetServiceHealthStatusResponses, GetServicePreviewEnvironmentVariableNamesData, GetServicePreviewEnvironmentVariableNamesErrors, GetServicePreviewEnvironmentVariableNamesResponses, GetServicePreviewEnvironmentVariablesMaskedData, GetServicePreviewEnvironmentVariablesMaskedErrors, GetServicePreviewEnvironmentVariablesMaskedResponses, GetServiceResponses, GetServiceRuntimeData, GetServiceRuntimeErrors, GetServiceRuntimeResponses, GetServiceStatsData, GetServiceStatsErrors, GetServiceStatsResponses, GetServiceTypeParametersData, GetServiceTypeParametersErrors, GetServiceTypeParametersResponses, GetServiceTypesData, GetServiceTypesErrors, GetServiceTypesResponses, GetSessionDetailsData, GetSessionDetailsErrors, GetSessionDetailsResponses, GetSessionEventsData, GetSessionEventsErrors, GetSessionEventsResponses, GetSessionLogsData, GetSessionLogsErrors, GetSessionLogsResponses, GetSessionReplayData, GetSessionReplayErrors, GetSessionReplayEventsData, GetSessionReplayEventsErrors, GetSessionReplayEventsResponses, GetSessionReplayResponses, GetSettingsData, GetSettingsErrors, GetSettingsResponses, GetSkillData, GetSkillErrors, GetSkillResponses, GetSlowQueriesData, GetSlowQueriesErrors, GetSlowQueriesResponses, GetStaticBundleData, GetStaticBundleErrors, GetStaticBundleResponses, GetStatusOverviewData, GetStatusOverviewErrors, GetStatusOverviewResponses, GetTagsByRepositoryIdData, GetTagsByRepositoryIdErrors, GetTagsByRepositoryIdResponses, GetTeamData, GetTeamErrors, GetTeamResponses, GetTimeBucketStatsData, GetTimeBucketStatsErrors, GetTimeBucketStatsResponses, GetTodayStatsData, GetTodayStatsErrors, GetTodayStatsResponses, GetTraceData, GetTraceErrors, GetTraceResponses, GetUnifiedTraceData, GetUnifiedTraceErrors, GetUnifiedTraceResponses, GetUniqueCountsData, GetUniqueCountsErrors, GetUniqueCountsResponses, GetUniqueEventsData, GetUniqueEventsErrors, GetUniqueEventsResponses, GetUpdateStatusData, GetUpdateStatusErrors, GetUpdateStatusResponses, GetUptimeHistoryData, GetUptimeHistoryErrors, GetUptimeHistoryResponses, GetUsageByProviderData, GetUsageByProviderErrors, GetUsageByProviderResponses, GetUsageRecentData, GetUsageRecentErrors, GetUsageRecentResponses, GetUsageSummaryData, GetUsageSummaryErrors, GetUsageSummaryResponses, GetUsageTimeseriesData, GetUsageTimeseriesErrors, GetUsageTimeseriesResponses, GetUsageTopModelsData, GetUsageTopModelsErrors, GetUsageTopModelsResponses, GetVisitorByGuidData, GetVisitorByGuidErrors, GetVisitorByGuidResponses, GetVisitorByIdData, GetVisitorByIdErrors, GetVisitorByIdResponses, GetVisitorDetailsData, GetVisitorDetailsErrors, GetVisitorDetailsResponses, GetVisitorFacetsData, GetVisitorFacetsErrors, GetVisitorFacetsResponses, GetVisitorInfoData, GetVisitorInfoErrors, GetVisitorInfoResponses, GetVisitorJourneyData, GetVisitorJourneyErrors, GetVisitorJourneyResponses, GetVisitorsData, GetVisitorsErrors, GetVisitorSessionsData, GetVisitorSessionsErrors, GetVisitorSessionsResponses, GetVisitorsResponses, GetVisitorStatsData, GetVisitorStatsErrors, GetVisitorStatsResponses, GetWebhookData, GetWebhookErrors, GetWebhookResponses, GrantProjectAccessData, GrantProjectAccessErrors, GrantProjectAccessResponses, HandleGitProviderOauthCallbackData, HandleGitProviderOauthCallbackErrors, HasAnalyticsEventsData, HasAnalyticsEventsErrors, HasAnalyticsEventsResponses, HasErrorGroupsData, HasErrorGroupsErrors, HasErrorGroupsResponses, HasPerformanceMetricsData, HasPerformanceMetricsErrors, HasPerformanceMetricsResponses, ImportExternalServiceData, ImportExternalServiceErrors, ImportExternalServiceResponses, IngestLogsByPathData, IngestLogsByPathErrors, IngestLogsByPathResponses, IngestLogsData, IngestLogsErrors, IngestLogsResponses, IngestMetricsByPathData, IngestMetricsByPathErrors, IngestMetricsByPathResponses, IngestMetricsData, IngestMetricsErrors, IngestMetricsResponses, IngestSentryEnvelopeData, IngestSentryEnvelopeErrors, IngestSentryEnvelopeResponses, IngestSentryEventData, IngestSentryEventErrors, IngestSentryEventResponses, IngestTracesByPathData, IngestTracesByPathErrors, IngestTracesByPathResponses, IngestTracesData, IngestTracesErrors, IngestTracesResponses, InitSessionReplayData, InitSessionReplayErrors, InitSessionReplayResponses, InspectDropArchiveData, InspectDropArchiveErrors, InspectDropArchiveResponses, JobLogsData, JobLogsErrors, JobLogsResponses, JobStatusData, JobStatusErrors, JobStatusResponses, KillJobData, KillJobErrors, KillJobResponses, KvDelData, KvDelErrors, KvDelResponses, KvDisableData, KvDisableErrors, KvDisableResponses, KvEnableData, KvEnableErrors, KvEnableResponses, KvExpireData, KvExpireErrors, KvExpireResponses, KvGetData, KvGetErrors, KvGetResponses, KvIncrData, KvIncrErrors, KvIncrResponses, KvKeysData, KvKeysErrors, KvKeysResponses, KvSetData, KvSetErrors, KvSetResponses, KvStatusData, KvStatusErrors, KvStatusResponses, KvTtlData, KvTtlErrors, KvTtlResponses, KvUpdateData, KvUpdateErrors, KvUpdateResponses, LatestRunForSourceData, LatestRunForSourceErrors, LatestRunForSourceResponses, LinkCustomDomainToCertificateData, LinkCustomDomainToCertificateErrors, LinkCustomDomainToCertificateResponses, LinkServiceToProjectData, LinkServiceToProjectErrors, LinkServiceToProjectResponses, ListAgentRunsData, ListAgentRunsErrors, ListAgentRunsResponses, ListAgentsData, ListAgentsErrors, ListAgentsResponses, ListAiProvidersData, ListAiProvidersErrors, ListAiProvidersResponses, ListAlertRulesData, ListAlertRulesErrors, ListAlertRulesResponses, ListAlertsData, ListAlertsErrors, ListAlertsResponses, ListAllConversationsData, ListAllConversationsErrors, ListAllConversationsResponses, ListAllRunsData, ListAllRunsErrors, ListAllRunsResponses, ListApiKeysData, ListApiKeysErrors, ListApiKeysResponses, ListAuditLogsData, ListAuditLogsErrors, ListAuditLogsResponses, ListAvailableContainersData, ListAvailableContainersErrors, ListAvailableContainersResponses, ListBackupAlertsData, ListBackupAlertsErrors, ListBackupAlertsResponses, ListBackupChildrenData, ListBackupChildrenErrors, ListBackupChildrenResponses, ListBackupSchedulesData, ListBackupSchedulesErrors, ListBackupSchedulesResponses, ListBackupsForScheduleData, ListBackupsForScheduleErrors, ListBackupsForScheduleResponses, ListCommitsByRepositoryIdData, ListCommitsByRepositoryIdErrors, ListCommitsByRepositoryIdResponses, ListConnectionsData, ListConnectionsErrors, ListConnectionsResponses, ListContainersAtPathData, ListContainersAtPathErrors, ListContainersAtPathResponses, ListContainersData, ListContainersErrors, ListContainersResponses, ListConversationsData, ListConversationsErrors, ListConversationsResponses, ListCustomDomainsForProjectData, ListCustomDomainsForProjectErrors, ListCustomDomainsForProjectResponses, ListDashboardsData, ListDashboardsErrors, ListDashboardsResponses, ListDeliveriesData, ListDeliveriesErrors, ListDeliveriesResponses, ListDeploymentContainerLogsData, ListDeploymentContainerLogsErrors, ListDeploymentContainerLogsResponses, ListDeploymentTokensData, ListDeploymentTokensErrors, ListDeploymentTokensResponses, ListDnsProvidersData, ListDnsProvidersErrors, ListDnsProvidersResponses, ListDomainsData, ListDomainsErrors, ListDomainsResponses, ListDsnsData, ListDsnsErrors, ListDsnsResponses, ListEmailDomainsData, ListEmailDomainsErrors, ListEmailDomainsResponses, ListEmailProvidersData, ListEmailProvidersErrors, ListEmailProvidersResponses, ListEmailsData, ListEmailsErrors, ListEmailsResponses, ListEnrollmentTokensData, ListEnrollmentTokensErrors, ListEnrollmentTokensResponses, ListEntitiesData, ListEntitiesErrors, ListEntitiesResponses, ListErrorEventsData, ListErrorEventsErrors, ListErrorEventsResponses, ListErrorGroupsData, ListErrorGroupsErrors, ListErrorGroupsResponses, ListEventsData, ListEventsResponses, ListEventTypesData, ListEventTypesResponses, ListExternalImagesData, ListExternalImagesErrors, ListExternalImagesResponses, ListExternalPluginsData, ListExternalPluginsErrors, ListExternalPluginsResponses, ListExternalServiceBackupsData, ListExternalServiceBackupsErrors, ListExternalServiceBackupsResponses, ListFlagsData, ListFlagsErrors, ListFlagsResponses, ListFunnelsData, ListFunnelsErrors, ListFunnelsResponses, ListGitProvidersData, ListGitProvidersErrors, ListGitProvidersResponses, ListGlobalMcpsData, ListGlobalMcpsErrors, ListGlobalMcpsResponses, ListGlobalSkillsData, ListGlobalSkillsErrors, ListGlobalSkillsResponses, ListIncidentsData, ListIncidentsErrors, ListIncidentsResponses, ListInsightsData, ListInsightsErrors, ListInsightsResponses, ListIpAccessControlData, ListIpAccessControlErrors, ListIpAccessControlResponses, ListJobsData, ListJobsErrors, ListJobsResponses, ListKnownAiAgentsData, ListKnownAiAgentsErrors, ListKnownAiAgentsResponses, ListManagedDomainsData, ListManagedDomainsErrors, ListManagedDomainsResponses, ListMcpsData, ListMcpsErrors, ListMcpsResponses, ListMetricLabelKeysData, ListMetricLabelKeysErrors, ListMetricLabelKeysResponses, ListMetricLabelValuesData, ListMetricLabelValuesErrors, ListMetricLabelValuesResponses, ListMetricNamesData, ListMetricNamesErrors, ListMetricNamesResponses, ListModelsData, ListModelsErrors, ListModelsResponses, ListMonitorsData, ListMonitorsErrors, ListMonitorsResponses, ListNotificationProvidersData, ListNotificationProvidersErrors, ListNotificationProvidersResponses, ListOidcProvidersData, ListOidcProvidersResponses, ListOidcProviderUsersData, ListOidcProviderUsersErrors, ListOidcProviderUsersResponses, ListOidcRoleMappingsData, ListOidcRoleMappingsResponses, ListOnDemandCertsData, ListOnDemandCertsErrors, ListOnDemandCertsResponses, ListOrdersData, ListOrdersErrors, ListOrdersResponses, ListPeersData, ListPeersErrors, ListPeersResponses, ListPendingActionsData, ListPendingActionsErrors, ListPendingActionsResponses, ListPgUpgradesData, ListPgUpgradesErrors, ListPgUpgradesResponses, ListPresetsData, ListPresetsErrors, ListPresetsResponses, ListProjectAccessData, ListProjectAccessErrors, ListProjectAccessResponses, ListProjectAlarmsData, ListProjectAlarmsErrors, ListProjectAlarmsResponses, ListProjectScansData, ListProjectScansErrors, ListProjectScansResponses, ListProjectSecretsData, ListProjectSecretsErrors, ListProjectSecretsResponses, ListProjectServicesData, ListProjectServicesErrors, ListProjectServicesResponses, ListProjectTemplatesData, ListProjectTemplatesErrors, ListProjectTemplatesResponses, ListProjectTemplateTagsData, ListProjectTemplateTagsErrors, ListProjectTemplateTagsResponses, ListProviderKeysData, ListProviderKeysErrors, ListProviderKeysResponses, ListProviderZonesData, ListProviderZonesErrors, ListProviderZonesResponses, ListPublicProvidersData, ListPublicProvidersResponses, ListReleaseFilesData, ListReleaseFilesErrors, ListReleaseFilesResponses, ListReleasesData, ListReleasesErrors, ListReleasesResponses, ListRemoteExternalImagesData, ListRemoteExternalImagesErrors, ListRemoteExternalImagesResponses, ListRepositoriesByConnectionData, ListRepositoriesByConnectionErrors, ListRepositoriesByConnectionResponses, ListRepositoriesByProviderData, ListRepositoriesByProviderErrors, ListRepositoriesByProviderResponses, ListRestoreRunsForServiceData, ListRestoreRunsForServiceResponses, ListRootContainersData, ListRootContainersErrors, ListRootContainersResponses, ListRoutesData, ListRoutesErrors, ListRoutesResponses, ListS3SourcesData, ListS3SourcesErrors, ListS3SourcesResponses, ListSandboxesData, ListSandboxesResponses, ListScheduleRunJobsData, ListScheduleRunJobsErrors, ListScheduleRunJobsResponses, ListScheduleRunsData, ListScheduleRunsErrors, ListScheduleRunsResponses, ListScheduleServicesData, ListScheduleServicesErrors, ListScheduleServicesResponses, ListSecretsData, ListSecretsErrors, ListSecretsResponses, ListServiceHealthStatusesData, ListServiceHealthStatusesErrors, ListServiceHealthStatusesResponses, ListServiceProjectsData, ListServiceProjectsErrors, ListServiceProjectsResponses, ListServiceSchedulesData, ListServiceSchedulesErrors, ListServiceSchedulesResponses, ListServicesData, ListServicesErrors, ListServicesResponses, ListSkillsData, ListSkillsErrors, ListSkillsResponses, ListSourceBackupsData, ListSourceBackupsErrors, ListSourceBackupsResponses, ListSourceFilesData, ListSourceFilesErrors, ListSourceFilesResponses, ListSourceMapsData, ListSourceMapsErrors, ListSourceMapsResponses, ListSourcesData, ListSourcesErrors, ListSourcesResponses, ListStaticBundlesData, ListStaticBundlesErrors, ListStaticBundlesResponses, ListSyncedRepositoriesData, ListSyncedRepositoriesErrors, ListSyncedRepositoriesResponses, ListTeamMembersData, ListTeamMembersErrors, ListTeamMembersResponses, ListTeamProjectsData, ListTeamProjectsErrors, ListTeamProjectsResponses, ListTeamsData, ListTeamsErrors, ListTeamsResponses, ListUsersData, ListUsersErrors, ListUsersResponses, ListWebhooksData, ListWebhooksErrors, ListWebhooksResponses, LoginData, LoginErrors, LoginResponses, LogoutData, LogoutErrors, LogoutResponses, LookupDnsARecordsData, LookupDnsARecordsErrors, LookupDnsARecordsResponses, MintEnrollmentTokenData, MintEnrollmentTokenErrors, MintEnrollmentTokenResponses, MkdirData, MkdirErrors, MkdirResponses, NodeHeartbeatData, NodeHeartbeatErrors, NodeHeartbeatResponses, NodeMetricsGetRangeData, NodeMetricsGetRangeErrors, NodeMetricsGetRangeResponses, ObservabilityFullEventData, ObservabilityFullEventErrors, ObservabilityFullEventResponses, ObservabilityListEventsData, ObservabilityListEventsErrors, ObservabilityListEventsResponses, OidcCallbackData, PatchAdminGateData, PatchAdminGateErrors, PatchAdminGateResponses, PatchPreviewGatewaySettingsData, PatchPreviewGatewaySettingsResponses, PauseDeploymentData, PauseDeploymentErrors, PauseDeploymentResponses, PauseSandboxData, PauseSandboxErrors, PauseSandboxResponses, PlanRestoreData, PlanRestoreErrors, PlanRestoreResponses, PostDnsAckData, PostDnsAckErrors, PostDnsAckResponses, PreviewAlertData, PreviewAlertErrors, PreviewAlertResponses, PreviewFunnelMetricsData, PreviewFunnelMetricsErrors, PreviewFunnelMetricsResponses, PreviewHostnameModeData, PreviewHostnameModeErrors, PreviewHostnameModeResponses, PromoteClusterMemberData, PromoteClusterMemberErrors, PromoteClusterMemberResponses, PromoteDeploymentData, PromoteDeploymentErrors, PromoteDeploymentResponses, ProvisionDomainData, ProvisionDomainErrors, ProvisionDomainResponses, PurgeProjectLogsData, PurgeProjectLogsErrors, PurgeProjectLogsResponses, PushExternalImageData, PushExternalImageErrors, PushExternalImageResponses, QueryDataData, QueryDataErrors, QueryDataResponses, QueryGenaiTracesData, QueryGenaiTracesErrors, QueryGenaiTracesResponses, QueryLogsData, QueryLogsErrors, QueryLogsResponses, QueryMetricsData, QueryMetricsErrors, QueryMetricsResponses, QueryTracesData, QueryTracesErrors, QueryTracesResponses, QueryTraceSummariesData, QueryTraceSummariesErrors, QueryTraceSummariesResponses, ReadFileData, ReadFileErrors, ReadFileResponses, ReAnalyzeData, ReAnalyzeErrors, ReAnalyzeResponses, RebuildSandboxImageData, RebuildSandboxImageErrors, RebuildSandboxImageResponses, RecordConsoleEventData, RecordConsoleEventErrors, RecordConsoleEventResponses, RecordEventMetricsData, RecordEventMetricsErrors, RecordEventMetricsResponses, RecordFlagExposureData, RecordFlagExposureErrors, RecordFlagExposureResponses, RecordSpeedMetricsData, RecordSpeedMetricsErrors, RecordSpeedMetricsResponses, RefreshRouteTableData, RefreshRouteTableErrors, RefreshRouteTableResponses, RegenerateDsnData, RegenerateDsnErrors, RegenerateDsnResponses, RegisterExternalImageData, RegisterExternalImageErrors, RegisterExternalImageResponses, RegisterNodeData, RegisterNodeErrors, RegisterNodeResponses, ReinstallGitlabWebhookData, ReinstallGitlabWebhookErrors, ReinstallGitlabWebhookResponses, RejectPendingActionData, RejectPendingActionErrors, RejectPendingActionResponses, ReloadPluginsData, ReloadPluginsErrors, ReloadPluginsResponses, RemoveClusterMemberData, RemoveClusterMemberErrors, RemoveClusterMemberResponses, RemoveManagedDomainData, RemoveManagedDomainErrors, RemoveManagedDomainResponses, RemoveRoleData, RemoveRoleErrors, RemoveRoleResponses, RemoveTeamMemberData, RemoveTeamMemberErrors, RemoveTeamMemberResponses, RenameConversationData, RenameConversationErrors, RenameConversationResponses, RenewDomainData, RenewDomainErrors, RenewDomainResponses, RequestPasswordResetData, RequestPasswordResetErrors, RequestPasswordResetResponses, ResetPasswordData, ResetPasswordErrors, ResetPasswordResponses, ResizeSandboxData, ResizeSandboxErrors, ResizeSandboxResponses, ResolveAlarmData, ResolveAlarmErrors, ResolveAlarmResponses, RestartContainerData, RestartContainerErrors, RestartContainerResponses, RestartPreviewGatewayData, RestartPreviewGatewayResponses, RestartSandboxData, RestartSandboxErrors, RestartSandboxResponses, RestoreFlagData, RestoreFlagErrors, RestoreFlagResponses, RestoreUserData, RestoreUserErrors, RestoreUserResponses, ResumeDeploymentData, ResumeDeploymentErrors, ResumeDeploymentResponses, ResumeSandboxData, ResumeSandboxErrors, ResumeSandboxResponses, RetryClusterData, RetryClusterErrors, RetryClusterResponses, RetryDeliveryData, RetryDeliveryErrors, RetryDeliveryResponses, RetryPgUpgradeData, RetryPgUpgradeErrors, RetryPgUpgradeResponses, RetryRunData, RetryRunErrors, RetryRunResponses, RevealGlobalMcpConfigData, RevealGlobalMcpConfigErrors, RevealGlobalMcpConfigResponses, RevealMcpConfigData, RevealMcpConfigErrors, RevealMcpConfigResponses, RevealNotificationProviderConfigData, RevealNotificationProviderConfigErrors, RevealNotificationProviderConfigResponses, RevealServiceParameterData, RevealServiceParameterErrors, RevealServiceParameterResponses, RevenueCreateIntegrationData, RevenueCreateIntegrationErrors, RevenueCreateIntegrationResponses, RevenueDeleteIntegrationData, RevenueDeleteIntegrationResponses, RevenueGlobalEventsData, RevenueGlobalEventsResponses, RevenueImportInvoicesCsvData, RevenueImportInvoicesCsvErrors, RevenueImportInvoicesCsvResponses, RevenueImportSubscriptionsCsvData, RevenueImportSubscriptionsCsvErrors, RevenueImportSubscriptionsCsvResponses, RevenueListIntegrationsData, RevenueListIntegrationsResponses, RevenueListProvidersData, RevenueListProvidersResponses, RevenueMetricsCustomersData, RevenueMetricsCustomersResponses, RevenueMetricsGlobalMrrData, RevenueMetricsGlobalMrrResponses, RevenueMetricsGlobalSummaryData, RevenueMetricsGlobalSummaryResponses, RevenueMetricsMrrData, RevenueMetricsMrrResponses, RevenueMetricsSummaryData, RevenueMetricsSummaryResponses, RevenueRecentEventsData, RevenueRecentEventsResponses, RevenueRotateTokenData, RevenueRotateTokenResponses, RevenueUpdateConfigData, RevenueUpdateConfigErrors, RevenueUpdateConfigResponses, RevenueUpdateSecretData, RevenueUpdateSecretErrors, RevenueUpdateSecretResponses, RevokeDsnData, RevokeDsnErrors, RevokeDsnResponses, RevokeEnrollmentTokenData, RevokeEnrollmentTokenErrors, RevokeEnrollmentTokenResponses, RevokeJoinTokenData, RevokeJoinTokenErrors, RevokeJoinTokenResponses, RevokeProjectAccessData, RevokeProjectAccessErrors, RevokeProjectAccessResponses, RollbackPgUpgradeData, RollbackPgUpgradeErrors, RollbackPgUpgradeResponses, RollbackToDeploymentData, RollbackToDeploymentErrors, RollbackToDeploymentResponses, RootfsGcData, RootfsGcResponses, RootfsReportData, RootfsReportResponses, RotateApiKeyData, RotateApiKeyErrors, RotateApiKeyResponses, RotateDeploymentTokenData, RotateDeploymentTokenErrors, RotateDeploymentTokenResponses, RunBackupForSourceData, RunBackupForSourceErrors, RunBackupForSourceResponses, RunConnectionHealthCheckData, RunConnectionHealthCheckErrors, RunConnectionHealthCheckResponses, RunExternalServiceBackupData, RunExternalServiceBackupErrors, RunExternalServiceBackupResponses, RunScheduleNowData, RunScheduleNowErrors, RunScheduleNowResponses, SandboxCreatePreviewLinkData, SandboxCreatePreviewLinkErrors, SandboxCreatePreviewLinkResponses, SaveAgentTokenData, SaveAgentTokenErrors, SaveAgentTokenResponses, SaveAiProviderCredentialData, SaveAiProviderCredentialErrors, SaveAiProviderCredentialResponses, SearchLogsData, SearchLogsErrors, SearchLogsResponses, SendEmailData, SendEmailErrors, SendEmailResponses, SendMessageData, SendMessageErrors, SendMessageResponses, SetDefaultS3SourceData, SetDefaultS3SourceErrors, SetDefaultS3SourceResponses, SetFlagEnvironmentData, SetFlagEnvironmentErrors, SetFlagEnvironmentResponses, SetPreviewPasswordData, SetPreviewPasswordErrors, SetPreviewPasswordResponses, SetupDnsChallengeData, SetupDnsChallengeErrors, SetupDnsChallengeResponses, SetupDnsData, SetupDnsErrors, SetupDnsResponses, SetupEmailTrackingData, SetupEmailTrackingErrors, SetupEmailTrackingResponses, SetupMfaData, SetupMfaErrors, SetupMfaResponses, SleepEnvironmentData, SleepEnvironmentErrors, SleepEnvironmentResponses, SmokeTestAgentData, SmokeTestAgentErrors, SmokeTestAgentResponses, SourceSandboxData, SourceSandboxErrors, SourceSandboxResponses, StartAnalysisData, StartAnalysisErrors, StartAnalysisResponses, StartContainerData, StartContainerErrors, StartContainerResponses, StartFixData, StartFixErrors, StartFixResponses, StartGitProviderOauthData, StartGitProviderOauthErrors, StartOidcLoginBySlugData, StartOidcLoginBySlugErrors, StartPgUpgradeData, StartPgUpgradeErrors, StartPgUpgradeResponses, StartRestoreData, StartRestoreErrors, StartRestoreResponses, StartServiceData, StartServiceErrors, StartServiceResponses, StatPathData, StatPathErrors, StatPathResponses, StopContainerData, StopContainerErrors, StopContainerResponses, StopSandboxData, StopSandboxErrors, StopSandboxResponses, StopServiceData, StopServiceErrors, StopServiceResponses, StreamContainerMetricsData, StreamContainerMetricsErrors, StreamContainerMetricsResponses, StreamEventsData, StreamEventsErrors, StreamEventsResponses, StreamRunEventsData, StreamRunEventsErrors, StreamRunEventsResponses, SyncRepositoriesData, SyncRepositoriesErrors, SyncRepositoriesResponses, TailDeploymentJobLogsData, TailDeploymentJobLogsErrors, TailLogsData, TailLogsErrors, TailLogsResponses, TeardownDeploymentData, TeardownDeploymentErrors, TeardownDeploymentResponses, TeardownEnvironmentData, TeardownEnvironmentErrors, TeardownEnvironmentResponses, TestNotificationProviderData, TestNotificationProviderErrors, TestNotificationProviderResponses, TestOidcProviderData, TestOidcProviderResponses, TestProviderConnectionData, TestProviderConnectionErrors, TestProviderConnectionResponses, TestProviderData, TestProviderErrors, TestProviderKeyByIdData, TestProviderKeyByIdErrors, TestProviderKeyByIdResponses, TestProviderKeyInlineData, TestProviderKeyInlineErrors, TestProviderKeyInlineResponses, TestProviderResponses, TestS3ConnectionPreviewData, TestS3ConnectionPreviewErrors, TestS3ConnectionPreviewResponses, TestS3SourceConnectionData, TestS3SourceConnectionErrors, TestS3SourceConnectionResponses, TrackClickData, TrackClickErrors, TrackOpenData, TrackOpenErrors, TrackOpenResponses, TriggerAgentData, TriggerAgentErrors, TriggerAgentResponses, TriggerProjectPipelineData, TriggerProjectPipelineErrors, TriggerProjectPipelineResponses, TriggerScanData, TriggerScanErrors, TriggerScanResponses, TriggerServiceHealthCheckData, TriggerServiceHealthCheckErrors, TriggerServiceHealthCheckResponses, TriggerWeeklyDigestData, TriggerWeeklyDigestErrors, TriggerWeeklyDigestResponses, UnlinkServiceFromProjectData, UnlinkServiceFromProjectErrors, UnlinkServiceFromProjectResponses, UpdateAgentData, UpdateAgentErrors, UpdateAgentResponses, UpdateAiProviderData, UpdateAiProviderErrors, UpdateAiProviderResponses, UpdateAlertData, UpdateAlertErrors, UpdateAlertResponses, UpdateAlertRuleData, UpdateAlertRuleErrors, UpdateAlertRuleResponses, UpdateApiKeyData, UpdateApiKeyErrors, UpdateApiKeyResponses, UpdateAutomaticDeployData, UpdateAutomaticDeployErrors, UpdateAutomaticDeployResponses, UpdateBackupScheduleData, UpdateBackupScheduleErrors, UpdateBackupScheduleResponses, UpdateCloudflareProviderData, UpdateCloudflareProviderErrors, UpdateCloudflareProviderResponses, UpdateConnectionTokenData, UpdateConnectionTokenErrors, UpdateConnectionTokenResponses, UpdateCustomDomainData, UpdateCustomDomainErrors, UpdateCustomDomainResponses, UpdateDashboardData, UpdateDashboardErrors, UpdateDashboardResponses, UpdateDeploymentTokenData, UpdateDeploymentTokenErrors, UpdateDeploymentTokenResponses, UpdateEmailProviderData, UpdateEmailProviderErrors, UpdateEmailProviderResponses, UpdateEnvironmentSettingsData, UpdateEnvironmentSettingsErrors, UpdateEnvironmentSettingsResponses, UpdateEnvironmentSubdomainData, UpdateEnvironmentSubdomainErrors, UpdateEnvironmentSubdomainResponses, UpdateEnvironmentVariableData, UpdateEnvironmentVariableErrors, UpdateEnvironmentVariableResponses, UpdateErrorGroupData, UpdateErrorGroupErrors, UpdateErrorGroupResponses, UpdateFlagData, UpdateFlagErrors, UpdateFlagResponses, UpdateFunnelData, UpdateFunnelErrors, UpdateFunnelResponses, UpdateGitProviderCredentialsData, UpdateGitProviderCredentialsErrors, UpdateGitProviderCredentialsResponses, UpdateGitSettingsData, UpdateGitSettingsErrors, UpdateGitSettingsResponses, UpdateGlobalMcpData, UpdateGlobalMcpErrors, UpdateGlobalMcpResponses, UpdateGlobalSkillData, UpdateGlobalSkillErrors, UpdateGlobalSkillResponses, UpdateIncidentStatusData, UpdateIncidentStatusErrors, UpdateIncidentStatusResponses, UpdateIpAccessControlData, UpdateIpAccessControlErrors, UpdateIpAccessControlResponses, UpdateManagedDomainData, UpdateManagedDomainErrors, UpdateManagedDomainResponses, UpdateMcpData, UpdateMcpErrors, UpdateMcpResponses, UpdateNotificationEmailProviderData, UpdateNotificationEmailProviderErrors, UpdateNotificationEmailProviderResponses, UpdateNotificationProviderData, UpdateNotificationProviderErrors, UpdateNotificationProviderResponses, UpdateOidcProviderData, UpdateOidcProviderResponses, UpdatePreferencesData, UpdatePreferencesErrors, UpdatePreferencesResponses, UpdateProjectData, UpdateProjectDeploymentConfigData, UpdateProjectDeploymentConfigErrors, UpdateProjectDeploymentConfigResponses, UpdateProjectErrors, UpdateProjectResponses, UpdateProjectSecretData, UpdateProjectSecretErrors, UpdateProjectSecretResponses, UpdateProjectSettingsData, UpdateProjectSettingsErrors, UpdateProjectSettingsResponses, UpdateProviderData, UpdateProviderErrors, UpdateProviderKeyData, UpdateProviderKeyErrors, UpdateProviderKeyResponses, UpdateProviderResponses, UpdateRouteData, UpdateRouteErrors, UpdateRouteResponses, UpdateS3SourceData, UpdateS3SourceErrors, UpdateS3SourceResponses, UpdateSelfData, UpdateSelfErrors, UpdateSelfResponses, UpdateServiceData, UpdateServiceErrors, UpdateServiceResourcesData, UpdateServiceResourcesErrors, UpdateServiceResourcesResponses, UpdateServiceResponses, UpdateSessionDurationData, UpdateSessionDurationErrors, UpdateSessionDurationResponses, UpdateSettingsData, UpdateSettingsErrors, UpdateSettingsResponses, UpdateSkillData, UpdateSkillErrors, UpdateSkillResponses, UpdateSlackProviderData, UpdateSlackProviderErrors, UpdateSlackProviderResponses, UpdateSpeedMetricsData, UpdateSpeedMetricsErrors, UpdateSpeedMetricsResponses, UpdateTeamData, UpdateTeamErrors, UpdateTeamMemberRoleData, UpdateTeamMemberRoleErrors, UpdateTeamMemberRoleResponses, UpdateTeamResponses, UpdateUserData, UpdateUserErrors, UpdateUserResponses, UpdateWebhookData, UpdateWebhookErrors, UpdateWebhookProviderData, UpdateWebhookProviderErrors, UpdateWebhookProviderResponses, UpdateWebhookResponses, UpgradePreviewGatewayData, UpgradePreviewGatewayResponses, UpgradeServiceData, UpgradeServiceErrors, UpgradeServiceResponses, UploadGlobalSkillData, UploadGlobalSkillErrors, UploadGlobalSkillResponses, UploadReleaseFileData, UploadReleaseFileErrors, UploadReleaseFileResponses, UploadSkillData, UploadSkillErrors, UploadSkillResponses, UploadSourceFileData, UploadSourceFileErrors, UploadSourceFileResponses, UploadSourceMapData, UploadSourceMapErrors, UploadSourceMapResponses, UploadStaticBundleData, UploadStaticBundleErrors, UploadStaticBundleResponses, UpsertSecretData, UpsertSecretErrors, UpsertSecretResponses, ValidateConnectionData, ValidateConnectionErrors, ValidateConnectionResponses, ValidateEmailData, ValidateEmailErrors, ValidateEmailResponses, VerifyAndEnableMfaData, VerifyAndEnableMfaErrors, VerifyAndEnableMfaResponses, VerifyDomainData, VerifyDomainErrors, VerifyDomainResponses, VerifyEmailData, VerifyEmailErrors, VerifyEmailResponses, VerifyManagedDomainData, VerifyManagedDomainErrors, VerifyManagedDomainResponses, VerifyMfaChallengeData, VerifyMfaChallengeErrors, VerifyMfaChallengeResponses, VerifyStepUpData, VerifyStepUpErrors, VerifyStepUpResponses, WakeEnvironmentData, WakeEnvironmentErrors, WakeEnvironmentResponses, WebhookTriggerData, WebhookTriggerErrors, WebhookTriggerResponses, WorkflowDryRunData, WorkflowDryRunErrors, WorkflowDryRunResponses, WriteFileData, WriteFileErrors, WriteFileResponses, WriteFilesData, WriteFilesErrors, WriteFilesResponses } from './types.gen'; +import type { AcknowledgeAlarmData, AcknowledgeAlarmErrors, AcknowledgeAlarmResponses, ActivateAiProviderData, ActivateAiProviderErrors, ActivateAiProviderResponses, ActivateApiKeyData, ActivateApiKeyErrors, ActivateApiKeyResponses, ActivateConnectionData, ActivateConnectionErrors, ActivateConnectionResponses, ActivateProviderData, ActivateProviderErrors, ActivateProviderResponses, AddClusterMemberData, AddClusterMemberErrors, AddClusterMemberResponses, AddContextData, AddContextErrors, AddContextResponses, AddEnvironmentDomainData, AddEnvironmentDomainErrors, AddEnvironmentDomainResponses, AddEventsData, AddEventsErrors, AddEventsResponses, AddManagedDomainData, AddManagedDomainErrors, AddManagedDomainResponses, AddSessionReplayEventsData, AddSessionReplayEventsErrors, AddSessionReplayEventsResponses, AddTeamMemberData, AddTeamMemberErrors, AddTeamMemberResponses, AdminDrainNodeData, AdminDrainNodeErrors, AdminDrainNodeResponses, AdminDrainStatusData, AdminDrainStatusErrors, AdminDrainStatusResponses, AdminGetNodeData, AdminGetNodeErrors, AdminGetNodeResponses, AdminListNodeContainersData, AdminListNodeContainersErrors, AdminListNodeContainersResponses, AdminListNodesData, AdminListNodesErrors, AdminListNodesResponses, AdminRemoveNodeData, AdminRemoveNodeErrors, AdminRemoveNodeResponses, AdminUndrainNodeData, AdminUndrainNodeErrors, AdminUndrainNodeResponses, ApplyHostnameModeData, ApplyHostnameModeErrors, ApplyHostnameModeResponses, ArchiveConversationData, ArchiveConversationErrors, ArchiveConversationResponses, ArchiveFlagData, ArchiveFlagErrors, ArchiveFlagResponses, AssignRoleData, AssignRoleErrors, AssignRoleResponses, AttachScheduleServicesData, AttachScheduleServicesErrors, AttachScheduleServicesResponses, BlobCopyData, BlobCopyErrors, BlobCopyResponses, BlobDeleteData, BlobDeleteErrors, BlobDeleteResponses, BlobDisableData, BlobDisableErrors, BlobDisableResponses, BlobDownloadData, BlobDownloadErrors, BlobDownloadResponses, BlobEnableData, BlobEnableErrors, BlobEnableResponses, BlobHeadData, BlobHeadErrors, BlobHeadResponses, BlobListData, BlobListErrors, BlobListResponses, BlobPutData, BlobPutErrors, BlobPutResponses, BlobStatusData, BlobStatusErrors, BlobStatusResponses, BlobUpdateData, BlobUpdateErrors, BlobUpdateResponses, CancelBackupData, CancelBackupErrors, CancelBackupResponses, CancelData, CancelDeploymentData, CancelDeploymentErrors, CancelDeploymentResponses, CancelDomainOrderData, CancelDomainOrderErrors, CancelDomainOrderResponses, CancelErrors, CancelPgUpgradeData, CancelPgUpgradeErrors, CancelPgUpgradeResponses, CancelResponses, CancelRunData, CancelRunErrors, CancelRunResponses, CancelScheduleRunData, CancelScheduleRunErrors, CancelScheduleRunResponses, ChangePasswordSelfData, ChangePasswordSelfErrors, ChangePasswordSelfResponses, ChangeProjectSourceData, ChangeProjectSourceErrors, ChangeProjectSourceResponses, ChangeRequiredPasswordData, ChangeRequiredPasswordErrors, ChangeRequiredPasswordResponses, ChatCompletionsData, ChatCompletionsErrors, ChatCompletionsResponses, CheckAnalyticsHasEventsData, CheckAnalyticsHasEventsErrors, CheckAnalyticsHasEventsResponses, CheckCommitExistsData, CheckCommitExistsErrors, CheckCommitExistsResponses, CheckDomainStatusData, CheckDomainStatusErrors, CheckDomainStatusResponses, CheckExplorerSupportData, CheckExplorerSupportErrors, CheckExplorerSupportResponses, CheckIpBlockedData, CheckIpBlockedErrors, CheckIpBlockedResponses, CheckProviderDeletionSafetyData, CheckProviderDeletionSafetyErrors, CheckProviderDeletionSafetyResponses, ChunkUploadOptionsData, ChunkUploadOptionsResponses, CleanupExpiredBackupsData, CleanupExpiredBackupsErrors, CleanupExpiredBackupsResponses, ClearPreviewPasswordData, ClearPreviewPasswordErrors, ClearPreviewPasswordResponses, CliDeviceApproveData, CliDeviceApproveErrors, CliDeviceApproveResponses, CliDeviceDenyData, CliDeviceDenyErrors, CliDeviceDenyResponses, CliDeviceLookupData, CliDeviceLookupErrors, CliDeviceLookupResponses, CliDevicePollData, CliDevicePollErrors, CliDevicePollResponses, CliDeviceStartData, CliDeviceStartErrors, CliDeviceStartResponses, CliLogoutData, CliLogoutErrors, CliLogoutResponses, CmdData, CmdErrors, CmdKillData, CmdKillErrors, CmdKillResponses, CmdLogsData, CmdLogsErrors, CmdLogsResponses, CmdResponses, ConfirmPendingActionData, ConfirmPendingActionErrors, ConfirmPendingActionResponses, ContainerMetricsGetHistoryData, ContainerMetricsGetHistoryErrors, ContainerMetricsGetHistoryResponses, CreateAgentData, CreateAgentErrors, CreateAgentResponses, CreateAlertData, CreateAlertErrors, CreateAlertResponses, CreateAlertRuleData, CreateAlertRuleErrors, CreateAlertRuleResponses, CreateApiKeyData, CreateApiKeyErrors, CreateApiKeyResponses, CreateBackupScheduleData, CreateBackupScheduleErrors, CreateBackupScheduleResponses, CreateBitbucketProviderData, CreateBitbucketProviderErrors, CreateBitbucketProviderResponses, CreateCloudflareProviderData, CreateCloudflareProviderErrors, CreateCloudflareProviderResponses, CreateConversationData, CreateConversationErrors, CreateConversationResponses, CreateCustomDomainData, CreateCustomDomainErrors, CreateCustomDomainResponses, CreateDashboardData, CreateDashboardErrors, CreateDashboardResponses, CreateDeploymentTokenData, CreateDeploymentTokenErrors, CreateDeploymentTokenResponses, CreateDnsProviderData, CreateDnsProviderErrors, CreateDnsProviderResponses, CreateDomainData, CreateDomainErrors, CreateDomainResponses, CreateDsnData, CreateDsnErrors, CreateDsnResponses, CreateEmailDomainData, CreateEmailDomainErrors, CreateEmailDomainResponses, CreateEmailProviderData, CreateEmailProviderErrors, CreateEmailProviderResponses, CreateEnvironmentData, CreateEnvironmentErrors, CreateEnvironmentResponses, CreateEnvironmentVariableData, CreateEnvironmentVariableErrors, CreateEnvironmentVariableResponses, CreateFlagData, CreateFlagErrors, CreateFlagResponses, CreateFunnelData, CreateFunnelErrors, CreateFunnelResponses, CreateGenericProviderData, CreateGenericProviderErrors, CreateGenericProviderResponses, CreateGiteaPatProviderData, CreateGiteaPatProviderErrors, CreateGiteaPatProviderResponses, CreateGithubPatProviderData, CreateGithubPatProviderErrors, CreateGithubPatProviderResponses, CreateGitlabOauthProviderData, CreateGitlabOauthProviderErrors, CreateGitlabOauthProviderResponses, CreateGitlabPatProviderData, CreateGitlabPatProviderErrors, CreateGitlabPatProviderResponses, CreateGitProviderData, CreateGitProviderErrors, CreateGitProviderResponses, CreateGlobalMcpData, CreateGlobalMcpErrors, CreateGlobalMcpResponses, CreateGlobalSkillData, CreateGlobalSkillErrors, CreateGlobalSkillResponses, CreateIncidentData, CreateIncidentErrors, CreateIncidentResponses, CreateIpAccessControlData, CreateIpAccessControlErrors, CreateIpAccessControlResponses, CreateMcpData, CreateMcpErrors, CreateMcpResponses, CreateMonitorData, CreateMonitorErrors, CreateMonitorResponses, CreateNotificationEmailProviderData, CreateNotificationEmailProviderErrors, CreateNotificationEmailProviderResponses, CreateNotificationProviderData, CreateNotificationProviderErrors, CreateNotificationProviderResponses, CreateOidcProviderData, CreateOidcProviderErrors, CreateOidcProviderResponses, CreateOidcRoleMappingData, CreateOidcRoleMappingResponses, CreateOrRecreateOrderData, CreateOrRecreateOrderErrors, CreateOrRecreateOrderResponses, CreatePlanData, CreatePlanErrors, CreatePlanResponses, CreatePrData, CreatePrErrors, CreateProjectData, CreateProjectErrors, CreateProjectFromTemplateData, CreateProjectFromTemplateErrors, CreateProjectFromTemplateResponses, CreateProjectReleaseData, CreateProjectReleaseErrors, CreateProjectReleaseResponses, CreateProjectResponses, CreateProjectSecretData, CreateProjectSecretErrors, CreateProjectSecretResponses, CreateProviderKeyData, CreateProviderKeyErrors, CreateProviderKeyResponses, CreatePrResponses, CreateReleaseData, CreateReleaseErrors, CreateReleaseResponses, CreateRouteData, CreateRouteErrors, CreateRouteResponses, CreateS3SourceData, CreateS3SourceErrors, CreateS3SourceResponses, CreateSandboxData, CreateSandboxErrors, CreateSandboxResponses, CreateServiceData, CreateServiceErrors, CreateServiceResponses, CreateSkillData, CreateSkillErrors, CreateSkillResponses, CreateSlackProviderData, CreateSlackProviderErrors, CreateSlackProviderResponses, CreateTeamData, CreateTeamErrors, CreateTeamResponses, CreateUserData, CreateUserErrors, CreateUserResponses, CreateWebhookData, CreateWebhookErrors, CreateWebhookProviderData, CreateWebhookProviderErrors, CreateWebhookProviderResponses, CreateWebhookResponses, DeactivateApiKeyData, DeactivateApiKeyErrors, DeactivateApiKeyResponses, DeactivateConnectionData, DeactivateConnectionErrors, DeactivateConnectionResponses, DeactivateProviderData, DeactivateProviderErrors, DeactivateProviderResponses, DeleteAgentData, DeleteAgentErrors, DeleteAgentResponses, DeleteAlertData, DeleteAlertErrors, DeleteAlertResponses, DeleteAlertRuleData, DeleteAlertRuleErrors, DeleteAlertRuleResponses, DeleteApiKeyData, DeleteApiKeyErrors, DeleteApiKeyResponses, DeleteBackupData, DeleteBackupErrors, DeleteBackupResponses, DeleteBackupScheduleData, DeleteBackupScheduleErrors, DeleteBackupScheduleResponses, DeleteConnectionData, DeleteConnectionErrors, DeleteConnectionResponses, DeleteCustomDomainData, DeleteCustomDomainErrors, DeleteCustomDomainResponses, DeleteDashboardData, DeleteDashboardErrors, DeleteDashboardResponses, DeleteDeploymentTokenData, DeleteDeploymentTokenErrors, DeleteDeploymentTokenResponses, DeleteDnsProviderData, DeleteDnsProviderErrors, DeleteDnsProviderResponses, DeleteDomainData, DeleteDomainErrors, DeleteDomainResponses, DeleteEmailDomainData, DeleteEmailDomainErrors, DeleteEmailDomainResponses, DeleteEmailProviderData, DeleteEmailProviderErrors, DeleteEmailProviderResponses, DeleteEnvironmentData, DeleteEnvironmentDomainData, DeleteEnvironmentDomainErrors, DeleteEnvironmentDomainResponses, DeleteEnvironmentErrors, DeleteEnvironmentResponses, DeleteEnvironmentVariableData, DeleteEnvironmentVariableErrors, DeleteEnvironmentVariableResponses, DeleteExternalImageData, DeleteExternalImageErrors, DeleteExternalImageResponses, DeleteFunnelData, DeleteFunnelErrors, DeleteFunnelResponses, DeleteGitProviderData, DeleteGitProviderErrors, DeleteGitProviderResponses, DeleteGlobalMcpData, DeleteGlobalMcpErrors, DeleteGlobalMcpResponses, DeleteGlobalSkillData, DeleteGlobalSkillErrors, DeleteGlobalSkillResponses, DeleteIpAccessControlData, DeleteIpAccessControlErrors, DeleteIpAccessControlResponses, DeleteMcpData, DeleteMcpErrors, DeleteMcpResponses, DeleteMonitorData, DeleteMonitorErrors, DeleteMonitorResponses, DeleteNotificationProviderData, DeleteNotificationProviderErrors, DeleteNotificationProviderResponses, DeleteOidcProviderData, DeleteOidcProviderResponses, DeleteOidcRoleMappingData, DeleteOidcRoleMappingResponses, DeletePreferencesData, DeletePreferencesErrors, DeletePreferencesResponses, DeleteProjectData, DeleteProjectErrors, DeleteProjectResponses, DeleteProjectSecretData, DeleteProjectSecretErrors, DeleteProjectSecretResponses, DeleteProviderKeyData, DeleteProviderKeyErrors, DeleteProviderKeyResponses, DeleteProviderSafelyData, DeleteProviderSafelyErrors, DeleteProviderSafelyResponses, DeleteReleaseSourceFilesData, DeleteReleaseSourceFilesErrors, DeleteReleaseSourceFilesResponses, DeleteReleaseSourceMapsData, DeleteReleaseSourceMapsErrors, DeleteReleaseSourceMapsResponses, DeleteRouteData, DeleteRouteErrors, DeleteRouteResponses, DeleteS3SourceData, DeleteS3SourceErrors, DeleteS3SourceResponses, DeleteScanData, DeleteScanErrors, DeleteScanResponses, DeleteSecretData, DeleteSecretErrors, DeleteSecretResponses, DeleteServiceData, DeleteServiceErrors, DeleteServiceResponses, DeleteSessionReplayData, DeleteSessionReplayErrors, DeleteSessionReplayResponses, DeleteSkillData, DeleteSkillErrors, DeleteSkillResponses, DeleteSourceMapData, DeleteSourceMapErrors, DeleteSourceMapResponses, DeleteStaticBundleData, DeleteStaticBundleErrors, DeleteStaticBundleResponses, DeleteTeamData, DeleteTeamErrors, DeleteTeamResponses, DeleteUserData, DeleteUserErrors, DeleteUserResponses, DeleteWebhookData, DeleteWebhookErrors, DeleteWebhookResponses, DeployFromImageData, DeployFromImageErrors, DeployFromImageResponses, DeployFromImageUploadData, DeployFromImageUploadErrors, DeployFromImageUploadResponses, DeployFromStaticData, DeployFromStaticErrors, DeployFromStaticResponses, DeployFromUploadedSourceData, DeployFromUploadedSourceErrors, DeployFromUploadedSourceResponses, DeploymentMetricsGetLatestData, DeploymentMetricsGetLatestErrors, DeploymentMetricsGetLatestResponses, DeploymentMetricsGetRangeData, DeploymentMetricsGetRangeErrors, DeploymentMetricsGetRangeResponses, DeploymentMetricsToggleData, DeploymentMetricsToggleErrors, DeploymentMetricsToggleResponses, DestroySandboxData, DestroySandboxErrors, DestroySandboxResponses, DetachScheduleServiceData, DetachScheduleServiceErrors, DetachScheduleServiceResponses, DetectPublicPresetsData, DetectPublicPresetsErrors, DetectPublicPresetsResponses, DisableBackupScheduleData, DisableBackupScheduleErrors, DisableBackupScheduleResponses, DisableMfaData, DisableMfaErrors, DisableMfaResponses, DiscoverWorkloadsData, DiscoverWorkloadsErrors, DiscoverWorkloadsResponses, DomainData, DomainErrors, DomainResponses, DownloadGlobalSkillArchiveData, DownloadGlobalSkillArchiveErrors, DownloadGlobalSkillArchiveResponses, DownloadObjectData, DownloadObjectErrors, DownloadObjectResponses, DownloadSkillArchiveData, DownloadSkillArchiveErrors, DownloadSkillArchiveResponses, EmailStatusData, EmailStatusErrors, EmailStatusResponses, EmbeddingsData, EmbeddingsErrors, EmbeddingsResponses, EnableBackupScheduleData, EnableBackupScheduleErrors, EnableBackupScheduleResponses, EnrichVisitorData, EnrichVisitorErrors, EnrichVisitorResponses, ExecData, ExecDetachedData, ExecDetachedErrors, ExecDetachedResponses, ExecErrors, ExecResponses, ExecuteDeploymentOperationData, ExecuteDeploymentOperationErrors, ExecuteDeploymentOperationResponses, ExecuteImportData, ExecuteImportErrors, ExecuteImportResponses, ExtendTimeoutData, ExtendTimeoutErrors, ExtendTimeoutResponses, ExternalServiceEnablePgStatStatementsData, ExternalServiceEnablePgStatStatementsErrors, ExternalServiceEnablePgStatStatementsResponses, ExternalServiceMetricsByDatabaseData, ExternalServiceMetricsByDatabaseErrors, ExternalServiceMetricsByDatabaseResponses, ExternalServiceMetricsCreateAlertRuleData, ExternalServiceMetricsCreateAlertRuleErrors, ExternalServiceMetricsCreateAlertRuleResponses, ExternalServiceMetricsDeleteAlertRuleData, ExternalServiceMetricsDeleteAlertRuleErrors, ExternalServiceMetricsDeleteAlertRuleResponses, ExternalServiceMetricsGetAlertRulesData, ExternalServiceMetricsGetAlertRulesErrors, ExternalServiceMetricsGetAlertRulesResponses, ExternalServiceMetricsGetLatestData, ExternalServiceMetricsGetLatestErrors, ExternalServiceMetricsGetLatestResponses, ExternalServiceMetricsGetRangeData, ExternalServiceMetricsGetRangeErrors, ExternalServiceMetricsGetRangeResponses, ExternalServiceMetricsStatusData, ExternalServiceMetricsStatusErrors, ExternalServiceMetricsStatusResponses, ExternalServiceMetricsToggleData, ExternalServiceMetricsToggleErrors, ExternalServiceMetricsToggleResponses, ExternalServiceMetricsUpdateAlertRuleData, ExternalServiceMetricsUpdateAlertRuleErrors, ExternalServiceMetricsUpdateAlertRuleResponses, ExternalServiceResetPgStatStatementsData, ExternalServiceResetPgStatStatementsErrors, ExternalServiceResetPgStatStatementsResponses, FinalizeOrderData, FinalizeOrderErrors, FinalizeOrderResponses, FinalizeProjectReleaseData, FinalizeProjectReleaseErrors, FinalizeProjectReleaseResponses, FindConversationData, FindConversationErrors, FindConversationResponses, GenerateJoinTokenData, GenerateJoinTokenErrors, GenerateJoinTokenResponses, GeneratePresetDockerfileData, GeneratePresetDockerfileErrors, GeneratePresetDockerfileResponses, GetAccessInfoData, GetAccessInfoErrors, GetAccessInfoResponses, GetActiveVisitorsData, GetActiveVisitorsErrors, GetActiveVisitorsResponses, GetActivityGraphData, GetActivityGraphErrors, GetActivityGraphResponses, GetAdminGateData, GetAdminGateErrors, GetAdminGateResponses, GetAgentData, GetAgentErrors, GetAgentResponses, GetAggregatedBucketsData, GetAggregatedBucketsErrors, GetAggregatedBucketsResponses, GetAiAgentBreakdownData, GetAiAgentBreakdownErrors, GetAiAgentBreakdownResponses, GetAiAgentPagesData, GetAiAgentPagesErrors, GetAiAgentPagesResponses, GetAiAgentTimelineData, GetAiAgentTimelineErrors, GetAiAgentTimelineResponses, GetAiPageBreakdownData, GetAiPageBreakdownErrors, GetAiPageBreakdownResponses, GetAiStatusBreakdownData, GetAiStatusBreakdownErrors, GetAiStatusBreakdownResponses, GetAlertData, GetAlertErrors, GetAlertResponses, GetAlertRuleData, GetAlertRuleErrors, GetAlertRuleResponses, GetAllRepositoriesByNameData, GetAllRepositoriesByNameErrors, GetAllRepositoriesByNameResponses, GetAnalyticsActiveVisitorsData, GetAnalyticsActiveVisitorsErrors, GetAnalyticsActiveVisitorsResponses, GetAnalyticsEventsCountData, GetAnalyticsEventsCountErrors, GetAnalyticsEventsCountResponses, GetAnalyticsSessionEventsData, GetAnalyticsSessionEventsErrors, GetAnalyticsSessionEventsResponses, GetAnalyticsVisitorSessionsData, GetAnalyticsVisitorSessionsErrors, GetAnalyticsVisitorSessionsResponses, GetApiKeyData, GetApiKeyErrors, GetApiKeyPermissionsData, GetApiKeyPermissionsErrors, GetApiKeyPermissionsResponses, GetApiKeyResponses, GetAuditLogData, GetAuditLogErrors, GetAuditLogResponses, GetBackupData, GetBackupErrors, GetBackupResponses, GetBackupScheduleData, GetBackupScheduleErrors, GetBackupScheduleResponses, GetBranchesByRepositoryIdData, GetBranchesByRepositoryIdErrors, GetBranchesByRepositoryIdResponses, GetBucketedIncidentsData, GetBucketedIncidentsErrors, GetBucketedIncidentsResponses, GetBucketedStatusData, GetBucketedStatusErrors, GetBucketedStatusResponses, GetChallengeTokenData, GetChallengeTokenErrors, GetChallengeTokenResponses, GetChatReadinessData, GetChatReadinessErrors, GetChatReadinessResponses, GetCliStatusData, GetCliStatusErrors, GetCliStatusResponses, GetClusterHealthData, GetClusterHealthErrors, GetClusterHealthResponses, GetClusterMemberData, GetClusterMemberErrors, GetClusterMemberResponses, GetCmdData, GetCmdErrors, GetCmdResponses, GetContainerDetailData, GetContainerDetailErrors, GetContainerDetailResponses, GetContainerEnvironmentVariableData, GetContainerEnvironmentVariableErrors, GetContainerEnvironmentVariableResponses, GetContainerInfoData, GetContainerInfoErrors, GetContainerInfoResponses, GetContainerLogsByIdData, GetContainerLogsByIdErrors, GetContainerLogsData, GetContainerLogsErrors, GetContainerMetricsData, GetContainerMetricsErrors, GetContainerMetricsResponses, GetConversationData, GetConversationDetailData, GetConversationDetailErrors, GetConversationDetailResponses, GetConversationErrors, GetConversationResponses, GetConversationsData, GetConversationsErrors, GetConversationsResponses, GetCronByIdData, GetCronByIdErrors, GetCronByIdResponses, GetCronExecutionsData, GetCronExecutionsErrors, GetCronExecutionsResponses, GetCrossProjectTraceSiblingsData, GetCrossProjectTraceSiblingsErrors, GetCrossProjectTraceSiblingsResponses, GetCurrentMonitorStatusData, GetCurrentMonitorStatusErrors, GetCurrentMonitorStatusResponses, GetCurrentUserData, GetCurrentUserErrors, GetCurrentUserResponses, GetCustomDomainData, GetCustomDomainErrors, GetCustomDomainResponses, GetDashboardData, GetDashboardErrors, GetDashboardProjectsAnalyticsData, GetDashboardProjectsAnalyticsErrors, GetDashboardProjectsAnalyticsResponses, GetDashboardResponses, GetDeliveryData, GetDeliveryErrors, GetDeliveryResponses, GetDeploymentContainerLogContentData, GetDeploymentContainerLogContentErrors, GetDeploymentContainerLogContentResponses, GetDeploymentData, GetDeploymentErrors, GetDeploymentJobLogsData, GetDeploymentJobLogsErrors, GetDeploymentJobLogsResponses, GetDeploymentJobsData, GetDeploymentJobsErrors, GetDeploymentJobsResponses, GetDeploymentOperationsData, GetDeploymentOperationsErrors, GetDeploymentOperationsResponses, GetDeploymentOperationStatusData, GetDeploymentOperationStatusErrors, GetDeploymentOperationStatusResponses, GetDeploymentResponses, GetDeploymentTokenData, GetDeploymentTokenErrors, GetDeploymentTokenResponses, GetDiskStatusData, GetDiskStatusErrors, GetDiskStatusResponses, GetDnsChangesData, GetDnsChangesErrors, GetDnsChangesResponses, GetDnsProviderData, GetDnsProviderErrors, GetDnsProviderResponses, GetDomainByHostData, GetDomainByHostErrors, GetDomainByHostResponses, GetDomainByIdData, GetDomainByIdErrors, GetDomainByIdResponses, GetDomainByNameData, GetDomainByNameErrors, GetDomainByNameResponses, GetDomainData, GetDomainDnsRecordsData, GetDomainDnsRecordsErrors, GetDomainDnsRecordsResponses, GetDomainErrors, GetDomainOrderData, GetDomainOrderErrors, GetDomainOrderResponses, GetDomainResponses, GetEmailData, GetEmailErrors, GetEmailEventsData, GetEmailEventsErrors, GetEmailEventsResponses, GetEmailLinksData, GetEmailLinksErrors, GetEmailLinksResponses, GetEmailProviderData, GetEmailProviderErrors, GetEmailProviderResponses, GetEmailResponses, GetEmailStatsData, GetEmailStatsErrors, GetEmailStatsResponses, GetEmailTrackingData, GetEmailTrackingErrors, GetEmailTrackingResponses, GetEmailTrackingStatusData, GetEmailTrackingStatusErrors, GetEmailTrackingStatusResponses, GetEntityInfoData, GetEntityInfoErrors, GetEntityInfoResponses, GetEnvironmentCronsData, GetEnvironmentCronsErrors, GetEnvironmentCronsResponses, GetEnvironmentData, GetEnvironmentDomainsData, GetEnvironmentDomainsErrors, GetEnvironmentDomainsResponses, GetEnvironmentErrors, GetEnvironmentResponses, GetEnvironmentsData, GetEnvironmentsErrors, GetEnvironmentsResponses, GetEnvironmentVariablesData, GetEnvironmentVariablesErrors, GetEnvironmentVariablesResponses, GetEnvironmentVariableValueData, GetEnvironmentVariableValueErrors, GetEnvironmentVariableValueResponses, GetErrorDashboardStatsData, GetErrorDashboardStatsErrors, GetErrorDashboardStatsResponses, GetErrorEventData, GetErrorEventErrors, GetErrorEventResponses, GetErrorGroupData, GetErrorGroupErrors, GetErrorGroupResponses, GetErrorStatsData, GetErrorStatsErrors, GetErrorStatsResponses, GetErrorTimeSeriesData, GetErrorTimeSeriesErrors, GetErrorTimeSeriesResponses, GetEventDetailData, GetEventDetailErrors, GetEventDetailResponses, GetEventEntriesData, GetEventEntriesErrors, GetEventEntriesResponses, GetEventsCountData, GetEventsCountErrors, GetEventsCountResponses, GetEventsTimelineData, GetEventsTimelineErrors, GetEventsTimelineResponses, GetEventTypeBreakdownData, GetEventTypeBreakdownErrors, GetEventTypeBreakdownResponses, GetEventVisitorsData, GetEventVisitorsErrors, GetEventVisitorsResponses, GetExternalImageData, GetExternalImageErrors, GetExternalImageResponses, GetFileData, GetFileErrors, GetFileResponses, GetFlagData, GetFlagErrors, GetFlagResponses, GetFlagSnapshotData, GetFlagSnapshotErrors, GetFlagSnapshotResponses, GetFunnelMetricsData, GetFunnelMetricsErrors, GetFunnelMetricsResponses, GetGenaiTraceData, GetGenaiTraceErrors, GetGenaiTraceResponses, GetGeneralStatsData, GetGeneralStatsErrors, GetGeneralStatsResponses, GetGitProviderData, GetGitProviderErrors, GetGitProviderResponses, GetGlobalEventsData, GetGlobalEventsErrors, GetGlobalEventsResponses, GetGlobalEventStatsData, GetGlobalEventStatsErrors, GetGlobalEventStatsResponses, GetGlobalMcpData, GetGlobalMcpErrors, GetGlobalMcpResponses, GetGlobalSandboxStatusData, GetGlobalSandboxStatusErrors, GetGlobalSandboxStatusResponses, GetGlobalSkillData, GetGlobalSkillErrors, GetGlobalSkillResponses, GetGroupedPageMetricsData, GetGroupedPageMetricsErrors, GetGroupedPageMetricsResponses, GetHealthData, GetHealthErrors, GetHealthResponses, GetHourlyVisitsData, GetHourlyVisitsErrors, GetHourlyVisitsResponses, GetHttpChallengeDebugData, GetHttpChallengeDebugErrors, GetHttpChallengeDebugResponses, GetImportStatusData, GetImportStatusErrors, GetImportStatusResponses, GetIncidentData, GetIncidentErrors, GetIncidentResponses, GetIncidentUpdatesData, GetIncidentUpdatesErrors, GetIncidentUpdatesResponses, GetIpAccessControlData, GetIpAccessControlErrors, GetIpAccessControlResponses, GetIpGeolocationData, GetIpGeolocationErrors, GetIpGeolocationResponses, GetJoinTokenStatusData, GetJoinTokenStatusErrors, GetJoinTokenStatusResponses, GetLastDeploymentData, GetLastDeploymentErrors, GetLastDeploymentResponses, GetLatestScanData, GetLatestScanErrors, GetLatestScanResponses, GetLatestScansPerEnvironmentData, GetLatestScansPerEnvironmentErrors, GetLatestScansPerEnvironmentResponses, GetLiveVisitorsListData, GetLiveVisitorsListErrors, GetLiveVisitorsListResponses, GetLogContextData, GetLogContextErrors, GetLogContextResponses, GetMcpData, GetMcpErrors, GetMcpResponses, GetMetricsOverTimeData, GetMetricsOverTimeErrors, GetMetricsOverTimeResponses, GetMonitorData, GetMonitorErrors, GetMonitorResponses, GetNotificationProviderData, GetNotificationProviderErrors, GetNotificationProviderResponses, GetOnDemandCertStatusData, GetOnDemandCertStatusErrors, GetOnDemandCertStatusResponses, GetOrCreateDsnData, GetOrCreateDsnErrors, GetOrCreateDsnResponses, GetPageFlowData, GetPageFlowErrors, GetPageFlowResponses, GetPageHourlySessionsData, GetPageHourlySessionsErrors, GetPageHourlySessionsResponses, GetPagePathDetailData, GetPagePathDetailErrors, GetPagePathDetailResponses, GetPagePathsData, GetPagePathsErrors, GetPagePathsResponses, GetPagePathsSparklinesData, GetPagePathsSparklinesErrors, GetPagePathsSparklinesResponses, GetPagePathVisitorsData, GetPagePathVisitorsErrors, GetPagePathVisitorsResponses, GetPendingActionData, GetPendingActionErrors, GetPendingActionResponses, GetPerformanceMetricsData, GetPerformanceMetricsErrors, GetPerformanceMetricsResponses, GetPgUpgradeData, GetPgUpgradeErrors, GetPgUpgradeLogsData, GetPgUpgradeLogsErrors, GetPgUpgradeLogsResponses, GetPgUpgradeResponses, GetPipelineStatsData, GetPipelineStatsErrors, GetPipelineStatsResponses, GetPlatformInfoData, GetPlatformInfoErrors, GetPlatformInfoResponses, GetPostgresWalHealthData, GetPostgresWalHealthErrors, GetPostgresWalHealthResponses, GetPreferencesData, GetPreferencesErrors, GetPreferencesResponses, GetPreviewGatewayLogsData, GetPreviewGatewayLogsResponses, GetPreviewGatewaySettingsData, GetPreviewGatewaySettingsResponses, GetPreviewGatewayStatusData, GetPreviewGatewayStatusResponses, GetPricingData, GetPricingErrors, GetPricingResponses, GetPrivateIpData, GetPrivateIpErrors, GetPrivateIpResponses, GetProjectAlarmsSummaryData, GetProjectAlarmsSummaryErrors, GetProjectAlarmsSummaryResponses, GetProjectBySlugData, GetProjectBySlugErrors, GetProjectBySlugResponses, GetProjectData, GetProjectDeploymentsData, GetProjectDeploymentsErrors, GetProjectDeploymentsResponses, GetProjectErrors, GetProjectResponses, GetProjectsData, GetProjectsErrors, GetProjectServiceEnvironmentVariablesData, GetProjectServiceEnvironmentVariablesErrors, GetProjectServiceEnvironmentVariablesResponses, GetProjectSessionReplaysData, GetProjectSessionReplaysErrors, GetProjectSessionReplaysResponses, GetProjectsHealthData, GetProjectsHealthErrors, GetProjectsHealthResponses, GetProjectsMonitorHealthData, GetProjectsMonitorHealthErrors, GetProjectsMonitorHealthResponses, GetProjectsResponses, GetProjectStatisticsData, GetProjectStatisticsErrors, GetProjectStatisticsResponses, GetProjectTemplateData, GetProjectTemplateErrors, GetProjectTemplateResponses, GetPropertyBreakdownData, GetPropertyBreakdownErrors, GetPropertyBreakdownResponses, GetPropertyTimelineData, GetPropertyTimelineErrors, GetPropertyTimelineResponses, GetProviderConnectionsData, GetProviderConnectionsErrors, GetProviderConnectionsResponses, GetProviderMetadataData, GetProviderMetadataErrors, GetProviderMetadataResponses, GetProvidersMetadataData, GetProvidersMetadataErrors, GetProvidersMetadataResponses, GetProxyLogByIdData, GetProxyLogByIdErrors, GetProxyLogByIdResponses, GetProxyLogByRequestIdData, GetProxyLogByRequestIdErrors, GetProxyLogByRequestIdResponses, GetProxyLogsData, GetProxyLogsErrors, GetProxyLogsResponses, GetPublicBranchesData, GetPublicBranchesErrors, GetPublicBranchesResponses, GetPublicIpData, GetPublicIpErrors, GetPublicIpResponses, GetPublicRepositoryData, GetPublicRepositoryErrors, GetPublicRepositoryResponses, GetQuotaData, GetQuotaErrors, GetQuotaResponses, GetRecentActivityData, GetRecentActivityErrors, GetRecentActivityResponses, GetRemoteExternalImageData, GetRemoteExternalImageErrors, GetRemoteExternalImageResponses, GetRepositoryBranchesData, GetRepositoryBranchesErrors, GetRepositoryBranchesResponses, GetRepositoryByIdData, GetRepositoryByIdErrors, GetRepositoryByIdResponses, GetRepositoryByNameData, GetRepositoryByNameErrors, GetRepositoryByNameResponses, GetRepositoryPresetByNameData, GetRepositoryPresetByNameErrors, GetRepositoryPresetByNameResponses, GetRepositoryPresetLiveData, GetRepositoryPresetLiveErrors, GetRepositoryPresetLiveResponses, GetRepositoryTagsData, GetRepositoryTagsErrors, GetRepositoryTagsResponses, GetResolvedEnvironmentVariablesData, GetResolvedEnvironmentVariablesErrors, GetResolvedEnvironmentVariablesResponses, GetResolvedEnvironmentVariableValueData, GetResolvedEnvironmentVariableValueErrors, GetResolvedEnvironmentVariableValueResponses, GetRestoreCapabilitiesData, GetRestoreCapabilitiesErrors, GetRestoreCapabilitiesResponses, GetRestoreRunData, GetRestoreRunErrors, GetRestoreRunResponses, GetRouteData, GetRouteErrors, GetRouteResponses, GetRunData, GetRunErrors, GetRunResponses, GetRunWithLogsData, GetRunWithLogsErrors, GetRunWithLogsResponses, GetS3CredentialsData, GetS3CredentialsErrors, GetS3CredentialsResponses, GetS3SourceData, GetS3SourceErrors, GetS3SourceResponses, GetSandboxData, GetSandboxErrors, GetSandboxResponses, GetSandboxStatusData, GetSandboxStatusErrors, GetSandboxStatusResponses, GetScanByDeploymentData, GetScanByDeploymentErrors, GetScanByDeploymentResponses, GetScanData, GetScanErrors, GetScanResponses, GetScanVulnerabilitiesData, GetScanVulnerabilitiesErrors, GetScanVulnerabilitiesResponses, GetServiceBySlugData, GetServiceBySlugErrors, GetServiceBySlugResponses, GetServiceData, GetServiceEnvironmentVariableData, GetServiceEnvironmentVariableErrors, GetServiceEnvironmentVariableResponses, GetServiceEnvironmentVariablesData, GetServiceEnvironmentVariablesErrors, GetServiceEnvironmentVariablesResponses, GetServiceErrors, GetServiceHealthStatusData, GetServiceHealthStatusErrors, GetServiceHealthStatusResponses, GetServicePreviewEnvironmentVariableNamesData, GetServicePreviewEnvironmentVariableNamesErrors, GetServicePreviewEnvironmentVariableNamesResponses, GetServicePreviewEnvironmentVariablesMaskedData, GetServicePreviewEnvironmentVariablesMaskedErrors, GetServicePreviewEnvironmentVariablesMaskedResponses, GetServiceResponses, GetServiceRuntimeData, GetServiceRuntimeErrors, GetServiceRuntimeResponses, GetServiceStatsData, GetServiceStatsErrors, GetServiceStatsResponses, GetServiceTypeParametersData, GetServiceTypeParametersErrors, GetServiceTypeParametersResponses, GetServiceTypesData, GetServiceTypesErrors, GetServiceTypesResponses, GetSessionDetailsData, GetSessionDetailsErrors, GetSessionDetailsResponses, GetSessionEventsData, GetSessionEventsErrors, GetSessionEventsResponses, GetSessionLogsData, GetSessionLogsErrors, GetSessionLogsResponses, GetSessionReplayData, GetSessionReplayErrors, GetSessionReplayEventsData, GetSessionReplayEventsErrors, GetSessionReplayEventsResponses, GetSessionReplayResponses, GetSettingsData, GetSettingsErrors, GetSettingsResponses, GetSkillData, GetSkillErrors, GetSkillResponses, GetSlowQueriesData, GetSlowQueriesErrors, GetSlowQueriesResponses, GetStaticBundleData, GetStaticBundleErrors, GetStaticBundleResponses, GetStatusOverviewData, GetStatusOverviewErrors, GetStatusOverviewResponses, GetTagsByRepositoryIdData, GetTagsByRepositoryIdErrors, GetTagsByRepositoryIdResponses, GetTeamData, GetTeamErrors, GetTeamResponses, GetTimeBucketStatsData, GetTimeBucketStatsErrors, GetTimeBucketStatsResponses, GetTodayStatsData, GetTodayStatsErrors, GetTodayStatsResponses, GetTraceData, GetTraceErrors, GetTraceResponses, GetUnifiedTraceData, GetUnifiedTraceErrors, GetUnifiedTraceResponses, GetUniqueCountsData, GetUniqueCountsErrors, GetUniqueCountsResponses, GetUniqueEventsData, GetUniqueEventsErrors, GetUniqueEventsResponses, GetUpdateCapabilityData, GetUpdateCapabilityErrors, GetUpdateCapabilityResponses, GetUpdateStatusData, GetUpdateStatusErrors, GetUpdateStatusResponses, GetUptimeHistoryData, GetUptimeHistoryErrors, GetUptimeHistoryResponses, GetUsageByProviderData, GetUsageByProviderErrors, GetUsageByProviderResponses, GetUsageRecentData, GetUsageRecentErrors, GetUsageRecentResponses, GetUsageSummaryData, GetUsageSummaryErrors, GetUsageSummaryResponses, GetUsageTimeseriesData, GetUsageTimeseriesErrors, GetUsageTimeseriesResponses, GetUsageTopModelsData, GetUsageTopModelsErrors, GetUsageTopModelsResponses, GetVisitorByGuidData, GetVisitorByGuidErrors, GetVisitorByGuidResponses, GetVisitorByIdData, GetVisitorByIdErrors, GetVisitorByIdResponses, GetVisitorDetailsData, GetVisitorDetailsErrors, GetVisitorDetailsResponses, GetVisitorFacetsData, GetVisitorFacetsErrors, GetVisitorFacetsResponses, GetVisitorInfoData, GetVisitorInfoErrors, GetVisitorInfoResponses, GetVisitorJourneyData, GetVisitorJourneyErrors, GetVisitorJourneyResponses, GetVisitorsData, GetVisitorsErrors, GetVisitorSessionsData, GetVisitorSessionsErrors, GetVisitorSessionsResponses, GetVisitorsResponses, GetVisitorStatsData, GetVisitorStatsErrors, GetVisitorStatsResponses, GetWebhookData, GetWebhookErrors, GetWebhookResponses, GrantProjectAccessData, GrantProjectAccessErrors, GrantProjectAccessResponses, HandleGitProviderOauthCallbackData, HandleGitProviderOauthCallbackErrors, HasAnalyticsEventsData, HasAnalyticsEventsErrors, HasAnalyticsEventsResponses, HasErrorGroupsData, HasErrorGroupsErrors, HasErrorGroupsResponses, HasPerformanceMetricsData, HasPerformanceMetricsErrors, HasPerformanceMetricsResponses, ImportExternalServiceData, ImportExternalServiceErrors, ImportExternalServiceResponses, IngestLogsByPathData, IngestLogsByPathErrors, IngestLogsByPathResponses, IngestLogsData, IngestLogsErrors, IngestLogsResponses, IngestMetricsByPathData, IngestMetricsByPathErrors, IngestMetricsByPathResponses, IngestMetricsData, IngestMetricsErrors, IngestMetricsResponses, IngestSentryEnvelopeData, IngestSentryEnvelopeErrors, IngestSentryEnvelopeResponses, IngestSentryEventData, IngestSentryEventErrors, IngestSentryEventResponses, IngestTracesByPathData, IngestTracesByPathErrors, IngestTracesByPathResponses, IngestTracesData, IngestTracesErrors, IngestTracesResponses, InitSessionReplayData, InitSessionReplayErrors, InitSessionReplayResponses, InspectDropArchiveData, InspectDropArchiveErrors, InspectDropArchiveResponses, JobLogsData, JobLogsErrors, JobLogsResponses, JobStatusData, JobStatusErrors, JobStatusResponses, KillJobData, KillJobErrors, KillJobResponses, KvDelData, KvDelErrors, KvDelResponses, KvDisableData, KvDisableErrors, KvDisableResponses, KvEnableData, KvEnableErrors, KvEnableResponses, KvExpireData, KvExpireErrors, KvExpireResponses, KvGetData, KvGetErrors, KvGetResponses, KvIncrData, KvIncrErrors, KvIncrResponses, KvKeysData, KvKeysErrors, KvKeysResponses, KvSetData, KvSetErrors, KvSetResponses, KvStatusData, KvStatusErrors, KvStatusResponses, KvTtlData, KvTtlErrors, KvTtlResponses, KvUpdateData, KvUpdateErrors, KvUpdateResponses, LatestRunForSourceData, LatestRunForSourceErrors, LatestRunForSourceResponses, LinkCustomDomainToCertificateData, LinkCustomDomainToCertificateErrors, LinkCustomDomainToCertificateResponses, LinkServiceToProjectData, LinkServiceToProjectErrors, LinkServiceToProjectResponses, ListAgentRunsData, ListAgentRunsErrors, ListAgentRunsResponses, ListAgentsData, ListAgentsErrors, ListAgentsResponses, ListAiProvidersData, ListAiProvidersErrors, ListAiProvidersResponses, ListAlertRulesData, ListAlertRulesErrors, ListAlertRulesResponses, ListAlertsData, ListAlertsErrors, ListAlertsResponses, ListAllConversationsData, ListAllConversationsErrors, ListAllConversationsResponses, ListAllRunsData, ListAllRunsErrors, ListAllRunsResponses, ListApiKeysData, ListApiKeysErrors, ListApiKeysResponses, ListAuditLogsData, ListAuditLogsErrors, ListAuditLogsResponses, ListAvailableContainersData, ListAvailableContainersErrors, ListAvailableContainersResponses, ListBackupAlertsData, ListBackupAlertsErrors, ListBackupAlertsResponses, ListBackupChildrenData, ListBackupChildrenErrors, ListBackupChildrenResponses, ListBackupSchedulesData, ListBackupSchedulesErrors, ListBackupSchedulesResponses, ListBackupsForScheduleData, ListBackupsForScheduleErrors, ListBackupsForScheduleResponses, ListCommitsByRepositoryIdData, ListCommitsByRepositoryIdErrors, ListCommitsByRepositoryIdResponses, ListConnectionsData, ListConnectionsErrors, ListConnectionsResponses, ListContainersAtPathData, ListContainersAtPathErrors, ListContainersAtPathResponses, ListContainersData, ListContainersErrors, ListContainersResponses, ListConversationsData, ListConversationsErrors, ListConversationsResponses, ListCustomDomainsForProjectData, ListCustomDomainsForProjectErrors, ListCustomDomainsForProjectResponses, ListDashboardsData, ListDashboardsErrors, ListDashboardsResponses, ListDeliveriesData, ListDeliveriesErrors, ListDeliveriesResponses, ListDeploymentContainerLogsData, ListDeploymentContainerLogsErrors, ListDeploymentContainerLogsResponses, ListDeploymentTokensData, ListDeploymentTokensErrors, ListDeploymentTokensResponses, ListDnsProvidersData, ListDnsProvidersErrors, ListDnsProvidersResponses, ListDomainsData, ListDomainsErrors, ListDomainsResponses, ListDsnsData, ListDsnsErrors, ListDsnsResponses, ListEmailDomainsData, ListEmailDomainsErrors, ListEmailDomainsResponses, ListEmailProvidersData, ListEmailProvidersErrors, ListEmailProvidersResponses, ListEmailsData, ListEmailsErrors, ListEmailsResponses, ListEnrollmentTokensData, ListEnrollmentTokensErrors, ListEnrollmentTokensResponses, ListEntitiesData, ListEntitiesErrors, ListEntitiesResponses, ListErrorEventsData, ListErrorEventsErrors, ListErrorEventsResponses, ListErrorGroupsData, ListErrorGroupsErrors, ListErrorGroupsResponses, ListEventsData, ListEventsResponses, ListEventTypesData, ListEventTypesResponses, ListExternalImagesData, ListExternalImagesErrors, ListExternalImagesResponses, ListExternalPluginsData, ListExternalPluginsErrors, ListExternalPluginsResponses, ListExternalServiceBackupsData, ListExternalServiceBackupsErrors, ListExternalServiceBackupsResponses, ListFlagsData, ListFlagsErrors, ListFlagsResponses, ListFunnelsData, ListFunnelsErrors, ListFunnelsResponses, ListGitProvidersData, ListGitProvidersErrors, ListGitProvidersResponses, ListGlobalMcpsData, ListGlobalMcpsErrors, ListGlobalMcpsResponses, ListGlobalSkillsData, ListGlobalSkillsErrors, ListGlobalSkillsResponses, ListIncidentsData, ListIncidentsErrors, ListIncidentsResponses, ListInsightsData, ListInsightsErrors, ListInsightsResponses, ListIpAccessControlData, ListIpAccessControlErrors, ListIpAccessControlResponses, ListJobsData, ListJobsErrors, ListJobsResponses, ListKnownAiAgentsData, ListKnownAiAgentsErrors, ListKnownAiAgentsResponses, ListManagedDomainsData, ListManagedDomainsErrors, ListManagedDomainsResponses, ListMcpsData, ListMcpsErrors, ListMcpsResponses, ListMetricLabelKeysData, ListMetricLabelKeysErrors, ListMetricLabelKeysResponses, ListMetricLabelValuesData, ListMetricLabelValuesErrors, ListMetricLabelValuesResponses, ListMetricNamesData, ListMetricNamesErrors, ListMetricNamesResponses, ListModelsData, ListModelsErrors, ListModelsResponses, ListMonitorsData, ListMonitorsErrors, ListMonitorsResponses, ListNotificationProvidersData, ListNotificationProvidersErrors, ListNotificationProvidersResponses, ListOidcProvidersData, ListOidcProvidersResponses, ListOidcProviderUsersData, ListOidcProviderUsersErrors, ListOidcProviderUsersResponses, ListOidcRoleMappingsData, ListOidcRoleMappingsResponses, ListOnDemandCertsData, ListOnDemandCertsErrors, ListOnDemandCertsResponses, ListOrdersData, ListOrdersErrors, ListOrdersResponses, ListPeersData, ListPeersErrors, ListPeersResponses, ListPendingActionsData, ListPendingActionsErrors, ListPendingActionsResponses, ListPgUpgradesData, ListPgUpgradesErrors, ListPgUpgradesResponses, ListPresetsData, ListPresetsErrors, ListPresetsResponses, ListProjectAccessData, ListProjectAccessErrors, ListProjectAccessResponses, ListProjectAlarmsData, ListProjectAlarmsErrors, ListProjectAlarmsResponses, ListProjectScansData, ListProjectScansErrors, ListProjectScansResponses, ListProjectSecretsData, ListProjectSecretsErrors, ListProjectSecretsResponses, ListProjectServicesData, ListProjectServicesErrors, ListProjectServicesResponses, ListProjectTemplatesData, ListProjectTemplatesErrors, ListProjectTemplatesResponses, ListProjectTemplateTagsData, ListProjectTemplateTagsErrors, ListProjectTemplateTagsResponses, ListProviderKeysData, ListProviderKeysErrors, ListProviderKeysResponses, ListProviderZonesData, ListProviderZonesErrors, ListProviderZonesResponses, ListPublicProvidersData, ListPublicProvidersResponses, ListReleaseFilesData, ListReleaseFilesErrors, ListReleaseFilesResponses, ListReleasesData, ListReleasesErrors, ListReleasesResponses, ListRemoteExternalImagesData, ListRemoteExternalImagesErrors, ListRemoteExternalImagesResponses, ListRepositoriesByConnectionData, ListRepositoriesByConnectionErrors, ListRepositoriesByConnectionResponses, ListRepositoriesByProviderData, ListRepositoriesByProviderErrors, ListRepositoriesByProviderResponses, ListRestoreRunsForServiceData, ListRestoreRunsForServiceResponses, ListRootContainersData, ListRootContainersErrors, ListRootContainersResponses, ListRoutesData, ListRoutesErrors, ListRoutesResponses, ListS3SourcesData, ListS3SourcesErrors, ListS3SourcesResponses, ListSandboxesData, ListSandboxesResponses, ListScheduleRunJobsData, ListScheduleRunJobsErrors, ListScheduleRunJobsResponses, ListScheduleRunsData, ListScheduleRunsErrors, ListScheduleRunsResponses, ListScheduleServicesData, ListScheduleServicesErrors, ListScheduleServicesResponses, ListSecretsData, ListSecretsErrors, ListSecretsResponses, ListServiceHealthStatusesData, ListServiceHealthStatusesErrors, ListServiceHealthStatusesResponses, ListServiceProjectsData, ListServiceProjectsErrors, ListServiceProjectsResponses, ListServiceSchedulesData, ListServiceSchedulesErrors, ListServiceSchedulesResponses, ListServicesData, ListServicesErrors, ListServicesResponses, ListSkillsData, ListSkillsErrors, ListSkillsResponses, ListSourceBackupsData, ListSourceBackupsErrors, ListSourceBackupsResponses, ListSourceFilesData, ListSourceFilesErrors, ListSourceFilesResponses, ListSourceMapsData, ListSourceMapsErrors, ListSourceMapsResponses, ListSourcesData, ListSourcesErrors, ListSourcesResponses, ListStaticBundlesData, ListStaticBundlesErrors, ListStaticBundlesResponses, ListSyncedRepositoriesData, ListSyncedRepositoriesErrors, ListSyncedRepositoriesResponses, ListTeamMembersData, ListTeamMembersErrors, ListTeamMembersResponses, ListTeamProjectsData, ListTeamProjectsErrors, ListTeamProjectsResponses, ListTeamsData, ListTeamsErrors, ListTeamsResponses, ListUsersData, ListUsersErrors, ListUsersResponses, ListWebhooksData, ListWebhooksErrors, ListWebhooksResponses, LoginData, LoginErrors, LoginResponses, LogoutData, LogoutErrors, LogoutResponses, LookupDnsARecordsData, LookupDnsARecordsErrors, LookupDnsARecordsResponses, MintEnrollmentTokenData, MintEnrollmentTokenErrors, MintEnrollmentTokenResponses, MkdirData, MkdirErrors, MkdirResponses, NodeHeartbeatData, NodeHeartbeatErrors, NodeHeartbeatResponses, NodeMetricsGetRangeData, NodeMetricsGetRangeErrors, NodeMetricsGetRangeResponses, ObservabilityFullEventData, ObservabilityFullEventErrors, ObservabilityFullEventResponses, ObservabilityListEventsData, ObservabilityListEventsErrors, ObservabilityListEventsResponses, OidcCallbackData, PatchAdminGateData, PatchAdminGateErrors, PatchAdminGateResponses, PatchPreviewGatewaySettingsData, PatchPreviewGatewaySettingsResponses, PauseDeploymentData, PauseDeploymentErrors, PauseDeploymentResponses, PauseSandboxData, PauseSandboxErrors, PauseSandboxResponses, PlanRestoreData, PlanRestoreErrors, PlanRestoreResponses, PostDnsAckData, PostDnsAckErrors, PostDnsAckResponses, PreviewAlertData, PreviewAlertErrors, PreviewAlertResponses, PreviewFunnelMetricsData, PreviewFunnelMetricsErrors, PreviewFunnelMetricsResponses, PreviewHostnameModeData, PreviewHostnameModeErrors, PreviewHostnameModeResponses, PromoteClusterMemberData, PromoteClusterMemberErrors, PromoteClusterMemberResponses, PromoteDeploymentData, PromoteDeploymentErrors, PromoteDeploymentResponses, ProvisionDomainData, ProvisionDomainErrors, ProvisionDomainResponses, PurgeProjectLogsData, PurgeProjectLogsErrors, PurgeProjectLogsResponses, PushExternalImageData, PushExternalImageErrors, PushExternalImageResponses, QueryDataData, QueryDataErrors, QueryDataResponses, QueryGenaiTracesData, QueryGenaiTracesErrors, QueryGenaiTracesResponses, QueryLogsData, QueryLogsErrors, QueryLogsResponses, QueryMetricsData, QueryMetricsErrors, QueryMetricsResponses, QueryTracesData, QueryTracesErrors, QueryTracesResponses, QueryTraceSummariesData, QueryTraceSummariesErrors, QueryTraceSummariesResponses, ReadFileData, ReadFileErrors, ReadFileResponses, ReAnalyzeData, ReAnalyzeErrors, ReAnalyzeResponses, RebuildSandboxImageData, RebuildSandboxImageErrors, RebuildSandboxImageResponses, RecordConsoleEventData, RecordConsoleEventErrors, RecordConsoleEventResponses, RecordEventMetricsData, RecordEventMetricsErrors, RecordEventMetricsResponses, RecordFlagExposureData, RecordFlagExposureErrors, RecordFlagExposureResponses, RecordSpeedMetricsData, RecordSpeedMetricsErrors, RecordSpeedMetricsResponses, RefreshRouteTableData, RefreshRouteTableErrors, RefreshRouteTableResponses, RegenerateDsnData, RegenerateDsnErrors, RegenerateDsnResponses, RegisterExternalImageData, RegisterExternalImageErrors, RegisterExternalImageResponses, RegisterNodeData, RegisterNodeErrors, RegisterNodeResponses, ReinstallGitlabWebhookData, ReinstallGitlabWebhookErrors, ReinstallGitlabWebhookResponses, RejectPendingActionData, RejectPendingActionErrors, RejectPendingActionResponses, ReloadPluginsData, ReloadPluginsErrors, ReloadPluginsResponses, RemoveClusterMemberData, RemoveClusterMemberErrors, RemoveClusterMemberResponses, RemoveManagedDomainData, RemoveManagedDomainErrors, RemoveManagedDomainResponses, RemoveRoleData, RemoveRoleErrors, RemoveRoleResponses, RemoveTeamMemberData, RemoveTeamMemberErrors, RemoveTeamMemberResponses, RenameConversationData, RenameConversationErrors, RenameConversationResponses, RenewDomainData, RenewDomainErrors, RenewDomainResponses, RequestPasswordResetData, RequestPasswordResetErrors, RequestPasswordResetResponses, ResetPasswordData, ResetPasswordErrors, ResetPasswordResponses, ResizeSandboxData, ResizeSandboxErrors, ResizeSandboxResponses, ResolveAlarmData, ResolveAlarmErrors, ResolveAlarmResponses, RestartContainerData, RestartContainerErrors, RestartContainerResponses, RestartPreviewGatewayData, RestartPreviewGatewayResponses, RestartSandboxData, RestartSandboxErrors, RestartSandboxResponses, RestoreFlagData, RestoreFlagErrors, RestoreFlagResponses, RestoreUserData, RestoreUserErrors, RestoreUserResponses, ResumeDeploymentData, ResumeDeploymentErrors, ResumeDeploymentResponses, ResumeSandboxData, ResumeSandboxErrors, ResumeSandboxResponses, RetryClusterData, RetryClusterErrors, RetryClusterResponses, RetryDeliveryData, RetryDeliveryErrors, RetryDeliveryResponses, RetryPgUpgradeData, RetryPgUpgradeErrors, RetryPgUpgradeResponses, RetryRunData, RetryRunErrors, RetryRunResponses, RevealGlobalMcpConfigData, RevealGlobalMcpConfigErrors, RevealGlobalMcpConfigResponses, RevealMcpConfigData, RevealMcpConfigErrors, RevealMcpConfigResponses, RevealNotificationProviderConfigData, RevealNotificationProviderConfigErrors, RevealNotificationProviderConfigResponses, RevealServiceParameterData, RevealServiceParameterErrors, RevealServiceParameterResponses, RevenueCreateIntegrationData, RevenueCreateIntegrationErrors, RevenueCreateIntegrationResponses, RevenueDeleteIntegrationData, RevenueDeleteIntegrationResponses, RevenueGlobalEventsData, RevenueGlobalEventsResponses, RevenueImportInvoicesCsvData, RevenueImportInvoicesCsvErrors, RevenueImportInvoicesCsvResponses, RevenueImportSubscriptionsCsvData, RevenueImportSubscriptionsCsvErrors, RevenueImportSubscriptionsCsvResponses, RevenueListIntegrationsData, RevenueListIntegrationsResponses, RevenueListProvidersData, RevenueListProvidersResponses, RevenueMetricsCustomersData, RevenueMetricsCustomersResponses, RevenueMetricsGlobalMrrData, RevenueMetricsGlobalMrrResponses, RevenueMetricsGlobalSummaryData, RevenueMetricsGlobalSummaryResponses, RevenueMetricsMrrData, RevenueMetricsMrrResponses, RevenueMetricsSummaryData, RevenueMetricsSummaryResponses, RevenueRecentEventsData, RevenueRecentEventsResponses, RevenueRotateTokenData, RevenueRotateTokenResponses, RevenueUpdateConfigData, RevenueUpdateConfigErrors, RevenueUpdateConfigResponses, RevenueUpdateSecretData, RevenueUpdateSecretErrors, RevenueUpdateSecretResponses, RevokeDsnData, RevokeDsnErrors, RevokeDsnResponses, RevokeEnrollmentTokenData, RevokeEnrollmentTokenErrors, RevokeEnrollmentTokenResponses, RevokeJoinTokenData, RevokeJoinTokenErrors, RevokeJoinTokenResponses, RevokeProjectAccessData, RevokeProjectAccessErrors, RevokeProjectAccessResponses, RollbackPgUpgradeData, RollbackPgUpgradeErrors, RollbackPgUpgradeResponses, RollbackToDeploymentData, RollbackToDeploymentErrors, RollbackToDeploymentResponses, RootfsGcData, RootfsGcResponses, RootfsReportData, RootfsReportResponses, RotateApiKeyData, RotateApiKeyErrors, RotateApiKeyResponses, RotateDeploymentTokenData, RotateDeploymentTokenErrors, RotateDeploymentTokenResponses, RunBackupForSourceData, RunBackupForSourceErrors, RunBackupForSourceResponses, RunConnectionHealthCheckData, RunConnectionHealthCheckErrors, RunConnectionHealthCheckResponses, RunExternalServiceBackupData, RunExternalServiceBackupErrors, RunExternalServiceBackupResponses, RunScheduleNowData, RunScheduleNowErrors, RunScheduleNowResponses, SandboxCreatePreviewLinkData, SandboxCreatePreviewLinkErrors, SandboxCreatePreviewLinkResponses, SaveAgentTokenData, SaveAgentTokenErrors, SaveAgentTokenResponses, SaveAiProviderCredentialData, SaveAiProviderCredentialErrors, SaveAiProviderCredentialResponses, SearchLogsData, SearchLogsErrors, SearchLogsResponses, SendEmailData, SendEmailErrors, SendEmailResponses, SendMessageData, SendMessageErrors, SendMessageResponses, SetDefaultS3SourceData, SetDefaultS3SourceErrors, SetDefaultS3SourceResponses, SetFlagEnvironmentData, SetFlagEnvironmentErrors, SetFlagEnvironmentResponses, SetPreviewPasswordData, SetPreviewPasswordErrors, SetPreviewPasswordResponses, SetupDnsChallengeData, SetupDnsChallengeErrors, SetupDnsChallengeResponses, SetupDnsData, SetupDnsErrors, SetupDnsResponses, SetupEmailTrackingData, SetupEmailTrackingErrors, SetupEmailTrackingResponses, SetupMfaData, SetupMfaErrors, SetupMfaResponses, SleepEnvironmentData, SleepEnvironmentErrors, SleepEnvironmentResponses, SmokeTestAgentData, SmokeTestAgentErrors, SmokeTestAgentResponses, SourceSandboxData, SourceSandboxErrors, SourceSandboxResponses, StartAnalysisData, StartAnalysisErrors, StartAnalysisResponses, StartContainerData, StartContainerErrors, StartContainerResponses, StartFixData, StartFixErrors, StartFixResponses, StartGitProviderOauthData, StartGitProviderOauthErrors, StartOidcLoginBySlugData, StartOidcLoginBySlugErrors, StartPgUpgradeData, StartPgUpgradeErrors, StartPgUpgradeResponses, StartRestoreData, StartRestoreErrors, StartRestoreResponses, StartServiceData, StartServiceErrors, StartServiceResponses, StartUpdateData, StartUpdateErrors, StartUpdateResponses, StatPathData, StatPathErrors, StatPathResponses, StopContainerData, StopContainerErrors, StopContainerResponses, StopSandboxData, StopSandboxErrors, StopSandboxResponses, StopServiceData, StopServiceErrors, StopServiceResponses, StreamContainerMetricsData, StreamContainerMetricsErrors, StreamContainerMetricsResponses, StreamEventsData, StreamEventsErrors, StreamEventsResponses, StreamRunEventsData, StreamRunEventsErrors, StreamRunEventsResponses, SyncRepositoriesData, SyncRepositoriesErrors, SyncRepositoriesResponses, TailDeploymentJobLogsData, TailDeploymentJobLogsErrors, TailLogsData, TailLogsErrors, TailLogsResponses, TeardownDeploymentData, TeardownDeploymentErrors, TeardownDeploymentResponses, TeardownEnvironmentData, TeardownEnvironmentErrors, TeardownEnvironmentResponses, TestNotificationProviderData, TestNotificationProviderErrors, TestNotificationProviderResponses, TestOidcProviderData, TestOidcProviderResponses, TestProviderConnectionData, TestProviderConnectionErrors, TestProviderConnectionResponses, TestProviderData, TestProviderErrors, TestProviderKeyByIdData, TestProviderKeyByIdErrors, TestProviderKeyByIdResponses, TestProviderKeyInlineData, TestProviderKeyInlineErrors, TestProviderKeyInlineResponses, TestProviderResponses, TestS3ConnectionPreviewData, TestS3ConnectionPreviewErrors, TestS3ConnectionPreviewResponses, TestS3SourceConnectionData, TestS3SourceConnectionErrors, TestS3SourceConnectionResponses, TrackClickData, TrackClickErrors, TrackOpenData, TrackOpenErrors, TrackOpenResponses, TriggerAgentData, TriggerAgentErrors, TriggerAgentResponses, TriggerProjectPipelineData, TriggerProjectPipelineErrors, TriggerProjectPipelineResponses, TriggerScanData, TriggerScanErrors, TriggerScanResponses, TriggerServiceHealthCheckData, TriggerServiceHealthCheckErrors, TriggerServiceHealthCheckResponses, TriggerWeeklyDigestData, TriggerWeeklyDigestErrors, TriggerWeeklyDigestResponses, UnlinkServiceFromProjectData, UnlinkServiceFromProjectErrors, UnlinkServiceFromProjectResponses, UpdateAgentData, UpdateAgentErrors, UpdateAgentResponses, UpdateAiProviderData, UpdateAiProviderErrors, UpdateAiProviderResponses, UpdateAlertData, UpdateAlertErrors, UpdateAlertResponses, UpdateAlertRuleData, UpdateAlertRuleErrors, UpdateAlertRuleResponses, UpdateApiKeyData, UpdateApiKeyErrors, UpdateApiKeyResponses, UpdateAutomaticDeployData, UpdateAutomaticDeployErrors, UpdateAutomaticDeployResponses, UpdateBackupScheduleData, UpdateBackupScheduleErrors, UpdateBackupScheduleResponses, UpdateCloudflareProviderData, UpdateCloudflareProviderErrors, UpdateCloudflareProviderResponses, UpdateConnectionTokenData, UpdateConnectionTokenErrors, UpdateConnectionTokenResponses, UpdateCustomDomainData, UpdateCustomDomainErrors, UpdateCustomDomainResponses, UpdateDashboardData, UpdateDashboardErrors, UpdateDashboardResponses, UpdateDeploymentTokenData, UpdateDeploymentTokenErrors, UpdateDeploymentTokenResponses, UpdateEmailProviderData, UpdateEmailProviderErrors, UpdateEmailProviderResponses, UpdateEnvironmentSettingsData, UpdateEnvironmentSettingsErrors, UpdateEnvironmentSettingsResponses, UpdateEnvironmentSubdomainData, UpdateEnvironmentSubdomainErrors, UpdateEnvironmentSubdomainResponses, UpdateEnvironmentVariableData, UpdateEnvironmentVariableErrors, UpdateEnvironmentVariableResponses, UpdateErrorGroupData, UpdateErrorGroupErrors, UpdateErrorGroupResponses, UpdateFlagData, UpdateFlagErrors, UpdateFlagResponses, UpdateFunnelData, UpdateFunnelErrors, UpdateFunnelResponses, UpdateGitProviderCredentialsData, UpdateGitProviderCredentialsErrors, UpdateGitProviderCredentialsResponses, UpdateGitSettingsData, UpdateGitSettingsErrors, UpdateGitSettingsResponses, UpdateGlobalMcpData, UpdateGlobalMcpErrors, UpdateGlobalMcpResponses, UpdateGlobalSkillData, UpdateGlobalSkillErrors, UpdateGlobalSkillResponses, UpdateIncidentStatusData, UpdateIncidentStatusErrors, UpdateIncidentStatusResponses, UpdateIpAccessControlData, UpdateIpAccessControlErrors, UpdateIpAccessControlResponses, UpdateManagedDomainData, UpdateManagedDomainErrors, UpdateManagedDomainResponses, UpdateMcpData, UpdateMcpErrors, UpdateMcpResponses, UpdateNotificationEmailProviderData, UpdateNotificationEmailProviderErrors, UpdateNotificationEmailProviderResponses, UpdateNotificationProviderData, UpdateNotificationProviderErrors, UpdateNotificationProviderResponses, UpdateOidcProviderData, UpdateOidcProviderResponses, UpdatePreferencesData, UpdatePreferencesErrors, UpdatePreferencesResponses, UpdateProjectData, UpdateProjectDeploymentConfigData, UpdateProjectDeploymentConfigErrors, UpdateProjectDeploymentConfigResponses, UpdateProjectErrors, UpdateProjectResponses, UpdateProjectSecretData, UpdateProjectSecretErrors, UpdateProjectSecretResponses, UpdateProjectSettingsData, UpdateProjectSettingsErrors, UpdateProjectSettingsResponses, UpdateProviderData, UpdateProviderErrors, UpdateProviderKeyData, UpdateProviderKeyErrors, UpdateProviderKeyResponses, UpdateProviderResponses, UpdateRouteData, UpdateRouteErrors, UpdateRouteResponses, UpdateS3SourceData, UpdateS3SourceErrors, UpdateS3SourceResponses, UpdateSelfData, UpdateSelfErrors, UpdateSelfResponses, UpdateServiceData, UpdateServiceErrors, UpdateServiceResourcesData, UpdateServiceResourcesErrors, UpdateServiceResourcesResponses, UpdateServiceResponses, UpdateSessionDurationData, UpdateSessionDurationErrors, UpdateSessionDurationResponses, UpdateSettingsData, UpdateSettingsErrors, UpdateSettingsResponses, UpdateSkillData, UpdateSkillErrors, UpdateSkillResponses, UpdateSlackProviderData, UpdateSlackProviderErrors, UpdateSlackProviderResponses, UpdateSpeedMetricsData, UpdateSpeedMetricsErrors, UpdateSpeedMetricsResponses, UpdateTeamData, UpdateTeamErrors, UpdateTeamMemberRoleData, UpdateTeamMemberRoleErrors, UpdateTeamMemberRoleResponses, UpdateTeamResponses, UpdateUserData, UpdateUserErrors, UpdateUserResponses, UpdateWebhookData, UpdateWebhookErrors, UpdateWebhookProviderData, UpdateWebhookProviderErrors, UpdateWebhookProviderResponses, UpdateWebhookResponses, UpgradePreviewGatewayData, UpgradePreviewGatewayResponses, UpgradeServiceData, UpgradeServiceErrors, UpgradeServiceResponses, UploadGlobalSkillData, UploadGlobalSkillErrors, UploadGlobalSkillResponses, UploadReleaseFileData, UploadReleaseFileErrors, UploadReleaseFileResponses, UploadSkillData, UploadSkillErrors, UploadSkillResponses, UploadSourceFileData, UploadSourceFileErrors, UploadSourceFileResponses, UploadSourceMapData, UploadSourceMapErrors, UploadSourceMapResponses, UploadStaticBundleData, UploadStaticBundleErrors, UploadStaticBundleResponses, UpsertSecretData, UpsertSecretErrors, UpsertSecretResponses, ValidateConnectionData, ValidateConnectionErrors, ValidateConnectionResponses, ValidateEmailData, ValidateEmailErrors, ValidateEmailResponses, VerifyAndEnableMfaData, VerifyAndEnableMfaErrors, VerifyAndEnableMfaResponses, VerifyDomainData, VerifyDomainErrors, VerifyDomainResponses, VerifyEmailData, VerifyEmailErrors, VerifyEmailResponses, VerifyManagedDomainData, VerifyManagedDomainErrors, VerifyManagedDomainResponses, VerifyMfaChallengeData, VerifyMfaChallengeErrors, VerifyMfaChallengeResponses, VerifyStepUpData, VerifyStepUpErrors, VerifyStepUpResponses, WakeEnvironmentData, WakeEnvironmentErrors, WakeEnvironmentResponses, WebhookTriggerData, WebhookTriggerErrors, WebhookTriggerResponses, WorkflowDryRunData, WorkflowDryRunErrors, WorkflowDryRunResponses, WriteFileData, WriteFileErrors, WriteFileResponses, WriteFilesData, WriteFilesErrors, WriteFilesResponses } from './types.gen'; export type Options = Options2 & { /** @@ -750,6 +750,15 @@ export const startOidcLoginBySlug = (optio export const listPublicProviders = (options?: Options): RequestResult => (options?.client ?? client).get({ url: '/auth/oidc/providers', ...options }); +export const changeRequiredPassword = (options: Options): RequestResult => (options.client ?? client).post({ + url: '/auth/password-change-required', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); + export const requestPasswordReset = (options: Options): RequestResult => (options.client ?? client).post({ url: '/auth/password-reset/request', ...options, @@ -6485,9 +6494,14 @@ export const getUniqueCounts = (options: O * deployed later using the deploy/static endpoint. */ export const uploadStaticBundle = (options: Options): RequestResult => (options.client ?? client).post({ + ...formDataBodySerializer, security: [{ scheme: 'bearer', type: 'http' }], url: '/projects/{project_id}/upload/static', - ...options + ...options, + headers: { + 'Content-Type': null, + ...options.headers + } }); export const listProjectScans = (options: Options): RequestResult => (options.client ?? client).get({ @@ -7222,6 +7236,33 @@ export const downloadGlobalSkillArchive = ...options }); +/** + * Report whether a release update can be applied from the console. + */ +export const getUpdateCapability = (options?: Options): RequestResult => (options?.client ?? client).get({ + security: [{ scheme: 'bearer', type: 'http' }], + url: '/settings/update', + ...options +}); + +/** + * Install a release and restart the server. + * + * Returns as soon as the attempt is accepted: the download and swap run in the + * background and the process then exits so its supervisor restarts it on the + * new binary. Poll `GET /settings/update` for progress — after the restart, + * `last_attempt` carries the outcome. + */ +export const startUpdate = (options: Options): RequestResult => (options.client ?? client).post({ + security: [{ scheme: 'bearer', type: 'http' }], + url: '/settings/update', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); + /** * Report whether a newer temps release is available for this install. */ diff --git a/apps/temps-cli/src/api/types.gen.ts b/apps/temps-cli/src/api/types.gen.ts index ecd8daf63..aadd5314d 100644 --- a/apps/temps-cli/src/api/types.gen.ts +++ b/apps/temps-cli/src/api/types.gen.ts @@ -1094,6 +1094,16 @@ export type AppSettings = { require_mfa_for_admins?: boolean; screenshots?: ScreenshotSettings; security_headers?: SecurityHeadersSettings; + /** + * One-click "Update now" from the console. Enabled by default; an admin + * can turn it off here to keep upgrades on the CLI/config-management path. + * + * This is the *soft* switch — it is stored in the database, so whoever can + * write settings can also turn it back on. Operators who need an upgrade + * path that no console session can re-open should start the server with + * `--disable-self-update`, which wins over this field unconditionally. + */ + self_update?: SelfUpdateSettings; /** * Set to `true` by `temps setup` (all modes) once initial configuration * has been applied. The web onboarding wizard reads this from the server @@ -1178,6 +1188,13 @@ export type AppSettingsResponse = { require_mfa_for_admins: boolean; screenshots: ScreenshotSettings; security_headers: SecurityHeadersSettings; + /** + * Whether admins may apply a release from the console. This is the + * database-backed toggle only — a server started with + * `--disable-self-update` refuses regardless of what this says, which + * `GET /settings/update` reports as the authoritative answer. + */ + self_update: SelfUpdateSettings; /** * Whether `temps setup` has been run at least once. The web onboarding * wizard checks this field on load and skips itself when true. @@ -1334,7 +1351,10 @@ export type AuthFlavorDto = { export type AuthResponse = { message: string; + mfa_enrollment_required: boolean; mfa_required: boolean; + mfa_setup?: null | MfaSetupResponse; + password_change_required: boolean; success: boolean; user_id?: number | null; }; @@ -3927,6 +3947,7 @@ export type CreateTeamRequest = { export type CreateUserRequest = { email?: string | null; + must_change_password?: boolean; password?: string | null; roles: Array; username: string; @@ -4737,6 +4758,19 @@ export type DeploymentMetadata = { * ID of the deployment this was rolled back from (if applicable) */ rolledBackFromId?: number | null; + /** + * Uploaded source archive content type. + */ + sourceBundleContentType?: string | null; + /** + * Uploaded source archive ID. Source archives are extracted before the + * regular preset build pipeline and do not require Git metadata. + */ + sourceBundleId?: number | null; + /** + * Uploaded source archive path in the Temps data directory. + */ + sourceBundlePath?: string | null; /** * Static bundle content type (for proper extraction: application/gzip or application/zip) */ @@ -12379,6 +12413,12 @@ export type PropertyBreakdownQuery = { * Property column to group by */ group_by: PropertyColumn; + /** + * Include crawler/bot traffic (default: false). Off by default so the + * breakdown percentages share a denominator with the headline counts, + * which always exclude crawlers. + */ + include_crawlers?: boolean | null; /** * Maximum number of results to return (default: 20, max: 100) */ @@ -12435,6 +12475,11 @@ export type PropertyTimelineQuery = { * Property column to group by */ group_by: PropertyColumn; + /** + * Include crawler/bot traffic (default: false). See + * [`PropertyBreakdownQuery::include_crawlers`]. + */ + include_crawlers?: boolean | null; /** * Start date for the query range */ @@ -13274,6 +13319,18 @@ export type RequestRow = { user_agent?: string | null; }; +export type RequiredPasswordChangeRequest = { + new_password: string; +}; + +export type RequiredPasswordChangeResponse = { + message: string; + mfa_enrollment_required: boolean; + mfa_setup?: null | MfaSetupResponse; + success: boolean; + user_id: number; +}; + export type ResetPasswordRequest = { new_password: string; token: string; @@ -13782,6 +13839,7 @@ export type RouteUser = { id: number; image: string; mfa_enabled: boolean; + must_change_password: boolean; name: string; updated_at: number; username: string; @@ -14411,6 +14469,73 @@ export type SecurityHeadersSettings = { x_xss_protection?: string; }; +/** + * A single update attempt. Persisted to `/self-update.json` so the + * result survives the restart it causes. + */ +export type SelfUpdateAttempt = { + /** + * Operator-facing failure reason. Always set when `status` is `Failed`. + */ + error?: string | null; + /** + * When the outcome was decided. `None` while still `Pending`. + */ + finished_at?: string | null; + /** + * Version the attempt started from. + */ + from_version: string; + /** + * Where the replaced binary was kept, so a bad release can be reverted by + * hand (`mv `). Set once the swap completes. + */ + previous_binary_path?: string | null; + started_at: string; + status: SelfUpdateStatus; + /** + * Version the attempt targeted. `None` if it failed before resolving one. + */ + to_version?: string | null; + /** + * User who clicked the button. `None` for attempts started by the CLI. + */ + triggered_by_user_id?: number | null; +}; + +/** + * Why a one-click update is unavailable. Exactly one is reported — the most + * fundamental blocker wins, so the operator fixes the real problem first + * rather than clearing one only to hit the next. + */ +export type SelfUpdateBlocker = 'disabled_by_flag' | 'disabled_by_setting' | 'container' | 'no_supervisor' | 'binary_not_writable' | 'unsupported_platform' | 'in_progress'; + +/** + * Where an in-flight update has got to. Polled by the console so a long + * download shows progress instead of an indefinite spinner. + */ +export type SelfUpdatePhase = 'idle' | 'resolving' | 'downloading' | 'verifying' | 'installing' | 'restarting' | 'failed'; + +/** + * Controls the console's one-click "Update now" action. + */ +export type SelfUpdateSettings = { + /** + * Allow admins to apply a release and restart the server from the console. + * `true` by default: the action is permission-gated, audited, and only + * ever installs an official release whose published SHA-256 matches. + * + * Turning this off hides nothing — the console still shows the update + * banner and the manual command, it just refuses to run it for you. + */ + enabled?: boolean; +}; + +/** + * Outcome of an update attempt, as persisted in the journal. + */ +export type SelfUpdateStatus = 'pending' | 'succeeded' | 'failed'; + export type SendEmailRequestBody = { /** * BCC recipients @@ -15980,6 +16105,33 @@ export type StartRestoreRequest = RestoreRequestMode & { s3_source_id?: number | null; }; +/** + * Optional pin for the version to install. + */ +export type StartUpdateRequest = { + /** + * Release tag to install (e.g. `v0.2.0`). Omit to take the newest release + * on the channel this install already tracks. + */ + version?: string | null; +}; + +/** + * Acknowledgement that an update was accepted and is running. + */ +export type StartUpdateResponse = { + /** + * Version the server is running as it accepts this request. + */ + current_version: string; + /** + * How long to allow for the server to come back before treating the + * restart as failed. + */ + estimated_restart_secs: number; + message: string; +}; + export type StatResponse = { exists: boolean; is_dir: boolean; @@ -16206,6 +16358,11 @@ export type StripeConfig = { product_allowlist?: Array; }; +/** + * What (if anything) will restart the process after it exits. + */ +export type SupervisorKind = 'systemd' | 'launchd' | 'container' | 'none'; + export type SyncedRepositoryListQuery = { direction?: string | null; git_provider_connection_id?: number | null; @@ -17132,6 +17289,57 @@ export type UpdateBlobResponse = { success: boolean; }; +/** + * Whether this install can apply a release update on request, and how the last + * attempt went. + * + * Deliberately answerable even when the answer is "no": an operator who cannot + * use the button still needs to know *why* and what to run instead, so this + * never 404s or returns an empty body when the feature is unavailable. + */ +export type UpdateCapabilityResponse = { + /** + * Whether the *caller* holds `platform:update`. Distinct from `can_apply`, + * which describes the server: the console shows the action only when both + * are true, so a reader is never offered a button that would 403. + */ + allowed: boolean; + /** + * Binary that would be replaced. + */ + binary_path: string; + blocker?: null | SelfUpdateBlocker; + /** + * True only when a request would actually download, install and restart. + */ + can_apply: boolean; + /** + * Non-blocking warning to show with the confirmation (split topology). + */ + caveat?: string | null; + last_attempt?: null | SelfUpdateAttempt; + /** + * The equivalent command to run by hand. Always present. + */ + manual_command: string; + /** + * Phase of an in-flight attempt: `idle` when none is running. + */ + phase: SelfUpdatePhase; + /** + * Failure detail while `phase` is `failed`. + */ + phase_error?: string | null; + /** + * Operator-facing explanation of `blocker`. + */ + reason?: string | null; + /** + * What would restart the process: `systemd`, `launchd`, `container`, `none`. + */ + supervisor: SupervisorKind; +}; + export type UpdateCloudflareProviderRequest = { config: CloudflareConfig; enabled?: boolean | null; @@ -22341,6 +22549,37 @@ export type ListPublicProvidersResponses = { export type ListPublicProvidersResponse = ListPublicProvidersResponses[keyof ListPublicProvidersResponses]; +export type ChangeRequiredPasswordData = { + body: RequiredPasswordChangeRequest; + path?: never; + query?: never; + url: '/auth/password-change-required'; +}; + +export type ChangeRequiredPasswordErrors = { + /** + * Password does not meet requirements + */ + 400: unknown; + /** + * Password-change session is missing or expired + */ + 401: unknown; + /** + * Internal server error + */ + 500: unknown; +}; + +export type ChangeRequiredPasswordResponses = { + /** + * Required password change completed + */ + 200: RequiredPasswordChangeResponse; +}; + +export type ChangeRequiredPasswordResponse = ChangeRequiredPasswordResponses[keyof ChangeRequiredPasswordResponses]; + export type RequestPasswordResetData = { body: EmailRequest; path?: never; @@ -40807,6 +41046,10 @@ export type GetPropertyBreakdownData = { * Maximum number of results (default: 20, max: 100) */ limit?: number; + /** + * Include crawler/bot traffic (default: false) + */ + include_crawlers?: boolean; /** * Filter by country (for region/city drill-downs) */ @@ -40900,6 +41143,10 @@ export type GetPropertyTimelineData = { * Time bucket: hour, day, week, month (default: auto-detect) */ bucket_size?: string; + /** + * Include crawler/bot traffic (default: false) + */ + include_crawlers?: boolean; }; url: '/projects/{project_id}/events/properties/timeline'; }; @@ -43854,7 +44101,7 @@ export type GetUniqueCountsResponses = { export type GetUniqueCountsResponse = GetUniqueCountsResponses[keyof GetUniqueCountsResponses]; export type UploadStaticBundleData = { - body?: never; + body: SourceArchiveUpload; path: { project_id: number; }; @@ -47072,6 +47319,70 @@ export type DownloadGlobalSkillArchiveResponses = { export type DownloadGlobalSkillArchiveResponse = DownloadGlobalSkillArchiveResponses[keyof DownloadGlobalSkillArchiveResponses]; +export type GetUpdateCapabilityData = { + body?: never; + path?: never; + query?: never; + url: '/settings/update'; +}; + +export type GetUpdateCapabilityErrors = { + /** + * Unauthorized + */ + 401: unknown; + /** + * Insufficient permissions + */ + 403: unknown; +}; + +export type GetUpdateCapabilityResponses = { + /** + * Self-update capability for this install + */ + 200: UpdateCapabilityResponse; +}; + +export type GetUpdateCapabilityResponse = GetUpdateCapabilityResponses[keyof GetUpdateCapabilityResponses]; + +export type StartUpdateData = { + body: StartUpdateRequest; + path?: never; + query?: never; + url: '/settings/update'; +}; + +export type StartUpdateErrors = { + /** + * Unauthorized + */ + 401: unknown; + /** + * Insufficient permissions + */ + 403: unknown; + /** + * Update unavailable or already running + */ + 409: ProblemDetails; + /** + * This process cannot apply updates + */ + 501: ProblemDetails; +}; + +export type StartUpdateError = StartUpdateErrors[keyof StartUpdateErrors]; + +export type StartUpdateResponses = { + /** + * Update accepted; the server will restart + */ + 202: StartUpdateResponse; +}; + +export type StartUpdateResponse2 = StartUpdateResponses[keyof StartUpdateResponses]; + export type GetUpdateStatusData = { body?: never; path?: never; @@ -47672,6 +47983,10 @@ export type SetupMfaErrors = { * Unauthorized */ 401: unknown; + /** + * MFA is already enabled; verify and disable it before re-enrollment + */ + 409: unknown; /** * Internal server error */ diff --git a/apps/temps-cli/src/commands/platform/index.ts b/apps/temps-cli/src/commands/platform/index.ts index b2f85329b..aba60a118 100644 --- a/apps/temps-cli/src/commands/platform/index.ts +++ b/apps/temps-cli/src/commands/platform/index.ts @@ -6,9 +6,13 @@ import { getAccessInfo, getPrivateIp, getPublicIp, + getUpdateCapability, + getUpdateStatus, + startUpdate, } from '../../api/sdk.gen.js' import { withSpinner } from '../../ui/spinner.js' -import { newline, header, icons, json, colors, info, keyValue, success } from '../../ui/output.js' +import { promptConfirm } from '../../ui/prompts.js' +import { newline, header, icons, json, colors, info, keyValue, success, warning, error, formatDate } from '../../ui/output.js' export function registerPlatformCommands(program: Command): void { const platform = program @@ -37,6 +41,24 @@ export function registerPlatformCommands(program: Command): void { .command('public-ip') .description('Get the server public IP address') .action(publicIpAction) + + const update = platform + .command('update') + .description('Check for and apply temps releases on the server') + + update + .command('status') + .description('Show the available release and whether it can be applied from here') + .option('--json', 'Output in JSON format') + .action(updateStatusAction) + + update + .command('apply') + .description('Install a release on the server and restart it') + .option('--version ', 'Release tag to install (default: newest on this channel)') + .option('-y, --yes', 'Skip the confirmation prompt') + .option('--json', 'Output in JSON format') + .action(updateApplyAction) } async function platformInfoAction(options: { json?: boolean }): Promise { @@ -144,3 +166,227 @@ async function publicIpAction(): Promise { json(result) } } + +/** + * Report both halves of the picture: whether a newer release exists, and + * whether this install can apply it without someone SSH-ing to the host. + */ +async function updateStatusAction(options: { json?: boolean }): Promise { + await requireAuth() + await setupClient() + + const { status, capability } = await withSpinner('Checking for updates...', async () => { + const [statusRes, capabilityRes] = await Promise.all([ + getUpdateStatus({ client }), + getUpdateCapability({ client }), + ]) + if (statusRes.error) { + throw new Error(getErrorMessage(statusRes.error)) + } + if (capabilityRes.error) { + throw new Error(getErrorMessage(capabilityRes.error)) + } + return { status: statusRes.data, capability: capabilityRes.data } + }) + + if (options.json) { + json({ status, capability }) + return + } + + newline() + header(`${icons.globe} Platform Updates`) + + if (status?.update_available) { + keyValue('Current', status.current_version ?? colors.muted('unknown')) + keyValue('Available', colors.success(status.latest_version ?? 'unknown')) + keyValue('Channel', status.channel ?? colors.muted('unknown')) + if (status.release_url) { + keyValue('Release notes', status.release_url) + } + } else { + keyValue('Status', 'Up to date (or no check has completed yet)') + keyValue('Current', status?.current_version ?? colors.muted('unknown')) + } + + newline() + keyValue('Supervisor', capability?.supervisor ?? colors.muted('unknown')) + keyValue('Binary', capability?.binary_path || colors.muted('unknown')) + + if (capability?.can_apply && capability.allowed) { + keyValue('Apply from here', colors.success('Yes')) + info(`Run ${colors.primary('temps platform update apply')} to install and restart.`) + } else { + keyValue('Apply from here', colors.warning('No')) + if (!capability?.allowed) { + warning('Your credentials lack the platform:update permission.') + } + if (capability?.reason) { + warning(capability.reason) + } + // Never leave the operator without a way forward. + info(`Upgrade manually on the host: ${colors.primary(capability?.manual_command ?? 'temps upgrade')}`) + } + + if (capability?.caveat) { + warning(capability.caveat) + } + + // Surface how the previous attempt ended — especially a failure, which the + // person running this may never have seen if it happened in the console. + const attempt = capability?.last_attempt + if (attempt) { + newline() + header(`${icons.bullet} Last update attempt`) + keyValue('Result', attempt.status === 'succeeded' + ? colors.success('succeeded') + : attempt.status === 'failed' + ? colors.error('failed') + : 'in progress') + keyValue('From', attempt.from_version) + keyValue('To', attempt.to_version ?? colors.muted('not resolved')) + keyValue('Started', formatDate(attempt.started_at)) + if (attempt.error) { + warning(attempt.error) + } + if (attempt.previous_binary_path) { + keyValue('Previous binary', attempt.previous_binary_path) + } + } + newline() +} + +/** + * Apply a release. The server restarts itself, so this deliberately does NOT + * wait for a response body beyond the acceptance — it polls afterwards and + * reports the recorded outcome once the server answers again. + */ +async function updateApplyAction(options: { + version?: string + yes?: boolean + json?: boolean +}): Promise { + await requireAuth() + await setupClient() + + const capability = await withSpinner('Checking update capability...', async () => { + const { data, error: err } = await getUpdateCapability({ client }) + if (err) { + throw new Error(getErrorMessage(err)) + } + return data + }) + + // Fail before prompting when the server has already told us it cannot. + if (!capability?.can_apply || !capability.allowed) { + error('This server cannot apply updates right now.') + if (!capability?.allowed) { + warning('Your credentials lack the platform:update permission.') + } + if (capability?.reason) { + warning(capability.reason) + } + info(`Upgrade manually on the host: ${colors.primary(capability?.manual_command ?? 'temps upgrade')}`) + process.exitCode = 1 + return + } + + if (capability.caveat) { + warning(capability.caveat) + } + + if (!options.yes) { + const confirmed = await promptConfirm({ + message: `Install ${options.version ?? 'the latest release'} and restart the server? It will be briefly unavailable.`, + default: false, + }) + if (!confirmed) { + info('Cancelled.') + return + } + } + + const started = await withSpinner('Starting update...', async () => { + const { data, error: err } = await startUpdate({ + client, + body: options.version ? { version: options.version } : {}, + }) + if (err) { + throw new Error(getErrorMessage(err)) + } + return data + }) + + if (options.json) { + json(started) + return + } + + success(`Update started from ${started?.current_version ?? 'the running version'}.`) + info('The server is downloading, verifying and installing, then restarting.') + + const outcome = await withSpinner('Waiting for the server to come back...', async () => + waitForUpdateOutcome( + capability.last_attempt?.started_at ?? null, + (started?.estimated_restart_secs ?? 45) + 60 + ) + ) + + newline() + if (!outcome) { + warning('The server did not report an outcome in time.') + info('Check the service on the host (systemctl status temps / journalctl -u temps).') + process.exitCode = 1 + return + } + if (outcome.status === 'succeeded') { + success(`temps is now running ${outcome.to_version} (was ${outcome.from_version}).`) + return + } + error(outcome.error ?? 'The update did not complete.') + info(`The server is still running ${outcome.from_version}.`) + if (outcome.previous_binary_path) { + info(`Previous binary kept at ${outcome.previous_binary_path}`) + } + process.exitCode = 1 +} + +/** + * Poll until the attempt we just started resolves. + * + * Connection errors are expected and ignored — the server is restarting, which + * is the whole point. `baselineStartedAt` distinguishes our attempt from a + * result left over from a previous one. + */ +async function waitForUpdateOutcome( + baselineStartedAt: string | null, + timeoutSecs: number +): Promise< + | { + status: string + from_version: string + to_version?: string | null + error?: string | null + previous_binary_path?: string | null + } + | null +> { + const deadline = Date.now() + timeoutSecs * 1000 + while (Date.now() < deadline) { + await new Promise((resolve) => setTimeout(resolve, 2000)) + try { + const { data } = await getUpdateCapability({ client }) + const attempt = data?.last_attempt + if ( + attempt && + attempt.status !== 'pending' && + attempt.started_at !== baselineStartedAt + ) { + return attempt + } + } catch { + // Server is down mid-restart; keep waiting. + } + } + return null +} diff --git a/crates/temps-auth/src/permissions.rs b/crates/temps-auth/src/permissions.rs index c7c7f1cf2..9014b4c01 100644 --- a/crates/temps-auth/src/permissions.rs +++ b/crates/temps-auth/src/permissions.rs @@ -86,6 +86,12 @@ pub enum Permission { DnsProvidersRead, DnsProvidersWrite, DnsAutomationWrite, + /// Apply a release update to the server binary and restart the process. + /// Deliberately separate from `SettingsWrite`: replacing the running binary + /// and dropping every in-flight request is a different class of action from + /// editing a config value, so a custom role scoped to settings must not + /// acquire it implicitly. + PlatformUpdate, // Files permissions FilesRead, @@ -331,6 +337,7 @@ impl fmt::Display for Permission { Permission::DnsProvidersRead => "dns_providers:read", Permission::DnsProvidersWrite => "dns_providers:write", Permission::DnsAutomationWrite => "dns_automation:write", + Permission::PlatformUpdate => "platform:update", Permission::ErrorTrackingRead => "error_tracking:read", Permission::ErrorTrackingWrite => "error_tracking:write", Permission::ErrorTrackingCreate => "error_tracking:create", @@ -448,6 +455,7 @@ impl Permission { "dns_providers:read" => Some(Permission::DnsProvidersRead), "dns_providers:write" => Some(Permission::DnsProvidersWrite), "dns_automation:write" => Some(Permission::DnsAutomationWrite), + "platform:update" => Some(Permission::PlatformUpdate), "files:read" => Some(Permission::FilesRead), "files:write" => Some(Permission::FilesWrite), "files:delete" => Some(Permission::FilesDelete), @@ -597,6 +605,7 @@ impl Permission { Permission::DnsProvidersRead, Permission::DnsProvidersWrite, Permission::DnsAutomationWrite, + Permission::PlatformUpdate, Permission::FilesRead, Permission::FilesWrite, Permission::FilesDelete, @@ -814,6 +823,7 @@ impl Role { Permission::PipelinesRead, Permission::PipelinesWrite, Permission::PlatformInfoRead, + Permission::PlatformUpdate, Permission::ProjectsCreate, Permission::ProjectsDelete, Permission::ProjectsRead, @@ -959,6 +969,7 @@ impl Role { Permission::PipelinesRead, Permission::PipelinesWrite, Permission::PlatformInfoRead, + Permission::PlatformUpdate, Permission::ProjectsRead, Permission::SessionMetricsRead, Permission::SettingsRead, diff --git a/crates/temps-cli/src/commands/serve/console.rs b/crates/temps-cli/src/commands/serve/console.rs index ccdc9cc04..a088f1434 100644 --- a/crates/temps-cli/src/commands/serve/console.rs +++ b/crates/temps-cli/src/commands/serve/console.rs @@ -1215,6 +1215,12 @@ pub struct ConsoleApiParams { /// banner (`GET /settings/update-status`). Advisory read-only metadata — /// it never influences routing, auth, or connection handling. pub update_status: Arc, + /// Applies a release update on request from the settings API and exits so + /// the supervisor restarts temps on the new binary. Owned by the caller + /// (`commands/serve/mod.rs`) so the journal of a previous attempt is + /// resolved exactly once per process; registered below for ConfigPlugin's + /// `GET/POST /settings/update`. + pub self_updater: Arc, } /// Build a ClickHouse-backed metrics store from the server config, or `None` @@ -1747,6 +1753,7 @@ pub async fn start_console_api(params: ConsoleApiParams) -> anyhow::Result<()> { admin_gate_handle: provided_admin_gate_handle, retention_resolver_slot, update_status, + self_updater, } = params; // Count panics for the anonymous `error_summary` telemetry event. Only @@ -1855,6 +1862,9 @@ pub async fn start_console_api(params: ConsoleApiParams) -> anyhow::Result<()> { // it; ConfigPlugin's `GET /settings/update-status` reads it so the web // console can render the upgrade banner. service_context.register_service(update_status.clone()); + // Registered behind the trait so temps-config depends only on the + // temps-core contract, never on the CLI crate that implements it. + service_context.register_service(self_updater.clone() as Arc); // Register the shared route table (created in serve/mod.rs) // This is used by analytics-events and other plugins that need to resolve hosts diff --git a/crates/temps-cli/src/commands/serve/mod.rs b/crates/temps-cli/src/commands/serve/mod.rs index 007509f43..4e53be841 100644 --- a/crates/temps-cli/src/commands/serve/mod.rs +++ b/crates/temps-cli/src/commands/serve/mod.rs @@ -4,6 +4,7 @@ pub(crate) mod admin_gate_service; pub mod console; pub(crate) mod on_demand_cert; pub(crate) mod proxy; +pub(crate) mod self_update; mod shutdown; use clap::{Args, ValueEnum}; @@ -72,6 +73,18 @@ pub struct ServeCommand { #[arg(long, env = "TEMPS_CONSOLE_ADMIN_ADDRESS")] pub console_admin_address: Option, + /// Forbid applying release updates from the console, permanently for the + /// lifetime of this process. + /// + /// The console also has a Settings toggle for the same thing, but that one + /// lives in the database and can be switched back on by anyone who can + /// write settings. This flag cannot: it is set at launch, so an operator + /// who keeps upgrades under configuration management (or policy) can rule + /// the API path out entirely. The update banner still appears and still + /// shows the manual command — only the "Update now" action is refused. + #[arg(long)] + pub disable_self_update: bool, + /// Screenshot provider to use: "local" (headless Chrome), "remote", or "noop" (disabled) /// Use "noop" on servers without Chrome installed to skip screenshot functionality #[arg(long, env = "TEMPS_SCREENSHOT_PROVIDER", value_parser = ["local", "remote", "noop", "disabled", "none"])] @@ -323,6 +336,27 @@ impl ServeCommand { update_check_interval, )); + // Companion to the notifier above: the notifier says a release exists, + // this applies it when an admin asks. Constructed here (not in the + // console) so it resolves the journal of a previous update attempt + // exactly once per process, before any request can observe it. + // + // In split topology (ADR-017) only the CONSOLE process restarts. The + // sibling `temps proxy` keeps serving :80/:443 on the binary it already + // exec'd, so the operator has to restart it separately to converge — + // stated up front rather than discovered as version skew later. + let self_update_caveat = (self.role == ServeRole::Console).then(|| { + "This process runs the console only (ADR-017 split topology). The separate \ + `temps proxy` service keeps serving traffic on the binary it started with — \ + restart it too once the console is back to finish the upgrade." + .to_string() + }); + let self_updater = Arc::new(self_update::BinarySelfUpdater::new( + serve_config.data_dir.clone(), + self.disable_self_update, + self_update_caveat, + )); + // Connect to Docker once and share the handle between: // 1. OnDemandManager (wake-on-request scale-to-zero) // 2. Preview gateway reconciler (workspace preview routing) @@ -524,6 +558,7 @@ impl ServeCommand { admin_gate_handle: Some(admin_gate_handle.clone()), retention_resolver_slot: retention_resolver_slot.clone(), update_status, + self_updater, }; if self.role == ServeRole::Console { diff --git a/crates/temps-cli/src/commands/serve/self_update.rs b/crates/temps-cli/src/commands/serve/self_update.rs new file mode 100644 index 000000000..7a99d38c1 --- /dev/null +++ b/crates/temps-cli/src/commands/serve/self_update.rs @@ -0,0 +1,929 @@ +//! Applies a published release to the running install, on request from the API. +//! +//! This is the implementation behind `temps_core::SelfUpdater`; the HTTP surface +//! lives in temps-config (`GET/POST /settings/update`). It reuses the download, +//! checksum and atomic-swap machinery of `temps upgrade` — the only genuinely +//! new problems here are (a) deciding honestly whether the process will come +//! back after it exits, and (b) reporting the outcome of an operation that by +//! definition kills the process that started it. +//! +//! **How the restart works.** Nothing in temps restarts temps. The binary is +//! swapped on disk and the process exits; whatever supervises it (systemd +//! `Restart=always`, launchd `KeepAlive`) starts it again, now on the new +//! binary. That is why an install with no supervisor is refused up front rather +//! than left dead — see `detect_supervisor`. +//! +//! **How the outcome is reported.** The attempt is written to +//! `/self-update.json` as `pending` immediately before exiting, and +//! resolved on the next boot by comparing the running version against the +//! target (`reconcile_journal`). So the console can say "updated to v0.2.0" or +//! "came back on the old version" instead of the operator staring at a +//! reconnecting spinner with no idea what happened. + +use std::path::{Path, PathBuf}; +use std::sync::{Arc, RwLock}; + +use chrono::Utc; +use temps_core::{ + SelfUpdateAttempt, SelfUpdateBlocker, SelfUpdateCapability, SelfUpdateError, SelfUpdatePhase, + SelfUpdateStatus, SelfUpdater, StartedSelfUpdate, SupervisorKind, SELF_UPDATE_JOURNAL_FILE, +}; +use tracing::{error, info, warn}; + +use crate::commands::upgrade::{ + check_write_permission, current_version_tag, download_asset, download_asset_text, + extract_binary_from_tarball, fetch_latest_release_in_channel, fetch_specific_release, + platform_target, replace_binary, verify_checksum, GitHubRelease, UpgradeChannel, +}; + +/// Grace period between accepting the update and exiting the process. Long +/// enough for the 202 response and one status poll to reach the console, so the +/// UI can show "restarting" instead of an unexplained connection drop. +const RESTART_GRACE: std::time::Duration = std::time::Duration::from_millis(1_500); + +/// What the console should budget for the server to come back: the systemd unit +/// installed by `deploy.sh` uses `RestartSec=5`, plus boot (migrations, plugin +/// init). Advisory only — it drives the polling timeout, nothing else. +const ESTIMATED_RESTART_SECS: u64 = 45; + +#[derive(Debug, Default)] +struct UpdaterState { + phase: SelfUpdatePhase, + phase_error: Option, + last_attempt: Option, +} + +/// Replaces the on-disk binary and exits so the supervisor restarts it. +pub struct BinarySelfUpdater { + /// Binary that gets replaced — the running executable, symlinks resolved. + binary_path: PathBuf, + /// Directory holding the update journal. + data_dir: PathBuf, + /// `temps serve --disable-self-update`. A hard, API-proof off switch: unlike + /// the settings toggle, nothing reachable over HTTP can clear it. + disabled_by_flag: bool, + supervisor: SupervisorKind, + /// Topology caveat surfaced with the confirmation (see the field of the + /// same name on `SelfUpdateCapability`). + caveat: Option, + state: Arc>, +} + +impl BinarySelfUpdater { + /// Build the updater and resolve any attempt left `pending` by the previous + /// process. Never fails: a bad journal or an unresolvable binary path + /// degrades to "self-update unavailable", which the capability endpoint + /// reports with a reason. + pub fn new(data_dir: PathBuf, disabled_by_flag: bool, caveat: Option) -> Self { + let binary_path = std::env::current_exe() + .map(|p| std::fs::canonicalize(&p).unwrap_or(p)) + .unwrap_or_else(|e| { + warn!("Could not determine the running binary path: {}", e); + PathBuf::new() + }); + + let supervisor = detect_supervisor(); + info!( + supervisor = supervisor.as_str(), + binary = %binary_path.display(), + disabled_by_flag, + "Self-update capability initialized" + ); + + let updater = Self { + binary_path, + data_dir, + disabled_by_flag, + supervisor, + caveat, + state: Arc::new(RwLock::new(UpdaterState::default())), + }; + + let last_attempt = updater.reconcile_journal(); + if let Ok(mut state) = updater.state.write() { + state.last_attempt = last_attempt; + } + updater + } + + fn journal_path(&self) -> PathBuf { + self.data_dir.join(SELF_UPDATE_JOURNAL_FILE) + } + + /// Resolve an attempt the previous process left `pending`. + /// + /// The process that started the update cannot record its own outcome — it + /// exits mid-flight by design. So its successor decides: if we are running + /// the version the attempt targeted it succeeded, otherwise the swap did not + /// take effect and the operator needs to know that (and where the previous + /// binary was kept). + fn reconcile_journal(&self) -> Option { + let path = self.journal_path(); + let mut attempt = match read_journal(&path) { + Ok(attempt) => attempt?, + Err(e) => { + warn!( + "Ignoring unreadable self-update journal at {}: {}", + path.display(), + e + ); + return None; + } + }; + + if attempt.status != SelfUpdateStatus::Pending { + return Some(attempt); + } + + let running = current_version_tag(); + attempt.finished_at = Some(Utc::now()); + if attempt.to_version.as_deref() == Some(running.as_str()) { + attempt.status = SelfUpdateStatus::Succeeded; + info!( + from = %attempt.from_version, + to = %running, + "Self-update completed: restarted on the new version" + ); + } else { + attempt.status = SelfUpdateStatus::Failed; + let target = attempt + .to_version + .clone() + .unwrap_or_else(|| "?".to_string()); + attempt.error = Some(format!( + "Restarted on {running} instead of {target}. The binary swap did not take effect \ + — the supervisor may have relaunched an older binary from a different path, or \ + the new binary failed to start and was rolled back by the supervisor.{}", + match &attempt.previous_binary_path { + Some(p) => format!(" The replaced binary was kept at {p}."), + None => String::new(), + } + )); + error!( + from = %attempt.from_version, + target = %target, + running = %running, + "Self-update did not take effect" + ); + } + + if let Err(e) = write_journal(&path, &attempt) { + warn!("Could not persist resolved self-update journal: {}", e); + } + Some(attempt) + } + + /// The command an operator runs by hand when the API path is unavailable. + /// Always answerable — there is no state in which the manual path is gone. + fn manual_command(&self, blocker: Option) -> String { + match blocker { + Some(SelfUpdateBlocker::Container) => { + "docker compose pull && docker compose up -d".to_string() + } + Some(SelfUpdateBlocker::BinaryNotWritable) => "sudo temps upgrade".to_string(), + _ => "temps upgrade".to_string(), + } + } + + /// First blocker that applies, or `None` when an update can run. + /// + /// Order is deliberate: an explicit operator decision (`--disable-self-update`, + /// then the settings toggle) is reported before any environmental problem, + /// because "you turned this off" is the honest answer even on a host that + /// also happens to be unsupervised. + fn find_blocker(&self, enabled_in_settings: bool) -> Option<(SelfUpdateBlocker, String)> { + if self.disabled_by_flag { + return Some(( + SelfUpdateBlocker::DisabledByFlag, + "The server was started with --disable-self-update. Restart it without that flag \ + to allow updates from the console; this cannot be re-enabled from the UI." + .to_string(), + )); + } + if !enabled_in_settings { + return Some(( + SelfUpdateBlocker::DisabledBySetting, + "One-click updates are turned off in Settings → Platform. An admin can re-enable \ + them there." + .to_string(), + )); + } + if self.supervisor == SupervisorKind::Container { + return Some(( + SelfUpdateBlocker::Container, + "This server runs inside a container, where the binary comes from the image. \ + Replacing it would be undone the next time the container is recreated — pull a \ + newer image tag instead." + .to_string(), + )); + } + if !self.supervisor.restarts_on_exit() { + return Some(( + SelfUpdateBlocker::NoSupervisor, + "No process supervisor was detected (no systemd or launchd), so nothing would \ + restart the server after it exits. Run temps under a service manager, or upgrade \ + from the command line." + .to_string(), + )); + } + if let Err(e) = platform_target() { + return Some((SelfUpdateBlocker::UnsupportedPlatform, e.to_string())); + } + if self.binary_path.as_os_str().is_empty() { + return Some(( + SelfUpdateBlocker::BinaryNotWritable, + "The path of the running binary could not be determined, so it cannot be replaced." + .to_string(), + )); + } + if let Err(e) = check_write_permission(&self.binary_path) { + return Some(( + SelfUpdateBlocker::BinaryNotWritable, + format!( + "The server user cannot replace {}: {}", + self.binary_path.display(), + e + ), + )); + } + // Checked last: an in-flight attempt is transient, and reporting it + // ahead of a permanent blocker would hide the real problem. + let phase = self + .state + .read() + .map(|s| s.phase) + .unwrap_or(SelfUpdatePhase::Idle); + if phase.is_active() { + return Some(( + SelfUpdateBlocker::InProgress, + format!("An update is already running ({}).", phase.as_str()), + )); + } + None + } + + fn set_phase(&self, phase: SelfUpdatePhase, phase_error: Option) { + if let Ok(mut state) = self.state.write() { + state.phase = phase; + state.phase_error = phase_error; + } + } +} + +impl SelfUpdater for BinarySelfUpdater { + fn capability(&self, enabled_in_settings: bool) -> SelfUpdateCapability { + let blocker = self.find_blocker(enabled_in_settings); + let (phase, phase_error, last_attempt) = match self.state.read() { + Ok(state) => ( + state.phase, + state.phase_error.clone(), + state.last_attempt.clone(), + ), + Err(poisoned) => { + let state = poisoned.into_inner(); + ( + state.phase, + state.phase_error.clone(), + state.last_attempt.clone(), + ) + } + }; + + SelfUpdateCapability { + can_apply: blocker.is_none(), + blocker: blocker.as_ref().map(|(b, _)| *b), + reason: blocker.as_ref().map(|(_, r)| r.clone()), + manual_command: self.manual_command(blocker.as_ref().map(|(b, _)| *b)), + supervisor: self.supervisor, + binary_path: self.binary_path.display().to_string(), + caveat: self.caveat.clone(), + phase, + phase_error, + last_attempt, + } + } + + fn start( + &self, + target_version: Option, + triggered_by_user_id: Option, + enabled_in_settings: bool, + ) -> Result { + if let Some((blocker, reason)) = self.find_blocker(enabled_in_settings) { + if blocker == SelfUpdateBlocker::InProgress { + let phase = self + .state + .read() + .map(|s| s.phase) + .unwrap_or(SelfUpdatePhase::Idle); + return Err(SelfUpdateError::AlreadyRunning { + phase: phase.as_str(), + }); + } + return Err(SelfUpdateError::Unavailable { blocker, reason }); + } + + let current_version = current_version_tag(); + self.set_phase(SelfUpdatePhase::Resolving, None); + + let job = UpdateJob { + binary_path: self.binary_path.clone(), + journal_path: self.journal_path(), + from_version: current_version.clone(), + target_version, + triggered_by_user_id, + state: self.state.clone(), + }; + tokio::spawn(job.run()); + + info!( + user_id = ?triggered_by_user_id, + from = %current_version, + "Self-update accepted; downloading in the background" + ); + + Ok(StartedSelfUpdate { + current_version, + estimated_restart_secs: ESTIMATED_RESTART_SECS, + }) + } +} + +/// The background half of an update: everything between "accepted" and "the +/// process is gone". Owns clones rather than borrowing the updater so it can +/// outlive the request that started it. +struct UpdateJob { + binary_path: PathBuf, + journal_path: PathBuf, + from_version: String, + target_version: Option, + triggered_by_user_id: Option, + state: Arc>, +} + +impl UpdateJob { + fn set_phase(&self, phase: SelfUpdatePhase, phase_error: Option) { + if let Ok(mut state) = self.state.write() { + state.phase = phase; + state.phase_error = phase_error; + } + } + + async fn run(self) { + let started_at = Utc::now(); + match self.execute(started_at).await { + Ok(target) => { + // The swap is done and the journal says `pending`. Exiting is + // now the whole job: the supervisor brings us back on the new + // binary and the next boot resolves the journal entry. + self.set_phase(SelfUpdatePhase::Restarting, None); + warn!( + from = %self.from_version, + to = %target, + "Binary replaced — exiting so the supervisor restarts temps on the new version" + ); + tokio::time::sleep(RESTART_GRACE).await; + std::process::exit(0); + } + Err(e) => { + let message = e.to_string(); + error!( + from = %self.from_version, + error = %message, + "Self-update failed; the running binary was left untouched" + ); + // Record the failure so it survives to the UI even if the + // operator's tab was closed when it happened. + let attempt = SelfUpdateAttempt { + from_version: self.from_version.clone(), + to_version: None, + status: SelfUpdateStatus::Failed, + started_at, + finished_at: Some(Utc::now()), + triggered_by_user_id: self.triggered_by_user_id, + error: Some(message.clone()), + previous_binary_path: None, + }; + if let Err(e) = write_journal(&self.journal_path, &attempt) { + warn!("Could not persist failed self-update attempt: {}", e); + } + if let Ok(mut state) = self.state.write() { + state.phase = SelfUpdatePhase::Failed; + state.phase_error = Some(message); + state.last_attempt = Some(attempt); + } + } + } + } + + /// Download, verify and install. Returns the version now on disk. + /// + /// Every failure here leaves the running binary untouched: the new bytes go + /// to a temp file and are only moved into place after the checksum matches + /// AND the new binary answers `--version`. + async fn execute(&self, started_at: chrono::DateTime) -> anyhow::Result { + let target = platform_target()?; + + let release = self.resolve_release().await?; + let to_version = release.tag_name.clone(); + if to_version == self.from_version { + return Err(anyhow::anyhow!( + "Already running {} — nothing to update", + self.from_version + )); + } + + let tarball_name = format!("temps-{}.tar.gz", target); + let asset = release + .assets + .iter() + .find(|a| a.name == tarball_name) + .ok_or_else(|| { + anyhow::anyhow!( + "Release {} publishes no asset for this platform ({}). Available: {}", + to_version, + target, + release + .assets + .iter() + .map(|a| a.name.as_str()) + .collect::>() + .join(", ") + ) + })?; + + info!( + to = %to_version, + size_mb = format!("{:.1}", asset.size as f64 / 1_048_576.0), + "Downloading release asset" + ); + self.set_phase(SelfUpdatePhase::Downloading, None); + let tarball = download_asset(&asset.browser_download_url).await?; + + self.set_phase(SelfUpdatePhase::Verifying, None); + // Fail closed on a missing checksum. `temps upgrade` merely warns + // because a human is watching the terminal and can judge; a background + // job triggered from a browser has nobody to make that call, so it must + // never install bytes it could not verify. + let checksum_asset = release + .assets + .iter() + .find(|a| a.name == format!("{}.sha256", tarball_name)) + .ok_or_else(|| { + anyhow::anyhow!( + "Release {} publishes no SHA-256 for {}, so the download cannot be verified. \ + Upgrade from the command line if you want to install it anyway.", + to_version, + tarball_name + ) + })?; + let expected = download_asset_text(&checksum_asset.browser_download_url).await?; + verify_checksum(&tarball, &expected)?; + + let new_binary = extract_binary_from_tarball(&tarball)?; + preflight_binary(&self.binary_path, &new_binary)?; + + self.set_phase(SelfUpdatePhase::Installing, None); + // Keep the outgoing binary next to the new one so a release that boots + // but misbehaves can be reverted with a single `mv`, without network. + let backup_path = backup_current_binary(&self.binary_path)?; + replace_binary(&self.binary_path, &new_binary)?; + + // Written BEFORE the exit: once the process is gone there is no second + // chance to record what it was doing. + let attempt = SelfUpdateAttempt { + from_version: self.from_version.clone(), + to_version: Some(to_version.clone()), + status: SelfUpdateStatus::Pending, + started_at, + finished_at: None, + triggered_by_user_id: self.triggered_by_user_id, + error: None, + previous_binary_path: backup_path.map(|p| p.display().to_string()), + }; + write_journal(&self.journal_path, &attempt)?; + if let Ok(mut state) = self.state.write() { + state.last_attempt = Some(attempt); + } + + Ok(to_version) + } + + /// The release to install: an explicit pin, or the newest one on the channel + /// this install already tracks (inferred from the running version tag, the + /// same rule the startup notifier uses). + async fn resolve_release(&self) -> anyhow::Result { + match &self.target_version { + Some(version) => fetch_specific_release(version).await, + None => { + let channel = UpgradeChannel::for_installed_version(&self.from_version); + fetch_latest_release_in_channel(channel).await + } + } + } +} + +/// Is this process running inside a container? Checked before anything else, +/// because a swapped binary there is silently discarded on the next recreate. +fn in_container() -> bool { + if Path::new("/.dockerenv").exists() || Path::new("/run/.containerenv").exists() { + return true; + } + // Fallback for runtimes that create neither marker file. + std::fs::read_to_string("/proc/1/cgroup").is_ok_and(|cgroup| { + cgroup.contains("/docker/") + || cgroup.contains("/docker-") + || cgroup.contains("containerd") + || cgroup.contains("kubepods") + || cgroup.contains("/lxc/") + }) +} + +/// Identify what will restart this process after it exits. +/// +/// Both signals are set by the supervisor itself in the child's environment, +/// so they cannot be faked by a wrong assumption about how temps was launched: +/// systemd exports `INVOCATION_ID`, launchd exports `XPC_SERVICE_NAME`. +fn detect_supervisor() -> SupervisorKind { + if in_container() { + return SupervisorKind::Container; + } + if std::env::var_os("INVOCATION_ID").is_some() { + return SupervisorKind::Systemd; + } + // launchd sets this for managed jobs; processes started from a terminal + // inherit the literal "0", which means "not a launchd service". + if std::env::var("XPC_SERVICE_NAME").is_ok_and(|v| v != "0") { + return SupervisorKind::Launchd; + } + SupervisorKind::None +} + +/// Run the downloaded binary's `--version` before trusting it. +/// +/// Catches the failures a checksum cannot: a build for the wrong libc, a +/// missing shared library, a corrupted extraction. Cheap insurance — without +/// it, a binary that cannot exec turns a one-click update into an outage that +/// only a console on the host can fix. +fn preflight_binary(binary_path: &Path, new_binary: &[u8]) -> anyhow::Result<()> { + let parent = binary_path + .parent() + .ok_or_else(|| anyhow::anyhow!("Cannot determine the binary's directory"))?; + let probe_path = parent.join(".temps-update-probe"); + + std::fs::write(&probe_path, new_binary).map_err(|e| { + anyhow::anyhow!( + "Failed to stage the new binary at {}: {}", + probe_path.display(), + e + ) + })?; + #[cfg(unix)] + { + use std::os::unix::fs::PermissionsExt; + if let Err(e) = + std::fs::set_permissions(&probe_path, std::fs::Permissions::from_mode(0o755)) + { + let _ = std::fs::remove_file(&probe_path); + return Err(anyhow::anyhow!( + "Failed to make the staged binary executable: {}", + e + )); + } + } + + let output = std::process::Command::new(&probe_path) + .arg("--version") + .output(); + let _ = std::fs::remove_file(&probe_path); + + let output = output.map_err(|e| { + anyhow::anyhow!( + "The downloaded binary could not be executed on this host: {}. \ + The running version was left untouched.", + e + ) + })?; + if !output.status.success() { + return Err(anyhow::anyhow!( + "The downloaded binary exited with {} when asked for its version: {}. \ + The running version was left untouched.", + output.status, + String::from_utf8_lossy(&output.stderr).trim() + )); + } + Ok(()) +} + +/// Copy the current binary aside as `.bak`, returning where it went. +/// +/// A copy (not a rename) so the target is never momentarily absent — if the +/// process dies between the two steps, the install is still intact. Best +/// effort: failing to keep a backup must not block an otherwise valid update, +/// since the release remains downloadable. +fn backup_current_binary(binary_path: &Path) -> anyhow::Result> { + let backup_path = binary_path.with_extension("bak"); + match std::fs::copy(binary_path, &backup_path) { + Ok(_) => { + info!( + "Previous binary kept at {} — restore it with `mv {} {}` if the new version misbehaves", + backup_path.display(), + backup_path.display(), + binary_path.display() + ); + Ok(Some(backup_path)) + } + Err(e) => { + warn!( + "Could not keep a backup of the current binary at {}: {}", + backup_path.display(), + e + ); + Ok(None) + } + } +} + +fn read_journal(path: &Path) -> anyhow::Result> { + if !path.exists() { + return Ok(None); + } + let raw = std::fs::read_to_string(path) + .map_err(|e| anyhow::anyhow!("Failed to read {}: {}", path.display(), e))?; + let attempt = serde_json::from_str(&raw) + .map_err(|e| anyhow::anyhow!("Failed to parse {}: {}", path.display(), e))?; + Ok(Some(attempt)) +} + +fn write_journal(path: &Path, attempt: &SelfUpdateAttempt) -> anyhow::Result<()> { + if let Some(parent) = path.parent() { + std::fs::create_dir_all(parent) + .map_err(|e| anyhow::anyhow!("Failed to create {}: {}", parent.display(), e))?; + } + let json = serde_json::to_string_pretty(attempt) + .map_err(|e| anyhow::anyhow!("Failed to serialize the update journal: {}", e))?; + std::fs::write(path, json) + .map_err(|e| anyhow::anyhow!("Failed to write {}: {}", path.display(), e)) +} + +#[cfg(test)] +mod tests { + use super::*; + + fn updater( + dir: &Path, + disabled_by_flag: bool, + supervisor: SupervisorKind, + ) -> BinarySelfUpdater { + BinarySelfUpdater { + // A path inside the temp dir: present and writable, so the write + // check passes and the test exercises the blocker being asserted. + binary_path: dir.join("temps"), + data_dir: dir.to_path_buf(), + disabled_by_flag, + supervisor, + caveat: None, + state: Arc::new(RwLock::new(UpdaterState::default())), + } + } + + fn temp_dir(name: &str) -> PathBuf { + let dir = std::env::temp_dir().join(format!("temps-self-update-test-{name}")); + let _ = std::fs::remove_dir_all(&dir); + std::fs::create_dir_all(&dir).expect("create temp dir"); + std::fs::write(dir.join("temps"), b"#!/bin/sh\n").expect("write fake binary"); + dir + } + + #[test] + fn test_flag_blocks_even_when_everything_else_is_fine() { + let dir = temp_dir("flag"); + let cap = updater(&dir, true, SupervisorKind::Systemd).capability(true); + assert!(!cap.can_apply); + assert_eq!(cap.blocker, Some(SelfUpdateBlocker::DisabledByFlag)); + // The reason must say the flag cannot be cleared from the UI, or an + // admin will hunt for a toggle that does not exist. + assert!(cap.reason.unwrap().contains("--disable-self-update")); + let _ = std::fs::remove_dir_all(&dir); + } + + #[test] + fn test_flag_wins_over_settings_toggle() { + // Both off: the flag is the one the operator cannot undo in the UI, so + // it must be the reported blocker. + let dir = temp_dir("flag-wins"); + let cap = updater(&dir, true, SupervisorKind::Systemd).capability(false); + assert_eq!(cap.blocker, Some(SelfUpdateBlocker::DisabledByFlag)); + let _ = std::fs::remove_dir_all(&dir); + } + + #[test] + fn test_settings_toggle_blocks() { + let dir = temp_dir("setting"); + let cap = updater(&dir, false, SupervisorKind::Systemd).capability(false); + assert!(!cap.can_apply); + assert_eq!(cap.blocker, Some(SelfUpdateBlocker::DisabledBySetting)); + let _ = std::fs::remove_dir_all(&dir); + } + + #[test] + fn test_container_is_never_updatable() { + let dir = temp_dir("container"); + let cap = updater(&dir, false, SupervisorKind::Container).capability(true); + assert!(!cap.can_apply); + assert_eq!(cap.blocker, Some(SelfUpdateBlocker::Container)); + // Must point at the image, not at `temps upgrade`, which would be + // undone on the next container recreate. + assert!(cap.manual_command.contains("docker")); + let _ = std::fs::remove_dir_all(&dir); + } + + #[test] + fn test_unsupervised_is_refused() { + let dir = temp_dir("unsupervised"); + let cap = updater(&dir, false, SupervisorKind::None).capability(true); + assert!(!cap.can_apply); + assert_eq!(cap.blocker, Some(SelfUpdateBlocker::NoSupervisor)); + // The manual path always remains available. + assert_eq!(cap.manual_command, "temps upgrade"); + let _ = std::fs::remove_dir_all(&dir); + } + + #[test] + fn test_supervised_install_can_apply() { + let dir = temp_dir("ok"); + let cap = updater(&dir, false, SupervisorKind::Systemd).capability(true); + assert!( + cap.can_apply, + "blocked by {:?}: {:?}", + cap.blocker, cap.reason + ); + assert_eq!(cap.blocker, None); + assert_eq!(cap.phase, SelfUpdatePhase::Idle); + let _ = std::fs::remove_dir_all(&dir); + } + + #[test] + fn test_start_refused_when_disabled_reports_blocker() { + let dir = temp_dir("start-refused"); + let err = updater(&dir, false, SupervisorKind::Systemd) + .start(None, Some(1), false) + .expect_err("must refuse when disabled in settings"); + assert_eq!(err.blocker(), SelfUpdateBlocker::DisabledBySetting); + let _ = std::fs::remove_dir_all(&dir); + } + + #[test] + fn test_start_refused_while_another_attempt_runs() { + let dir = temp_dir("start-busy"); + let updater = updater(&dir, false, SupervisorKind::Systemd); + updater.set_phase(SelfUpdatePhase::Downloading, None); + let err = updater + .start(None, Some(1), true) + .expect_err("must refuse a concurrent attempt"); + assert!(matches!(err, SelfUpdateError::AlreadyRunning { .. })); + let _ = std::fs::remove_dir_all(&dir); + } + + #[test] + fn test_failed_phase_does_not_block_a_retry() { + // A previous failure must not wedge the updater — the operator has to + // be able to try again after fixing whatever broke. + let dir = temp_dir("retry"); + let updater = updater(&dir, false, SupervisorKind::Systemd); + updater.set_phase(SelfUpdatePhase::Failed, Some("network down".to_string())); + let cap = updater.capability(true); + assert!(cap.can_apply); + assert_eq!(cap.phase, SelfUpdatePhase::Failed); + assert_eq!(cap.phase_error.as_deref(), Some("network down")); + let _ = std::fs::remove_dir_all(&dir); + } + + #[test] + fn test_pending_journal_resolves_to_succeeded_on_matching_version() { + let dir = temp_dir("journal-ok"); + let running = current_version_tag(); + let attempt = SelfUpdateAttempt { + from_version: "v0.0.1".to_string(), + to_version: Some(running.clone()), + status: SelfUpdateStatus::Pending, + started_at: Utc::now(), + finished_at: None, + triggered_by_user_id: Some(3), + error: None, + previous_binary_path: None, + }; + let path = dir.join(SELF_UPDATE_JOURNAL_FILE); + write_journal(&path, &attempt).expect("write journal"); + + let resolved = updater(&dir, false, SupervisorKind::Systemd) + .reconcile_journal() + .expect("journal entry"); + assert_eq!(resolved.status, SelfUpdateStatus::Succeeded); + assert!(resolved.finished_at.is_some()); + // Resolution is persisted, so a later boot doesn't redo it. + let reread = read_journal(&path).expect("read").expect("entry"); + assert_eq!(reread.status, SelfUpdateStatus::Succeeded); + let _ = std::fs::remove_dir_all(&dir); + } + + #[test] + fn test_pending_journal_resolves_to_failed_on_version_mismatch() { + let dir = temp_dir("journal-fail"); + let attempt = SelfUpdateAttempt { + from_version: current_version_tag(), + // A version we are demonstrably not running. + to_version: Some("v999.0.0".to_string()), + status: SelfUpdateStatus::Pending, + started_at: Utc::now(), + finished_at: None, + triggered_by_user_id: None, + error: None, + previous_binary_path: Some("/usr/local/bin/temps.bak".to_string()), + }; + write_journal(&dir.join(SELF_UPDATE_JOURNAL_FILE), &attempt).expect("write journal"); + + let resolved = updater(&dir, false, SupervisorKind::Systemd) + .reconcile_journal() + .expect("journal entry"); + assert_eq!(resolved.status, SelfUpdateStatus::Failed); + let error = resolved.error.expect("failure must explain itself"); + assert!(error.contains("v999.0.0"), "{error}"); + // The operator needs to be told where the old binary went. + assert!(error.contains("/usr/local/bin/temps.bak"), "{error}"); + let _ = std::fs::remove_dir_all(&dir); + } + + #[test] + fn test_resolved_journal_is_left_alone() { + // Already-decided attempts must not be re-resolved on every boot, + // which would rewrite a success into a failure once the NEXT version + // is installed. + let dir = temp_dir("journal-stable"); + let attempt = SelfUpdateAttempt { + from_version: "v0.0.1".to_string(), + to_version: Some("v0.0.2".to_string()), + status: SelfUpdateStatus::Succeeded, + started_at: Utc::now(), + finished_at: Some(Utc::now()), + triggered_by_user_id: None, + error: None, + previous_binary_path: None, + }; + write_journal(&dir.join(SELF_UPDATE_JOURNAL_FILE), &attempt).expect("write journal"); + let resolved = updater(&dir, false, SupervisorKind::Systemd) + .reconcile_journal() + .expect("journal entry"); + assert_eq!(resolved.status, SelfUpdateStatus::Succeeded); + assert_eq!(resolved.to_version.as_deref(), Some("v0.0.2")); + let _ = std::fs::remove_dir_all(&dir); + } + + #[test] + fn test_missing_journal_is_not_an_error() { + let dir = temp_dir("journal-absent"); + assert!(updater(&dir, false, SupervisorKind::Systemd) + .reconcile_journal() + .is_none()); + let _ = std::fs::remove_dir_all(&dir); + } + + #[test] + fn test_corrupt_journal_degrades_instead_of_failing_startup() { + let dir = temp_dir("journal-corrupt"); + std::fs::write(dir.join(SELF_UPDATE_JOURNAL_FILE), "{not json").expect("write"); + assert!(updater(&dir, false, SupervisorKind::Systemd) + .reconcile_journal() + .is_none()); + let _ = std::fs::remove_dir_all(&dir); + } + + #[test] + fn test_preflight_rejects_a_binary_that_cannot_run() { + let dir = temp_dir("preflight"); + // Not a valid executable — exec must fail, and the error must say the + // running version is untouched. + let err = preflight_binary(&dir.join("temps"), b"definitely not an executable") + .expect_err("must reject"); + assert!(err.to_string().contains("left untouched"), "{err}"); + // The probe file must not be left behind. + assert!(!dir.join(".temps-update-probe").exists()); + let _ = std::fs::remove_dir_all(&dir); + } + + #[test] + fn test_backup_keeps_the_original_in_place() { + let dir = temp_dir("backup"); + let binary = dir.join("temps"); + let backup = backup_current_binary(&binary) + .expect("backup") + .expect("path"); + assert!(binary.exists(), "the original must never be moved away"); + assert!(backup.exists()); + assert_eq!( + std::fs::read(&binary).unwrap(), + std::fs::read(&backup).unwrap() + ); + let _ = std::fs::remove_dir_all(&dir); + } +} diff --git a/crates/temps-cli/src/commands/upgrade.rs b/crates/temps-cli/src/commands/upgrade.rs index 3b4e8b593..02b3bd519 100644 --- a/crates/temps-cli/src/commands/upgrade.rs +++ b/crates/temps-cli/src/commands/upgrade.rs @@ -184,9 +184,9 @@ pub struct GitHubRelease { #[derive(Clone, Deserialize, Debug)] pub struct GitHubAsset { - name: String, - browser_download_url: String, - size: u64, + pub(crate) name: String, + pub(crate) browser_download_url: String, + pub(crate) size: u64, } impl UpgradeCommand { @@ -843,7 +843,7 @@ pub async fn update_notifier_loop( } /// Determine the platform target string matching release asset names. -fn platform_target() -> anyhow::Result { +pub(crate) fn platform_target() -> anyhow::Result { let target = match (OS, ARCH) { ("macos", "x86_64") => "darwin-amd64", ("macos", "aarch64") => "darwin-arm64", @@ -921,7 +921,7 @@ fn pick_release_for_channel( } /// Fetch a specific release by tag from GitHub. -async fn fetch_specific_release(version: &str) -> anyhow::Result { +pub(crate) async fn fetch_specific_release(version: &str) -> anyhow::Result { // Ensure the version starts with 'v' let tag = if version.starts_with('v') { version.to_string() @@ -1037,7 +1037,7 @@ pub(crate) fn verify_checksum(data: &[u8], checksum_text: &str) -> anyhow::Resul } /// Extract the `temps` binary from a gzipped tarball. -fn extract_binary_from_tarball(tarball_bytes: &[u8]) -> anyhow::Result> { +pub(crate) fn extract_binary_from_tarball(tarball_bytes: &[u8]) -> anyhow::Result> { use flate2::read::GzDecoder; use std::io::Read; @@ -1061,7 +1061,7 @@ fn extract_binary_from_tarball(tarball_bytes: &[u8]) -> anyhow::Result> } /// Check we have write permission to the binary path. -fn check_write_permission(binary_path: &PathBuf) -> anyhow::Result<()> { +pub(crate) fn check_write_permission(binary_path: &PathBuf) -> anyhow::Result<()> { // Check the parent directory is writable (for atomic rename) let parent = binary_path .parent() @@ -1098,7 +1098,7 @@ fn check_write_permission(binary_path: &PathBuf) -> anyhow::Result<()> { /// 1. Write new binary to a temp file next to the target /// 2. Set executable permissions /// 3. Rename temp file over the target (atomic on the same filesystem) -fn replace_binary(binary_path: &PathBuf, new_binary: &[u8]) -> anyhow::Result<()> { +pub(crate) fn replace_binary(binary_path: &PathBuf, new_binary: &[u8]) -> anyhow::Result<()> { let parent = binary_path .parent() .ok_or_else(|| anyhow::anyhow!("Cannot determine parent directory"))?; diff --git a/crates/temps-config/src/handler.rs b/crates/temps-config/src/handler.rs index 307cd4e70..56112f854 100644 --- a/crates/temps-config/src/handler.rs +++ b/crates/temps-config/src/handler.rs @@ -34,6 +34,11 @@ pub struct SettingsState { /// (e.g. the standalone proxy's plugin context) — the update-status /// endpoint then reports "no update known". pub update_status: Option>, + /// Applies a release and restarts the server. `None` in hosts that cannot + /// meaningfully restart themselves (e.g. the standalone proxy) — the + /// update endpoints then report the feature as unsupported here rather + /// than pretending it is merely misconfigured. + pub self_updater: Option>, } #[derive(Debug, Clone, serde::Serialize)] @@ -60,6 +65,36 @@ impl AuditOperation for SettingsUpdatedAudit { } } +/// Audit record for a console-triggered platform update. Written before the +/// process exits, so the trail survives the restart it causes. +#[derive(Debug, Clone, serde::Serialize)] +struct PlatformUpdateStartedAudit { + context: AuditContext, + /// Version the server was running when the update was requested. + from_version: String, + /// Explicitly pinned target, or `None` for "newest on this channel". + target_version: Option, +} + +impl AuditOperation for PlatformUpdateStartedAudit { + fn operation_type(&self) -> String { + "PLATFORM_UPDATE_STARTED".to_string() + } + fn user_id(&self) -> Option { + Some(self.context.user_id) + } + fn ip_address(&self) -> Option { + self.context.ip_address.clone() + } + fn user_agent(&self) -> &str { + &self.context.user_agent + } + fn serialize(&self) -> anyhow::Result { + serde_json::to_string(self) + .map_err(|e| anyhow::anyhow!("Failed to serialize audit operation {}", e)) + } +} + /// Response for successful settings update #[derive(Debug, Serialize, Deserialize, ToSchema)] pub struct SettingsUpdateResponse { @@ -175,6 +210,11 @@ pub struct AppSettingsResponse { /// Per-turn limits for the AI chat. No sensitive content. pub ai_chat_limits: AiChatLimitsSettings, + /// Whether admins may apply a release from the console. This is the + /// database-backed toggle only — a server started with + /// `--disable-self-update` refuses regardless of what this says, which + /// `GET /settings/update` reports as the authoritative answer. + pub self_update: temps_core::SelfUpdateSettings, } /// Monitoring settings with the ClickHouse DSN masked. @@ -387,6 +427,7 @@ impl From for AppSettingsResponse { cluster_dns: settings.cluster_dns, build_limits: settings.build_limits, ai_chat_limits: settings.ai_chat_limits, + self_update: settings.self_update, } } } @@ -465,6 +506,8 @@ impl AppSettingsResponse { paths( get_settings, get_update_status, + get_update_capability, + start_update, get_disk_status, update_settings, generate_join_token, @@ -503,6 +546,15 @@ impl AppSettingsResponse { EnrollmentTokenListResponse, RouteRefreshResponse, UpdateStatusResponse, + UpdateCapabilityResponse, + StartUpdateRequest, + StartUpdateResponse, + temps_core::SelfUpdateSettings, + temps_core::SelfUpdateAttempt, + temps_core::SelfUpdateBlocker, + temps_core::SelfUpdatePhase, + temps_core::SelfUpdateStatus, + temps_core::SupervisorKind, )), info( title = "Settings API", @@ -518,6 +570,10 @@ pub fn configure_routes() -> Router> { .route("/settings", get(get_settings)) .route("/settings", put(update_settings)) .route("/settings/update-status", get(get_update_status)) + .route( + "/settings/update", + get(get_update_capability).post(start_update), + ) .route("/settings/disk-status", get(get_disk_status)) .route("/settings/join-token/generate", post(generate_join_token)) .route("/settings/join-token", delete(revoke_join_token)) @@ -823,6 +879,273 @@ async fn get_update_status( Ok(Json(response)) } +// ── Applying a release from the console ────────────────────────────────────── + +/// Whether this install can apply a release update on request, and how the last +/// attempt went. +/// +/// Deliberately answerable even when the answer is "no": an operator who cannot +/// use the button still needs to know *why* and what to run instead, so this +/// never 404s or returns an empty body when the feature is unavailable. +#[derive(Debug, Serialize, ToSchema)] +pub struct UpdateCapabilityResponse { + /// True only when a request would actually download, install and restart. + pub can_apply: bool, + /// Whether the *caller* holds `platform:update`. Distinct from `can_apply`, + /// which describes the server: the console shows the action only when both + /// are true, so a reader is never offered a button that would 403. + pub allowed: bool, + /// Machine-readable reason `can_apply` is false (`disabled_by_flag`, + /// `disabled_by_setting`, `container`, `no_supervisor`, `binary_not_writable`, + /// `unsupported_platform`, `in_progress`). + pub blocker: Option, + /// Operator-facing explanation of `blocker`. + pub reason: Option, + /// Non-blocking warning to show with the confirmation (split topology). + pub caveat: Option, + /// The equivalent command to run by hand. Always present. + pub manual_command: String, + /// What would restart the process: `systemd`, `launchd`, `container`, `none`. + pub supervisor: temps_core::SupervisorKind, + /// Binary that would be replaced. + pub binary_path: String, + /// Phase of an in-flight attempt: `idle` when none is running. + pub phase: temps_core::SelfUpdatePhase, + /// Failure detail while `phase` is `failed`. + pub phase_error: Option, + /// Most recent attempt, including one resolved during this boot — this is + /// how the console reports the outcome of an update that restarted it. + pub last_attempt: Option, +} + +/// Optional pin for the version to install. +#[derive(Debug, Default, Deserialize, ToSchema)] +pub struct StartUpdateRequest { + /// Release tag to install (e.g. `v0.2.0`). Omit to take the newest release + /// on the channel this install already tracks. + pub version: Option, +} + +/// Acknowledgement that an update was accepted and is running. +#[derive(Debug, Serialize, ToSchema)] +pub struct StartUpdateResponse { + /// Version the server is running as it accepts this request. + pub current_version: String, + /// How long to allow for the server to come back before treating the + /// restart as failed. + pub estimated_restart_secs: u64, + pub message: String, +} + +/// Build the "no updater registered in this process" answer. +/// +/// Reached in hosts that run the settings API without owning the process +/// lifecycle. Reported as a capability with a reason rather than an error, so +/// the console renders the same explain-and-point-at-the-CLI surface it uses +/// for every other blocked state. +fn updater_unavailable_response(allowed: bool) -> UpdateCapabilityResponse { + UpdateCapabilityResponse { + can_apply: false, + allowed, + blocker: Some(temps_core::SelfUpdateBlocker::NoSupervisor), + reason: Some( + "This process does not manage the temps binary, so it cannot apply an update. \ + Upgrade from the command line on the host instead." + .to_string(), + ), + caveat: None, + manual_command: "temps upgrade".to_string(), + supervisor: temps_core::SupervisorKind::None, + binary_path: String::new(), + phase: temps_core::SelfUpdatePhase::Idle, + phase_error: None, + last_attempt: None, + } +} + +/// Report whether a release update can be applied from the console. +#[utoipa::path( + tag = "Settings", + get, + path = "/settings/update", + responses( + (status = 200, description = "Self-update capability for this install", body = UpdateCapabilityResponse), + (status = 401, description = "Unauthorized"), + (status = 403, description = "Insufficient permissions") + ), + security(("bearer_auth" = [])) +)] +async fn get_update_capability( + RequireAuth(auth): RequireAuth, + State(app_state): State>, +) -> Result { + // Readable by anyone who can read settings: the banner needs this to decide + // what to render. Actually *starting* an update needs `platform:update`, + // reported separately as `allowed`. + permission_guard!(auth, SettingsRead); + + let allowed = auth.has_permission(&temps_auth::Permission::PlatformUpdate); + + let Some(updater) = app_state.self_updater.as_ref() else { + return Ok(Json(updater_unavailable_response(allowed))); + }; + + // The database toggle is only half the answer; the updater combines it with + // the launch flag and the environment to decide what is actually possible. + let enabled_in_settings = app_state + .config_service + .get_settings() + .await + .map(|s| s.self_update.enabled) + // Fail closed: if the setting cannot be read we must not report a + // capability the operator may have turned off. + .unwrap_or(false); + + let capability = updater.capability(enabled_in_settings); + Ok(Json(UpdateCapabilityResponse { + // Describes the SERVER only. Permission is reported separately as + // `allowed` so a blocked install and an under-privileged caller stay + // distinguishable — collapsing them would leave the UI unable to say + // which of the two it is looking at. + can_apply: capability.can_apply, + allowed, + blocker: capability.blocker, + reason: capability.reason, + caveat: capability.caveat, + manual_command: capability.manual_command, + supervisor: capability.supervisor, + binary_path: capability.binary_path, + phase: capability.phase, + phase_error: capability.phase_error, + last_attempt: capability.last_attempt, + })) +} + +/// Install a release and restart the server. +/// +/// Returns as soon as the attempt is accepted: the download and swap run in the +/// background and the process then exits so its supervisor restarts it on the +/// new binary. Poll `GET /settings/update` for progress — after the restart, +/// `last_attempt` carries the outcome. +#[utoipa::path( + tag = "Settings", + post, + path = "/settings/update", + request_body = StartUpdateRequest, + responses( + (status = 202, description = "Update accepted; the server will restart", body = StartUpdateResponse), + (status = 401, description = "Unauthorized"), + (status = 403, description = "Insufficient permissions"), + (status = 409, description = "Update unavailable or already running", body = temps_core::ProblemDetails), + (status = 501, description = "This process cannot apply updates", body = temps_core::ProblemDetails) + ), + security(("bearer_auth" = [])) +)] +async fn start_update( + RequireAuth(auth): RequireAuth, + State(app_state): State>, + Extension(metadata): Extension, + Json(request): Json, +) -> Result { + // NOT SettingsWrite: replacing the running binary and dropping every + // in-flight request is a different class of action from editing a config + // value, so it carries its own permission. + permission_guard!(auth, PlatformUpdate); + + let Some(updater) = app_state.self_updater.as_ref() else { + return Err(ErrorBuilder::new(StatusCode::NOT_IMPLEMENTED) + .title("Self-Update Not Supported Here") + .detail( + "This process does not manage the temps binary. Upgrade from the command line \ + on the host with `temps upgrade`.", + ) + .build()); + }; + + let enabled_in_settings = app_state + .config_service + .get_settings() + .await + .map(|s| s.self_update.enabled) + .unwrap_or(false); + + let started = updater + .start( + request.version.clone(), + Some(auth.user_id()), + enabled_in_settings, + ) + .map_err(self_update_error_to_problem)?; + + // Audited BEFORE the restart — the process is about to exit, and an update + // that leaves no trace of who triggered it is exactly the record an + // operator needs afterwards. + let audit = PlatformUpdateStartedAudit { + context: AuditContext { + user_id: auth.user_id(), + ip_address: Some(metadata.ip_address.clone()), + user_agent: metadata.user_agent.clone(), + }, + from_version: started.current_version.clone(), + target_version: request.version.clone(), + }; + if let Err(e) = app_state.audit_service.create_audit_log(&audit).await { + error!("Failed to create audit log for platform update: {}", e); + } + + info!( + user_id = auth.user_id(), + from = %started.current_version, + target = ?request.version, + "Platform update started from the console" + ); + + Ok(( + StatusCode::ACCEPTED, + Json(StartUpdateResponse { + current_version: started.current_version, + estimated_restart_secs: started.estimated_restart_secs, + message: "Update started. The server will restart when the new binary is installed." + .to_string(), + }), + )) +} + +fn self_update_error_to_problem(error: temps_core::SelfUpdateError) -> Problem { + use temps_core::{SelfUpdateBlocker, SelfUpdateError}; + let status = match error { + // Every blocker describes current state that the caller can change + // (a flag, a setting, a running attempt, the host itself) rather than a + // malformed request, so they are all conflicts. + SelfUpdateError::Unavailable { .. } | SelfUpdateError::AlreadyRunning { .. } => { + StatusCode::CONFLICT + } + }; + let blocker = error.blocker(); + let title = match blocker { + SelfUpdateBlocker::DisabledByFlag | SelfUpdateBlocker::DisabledBySetting => { + "Self-Update Disabled" + } + SelfUpdateBlocker::InProgress => "Update Already Running", + SelfUpdateBlocker::Container => "Self-Update Not Possible In A Container", + SelfUpdateBlocker::NoSupervisor => "No Process Supervisor", + SelfUpdateBlocker::BinaryNotWritable => "Binary Not Writable", + SelfUpdateBlocker::UnsupportedPlatform => "Unsupported Platform", + }; + ErrorBuilder::new(status) + .title(title) + .detail(error.to_string()) + .value( + "blocker", + serde_json::to_value(blocker) + .unwrap_or(serde_json::Value::Null) + .as_str() + .unwrap_or_default() + .to_string(), + ) + .build() +} + /// Get application settings #[utoipa::path( tag = "Settings", diff --git a/crates/temps-config/src/plugin.rs b/crates/temps-config/src/plugin.rs index f6a346149..018a79070 100644 --- a/crates/temps-config/src/plugin.rs +++ b/crates/temps-config/src/plugin.rs @@ -74,6 +74,10 @@ impl TempsPlugin for ConfigPlugin { // not). Optional: without it, update-status just reports "no update". let update_status = context.get_service::(); + // Same optionality as the slot above, for the same reason: only a host + // that owns the binary and the process lifecycle registers an updater. + let self_updater = context.get_service::(); + // Create SettingsState let settings_state = Arc::new(SettingsState { config_service, @@ -81,6 +85,7 @@ impl TempsPlugin for ConfigPlugin { route_table_refresher, enrollment_token_service, update_status, + self_updater, }); // Configure routes with the state diff --git a/crates/temps-core/src/app_settings.rs b/crates/temps-core/src/app_settings.rs index 140787d2f..1e3d1cd38 100644 --- a/crates/temps-core/src/app_settings.rs +++ b/crates/temps-core/src/app_settings.rs @@ -121,6 +121,16 @@ pub struct AppSettings { #[serde(default)] pub require_mfa_for_admins: bool, + /// One-click "Update now" from the console. Enabled by default; an admin + /// can turn it off here to keep upgrades on the CLI/config-management path. + /// + /// This is the *soft* switch — it is stored in the database, so whoever can + /// write settings can also turn it back on. Operators who need an upgrade + /// path that no console session can re-open should start the server with + /// `--disable-self-update`, which wins over this field unconditionally. + #[serde(default)] + pub self_update: SelfUpdateSettings, + /// Binary version tag (e.g. "v0.1.0") of the *console* process /// (`temps serve`, role=all or role=console) that last started. Written /// on console startup; read by the standalone `temps proxy` to detect @@ -905,11 +915,32 @@ impl Default for AppSettings { observability_retention: ObservabilityRetentionSettings::default(), setup_complete: false, require_mfa_for_admins: false, + self_update: SelfUpdateSettings::default(), console_version: None, } } } +/// Controls the console's one-click "Update now" action. +#[derive(Debug, Clone, Serialize, Deserialize, ToSchema, PartialEq, Eq)] +#[serde(default)] +pub struct SelfUpdateSettings { + /// Allow admins to apply a release and restart the server from the console. + /// `true` by default: the action is permission-gated, audited, and only + /// ever installs an official release whose published SHA-256 matches. + /// + /// Turning this off hides nothing — the console still shows the update + /// banner and the manual command, it just refuses to run it for you. + #[schema(example = true)] + pub enabled: bool, +} + +impl Default for SelfUpdateSettings { + fn default() -> Self { + Self { enabled: true } + } +} + impl Default for ContainerLogSettings { fn default() -> Self { Self { diff --git a/crates/temps-core/src/lib.rs b/crates/temps-core/src/lib.rs index 781db0af9..097fd5075 100644 --- a/crates/temps-core/src/lib.rs +++ b/crates/temps-core/src/lib.rs @@ -24,6 +24,7 @@ pub mod public_hostname_resolver; pub mod retention; pub mod retry; pub mod secrets_manager; +pub mod self_update; pub mod sensitive_action; pub mod telemetry; pub mod time_window; @@ -31,6 +32,10 @@ pub mod tls; pub mod traces; pub mod update_status; pub use problemdetails::ProblemDetails; +pub use self_update::{ + SelfUpdateAttempt, SelfUpdateBlocker, SelfUpdateCapability, SelfUpdateError, SelfUpdatePhase, + SelfUpdateStatus, SelfUpdater, StartedSelfUpdate, SupervisorKind, SELF_UPDATE_JOURNAL_FILE, +}; pub use update_status::{AvailableUpdate, UpdateStatusSlot, UPGRADE_DOCS_URL}; mod app_settings; mod constants; @@ -96,7 +101,7 @@ pub use app_settings::{ DockerRegistrySettings, LetsEncryptSettings, MetricsStoreKind, MonitoringSettings, MultiNodeSettings, ObservabilityCompressionSettings, ObservabilityRetentionSettings, PreviewGatewaySettings, ProviderConfig, RateLimitSettings, ScreenshotSettings, - SecurityHeadersSettings, + SecurityHeadersSettings, SelfUpdateSettings, }; pub use async_trait; pub use chrono; diff --git a/crates/temps-core/src/self_update.rs b/crates/temps-core/src/self_update.rs new file mode 100644 index 000000000..4894688ae --- /dev/null +++ b/crates/temps-core/src/self_update.rs @@ -0,0 +1,309 @@ +//! Contract for applying a release update to the running binary from the API. +//! +//! Lives in temps-core because the two crates involved must not depend on each +//! other: the implementation belongs to temps-cli (it owns the binary path, the +//! release downloader and the process lifecycle), while the HTTP surface +//! belongs to temps-config (`POST /settings/update`). The console registers the +//! implementation as a service; ConfigPlugin picks it up if present. +//! +//! **Why a capability instead of "just do it":** replacing the binary is only +//! half the job — the process then has to come back on the new one. That is +//! only true when something supervises it (systemd `Restart=always`, launchd +//! `KeepAlive`). Inside a container the binary lives in the image, so a swap is +//! discarded on the next container recreate and a restart returns to the OLD +//! version; run from a shell, exiting is simply permanent downtime. So the +//! capability is reported honestly up front, with the reason and the manual +//! command to run instead, rather than discovering it after the process is gone. + +use chrono::{DateTime, Utc}; +use serde::{Deserialize, Serialize}; +use utoipa::ToSchema; + +/// File under the data dir recording the in-flight/last update attempt. Read +/// back on the next boot to report the outcome of an update that, by +/// definition, killed the process that started it. +pub const SELF_UPDATE_JOURNAL_FILE: &str = "self-update.json"; + +/// What (if anything) will restart the process after it exits. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ToSchema)] +#[serde(rename_all = "snake_case")] +pub enum SupervisorKind { + /// Started by systemd (detected via `INVOCATION_ID`). The unit installed by + /// `deploy.sh` carries `Restart=always`, so exiting restarts on the new binary. + Systemd, + /// Started by launchd (detected via `XPC_SERVICE_NAME`), the macOS install path. + Launchd, + /// Running inside a container. The binary comes from the image, so a + /// self-update cannot survive a container recreate — never updatable. + Container, + /// No supervisor found: a foreground/manual `temps serve`. Exiting is downtime. + None, +} + +impl SupervisorKind { + /// Can a process under this supervisor be expected to come back after exit? + pub fn restarts_on_exit(self) -> bool { + matches!(self, Self::Systemd | Self::Launchd) + } + + pub fn as_str(self) -> &'static str { + match self { + Self::Systemd => "systemd", + Self::Launchd => "launchd", + Self::Container => "container", + Self::None => "none", + } + } +} + +/// Why a one-click update is unavailable. Exactly one is reported — the most +/// fundamental blocker wins, so the operator fixes the real problem first +/// rather than clearing one only to hit the next. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ToSchema)] +#[serde(rename_all = "snake_case")] +pub enum SelfUpdateBlocker { + /// The operator started the server with `--disable-self-update`. Deliberate + /// and NOT overridable from the API — see the module docs on the two levels. + DisabledByFlag, + /// Turned off in Settings (`self_update.enabled = false`). An admin can turn + /// it back on in the UI. + DisabledBySetting, + /// Running in a container: update the image tag instead. + Container, + /// Nothing would restart the process after it exits. + NoSupervisor, + /// The binary (or its directory) is not writable by the server user. + BinaryNotWritable, + /// No release assets are published for this OS/arch. + UnsupportedPlatform, + /// Another update attempt is already running. + InProgress, +} + +/// Where an in-flight update has got to. Polled by the console so a long +/// download shows progress instead of an indefinite spinner. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ToSchema, Default)] +#[serde(rename_all = "snake_case")] +pub enum SelfUpdatePhase { + /// Nothing running. + #[default] + Idle, + /// Resolving the target release from the release API. + Resolving, + /// Downloading the release tarball. + Downloading, + /// Checking the published SHA-256 and running `--version` on the new binary. + Verifying, + /// Swapping the binary on disk (previous one kept as a `.bak` sibling). + Installing, + /// Binary swapped; the process is shutting down so the supervisor restarts it. + Restarting, + /// The attempt failed. The running binary was left untouched. + Failed, +} + +impl SelfUpdatePhase { + /// Is an attempt currently occupying the updater? + pub fn is_active(self) -> bool { + matches!( + self, + Self::Resolving | Self::Downloading | Self::Verifying | Self::Installing + ) + } + + pub fn as_str(self) -> &'static str { + match self { + Self::Idle => "idle", + Self::Resolving => "resolving", + Self::Downloading => "downloading", + Self::Verifying => "verifying", + Self::Installing => "installing", + Self::Restarting => "restarting", + Self::Failed => "failed", + } + } +} + +/// Outcome of an update attempt, as persisted in the journal. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ToSchema)] +#[serde(rename_all = "snake_case")] +pub enum SelfUpdateStatus { + /// Binary swapped, process exiting — written just before shutdown and + /// resolved on the next boot by comparing the running version to the target. + Pending, + /// The process came back on the target version. + Succeeded, + /// The attempt failed before the swap, or the process came back on the old + /// version despite a completed swap. + Failed, +} + +/// A single update attempt. Persisted to `/self-update.json` so the +/// result survives the restart it causes. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema)] +pub struct SelfUpdateAttempt { + /// Version the attempt started from. + pub from_version: String, + /// Version the attempt targeted. `None` if it failed before resolving one. + pub to_version: Option, + pub status: SelfUpdateStatus, + #[schema(value_type = String, format = DateTime, example = "2026-08-06T09:12:31Z")] + pub started_at: DateTime, + /// When the outcome was decided. `None` while still `Pending`. + #[schema(value_type = Option, format = DateTime)] + pub finished_at: Option>, + /// User who clicked the button. `None` for attempts started by the CLI. + pub triggered_by_user_id: Option, + /// Operator-facing failure reason. Always set when `status` is `Failed`. + pub error: Option, + /// Where the replaced binary was kept, so a bad release can be reverted by + /// hand (`mv `). Set once the swap completes. + pub previous_binary_path: Option, +} + +/// Everything the console needs to render the update control honestly: whether +/// it can run, why not, what to do instead, and how the last attempt went. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema)] +pub struct SelfUpdateCapability { + /// True only when a click would actually download, swap and come back up. + pub can_apply: bool, + /// Set iff `can_apply` is false. + pub blocker: Option, + /// Operator-facing explanation of `blocker`, naming the specific thing that + /// is wrong (path, supervisor, flag) rather than a generic refusal. + pub reason: Option, + /// Command to run by hand instead. Always present — the manual path works + /// even when the API path is blocked, so the operator is never stuck. + pub manual_command: String, + pub supervisor: SupervisorKind, + /// Absolute path of the binary that would be replaced. + pub binary_path: String, + /// Something true about this topology that the operator must know *before* + /// clicking, even though it does not block the update — currently the + /// split-topology case, where restarting the console leaves the separate + /// proxy process on the old binary. Shown alongside the confirmation. + pub caveat: Option, + /// Phase of the in-flight attempt (`idle` when none). + pub phase: SelfUpdatePhase, + /// Failure detail for `phase == failed`, before it is cleared by a retry. + pub phase_error: Option, + /// The most recent attempt, including one resolved on this boot. + pub last_attempt: Option, +} + +/// Accepted-update receipt returned by `start`. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema)] +pub struct StartedSelfUpdate { + /// Version the server is running right now. + pub current_version: String, + /// How long the console should expect to wait before the server answers + /// again, so it can poll with a sensible timeout instead of guessing. + pub estimated_restart_secs: u64, +} + +#[derive(Debug, thiserror::Error)] +pub enum SelfUpdateError { + #[error("Self-update is unavailable on this install: {reason}")] + Unavailable { + blocker: SelfUpdateBlocker, + reason: String, + }, + #[error("An update is already running (phase: {phase})")] + AlreadyRunning { phase: &'static str }, +} + +impl SelfUpdateError { + /// The blocker behind this error, for mapping to a response body. + pub fn blocker(&self) -> SelfUpdateBlocker { + match self { + Self::Unavailable { blocker, .. } => *blocker, + Self::AlreadyRunning { .. } => SelfUpdateBlocker::InProgress, + } + } +} + +/// Applies a published release to the running install. +/// +/// Registered as a service by `temps serve` and consumed by the settings API. +/// Absent in hosts that cannot restart themselves meaningfully (e.g. the +/// standalone proxy), in which case the endpoint reports "not supported here". +pub trait SelfUpdater: Send + Sync { + /// Report whether an update can be applied right now. + /// + /// `enabled_in_settings` is passed in rather than read here: the setting + /// lives in the database, which this trait deliberately knows nothing + /// about. The caller (which already loaded `AppSettings`) supplies it. + fn capability(&self, enabled_in_settings: bool) -> SelfUpdateCapability; + + /// Begin an update. Returns as soon as the attempt is accepted — the + /// download, swap and restart continue in the background and are observable + /// through `capability().phase`, then through the journal after the restart. + /// + /// `target_version` pins a specific tag; `None` takes the newest release on + /// this install's channel. + fn start( + &self, + target_version: Option, + triggered_by_user_id: Option, + enabled_in_settings: bool, + ) -> Result; +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_only_real_supervisors_restart_on_exit() { + assert!(SupervisorKind::Systemd.restarts_on_exit()); + assert!(SupervisorKind::Launchd.restarts_on_exit()); + // A container restart returns to the image's binary, not the swapped + // one, so it must never count as "will come back updated". + assert!(!SupervisorKind::Container.restarts_on_exit()); + assert!(!SupervisorKind::None.restarts_on_exit()); + } + + #[test] + fn test_only_pre_restart_phases_are_active() { + for phase in [ + SelfUpdatePhase::Resolving, + SelfUpdatePhase::Downloading, + SelfUpdatePhase::Verifying, + SelfUpdatePhase::Installing, + ] { + assert!(phase.is_active(), "{phase:?} should occupy the updater"); + } + // Restarting is deliberately NOT active: the swap is done and the + // process is on its way out, so a second attempt has nothing to race. + assert!(!SelfUpdatePhase::Restarting.is_active()); + assert!(!SelfUpdatePhase::Idle.is_active()); + assert!(!SelfUpdatePhase::Failed.is_active()); + } + + #[test] + fn test_already_running_maps_to_in_progress_blocker() { + let err = SelfUpdateError::AlreadyRunning { + phase: "downloading", + }; + assert_eq!(err.blocker(), SelfUpdateBlocker::InProgress); + } + + #[test] + fn test_attempt_roundtrips_through_json() { + // The journal is written by one process and read by its successor, so + // the on-disk shape must survive a serialize/deserialize round trip. + let attempt = SelfUpdateAttempt { + from_version: "v0.1.0".to_string(), + to_version: Some("v0.2.0".to_string()), + status: SelfUpdateStatus::Pending, + started_at: Utc::now(), + finished_at: None, + triggered_by_user_id: Some(7), + error: None, + previous_binary_path: Some("/usr/local/bin/temps.bak".to_string()), + }; + let json = serde_json::to_string(&attempt).expect("serialize"); + let parsed: SelfUpdateAttempt = serde_json::from_str(&json).expect("deserialize"); + assert_eq!(parsed, attempt); + } +} diff --git a/web/src/api/client/@tanstack/react-query.gen.ts b/web/src/api/client/@tanstack/react-query.gen.ts index 9b7b132ba..c1dd5207c 100644 --- a/web/src/api/client/@tanstack/react-query.gen.ts +++ b/web/src/api/client/@tanstack/react-query.gen.ts @@ -3,8 +3,8 @@ import { type DefaultError, type InfiniteData, infiniteQueryOptions, queryOptions, type UseMutationOptions } from '@tanstack/react-query'; import { client } from '../client.gen'; -import { acknowledgeAlarm, activateAiProvider, activateApiKey, activateConnection, activateProvider, addClusterMember, addContext, addEnvironmentDomain, addEvents, addManagedDomain, addSessionReplayEvents, addTeamMember, adminDrainNode, adminDrainStatus, adminGetNode, adminListNodeContainers, adminListNodes, adminRemoveNode, adminUndrainNode, applyHostnameMode, archiveConversation, archiveFlag, assignRole, attachScheduleServices, blobCopy, blobDelete, blobDisable, blobDownload, blobEnable, blobList, blobPut, blobStatus, blobUpdate, cancel, cancelBackup, cancelDeployment, cancelDomainOrder, cancelPgUpgrade, cancelRun, cancelScheduleRun, changePasswordSelf, changeProjectSource, changeRequiredPassword, chatCompletions, checkAnalyticsHasEvents, checkCommitExists, checkDomainStatus, checkExplorerSupport, checkIpBlocked, checkProviderDeletionSafety, chunkUploadOptions, cleanupExpiredBackups, clearPreviewPassword, cliDeviceApprove, cliDeviceDeny, cliDeviceLookup, cliDevicePoll, cliDeviceStart, cliLogout, cmd, cmdKill, cmdLogs, confirmPendingAction, containerMetricsGetHistory, createAgent, createAlert, createAlertRule, createApiKey, createBackupSchedule, createBitbucketProvider, createCloudflareProvider, createConversation, createCustomDomain, createDashboard, createDeploymentToken, createDnsProvider, createDomain, createDsn, createEmailDomain, createEmailProvider, createEnvironment, createEnvironmentVariable, createFlag, createFunnel, createGenericProvider, createGiteaPatProvider, createGithubPatProvider, createGitlabOauthProvider, createGitlabPatProvider, createGitProvider, createGlobalMcp, createGlobalSkill, createIncident, createIpAccessControl, createMcp, createMonitor, createNotificationEmailProvider, createNotificationProvider, createOidcProvider, createOidcRoleMapping, createOrRecreateOrder, createPlan, createPr, createProject, createProjectFromTemplate, createProjectRelease, createProjectSecret, createProviderKey, createRelease, createRoute, createS3Source, createSandbox, createService, createSkill, createSlackProvider, createTeam, createUser, createWebhook, createWebhookProvider, deactivateApiKey, deactivateConnection, deactivateProvider, deleteAgent, deleteAlert, deleteAlertRule, deleteApiKey, deleteBackup, deleteBackupSchedule, deleteConnection, deleteCustomDomain, deleteDashboard, deleteDeploymentToken, deleteDnsProvider, deleteDomain, deleteEmailDomain, deleteEmailProvider, deleteEnvironment, deleteEnvironmentDomain, deleteEnvironmentVariable, deleteExternalImage, deleteFunnel, deleteGitProvider, deleteGlobalMcp, deleteGlobalSkill, deleteIpAccessControl, deleteMcp, deleteMonitor, deleteNotificationProvider, deleteOidcProvider, deleteOidcRoleMapping, deletePreferences, deleteProject, deleteProjectSecret, deleteProviderKey, deleteProviderSafely, deleteReleaseSourceFiles, deleteReleaseSourceMaps, deleteRoute, deleteS3Source, deleteScan, deleteSecret, deleteService, deleteSessionReplay, deleteSkill, deleteSourceMap, deleteStaticBundle, deleteTeam, deleteUser, deleteWebhook, deployFromImage, deployFromImageUpload, deployFromStatic, deployFromUploadedSource, deploymentMetricsGetLatest, deploymentMetricsGetRange, deploymentMetricsToggle, destroySandbox, detachScheduleService, detectPublicPresets, disableBackupSchedule, disableMfa, discoverWorkloads, domain, downloadGlobalSkillArchive, downloadObject, downloadSkillArchive, emailStatus, embeddings, enableBackupSchedule, enrichVisitor, exec, execDetached, executeDeploymentOperation, executeImport, extendTimeout, externalServiceEnablePgStatStatements, externalServiceMetricsByDatabase, externalServiceMetricsCreateAlertRule, externalServiceMetricsDeleteAlertRule, externalServiceMetricsGetAlertRules, externalServiceMetricsGetLatest, externalServiceMetricsGetRange, externalServiceMetricsStatus, externalServiceMetricsToggle, externalServiceMetricsUpdateAlertRule, externalServiceResetPgStatStatements, finalizeOrder, finalizeProjectRelease, findConversation, generateJoinToken, generatePresetDockerfile, getAccessInfo, getActiveVisitors, getActivityGraph, getAdminGate, getAgent, getAggregatedBuckets, getAiAgentBreakdown, getAiAgentPages, getAiAgentTimeline, getAiPageBreakdown, getAiStatusBreakdown, getAlert, getAlertRule, getAllRepositoriesByName, getAnalyticsActiveVisitors, getAnalyticsEventsCount, getAnalyticsSessionEvents, getAnalyticsVisitorSessions, getApiKey, getApiKeyPermissions, getAuditLog, getBackup, getBackupSchedule, getBranchesByRepositoryId, getBucketedIncidents, getBucketedStatus, getChallengeToken, getChatReadiness, getCliStatus, getClusterHealth, getClusterMember, getCmd, getContainerDetail, getContainerEnvironmentVariable, getContainerInfo, getContainerLogs, getContainerLogsById, getContainerMetrics, getConversation, getConversationDetail, getConversations, getCronById, getCronExecutions, getCrossProjectTraceSiblings, getCurrentMonitorStatus, getCurrentUser, getCustomDomain, getDashboard, getDashboardProjectsAnalytics, getDelivery, getDeployment, getDeploymentContainerLogContent, getDeploymentJobLogs, getDeploymentJobs, getDeploymentOperations, getDeploymentOperationStatus, getDeploymentToken, getDiskStatus, getDnsChanges, getDnsProvider, getDomain, getDomainByHost, getDomainById, getDomainByName, getDomainDnsRecords, getDomainOrder, getEmail, getEmailEvents, getEmailLinks, getEmailProvider, getEmailStats, getEmailTracking, getEmailTrackingStatus, getEntityInfo, getEnvironment, getEnvironmentCrons, getEnvironmentDomains, getEnvironments, getEnvironmentVariables, getEnvironmentVariableValue, getErrorDashboardStats, getErrorEvent, getErrorGroup, getErrorStats, getErrorTimeSeries, getEventDetail, getEventEntries, getEventsCount, getEventsTimeline, getEventTypeBreakdown, getEventVisitors, getExternalImage, getFile, getFlag, getFlagSnapshot, getFunnelMetrics, getGenaiTrace, getGeneralStats, getGitProvider, getGlobalEvents, getGlobalEventStats, getGlobalMcp, getGlobalSandboxStatus, getGlobalSkill, getGroupedPageMetrics, getHealth, getHourlyVisits, getHttpChallengeDebug, getImportStatus, getIncident, getIncidentUpdates, getIpAccessControl, getIpGeolocation, getJoinTokenStatus, getLastDeployment, getLatestScan, getLatestScansPerEnvironment, getLiveVisitorsList, getLogContext, getMcp, getMetricsOverTime, getMonitor, getNotificationProvider, getOnDemandCertStatus, getOrCreateDsn, getPageFlow, getPageHourlySessions, getPagePathDetail, getPagePaths, getPagePathsSparklines, getPagePathVisitors, getPendingAction, getPerformanceMetrics, getPgUpgrade, getPgUpgradeLogs, getPipelineStats, getPlatformInfo, getPostgresWalHealth, getPreferences, getPreviewGatewayLogs, getPreviewGatewaySettings, getPreviewGatewayStatus, getPricing, getPrivateIp, getProject, getProjectAlarmsSummary, getProjectBySlug, getProjectDeployments, getProjects, getProjectServiceEnvironmentVariables, getProjectSessionReplays, getProjectsHealth, getProjectsMonitorHealth, getProjectStatistics, getProjectTemplate, getPropertyBreakdown, getPropertyTimeline, getProviderConnections, getProviderMetadata, getProvidersMetadata, getProxyLogById, getProxyLogByRequestId, getProxyLogs, getPublicBranches, getPublicIp, getPublicRepository, getQuota, getRecentActivity, getRemoteExternalImage, getRepositoryBranches, getRepositoryById, getRepositoryByName, getRepositoryPresetByName, getRepositoryPresetLive, getRepositoryTags, getResolvedEnvironmentVariables, getResolvedEnvironmentVariableValue, getRestoreCapabilities, getRestoreRun, getRoute, getRun, getRunWithLogs, getS3Credentials, getS3Source, getSandbox, getSandboxStatus, getScan, getScanByDeployment, getScanVulnerabilities, getService, getServiceBySlug, getServiceEnvironmentVariable, getServiceEnvironmentVariables, getServiceHealthStatus, getServicePreviewEnvironmentVariableNames, getServicePreviewEnvironmentVariablesMasked, getServiceRuntime, getServiceStats, getServiceTypeParameters, getServiceTypes, getSessionDetails, getSessionEvents, getSessionLogs, getSessionReplay, getSessionReplayEvents, getSettings, getSkill, getSlowQueries, getStaticBundle, getStatusOverview, getTagsByRepositoryId, getTeam, getTimeBucketStats, getTodayStats, getTrace, getUnifiedTrace, getUniqueCounts, getUniqueEvents, getUpdateStatus, getUptimeHistory, getUsageByProvider, getUsageRecent, getUsageSummary, getUsageTimeseries, getUsageTopModels, getVisitorByGuid, getVisitorById, getVisitorDetails, getVisitorFacets, getVisitorInfo, getVisitorJourney, getVisitors, getVisitorSessions, getVisitorStats, getWebhook, grantProjectAccess, handleGitProviderOauthCallback, hasAnalyticsEvents, hasErrorGroups, hasPerformanceMetrics, importExternalService, ingestLogs, ingestLogsByPath, ingestMetrics, ingestMetricsByPath, ingestSentryEnvelope, ingestSentryEvent, ingestTraces, ingestTracesByPath, initSessionReplay, inspectDropArchive, jobLogs, jobStatus, killJob, kvDel, kvDisable, kvEnable, kvExpire, kvGet, kvIncr, kvKeys, kvSet, kvStatus, kvTtl, kvUpdate, latestRunForSource, linkCustomDomainToCertificate, linkServiceToProject, listAgentRuns, listAgents, listAiProviders, listAlertRules, listAlerts, listAllConversations, listAllRuns, listApiKeys, listAuditLogs, listAvailableContainers, listBackupAlerts, listBackupChildren, listBackupSchedules, listBackupsForSchedule, listCommitsByRepositoryId, listConnections, listContainers, listContainersAtPath, listConversations, listCustomDomainsForProject, listDashboards, listDeliveries, listDeploymentContainerLogs, listDeploymentTokens, listDnsProviders, listDomains, listDsns, listEmailDomains, listEmailProviders, listEmails, listEnrollmentTokens, listEntities, listErrorEvents, listErrorGroups, listEvents, listEventTypes, listExternalImages, listExternalPlugins, listExternalServiceBackups, listFlags, listFunnels, listGitProviders, listGlobalMcps, listGlobalSkills, listIncidents, listInsights, listIpAccessControl, listJobs, listKnownAiAgents, listManagedDomains, listMcps, listMetricLabelKeys, listMetricLabelValues, listMetricNames, listModels, listMonitors, listNotificationProviders, listOidcProviders, listOidcProviderUsers, listOidcRoleMappings, listOnDemandCerts, listOrders, listPeers, listPendingActions, listPgUpgrades, listPresets, listProjectAccess, listProjectAlarms, listProjectScans, listProjectSecrets, listProjectServices, listProjectTemplates, listProjectTemplateTags, listProviderKeys, listProviderZones, listPublicProviders, listReleaseFiles, listReleases, listRemoteExternalImages, listRepositoriesByConnection, listRepositoriesByProvider, listRestoreRunsForService, listRootContainers, listRoutes, listS3Sources, listSandboxes, listScheduleRunJobs, listScheduleRuns, listScheduleServices, listSecrets, listServiceHealthStatuses, listServiceProjects, listServices, listServiceSchedules, listSkills, listSourceBackups, listSourceFiles, listSourceMaps, listSources, listStaticBundles, listSyncedRepositories, listTeamMembers, listTeamProjects, listTeams, listUsers, listWebhooks, login, logout, lookupDnsARecords, mintEnrollmentToken, mkdir, nodeHeartbeat, nodeMetricsGetRange, observabilityFullEvent, observabilityListEvents, oidcCallback, type Options, patchAdminGate, patchPreviewGatewaySettings, pauseDeployment, pauseSandbox, planRestore, postDnsAck, previewAlert, previewFunnelMetrics, previewHostnameMode, promoteClusterMember, promoteDeployment, provisionDomain, purgeProjectLogs, pushExternalImage, queryData, queryGenaiTraces, queryLogs, queryMetrics, queryTraces, queryTraceSummaries, readFile, reAnalyze, recordConsoleEvent, recordEventMetrics, recordFlagExposure, recordSpeedMetrics, refreshRouteTable, regenerateDsn, registerExternalImage, registerNode, reinstallGitlabWebhook, rejectPendingAction, reloadPlugins, removeClusterMember, removeManagedDomain, removeRole, removeTeamMember, renameConversation, renewDomain, requestPasswordReset, resetPassword, resizeSandbox, resolveAlarm, restartContainer, restartPreviewGateway, restartSandbox, restoreFlag, restoreUser, resumeDeployment, resumeSandbox, retryCluster, retryDelivery, retryPgUpgrade, retryRun, revealGlobalMcpConfig, revealMcpConfig, revealNotificationProviderConfig, revealServiceParameter, revenueCreateIntegration, revenueDeleteIntegration, revenueGlobalEvents, revenueImportInvoicesCsv, revenueImportSubscriptionsCsv, revenueListIntegrations, revenueListProviders, revenueMetricsCustomers, revenueMetricsGlobalMrr, revenueMetricsGlobalSummary, revenueMetricsMrr, revenueMetricsSummary, revenueRecentEvents, revenueRotateToken, revenueUpdateConfig, revenueUpdateSecret, revokeDsn, revokeEnrollmentToken, revokeJoinToken, revokeProjectAccess, rollbackPgUpgrade, rollbackToDeployment, rootfsGc, rootfsReport, rotateApiKey, rotateDeploymentToken, runBackupForSource, runConnectionHealthCheck, runExternalServiceBackup, runScheduleNow, sandboxCreatePreviewLink, saveAgentToken, saveAiProviderCredential, searchLogs, sendEmail, setDefaultS3Source, setFlagEnvironment, setPreviewPassword, setupDns, setupDnsChallenge, setupEmailTracking, setupMfa, sleepEnvironment, smokeTestAgent, sourceSandbox, startAnalysis, startContainer, startFix, startGitProviderOauth, startOidcLoginBySlug, startPgUpgrade, startRestore, startService, statPath, stopContainer, stopSandbox, stopService, streamContainerMetrics, syncRepositories, tailDeploymentJobLogs, tailLogs, teardownDeployment, teardownEnvironment, testNotificationProvider, testOidcProvider, testProvider, testProviderConnection, testProviderKeyById, testProviderKeyInline, testS3ConnectionPreview, testS3SourceConnection, trackClick, trackOpen, triggerAgent, triggerProjectPipeline, triggerScan, triggerServiceHealthCheck, triggerWeeklyDigest, unlinkServiceFromProject, updateAgent, updateAiProvider, updateAlert, updateAlertRule, updateApiKey, updateAutomaticDeploy, updateBackupSchedule, updateCloudflareProvider, updateConnectionToken, updateCustomDomain, updateDashboard, updateDeploymentToken, updateEmailProvider, updateEnvironmentSettings, updateEnvironmentSubdomain, updateEnvironmentVariable, updateErrorGroup, updateFlag, updateFunnel, updateGitProviderCredentials, updateGitSettings, updateGlobalMcp, updateGlobalSkill, updateIncidentStatus, updateIpAccessControl, updateManagedDomain, updateMcp, updateNotificationEmailProvider, updateNotificationProvider, updateOidcProvider, updatePreferences, updateProject, updateProjectDeploymentConfig, updateProjectSecret, updateProjectSettings, updateProvider, updateProviderKey, updateRoute, updateS3Source, updateSelf, updateService, updateServiceResources, updateSessionDuration, updateSettings, updateSkill, updateSlackProvider, updateSpeedMetrics, updateTeam, updateTeamMemberRole, updateUser, updateWebhook, updateWebhookProvider, upgradePreviewGateway, upgradeService, uploadGlobalSkill, uploadReleaseFile, uploadSkill, uploadSourceFile, uploadSourceMap, uploadStaticBundle, upsertSecret, validateConnection, validateEmail, verifyAndEnableMfa, verifyDomain, verifyEmail, verifyManagedDomain, verifyMfaChallenge, verifyStepUp, wakeEnvironment, webhookTrigger, workflowDryRun, writeFile, writeFiles } from '../sdk.gen'; -import type { AcknowledgeAlarmData, ActivateAiProviderData, ActivateAiProviderResponse, ActivateApiKeyData, ActivateApiKeyResponse, ActivateConnectionData, ActivateProviderData, AddClusterMemberData, AddClusterMemberResponse, AddContextData, AddEnvironmentDomainData, AddEnvironmentDomainResponse, AddEventsData, AddEventsError, AddEventsResponse2, AddManagedDomainData, AddManagedDomainResponse, AddSessionReplayEventsData, AddSessionReplayEventsError, AddSessionReplayEventsResponse, AddTeamMemberData, AddTeamMemberResponse, AdminDrainNodeData, AdminDrainNodeResponse, AdminDrainStatusData, AdminDrainStatusResponse, AdminGetNodeData, AdminGetNodeResponse, AdminListNodeContainersData, AdminListNodeContainersResponse, AdminListNodesData, AdminListNodesResponse, AdminRemoveNodeData, AdminRemoveNodeResponse, AdminUndrainNodeData, AdminUndrainNodeResponse, ApplyHostnameModeData, ApplyHostnameModeResponse, ArchiveConversationData, ArchiveConversationResponse, ArchiveFlagData, ArchiveFlagResponse2, AssignRoleData, AttachScheduleServicesData, AttachScheduleServicesError, AttachScheduleServicesResponse2, BlobCopyData, BlobCopyError, BlobCopyResponse, BlobDeleteData, BlobDeleteError, BlobDeleteResponse, BlobDisableData, BlobDisableResponse, BlobDownloadData, BlobDownloadError, BlobEnableData, BlobEnableResponse, BlobListData, BlobListError, BlobListResponse, BlobPutData, BlobPutError, BlobPutResponse, BlobStatusData, BlobStatusResponse2, BlobUpdateData, BlobUpdateResponse, CancelBackupData, CancelBackupError, CancelBackupResponse2, CancelData, CancelDeploymentData, CancelDeploymentResponse, CancelDomainOrderData, CancelDomainOrderResponse, CancelPgUpgradeData, CancelPgUpgradeResponse, CancelRunData, CancelRunResponse, CancelScheduleRunData, CancelScheduleRunError, CancelScheduleRunResponse, ChangePasswordSelfData, ChangePasswordSelfResponse, ChangeProjectSourceData, ChangeProjectSourceResponse, ChangeRequiredPasswordData, ChangeRequiredPasswordResponse, ChatCompletionsData, ChatCompletionsError, ChatCompletionsResponse, CheckAnalyticsHasEventsData, CheckAnalyticsHasEventsResponse, CheckCommitExistsData, CheckCommitExistsResponse, CheckDomainStatusData, CheckDomainStatusResponse, CheckExplorerSupportData, CheckExplorerSupportResponse, CheckIpBlockedData, CheckIpBlockedError, CheckProviderDeletionSafetyData, CheckProviderDeletionSafetyResponse, ChunkUploadOptionsData, ChunkUploadOptionsResponse, CleanupExpiredBackupsData, CleanupExpiredBackupsError, CleanupExpiredBackupsResponse, ClearPreviewPasswordData, ClearPreviewPasswordResponse, CliDeviceApproveData, CliDeviceApproveResponse2, CliDeviceDenyData, CliDeviceDenyResponse, CliDeviceLookupData, CliDeviceLookupResponse2, CliDevicePollData, CliDevicePollResponse2, CliDeviceStartData, CliDeviceStartResponse2, CliLogoutData, CliLogoutResponse, CmdData, CmdKillData, CmdKillResponse, CmdLogsData, CmdResponse2, ConfirmPendingActionData, ConfirmPendingActionResponse, ContainerMetricsGetHistoryData, ContainerMetricsGetHistoryResponse, CreateAgentData, CreateAgentResponse, CreateAlertData, CreateAlertError, CreateAlertResponse, CreateAlertRuleData, CreateAlertRuleResponse, CreateApiKeyData, CreateApiKeyResponse2, CreateBackupScheduleData, CreateBackupScheduleError, CreateBackupScheduleResponse, CreateBitbucketProviderData, CreateBitbucketProviderResponse, CreateCloudflareProviderData, CreateCloudflareProviderResponse, CreateConversationData, CreateConversationResponse, CreateCustomDomainData, CreateCustomDomainResponse, CreateDashboardData, CreateDashboardError, CreateDashboardResponse, CreateDeploymentTokenData, CreateDeploymentTokenResponse2, CreateDnsProviderData, CreateDnsProviderResponse, CreateDomainData, CreateDomainResponse, CreateDsnData, CreateDsnResponse, CreateEmailDomainData, CreateEmailDomainResponse, CreateEmailProviderData, CreateEmailProviderResponse, CreateEnvironmentData, CreateEnvironmentResponse, CreateEnvironmentVariableData, CreateEnvironmentVariableResponse, CreateFlagData, CreateFlagResponse, CreateFunnelData, CreateFunnelResponse2, CreateGenericProviderData, CreateGenericProviderResponse, CreateGiteaPatProviderData, CreateGiteaPatProviderResponse, CreateGithubPatProviderData, CreateGithubPatProviderResponse, CreateGitlabOauthProviderData, CreateGitlabOauthProviderResponse, CreateGitlabPatProviderData, CreateGitlabPatProviderResponse, CreateGitProviderData, CreateGitProviderResponse, CreateGlobalMcpData, CreateGlobalMcpResponse, CreateGlobalSkillData, CreateGlobalSkillResponse, CreateIncidentData, CreateIncidentResponse, CreateIpAccessControlData, CreateIpAccessControlError, CreateIpAccessControlResponse, CreateMcpData, CreateMcpResponse, CreateMonitorData, CreateMonitorResponse, CreateNotificationEmailProviderData, CreateNotificationEmailProviderResponse, CreateNotificationProviderData, CreateNotificationProviderResponse, CreateOidcProviderData, CreateOidcProviderResponse, CreateOidcRoleMappingData, CreateOidcRoleMappingResponse, CreateOrRecreateOrderData, CreateOrRecreateOrderResponse, CreatePlanData, CreatePlanResponse2, CreatePrData, CreateProjectData, CreateProjectFromTemplateData, CreateProjectFromTemplateResponse2, CreateProjectReleaseData, CreateProjectReleaseResponse, CreateProjectResponse, CreateProjectSecretData, CreateProjectSecretResponse, CreateProviderKeyData, CreateProviderKeyError, CreateProviderKeyResponse, CreatePrResponse2, CreateReleaseData, CreateReleaseResponse, CreateRouteData, CreateRouteResponse, CreateS3SourceData, CreateS3SourceError, CreateS3SourceResponse, CreateSandboxData, CreateSandboxResponse, CreateServiceData, CreateServiceResponse, CreateSkillData, CreateSkillResponse, CreateSlackProviderData, CreateSlackProviderResponse, CreateTeamData, CreateTeamResponse, CreateUserData, CreateUserResponse, CreateWebhookData, CreateWebhookProviderData, CreateWebhookProviderResponse, CreateWebhookResponse, DeactivateApiKeyData, DeactivateApiKeyResponse, DeactivateConnectionData, DeactivateProviderData, DeleteAgentData, DeleteAgentResponse, DeleteAlertData, DeleteAlertError, DeleteAlertResponse, DeleteAlertRuleData, DeleteAlertRuleResponse, DeleteApiKeyData, DeleteApiKeyResponse, DeleteBackupData, DeleteBackupError, DeleteBackupResponse, DeleteBackupScheduleData, DeleteBackupScheduleError, DeleteBackupScheduleResponse, DeleteConnectionData, DeleteConnectionResponse, DeleteCustomDomainData, DeleteCustomDomainResponse, DeleteDashboardData, DeleteDashboardError, DeleteDashboardResponse, DeleteDeploymentTokenData, DeleteDeploymentTokenResponse, DeleteDnsProviderData, DeleteDnsProviderResponse, DeleteDomainData, DeleteDomainResponse, DeleteEmailDomainData, DeleteEmailDomainResponse, DeleteEmailProviderData, DeleteEmailProviderResponse, DeleteEnvironmentData, DeleteEnvironmentDomainData, DeleteEnvironmentDomainResponse, DeleteEnvironmentResponse, DeleteEnvironmentVariableData, DeleteEnvironmentVariableResponse, DeleteExternalImageData, DeleteExternalImageResponse, DeleteFunnelData, DeleteGitProviderData, DeleteGitProviderResponse, DeleteGlobalMcpData, DeleteGlobalMcpResponse, DeleteGlobalSkillData, DeleteGlobalSkillResponse, DeleteIpAccessControlData, DeleteIpAccessControlError, DeleteIpAccessControlResponse, DeleteMcpData, DeleteMcpResponse, DeleteMonitorData, DeleteMonitorResponse, DeleteNotificationProviderData, DeleteNotificationProviderResponse, DeleteOidcProviderData, DeleteOidcProviderResponse, DeleteOidcRoleMappingData, DeleteOidcRoleMappingResponse, DeletePreferencesData, DeletePreferencesResponse, DeleteProjectData, DeleteProjectResponse, DeleteProjectSecretData, DeleteProjectSecretResponse, DeleteProviderKeyData, DeleteProviderKeyError, DeleteProviderKeyResponse, DeleteProviderSafelyData, DeleteProviderSafelyResponse, DeleteReleaseSourceFilesData, DeleteReleaseSourceFilesResponse, DeleteReleaseSourceMapsData, DeleteReleaseSourceMapsResponse, DeleteRouteData, DeleteRouteResponse, DeleteS3SourceData, DeleteS3SourceError, DeleteS3SourceResponse, DeleteScanData, DeleteScanError, DeleteScanResponse, DeleteSecretData, DeleteSecretResponse, DeleteServiceData, DeleteServiceResponse, DeleteSessionReplayData, DeleteSessionReplayError, DeleteSkillData, DeleteSkillResponse, DeleteSourceMapData, DeleteSourceMapResponse, DeleteStaticBundleData, DeleteStaticBundleResponse, DeleteTeamData, DeleteTeamResponse, DeleteUserData, DeleteUserResponse, DeleteWebhookData, DeleteWebhookResponse, DeployFromImageData, DeployFromImageResponse, DeployFromImageUploadData, DeployFromImageUploadResponse, DeployFromStaticData, DeployFromStaticResponse, DeployFromUploadedSourceData, DeployFromUploadedSourceResponse, DeploymentMetricsGetLatestData, DeploymentMetricsGetLatestResponse, DeploymentMetricsGetRangeData, DeploymentMetricsGetRangeResponse, DeploymentMetricsToggleData, DestroySandboxData, DestroySandboxResponse, DetachScheduleServiceData, DetachScheduleServiceError, DetachScheduleServiceResponse, DetectPublicPresetsData, DetectPublicPresetsResponse, DisableBackupScheduleData, DisableBackupScheduleResponse, DisableMfaData, DisableMfaResponse, DiscoverWorkloadsData, DiscoverWorkloadsResponse, DomainData, DomainResponse2, DownloadGlobalSkillArchiveData, DownloadGlobalSkillArchiveResponse, DownloadObjectData, DownloadObjectResponse, DownloadSkillArchiveData, DownloadSkillArchiveResponse, EmailStatusData, EmailStatusResponse2, EmbeddingsData, EmbeddingsError, EmbeddingsResponse, EnableBackupScheduleData, EnableBackupScheduleResponse, EnrichVisitorData, EnrichVisitorResponse2, ExecData, ExecDetachedData, ExecDetachedResponse2, ExecResponse2, ExecuteDeploymentOperationData, ExecuteDeploymentOperationResponse, ExecuteImportData, ExecuteImportResponse2, ExtendTimeoutData, ExtendTimeoutResponse, ExternalServiceEnablePgStatStatementsData, ExternalServiceEnablePgStatStatementsResponse, ExternalServiceMetricsByDatabaseData, ExternalServiceMetricsByDatabaseResponse, ExternalServiceMetricsCreateAlertRuleData, ExternalServiceMetricsCreateAlertRuleResponse, ExternalServiceMetricsDeleteAlertRuleData, ExternalServiceMetricsDeleteAlertRuleResponse, ExternalServiceMetricsGetAlertRulesData, ExternalServiceMetricsGetAlertRulesResponse, ExternalServiceMetricsGetLatestData, ExternalServiceMetricsGetLatestResponse, ExternalServiceMetricsGetRangeData, ExternalServiceMetricsGetRangeResponse, ExternalServiceMetricsStatusData, ExternalServiceMetricsStatusResponse, ExternalServiceMetricsToggleData, ExternalServiceMetricsUpdateAlertRuleData, ExternalServiceMetricsUpdateAlertRuleResponse, ExternalServiceResetPgStatStatementsData, ExternalServiceResetPgStatStatementsResponse, FinalizeOrderData, FinalizeOrderResponse, FinalizeProjectReleaseData, FinalizeProjectReleaseResponse, FindConversationData, FindConversationResponse, GenerateJoinTokenData, GenerateJoinTokenResponse2, GeneratePresetDockerfileData, GeneratePresetDockerfileResponse, GetAccessInfoData, GetAccessInfoResponse, GetActiveVisitorsData, GetActiveVisitorsResponse, GetActivityGraphData, GetActivityGraphResponse, GetAdminGateData, GetAdminGateResponse, GetAgentData, GetAgentResponse, GetAggregatedBucketsData, GetAggregatedBucketsResponse, GetAiAgentBreakdownData, GetAiAgentBreakdownError, GetAiAgentBreakdownResponse, GetAiAgentPagesData, GetAiAgentPagesError, GetAiAgentPagesResponse, GetAiAgentTimelineData, GetAiAgentTimelineError, GetAiAgentTimelineResponse, GetAiPageBreakdownData, GetAiPageBreakdownError, GetAiPageBreakdownResponse, GetAiStatusBreakdownData, GetAiStatusBreakdownError, GetAiStatusBreakdownResponse, GetAlertData, GetAlertError, GetAlertResponse, GetAlertRuleData, GetAlertRuleResponse, GetAllRepositoriesByNameData, GetAllRepositoriesByNameResponse, GetAnalyticsActiveVisitorsData, GetAnalyticsActiveVisitorsResponse, GetAnalyticsEventsCountData, GetAnalyticsEventsCountResponse, GetAnalyticsSessionEventsData, GetAnalyticsSessionEventsResponse, GetAnalyticsVisitorSessionsData, GetAnalyticsVisitorSessionsResponse, GetApiKeyData, GetApiKeyPermissionsData, GetApiKeyPermissionsResponse, GetApiKeyResponse, GetAuditLogData, GetAuditLogResponse, GetBackupData, GetBackupError, GetBackupResponse, GetBackupScheduleData, GetBackupScheduleResponse, GetBranchesByRepositoryIdData, GetBranchesByRepositoryIdResponse, GetBucketedIncidentsData, GetBucketedIncidentsResponse, GetBucketedStatusData, GetBucketedStatusResponse, GetChallengeTokenData, GetChallengeTokenResponse, GetChatReadinessData, GetChatReadinessResponse, GetCliStatusData, GetClusterHealthData, GetClusterHealthResponse, GetClusterMemberData, GetClusterMemberResponse, GetCmdData, GetCmdResponse, GetContainerDetailData, GetContainerDetailResponse, GetContainerEnvironmentVariableData, GetContainerEnvironmentVariableResponse, GetContainerInfoData, GetContainerInfoResponse, GetContainerLogsByIdData, GetContainerLogsData, GetContainerMetricsData, GetContainerMetricsResponse, GetConversationData, GetConversationDetailData, GetConversationDetailError, GetConversationDetailResponse, GetConversationResponse, GetConversationsData, GetConversationsError, GetConversationsResponse, GetCronByIdData, GetCronByIdResponse, GetCronExecutionsData, GetCronExecutionsResponse, GetCrossProjectTraceSiblingsData, GetCrossProjectTraceSiblingsError, GetCrossProjectTraceSiblingsResponse, GetCurrentMonitorStatusData, GetCurrentMonitorStatusResponse, GetCurrentUserData, GetCurrentUserResponse, GetCustomDomainData, GetCustomDomainResponse, GetDashboardData, GetDashboardError, GetDashboardProjectsAnalyticsData, GetDashboardProjectsAnalyticsResponse, GetDashboardResponse, GetDeliveryData, GetDeliveryResponse, GetDeploymentContainerLogContentData, GetDeploymentContainerLogContentResponse, GetDeploymentData, GetDeploymentJobLogsData, GetDeploymentJobLogsResponse, GetDeploymentJobsData, GetDeploymentJobsResponse, GetDeploymentOperationsData, GetDeploymentOperationsResponse, GetDeploymentOperationStatusData, GetDeploymentOperationStatusResponse, GetDeploymentResponse, GetDeploymentTokenData, GetDeploymentTokenResponse, GetDiskStatusData, GetDiskStatusResponse, GetDnsChangesData, GetDnsChangesResponse, GetDnsProviderData, GetDnsProviderResponse, GetDomainByHostData, GetDomainByHostResponse, GetDomainByIdData, GetDomainByIdResponse, GetDomainByNameData, GetDomainByNameResponse, GetDomainData, GetDomainDnsRecordsData, GetDomainDnsRecordsResponse, GetDomainOrderData, GetDomainOrderResponse, GetDomainResponse, GetEmailData, GetEmailEventsData, GetEmailEventsResponse, GetEmailLinksData, GetEmailLinksResponse, GetEmailProviderData, GetEmailProviderResponse, GetEmailResponse, GetEmailStatsData, GetEmailStatsResponse, GetEmailTrackingData, GetEmailTrackingResponse, GetEmailTrackingStatusData, GetEmailTrackingStatusResponse, GetEntityInfoData, GetEntityInfoResponse, GetEnvironmentCronsData, GetEnvironmentCronsResponse, GetEnvironmentData, GetEnvironmentDomainsData, GetEnvironmentDomainsResponse, GetEnvironmentResponse, GetEnvironmentsData, GetEnvironmentsResponse, GetEnvironmentVariablesData, GetEnvironmentVariablesResponse, GetEnvironmentVariableValueData, GetEnvironmentVariableValueResponse, GetErrorDashboardStatsData, GetErrorDashboardStatsResponse, GetErrorEventData, GetErrorEventResponse, GetErrorGroupData, GetErrorGroupResponse, GetErrorStatsData, GetErrorStatsResponse, GetErrorTimeSeriesData, GetErrorTimeSeriesResponse, GetEventDetailData, GetEventDetailResponse, GetEventEntriesData, GetEventEntriesResponse, GetEventsCountData, GetEventsCountResponse, GetEventsTimelineData, GetEventsTimelineResponse, GetEventTypeBreakdownData, GetEventTypeBreakdownResponse, GetEventVisitorsData, GetEventVisitorsResponse, GetExternalImageData, GetExternalImageResponse, GetFileData, GetFileResponse, GetFlagData, GetFlagResponse, GetFlagSnapshotData, GetFlagSnapshotResponse, GetFunnelMetricsData, GetFunnelMetricsResponse, GetGenaiTraceData, GetGenaiTraceError, GetGenaiTraceResponse, GetGeneralStatsData, GetGeneralStatsResponse, GetGitProviderData, GetGitProviderResponse, GetGlobalEventsData, GetGlobalEventsResponse, GetGlobalEventStatsData, GetGlobalEventStatsResponse, GetGlobalMcpData, GetGlobalMcpResponse, GetGlobalSandboxStatusData, GetGlobalSandboxStatusResponse, GetGlobalSkillData, GetGlobalSkillResponse, GetGroupedPageMetricsData, GetGroupedPageMetricsError, GetGroupedPageMetricsResponse, GetHealthData, GetHealthError, GetHealthResponse, GetHourlyVisitsData, GetHourlyVisitsResponse, GetHttpChallengeDebugData, GetHttpChallengeDebugResponse, GetImportStatusData, GetImportStatusResponse, GetIncidentData, GetIncidentResponse, GetIncidentUpdatesData, GetIncidentUpdatesResponse, GetIpAccessControlData, GetIpAccessControlError, GetIpAccessControlResponse, GetIpGeolocationData, GetIpGeolocationError, GetIpGeolocationResponse, GetJoinTokenStatusData, GetJoinTokenStatusResponse, GetLastDeploymentData, GetLastDeploymentResponse, GetLatestScanData, GetLatestScanError, GetLatestScanResponse, GetLatestScansPerEnvironmentData, GetLatestScansPerEnvironmentError, GetLatestScansPerEnvironmentResponse, GetLiveVisitorsListData, GetLiveVisitorsListResponse, GetLogContextData, GetLogContextError, GetLogContextResponse, GetMcpData, GetMcpResponse, GetMetricsOverTimeData, GetMetricsOverTimeError, GetMetricsOverTimeResponse, GetMonitorData, GetMonitorResponse, GetNotificationProviderData, GetNotificationProviderResponse, GetOnDemandCertStatusData, GetOnDemandCertStatusResponse, GetOrCreateDsnData, GetOrCreateDsnResponse, GetPageFlowData, GetPageFlowResponse, GetPageHourlySessionsData, GetPageHourlySessionsResponse, GetPagePathDetailData, GetPagePathDetailResponse, GetPagePathsData, GetPagePathsResponse, GetPagePathsSparklinesData, GetPagePathsSparklinesResponse, GetPagePathVisitorsData, GetPagePathVisitorsResponse, GetPendingActionData, GetPendingActionResponse, GetPerformanceMetricsData, GetPerformanceMetricsError, GetPerformanceMetricsResponse, GetPgUpgradeData, GetPgUpgradeLogsData, GetPgUpgradeLogsResponse, GetPgUpgradeResponse, GetPipelineStatsData, GetPipelineStatsError, GetPipelineStatsResponse, GetPlatformInfoData, GetPlatformInfoResponse, GetPostgresWalHealthData, GetPostgresWalHealthResponse, GetPreferencesData, GetPreferencesResponse, GetPreviewGatewayLogsData, GetPreviewGatewayLogsResponse, GetPreviewGatewaySettingsData, GetPreviewGatewaySettingsResponse, GetPreviewGatewayStatusData, GetPreviewGatewayStatusResponse, GetPricingData, GetPricingError, GetPricingResponse, GetPrivateIpData, GetProjectAlarmsSummaryData, GetProjectAlarmsSummaryResponse, GetProjectBySlugData, GetProjectBySlugResponse, GetProjectData, GetProjectDeploymentsData, GetProjectDeploymentsResponse, GetProjectResponse, GetProjectsData, GetProjectServiceEnvironmentVariablesData, GetProjectServiceEnvironmentVariablesResponse, GetProjectSessionReplaysData, GetProjectSessionReplaysError, GetProjectSessionReplaysResponse2, GetProjectsHealthData, GetProjectsHealthError, GetProjectsHealthResponse, GetProjectsMonitorHealthData, GetProjectsMonitorHealthResponse, GetProjectsResponse, GetProjectStatisticsData, GetProjectStatisticsResponse, GetProjectTemplateData, GetProjectTemplateResponse, GetPropertyBreakdownData, GetPropertyBreakdownResponse, GetPropertyTimelineData, GetPropertyTimelineResponse, GetProviderConnectionsData, GetProviderConnectionsResponse, GetProviderMetadataData, GetProviderMetadataResponse, GetProvidersMetadataData, GetProvidersMetadataResponse, GetProxyLogByIdData, GetProxyLogByIdError, GetProxyLogByIdResponse, GetProxyLogByRequestIdData, GetProxyLogByRequestIdError, GetProxyLogByRequestIdResponse, GetProxyLogsData, GetProxyLogsError, GetProxyLogsResponse, GetPublicBranchesData, GetPublicBranchesResponse, GetPublicIpData, GetPublicRepositoryData, GetPublicRepositoryResponse, GetQuotaData, GetQuotaError, GetQuotaResponse, GetRecentActivityData, GetRecentActivityResponse, GetRemoteExternalImageData, GetRemoteExternalImageResponse, GetRepositoryBranchesData, GetRepositoryBranchesResponse, GetRepositoryByIdData, GetRepositoryByIdResponse, GetRepositoryByNameData, GetRepositoryByNameResponse, GetRepositoryPresetByNameData, GetRepositoryPresetByNameResponse, GetRepositoryPresetLiveData, GetRepositoryPresetLiveResponse, GetRepositoryTagsData, GetRepositoryTagsResponse, GetResolvedEnvironmentVariablesData, GetResolvedEnvironmentVariablesResponse, GetResolvedEnvironmentVariableValueData, GetResolvedEnvironmentVariableValueResponse, GetRestoreCapabilitiesData, GetRestoreCapabilitiesError, GetRestoreCapabilitiesResponse, GetRestoreRunData, GetRestoreRunError, GetRestoreRunResponse, GetRouteData, GetRouteResponse, GetRunData, GetRunResponse, GetRunWithLogsData, GetRunWithLogsResponse, GetS3CredentialsData, GetS3CredentialsResponse, GetS3SourceData, GetS3SourceError, GetS3SourceResponse, GetSandboxData, GetSandboxResponse, GetSandboxStatusData, GetSandboxStatusResponse, GetScanByDeploymentData, GetScanByDeploymentError, GetScanByDeploymentResponse, GetScanData, GetScanError, GetScanResponse, GetScanVulnerabilitiesData, GetScanVulnerabilitiesError, GetScanVulnerabilitiesResponse, GetServiceBySlugData, GetServiceBySlugResponse, GetServiceData, GetServiceEnvironmentVariableData, GetServiceEnvironmentVariableResponse, GetServiceEnvironmentVariablesData, GetServiceEnvironmentVariablesResponse, GetServiceHealthStatusData, GetServiceHealthStatusResponse, GetServicePreviewEnvironmentVariableNamesData, GetServicePreviewEnvironmentVariableNamesResponse, GetServicePreviewEnvironmentVariablesMaskedData, GetServicePreviewEnvironmentVariablesMaskedResponse, GetServiceResponse, GetServiceRuntimeData, GetServiceRuntimeResponse, GetServiceStatsData, GetServiceStatsResponse, GetServiceTypeParametersData, GetServiceTypesData, GetServiceTypesResponse, GetSessionDetailsData, GetSessionDetailsResponse, GetSessionEventsData, GetSessionEventsResponse, GetSessionLogsData, GetSessionLogsResponse, GetSessionReplayData, GetSessionReplayError, GetSessionReplayEventsData, GetSessionReplayEventsError, GetSessionReplayEventsResponse, GetSessionReplayResponse2, GetSettingsData, GetSettingsResponse, GetSkillData, GetSkillResponse, GetSlowQueriesData, GetSlowQueriesResponse, GetStaticBundleData, GetStaticBundleResponse, GetStatusOverviewData, GetStatusOverviewResponse, GetTagsByRepositoryIdData, GetTagsByRepositoryIdResponse, GetTeamData, GetTeamResponse, GetTimeBucketStatsData, GetTimeBucketStatsError, GetTimeBucketStatsResponse, GetTodayStatsData, GetTodayStatsError, GetTodayStatsResponse, GetTraceData, GetTraceError, GetTraceResponse, GetUnifiedTraceData, GetUnifiedTraceError, GetUnifiedTraceResponse, GetUniqueCountsData, GetUniqueCountsResponse, GetUniqueEventsData, GetUniqueEventsResponse, GetUpdateStatusData, GetUpdateStatusResponse, GetUptimeHistoryData, GetUptimeHistoryResponse, GetUsageByProviderData, GetUsageByProviderError, GetUsageByProviderResponse, GetUsageRecentData, GetUsageRecentError, GetUsageRecentResponse, GetUsageSummaryData, GetUsageSummaryError, GetUsageSummaryResponse, GetUsageTimeseriesData, GetUsageTimeseriesError, GetUsageTimeseriesResponse, GetUsageTopModelsData, GetUsageTopModelsError, GetUsageTopModelsResponse, GetVisitorByGuidData, GetVisitorByGuidResponse, GetVisitorByIdData, GetVisitorByIdResponse, GetVisitorDetailsData, GetVisitorDetailsResponse, GetVisitorFacetsData, GetVisitorFacetsResponse, GetVisitorInfoData, GetVisitorInfoResponse, GetVisitorJourneyData, GetVisitorJourneyResponse, GetVisitorsData, GetVisitorSessionsData, GetVisitorSessionsError, GetVisitorSessionsResponse2, GetVisitorsResponse, GetVisitorStatsData, GetVisitorStatsResponse, GetWebhookData, GetWebhookResponse, GrantProjectAccessData, GrantProjectAccessResponse, HandleGitProviderOauthCallbackData, HasAnalyticsEventsData, HasAnalyticsEventsResponse2, HasErrorGroupsData, HasErrorGroupsResponse2, HasPerformanceMetricsData, HasPerformanceMetricsError, HasPerformanceMetricsResponse, ImportExternalServiceData, ImportExternalServiceResponse, IngestLogsByPathData, IngestLogsByPathError, IngestLogsData, IngestLogsError, IngestMetricsByPathData, IngestMetricsByPathError, IngestMetricsData, IngestMetricsError, IngestSentryEnvelopeData, IngestSentryEventData, IngestSentryEventResponse, IngestTracesByPathData, IngestTracesByPathError, IngestTracesData, IngestTracesError, InitSessionReplayData, InitSessionReplayError, InitSessionReplayResponse, InspectDropArchiveData, InspectDropArchiveResponse, JobLogsData, JobStatusData, JobStatusResponse2, KillJobData, KillJobResponse, KvDelData, KvDelResponse, KvDisableData, KvDisableResponse, KvEnableData, KvEnableResponse, KvExpireData, KvExpireResponse, KvGetData, KvGetResponse, KvIncrData, KvIncrResponse, KvKeysData, KvKeysResponse, KvSetData, KvSetResponse, KvStatusData, KvStatusResponse2, KvTtlData, KvTtlResponse, KvUpdateData, KvUpdateResponse, LatestRunForSourceData, LatestRunForSourceResponse, LinkCustomDomainToCertificateData, LinkCustomDomainToCertificateResponse, LinkServiceToProjectData, LinkServiceToProjectResponse, ListAgentRunsData, ListAgentRunsResponse, ListAgentsData, ListAgentsResponse2, ListAiProvidersData, ListAiProvidersResponse, ListAlertRulesData, ListAlertRulesResponse, ListAlertsData, ListAlertsError, ListAlertsResponse, ListAllConversationsData, ListAllConversationsResponse, ListAllRunsData, ListAllRunsResponse, ListApiKeysData, ListApiKeysResponse, ListAuditLogsData, ListAuditLogsResponse, ListAvailableContainersData, ListAvailableContainersResponse, ListBackupAlertsData, ListBackupAlertsError, ListBackupAlertsResponse, ListBackupChildrenData, ListBackupChildrenError, ListBackupChildrenResponse, ListBackupSchedulesData, ListBackupSchedulesError, ListBackupSchedulesResponse, ListBackupsForScheduleData, ListBackupsForScheduleResponse, ListCommitsByRepositoryIdData, ListCommitsByRepositoryIdResponse, ListConnectionsData, ListConnectionsResponse, ListContainersAtPathData, ListContainersAtPathResponse, ListContainersData, ListContainersResponse, ListConversationsData, ListConversationsResponse, ListCustomDomainsForProjectData, ListCustomDomainsForProjectResponse, ListDashboardsData, ListDashboardsError, ListDashboardsResponse, ListDeliveriesData, ListDeliveriesResponse, ListDeploymentContainerLogsData, ListDeploymentContainerLogsResponse, ListDeploymentTokensData, ListDeploymentTokensResponse, ListDnsProvidersData, ListDnsProvidersResponse, ListDomainsData, ListDomainsResponse2, ListDsnsData, ListDsnsResponse, ListEmailDomainsData, ListEmailDomainsResponse, ListEmailProvidersData, ListEmailProvidersResponse, ListEmailsData, ListEmailsResponse, ListEnrollmentTokensData, ListEnrollmentTokensResponse, ListEntitiesData, ListEntitiesResponse, ListErrorEventsData, ListErrorEventsResponse, ListErrorGroupsData, ListErrorGroupsResponse, ListEventsData, ListEventsResponse, ListEventTypesData, ListEventTypesResponse, ListExternalImagesData, ListExternalImagesResponse, ListExternalPluginsData, ListExternalPluginsResponse, ListExternalServiceBackupsData, ListExternalServiceBackupsError, ListExternalServiceBackupsResponse, ListFlagsData, ListFlagsResponse, ListFunnelsData, ListFunnelsResponse, ListGitProvidersData, ListGitProvidersResponse, ListGlobalMcpsData, ListGlobalMcpsResponse, ListGlobalSkillsData, ListGlobalSkillsResponse, ListIncidentsData, ListInsightsData, ListInsightsError, ListInsightsResponse, ListIpAccessControlData, ListIpAccessControlError, ListIpAccessControlResponse, ListJobsData, ListJobsResponse2, ListKnownAiAgentsData, ListKnownAiAgentsError, ListKnownAiAgentsResponse, ListManagedDomainsData, ListManagedDomainsResponse, ListMcpsData, ListMcpsResponse2, ListMetricLabelKeysData, ListMetricLabelKeysError, ListMetricLabelKeysResponse, ListMetricLabelValuesData, ListMetricLabelValuesError, ListMetricLabelValuesResponse, ListMetricNamesData, ListMetricNamesError, ListMetricNamesResponse, ListModelsData, ListModelsError, ListModelsResponse, ListMonitorsData, ListMonitorsResponse, ListNotificationProvidersData, ListNotificationProvidersResponse, ListOidcProvidersData, ListOidcProvidersResponse, ListOidcProviderUsersData, ListOidcProviderUsersResponse, ListOidcRoleMappingsData, ListOidcRoleMappingsResponse, ListOnDemandCertsData, ListOnDemandCertsResponse2, ListOrdersData, ListOrdersResponse2, ListPeersData, ListPeersResponse, ListPendingActionsData, ListPendingActionsResponse, ListPgUpgradesData, ListPgUpgradesResponse, ListPresetsData, ListPresetsResponse2, ListProjectAccessData, ListProjectAccessResponse, ListProjectAlarmsData, ListProjectAlarmsResponse, ListProjectScansData, ListProjectScansError, ListProjectScansResponse, ListProjectSecretsData, ListProjectSecretsResponse, ListProjectServicesData, ListProjectServicesResponse, ListProjectTemplatesData, ListProjectTemplatesResponse, ListProjectTemplateTagsData, ListProjectTemplateTagsResponse, ListProviderKeysData, ListProviderKeysError, ListProviderKeysResponse, ListProviderZonesData, ListProviderZonesResponse, ListPublicProvidersData, ListPublicProvidersResponse, ListReleaseFilesData, ListReleaseFilesResponse, ListReleasesData, ListReleasesResponse, ListRemoteExternalImagesData, ListRemoteExternalImagesResponse, ListRepositoriesByConnectionData, ListRepositoriesByConnectionResponse, ListRepositoriesByProviderData, ListRepositoriesByProviderResponse, ListRestoreRunsForServiceData, ListRestoreRunsForServiceResponse, ListRootContainersData, ListRootContainersResponse, ListRoutesData, ListRoutesResponse, ListS3SourcesData, ListS3SourcesError, ListS3SourcesResponse, ListSandboxesData, ListSandboxesResponse2, ListScheduleRunJobsData, ListScheduleRunJobsError, ListScheduleRunJobsResponse, ListScheduleRunsData, ListScheduleRunsError, ListScheduleRunsResponse, ListScheduleServicesData, ListScheduleServicesError, ListScheduleServicesResponse, ListSecretsData, ListSecretsResponse2, ListServiceHealthStatusesData, ListServiceHealthStatusesResponse, ListServiceProjectsData, ListServiceProjectsResponse, ListServiceSchedulesData, ListServiceSchedulesError, ListServiceSchedulesResponse, ListServicesData, ListServicesResponse, ListSkillsData, ListSkillsResponse2, ListSourceBackupsData, ListSourceBackupsError, ListSourceBackupsResponse, ListSourceFilesData, ListSourceFilesResponse, ListSourceMapsData, ListSourceMapsResponse, ListSourcesData, ListSourcesResponse, ListStaticBundlesData, ListStaticBundlesResponse, ListSyncedRepositoriesData, ListSyncedRepositoriesResponse, ListTeamMembersData, ListTeamMembersResponse, ListTeamProjectsData, ListTeamProjectsResponse, ListTeamsData, ListTeamsResponse, ListUsersData, ListUsersResponse, ListWebhooksData, ListWebhooksResponse, LoginData, LoginResponse, LogoutData, LookupDnsARecordsData, LookupDnsARecordsError, LookupDnsARecordsResponse, MintEnrollmentTokenData, MintEnrollmentTokenResponse2, MkdirData, MkdirResponse, NodeHeartbeatData, NodeHeartbeatResponse, NodeMetricsGetRangeData, NodeMetricsGetRangeResponse, ObservabilityFullEventData, ObservabilityFullEventError, ObservabilityFullEventResponse, ObservabilityListEventsData, ObservabilityListEventsError, ObservabilityListEventsResponse, OidcCallbackData, PatchAdminGateData, PatchAdminGateResponse, PatchPreviewGatewaySettingsData, PatchPreviewGatewaySettingsResponse, PauseDeploymentData, PauseDeploymentResponse, PauseSandboxData, PauseSandboxResponse, PlanRestoreData, PlanRestoreError, PlanRestoreResponse, PostDnsAckData, PostDnsAckResponse, PreviewAlertData, PreviewAlertError, PreviewAlertResponse, PreviewFunnelMetricsData, PreviewFunnelMetricsResponse, PreviewHostnameModeData, PreviewHostnameModeResponse, PromoteClusterMemberData, PromoteDeploymentData, PromoteDeploymentResponse, ProvisionDomainData, ProvisionDomainResponse, PurgeProjectLogsData, PurgeProjectLogsError, PushExternalImageData, PushExternalImageResponse, QueryDataData, QueryDataResponse2, QueryGenaiTracesData, QueryGenaiTracesError, QueryGenaiTracesResponse, QueryLogsData, QueryLogsError, QueryLogsResponse, QueryMetricsData, QueryMetricsError, QueryMetricsResponse, QueryTracesData, QueryTracesError, QueryTracesResponse, QueryTraceSummariesData, QueryTraceSummariesError, QueryTraceSummariesResponse, ReadFileData, ReadFileResponse2, ReAnalyzeData, RecordConsoleEventData, RecordEventMetricsData, RecordEventMetricsResponse, RecordFlagExposureData, RecordFlagExposureResponse, RecordSpeedMetricsData, RecordSpeedMetricsError, RecordSpeedMetricsResponse, RefreshRouteTableData, RefreshRouteTableResponse, RegenerateDsnData, RegenerateDsnResponse, RegisterExternalImageData, RegisterExternalImageResponse, RegisterNodeData, RegisterNodeResponse2, ReinstallGitlabWebhookData, ReinstallGitlabWebhookResponse, RejectPendingActionData, RejectPendingActionResponse, ReloadPluginsData, ReloadPluginsResponse, RemoveClusterMemberData, RemoveClusterMemberResponse, RemoveManagedDomainData, RemoveManagedDomainResponse, RemoveRoleData, RemoveRoleResponse, RemoveTeamMemberData, RemoveTeamMemberResponse, RenameConversationData, RenameConversationResponse, RenewDomainData, RenewDomainResponse, RequestPasswordResetData, RequestPasswordResetResponse, ResetPasswordData, ResetPasswordResponse, ResizeSandboxData, ResizeSandboxResponse, ResolveAlarmData, RestartContainerData, RestartContainerResponse, RestartPreviewGatewayData, RestartPreviewGatewayResponse, RestartSandboxData, RestartSandboxResponse, RestoreFlagData, RestoreFlagResponse, RestoreUserData, RestoreUserResponse, ResumeDeploymentData, ResumeDeploymentResponse, ResumeSandboxData, ResumeSandboxResponse, RetryClusterData, RetryClusterResponse, RetryDeliveryData, RetryDeliveryResponse, RetryPgUpgradeData, RetryPgUpgradeResponse, RetryRunData, RetryRunResponse, RevealGlobalMcpConfigData, RevealGlobalMcpConfigResponse, RevealMcpConfigData, RevealMcpConfigResponse, RevealNotificationProviderConfigData, RevealNotificationProviderConfigResponse, RevealServiceParameterData, RevealServiceParameterResponse, RevenueCreateIntegrationData, RevenueCreateIntegrationResponse, RevenueDeleteIntegrationData, RevenueDeleteIntegrationResponse, RevenueGlobalEventsData, RevenueGlobalEventsResponse, RevenueImportInvoicesCsvData, RevenueImportInvoicesCsvResponse, RevenueImportSubscriptionsCsvData, RevenueImportSubscriptionsCsvResponse, RevenueListIntegrationsData, RevenueListIntegrationsResponse, RevenueListProvidersData, RevenueListProvidersResponse, RevenueMetricsCustomersData, RevenueMetricsCustomersResponse, RevenueMetricsGlobalMrrData, RevenueMetricsGlobalMrrResponse, RevenueMetricsGlobalSummaryData, RevenueMetricsGlobalSummaryResponse, RevenueMetricsMrrData, RevenueMetricsMrrResponse, RevenueMetricsSummaryData, RevenueMetricsSummaryResponse, RevenueRecentEventsData, RevenueRecentEventsResponse, RevenueRotateTokenData, RevenueRotateTokenResponse, RevenueUpdateConfigData, RevenueUpdateConfigResponse, RevenueUpdateSecretData, RevenueUpdateSecretResponse, RevokeDsnData, RevokeDsnResponse, RevokeEnrollmentTokenData, RevokeEnrollmentTokenResponse, RevokeJoinTokenData, RevokeJoinTokenResponse, RevokeProjectAccessData, RevokeProjectAccessResponse, RollbackPgUpgradeData, RollbackPgUpgradeResponse, RollbackToDeploymentData, RollbackToDeploymentResponse, RootfsGcData, RootfsReportData, RotateApiKeyData, RotateApiKeyResponse, RotateDeploymentTokenData, RotateDeploymentTokenResponse, RunBackupForSourceData, RunBackupForSourceError, RunBackupForSourceResponse, RunConnectionHealthCheckData, RunConnectionHealthCheckResponse, RunExternalServiceBackupData, RunExternalServiceBackupError, RunExternalServiceBackupResponse, RunScheduleNowData, RunScheduleNowError, RunScheduleNowResponse, SandboxCreatePreviewLinkData, SandboxCreatePreviewLinkResponse, SaveAgentTokenData, SaveAgentTokenResponse2, SaveAiProviderCredentialData, SaveAiProviderCredentialResponse, SearchLogsData, SearchLogsError, SearchLogsResponse2, SendEmailData, SendEmailResponse, SetDefaultS3SourceData, SetDefaultS3SourceError, SetDefaultS3SourceResponse, SetFlagEnvironmentData, SetFlagEnvironmentResponse, SetPreviewPasswordData, SetPreviewPasswordResponse2, SetupDnsChallengeData, SetupDnsChallengeResponse2, SetupDnsData, SetupDnsResponse2, SetupEmailTrackingData, SetupEmailTrackingResponse, SetupMfaData, SetupMfaResponse, SleepEnvironmentData, SleepEnvironmentResponse, SmokeTestAgentData, SmokeTestAgentResponse, SourceSandboxData, SourceSandboxResponse, StartAnalysisData, StartAnalysisResponse, StartContainerData, StartContainerResponse, StartFixData, StartGitProviderOauthData, StartOidcLoginBySlugData, StartPgUpgradeData, StartPgUpgradeResponse, StartRestoreData, StartRestoreError, StartRestoreResponse, StartServiceData, StartServiceResponse, StatPathData, StatPathResponse, StopContainerData, StopContainerResponse, StopSandboxData, StopSandboxResponse, StopServiceData, StopServiceResponse, StreamContainerMetricsData, SyncRepositoriesData, SyncRepositoriesResponse, TailDeploymentJobLogsData, TailLogsData, TailLogsError, TeardownDeploymentData, TeardownDeploymentResponse, TeardownEnvironmentData, TeardownEnvironmentResponse, TestNotificationProviderData, TestNotificationProviderResponse, TestOidcProviderData, TestOidcProviderResponse, TestProviderConnectionData, TestProviderConnectionResponse, TestProviderData, TestProviderKeyByIdData, TestProviderKeyByIdError, TestProviderKeyByIdResponse, TestProviderKeyInlineData, TestProviderKeyInlineError, TestProviderKeyInlineResponse, TestProviderResponse2, TestS3ConnectionPreviewData, TestS3ConnectionPreviewError, TestS3ConnectionPreviewResponse, TestS3SourceConnectionData, TestS3SourceConnectionError, TestS3SourceConnectionResponse, TrackClickData, TrackOpenData, TriggerAgentData, TriggerAgentResponse, TriggerProjectPipelineData, TriggerProjectPipelineResponse, TriggerScanData, TriggerScanError, TriggerScanResponse2, TriggerServiceHealthCheckData, TriggerServiceHealthCheckResponse, TriggerWeeklyDigestData, TriggerWeeklyDigestResponse, UnlinkServiceFromProjectData, UnlinkServiceFromProjectResponse, UpdateAgentData, UpdateAgentResponse, UpdateAiProviderData, UpdateAiProviderResponse2, UpdateAlertData, UpdateAlertError, UpdateAlertResponse, UpdateAlertRuleData, UpdateAlertRuleResponse, UpdateApiKeyData, UpdateApiKeyResponse, UpdateAutomaticDeployData, UpdateAutomaticDeployResponse, UpdateBackupScheduleData, UpdateBackupScheduleError, UpdateBackupScheduleResponse, UpdateCloudflareProviderData, UpdateCloudflareProviderResponse, UpdateConnectionTokenData, UpdateConnectionTokenResponse, UpdateCustomDomainData, UpdateCustomDomainResponse, UpdateDashboardData, UpdateDashboardError, UpdateDashboardResponse, UpdateDeploymentTokenData, UpdateDeploymentTokenResponse, UpdateEmailProviderData, UpdateEmailProviderResponse, UpdateEnvironmentSettingsData, UpdateEnvironmentSettingsResponse, UpdateEnvironmentSubdomainData, UpdateEnvironmentSubdomainResponse, UpdateEnvironmentVariableData, UpdateEnvironmentVariableResponse, UpdateErrorGroupData, UpdateFlagData, UpdateFlagResponse, UpdateFunnelData, UpdateGitProviderCredentialsData, UpdateGitProviderCredentialsResponse, UpdateGitSettingsData, UpdateGitSettingsResponse, UpdateGlobalMcpData, UpdateGlobalMcpResponse, UpdateGlobalSkillData, UpdateGlobalSkillResponse, UpdateIncidentStatusData, UpdateIncidentStatusResponse, UpdateIpAccessControlData, UpdateIpAccessControlError, UpdateIpAccessControlResponse, UpdateManagedDomainData, UpdateManagedDomainResponse, UpdateMcpData, UpdateMcpResponse, UpdateNotificationEmailProviderData, UpdateNotificationEmailProviderResponse, UpdateNotificationProviderData, UpdateNotificationProviderResponse, UpdateOidcProviderData, UpdateOidcProviderResponse, UpdatePreferencesData, UpdatePreferencesResponse, UpdateProjectData, UpdateProjectDeploymentConfigData, UpdateProjectDeploymentConfigResponse, UpdateProjectResponse, UpdateProjectSecretData, UpdateProjectSecretResponse, UpdateProjectSettingsData, UpdateProjectSettingsResponse, UpdateProviderData, UpdateProviderKeyData, UpdateProviderKeyError, UpdateProviderKeyResponse, UpdateProviderResponse, UpdateRouteData, UpdateRouteResponse, UpdateS3SourceData, UpdateS3SourceError, UpdateS3SourceResponse, UpdateSelfData, UpdateSelfResponse, UpdateServiceData, UpdateServiceResourcesData, UpdateServiceResourcesResponse, UpdateServiceResponse, UpdateSessionDurationData, UpdateSessionDurationError, UpdateSessionDurationResponse2, UpdateSettingsData, UpdateSettingsResponse, UpdateSkillData, UpdateSkillResponse, UpdateSlackProviderData, UpdateSlackProviderResponse, UpdateSpeedMetricsData, UpdateSpeedMetricsError, UpdateSpeedMetricsResponse, UpdateTeamData, UpdateTeamMemberRoleData, UpdateTeamMemberRoleResponse, UpdateTeamResponse, UpdateUserData, UpdateUserResponse, UpdateWebhookData, UpdateWebhookProviderData, UpdateWebhookProviderResponse, UpdateWebhookResponse, UpgradePreviewGatewayData, UpgradePreviewGatewayResponse, UpgradeServiceData, UpgradeServiceResponse, UploadGlobalSkillData, UploadGlobalSkillResponse, UploadReleaseFileData, UploadReleaseFileResponse, UploadSkillData, UploadSkillResponse, UploadSourceFileData, UploadSourceFileResponse, UploadSourceMapData, UploadSourceMapResponse, UploadStaticBundleData, UploadStaticBundleResponse, UpsertSecretData, UpsertSecretResponse, ValidateConnectionData, ValidateConnectionResponse, ValidateEmailData, ValidateEmailResponse2, VerifyAndEnableMfaData, VerifyAndEnableMfaResponse, VerifyDomainData, VerifyDomainResponse, VerifyEmailData, VerifyEmailResponse, VerifyManagedDomainData, VerifyManagedDomainResponse, VerifyMfaChallengeData, VerifyMfaChallengeResponse, VerifyStepUpData, VerifyStepUpResponse, WakeEnvironmentData, WakeEnvironmentResponse, WebhookTriggerData, WebhookTriggerResponse2, WorkflowDryRunData, WorkflowDryRunResponse, WriteFileData, WriteFileResponse, WriteFilesData, WriteFilesResponse2 } from '../types.gen'; +import { acknowledgeAlarm, activateAiProvider, activateApiKey, activateConnection, activateProvider, addClusterMember, addContext, addEnvironmentDomain, addEvents, addManagedDomain, addSessionReplayEvents, addTeamMember, adminDrainNode, adminDrainStatus, adminGetNode, adminListNodeContainers, adminListNodes, adminRemoveNode, adminUndrainNode, applyHostnameMode, archiveConversation, archiveFlag, assignRole, attachScheduleServices, blobCopy, blobDelete, blobDisable, blobDownload, blobEnable, blobList, blobPut, blobStatus, blobUpdate, cancel, cancelBackup, cancelDeployment, cancelDomainOrder, cancelPgUpgrade, cancelRun, cancelScheduleRun, changePasswordSelf, changeProjectSource, changeRequiredPassword, chatCompletions, checkAnalyticsHasEvents, checkCommitExists, checkDomainStatus, checkExplorerSupport, checkIpBlocked, checkProviderDeletionSafety, chunkUploadOptions, cleanupExpiredBackups, clearPreviewPassword, cliDeviceApprove, cliDeviceDeny, cliDeviceLookup, cliDevicePoll, cliDeviceStart, cliLogout, cmd, cmdKill, cmdLogs, confirmPendingAction, containerMetricsGetHistory, createAgent, createAlert, createAlertRule, createApiKey, createBackupSchedule, createBitbucketProvider, createCloudflareProvider, createConversation, createCustomDomain, createDashboard, createDeploymentToken, createDnsProvider, createDomain, createDsn, createEmailDomain, createEmailProvider, createEnvironment, createEnvironmentVariable, createFlag, createFunnel, createGenericProvider, createGiteaPatProvider, createGithubPatProvider, createGitlabOauthProvider, createGitlabPatProvider, createGitProvider, createGlobalMcp, createGlobalSkill, createIncident, createIpAccessControl, createMcp, createMonitor, createNotificationEmailProvider, createNotificationProvider, createOidcProvider, createOidcRoleMapping, createOrRecreateOrder, createPlan, createPr, createProject, createProjectFromTemplate, createProjectRelease, createProjectSecret, createProviderKey, createRelease, createRoute, createS3Source, createSandbox, createService, createSkill, createSlackProvider, createTeam, createUser, createWebhook, createWebhookProvider, deactivateApiKey, deactivateConnection, deactivateProvider, deleteAgent, deleteAlert, deleteAlertRule, deleteApiKey, deleteBackup, deleteBackupSchedule, deleteConnection, deleteCustomDomain, deleteDashboard, deleteDeploymentToken, deleteDnsProvider, deleteDomain, deleteEmailDomain, deleteEmailProvider, deleteEnvironment, deleteEnvironmentDomain, deleteEnvironmentVariable, deleteExternalImage, deleteFunnel, deleteGitProvider, deleteGlobalMcp, deleteGlobalSkill, deleteIpAccessControl, deleteMcp, deleteMonitor, deleteNotificationProvider, deleteOidcProvider, deleteOidcRoleMapping, deletePreferences, deleteProject, deleteProjectSecret, deleteProviderKey, deleteProviderSafely, deleteReleaseSourceFiles, deleteReleaseSourceMaps, deleteRoute, deleteS3Source, deleteScan, deleteSecret, deleteService, deleteSessionReplay, deleteSkill, deleteSourceMap, deleteStaticBundle, deleteTeam, deleteUser, deleteWebhook, deployFromImage, deployFromImageUpload, deployFromStatic, deployFromUploadedSource, deploymentMetricsGetLatest, deploymentMetricsGetRange, deploymentMetricsToggle, destroySandbox, detachScheduleService, detectPublicPresets, disableBackupSchedule, disableMfa, discoverWorkloads, domain, downloadGlobalSkillArchive, downloadObject, downloadSkillArchive, emailStatus, embeddings, enableBackupSchedule, enrichVisitor, exec, execDetached, executeDeploymentOperation, executeImport, extendTimeout, externalServiceEnablePgStatStatements, externalServiceMetricsByDatabase, externalServiceMetricsCreateAlertRule, externalServiceMetricsDeleteAlertRule, externalServiceMetricsGetAlertRules, externalServiceMetricsGetLatest, externalServiceMetricsGetRange, externalServiceMetricsStatus, externalServiceMetricsToggle, externalServiceMetricsUpdateAlertRule, externalServiceResetPgStatStatements, finalizeOrder, finalizeProjectRelease, findConversation, generateJoinToken, generatePresetDockerfile, getAccessInfo, getActiveVisitors, getActivityGraph, getAdminGate, getAgent, getAggregatedBuckets, getAiAgentBreakdown, getAiAgentPages, getAiAgentTimeline, getAiPageBreakdown, getAiStatusBreakdown, getAlert, getAlertRule, getAllRepositoriesByName, getAnalyticsActiveVisitors, getAnalyticsEventsCount, getAnalyticsSessionEvents, getAnalyticsVisitorSessions, getApiKey, getApiKeyPermissions, getAuditLog, getBackup, getBackupSchedule, getBranchesByRepositoryId, getBucketedIncidents, getBucketedStatus, getChallengeToken, getChatReadiness, getCliStatus, getClusterHealth, getClusterMember, getCmd, getContainerDetail, getContainerEnvironmentVariable, getContainerInfo, getContainerLogs, getContainerLogsById, getContainerMetrics, getConversation, getConversationDetail, getConversations, getCronById, getCronExecutions, getCrossProjectTraceSiblings, getCurrentMonitorStatus, getCurrentUser, getCustomDomain, getDashboard, getDashboardProjectsAnalytics, getDelivery, getDeployment, getDeploymentContainerLogContent, getDeploymentJobLogs, getDeploymentJobs, getDeploymentOperations, getDeploymentOperationStatus, getDeploymentToken, getDiskStatus, getDnsChanges, getDnsProvider, getDomain, getDomainByHost, getDomainById, getDomainByName, getDomainDnsRecords, getDomainOrder, getEmail, getEmailEvents, getEmailLinks, getEmailProvider, getEmailStats, getEmailTracking, getEmailTrackingStatus, getEntityInfo, getEnvironment, getEnvironmentCrons, getEnvironmentDomains, getEnvironments, getEnvironmentVariables, getEnvironmentVariableValue, getErrorDashboardStats, getErrorEvent, getErrorGroup, getErrorStats, getErrorTimeSeries, getEventDetail, getEventEntries, getEventsCount, getEventsTimeline, getEventTypeBreakdown, getEventVisitors, getExternalImage, getFile, getFlag, getFlagSnapshot, getFunnelMetrics, getGenaiTrace, getGeneralStats, getGitProvider, getGlobalEvents, getGlobalEventStats, getGlobalMcp, getGlobalSandboxStatus, getGlobalSkill, getGroupedPageMetrics, getHealth, getHourlyVisits, getHttpChallengeDebug, getImportStatus, getIncident, getIncidentUpdates, getIpAccessControl, getIpGeolocation, getJoinTokenStatus, getLastDeployment, getLatestScan, getLatestScansPerEnvironment, getLiveVisitorsList, getLogContext, getMcp, getMetricsOverTime, getMonitor, getNotificationProvider, getOnDemandCertStatus, getOrCreateDsn, getPageFlow, getPageHourlySessions, getPagePathDetail, getPagePaths, getPagePathsSparklines, getPagePathVisitors, getPendingAction, getPerformanceMetrics, getPgUpgrade, getPgUpgradeLogs, getPipelineStats, getPlatformInfo, getPostgresWalHealth, getPreferences, getPreviewGatewayLogs, getPreviewGatewaySettings, getPreviewGatewayStatus, getPricing, getPrivateIp, getProject, getProjectAlarmsSummary, getProjectBySlug, getProjectDeployments, getProjects, getProjectServiceEnvironmentVariables, getProjectSessionReplays, getProjectsHealth, getProjectsMonitorHealth, getProjectStatistics, getProjectTemplate, getPropertyBreakdown, getPropertyTimeline, getProviderConnections, getProviderMetadata, getProvidersMetadata, getProxyLogById, getProxyLogByRequestId, getProxyLogs, getPublicBranches, getPublicIp, getPublicRepository, getQuota, getRecentActivity, getRemoteExternalImage, getRepositoryBranches, getRepositoryById, getRepositoryByName, getRepositoryPresetByName, getRepositoryPresetLive, getRepositoryTags, getResolvedEnvironmentVariables, getResolvedEnvironmentVariableValue, getRestoreCapabilities, getRestoreRun, getRoute, getRun, getRunWithLogs, getS3Credentials, getS3Source, getSandbox, getSandboxStatus, getScan, getScanByDeployment, getScanVulnerabilities, getService, getServiceBySlug, getServiceEnvironmentVariable, getServiceEnvironmentVariables, getServiceHealthStatus, getServicePreviewEnvironmentVariableNames, getServicePreviewEnvironmentVariablesMasked, getServiceRuntime, getServiceStats, getServiceTypeParameters, getServiceTypes, getSessionDetails, getSessionEvents, getSessionLogs, getSessionReplay, getSessionReplayEvents, getSettings, getSkill, getSlowQueries, getStaticBundle, getStatusOverview, getTagsByRepositoryId, getTeam, getTimeBucketStats, getTodayStats, getTrace, getUnifiedTrace, getUniqueCounts, getUniqueEvents, getUpdateCapability, getUpdateStatus, getUptimeHistory, getUsageByProvider, getUsageRecent, getUsageSummary, getUsageTimeseries, getUsageTopModels, getVisitorByGuid, getVisitorById, getVisitorDetails, getVisitorFacets, getVisitorInfo, getVisitorJourney, getVisitors, getVisitorSessions, getVisitorStats, getWebhook, grantProjectAccess, handleGitProviderOauthCallback, hasAnalyticsEvents, hasErrorGroups, hasPerformanceMetrics, importExternalService, ingestLogs, ingestLogsByPath, ingestMetrics, ingestMetricsByPath, ingestSentryEnvelope, ingestSentryEvent, ingestTraces, ingestTracesByPath, initSessionReplay, inspectDropArchive, jobLogs, jobStatus, killJob, kvDel, kvDisable, kvEnable, kvExpire, kvGet, kvIncr, kvKeys, kvSet, kvStatus, kvTtl, kvUpdate, latestRunForSource, linkCustomDomainToCertificate, linkServiceToProject, listAgentRuns, listAgents, listAiProviders, listAlertRules, listAlerts, listAllConversations, listAllRuns, listApiKeys, listAuditLogs, listAvailableContainers, listBackupAlerts, listBackupChildren, listBackupSchedules, listBackupsForSchedule, listCommitsByRepositoryId, listConnections, listContainers, listContainersAtPath, listConversations, listCustomDomainsForProject, listDashboards, listDeliveries, listDeploymentContainerLogs, listDeploymentTokens, listDnsProviders, listDomains, listDsns, listEmailDomains, listEmailProviders, listEmails, listEnrollmentTokens, listEntities, listErrorEvents, listErrorGroups, listEvents, listEventTypes, listExternalImages, listExternalPlugins, listExternalServiceBackups, listFlags, listFunnels, listGitProviders, listGlobalMcps, listGlobalSkills, listIncidents, listInsights, listIpAccessControl, listJobs, listKnownAiAgents, listManagedDomains, listMcps, listMetricLabelKeys, listMetricLabelValues, listMetricNames, listModels, listMonitors, listNotificationProviders, listOidcProviders, listOidcProviderUsers, listOidcRoleMappings, listOnDemandCerts, listOrders, listPeers, listPendingActions, listPgUpgrades, listPresets, listProjectAccess, listProjectAlarms, listProjectScans, listProjectSecrets, listProjectServices, listProjectTemplates, listProjectTemplateTags, listProviderKeys, listProviderZones, listPublicProviders, listReleaseFiles, listReleases, listRemoteExternalImages, listRepositoriesByConnection, listRepositoriesByProvider, listRestoreRunsForService, listRootContainers, listRoutes, listS3Sources, listSandboxes, listScheduleRunJobs, listScheduleRuns, listScheduleServices, listSecrets, listServiceHealthStatuses, listServiceProjects, listServices, listServiceSchedules, listSkills, listSourceBackups, listSourceFiles, listSourceMaps, listSources, listStaticBundles, listSyncedRepositories, listTeamMembers, listTeamProjects, listTeams, listUsers, listWebhooks, login, logout, lookupDnsARecords, mintEnrollmentToken, mkdir, nodeHeartbeat, nodeMetricsGetRange, observabilityFullEvent, observabilityListEvents, oidcCallback, type Options, patchAdminGate, patchPreviewGatewaySettings, pauseDeployment, pauseSandbox, planRestore, postDnsAck, previewAlert, previewFunnelMetrics, previewHostnameMode, promoteClusterMember, promoteDeployment, provisionDomain, purgeProjectLogs, pushExternalImage, queryData, queryGenaiTraces, queryLogs, queryMetrics, queryTraces, queryTraceSummaries, readFile, reAnalyze, recordConsoleEvent, recordEventMetrics, recordFlagExposure, recordSpeedMetrics, refreshRouteTable, regenerateDsn, registerExternalImage, registerNode, reinstallGitlabWebhook, rejectPendingAction, reloadPlugins, removeClusterMember, removeManagedDomain, removeRole, removeTeamMember, renameConversation, renewDomain, requestPasswordReset, resetPassword, resizeSandbox, resolveAlarm, restartContainer, restartPreviewGateway, restartSandbox, restoreFlag, restoreUser, resumeDeployment, resumeSandbox, retryCluster, retryDelivery, retryPgUpgrade, retryRun, revealGlobalMcpConfig, revealMcpConfig, revealNotificationProviderConfig, revealServiceParameter, revenueCreateIntegration, revenueDeleteIntegration, revenueGlobalEvents, revenueImportInvoicesCsv, revenueImportSubscriptionsCsv, revenueListIntegrations, revenueListProviders, revenueMetricsCustomers, revenueMetricsGlobalMrr, revenueMetricsGlobalSummary, revenueMetricsMrr, revenueMetricsSummary, revenueRecentEvents, revenueRotateToken, revenueUpdateConfig, revenueUpdateSecret, revokeDsn, revokeEnrollmentToken, revokeJoinToken, revokeProjectAccess, rollbackPgUpgrade, rollbackToDeployment, rootfsGc, rootfsReport, rotateApiKey, rotateDeploymentToken, runBackupForSource, runConnectionHealthCheck, runExternalServiceBackup, runScheduleNow, sandboxCreatePreviewLink, saveAgentToken, saveAiProviderCredential, searchLogs, sendEmail, setDefaultS3Source, setFlagEnvironment, setPreviewPassword, setupDns, setupDnsChallenge, setupEmailTracking, setupMfa, sleepEnvironment, smokeTestAgent, sourceSandbox, startAnalysis, startContainer, startFix, startGitProviderOauth, startOidcLoginBySlug, startPgUpgrade, startRestore, startService, startUpdate, statPath, stopContainer, stopSandbox, stopService, streamContainerMetrics, syncRepositories, tailDeploymentJobLogs, tailLogs, teardownDeployment, teardownEnvironment, testNotificationProvider, testOidcProvider, testProvider, testProviderConnection, testProviderKeyById, testProviderKeyInline, testS3ConnectionPreview, testS3SourceConnection, trackClick, trackOpen, triggerAgent, triggerProjectPipeline, triggerScan, triggerServiceHealthCheck, triggerWeeklyDigest, unlinkServiceFromProject, updateAgent, updateAiProvider, updateAlert, updateAlertRule, updateApiKey, updateAutomaticDeploy, updateBackupSchedule, updateCloudflareProvider, updateConnectionToken, updateCustomDomain, updateDashboard, updateDeploymentToken, updateEmailProvider, updateEnvironmentSettings, updateEnvironmentSubdomain, updateEnvironmentVariable, updateErrorGroup, updateFlag, updateFunnel, updateGitProviderCredentials, updateGitSettings, updateGlobalMcp, updateGlobalSkill, updateIncidentStatus, updateIpAccessControl, updateManagedDomain, updateMcp, updateNotificationEmailProvider, updateNotificationProvider, updateOidcProvider, updatePreferences, updateProject, updateProjectDeploymentConfig, updateProjectSecret, updateProjectSettings, updateProvider, updateProviderKey, updateRoute, updateS3Source, updateSelf, updateService, updateServiceResources, updateSessionDuration, updateSettings, updateSkill, updateSlackProvider, updateSpeedMetrics, updateTeam, updateTeamMemberRole, updateUser, updateWebhook, updateWebhookProvider, upgradePreviewGateway, upgradeService, uploadGlobalSkill, uploadReleaseFile, uploadSkill, uploadSourceFile, uploadSourceMap, uploadStaticBundle, upsertSecret, validateConnection, validateEmail, verifyAndEnableMfa, verifyDomain, verifyEmail, verifyManagedDomain, verifyMfaChallenge, verifyStepUp, wakeEnvironment, webhookTrigger, workflowDryRun, writeFile, writeFiles } from '../sdk.gen'; +import type { AcknowledgeAlarmData, ActivateAiProviderData, ActivateAiProviderResponse, ActivateApiKeyData, ActivateApiKeyResponse, ActivateConnectionData, ActivateProviderData, AddClusterMemberData, AddClusterMemberResponse, AddContextData, AddEnvironmentDomainData, AddEnvironmentDomainResponse, AddEventsData, AddEventsError, AddEventsResponse2, AddManagedDomainData, AddManagedDomainResponse, AddSessionReplayEventsData, AddSessionReplayEventsError, AddSessionReplayEventsResponse, AddTeamMemberData, AddTeamMemberResponse, AdminDrainNodeData, AdminDrainNodeResponse, AdminDrainStatusData, AdminDrainStatusResponse, AdminGetNodeData, AdminGetNodeResponse, AdminListNodeContainersData, AdminListNodeContainersResponse, AdminListNodesData, AdminListNodesResponse, AdminRemoveNodeData, AdminRemoveNodeResponse, AdminUndrainNodeData, AdminUndrainNodeResponse, ApplyHostnameModeData, ApplyHostnameModeResponse, ArchiveConversationData, ArchiveConversationResponse, ArchiveFlagData, ArchiveFlagResponse2, AssignRoleData, AttachScheduleServicesData, AttachScheduleServicesError, AttachScheduleServicesResponse2, BlobCopyData, BlobCopyError, BlobCopyResponse, BlobDeleteData, BlobDeleteError, BlobDeleteResponse, BlobDisableData, BlobDisableResponse, BlobDownloadData, BlobDownloadError, BlobEnableData, BlobEnableResponse, BlobListData, BlobListError, BlobListResponse, BlobPutData, BlobPutError, BlobPutResponse, BlobStatusData, BlobStatusResponse2, BlobUpdateData, BlobUpdateResponse, CancelBackupData, CancelBackupError, CancelBackupResponse2, CancelData, CancelDeploymentData, CancelDeploymentResponse, CancelDomainOrderData, CancelDomainOrderResponse, CancelPgUpgradeData, CancelPgUpgradeResponse, CancelRunData, CancelRunResponse, CancelScheduleRunData, CancelScheduleRunError, CancelScheduleRunResponse, ChangePasswordSelfData, ChangePasswordSelfResponse, ChangeProjectSourceData, ChangeProjectSourceResponse, ChangeRequiredPasswordData, ChangeRequiredPasswordResponse, ChatCompletionsData, ChatCompletionsError, ChatCompletionsResponse, CheckAnalyticsHasEventsData, CheckAnalyticsHasEventsResponse, CheckCommitExistsData, CheckCommitExistsResponse, CheckDomainStatusData, CheckDomainStatusResponse, CheckExplorerSupportData, CheckExplorerSupportResponse, CheckIpBlockedData, CheckIpBlockedError, CheckProviderDeletionSafetyData, CheckProviderDeletionSafetyResponse, ChunkUploadOptionsData, ChunkUploadOptionsResponse, CleanupExpiredBackupsData, CleanupExpiredBackupsError, CleanupExpiredBackupsResponse, ClearPreviewPasswordData, ClearPreviewPasswordResponse, CliDeviceApproveData, CliDeviceApproveResponse2, CliDeviceDenyData, CliDeviceDenyResponse, CliDeviceLookupData, CliDeviceLookupResponse2, CliDevicePollData, CliDevicePollResponse2, CliDeviceStartData, CliDeviceStartResponse2, CliLogoutData, CliLogoutResponse, CmdData, CmdKillData, CmdKillResponse, CmdLogsData, CmdResponse2, ConfirmPendingActionData, ConfirmPendingActionResponse, ContainerMetricsGetHistoryData, ContainerMetricsGetHistoryResponse, CreateAgentData, CreateAgentResponse, CreateAlertData, CreateAlertError, CreateAlertResponse, CreateAlertRuleData, CreateAlertRuleResponse, CreateApiKeyData, CreateApiKeyResponse2, CreateBackupScheduleData, CreateBackupScheduleError, CreateBackupScheduleResponse, CreateBitbucketProviderData, CreateBitbucketProviderResponse, CreateCloudflareProviderData, CreateCloudflareProviderResponse, CreateConversationData, CreateConversationResponse, CreateCustomDomainData, CreateCustomDomainResponse, CreateDashboardData, CreateDashboardError, CreateDashboardResponse, CreateDeploymentTokenData, CreateDeploymentTokenResponse2, CreateDnsProviderData, CreateDnsProviderResponse, CreateDomainData, CreateDomainResponse, CreateDsnData, CreateDsnResponse, CreateEmailDomainData, CreateEmailDomainResponse, CreateEmailProviderData, CreateEmailProviderResponse, CreateEnvironmentData, CreateEnvironmentResponse, CreateEnvironmentVariableData, CreateEnvironmentVariableResponse, CreateFlagData, CreateFlagResponse, CreateFunnelData, CreateFunnelResponse2, CreateGenericProviderData, CreateGenericProviderResponse, CreateGiteaPatProviderData, CreateGiteaPatProviderResponse, CreateGithubPatProviderData, CreateGithubPatProviderResponse, CreateGitlabOauthProviderData, CreateGitlabOauthProviderResponse, CreateGitlabPatProviderData, CreateGitlabPatProviderResponse, CreateGitProviderData, CreateGitProviderResponse, CreateGlobalMcpData, CreateGlobalMcpResponse, CreateGlobalSkillData, CreateGlobalSkillResponse, CreateIncidentData, CreateIncidentResponse, CreateIpAccessControlData, CreateIpAccessControlError, CreateIpAccessControlResponse, CreateMcpData, CreateMcpResponse, CreateMonitorData, CreateMonitorResponse, CreateNotificationEmailProviderData, CreateNotificationEmailProviderResponse, CreateNotificationProviderData, CreateNotificationProviderResponse, CreateOidcProviderData, CreateOidcProviderResponse, CreateOidcRoleMappingData, CreateOidcRoleMappingResponse, CreateOrRecreateOrderData, CreateOrRecreateOrderResponse, CreatePlanData, CreatePlanResponse2, CreatePrData, CreateProjectData, CreateProjectFromTemplateData, CreateProjectFromTemplateResponse2, CreateProjectReleaseData, CreateProjectReleaseResponse, CreateProjectResponse, CreateProjectSecretData, CreateProjectSecretResponse, CreateProviderKeyData, CreateProviderKeyError, CreateProviderKeyResponse, CreatePrResponse2, CreateReleaseData, CreateReleaseResponse, CreateRouteData, CreateRouteResponse, CreateS3SourceData, CreateS3SourceError, CreateS3SourceResponse, CreateSandboxData, CreateSandboxResponse, CreateServiceData, CreateServiceResponse, CreateSkillData, CreateSkillResponse, CreateSlackProviderData, CreateSlackProviderResponse, CreateTeamData, CreateTeamResponse, CreateUserData, CreateUserResponse, CreateWebhookData, CreateWebhookProviderData, CreateWebhookProviderResponse, CreateWebhookResponse, DeactivateApiKeyData, DeactivateApiKeyResponse, DeactivateConnectionData, DeactivateProviderData, DeleteAgentData, DeleteAgentResponse, DeleteAlertData, DeleteAlertError, DeleteAlertResponse, DeleteAlertRuleData, DeleteAlertRuleResponse, DeleteApiKeyData, DeleteApiKeyResponse, DeleteBackupData, DeleteBackupError, DeleteBackupResponse, DeleteBackupScheduleData, DeleteBackupScheduleError, DeleteBackupScheduleResponse, DeleteConnectionData, DeleteConnectionResponse, DeleteCustomDomainData, DeleteCustomDomainResponse, DeleteDashboardData, DeleteDashboardError, DeleteDashboardResponse, DeleteDeploymentTokenData, DeleteDeploymentTokenResponse, DeleteDnsProviderData, DeleteDnsProviderResponse, DeleteDomainData, DeleteDomainResponse, DeleteEmailDomainData, DeleteEmailDomainResponse, DeleteEmailProviderData, DeleteEmailProviderResponse, DeleteEnvironmentData, DeleteEnvironmentDomainData, DeleteEnvironmentDomainResponse, DeleteEnvironmentResponse, DeleteEnvironmentVariableData, DeleteEnvironmentVariableResponse, DeleteExternalImageData, DeleteExternalImageResponse, DeleteFunnelData, DeleteGitProviderData, DeleteGitProviderResponse, DeleteGlobalMcpData, DeleteGlobalMcpResponse, DeleteGlobalSkillData, DeleteGlobalSkillResponse, DeleteIpAccessControlData, DeleteIpAccessControlError, DeleteIpAccessControlResponse, DeleteMcpData, DeleteMcpResponse, DeleteMonitorData, DeleteMonitorResponse, DeleteNotificationProviderData, DeleteNotificationProviderResponse, DeleteOidcProviderData, DeleteOidcProviderResponse, DeleteOidcRoleMappingData, DeleteOidcRoleMappingResponse, DeletePreferencesData, DeletePreferencesResponse, DeleteProjectData, DeleteProjectResponse, DeleteProjectSecretData, DeleteProjectSecretResponse, DeleteProviderKeyData, DeleteProviderKeyError, DeleteProviderKeyResponse, DeleteProviderSafelyData, DeleteProviderSafelyResponse, DeleteReleaseSourceFilesData, DeleteReleaseSourceFilesResponse, DeleteReleaseSourceMapsData, DeleteReleaseSourceMapsResponse, DeleteRouteData, DeleteRouteResponse, DeleteS3SourceData, DeleteS3SourceError, DeleteS3SourceResponse, DeleteScanData, DeleteScanError, DeleteScanResponse, DeleteSecretData, DeleteSecretResponse, DeleteServiceData, DeleteServiceResponse, DeleteSessionReplayData, DeleteSessionReplayError, DeleteSkillData, DeleteSkillResponse, DeleteSourceMapData, DeleteSourceMapResponse, DeleteStaticBundleData, DeleteStaticBundleResponse, DeleteTeamData, DeleteTeamResponse, DeleteUserData, DeleteUserResponse, DeleteWebhookData, DeleteWebhookResponse, DeployFromImageData, DeployFromImageResponse, DeployFromImageUploadData, DeployFromImageUploadResponse, DeployFromStaticData, DeployFromStaticResponse, DeployFromUploadedSourceData, DeployFromUploadedSourceResponse, DeploymentMetricsGetLatestData, DeploymentMetricsGetLatestResponse, DeploymentMetricsGetRangeData, DeploymentMetricsGetRangeResponse, DeploymentMetricsToggleData, DestroySandboxData, DestroySandboxResponse, DetachScheduleServiceData, DetachScheduleServiceError, DetachScheduleServiceResponse, DetectPublicPresetsData, DetectPublicPresetsResponse, DisableBackupScheduleData, DisableBackupScheduleResponse, DisableMfaData, DisableMfaResponse, DiscoverWorkloadsData, DiscoverWorkloadsResponse, DomainData, DomainResponse2, DownloadGlobalSkillArchiveData, DownloadGlobalSkillArchiveResponse, DownloadObjectData, DownloadObjectResponse, DownloadSkillArchiveData, DownloadSkillArchiveResponse, EmailStatusData, EmailStatusResponse2, EmbeddingsData, EmbeddingsError, EmbeddingsResponse, EnableBackupScheduleData, EnableBackupScheduleResponse, EnrichVisitorData, EnrichVisitorResponse2, ExecData, ExecDetachedData, ExecDetachedResponse2, ExecResponse2, ExecuteDeploymentOperationData, ExecuteDeploymentOperationResponse, ExecuteImportData, ExecuteImportResponse2, ExtendTimeoutData, ExtendTimeoutResponse, ExternalServiceEnablePgStatStatementsData, ExternalServiceEnablePgStatStatementsResponse, ExternalServiceMetricsByDatabaseData, ExternalServiceMetricsByDatabaseResponse, ExternalServiceMetricsCreateAlertRuleData, ExternalServiceMetricsCreateAlertRuleResponse, ExternalServiceMetricsDeleteAlertRuleData, ExternalServiceMetricsDeleteAlertRuleResponse, ExternalServiceMetricsGetAlertRulesData, ExternalServiceMetricsGetAlertRulesResponse, ExternalServiceMetricsGetLatestData, ExternalServiceMetricsGetLatestResponse, ExternalServiceMetricsGetRangeData, ExternalServiceMetricsGetRangeResponse, ExternalServiceMetricsStatusData, ExternalServiceMetricsStatusResponse, ExternalServiceMetricsToggleData, ExternalServiceMetricsUpdateAlertRuleData, ExternalServiceMetricsUpdateAlertRuleResponse, ExternalServiceResetPgStatStatementsData, ExternalServiceResetPgStatStatementsResponse, FinalizeOrderData, FinalizeOrderResponse, FinalizeProjectReleaseData, FinalizeProjectReleaseResponse, FindConversationData, FindConversationResponse, GenerateJoinTokenData, GenerateJoinTokenResponse2, GeneratePresetDockerfileData, GeneratePresetDockerfileResponse, GetAccessInfoData, GetAccessInfoResponse, GetActiveVisitorsData, GetActiveVisitorsResponse, GetActivityGraphData, GetActivityGraphResponse, GetAdminGateData, GetAdminGateResponse, GetAgentData, GetAgentResponse, GetAggregatedBucketsData, GetAggregatedBucketsResponse, GetAiAgentBreakdownData, GetAiAgentBreakdownError, GetAiAgentBreakdownResponse, GetAiAgentPagesData, GetAiAgentPagesError, GetAiAgentPagesResponse, GetAiAgentTimelineData, GetAiAgentTimelineError, GetAiAgentTimelineResponse, GetAiPageBreakdownData, GetAiPageBreakdownError, GetAiPageBreakdownResponse, GetAiStatusBreakdownData, GetAiStatusBreakdownError, GetAiStatusBreakdownResponse, GetAlertData, GetAlertError, GetAlertResponse, GetAlertRuleData, GetAlertRuleResponse, GetAllRepositoriesByNameData, GetAllRepositoriesByNameResponse, GetAnalyticsActiveVisitorsData, GetAnalyticsActiveVisitorsResponse, GetAnalyticsEventsCountData, GetAnalyticsEventsCountResponse, GetAnalyticsSessionEventsData, GetAnalyticsSessionEventsResponse, GetAnalyticsVisitorSessionsData, GetAnalyticsVisitorSessionsResponse, GetApiKeyData, GetApiKeyPermissionsData, GetApiKeyPermissionsResponse, GetApiKeyResponse, GetAuditLogData, GetAuditLogResponse, GetBackupData, GetBackupError, GetBackupResponse, GetBackupScheduleData, GetBackupScheduleResponse, GetBranchesByRepositoryIdData, GetBranchesByRepositoryIdResponse, GetBucketedIncidentsData, GetBucketedIncidentsResponse, GetBucketedStatusData, GetBucketedStatusResponse, GetChallengeTokenData, GetChallengeTokenResponse, GetChatReadinessData, GetChatReadinessResponse, GetCliStatusData, GetClusterHealthData, GetClusterHealthResponse, GetClusterMemberData, GetClusterMemberResponse, GetCmdData, GetCmdResponse, GetContainerDetailData, GetContainerDetailResponse, GetContainerEnvironmentVariableData, GetContainerEnvironmentVariableResponse, GetContainerInfoData, GetContainerInfoResponse, GetContainerLogsByIdData, GetContainerLogsData, GetContainerMetricsData, GetContainerMetricsResponse, GetConversationData, GetConversationDetailData, GetConversationDetailError, GetConversationDetailResponse, GetConversationResponse, GetConversationsData, GetConversationsError, GetConversationsResponse, GetCronByIdData, GetCronByIdResponse, GetCronExecutionsData, GetCronExecutionsResponse, GetCrossProjectTraceSiblingsData, GetCrossProjectTraceSiblingsError, GetCrossProjectTraceSiblingsResponse, GetCurrentMonitorStatusData, GetCurrentMonitorStatusResponse, GetCurrentUserData, GetCurrentUserResponse, GetCustomDomainData, GetCustomDomainResponse, GetDashboardData, GetDashboardError, GetDashboardProjectsAnalyticsData, GetDashboardProjectsAnalyticsResponse, GetDashboardResponse, GetDeliveryData, GetDeliveryResponse, GetDeploymentContainerLogContentData, GetDeploymentContainerLogContentResponse, GetDeploymentData, GetDeploymentJobLogsData, GetDeploymentJobLogsResponse, GetDeploymentJobsData, GetDeploymentJobsResponse, GetDeploymentOperationsData, GetDeploymentOperationsResponse, GetDeploymentOperationStatusData, GetDeploymentOperationStatusResponse, GetDeploymentResponse, GetDeploymentTokenData, GetDeploymentTokenResponse, GetDiskStatusData, GetDiskStatusResponse, GetDnsChangesData, GetDnsChangesResponse, GetDnsProviderData, GetDnsProviderResponse, GetDomainByHostData, GetDomainByHostResponse, GetDomainByIdData, GetDomainByIdResponse, GetDomainByNameData, GetDomainByNameResponse, GetDomainData, GetDomainDnsRecordsData, GetDomainDnsRecordsResponse, GetDomainOrderData, GetDomainOrderResponse, GetDomainResponse, GetEmailData, GetEmailEventsData, GetEmailEventsResponse, GetEmailLinksData, GetEmailLinksResponse, GetEmailProviderData, GetEmailProviderResponse, GetEmailResponse, GetEmailStatsData, GetEmailStatsResponse, GetEmailTrackingData, GetEmailTrackingResponse, GetEmailTrackingStatusData, GetEmailTrackingStatusResponse, GetEntityInfoData, GetEntityInfoResponse, GetEnvironmentCronsData, GetEnvironmentCronsResponse, GetEnvironmentData, GetEnvironmentDomainsData, GetEnvironmentDomainsResponse, GetEnvironmentResponse, GetEnvironmentsData, GetEnvironmentsResponse, GetEnvironmentVariablesData, GetEnvironmentVariablesResponse, GetEnvironmentVariableValueData, GetEnvironmentVariableValueResponse, GetErrorDashboardStatsData, GetErrorDashboardStatsResponse, GetErrorEventData, GetErrorEventResponse, GetErrorGroupData, GetErrorGroupResponse, GetErrorStatsData, GetErrorStatsResponse, GetErrorTimeSeriesData, GetErrorTimeSeriesResponse, GetEventDetailData, GetEventDetailResponse, GetEventEntriesData, GetEventEntriesResponse, GetEventsCountData, GetEventsCountResponse, GetEventsTimelineData, GetEventsTimelineResponse, GetEventTypeBreakdownData, GetEventTypeBreakdownResponse, GetEventVisitorsData, GetEventVisitorsResponse, GetExternalImageData, GetExternalImageResponse, GetFileData, GetFileResponse, GetFlagData, GetFlagResponse, GetFlagSnapshotData, GetFlagSnapshotResponse, GetFunnelMetricsData, GetFunnelMetricsResponse, GetGenaiTraceData, GetGenaiTraceError, GetGenaiTraceResponse, GetGeneralStatsData, GetGeneralStatsResponse, GetGitProviderData, GetGitProviderResponse, GetGlobalEventsData, GetGlobalEventsResponse, GetGlobalEventStatsData, GetGlobalEventStatsResponse, GetGlobalMcpData, GetGlobalMcpResponse, GetGlobalSandboxStatusData, GetGlobalSandboxStatusResponse, GetGlobalSkillData, GetGlobalSkillResponse, GetGroupedPageMetricsData, GetGroupedPageMetricsError, GetGroupedPageMetricsResponse, GetHealthData, GetHealthError, GetHealthResponse, GetHourlyVisitsData, GetHourlyVisitsResponse, GetHttpChallengeDebugData, GetHttpChallengeDebugResponse, GetImportStatusData, GetImportStatusResponse, GetIncidentData, GetIncidentResponse, GetIncidentUpdatesData, GetIncidentUpdatesResponse, GetIpAccessControlData, GetIpAccessControlError, GetIpAccessControlResponse, GetIpGeolocationData, GetIpGeolocationError, GetIpGeolocationResponse, GetJoinTokenStatusData, GetJoinTokenStatusResponse, GetLastDeploymentData, GetLastDeploymentResponse, GetLatestScanData, GetLatestScanError, GetLatestScanResponse, GetLatestScansPerEnvironmentData, GetLatestScansPerEnvironmentError, GetLatestScansPerEnvironmentResponse, GetLiveVisitorsListData, GetLiveVisitorsListResponse, GetLogContextData, GetLogContextError, GetLogContextResponse, GetMcpData, GetMcpResponse, GetMetricsOverTimeData, GetMetricsOverTimeError, GetMetricsOverTimeResponse, GetMonitorData, GetMonitorResponse, GetNotificationProviderData, GetNotificationProviderResponse, GetOnDemandCertStatusData, GetOnDemandCertStatusResponse, GetOrCreateDsnData, GetOrCreateDsnResponse, GetPageFlowData, GetPageFlowResponse, GetPageHourlySessionsData, GetPageHourlySessionsResponse, GetPagePathDetailData, GetPagePathDetailResponse, GetPagePathsData, GetPagePathsResponse, GetPagePathsSparklinesData, GetPagePathsSparklinesResponse, GetPagePathVisitorsData, GetPagePathVisitorsResponse, GetPendingActionData, GetPendingActionResponse, GetPerformanceMetricsData, GetPerformanceMetricsError, GetPerformanceMetricsResponse, GetPgUpgradeData, GetPgUpgradeLogsData, GetPgUpgradeLogsResponse, GetPgUpgradeResponse, GetPipelineStatsData, GetPipelineStatsError, GetPipelineStatsResponse, GetPlatformInfoData, GetPlatformInfoResponse, GetPostgresWalHealthData, GetPostgresWalHealthResponse, GetPreferencesData, GetPreferencesResponse, GetPreviewGatewayLogsData, GetPreviewGatewayLogsResponse, GetPreviewGatewaySettingsData, GetPreviewGatewaySettingsResponse, GetPreviewGatewayStatusData, GetPreviewGatewayStatusResponse, GetPricingData, GetPricingError, GetPricingResponse, GetPrivateIpData, GetProjectAlarmsSummaryData, GetProjectAlarmsSummaryResponse, GetProjectBySlugData, GetProjectBySlugResponse, GetProjectData, GetProjectDeploymentsData, GetProjectDeploymentsResponse, GetProjectResponse, GetProjectsData, GetProjectServiceEnvironmentVariablesData, GetProjectServiceEnvironmentVariablesResponse, GetProjectSessionReplaysData, GetProjectSessionReplaysError, GetProjectSessionReplaysResponse2, GetProjectsHealthData, GetProjectsHealthError, GetProjectsHealthResponse, GetProjectsMonitorHealthData, GetProjectsMonitorHealthResponse, GetProjectsResponse, GetProjectStatisticsData, GetProjectStatisticsResponse, GetProjectTemplateData, GetProjectTemplateResponse, GetPropertyBreakdownData, GetPropertyBreakdownResponse, GetPropertyTimelineData, GetPropertyTimelineResponse, GetProviderConnectionsData, GetProviderConnectionsResponse, GetProviderMetadataData, GetProviderMetadataResponse, GetProvidersMetadataData, GetProvidersMetadataResponse, GetProxyLogByIdData, GetProxyLogByIdError, GetProxyLogByIdResponse, GetProxyLogByRequestIdData, GetProxyLogByRequestIdError, GetProxyLogByRequestIdResponse, GetProxyLogsData, GetProxyLogsError, GetProxyLogsResponse, GetPublicBranchesData, GetPublicBranchesResponse, GetPublicIpData, GetPublicRepositoryData, GetPublicRepositoryResponse, GetQuotaData, GetQuotaError, GetQuotaResponse, GetRecentActivityData, GetRecentActivityResponse, GetRemoteExternalImageData, GetRemoteExternalImageResponse, GetRepositoryBranchesData, GetRepositoryBranchesResponse, GetRepositoryByIdData, GetRepositoryByIdResponse, GetRepositoryByNameData, GetRepositoryByNameResponse, GetRepositoryPresetByNameData, GetRepositoryPresetByNameResponse, GetRepositoryPresetLiveData, GetRepositoryPresetLiveResponse, GetRepositoryTagsData, GetRepositoryTagsResponse, GetResolvedEnvironmentVariablesData, GetResolvedEnvironmentVariablesResponse, GetResolvedEnvironmentVariableValueData, GetResolvedEnvironmentVariableValueResponse, GetRestoreCapabilitiesData, GetRestoreCapabilitiesError, GetRestoreCapabilitiesResponse, GetRestoreRunData, GetRestoreRunError, GetRestoreRunResponse, GetRouteData, GetRouteResponse, GetRunData, GetRunResponse, GetRunWithLogsData, GetRunWithLogsResponse, GetS3CredentialsData, GetS3CredentialsResponse, GetS3SourceData, GetS3SourceError, GetS3SourceResponse, GetSandboxData, GetSandboxResponse, GetSandboxStatusData, GetSandboxStatusResponse, GetScanByDeploymentData, GetScanByDeploymentError, GetScanByDeploymentResponse, GetScanData, GetScanError, GetScanResponse, GetScanVulnerabilitiesData, GetScanVulnerabilitiesError, GetScanVulnerabilitiesResponse, GetServiceBySlugData, GetServiceBySlugResponse, GetServiceData, GetServiceEnvironmentVariableData, GetServiceEnvironmentVariableResponse, GetServiceEnvironmentVariablesData, GetServiceEnvironmentVariablesResponse, GetServiceHealthStatusData, GetServiceHealthStatusResponse, GetServicePreviewEnvironmentVariableNamesData, GetServicePreviewEnvironmentVariableNamesResponse, GetServicePreviewEnvironmentVariablesMaskedData, GetServicePreviewEnvironmentVariablesMaskedResponse, GetServiceResponse, GetServiceRuntimeData, GetServiceRuntimeResponse, GetServiceStatsData, GetServiceStatsResponse, GetServiceTypeParametersData, GetServiceTypesData, GetServiceTypesResponse, GetSessionDetailsData, GetSessionDetailsResponse, GetSessionEventsData, GetSessionEventsResponse, GetSessionLogsData, GetSessionLogsResponse, GetSessionReplayData, GetSessionReplayError, GetSessionReplayEventsData, GetSessionReplayEventsError, GetSessionReplayEventsResponse, GetSessionReplayResponse2, GetSettingsData, GetSettingsResponse, GetSkillData, GetSkillResponse, GetSlowQueriesData, GetSlowQueriesResponse, GetStaticBundleData, GetStaticBundleResponse, GetStatusOverviewData, GetStatusOverviewResponse, GetTagsByRepositoryIdData, GetTagsByRepositoryIdResponse, GetTeamData, GetTeamResponse, GetTimeBucketStatsData, GetTimeBucketStatsError, GetTimeBucketStatsResponse, GetTodayStatsData, GetTodayStatsError, GetTodayStatsResponse, GetTraceData, GetTraceError, GetTraceResponse, GetUnifiedTraceData, GetUnifiedTraceError, GetUnifiedTraceResponse, GetUniqueCountsData, GetUniqueCountsResponse, GetUniqueEventsData, GetUniqueEventsResponse, GetUpdateCapabilityData, GetUpdateCapabilityResponse, GetUpdateStatusData, GetUpdateStatusResponse, GetUptimeHistoryData, GetUptimeHistoryResponse, GetUsageByProviderData, GetUsageByProviderError, GetUsageByProviderResponse, GetUsageRecentData, GetUsageRecentError, GetUsageRecentResponse, GetUsageSummaryData, GetUsageSummaryError, GetUsageSummaryResponse, GetUsageTimeseriesData, GetUsageTimeseriesError, GetUsageTimeseriesResponse, GetUsageTopModelsData, GetUsageTopModelsError, GetUsageTopModelsResponse, GetVisitorByGuidData, GetVisitorByGuidResponse, GetVisitorByIdData, GetVisitorByIdResponse, GetVisitorDetailsData, GetVisitorDetailsResponse, GetVisitorFacetsData, GetVisitorFacetsResponse, GetVisitorInfoData, GetVisitorInfoResponse, GetVisitorJourneyData, GetVisitorJourneyResponse, GetVisitorsData, GetVisitorSessionsData, GetVisitorSessionsError, GetVisitorSessionsResponse2, GetVisitorsResponse, GetVisitorStatsData, GetVisitorStatsResponse, GetWebhookData, GetWebhookResponse, GrantProjectAccessData, GrantProjectAccessResponse, HandleGitProviderOauthCallbackData, HasAnalyticsEventsData, HasAnalyticsEventsResponse2, HasErrorGroupsData, HasErrorGroupsResponse2, HasPerformanceMetricsData, HasPerformanceMetricsError, HasPerformanceMetricsResponse, ImportExternalServiceData, ImportExternalServiceResponse, IngestLogsByPathData, IngestLogsByPathError, IngestLogsData, IngestLogsError, IngestMetricsByPathData, IngestMetricsByPathError, IngestMetricsData, IngestMetricsError, IngestSentryEnvelopeData, IngestSentryEventData, IngestSentryEventResponse, IngestTracesByPathData, IngestTracesByPathError, IngestTracesData, IngestTracesError, InitSessionReplayData, InitSessionReplayError, InitSessionReplayResponse, InspectDropArchiveData, InspectDropArchiveResponse, JobLogsData, JobStatusData, JobStatusResponse2, KillJobData, KillJobResponse, KvDelData, KvDelResponse, KvDisableData, KvDisableResponse, KvEnableData, KvEnableResponse, KvExpireData, KvExpireResponse, KvGetData, KvGetResponse, KvIncrData, KvIncrResponse, KvKeysData, KvKeysResponse, KvSetData, KvSetResponse, KvStatusData, KvStatusResponse2, KvTtlData, KvTtlResponse, KvUpdateData, KvUpdateResponse, LatestRunForSourceData, LatestRunForSourceResponse, LinkCustomDomainToCertificateData, LinkCustomDomainToCertificateResponse, LinkServiceToProjectData, LinkServiceToProjectResponse, ListAgentRunsData, ListAgentRunsResponse, ListAgentsData, ListAgentsResponse2, ListAiProvidersData, ListAiProvidersResponse, ListAlertRulesData, ListAlertRulesResponse, ListAlertsData, ListAlertsError, ListAlertsResponse, ListAllConversationsData, ListAllConversationsResponse, ListAllRunsData, ListAllRunsResponse, ListApiKeysData, ListApiKeysResponse, ListAuditLogsData, ListAuditLogsResponse, ListAvailableContainersData, ListAvailableContainersResponse, ListBackupAlertsData, ListBackupAlertsError, ListBackupAlertsResponse, ListBackupChildrenData, ListBackupChildrenError, ListBackupChildrenResponse, ListBackupSchedulesData, ListBackupSchedulesError, ListBackupSchedulesResponse, ListBackupsForScheduleData, ListBackupsForScheduleResponse, ListCommitsByRepositoryIdData, ListCommitsByRepositoryIdResponse, ListConnectionsData, ListConnectionsResponse, ListContainersAtPathData, ListContainersAtPathResponse, ListContainersData, ListContainersResponse, ListConversationsData, ListConversationsResponse, ListCustomDomainsForProjectData, ListCustomDomainsForProjectResponse, ListDashboardsData, ListDashboardsError, ListDashboardsResponse, ListDeliveriesData, ListDeliveriesResponse, ListDeploymentContainerLogsData, ListDeploymentContainerLogsResponse, ListDeploymentTokensData, ListDeploymentTokensResponse, ListDnsProvidersData, ListDnsProvidersResponse, ListDomainsData, ListDomainsResponse2, ListDsnsData, ListDsnsResponse, ListEmailDomainsData, ListEmailDomainsResponse, ListEmailProvidersData, ListEmailProvidersResponse, ListEmailsData, ListEmailsResponse, ListEnrollmentTokensData, ListEnrollmentTokensResponse, ListEntitiesData, ListEntitiesResponse, ListErrorEventsData, ListErrorEventsResponse, ListErrorGroupsData, ListErrorGroupsResponse, ListEventsData, ListEventsResponse, ListEventTypesData, ListEventTypesResponse, ListExternalImagesData, ListExternalImagesResponse, ListExternalPluginsData, ListExternalPluginsResponse, ListExternalServiceBackupsData, ListExternalServiceBackupsError, ListExternalServiceBackupsResponse, ListFlagsData, ListFlagsResponse, ListFunnelsData, ListFunnelsResponse, ListGitProvidersData, ListGitProvidersResponse, ListGlobalMcpsData, ListGlobalMcpsResponse, ListGlobalSkillsData, ListGlobalSkillsResponse, ListIncidentsData, ListInsightsData, ListInsightsError, ListInsightsResponse, ListIpAccessControlData, ListIpAccessControlError, ListIpAccessControlResponse, ListJobsData, ListJobsResponse2, ListKnownAiAgentsData, ListKnownAiAgentsError, ListKnownAiAgentsResponse, ListManagedDomainsData, ListManagedDomainsResponse, ListMcpsData, ListMcpsResponse2, ListMetricLabelKeysData, ListMetricLabelKeysError, ListMetricLabelKeysResponse, ListMetricLabelValuesData, ListMetricLabelValuesError, ListMetricLabelValuesResponse, ListMetricNamesData, ListMetricNamesError, ListMetricNamesResponse, ListModelsData, ListModelsError, ListModelsResponse, ListMonitorsData, ListMonitorsResponse, ListNotificationProvidersData, ListNotificationProvidersResponse, ListOidcProvidersData, ListOidcProvidersResponse, ListOidcProviderUsersData, ListOidcProviderUsersResponse, ListOidcRoleMappingsData, ListOidcRoleMappingsResponse, ListOnDemandCertsData, ListOnDemandCertsResponse2, ListOrdersData, ListOrdersResponse2, ListPeersData, ListPeersResponse, ListPendingActionsData, ListPendingActionsResponse, ListPgUpgradesData, ListPgUpgradesResponse, ListPresetsData, ListPresetsResponse2, ListProjectAccessData, ListProjectAccessResponse, ListProjectAlarmsData, ListProjectAlarmsResponse, ListProjectScansData, ListProjectScansError, ListProjectScansResponse, ListProjectSecretsData, ListProjectSecretsResponse, ListProjectServicesData, ListProjectServicesResponse, ListProjectTemplatesData, ListProjectTemplatesResponse, ListProjectTemplateTagsData, ListProjectTemplateTagsResponse, ListProviderKeysData, ListProviderKeysError, ListProviderKeysResponse, ListProviderZonesData, ListProviderZonesResponse, ListPublicProvidersData, ListPublicProvidersResponse, ListReleaseFilesData, ListReleaseFilesResponse, ListReleasesData, ListReleasesResponse, ListRemoteExternalImagesData, ListRemoteExternalImagesResponse, ListRepositoriesByConnectionData, ListRepositoriesByConnectionResponse, ListRepositoriesByProviderData, ListRepositoriesByProviderResponse, ListRestoreRunsForServiceData, ListRestoreRunsForServiceResponse, ListRootContainersData, ListRootContainersResponse, ListRoutesData, ListRoutesResponse, ListS3SourcesData, ListS3SourcesError, ListS3SourcesResponse, ListSandboxesData, ListSandboxesResponse2, ListScheduleRunJobsData, ListScheduleRunJobsError, ListScheduleRunJobsResponse, ListScheduleRunsData, ListScheduleRunsError, ListScheduleRunsResponse, ListScheduleServicesData, ListScheduleServicesError, ListScheduleServicesResponse, ListSecretsData, ListSecretsResponse2, ListServiceHealthStatusesData, ListServiceHealthStatusesResponse, ListServiceProjectsData, ListServiceProjectsResponse, ListServiceSchedulesData, ListServiceSchedulesError, ListServiceSchedulesResponse, ListServicesData, ListServicesResponse, ListSkillsData, ListSkillsResponse2, ListSourceBackupsData, ListSourceBackupsError, ListSourceBackupsResponse, ListSourceFilesData, ListSourceFilesResponse, ListSourceMapsData, ListSourceMapsResponse, ListSourcesData, ListSourcesResponse, ListStaticBundlesData, ListStaticBundlesResponse, ListSyncedRepositoriesData, ListSyncedRepositoriesResponse, ListTeamMembersData, ListTeamMembersResponse, ListTeamProjectsData, ListTeamProjectsResponse, ListTeamsData, ListTeamsResponse, ListUsersData, ListUsersResponse, ListWebhooksData, ListWebhooksResponse, LoginData, LoginResponse, LogoutData, LookupDnsARecordsData, LookupDnsARecordsError, LookupDnsARecordsResponse, MintEnrollmentTokenData, MintEnrollmentTokenResponse2, MkdirData, MkdirResponse, NodeHeartbeatData, NodeHeartbeatResponse, NodeMetricsGetRangeData, NodeMetricsGetRangeResponse, ObservabilityFullEventData, ObservabilityFullEventError, ObservabilityFullEventResponse, ObservabilityListEventsData, ObservabilityListEventsError, ObservabilityListEventsResponse, OidcCallbackData, PatchAdminGateData, PatchAdminGateResponse, PatchPreviewGatewaySettingsData, PatchPreviewGatewaySettingsResponse, PauseDeploymentData, PauseDeploymentResponse, PauseSandboxData, PauseSandboxResponse, PlanRestoreData, PlanRestoreError, PlanRestoreResponse, PostDnsAckData, PostDnsAckResponse, PreviewAlertData, PreviewAlertError, PreviewAlertResponse, PreviewFunnelMetricsData, PreviewFunnelMetricsResponse, PreviewHostnameModeData, PreviewHostnameModeResponse, PromoteClusterMemberData, PromoteDeploymentData, PromoteDeploymentResponse, ProvisionDomainData, ProvisionDomainResponse, PurgeProjectLogsData, PurgeProjectLogsError, PushExternalImageData, PushExternalImageResponse, QueryDataData, QueryDataResponse2, QueryGenaiTracesData, QueryGenaiTracesError, QueryGenaiTracesResponse, QueryLogsData, QueryLogsError, QueryLogsResponse, QueryMetricsData, QueryMetricsError, QueryMetricsResponse, QueryTracesData, QueryTracesError, QueryTracesResponse, QueryTraceSummariesData, QueryTraceSummariesError, QueryTraceSummariesResponse, ReadFileData, ReadFileResponse2, ReAnalyzeData, RecordConsoleEventData, RecordEventMetricsData, RecordEventMetricsResponse, RecordFlagExposureData, RecordFlagExposureResponse, RecordSpeedMetricsData, RecordSpeedMetricsError, RecordSpeedMetricsResponse, RefreshRouteTableData, RefreshRouteTableResponse, RegenerateDsnData, RegenerateDsnResponse, RegisterExternalImageData, RegisterExternalImageResponse, RegisterNodeData, RegisterNodeResponse2, ReinstallGitlabWebhookData, ReinstallGitlabWebhookResponse, RejectPendingActionData, RejectPendingActionResponse, ReloadPluginsData, ReloadPluginsResponse, RemoveClusterMemberData, RemoveClusterMemberResponse, RemoveManagedDomainData, RemoveManagedDomainResponse, RemoveRoleData, RemoveRoleResponse, RemoveTeamMemberData, RemoveTeamMemberResponse, RenameConversationData, RenameConversationResponse, RenewDomainData, RenewDomainResponse, RequestPasswordResetData, RequestPasswordResetResponse, ResetPasswordData, ResetPasswordResponse, ResizeSandboxData, ResizeSandboxResponse, ResolveAlarmData, RestartContainerData, RestartContainerResponse, RestartPreviewGatewayData, RestartPreviewGatewayResponse, RestartSandboxData, RestartSandboxResponse, RestoreFlagData, RestoreFlagResponse, RestoreUserData, RestoreUserResponse, ResumeDeploymentData, ResumeDeploymentResponse, ResumeSandboxData, ResumeSandboxResponse, RetryClusterData, RetryClusterResponse, RetryDeliveryData, RetryDeliveryResponse, RetryPgUpgradeData, RetryPgUpgradeResponse, RetryRunData, RetryRunResponse, RevealGlobalMcpConfigData, RevealGlobalMcpConfigResponse, RevealMcpConfigData, RevealMcpConfigResponse, RevealNotificationProviderConfigData, RevealNotificationProviderConfigResponse, RevealServiceParameterData, RevealServiceParameterResponse, RevenueCreateIntegrationData, RevenueCreateIntegrationResponse, RevenueDeleteIntegrationData, RevenueDeleteIntegrationResponse, RevenueGlobalEventsData, RevenueGlobalEventsResponse, RevenueImportInvoicesCsvData, RevenueImportInvoicesCsvResponse, RevenueImportSubscriptionsCsvData, RevenueImportSubscriptionsCsvResponse, RevenueListIntegrationsData, RevenueListIntegrationsResponse, RevenueListProvidersData, RevenueListProvidersResponse, RevenueMetricsCustomersData, RevenueMetricsCustomersResponse, RevenueMetricsGlobalMrrData, RevenueMetricsGlobalMrrResponse, RevenueMetricsGlobalSummaryData, RevenueMetricsGlobalSummaryResponse, RevenueMetricsMrrData, RevenueMetricsMrrResponse, RevenueMetricsSummaryData, RevenueMetricsSummaryResponse, RevenueRecentEventsData, RevenueRecentEventsResponse, RevenueRotateTokenData, RevenueRotateTokenResponse, RevenueUpdateConfigData, RevenueUpdateConfigResponse, RevenueUpdateSecretData, RevenueUpdateSecretResponse, RevokeDsnData, RevokeDsnResponse, RevokeEnrollmentTokenData, RevokeEnrollmentTokenResponse, RevokeJoinTokenData, RevokeJoinTokenResponse, RevokeProjectAccessData, RevokeProjectAccessResponse, RollbackPgUpgradeData, RollbackPgUpgradeResponse, RollbackToDeploymentData, RollbackToDeploymentResponse, RootfsGcData, RootfsReportData, RotateApiKeyData, RotateApiKeyResponse, RotateDeploymentTokenData, RotateDeploymentTokenResponse, RunBackupForSourceData, RunBackupForSourceError, RunBackupForSourceResponse, RunConnectionHealthCheckData, RunConnectionHealthCheckResponse, RunExternalServiceBackupData, RunExternalServiceBackupError, RunExternalServiceBackupResponse, RunScheduleNowData, RunScheduleNowError, RunScheduleNowResponse, SandboxCreatePreviewLinkData, SandboxCreatePreviewLinkResponse, SaveAgentTokenData, SaveAgentTokenResponse2, SaveAiProviderCredentialData, SaveAiProviderCredentialResponse, SearchLogsData, SearchLogsError, SearchLogsResponse2, SendEmailData, SendEmailResponse, SetDefaultS3SourceData, SetDefaultS3SourceError, SetDefaultS3SourceResponse, SetFlagEnvironmentData, SetFlagEnvironmentResponse, SetPreviewPasswordData, SetPreviewPasswordResponse2, SetupDnsChallengeData, SetupDnsChallengeResponse2, SetupDnsData, SetupDnsResponse2, SetupEmailTrackingData, SetupEmailTrackingResponse, SetupMfaData, SetupMfaResponse, SleepEnvironmentData, SleepEnvironmentResponse, SmokeTestAgentData, SmokeTestAgentResponse, SourceSandboxData, SourceSandboxResponse, StartAnalysisData, StartAnalysisResponse, StartContainerData, StartContainerResponse, StartFixData, StartGitProviderOauthData, StartOidcLoginBySlugData, StartPgUpgradeData, StartPgUpgradeResponse, StartRestoreData, StartRestoreError, StartRestoreResponse, StartServiceData, StartServiceResponse, StartUpdateData, StartUpdateError, StartUpdateResponse2, StatPathData, StatPathResponse, StopContainerData, StopContainerResponse, StopSandboxData, StopSandboxResponse, StopServiceData, StopServiceResponse, StreamContainerMetricsData, SyncRepositoriesData, SyncRepositoriesResponse, TailDeploymentJobLogsData, TailLogsData, TailLogsError, TeardownDeploymentData, TeardownDeploymentResponse, TeardownEnvironmentData, TeardownEnvironmentResponse, TestNotificationProviderData, TestNotificationProviderResponse, TestOidcProviderData, TestOidcProviderResponse, TestProviderConnectionData, TestProviderConnectionResponse, TestProviderData, TestProviderKeyByIdData, TestProviderKeyByIdError, TestProviderKeyByIdResponse, TestProviderKeyInlineData, TestProviderKeyInlineError, TestProviderKeyInlineResponse, TestProviderResponse2, TestS3ConnectionPreviewData, TestS3ConnectionPreviewError, TestS3ConnectionPreviewResponse, TestS3SourceConnectionData, TestS3SourceConnectionError, TestS3SourceConnectionResponse, TrackClickData, TrackOpenData, TriggerAgentData, TriggerAgentResponse, TriggerProjectPipelineData, TriggerProjectPipelineResponse, TriggerScanData, TriggerScanError, TriggerScanResponse2, TriggerServiceHealthCheckData, TriggerServiceHealthCheckResponse, TriggerWeeklyDigestData, TriggerWeeklyDigestResponse, UnlinkServiceFromProjectData, UnlinkServiceFromProjectResponse, UpdateAgentData, UpdateAgentResponse, UpdateAiProviderData, UpdateAiProviderResponse2, UpdateAlertData, UpdateAlertError, UpdateAlertResponse, UpdateAlertRuleData, UpdateAlertRuleResponse, UpdateApiKeyData, UpdateApiKeyResponse, UpdateAutomaticDeployData, UpdateAutomaticDeployResponse, UpdateBackupScheduleData, UpdateBackupScheduleError, UpdateBackupScheduleResponse, UpdateCloudflareProviderData, UpdateCloudflareProviderResponse, UpdateConnectionTokenData, UpdateConnectionTokenResponse, UpdateCustomDomainData, UpdateCustomDomainResponse, UpdateDashboardData, UpdateDashboardError, UpdateDashboardResponse, UpdateDeploymentTokenData, UpdateDeploymentTokenResponse, UpdateEmailProviderData, UpdateEmailProviderResponse, UpdateEnvironmentSettingsData, UpdateEnvironmentSettingsResponse, UpdateEnvironmentSubdomainData, UpdateEnvironmentSubdomainResponse, UpdateEnvironmentVariableData, UpdateEnvironmentVariableResponse, UpdateErrorGroupData, UpdateFlagData, UpdateFlagResponse, UpdateFunnelData, UpdateGitProviderCredentialsData, UpdateGitProviderCredentialsResponse, UpdateGitSettingsData, UpdateGitSettingsResponse, UpdateGlobalMcpData, UpdateGlobalMcpResponse, UpdateGlobalSkillData, UpdateGlobalSkillResponse, UpdateIncidentStatusData, UpdateIncidentStatusResponse, UpdateIpAccessControlData, UpdateIpAccessControlError, UpdateIpAccessControlResponse, UpdateManagedDomainData, UpdateManagedDomainResponse, UpdateMcpData, UpdateMcpResponse, UpdateNotificationEmailProviderData, UpdateNotificationEmailProviderResponse, UpdateNotificationProviderData, UpdateNotificationProviderResponse, UpdateOidcProviderData, UpdateOidcProviderResponse, UpdatePreferencesData, UpdatePreferencesResponse, UpdateProjectData, UpdateProjectDeploymentConfigData, UpdateProjectDeploymentConfigResponse, UpdateProjectResponse, UpdateProjectSecretData, UpdateProjectSecretResponse, UpdateProjectSettingsData, UpdateProjectSettingsResponse, UpdateProviderData, UpdateProviderKeyData, UpdateProviderKeyError, UpdateProviderKeyResponse, UpdateProviderResponse, UpdateRouteData, UpdateRouteResponse, UpdateS3SourceData, UpdateS3SourceError, UpdateS3SourceResponse, UpdateSelfData, UpdateSelfResponse, UpdateServiceData, UpdateServiceResourcesData, UpdateServiceResourcesResponse, UpdateServiceResponse, UpdateSessionDurationData, UpdateSessionDurationError, UpdateSessionDurationResponse2, UpdateSettingsData, UpdateSettingsResponse, UpdateSkillData, UpdateSkillResponse, UpdateSlackProviderData, UpdateSlackProviderResponse, UpdateSpeedMetricsData, UpdateSpeedMetricsError, UpdateSpeedMetricsResponse, UpdateTeamData, UpdateTeamMemberRoleData, UpdateTeamMemberRoleResponse, UpdateTeamResponse, UpdateUserData, UpdateUserResponse, UpdateWebhookData, UpdateWebhookProviderData, UpdateWebhookProviderResponse, UpdateWebhookResponse, UpgradePreviewGatewayData, UpgradePreviewGatewayResponse, UpgradeServiceData, UpgradeServiceResponse, UploadGlobalSkillData, UploadGlobalSkillResponse, UploadReleaseFileData, UploadReleaseFileResponse, UploadSkillData, UploadSkillResponse, UploadSourceFileData, UploadSourceFileResponse, UploadSourceMapData, UploadSourceMapResponse, UploadStaticBundleData, UploadStaticBundleResponse, UpsertSecretData, UpsertSecretResponse, ValidateConnectionData, ValidateConnectionResponse, ValidateEmailData, ValidateEmailResponse2, VerifyAndEnableMfaData, VerifyAndEnableMfaResponse, VerifyDomainData, VerifyDomainResponse, VerifyEmailData, VerifyEmailResponse, VerifyManagedDomainData, VerifyManagedDomainResponse, VerifyMfaChallengeData, VerifyMfaChallengeResponse, VerifyStepUpData, VerifyStepUpResponse, WakeEnvironmentData, WakeEnvironmentResponse, WebhookTriggerData, WebhookTriggerResponse2, WorkflowDryRunData, WorkflowDryRunResponse, WriteFileData, WriteFileResponse, WriteFilesData, WriteFilesResponse2 } from '../types.gen'; export type QueryKey = [ Pick & { @@ -14553,6 +14553,46 @@ export const downloadGlobalSkillArchiveOptions = (options: Options) => createQueryKey('getUpdateCapability', options); + +/** + * Report whether a release update can be applied from the console. + */ +export const getUpdateCapabilityOptions = (options?: Options) => queryOptions>({ + queryFn: async ({ queryKey, signal }) => { + const { data } = await getUpdateCapability({ + ...options, + ...queryKey[0], + signal, + throwOnError: true + }); + return data; + }, + queryKey: getUpdateCapabilityQueryKey(options) +}); + +/** + * Install a release and restart the server. + * + * Returns as soon as the attempt is accepted: the download and swap run in the + * background and the process then exits so its supervisor restarts it on the + * new binary. Poll `GET /settings/update` for progress — after the restart, + * `last_attempt` carries the outcome. + */ +export const startUpdateMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await startUpdate({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + export const getUpdateStatusQueryKey = (options?: Options) => createQueryKey('getUpdateStatus', options); /** diff --git a/web/src/api/client/index.ts b/web/src/api/client/index.ts index c23bd6359..6dcda3cbf 100644 --- a/web/src/api/client/index.ts +++ b/web/src/api/client/index.ts @@ -1,4 +1,4 @@ // This file is auto-generated by @hey-api/openapi-ts -export { acknowledgeAlarm, activateAiProvider, activateApiKey, activateConnection, activateProvider, addClusterMember, addContext, addEnvironmentDomain, addEvents, addManagedDomain, addSessionReplayEvents, addTeamMember, adminDrainNode, adminDrainStatus, adminGetNode, adminListNodeContainers, adminListNodes, adminRemoveNode, adminUndrainNode, applyHostnameMode, archiveConversation, archiveFlag, assignRole, attachScheduleServices, blobCopy, blobDelete, blobDisable, blobDownload, blobEnable, blobHead, blobList, blobPut, blobStatus, blobUpdate, cancel, cancelBackup, cancelDeployment, cancelDomainOrder, cancelPgUpgrade, cancelRun, cancelScheduleRun, changePasswordSelf, changeProjectSource, changeRequiredPassword, chatCompletions, checkAnalyticsHasEvents, checkCommitExists, checkDomainStatus, checkExplorerSupport, checkIpBlocked, checkProviderDeletionSafety, chunkUploadOptions, cleanupExpiredBackups, clearPreviewPassword, cliDeviceApprove, cliDeviceDeny, cliDeviceLookup, cliDevicePoll, cliDeviceStart, cliLogout, cmd, cmdKill, cmdLogs, confirmPendingAction, containerMetricsGetHistory, createAgent, createAlert, createAlertRule, createApiKey, createBackupSchedule, createBitbucketProvider, createCloudflareProvider, createConversation, createCustomDomain, createDashboard, createDeploymentToken, createDnsProvider, createDomain, createDsn, createEmailDomain, createEmailProvider, createEnvironment, createEnvironmentVariable, createFlag, createFunnel, createGenericProvider, createGiteaPatProvider, createGithubPatProvider, createGitlabOauthProvider, createGitlabPatProvider, createGitProvider, createGlobalMcp, createGlobalSkill, createIncident, createIpAccessControl, createMcp, createMonitor, createNotificationEmailProvider, createNotificationProvider, createOidcProvider, createOidcRoleMapping, createOrRecreateOrder, createPlan, createPr, createProject, createProjectFromTemplate, createProjectRelease, createProjectSecret, createProviderKey, createRelease, createRoute, createS3Source, createSandbox, createService, createSkill, createSlackProvider, createTeam, createUser, createWebhook, createWebhookProvider, deactivateApiKey, deactivateConnection, deactivateProvider, deleteAgent, deleteAlert, deleteAlertRule, deleteApiKey, deleteBackup, deleteBackupSchedule, deleteConnection, deleteCustomDomain, deleteDashboard, deleteDeploymentToken, deleteDnsProvider, deleteDomain, deleteEmailDomain, deleteEmailProvider, deleteEnvironment, deleteEnvironmentDomain, deleteEnvironmentVariable, deleteExternalImage, deleteFunnel, deleteGitProvider, deleteGlobalMcp, deleteGlobalSkill, deleteIpAccessControl, deleteMcp, deleteMonitor, deleteNotificationProvider, deleteOidcProvider, deleteOidcRoleMapping, deletePreferences, deleteProject, deleteProjectSecret, deleteProviderKey, deleteProviderSafely, deleteReleaseSourceFiles, deleteReleaseSourceMaps, deleteRoute, deleteS3Source, deleteScan, deleteSecret, deleteService, deleteSessionReplay, deleteSkill, deleteSourceMap, deleteStaticBundle, deleteTeam, deleteUser, deleteWebhook, deployFromImage, deployFromImageUpload, deployFromStatic, deployFromUploadedSource, deploymentMetricsGetLatest, deploymentMetricsGetRange, deploymentMetricsToggle, destroySandbox, detachScheduleService, detectPublicPresets, disableBackupSchedule, disableMfa, discoverWorkloads, domain, downloadGlobalSkillArchive, downloadObject, downloadSkillArchive, emailStatus, embeddings, enableBackupSchedule, enrichVisitor, exec, execDetached, executeDeploymentOperation, executeImport, extendTimeout, externalServiceEnablePgStatStatements, externalServiceMetricsByDatabase, externalServiceMetricsCreateAlertRule, externalServiceMetricsDeleteAlertRule, externalServiceMetricsGetAlertRules, externalServiceMetricsGetLatest, externalServiceMetricsGetRange, externalServiceMetricsStatus, externalServiceMetricsToggle, externalServiceMetricsUpdateAlertRule, externalServiceResetPgStatStatements, finalizeOrder, finalizeProjectRelease, findConversation, generateJoinToken, generatePresetDockerfile, getAccessInfo, getActiveVisitors, getActivityGraph, getAdminGate, getAgent, getAggregatedBuckets, getAiAgentBreakdown, getAiAgentPages, getAiAgentTimeline, getAiPageBreakdown, getAiStatusBreakdown, getAlert, getAlertRule, getAllRepositoriesByName, getAnalyticsActiveVisitors, getAnalyticsEventsCount, getAnalyticsSessionEvents, getAnalyticsVisitorSessions, getApiKey, getApiKeyPermissions, getAuditLog, getBackup, getBackupSchedule, getBranchesByRepositoryId, getBucketedIncidents, getBucketedStatus, getChallengeToken, getChatReadiness, getCliStatus, getClusterHealth, getClusterMember, getCmd, getContainerDetail, getContainerEnvironmentVariable, getContainerInfo, getContainerLogs, getContainerLogsById, getContainerMetrics, getConversation, getConversationDetail, getConversations, getCronById, getCronExecutions, getCrossProjectTraceSiblings, getCurrentMonitorStatus, getCurrentUser, getCustomDomain, getDashboard, getDashboardProjectsAnalytics, getDelivery, getDeployment, getDeploymentContainerLogContent, getDeploymentJobLogs, getDeploymentJobs, getDeploymentOperations, getDeploymentOperationStatus, getDeploymentToken, getDiskStatus, getDnsChanges, getDnsProvider, getDomain, getDomainByHost, getDomainById, getDomainByName, getDomainDnsRecords, getDomainOrder, getEmail, getEmailEvents, getEmailLinks, getEmailProvider, getEmailStats, getEmailTracking, getEmailTrackingStatus, getEntityInfo, getEnvironment, getEnvironmentCrons, getEnvironmentDomains, getEnvironments, getEnvironmentVariables, getEnvironmentVariableValue, getErrorDashboardStats, getErrorEvent, getErrorGroup, getErrorStats, getErrorTimeSeries, getEventDetail, getEventEntries, getEventsCount, getEventsTimeline, getEventTypeBreakdown, getEventVisitors, getExternalImage, getFile, getFlag, getFlagSnapshot, getFunnelMetrics, getGenaiTrace, getGeneralStats, getGitProvider, getGlobalEvents, getGlobalEventStats, getGlobalMcp, getGlobalSandboxStatus, getGlobalSkill, getGroupedPageMetrics, getHealth, getHourlyVisits, getHttpChallengeDebug, getImportStatus, getIncident, getIncidentUpdates, getIpAccessControl, getIpGeolocation, getJoinTokenStatus, getLastDeployment, getLatestScan, getLatestScansPerEnvironment, getLiveVisitorsList, getLogContext, getMcp, getMetricsOverTime, getMonitor, getNotificationProvider, getOnDemandCertStatus, getOrCreateDsn, getPageFlow, getPageHourlySessions, getPagePathDetail, getPagePaths, getPagePathsSparklines, getPagePathVisitors, getPendingAction, getPerformanceMetrics, getPgUpgrade, getPgUpgradeLogs, getPipelineStats, getPlatformInfo, getPostgresWalHealth, getPreferences, getPreviewGatewayLogs, getPreviewGatewaySettings, getPreviewGatewayStatus, getPricing, getPrivateIp, getProject, getProjectAlarmsSummary, getProjectBySlug, getProjectDeployments, getProjects, getProjectServiceEnvironmentVariables, getProjectSessionReplays, getProjectsHealth, getProjectsMonitorHealth, getProjectStatistics, getProjectTemplate, getPropertyBreakdown, getPropertyTimeline, getProviderConnections, getProviderMetadata, getProvidersMetadata, getProxyLogById, getProxyLogByRequestId, getProxyLogs, getPublicBranches, getPublicIp, getPublicRepository, getQuota, getRecentActivity, getRemoteExternalImage, getRepositoryBranches, getRepositoryById, getRepositoryByName, getRepositoryPresetByName, getRepositoryPresetLive, getRepositoryTags, getResolvedEnvironmentVariables, getResolvedEnvironmentVariableValue, getRestoreCapabilities, getRestoreRun, getRoute, getRun, getRunWithLogs, getS3Credentials, getS3Source, getSandbox, getSandboxStatus, getScan, getScanByDeployment, getScanVulnerabilities, getService, getServiceBySlug, getServiceEnvironmentVariable, getServiceEnvironmentVariables, getServiceHealthStatus, getServicePreviewEnvironmentVariableNames, getServicePreviewEnvironmentVariablesMasked, getServiceRuntime, getServiceStats, getServiceTypeParameters, getServiceTypes, getSessionDetails, getSessionEvents, getSessionLogs, getSessionReplay, getSessionReplayEvents, getSettings, getSkill, getSlowQueries, getStaticBundle, getStatusOverview, getTagsByRepositoryId, getTeam, getTimeBucketStats, getTodayStats, getTrace, getUnifiedTrace, getUniqueCounts, getUniqueEvents, getUpdateStatus, getUptimeHistory, getUsageByProvider, getUsageRecent, getUsageSummary, getUsageTimeseries, getUsageTopModels, getVisitorByGuid, getVisitorById, getVisitorDetails, getVisitorFacets, getVisitorInfo, getVisitorJourney, getVisitors, getVisitorSessions, getVisitorStats, getWebhook, grantProjectAccess, handleGitProviderOauthCallback, hasAnalyticsEvents, hasErrorGroups, hasPerformanceMetrics, importExternalService, ingestLogs, ingestLogsByPath, ingestMetrics, ingestMetricsByPath, ingestSentryEnvelope, ingestSentryEvent, ingestTraces, ingestTracesByPath, initSessionReplay, inspectDropArchive, jobLogs, jobStatus, killJob, kvDel, kvDisable, kvEnable, kvExpire, kvGet, kvIncr, kvKeys, kvSet, kvStatus, kvTtl, kvUpdate, latestRunForSource, linkCustomDomainToCertificate, linkServiceToProject, listAgentRuns, listAgents, listAiProviders, listAlertRules, listAlerts, listAllConversations, listAllRuns, listApiKeys, listAuditLogs, listAvailableContainers, listBackupAlerts, listBackupChildren, listBackupSchedules, listBackupsForSchedule, listCommitsByRepositoryId, listConnections, listContainers, listContainersAtPath, listConversations, listCustomDomainsForProject, listDashboards, listDeliveries, listDeploymentContainerLogs, listDeploymentTokens, listDnsProviders, listDomains, listDsns, listEmailDomains, listEmailProviders, listEmails, listEnrollmentTokens, listEntities, listErrorEvents, listErrorGroups, listEvents, listEventTypes, listExternalImages, listExternalPlugins, listExternalServiceBackups, listFlags, listFunnels, listGitProviders, listGlobalMcps, listGlobalSkills, listIncidents, listInsights, listIpAccessControl, listJobs, listKnownAiAgents, listManagedDomains, listMcps, listMetricLabelKeys, listMetricLabelValues, listMetricNames, listModels, listMonitors, listNotificationProviders, listOidcProviders, listOidcProviderUsers, listOidcRoleMappings, listOnDemandCerts, listOrders, listPeers, listPendingActions, listPgUpgrades, listPresets, listProjectAccess, listProjectAlarms, listProjectScans, listProjectSecrets, listProjectServices, listProjectTemplates, listProjectTemplateTags, listProviderKeys, listProviderZones, listPublicProviders, listReleaseFiles, listReleases, listRemoteExternalImages, listRepositoriesByConnection, listRepositoriesByProvider, listRestoreRunsForService, listRootContainers, listRoutes, listS3Sources, listSandboxes, listScheduleRunJobs, listScheduleRuns, listScheduleServices, listSecrets, listServiceHealthStatuses, listServiceProjects, listServices, listServiceSchedules, listSkills, listSourceBackups, listSourceFiles, listSourceMaps, listSources, listStaticBundles, listSyncedRepositories, listTeamMembers, listTeamProjects, listTeams, listUsers, listWebhooks, login, logout, lookupDnsARecords, mintEnrollmentToken, mkdir, nodeHeartbeat, nodeMetricsGetRange, observabilityFullEvent, observabilityListEvents, oidcCallback, type Options, patchAdminGate, patchPreviewGatewaySettings, pauseDeployment, pauseSandbox, planRestore, postDnsAck, previewAlert, previewFunnelMetrics, previewHostnameMode, promoteClusterMember, promoteDeployment, provisionDomain, purgeProjectLogs, pushExternalImage, queryData, queryGenaiTraces, queryLogs, queryMetrics, queryTraces, queryTraceSummaries, readFile, reAnalyze, recordConsoleEvent, recordEventMetrics, recordFlagExposure, recordSpeedMetrics, refreshRouteTable, regenerateDsn, registerExternalImage, registerNode, reinstallGitlabWebhook, rejectPendingAction, reloadPlugins, removeClusterMember, removeManagedDomain, removeRole, removeTeamMember, renameConversation, renewDomain, requestPasswordReset, resetPassword, resizeSandbox, resolveAlarm, restartContainer, restartPreviewGateway, restartSandbox, restoreFlag, restoreUser, resumeDeployment, resumeSandbox, retryCluster, retryDelivery, retryPgUpgrade, retryRun, revealGlobalMcpConfig, revealMcpConfig, revealNotificationProviderConfig, revealServiceParameter, revenueCreateIntegration, revenueDeleteIntegration, revenueGlobalEvents, revenueImportInvoicesCsv, revenueImportSubscriptionsCsv, revenueListIntegrations, revenueListProviders, revenueMetricsCustomers, revenueMetricsGlobalMrr, revenueMetricsGlobalSummary, revenueMetricsMrr, revenueMetricsSummary, revenueRecentEvents, revenueRotateToken, revenueUpdateConfig, revenueUpdateSecret, revokeDsn, revokeEnrollmentToken, revokeJoinToken, revokeProjectAccess, rollbackPgUpgrade, rollbackToDeployment, rootfsGc, rootfsReport, rotateApiKey, rotateDeploymentToken, runBackupForSource, runConnectionHealthCheck, runExternalServiceBackup, runScheduleNow, sandboxCreatePreviewLink, saveAgentToken, saveAiProviderCredential, searchLogs, sendEmail, setDefaultS3Source, setFlagEnvironment, setPreviewPassword, setupDns, setupDnsChallenge, setupEmailTracking, setupMfa, sleepEnvironment, smokeTestAgent, sourceSandbox, startAnalysis, startContainer, startFix, startGitProviderOauth, startOidcLoginBySlug, startPgUpgrade, startRestore, startService, statPath, stopContainer, stopSandbox, stopService, streamContainerMetrics, streamEvents, streamRunEvents, syncRepositories, tailDeploymentJobLogs, tailLogs, teardownDeployment, teardownEnvironment, testNotificationProvider, testOidcProvider, testProvider, testProviderConnection, testProviderKeyById, testProviderKeyInline, testS3ConnectionPreview, testS3SourceConnection, trackClick, trackOpen, triggerAgent, triggerProjectPipeline, triggerScan, triggerServiceHealthCheck, triggerWeeklyDigest, unlinkServiceFromProject, updateAgent, updateAiProvider, updateAlert, updateAlertRule, updateApiKey, updateAutomaticDeploy, updateBackupSchedule, updateCloudflareProvider, updateConnectionToken, updateCustomDomain, updateDashboard, updateDeploymentToken, updateEmailProvider, updateEnvironmentSettings, updateEnvironmentSubdomain, updateEnvironmentVariable, updateErrorGroup, updateFlag, updateFunnel, updateGitProviderCredentials, updateGitSettings, updateGlobalMcp, updateGlobalSkill, updateIncidentStatus, updateIpAccessControl, updateManagedDomain, updateMcp, updateNotificationEmailProvider, updateNotificationProvider, updateOidcProvider, updatePreferences, updateProject, updateProjectDeploymentConfig, updateProjectSecret, updateProjectSettings, updateProvider, updateProviderKey, updateRoute, updateS3Source, updateSelf, updateService, updateServiceResources, updateSessionDuration, updateSettings, updateSkill, updateSlackProvider, updateSpeedMetrics, updateTeam, updateTeamMemberRole, updateUser, updateWebhook, updateWebhookProvider, upgradePreviewGateway, upgradeService, uploadGlobalSkill, uploadReleaseFile, uploadSkill, uploadSourceFile, uploadSourceMap, uploadStaticBundle, upsertSecret, validateConnection, validateEmail, verifyAndEnableMfa, verifyDomain, verifyEmail, verifyManagedDomain, verifyMfaChallenge, verifyStepUp, wakeEnvironment, webhookTrigger, workflowDryRun, writeFile, writeFiles } from './sdk.gen'; -export type { AcknowledgeAlarmData, AcknowledgeAlarmErrors, AcknowledgeAlarmResponses, AcmeOrderResponse, ActivateAiProviderData, ActivateAiProviderErrors, ActivateAiProviderResponse, ActivateAiProviderResponses, ActivateApiKeyData, ActivateApiKeyErrors, ActivateApiKeyResponse, ActivateApiKeyResponses, ActivateConnectionData, ActivateConnectionErrors, ActivateConnectionResponses, ActivateProviderData, ActivateProviderErrors, ActivateProviderResponse, ActivateProviderResponses, ActiveVisitor, ActiveVisitorsQuery, ActiveVisitorsResponse, ActivityDay, ActivityEvent, ActivityGraphQuery, ActivityGraphResponse, AddClusterMemberData, AddClusterMemberErrors, AddClusterMemberRequest, AddClusterMemberResponse, AddClusterMemberResponses, AddContextData, AddContextErrors, AddContextRequest, AddContextResponses, AddEnvironmentDomainData, AddEnvironmentDomainErrors, AddEnvironmentDomainRequest, AddEnvironmentDomainResponse, AddEnvironmentDomainResponses, AddEventsData, AddEventsError, AddEventsErrors, AddEventsRequest, AddEventsResponse, AddEventsResponse2, AddEventsResponses, AddManagedDomainApiRequest, AddManagedDomainData, AddManagedDomainErrors, AddManagedDomainResponse, AddManagedDomainResponses, AddSessionReplayEventsData, AddSessionReplayEventsError, AddSessionReplayEventsErrors, AddSessionReplayEventsResponse, AddSessionReplayEventsResponses, AddTeamMemberData, AddTeamMemberErrors, AddTeamMemberResponse, AddTeamMemberResponses, AdminDrainNodeData, AdminDrainNodeErrors, AdminDrainNodeResponse, AdminDrainNodeResponses, AdminDrainStatusData, AdminDrainStatusErrors, AdminDrainStatusResponse, AdminDrainStatusResponses, AdminGateResponse, AdminGateSource, AdminGetNodeData, AdminGetNodeErrors, AdminGetNodeResponse, AdminGetNodeResponses, AdminListNodeContainersData, AdminListNodeContainersErrors, AdminListNodeContainersResponse, AdminListNodeContainersResponses, AdminListNodesData, AdminListNodesErrors, AdminListNodesResponse, AdminListNodesResponses, AdminRemoveNodeData, AdminRemoveNodeErrors, AdminRemoveNodeResponse, AdminRemoveNodeResponses, AdminUndrainNodeData, AdminUndrainNodeErrors, AdminUndrainNodeResponse, AdminUndrainNodeResponses, AgentConfigResponse, AgentRunLogResponse, AgentRunResponse, AgentRunWithLogsResponse, AgentSandboxSettings, AgentSandboxSettingsMasked, AggregatedBucketItem, AggregatedBucketsQuery, AggregatedBucketsResponse, AggregationLevel, AggregationTemporality, AiAgentBreakdownResponse, AiAgentBreakdownRow, AiAgentDescriptor, AiAgentPageRow, AiAgentPagesResponse, AiAgentTimelineResponse, AiAgentTimelineRow, AiChatLimitsSettings, AiConfigSettings, AiPageBreakdownResponse, AiPageBreakdownRow, AiStatusBreakdownResponse, AiStatusBreakdownRow, AlarmListResponse, AlarmResponse, AlarmSummaryResponse, AlertRuleResponse, AllocEntry, AnalyticsSessionEventsResponse, AnnotatedSpan, AnomalyAlgorithm, AnomalyParams, AnomalyPreviewPointResponse, AnomalyPreviewRequest, AnomalyPreviewResponse, ApiKeyListResponse, ApiKeyResponse, ApplyHostnameModeData, ApplyHostnameModeErrors, ApplyHostnameModeRequest, ApplyHostnameModeResponse, ApplyHostnameModeResponses, AppSettings, AppSettingsResponse, ArchiveConversationData, ArchiveConversationErrors, ArchiveConversationResponse, ArchiveConversationResponses, ArchiveFlagData, ArchiveFlagErrors, ArchiveFlagResponse, ArchiveFlagResponse2, ArchiveFlagResponses, ArchiveMode, AssignRoleData, AssignRoleErrors, AssignRoleRequest, AssignRoleResponses, AttachScheduleServicesData, AttachScheduleServicesError, AttachScheduleServicesErrors, AttachScheduleServicesRequest, AttachScheduleServicesResponse, AttachScheduleServicesResponse2, AttachScheduleServicesResponses, AuditLogIpInfo, AuditLogResponse, AuditLogUserInfo, AuthFlavorDto, AuthResponse, AuthStatusResponse, AuthTokenResponse, AutofixerRunResponse, AutofixerRunWithLogsResponse, AutofixRunConfig, AutoWatchParams, AvailableContainerInfo, AvailablePermissions, BackupAlertListResponse, BackupAlertResponse, BackupResponse, BackupScheduleResponse, BitbucketAuthInput, BlobCopyData, BlobCopyError, BlobCopyErrors, BlobCopyResponse, BlobCopyResponses, BlobDeleteData, BlobDeleteError, BlobDeleteErrors, BlobDeleteResponse, BlobDeleteResponses, BlobDisableData, BlobDisableErrors, BlobDisableResponse, BlobDisableResponses, BlobDownloadData, BlobDownloadError, BlobDownloadErrors, BlobDownloadResponses, BlobEnableData, BlobEnableErrors, BlobEnableResponse, BlobEnableResponses, BlobHeadData, BlobHeadError, BlobHeadErrors, BlobHeadResponses, BlobListData, BlobListError, BlobListErrors, BlobListResponse, BlobListResponses, BlobPutData, BlobPutError, BlobPutErrors, BlobPutResponse, BlobPutResponses, BlobResponse, BlobStatusData, BlobStatusErrors, BlobStatusResponse, BlobStatusResponse2, BlobStatusResponses, BlobUpdateData, BlobUpdateErrors, BlobUpdateResponse, BlobUpdateResponses, BranchInfo, BranchListResponse, BrowserCount, BrowsersQuery, BuildConfiguration, BuildLimitsSettings, CancelBackupData, CancelBackupError, CancelBackupErrors, CancelBackupResponse, CancelBackupResponse2, CancelBackupResponses, CancelData, CancelDeploymentData, CancelDeploymentErrors, CancelDeploymentResponse, CancelDeploymentResponses, CancelDomainOrderData, CancelDomainOrderErrors, CancelDomainOrderResponse, CancelDomainOrderResponses, CancelErrors, CancelPgUpgradeData, CancelPgUpgradeErrors, CancelPgUpgradeResponse, CancelPgUpgradeResponses, CancelResponses, CancelRunData, CancelRunErrors, CancelRunResponse, CancelRunResponses, CancelScheduleRunData, CancelScheduleRunError, CancelScheduleRunErrors, CancelScheduleRunResponse, CancelScheduleRunResponses, CertStatusResponse, ChallengeConfig, ChallengeError, ChallengeValidationStatus, ChangePasswordRequest, ChangePasswordSelfData, ChangePasswordSelfErrors, ChangePasswordSelfResponse, ChangePasswordSelfResponses, ChangeProjectSourceData, ChangeProjectSourceErrors, ChangeProjectSourceRequest, ChangeProjectSourceResponse, ChangeProjectSourceResponses, ChangeRequiredPasswordData, ChangeRequiredPasswordErrors, ChangeRequiredPasswordResponse, ChangeRequiredPasswordResponses, ChatCompletionChoice, ChatCompletionRequest, ChatCompletionResponse, ChatCompletionsData, ChatCompletionsError, ChatCompletionsErrors, ChatCompletionsResponse, ChatCompletionsResponses, ChatMessage, ChatReadinessResponse, CheckAnalyticsHasEventsData, CheckAnalyticsHasEventsErrors, CheckAnalyticsHasEventsResponse, CheckAnalyticsHasEventsResponses, CheckCommitExistsData, CheckCommitExistsErrors, CheckCommitExistsResponse, CheckCommitExistsResponses, CheckDomainStatusData, CheckDomainStatusErrors, CheckDomainStatusResponse, CheckDomainStatusResponses, CheckExplorerSupportData, CheckExplorerSupportErrors, CheckExplorerSupportResponse, CheckExplorerSupportResponses, CheckIpBlockedData, CheckIpBlockedError, CheckIpBlockedErrors, CheckIpBlockedResponses, CheckProviderDeletionSafetyData, CheckProviderDeletionSafetyErrors, CheckProviderDeletionSafetyResponse, CheckProviderDeletionSafetyResponses, ChildBackupEntryResponse, ChildBackupListResponse, ChunkUploadOptionsData, ChunkUploadOptionsResponse, ChunkUploadOptionsResponses, CleanupExpiredBackupsData, CleanupExpiredBackupsError, CleanupExpiredBackupsErrors, CleanupExpiredBackupsRequest, CleanupExpiredBackupsResponse, CleanupExpiredBackupsResponses, ClearPreviewPasswordData, ClearPreviewPasswordErrors, ClearPreviewPasswordResponse, ClearPreviewPasswordResponses, CliDeviceApproveData, CliDeviceApproveErrors, CliDeviceApproveRequest, CliDeviceApproveResponse, CliDeviceApproveResponse2, CliDeviceApproveResponses, CliDeviceDenyData, CliDeviceDenyErrors, CliDeviceDenyResponse, CliDeviceDenyResponses, CliDeviceLookupData, CliDeviceLookupErrors, CliDeviceLookupResponse, CliDeviceLookupResponse2, CliDeviceLookupResponses, CliDevicePollData, CliDevicePollErrors, CliDevicePollRequest, CliDevicePollResponse, CliDevicePollResponse2, CliDevicePollResponses, CliDeviceStartData, CliDeviceStartErrors, CliDeviceStartRequest, CliDeviceStartResponse, CliDeviceStartResponse2, CliDeviceStartResponses, ClientOptions, CliLoginRequest, CliLogoutData, CliLogoutErrors, CliLogoutResponse, CliLogoutResponses, CloudflareConfig, CloudProvider, ClusterCapacity, ClusterDnsSettings, ClusterHealthReportResponse, ClusterMemberHealthResponse, ClusterMemberRequest, CmdBody, CmdData, CmdErrors, CmdInner, CmdKillBody, CmdKillData, CmdKillErrors, CmdKillResponse, CmdKillResponses, CmdLogsData, CmdLogsErrors, CmdLogsResponses, CmdResponse, CmdResponse2, CmdResponses, CommitExistsResponse, CommitInfo, CommitListResponse, Comparator, ComposePublicPort, ConfirmPendingActionData, ConfirmPendingActionErrors, ConfirmPendingActionResponse, ConfirmPendingActionResponses, ConnectionListQuery, ConnectionListResponse, ConnectionResponse, ConnectionTestResult, ConsoleEventPayload, ContainerActionResponse, ContainerDetailResponse, ContainerEnvironmentVariableValueResponse, ContainerInfoResponse, ContainerInventoryItem, ContainerListResponse, ContainerLogSettings, ContainerLogsQuery, ContainerMetricHistoryPoint, ContainerMetricsGetHistoryData, ContainerMetricsGetHistoryErrors, ContainerMetricsGetHistoryResponse, ContainerMetricsGetHistoryResponses, ContainerMetricsHistoryQuery, ContainerMetricsResponse, ContainerResponse, ContainerRuntimeInfo, ContainerStatsSample, ContentPart, ContextLine, ContextLogsRequest, ContextLogsResponse, ConversationDetailResponse, ConversationResponse, ConversationsQueryParams, ConversationSummary, CopyBlobRequest, CostAnalysis, CreateAgentData, CreateAgentErrors, CreateAgentResponse, CreateAgentResponses, CreateAlertData, CreateAlertError, CreateAlertErrors, CreateAlertResponse, CreateAlertResponses, CreateAlertRuleData, CreateAlertRuleErrors, CreateAlertRuleRequest, CreateAlertRuleResponse, CreateAlertRuleResponses, CreateApiKeyData, CreateApiKeyErrors, CreateApiKeyRequest, CreateApiKeyResponse, CreateApiKeyResponse2, CreateApiKeyResponses, CreateBackupScheduleData, CreateBackupScheduleError, CreateBackupScheduleErrors, CreateBackupScheduleRequest, CreateBackupScheduleResponse, CreateBackupScheduleResponses, CreateBitbucketProviderData, CreateBitbucketProviderErrors, CreateBitbucketProviderResponse, CreateBitbucketProviderResponses, CreateBitbucketRequest, CreateCloudflareProviderData, CreateCloudflareProviderErrors, CreateCloudflareProviderRequest, CreateCloudflareProviderResponse, CreateCloudflareProviderResponses, CreateConversationData, CreateConversationErrors, CreateConversationRequest, CreateConversationResponse, CreateConversationResponses, CreateCustomDomainData, CreateCustomDomainErrors, CreateCustomDomainResponse, CreateCustomDomainResponses, CreateDashboardData, CreateDashboardError, CreateDashboardErrors, CreateDashboardRequest, CreateDashboardResponse, CreateDashboardResponses, CreateDeploymentTokenData, CreateDeploymentTokenErrors, CreateDeploymentTokenRequest, CreateDeploymentTokenResponse, CreateDeploymentTokenResponse2, CreateDeploymentTokenResponses, CreateDnsProviderData, CreateDnsProviderErrors, CreateDnsProviderRequest, CreateDnsProviderResponse, CreateDnsProviderResponses, CreateDomainData, CreateDomainErrors, CreateDomainRequest, CreateDomainResponse, CreateDomainResponses, CreatedResource, CreateDsnData, CreateDsnErrors, CreateDsnRequest, CreateDsnResponse, CreateDsnResponses, CreateEmailDomainData, CreateEmailDomainErrors, CreateEmailDomainRequest, CreateEmailDomainResponse, CreateEmailDomainResponses, CreateEmailProviderData, CreateEmailProviderErrors, CreateEmailProviderRequest, CreateEmailProviderResponse, CreateEmailProviderResponses, CreateEnvironmentData, CreateEnvironmentErrors, CreateEnvironmentRequest, CreateEnvironmentResponse, CreateEnvironmentResponses, CreateEnvironmentVariableData, CreateEnvironmentVariableErrors, CreateEnvironmentVariableRequest, CreateEnvironmentVariableResponse, CreateEnvironmentVariableResponses, CreateExternalServiceRequest, CreateFlagData, CreateFlagErrors, CreateFlagRequest, CreateFlagResponse, CreateFlagResponses, CreateFunnelData, CreateFunnelErrors, CreateFunnelRequest, CreateFunnelResponse, CreateFunnelResponse2, CreateFunnelResponses, CreateFunnelStep, CreateGenericProviderData, CreateGenericProviderErrors, CreateGenericProviderResponse, CreateGenericProviderResponses, CreateGenericRequest, CreateGiteaPatProviderData, CreateGiteaPatProviderErrors, CreateGiteaPatProviderResponse, CreateGiteaPatProviderResponses, CreateGiteaPatRequest, CreateGithubPatProviderData, CreateGithubPatProviderErrors, CreateGithubPatProviderResponse, CreateGithubPatProviderResponses, CreateGitHubPatRequest, CreateGitlabOauthProviderData, CreateGitlabOauthProviderErrors, CreateGitlabOauthProviderResponse, CreateGitlabOauthProviderResponses, CreateGitLabOAuthRequest, CreateGitlabPatProviderData, CreateGitlabPatProviderErrors, CreateGitlabPatProviderResponse, CreateGitlabPatProviderResponses, CreateGitLabPatRequest, CreateGitProviderData, CreateGitProviderErrors, CreateGitProviderResponse, CreateGitProviderResponses, CreateGlobalMcpData, CreateGlobalMcpErrors, CreateGlobalMcpResponse, CreateGlobalMcpResponses, CreateGlobalSkillData, CreateGlobalSkillErrors, CreateGlobalSkillResponse, CreateGlobalSkillResponses, CreateIncidentData, CreateIncidentErrors, CreateIncidentRequest, CreateIncidentResponse, CreateIncidentResponses, CreateIntegrationBody, CreateIpAccessControlData, CreateIpAccessControlError, CreateIpAccessControlErrors, CreateIpAccessControlRequest, CreateIpAccessControlResponse, CreateIpAccessControlResponses, CreateMcpData, CreateMcpErrors, CreateMcpRequest, CreateMcpResponse, CreateMcpResponses, CreateMetricAlertRequest, CreateMonitorData, CreateMonitorErrors, CreateMonitorRequest, CreateMonitorResponse, CreateMonitorResponses, CreateNotificationEmailProviderData, CreateNotificationEmailProviderErrors, CreateNotificationEmailProviderRequest, CreateNotificationEmailProviderResponse, CreateNotificationEmailProviderResponses, CreateNotificationProviderData, CreateNotificationProviderErrors, CreateNotificationProviderResponse, CreateNotificationProviderResponses, CreateOidcProviderData, CreateOidcProviderErrors, CreateOidcProviderRequest, CreateOidcProviderResponse, CreateOidcProviderResponses, CreateOidcRoleMappingData, CreateOidcRoleMappingRequest, CreateOidcRoleMappingResponse, CreateOidcRoleMappingResponses, CreateOrRecreateOrderData, CreateOrRecreateOrderErrors, CreateOrRecreateOrderResponse, CreateOrRecreateOrderResponses, CreatePlanData, CreatePlanErrors, CreatePlanRequest, CreatePlanResponse, CreatePlanResponse2, CreatePlanResponses, CreatePrData, CreatePrErrors, CreateProjectAccessRequest, CreateProjectData, CreateProjectErrors, CreateProjectFromTemplateData, CreateProjectFromTemplateErrors, CreateProjectFromTemplateRequest, CreateProjectFromTemplateResponse, CreateProjectFromTemplateResponse2, CreateProjectFromTemplateResponses, CreateProjectReleaseData, CreateProjectReleaseErrors, CreateProjectReleaseResponse, CreateProjectReleaseResponses, CreateProjectRequest, CreateProjectResponse, CreateProjectResponses, CreateProjectSecretData, CreateProjectSecretErrors, CreateProjectSecretRequest, CreateProjectSecretResponse, CreateProjectSecretResponses, CreateProviderKeyData, CreateProviderKeyError, CreateProviderKeyErrors, CreateProviderKeyRequest, CreateProviderKeyResponse, CreateProviderKeyResponses, CreateProviderRequest, CreatePrResponse, CreatePrResponse2, CreatePrResponses, CreateReleaseData, CreateReleaseErrors, CreateReleaseResponse, CreateReleaseResponses, CreateRouteData, CreateRouteErrors, CreateRouteRequest, CreateRouteResponse, CreateRouteResponses, CreateS3SourceData, CreateS3SourceError, CreateS3SourceErrors, CreateS3SourceRequest, CreateS3SourceResponse, CreateS3SourceResponses, CreateSandboxBody, CreateSandboxData, CreateSandboxErrors, CreateSandboxResponse, CreateSandboxResponses, CreateServiceData, CreateServiceErrors, CreateServiceResponse, CreateServiceResponses, CreateSkillData, CreateSkillErrors, CreateSkillRequest, CreateSkillResponse, CreateSkillResponses, CreateSlackProviderData, CreateSlackProviderErrors, CreateSlackProviderRequest, CreateSlackProviderResponse, CreateSlackProviderResponses, CreateTeamData, CreateTeamErrors, CreateTeamMemberRequest, CreateTeamRequest, CreateTeamResponse, CreateTeamResponses, CreateUserData, CreateUserErrors, CreateUserRequest, CreateUserResponse, CreateUserResponses, CreateWebhookData, CreateWebhookErrors, CreateWebhookProviderData, CreateWebhookProviderErrors, CreateWebhookProviderRequest, CreateWebhookProviderResponse, CreateWebhookProviderResponses, CreateWebhookRequestBody, CreateWebhookResponse, CreateWebhookResponses, CronExecutionInfo, CronInfo, CrossProjectSiblingRef, CrossProjectTraceResponse, CurrentStatusResponse, CustomDomainRequest, CustomDomainResponse, CustomerMovementResponse, DashboardLayout, DashboardProjectsAnalyticsQuery, DashboardProjectsAnalyticsResponse, DashboardSection, DashboardTile, DatabaseMetricsResponse, DatabaseMetricsRow, DataImplication, DataImplicationSeverity, DeactivateApiKeyData, DeactivateApiKeyErrors, DeactivateApiKeyResponse, DeactivateApiKeyResponses, DeactivateConnectionData, DeactivateConnectionErrors, DeactivateConnectionResponses, DeactivateProviderData, DeactivateProviderErrors, DeactivateProviderResponses, DeleteAgentData, DeleteAgentErrors, DeleteAgentResponse, DeleteAgentResponses, DeleteAlertData, DeleteAlertError, DeleteAlertErrors, DeleteAlertResponse, DeleteAlertResponses, DeleteAlertRuleData, DeleteAlertRuleErrors, DeleteAlertRuleResponse, DeleteAlertRuleResponses, DeleteApiKeyData, DeleteApiKeyErrors, DeleteApiKeyResponse, DeleteApiKeyResponses, DeleteBackupData, DeleteBackupError, DeleteBackupErrors, DeleteBackupResponse, DeleteBackupResponses, DeleteBackupScheduleData, DeleteBackupScheduleError, DeleteBackupScheduleErrors, DeleteBackupScheduleResponse, DeleteBackupScheduleResponses, DeleteBlobRequest, DeleteBlobResponse, DeleteConnectionData, DeleteConnectionErrors, DeleteConnectionResponse, DeleteConnectionResponses, DeleteCustomDomainData, DeleteCustomDomainErrors, DeleteCustomDomainResponse, DeleteCustomDomainResponses, DeleteDashboardData, DeleteDashboardError, DeleteDashboardErrors, DeleteDashboardResponse, DeleteDashboardResponses, DeleteDeploymentTokenData, DeleteDeploymentTokenErrors, DeleteDeploymentTokenResponse, DeleteDeploymentTokenResponses, DeleteDnsProviderData, DeleteDnsProviderErrors, DeleteDnsProviderResponse, DeleteDnsProviderResponses, DeleteDomainData, DeleteDomainErrors, DeleteDomainResponse, DeleteDomainResponses, DeleteEmailDomainData, DeleteEmailDomainErrors, DeleteEmailDomainResponse, DeleteEmailDomainResponses, DeleteEmailProviderData, DeleteEmailProviderErrors, DeleteEmailProviderResponse, DeleteEmailProviderResponses, DeleteEnvironmentData, DeleteEnvironmentDomainData, DeleteEnvironmentDomainErrors, DeleteEnvironmentDomainResponse, DeleteEnvironmentDomainResponses, DeleteEnvironmentErrors, DeleteEnvironmentResponse, DeleteEnvironmentResponses, DeleteEnvironmentVariableData, DeleteEnvironmentVariableErrors, DeleteEnvironmentVariableResponse, DeleteEnvironmentVariableResponses, DeleteExternalImageData, DeleteExternalImageErrors, DeleteExternalImageResponse, DeleteExternalImageResponses, DeleteFunnelData, DeleteFunnelErrors, DeleteFunnelResponses, DeleteGitProviderData, DeleteGitProviderErrors, DeleteGitProviderResponse, DeleteGitProviderResponses, DeleteGlobalMcpData, DeleteGlobalMcpErrors, DeleteGlobalMcpResponse, DeleteGlobalMcpResponses, DeleteGlobalSkillData, DeleteGlobalSkillErrors, DeleteGlobalSkillResponse, DeleteGlobalSkillResponses, DeleteIpAccessControlData, DeleteIpAccessControlError, DeleteIpAccessControlErrors, DeleteIpAccessControlResponse, DeleteIpAccessControlResponses, DeleteMcpData, DeleteMcpErrors, DeleteMcpResponse, DeleteMcpResponses, DeleteMonitorData, DeleteMonitorErrors, DeleteMonitorResponse, DeleteMonitorResponses, DeleteNotificationProviderData, DeleteNotificationProviderErrors, DeleteNotificationProviderResponse, DeleteNotificationProviderResponses, DeleteOidcProviderData, DeleteOidcProviderResponse, DeleteOidcProviderResponses, DeleteOidcRoleMappingData, DeleteOidcRoleMappingResponse, DeleteOidcRoleMappingResponses, DeletePreferencesData, DeletePreferencesErrors, DeletePreferencesResponse, DeletePreferencesResponses, DeleteProjectData, DeleteProjectErrors, DeleteProjectResponse, DeleteProjectResponses, DeleteProjectSecretData, DeleteProjectSecretErrors, DeleteProjectSecretResponse, DeleteProjectSecretResponses, DeleteProviderKeyData, DeleteProviderKeyError, DeleteProviderKeyErrors, DeleteProviderKeyResponse, DeleteProviderKeyResponses, DeleteProviderSafelyData, DeleteProviderSafelyErrors, DeleteProviderSafelyResponse, DeleteProviderSafelyResponses, DeleteReleaseSourceFilesData, DeleteReleaseSourceFilesErrors, DeleteReleaseSourceFilesResponse, DeleteReleaseSourceFilesResponses, DeleteReleaseSourceMapsData, DeleteReleaseSourceMapsErrors, DeleteReleaseSourceMapsResponse, DeleteReleaseSourceMapsResponses, DeleteResponse, DeleteRouteData, DeleteRouteErrors, DeleteRouteResponse, DeleteRouteResponses, DeleteS3SourceData, DeleteS3SourceError, DeleteS3SourceErrors, DeleteS3SourceResponse, DeleteS3SourceResponses, DeleteScanData, DeleteScanError, DeleteScanErrors, DeleteScanResponse, DeleteScanResponses, DeleteSecretData, DeleteSecretErrors, DeleteSecretResponse, DeleteSecretResponses, DeleteServiceData, DeleteServiceErrors, DeleteServiceResponse, DeleteServiceResponses, DeleteSessionReplayData, DeleteSessionReplayError, DeleteSessionReplayErrors, DeleteSessionReplayResponses, DeleteSkillData, DeleteSkillErrors, DeleteSkillResponse, DeleteSkillResponses, DeleteSourceMapData, DeleteSourceMapErrors, DeleteSourceMapResponse, DeleteSourceMapResponses, DeleteStaticBundleData, DeleteStaticBundleErrors, DeleteStaticBundleResponse, DeleteStaticBundleResponses, DeleteTeamData, DeleteTeamErrors, DeleteTeamResponse, DeleteTeamResponses, DeleteUserData, DeleteUserErrors, DeleteUserResponse, DeleteUserResponses, DeleteWebhookData, DeleteWebhookErrors, DeleteWebhookResponse, DeleteWebhookResponses, DelRequest, DelResponse, DeployFromImageData, DeployFromImageErrors, DeployFromImageRequest, DeployFromImageResponse, DeployFromImageResponses, DeployFromImageUploadData, DeployFromImageUploadErrors, DeployFromImageUploadQuery, DeployFromImageUploadResponse, DeployFromImageUploadResponses, DeployFromStaticData, DeployFromStaticErrors, DeployFromStaticRequest, DeployFromStaticResponse, DeployFromStaticResponses, DeployFromUploadedSourceData, DeployFromUploadedSourceErrors, DeployFromUploadedSourceResponse, DeployFromUploadedSourceResponses, DeploymentConfig, DeploymentConfigSnapshot, DeploymentConfiguration, DeploymentContainerLogContentResponse, DeploymentContainerLogResponse, DeploymentContainerLogsListResponse, DeploymentEnvironmentResponse, DeploymentJobResponse, DeploymentJobsResponse, DeploymentListResponse, DeploymentMetadata, DeploymentMetricsGetLatestData, DeploymentMetricsGetLatestErrors, DeploymentMetricsGetLatestResponse, DeploymentMetricsGetLatestResponses, DeploymentMetricsGetRangeData, DeploymentMetricsGetRangeErrors, DeploymentMetricsGetRangeResponse, DeploymentMetricsGetRangeResponses, DeploymentMetricsToggleData, DeploymentMetricsToggleErrors, DeploymentMetricsToggleResponses, DeploymentResponse, DeploymentStateResponse, DeploymentStrategy, DeploymentTokenListResponse, DeploymentTokenResponse, DestroySandboxData, DestroySandboxErrors, DestroySandboxResponse, DestroySandboxResponses, DetachScheduleServiceData, DetachScheduleServiceError, DetachScheduleServiceErrors, DetachScheduleServiceResponse, DetachScheduleServiceResponses, DetectionConfig, DetectPublicPresetsData, DetectPublicPresetsErrors, DetectPublicPresetsResponse, DetectPublicPresetsResponses, DeviceCount, DigestSections, Direction, DisableBackupScheduleData, DisableBackupScheduleErrors, DisableBackupScheduleResponse, DisableBackupScheduleResponses, DisableBlobResponse, DisableKvResponse, DisableMfaData, DisableMfaErrors, DisableMfaRequest, DisableMfaResponse, DisableMfaResponses, DiscoverRequest, DiscoverResponse, DiscoverWorkloadsData, DiscoverWorkloadsErrors, DiscoverWorkloadsResponse, DiscoverWorkloadsResponses, DiskInfo, DiskSpaceAlert, DiskSpaceAlertSettings, DiskSpaceCheckResult, DnsAckRequest, DnsAckResponse, DnsChallengeRecordResult, DnsChangesResponse, DnsCompletionResponse, DnsLookupError, DnsLookupRequest, DnsLookupResponse, DnsProviderCredentials, DnsProviderResponse, DnsProviderSettings, DnsProviderSettingsMasked, DnsProviderType, DnsRecord, DnsRecordChange, DnsRecordContent, DnsRecordResponse, DnsRecordSetupResult, DnsRecordStatusResponse, DnsZone, DockerComposePresetConfig, DockerfilePresetConfig, DockerfileVariant, DockerRegistrySettings, DockerRegistrySettingsMasked, DomainAction, DomainChallengeResponse, DomainData, DomainEnvironmentResponse, DomainError, DomainErrors, DomainPlan, DomainResponse, DomainResponse2, DomainResponses, DownloadGlobalSkillArchiveData, DownloadGlobalSkillArchiveErrors, DownloadGlobalSkillArchiveResponse, DownloadGlobalSkillArchiveResponses, DownloadObjectData, DownloadObjectErrors, DownloadObjectResponse, DownloadObjectResponses, DownloadSkillArchiveData, DownloadSkillArchiveErrors, DownloadSkillArchiveResponse, DownloadSkillArchiveResponses, DrainNodeResponse, DrainStatusResponse, DropArchiveUpload, DropInspectionResponse, DropOffPoint, DropPresetCandidate, EmailConfig, EmailDomainResponse, EmailDomainWithDnsResponse, EmailProviderResponse, EmailProviderTypeRoute, EmailRequest, EmailResponse, EmailStatsResponse, EmailStatusData, EmailStatusErrors, EmailStatusResponse, EmailStatusResponse2, EmailStatusResponses, EmailTrackingResponse, EmailTrackingSetupResponse, EmailTrackingStatusResponse, EmbeddingData, EmbeddingInput, EmbeddingRequest, EmbeddingResponse, EmbeddingsData, EmbeddingsError, EmbeddingsErrors, EmbeddingsResponse, EmbeddingsResponses, EmbeddingUsage, EnableBackupScheduleData, EnableBackupScheduleErrors, EnableBackupScheduleResponse, EnableBackupScheduleResponses, EnableBlobRequest, EnableBlobResponse, EnableKvRequest, EnableKvResponse, EnablePgStatStatementsResponse, EndpointDto, EnqueuedJob, EnrichVisitorData, EnrichVisitorErrors, EnrichVisitorRequest, EnrichVisitorResponse, EnrichVisitorResponse2, EnrichVisitorResponses, EnrollmentTokenInfo, EnrollmentTokenListResponse, EntityInfoResponse, EntityResponse, EnvironmentConfiguration, EnvironmentDomainResponse, EnvironmentInfo, EnvironmentResponse, EnvironmentVariable, EnvironmentVariableInfo, EnvironmentVariableResponse, EnvironmentVariableValueResponse, EnvVarInput, EnvVarIntegrationInfo, EnvVarResponse, EnvVarTemplateResponse, ErrorDashboardStatsQuery, ErrorDashboardStatsResponse, ErrorEventResponse, ErrorGroupResponse, ErrorGroupStatsResponse, ErrorResponse, ErrorRow, ErrorTimeSeriesDataResponse, ErrorTimeSeriesQuery, EventActivityBucket, EventBreakdown, EventBrowserStats, EventCount, EventCountryStats, EventDetailQuery, EventDetailResponse, EventEntriesQuery, EventEntriesResponse, EventEntryInfo, EventKind, EventMetricsPayload, EventReferrerStats, EventsCountQuery, EventsResponse, EventTimeline, EventTimelineQuery, EventType, EventTypeBreakdown, EventTypeBreakdownQuery, EventTypeResponse, EventTypesResponse, EventVisitorInfo, EventVisitorsQuery, EventVisitorsResponse, ExecBody, ExecData, ExecDetachedData, ExecDetachedErrors, ExecDetachedResponse, ExecDetachedResponse2, ExecDetachedResponses, ExecErrors, ExecResponse, ExecResponse2, ExecResponses, ExecuteDeploymentOperationData, ExecuteDeploymentOperationErrors, ExecuteDeploymentOperationResponse, ExecuteDeploymentOperationResponses, ExecuteImportData, ExecuteImportErrors, ExecuteImportRequest, ExecuteImportResponse, ExecuteImportResponse2, ExecuteImportResponses, ExecuteOperationRequest, ExpireRequest, ExpireResponse, ExplorerSupportResponse, ExtendTimeoutBody, ExtendTimeoutData, ExtendTimeoutErrors, ExtendTimeoutResponse, ExtendTimeoutResponses, ExternalImageResponse, ExternalServiceBackupResponse, ExternalServiceDetails, ExternalServiceEnablePgStatStatementsData, ExternalServiceEnablePgStatStatementsErrors, ExternalServiceEnablePgStatStatementsResponse, ExternalServiceEnablePgStatStatementsResponses, ExternalServiceInfo, ExternalServiceMetricsByDatabaseData, ExternalServiceMetricsByDatabaseErrors, ExternalServiceMetricsByDatabaseResponse, ExternalServiceMetricsByDatabaseResponses, ExternalServiceMetricsCreateAlertRuleData, ExternalServiceMetricsCreateAlertRuleErrors, ExternalServiceMetricsCreateAlertRuleResponse, ExternalServiceMetricsCreateAlertRuleResponses, ExternalServiceMetricsDeleteAlertRuleData, ExternalServiceMetricsDeleteAlertRuleErrors, ExternalServiceMetricsDeleteAlertRuleResponse, ExternalServiceMetricsDeleteAlertRuleResponses, ExternalServiceMetricsGetAlertRulesData, ExternalServiceMetricsGetAlertRulesErrors, ExternalServiceMetricsGetAlertRulesResponse, ExternalServiceMetricsGetAlertRulesResponses, ExternalServiceMetricsGetLatestData, ExternalServiceMetricsGetLatestErrors, ExternalServiceMetricsGetLatestResponse, ExternalServiceMetricsGetLatestResponses, ExternalServiceMetricsGetRangeData, ExternalServiceMetricsGetRangeErrors, ExternalServiceMetricsGetRangeResponse, ExternalServiceMetricsGetRangeResponses, ExternalServiceMetricsStatusData, ExternalServiceMetricsStatusErrors, ExternalServiceMetricsStatusResponse, ExternalServiceMetricsStatusResponses, ExternalServiceMetricsToggleData, ExternalServiceMetricsToggleErrors, ExternalServiceMetricsToggleResponses, ExternalServiceMetricsUpdateAlertRuleData, ExternalServiceMetricsUpdateAlertRuleErrors, ExternalServiceMetricsUpdateAlertRuleResponse, ExternalServiceMetricsUpdateAlertRuleResponses, ExternalServiceResetPgStatStatementsData, ExternalServiceResetPgStatStatementsErrors, ExternalServiceResetPgStatStatementsResponse, ExternalServiceResetPgStatStatementsResponses, ExternalServiceSummary, FieldResponse, FinalizeOrderData, FinalizeOrderErrors, FinalizeOrderResponse, FinalizeOrderResponses, FinalizeProjectReleaseData, FinalizeProjectReleaseErrors, FinalizeProjectReleaseResponse, FinalizeProjectReleaseResponses, FindConversationData, FindConversationErrors, FindConversationResponse, FindConversationResponses, FiringSeriesEntry, FlagEnvironmentResponse, FlagListResponse, FlagResponse, FlagSnapshot, FlagSnapshotResponse, FlagValueType, ForecastAlgorithm, ForecastParams, FullError, FullEvent, FullRequest, FunnelMetricsResponse, FunnelResponse, GatewayStatus, GenAiEvent, GenAiSpanDetail, GenAiTraceDetailResponse, GenAiTraceSummariesResponse, GenAiTraceSummary, GeneralStatsQuery, GeneralStatsResponse, GenerateDockerfileRequest, GenerateDockerfileResponse, GenerateJoinTokenData, GenerateJoinTokenErrors, GenerateJoinTokenResponse, GenerateJoinTokenResponse2, GenerateJoinTokenResponses, GeneratePresetDockerfileData, GeneratePresetDockerfileErrors, GeneratePresetDockerfileResponse, GeneratePresetDockerfileResponses, GeoLocationResponse, GeoRestrictionsConfig, GetAccessInfoData, GetAccessInfoErrors, GetAccessInfoResponse, GetAccessInfoResponses, GetActiveVisitorsData, GetActiveVisitorsErrors, GetActiveVisitorsResponse, GetActiveVisitorsResponses, GetActivityGraphData, GetActivityGraphErrors, GetActivityGraphResponse, GetActivityGraphResponses, GetAdminGateData, GetAdminGateErrors, GetAdminGateResponse, GetAdminGateResponses, GetAgentData, GetAgentErrors, GetAgentResponse, GetAgentResponses, GetAggregatedBucketsData, GetAggregatedBucketsErrors, GetAggregatedBucketsResponse, GetAggregatedBucketsResponses, GetAiAgentBreakdownData, GetAiAgentBreakdownError, GetAiAgentBreakdownErrors, GetAiAgentBreakdownResponse, GetAiAgentBreakdownResponses, GetAiAgentPagesData, GetAiAgentPagesError, GetAiAgentPagesErrors, GetAiAgentPagesResponse, GetAiAgentPagesResponses, GetAiAgentTimelineData, GetAiAgentTimelineError, GetAiAgentTimelineErrors, GetAiAgentTimelineResponse, GetAiAgentTimelineResponses, GetAiPageBreakdownData, GetAiPageBreakdownError, GetAiPageBreakdownErrors, GetAiPageBreakdownResponse, GetAiPageBreakdownResponses, GetAiStatusBreakdownData, GetAiStatusBreakdownError, GetAiStatusBreakdownErrors, GetAiStatusBreakdownResponse, GetAiStatusBreakdownResponses, GetAlertData, GetAlertError, GetAlertErrors, GetAlertResponse, GetAlertResponses, GetAlertRuleData, GetAlertRuleErrors, GetAlertRuleResponse, GetAlertRuleResponses, GetAllRepositoriesByNameData, GetAllRepositoriesByNameErrors, GetAllRepositoriesByNameResponse, GetAllRepositoriesByNameResponses, GetAnalyticsActiveVisitorsData, GetAnalyticsActiveVisitorsErrors, GetAnalyticsActiveVisitorsResponse, GetAnalyticsActiveVisitorsResponses, GetAnalyticsEventsCountData, GetAnalyticsEventsCountErrors, GetAnalyticsEventsCountResponse, GetAnalyticsEventsCountResponses, GetAnalyticsSessionEventsData, GetAnalyticsSessionEventsErrors, GetAnalyticsSessionEventsResponse, GetAnalyticsSessionEventsResponses, GetAnalyticsVisitorSessionsData, GetAnalyticsVisitorSessionsErrors, GetAnalyticsVisitorSessionsResponse, GetAnalyticsVisitorSessionsResponses, GetApiKeyData, GetApiKeyErrors, GetApiKeyPermissionsData, GetApiKeyPermissionsErrors, GetApiKeyPermissionsResponse, GetApiKeyPermissionsResponses, GetApiKeyResponse, GetApiKeyResponses, GetAuditLogData, GetAuditLogErrors, GetAuditLogResponse, GetAuditLogResponses, GetBackupData, GetBackupError, GetBackupErrors, GetBackupResponse, GetBackupResponses, GetBackupScheduleData, GetBackupScheduleErrors, GetBackupScheduleResponse, GetBackupScheduleResponses, GetBranchesByRepositoryIdData, GetBranchesByRepositoryIdErrors, GetBranchesByRepositoryIdResponse, GetBranchesByRepositoryIdResponses, GetBucketedIncidentsData, GetBucketedIncidentsErrors, GetBucketedIncidentsResponse, GetBucketedIncidentsResponses, GetBucketedStatusData, GetBucketedStatusErrors, GetBucketedStatusResponse, GetBucketedStatusResponses, GetChallengeTokenData, GetChallengeTokenErrors, GetChallengeTokenResponse, GetChallengeTokenResponses, GetChatReadinessData, GetChatReadinessErrors, GetChatReadinessResponse, GetChatReadinessResponses, GetCliStatusData, GetCliStatusErrors, GetCliStatusResponses, GetClusterHealthData, GetClusterHealthErrors, GetClusterHealthResponse, GetClusterHealthResponses, GetClusterMemberData, GetClusterMemberErrors, GetClusterMemberResponse, GetClusterMemberResponses, GetCmdData, GetCmdErrors, GetCmdResponse, GetCmdResponses, GetContainerDetailData, GetContainerDetailErrors, GetContainerDetailResponse, GetContainerDetailResponses, GetContainerEnvironmentVariableData, GetContainerEnvironmentVariableErrors, GetContainerEnvironmentVariableResponse, GetContainerEnvironmentVariableResponses, GetContainerInfoData, GetContainerInfoErrors, GetContainerInfoResponse, GetContainerInfoResponses, GetContainerLogsByIdData, GetContainerLogsByIdErrors, GetContainerLogsData, GetContainerLogsErrors, GetContainerMetricsData, GetContainerMetricsErrors, GetContainerMetricsResponse, GetContainerMetricsResponses, GetConversationData, GetConversationDetailData, GetConversationDetailError, GetConversationDetailErrors, GetConversationDetailResponse, GetConversationDetailResponses, GetConversationErrors, GetConversationResponse, GetConversationResponses, GetConversationsData, GetConversationsError, GetConversationsErrors, GetConversationsResponse, GetConversationsResponses, GetCronByIdData, GetCronByIdErrors, GetCronByIdResponse, GetCronByIdResponses, GetCronExecutionsData, GetCronExecutionsErrors, GetCronExecutionsResponse, GetCronExecutionsResponses, GetCrossProjectTraceSiblingsData, GetCrossProjectTraceSiblingsError, GetCrossProjectTraceSiblingsErrors, GetCrossProjectTraceSiblingsResponse, GetCrossProjectTraceSiblingsResponses, GetCurrentMonitorStatusData, GetCurrentMonitorStatusErrors, GetCurrentMonitorStatusResponse, GetCurrentMonitorStatusResponses, GetCurrentUserData, GetCurrentUserErrors, GetCurrentUserResponse, GetCurrentUserResponses, GetCustomDomainData, GetCustomDomainErrors, GetCustomDomainResponse, GetCustomDomainResponses, GetDashboardData, GetDashboardError, GetDashboardErrors, GetDashboardProjectsAnalyticsData, GetDashboardProjectsAnalyticsErrors, GetDashboardProjectsAnalyticsResponse, GetDashboardProjectsAnalyticsResponses, GetDashboardResponse, GetDashboardResponses, GetDeliveryData, GetDeliveryErrors, GetDeliveryResponse, GetDeliveryResponses, GetDeploymentContainerLogContentData, GetDeploymentContainerLogContentErrors, GetDeploymentContainerLogContentResponse, GetDeploymentContainerLogContentResponses, GetDeploymentData, GetDeploymentErrors, GetDeploymentJobLogsData, GetDeploymentJobLogsErrors, GetDeploymentJobLogsResponse, GetDeploymentJobLogsResponses, GetDeploymentJobsData, GetDeploymentJobsErrors, GetDeploymentJobsResponse, GetDeploymentJobsResponses, GetDeploymentOperationsData, GetDeploymentOperationsErrors, GetDeploymentOperationsResponse, GetDeploymentOperationsResponses, GetDeploymentOperationStatusData, GetDeploymentOperationStatusErrors, GetDeploymentOperationStatusResponse, GetDeploymentOperationStatusResponses, GetDeploymentResponse, GetDeploymentResponses, GetDeploymentsParams, GetDeploymentTokenData, GetDeploymentTokenErrors, GetDeploymentTokenResponse, GetDeploymentTokenResponses, GetDiskStatusData, GetDiskStatusErrors, GetDiskStatusResponse, GetDiskStatusResponses, GetDnsChangesData, GetDnsChangesErrors, GetDnsChangesResponse, GetDnsChangesResponses, GetDnsProviderData, GetDnsProviderErrors, GetDnsProviderResponse, GetDnsProviderResponses, GetDomainByHostData, GetDomainByHostErrors, GetDomainByHostResponse, GetDomainByHostResponses, GetDomainByIdData, GetDomainByIdErrors, GetDomainByIdResponse, GetDomainByIdResponses, GetDomainByNameData, GetDomainByNameErrors, GetDomainByNameResponse, GetDomainByNameResponses, GetDomainData, GetDomainDnsRecordsData, GetDomainDnsRecordsErrors, GetDomainDnsRecordsResponse, GetDomainDnsRecordsResponses, GetDomainErrors, GetDomainOrderData, GetDomainOrderErrors, GetDomainOrderResponse, GetDomainOrderResponses, GetDomainResponse, GetDomainResponses, GetEmailData, GetEmailErrors, GetEmailEventsData, GetEmailEventsErrors, GetEmailEventsResponse, GetEmailEventsResponses, GetEmailLinksData, GetEmailLinksErrors, GetEmailLinksResponse, GetEmailLinksResponses, GetEmailProviderData, GetEmailProviderErrors, GetEmailProviderResponse, GetEmailProviderResponses, GetEmailResponse, GetEmailResponses, GetEmailStatsData, GetEmailStatsErrors, GetEmailStatsResponse, GetEmailStatsResponses, GetEmailTrackingData, GetEmailTrackingErrors, GetEmailTrackingResponse, GetEmailTrackingResponses, GetEmailTrackingStatusData, GetEmailTrackingStatusErrors, GetEmailTrackingStatusResponse, GetEmailTrackingStatusResponses, GetEntityInfoData, GetEntityInfoErrors, GetEntityInfoResponse, GetEntityInfoResponses, GetEnvironmentCronsData, GetEnvironmentCronsErrors, GetEnvironmentCronsResponse, GetEnvironmentCronsResponses, GetEnvironmentData, GetEnvironmentDomainsData, GetEnvironmentDomainsErrors, GetEnvironmentDomainsResponse, GetEnvironmentDomainsResponses, GetEnvironmentErrors, GetEnvironmentResponse, GetEnvironmentResponses, GetEnvironmentsData, GetEnvironmentsErrors, GetEnvironmentsResponse, GetEnvironmentsResponses, GetEnvironmentVariablesData, GetEnvironmentVariablesErrors, GetEnvironmentVariablesQuery, GetEnvironmentVariablesResponse, GetEnvironmentVariablesResponses, GetEnvironmentVariableValueData, GetEnvironmentVariableValueErrors, GetEnvironmentVariableValueResponse, GetEnvironmentVariableValueResponses, GetErrorDashboardStatsData, GetErrorDashboardStatsErrors, GetErrorDashboardStatsResponse, GetErrorDashboardStatsResponses, GetErrorEventData, GetErrorEventErrors, GetErrorEventResponse, GetErrorEventResponses, GetErrorGroupData, GetErrorGroupErrors, GetErrorGroupResponse, GetErrorGroupResponses, GetErrorStatsData, GetErrorStatsErrors, GetErrorStatsResponse, GetErrorStatsResponses, GetErrorTimeSeriesData, GetErrorTimeSeriesErrors, GetErrorTimeSeriesResponse, GetErrorTimeSeriesResponses, GetEventDetailData, GetEventDetailErrors, GetEventDetailResponse, GetEventDetailResponses, GetEventEntriesData, GetEventEntriesErrors, GetEventEntriesResponse, GetEventEntriesResponses, GetEventsCountData, GetEventsCountErrors, GetEventsCountResponse, GetEventsCountResponses, GetEventsTimelineData, GetEventsTimelineErrors, GetEventsTimelineResponse, GetEventsTimelineResponses, GetEventTypeBreakdownData, GetEventTypeBreakdownErrors, GetEventTypeBreakdownResponse, GetEventTypeBreakdownResponses, GetEventVisitorsData, GetEventVisitorsErrors, GetEventVisitorsResponse, GetEventVisitorsResponses, GetExternalImageData, GetExternalImageErrors, GetExternalImageResponse, GetExternalImageResponses, GetFileData, GetFileErrors, GetFileResponse, GetFileResponses, GetFlagData, GetFlagErrors, GetFlagResponse, GetFlagResponses, GetFlagSnapshotData, GetFlagSnapshotErrors, GetFlagSnapshotResponse, GetFlagSnapshotResponses, GetFunnelMetricsData, GetFunnelMetricsErrors, GetFunnelMetricsQuery, GetFunnelMetricsResponse, GetFunnelMetricsResponses, GetGenaiTraceData, GetGenaiTraceError, GetGenaiTraceErrors, GetGenaiTraceResponse, GetGenaiTraceResponses, GetGeneralStatsData, GetGeneralStatsErrors, GetGeneralStatsResponse, GetGeneralStatsResponses, GetGitProviderData, GetGitProviderErrors, GetGitProviderResponse, GetGitProviderResponses, GetGlobalEventsData, GetGlobalEventsErrors, GetGlobalEventsResponse, GetGlobalEventsResponses, GetGlobalEventStatsData, GetGlobalEventStatsErrors, GetGlobalEventStatsResponse, GetGlobalEventStatsResponses, GetGlobalMcpData, GetGlobalMcpErrors, GetGlobalMcpResponse, GetGlobalMcpResponses, GetGlobalSandboxStatusData, GetGlobalSandboxStatusErrors, GetGlobalSandboxStatusResponse, GetGlobalSandboxStatusResponses, GetGlobalSkillData, GetGlobalSkillErrors, GetGlobalSkillResponse, GetGlobalSkillResponses, GetGroupedPageMetricsData, GetGroupedPageMetricsError, GetGroupedPageMetricsErrors, GetGroupedPageMetricsResponse, GetGroupedPageMetricsResponses, GetHealthData, GetHealthError, GetHealthErrors, GetHealthResponse, GetHealthResponses, GetHourlyVisitsData, GetHourlyVisitsErrors, GetHourlyVisitsResponse, GetHourlyVisitsResponses, GetHttpChallengeDebugData, GetHttpChallengeDebugErrors, GetHttpChallengeDebugResponse, GetHttpChallengeDebugResponses, GetImportStatusData, GetImportStatusErrors, GetImportStatusResponse, GetImportStatusResponses, GetIncidentData, GetIncidentErrors, GetIncidentResponse, GetIncidentResponses, GetIncidentUpdatesData, GetIncidentUpdatesErrors, GetIncidentUpdatesResponse, GetIncidentUpdatesResponses, GetIpAccessControlData, GetIpAccessControlError, GetIpAccessControlErrors, GetIpAccessControlResponse, GetIpAccessControlResponses, GetIpGeolocationData, GetIpGeolocationError, GetIpGeolocationErrors, GetIpGeolocationResponse, GetIpGeolocationResponses, GetJoinTokenStatusData, GetJoinTokenStatusErrors, GetJoinTokenStatusResponse, GetJoinTokenStatusResponses, GetLastDeploymentData, GetLastDeploymentErrors, GetLastDeploymentResponse, GetLastDeploymentResponses, GetLatestScanData, GetLatestScanError, GetLatestScanErrors, GetLatestScanResponse, GetLatestScanResponses, GetLatestScansPerEnvironmentData, GetLatestScansPerEnvironmentError, GetLatestScansPerEnvironmentErrors, GetLatestScansPerEnvironmentResponse, GetLatestScansPerEnvironmentResponses, GetLiveVisitorsListData, GetLiveVisitorsListErrors, GetLiveVisitorsListResponse, GetLiveVisitorsListResponses, GetLogContextData, GetLogContextError, GetLogContextErrors, GetLogContextResponse, GetLogContextResponses, GetMcpData, GetMcpErrors, GetMcpResponse, GetMcpResponses, GetMetricsOverTimeData, GetMetricsOverTimeError, GetMetricsOverTimeErrors, GetMetricsOverTimeResponse, GetMetricsOverTimeResponses, GetMonitorData, GetMonitorErrors, GetMonitorResponse, GetMonitorResponses, GetNotificationProviderData, GetNotificationProviderErrors, GetNotificationProviderResponse, GetNotificationProviderResponses, GetOnDemandCertStatusData, GetOnDemandCertStatusErrors, GetOnDemandCertStatusResponse, GetOnDemandCertStatusResponses, GetOrCreateDsnData, GetOrCreateDsnErrors, GetOrCreateDsnRequest, GetOrCreateDsnResponse, GetOrCreateDsnResponses, GetPageFlowData, GetPageFlowErrors, GetPageFlowResponse, GetPageFlowResponses, GetPageHourlySessionsData, GetPageHourlySessionsErrors, GetPageHourlySessionsResponse, GetPageHourlySessionsResponses, GetPagePathDetailData, GetPagePathDetailErrors, GetPagePathDetailResponse, GetPagePathDetailResponses, GetPagePathsData, GetPagePathsErrors, GetPagePathsResponse, GetPagePathsResponses, GetPagePathsSparklinesData, GetPagePathsSparklinesErrors, GetPagePathsSparklinesResponse, GetPagePathsSparklinesResponses, GetPagePathVisitorsData, GetPagePathVisitorsErrors, GetPagePathVisitorsResponse, GetPagePathVisitorsResponses, GetPendingActionData, GetPendingActionErrors, GetPendingActionResponse, GetPendingActionResponses, GetPerformanceMetricsData, GetPerformanceMetricsError, GetPerformanceMetricsErrors, GetPerformanceMetricsResponse, GetPerformanceMetricsResponses, GetPgUpgradeData, GetPgUpgradeErrors, GetPgUpgradeLogsData, GetPgUpgradeLogsErrors, GetPgUpgradeLogsResponse, GetPgUpgradeLogsResponses, GetPgUpgradeResponse, GetPgUpgradeResponses, GetPipelineStatsData, GetPipelineStatsError, GetPipelineStatsErrors, GetPipelineStatsResponse, GetPipelineStatsResponses, GetPlatformInfoData, GetPlatformInfoErrors, GetPlatformInfoResponse, GetPlatformInfoResponses, GetPostgresWalHealthData, GetPostgresWalHealthErrors, GetPostgresWalHealthResponse, GetPostgresWalHealthResponses, GetPreferencesData, GetPreferencesErrors, GetPreferencesResponse, GetPreferencesResponses, GetPreviewGatewayLogsData, GetPreviewGatewayLogsResponse, GetPreviewGatewayLogsResponses, GetPreviewGatewaySettingsData, GetPreviewGatewaySettingsResponse, GetPreviewGatewaySettingsResponses, GetPreviewGatewayStatusData, GetPreviewGatewayStatusResponse, GetPreviewGatewayStatusResponses, GetPricingData, GetPricingError, GetPricingErrors, GetPricingResponse, GetPricingResponses, GetPrivateIpData, GetPrivateIpErrors, GetPrivateIpResponses, GetProjectAlarmsSummaryData, GetProjectAlarmsSummaryErrors, GetProjectAlarmsSummaryResponse, GetProjectAlarmsSummaryResponses, GetProjectBySlugData, GetProjectBySlugErrors, GetProjectBySlugResponse, GetProjectBySlugResponses, GetProjectData, GetProjectDeploymentsData, GetProjectDeploymentsErrors, GetProjectDeploymentsResponse, GetProjectDeploymentsResponses, GetProjectErrors, GetProjectResponse, GetProjectResponses, GetProjectsData, GetProjectSecretsQuery, GetProjectsErrors, GetProjectServiceEnvironmentVariablesData, GetProjectServiceEnvironmentVariablesErrors, GetProjectServiceEnvironmentVariablesResponse, GetProjectServiceEnvironmentVariablesResponses, GetProjectSessionReplaysData, GetProjectSessionReplaysError, GetProjectSessionReplaysErrors, GetProjectSessionReplaysQuery, GetProjectSessionReplaysResponse, GetProjectSessionReplaysResponse2, GetProjectSessionReplaysResponses, GetProjectsHealthData, GetProjectsHealthError, GetProjectsHealthErrors, GetProjectsHealthResponse, GetProjectsHealthResponses, GetProjectsMonitorHealthData, GetProjectsMonitorHealthErrors, GetProjectsMonitorHealthResponse, GetProjectsMonitorHealthResponses, GetProjectsResponse, GetProjectsResponses, GetProjectStatisticsData, GetProjectStatisticsErrors, GetProjectStatisticsResponse, GetProjectStatisticsResponses, GetProjectTemplateData, GetProjectTemplateErrors, GetProjectTemplateResponse, GetProjectTemplateResponses, GetPropertyBreakdownData, GetPropertyBreakdownErrors, GetPropertyBreakdownResponse, GetPropertyBreakdownResponses, GetPropertyTimelineData, GetPropertyTimelineErrors, GetPropertyTimelineResponse, GetPropertyTimelineResponses, GetProviderConnectionsData, GetProviderConnectionsErrors, GetProviderConnectionsResponse, GetProviderConnectionsResponses, GetProviderMetadataData, GetProviderMetadataErrors, GetProviderMetadataResponse, GetProviderMetadataResponses, GetProvidersMetadataData, GetProvidersMetadataErrors, GetProvidersMetadataResponse, GetProvidersMetadataResponses, GetProxyLogByIdData, GetProxyLogByIdError, GetProxyLogByIdErrors, GetProxyLogByIdResponse, GetProxyLogByIdResponses, GetProxyLogByRequestIdData, GetProxyLogByRequestIdError, GetProxyLogByRequestIdErrors, GetProxyLogByRequestIdResponse, GetProxyLogByRequestIdResponses, GetProxyLogsData, GetProxyLogsError, GetProxyLogsErrors, GetProxyLogsResponse, GetProxyLogsResponses, GetPublicBranchesData, GetPublicBranchesErrors, GetPublicBranchesResponse, GetPublicBranchesResponses, GetPublicIpData, GetPublicIpErrors, GetPublicIpResponses, GetPublicRepositoryData, GetPublicRepositoryErrors, GetPublicRepositoryResponse, GetPublicRepositoryResponses, GetQuotaData, GetQuotaError, GetQuotaErrors, GetQuotaResponse, GetQuotaResponses, GetRecentActivityData, GetRecentActivityErrors, GetRecentActivityResponse, GetRecentActivityResponses, GetRemoteExternalImageData, GetRemoteExternalImageErrors, GetRemoteExternalImageResponse, GetRemoteExternalImageResponses, GetRepositoryBranchesData, GetRepositoryBranchesErrors, GetRepositoryBranchesResponse, GetRepositoryBranchesResponses, GetRepositoryByIdData, GetRepositoryByIdErrors, GetRepositoryByIdResponse, GetRepositoryByIdResponses, GetRepositoryByNameData, GetRepositoryByNameErrors, GetRepositoryByNameResponse, GetRepositoryByNameResponses, GetRepositoryPresetByNameData, GetRepositoryPresetByNameErrors, GetRepositoryPresetByNameResponse, GetRepositoryPresetByNameResponses, GetRepositoryPresetLiveData, GetRepositoryPresetLiveErrors, GetRepositoryPresetLiveResponse, GetRepositoryPresetLiveResponses, GetRepositoryTagsData, GetRepositoryTagsErrors, GetRepositoryTagsResponse, GetRepositoryTagsResponses, GetRequest, GetResolvedEnvironmentVariablesData, GetResolvedEnvironmentVariablesErrors, GetResolvedEnvironmentVariablesResponse, GetResolvedEnvironmentVariablesResponses, GetResolvedEnvironmentVariableValueData, GetResolvedEnvironmentVariableValueErrors, GetResolvedEnvironmentVariableValueResponse, GetResolvedEnvironmentVariableValueResponses, GetResponse, GetRestoreCapabilitiesData, GetRestoreCapabilitiesError, GetRestoreCapabilitiesErrors, GetRestoreCapabilitiesResponse, GetRestoreCapabilitiesResponses, GetRestoreRunData, GetRestoreRunError, GetRestoreRunErrors, GetRestoreRunResponse, GetRestoreRunResponses, GetRouteData, GetRouteErrors, GetRouteResponse, GetRouteResponses, GetRunData, GetRunErrors, GetRunResponse, GetRunResponses, GetRunWithLogsData, GetRunWithLogsErrors, GetRunWithLogsResponse, GetRunWithLogsResponses, GetS3CredentialsData, GetS3CredentialsErrors, GetS3CredentialsResponse, GetS3CredentialsResponses, GetS3SourceData, GetS3SourceError, GetS3SourceErrors, GetS3SourceResponse, GetS3SourceResponses, GetSandboxData, GetSandboxErrors, GetSandboxResponse, GetSandboxResponses, GetSandboxStatusData, GetSandboxStatusErrors, GetSandboxStatusResponse, GetSandboxStatusResponses, GetScanByDeploymentData, GetScanByDeploymentError, GetScanByDeploymentErrors, GetScanByDeploymentResponse, GetScanByDeploymentResponses, GetScanData, GetScanError, GetScanErrors, GetScanResponse, GetScanResponses, GetScanVulnerabilitiesData, GetScanVulnerabilitiesError, GetScanVulnerabilitiesErrors, GetScanVulnerabilitiesResponse, GetScanVulnerabilitiesResponses, GetServiceBySlugData, GetServiceBySlugErrors, GetServiceBySlugResponse, GetServiceBySlugResponses, GetServiceData, GetServiceEnvironmentVariableData, GetServiceEnvironmentVariableErrors, GetServiceEnvironmentVariableResponse, GetServiceEnvironmentVariableResponses, GetServiceEnvironmentVariablesData, GetServiceEnvironmentVariablesErrors, GetServiceEnvironmentVariablesResponse, GetServiceEnvironmentVariablesResponses, GetServiceErrors, GetServiceHealthStatusData, GetServiceHealthStatusErrors, GetServiceHealthStatusResponse, GetServiceHealthStatusResponses, GetServicePreviewEnvironmentVariableNamesData, GetServicePreviewEnvironmentVariableNamesErrors, GetServicePreviewEnvironmentVariableNamesResponse, GetServicePreviewEnvironmentVariableNamesResponses, GetServicePreviewEnvironmentVariablesMaskedData, GetServicePreviewEnvironmentVariablesMaskedErrors, GetServicePreviewEnvironmentVariablesMaskedResponse, GetServicePreviewEnvironmentVariablesMaskedResponses, GetServiceResponse, GetServiceResponses, GetServiceRuntimeData, GetServiceRuntimeErrors, GetServiceRuntimeResponse, GetServiceRuntimeResponses, GetServiceStatsData, GetServiceStatsErrors, GetServiceStatsResponse, GetServiceStatsResponses, GetServiceTypeParametersData, GetServiceTypeParametersErrors, GetServiceTypeParametersResponses, GetServiceTypesData, GetServiceTypesErrors, GetServiceTypesResponse, GetServiceTypesResponses, GetSessionDetailsData, GetSessionDetailsErrors, GetSessionDetailsResponse, GetSessionDetailsResponses, GetSessionEventsData, GetSessionEventsErrors, GetSessionEventsResponse, GetSessionEventsResponses, GetSessionLogsData, GetSessionLogsErrors, GetSessionLogsResponse, GetSessionLogsResponses, GetSessionReplayData, GetSessionReplayError, GetSessionReplayErrors, GetSessionReplayEventsData, GetSessionReplayEventsError, GetSessionReplayEventsErrors, GetSessionReplayEventsResponse, GetSessionReplayEventsResponses, GetSessionReplayResponse, GetSessionReplayResponse2, GetSessionReplayResponses, GetSettingsData, GetSettingsErrors, GetSettingsResponse, GetSettingsResponses, GetSkillData, GetSkillErrors, GetSkillResponse, GetSkillResponses, GetSlowQueriesData, GetSlowQueriesErrors, GetSlowQueriesResponse, GetSlowQueriesResponses, GetStaticBundleData, GetStaticBundleErrors, GetStaticBundleResponse, GetStaticBundleResponses, GetStatusOverviewData, GetStatusOverviewErrors, GetStatusOverviewResponse, GetStatusOverviewResponses, GetTagsByRepositoryIdData, GetTagsByRepositoryIdErrors, GetTagsByRepositoryIdResponse, GetTagsByRepositoryIdResponses, GetTeamData, GetTeamErrors, GetTeamResponse, GetTeamResponses, GetTimeBucketStatsData, GetTimeBucketStatsError, GetTimeBucketStatsErrors, GetTimeBucketStatsResponse, GetTimeBucketStatsResponses, GetTodayStatsData, GetTodayStatsError, GetTodayStatsErrors, GetTodayStatsResponse, GetTodayStatsResponses, GetTraceData, GetTraceError, GetTraceErrors, GetTraceResponse, GetTraceResponses, GetUnifiedTraceData, GetUnifiedTraceError, GetUnifiedTraceErrors, GetUnifiedTraceResponse, GetUnifiedTraceResponses, GetUniqueCountsData, GetUniqueCountsErrors, GetUniqueCountsResponse, GetUniqueCountsResponses, GetUniqueEventsData, GetUniqueEventsErrors, GetUniqueEventsQuery, GetUniqueEventsResponse, GetUniqueEventsResponses, GetUpdateStatusData, GetUpdateStatusErrors, GetUpdateStatusResponse, GetUpdateStatusResponses, GetUptimeHistoryData, GetUptimeHistoryErrors, GetUptimeHistoryResponse, GetUptimeHistoryResponses, GetUsageByProviderData, GetUsageByProviderError, GetUsageByProviderErrors, GetUsageByProviderResponse, GetUsageByProviderResponses, GetUsageRecentData, GetUsageRecentError, GetUsageRecentErrors, GetUsageRecentResponse, GetUsageRecentResponses, GetUsageSummaryData, GetUsageSummaryError, GetUsageSummaryErrors, GetUsageSummaryResponse, GetUsageSummaryResponses, GetUsageTimeseriesData, GetUsageTimeseriesError, GetUsageTimeseriesErrors, GetUsageTimeseriesResponse, GetUsageTimeseriesResponses, GetUsageTopModelsData, GetUsageTopModelsError, GetUsageTopModelsErrors, GetUsageTopModelsResponse, GetUsageTopModelsResponses, GetVisitorByGuidData, GetVisitorByGuidErrors, GetVisitorByGuidResponse, GetVisitorByGuidResponses, GetVisitorByIdData, GetVisitorByIdErrors, GetVisitorByIdResponse, GetVisitorByIdResponses, GetVisitorDetailsData, GetVisitorDetailsErrors, GetVisitorDetailsResponse, GetVisitorDetailsResponses, GetVisitorFacetsData, GetVisitorFacetsErrors, GetVisitorFacetsResponse, GetVisitorFacetsResponses, GetVisitorInfoData, GetVisitorInfoErrors, GetVisitorInfoResponse, GetVisitorInfoResponses, GetVisitorJourneyData, GetVisitorJourneyErrors, GetVisitorJourneyResponse, GetVisitorJourneyResponses, GetVisitorsData, GetVisitorsErrors, GetVisitorSessionsData, GetVisitorSessionsError, GetVisitorSessionsErrors, GetVisitorSessionsQuery, GetVisitorSessionsResponse, GetVisitorSessionsResponse2, GetVisitorSessionsResponses, GetVisitorsResponse, GetVisitorsResponses, GetVisitorStatsData, GetVisitorStatsErrors, GetVisitorStatsResponse, GetVisitorStatsResponses, GetWebhookData, GetWebhookErrors, GetWebhookResponse, GetWebhookResponses, GitPushEvent, GitRefResponse, GitSourcePlan, GlobalConversationResponse, GlobalEventStatsResponse, GlobalMrrResponse, GlobalRecentEventResponse, GlobalRevenueSummaryResponse, GrantProjectAccessData, GrantProjectAccessErrors, GrantProjectAccessResponse, GrantProjectAccessResponses, GroupedPageMetric, GroupedPageMetricsQuery, GroupedPageMetricsResponse, HandleGitProviderOauthCallbackData, HandleGitProviderOauthCallbackErrors, HasAnalyticsEventsData, HasAnalyticsEventsErrors, HasAnalyticsEventsResponse, HasAnalyticsEventsResponse2, HasAnalyticsEventsResponses, HasErrorGroupsData, HasErrorGroupsErrors, HasErrorGroupsResponse, HasErrorGroupsResponse2, HasErrorGroupsResponses, HasEventsQuery, HasEventsResponse, HasMetricsQuery, HasMetricsResponse, HasPerformanceMetricsData, HasPerformanceMetricsError, HasPerformanceMetricsErrors, HasPerformanceMetricsResponse, HasPerformanceMetricsResponses, HealthCheckConfiguration, HealthCheckEntryResponse, HealthResponse, HealthStatus, HealthSummary, HeartbeatApiRequest, HeartbeatResponse, HierarchyLevel, HistogramSummary, HostnameChange, HostnamePreviewResponse, HourlyPageSessions, HourlyVisitsQuery, HttpChallengeDebugResponse, ImportCredentials, ImportExecutionStatus, ImportExternalServiceData, ImportExternalServiceErrors, ImportExternalServiceRequest, ImportExternalServiceResponse, ImportExternalServiceResponses, ImportOutcomeResponse, ImportPlan, ImportRowErrorResponse, ImportSelector, ImportSource, ImportSourceCapabilities, ImportSourceInfo, ImportStatusResponse, IncidentBucket, IncidentBucketedResponse, IncidentResponse, IncidentUpdateResponse, IncrRequest, IncrResponse, IngestLogsByPathData, IngestLogsByPathError, IngestLogsByPathErrors, IngestLogsByPathResponses, IngestLogsData, IngestLogsError, IngestLogsErrors, IngestLogsResponses, IngestMetricsByPathData, IngestMetricsByPathError, IngestMetricsByPathErrors, IngestMetricsByPathResponses, IngestMetricsData, IngestMetricsError, IngestMetricsErrors, IngestMetricsResponses, IngestSentryEnvelopeData, IngestSentryEnvelopeErrors, IngestSentryEnvelopeResponses, IngestSentryEventData, IngestSentryEventErrors, IngestSentryEventResponse, IngestSentryEventResponses, IngestTracesByPathData, IngestTracesByPathError, IngestTracesByPathErrors, IngestTracesByPathResponses, IngestTracesData, IngestTracesError, IngestTracesErrors, IngestTracesResponses, InitAuthResponse, InitSessionReplayData, InitSessionReplayError, InitSessionReplayErrors, InitSessionReplayResponse, InitSessionReplayResponses, Insight, InsightSeverity, InsightsResponse, InsightStatus, InspectDropArchiveData, InspectDropArchiveErrors, InspectDropArchiveResponse, InspectDropArchiveResponses, IntegrationResponse, IpAccessControlQuery, IpAccessControlResponse, JobLogsData, JobLogsErrors, JobLogsResponses, JobStatusData, JobStatusErrors, JobStatusResponse, JobStatusResponse2, JobStatusResponses, JobSummaryResponse, JoinTokenStatusResponse, JourneyEvent, JourneySession, KeysRequest, KeysResponse, KillJobBody, KillJobData, KillJobErrors, KillJobResponse, KillJobResponses, KnownAiAgentsResponse, KvDelData, KvDelErrors, KvDelResponse, KvDelResponses, KvDisableData, KvDisableErrors, KvDisableResponse, KvDisableResponses, KvEnableData, KvEnableErrors, KvEnableResponse, KvEnableResponses, KvExpireData, KvExpireErrors, KvExpireResponse, KvExpireResponses, KvGetData, KvGetErrors, KvGetResponse, KvGetResponses, KvIncrData, KvIncrErrors, KvIncrResponse, KvIncrResponses, KvKeysData, KvKeysErrors, KvKeysResponse, KvKeysResponses, KvSetData, KvSetErrors, KvSetResponse, KvSetResponses, KvStatusData, KvStatusErrors, KvStatusResponse, KvStatusResponse2, KvStatusResponses, KvTtlData, KvTtlErrors, KvTtlResponse, KvTtlResponses, KvUpdateData, KvUpdateErrors, KvUpdateResponse, KvUpdateResponses, LatestRunForSourceData, LatestRunForSourceErrors, LatestRunForSourceResponse, LatestRunForSourceResponses, LemonSqueezyConfig, LetsEncryptSettings, LineContext, LinkCustomDomainToCertificateData, LinkCustomDomainToCertificateErrors, LinkCustomDomainToCertificateResponse, LinkCustomDomainToCertificateResponses, LinkServiceRequest, LinkServiceToProjectData, LinkServiceToProjectErrors, LinkServiceToProjectResponse, LinkServiceToProjectResponses, ListAgentRunsData, ListAgentRunsErrors, ListAgentRunsResponse, ListAgentRunsResponses, ListAgentsData, ListAgentsErrors, ListAgentsResponse, ListAgentsResponse2, ListAgentsResponses, ListAiProvidersData, ListAiProvidersErrors, ListAiProvidersResponse, ListAiProvidersResponses, ListAlertRulesData, ListAlertRulesErrors, ListAlertRulesResponse, ListAlertRulesResponses, ListAlertsData, ListAlertsError, ListAlertsErrors, ListAlertsResponse, ListAlertsResponses, ListAllConversationsData, ListAllConversationsErrors, ListAllConversationsResponse, ListAllConversationsResponses, ListAllRunsData, ListAllRunsErrors, ListAllRunsResponse, ListAllRunsResponses, ListApiKeysData, ListApiKeysErrors, ListApiKeysQuery, ListApiKeysResponse, ListApiKeysResponses, ListAuditLogsData, ListAuditLogsErrors, ListAuditLogsQuery, ListAuditLogsResponse, ListAuditLogsResponses, ListAvailableContainersData, ListAvailableContainersErrors, ListAvailableContainersResponse, ListAvailableContainersResponses, ListBackupAlertsData, ListBackupAlertsError, ListBackupAlertsErrors, ListBackupAlertsResponse, ListBackupAlertsResponses, ListBackupChildrenData, ListBackupChildrenError, ListBackupChildrenErrors, ListBackupChildrenResponse, ListBackupChildrenResponses, ListBackupSchedulesData, ListBackupSchedulesError, ListBackupSchedulesErrors, ListBackupSchedulesResponse, ListBackupSchedulesResponses, ListBackupsForScheduleData, ListBackupsForScheduleErrors, ListBackupsForScheduleResponse, ListBackupsForScheduleResponses, ListBlobsQuery, ListBlobsResponse, ListCommitsByRepositoryIdData, ListCommitsByRepositoryIdErrors, ListCommitsByRepositoryIdResponse, ListCommitsByRepositoryIdResponses, ListConnectionsData, ListConnectionsErrors, ListConnectionsResponse, ListConnectionsResponses, ListContainersAtPathData, ListContainersAtPathErrors, ListContainersAtPathResponse, ListContainersAtPathResponses, ListContainersData, ListContainersErrors, ListContainersResponse, ListContainersResponses, ListConversationsData, ListConversationsErrors, ListConversationsResponse, ListConversationsResponses, ListCustomDomainsForProjectData, ListCustomDomainsForProjectErrors, ListCustomDomainsForProjectResponse, ListCustomDomainsForProjectResponses, ListCustomDomainsResponse, ListDashboardsData, ListDashboardsError, ListDashboardsErrors, ListDashboardsResponse, ListDashboardsResponses, ListDeliveriesData, ListDeliveriesErrors, ListDeliveriesResponse, ListDeliveriesResponses, ListDeploymentContainerLogsData, ListDeploymentContainerLogsErrors, ListDeploymentContainerLogsResponse, ListDeploymentContainerLogsResponses, ListDeploymentTokensData, ListDeploymentTokensErrors, ListDeploymentTokensQuery, ListDeploymentTokensResponse, ListDeploymentTokensResponses, ListDnsProvidersData, ListDnsProvidersErrors, ListDnsProvidersResponse, ListDnsProvidersResponses, ListDomainsData, ListDomainsErrors, ListDomainsResponse, ListDomainsResponse2, ListDomainsResponses, ListDsnsData, ListDsnsErrors, ListDsnsResponse, ListDsnsResponses, ListEmailDomainsData, ListEmailDomainsErrors, ListEmailDomainsResponse, ListEmailDomainsResponses, ListEmailProvidersData, ListEmailProvidersErrors, ListEmailProvidersResponse, ListEmailProvidersResponses, ListEmailsData, ListEmailsErrors, ListEmailsResponse, ListEmailsResponses, ListEnrollmentTokensData, ListEnrollmentTokensErrors, ListEnrollmentTokensResponse, ListEnrollmentTokensResponses, ListEntitiesData, ListEntitiesErrors, ListEntitiesQuery, ListEntitiesResponse, ListEntitiesResponses, ListErrorEventsData, ListErrorEventsErrors, ListErrorEventsQuery, ListErrorEventsResponse, ListErrorEventsResponses, ListErrorGroupsData, ListErrorGroupsErrors, ListErrorGroupsQuery, ListErrorGroupsResponse, ListErrorGroupsResponses, ListEventsData, ListEventsResponse, ListEventsResponses, ListEventTypesData, ListEventTypesResponse, ListEventTypesResponses, ListExternalImagesData, ListExternalImagesErrors, ListExternalImagesResponse, ListExternalImagesResponses, ListExternalPluginsData, ListExternalPluginsErrors, ListExternalPluginsResponse, ListExternalPluginsResponses, ListExternalServiceBackupsData, ListExternalServiceBackupsError, ListExternalServiceBackupsErrors, ListExternalServiceBackupsResponse, ListExternalServiceBackupsResponses, ListFlagsData, ListFlagsErrors, ListFlagsResponse, ListFlagsResponses, ListFunnelsData, ListFunnelsErrors, ListFunnelsResponse, ListFunnelsResponses, ListGitProvidersData, ListGitProvidersErrors, ListGitProvidersResponse, ListGitProvidersResponses, ListGlobalMcpsData, ListGlobalMcpsErrors, ListGlobalMcpsResponse, ListGlobalMcpsResponses, ListGlobalSkillsData, ListGlobalSkillsErrors, ListGlobalSkillsResponse, ListGlobalSkillsResponses, ListIncidentsData, ListIncidentsErrors, ListIncidentsResponses, ListInsightsData, ListInsightsError, ListInsightsErrors, ListInsightsResponse, ListInsightsResponses, ListIpAccessControlData, ListIpAccessControlError, ListIpAccessControlErrors, ListIpAccessControlResponse, ListIpAccessControlResponses, ListJobsData, ListJobsErrors, ListJobsResponse, ListJobsResponse2, ListJobsResponses, ListKnownAiAgentsData, ListKnownAiAgentsError, ListKnownAiAgentsErrors, ListKnownAiAgentsResponse, ListKnownAiAgentsResponses, ListManagedDomainsData, ListManagedDomainsErrors, ListManagedDomainsResponse, ListManagedDomainsResponses, ListMcpsData, ListMcpsErrors, ListMcpsResponse, ListMcpsResponse2, ListMcpsResponses, ListMetricLabelKeysData, ListMetricLabelKeysError, ListMetricLabelKeysErrors, ListMetricLabelKeysResponse, ListMetricLabelKeysResponses, ListMetricLabelValuesData, ListMetricLabelValuesError, ListMetricLabelValuesErrors, ListMetricLabelValuesResponse, ListMetricLabelValuesResponses, ListMetricNamesData, ListMetricNamesError, ListMetricNamesErrors, ListMetricNamesResponse, ListMetricNamesResponses, ListModelsData, ListModelsError, ListModelsErrors, ListModelsResponse, ListModelsResponses, ListMonitorsData, ListMonitorsErrors, ListMonitorsResponse, ListMonitorsResponses, ListNotificationProvidersData, ListNotificationProvidersErrors, ListNotificationProvidersResponse, ListNotificationProvidersResponses, ListOidcProvidersData, ListOidcProvidersResponse, ListOidcProvidersResponses, ListOidcProviderUsersData, ListOidcProviderUsersErrors, ListOidcProviderUsersResponse, ListOidcProviderUsersResponses, ListOidcRoleMappingsData, ListOidcRoleMappingsResponse, ListOidcRoleMappingsResponses, ListOnDemandCertsData, ListOnDemandCertsErrors, ListOnDemandCertsResponse, ListOnDemandCertsResponse2, ListOnDemandCertsResponses, ListOrdersData, ListOrdersErrors, ListOrdersResponse, ListOrdersResponse2, ListOrdersResponses, ListPeersData, ListPeersErrors, ListPeersResponse, ListPeersResponses, ListPendingActionsData, ListPendingActionsErrors, ListPendingActionsResponse, ListPendingActionsResponses, ListPgUpgradesData, ListPgUpgradesErrors, ListPgUpgradesResponse, ListPgUpgradesResponses, ListPresetsData, ListPresetsErrors, ListPresetsResponse, ListPresetsResponse2, ListPresetsResponses, ListProjectAccessData, ListProjectAccessErrors, ListProjectAccessResponse, ListProjectAccessResponses, ListProjectAlarmsData, ListProjectAlarmsErrors, ListProjectAlarmsResponse, ListProjectAlarmsResponses, ListProjectScansData, ListProjectScansError, ListProjectScansErrors, ListProjectScansResponse, ListProjectScansResponses, ListProjectSecretsData, ListProjectSecretsErrors, ListProjectSecretsResponse, ListProjectSecretsResponses, ListProjectServicesData, ListProjectServicesErrors, ListProjectServicesResponse, ListProjectServicesResponses, ListProjectTemplatesData, ListProjectTemplatesErrors, ListProjectTemplatesResponse, ListProjectTemplatesResponses, ListProjectTemplateTagsData, ListProjectTemplateTagsErrors, ListProjectTemplateTagsResponse, ListProjectTemplateTagsResponses, ListProviderKeysData, ListProviderKeysError, ListProviderKeysErrors, ListProviderKeysResponse, ListProviderKeysResponses, ListProviderZonesData, ListProviderZonesErrors, ListProviderZonesResponse, ListProviderZonesResponses, ListPublicProvidersData, ListPublicProvidersResponse, ListPublicProvidersResponses, ListReleaseFilesData, ListReleaseFilesErrors, ListReleaseFilesResponse, ListReleaseFilesResponses, ListReleasesData, ListReleasesErrors, ListReleasesResponse, ListReleasesResponses, ListRemoteExternalImagesData, ListRemoteExternalImagesErrors, ListRemoteExternalImagesResponse, ListRemoteExternalImagesResponses, ListRepositoriesByConnectionData, ListRepositoriesByConnectionErrors, ListRepositoriesByConnectionResponse, ListRepositoriesByConnectionResponses, ListRepositoriesByProviderData, ListRepositoriesByProviderErrors, ListRepositoriesByProviderResponse, ListRepositoriesByProviderResponses, ListRestoreRunsForServiceData, ListRestoreRunsForServiceResponse, ListRestoreRunsForServiceResponses, ListRootContainersData, ListRootContainersErrors, ListRootContainersResponse, ListRootContainersResponses, ListRoutesData, ListRoutesErrors, ListRoutesResponse, ListRoutesResponses, ListRunsResponse, ListS3SourcesData, ListS3SourcesError, ListS3SourcesErrors, ListS3SourcesResponse, ListS3SourcesResponses, ListSandboxesData, ListSandboxesResponse, ListSandboxesResponse2, ListSandboxesResponses, ListScansQuery, ListScheduleRunJobsData, ListScheduleRunJobsError, ListScheduleRunJobsErrors, ListScheduleRunJobsResponse, ListScheduleRunJobsResponses, ListScheduleRunsData, ListScheduleRunsError, ListScheduleRunsErrors, ListScheduleRunsResponse, ListScheduleRunsResponses, ListScheduleServicesData, ListScheduleServicesError, ListScheduleServicesErrors, ListScheduleServicesResponse, ListScheduleServicesResponses, ListSecretsData, ListSecretsErrors, ListSecretsResponse, ListSecretsResponse2, ListSecretsResponses, ListServiceHealthStatusesData, ListServiceHealthStatusesErrors, ListServiceHealthStatusesResponse, ListServiceHealthStatusesResponses, ListServiceProjectsData, ListServiceProjectsErrors, ListServiceProjectsResponse, ListServiceProjectsResponses, ListServiceSchedulesData, ListServiceSchedulesError, ListServiceSchedulesErrors, ListServiceSchedulesResponse, ListServiceSchedulesResponses, ListServicesData, ListServicesErrors, ListServicesResponse, ListServicesResponses, ListSkillsData, ListSkillsErrors, ListSkillsResponse, ListSkillsResponse2, ListSkillsResponses, ListSourceBackupsData, ListSourceBackupsError, ListSourceBackupsErrors, ListSourceBackupsResponse, ListSourceBackupsResponses, ListSourceFilesData, ListSourceFilesErrors, ListSourceFilesResponse, ListSourceFilesResponses, ListSourceMapsData, ListSourceMapsErrors, ListSourceMapsResponse, ListSourceMapsResponses, ListSourcesData, ListSourcesErrors, ListSourcesResponse, ListSourcesResponses, ListStaticBundlesData, ListStaticBundlesErrors, ListStaticBundlesResponse, ListStaticBundlesResponses, ListSyncedRepositoriesData, ListSyncedRepositoriesErrors, ListSyncedRepositoriesResponse, ListSyncedRepositoriesResponses, ListTagsResponse, ListTeamMembersData, ListTeamMembersErrors, ListTeamMembersResponse, ListTeamMembersResponses, ListTeamProjectsData, ListTeamProjectsErrors, ListTeamProjectsResponse, ListTeamProjectsResponses, ListTeamsData, ListTeamsErrors, ListTeamsResponse, ListTeamsResponses, ListTemplatesQuery, ListTemplatesResponse, ListUsersData, ListUsersErrors, ListUsersResponse, ListUsersResponses, ListVulnerabilitiesQuery, ListWebhooksData, ListWebhooksErrors, ListWebhooksResponse, ListWebhooksResponses, LiveVisitorInfo, LiveVisitorsListResponse, LocationCount, LocationGranularity, LocationInfo, LoginData, LoginErrors, LoginRequest, LoginResponse, LoginResponses, LogLevel, LogoutData, LogoutErrors, LogoutResponses, LogRecord, LogSearchLine, LogSeverity, LogSource, LogsQuery, LogsResponse, LogStream, LookupDnsARecordsData, LookupDnsARecordsError, LookupDnsARecordsErrors, LookupDnsARecordsResponse, LookupDnsARecordsResponses, ManagedDomainResponse, ManualAction, ManualActionTiming, McpDefinitionResponse, MessageContent, MessagePart, MessageResponse, MeteredMode, MetricAggregation, MetricBucket, MetricDataPoint, MetricsOverTimeResponse, MetricsQuery, MetricsRangeQuery, MetricsStatusResponse, MetricsStoreKind, MetricsSummaryResponse, MetricType, MfaRequiredResponse, MfaSetupResponse, MfaVerificationRequest, MigrationStep, MigrationSummary, MintEnrollmentTokenData, MintEnrollmentTokenErrors, MintEnrollmentTokenRequest, MintEnrollmentTokenResponse, MintEnrollmentTokenResponse2, MintEnrollmentTokenResponses, MiscResult, MkdirBody, MkdirData, MkdirErrors, MkdirResponse, MkdirResponses, ModelInfo, ModelListResponse, ModelPricing, ModelUsage, MonitoringSettings, MonitoringSettingsMasked, MonitorResponse, MonitorStatus, MrrBucketResponse, MultiNodeSettings, MultiNodeSettingsMasked, MxResult, NavEntry, NavSection, NetworkConfiguration, NetworkMode, NixpacksPresetConfig, NixpacksProvider, NodeContainerListResponse, NodeContainerResponse, NodeCostInfo, NodeHeartbeatData, NodeHeartbeatErrors, NodeHeartbeatResponse, NodeHeartbeatResponses, NodeInfoResponse, NodeListResponse, NodeMetricsGetRangeData, NodeMetricsGetRangeErrors, NodeMetricsGetRangeResponse, NodeMetricsGetRangeResponses, NotificationPreferencesResponse, NotificationProviderResponse, ObservabilityCompressionSettings, ObservabilityEvent, ObservabilityFullEventData, ObservabilityFullEventError, ObservabilityFullEventErrors, ObservabilityFullEventResponse, ObservabilityFullEventResponses, ObservabilityListEventsData, ObservabilityListEventsError, ObservabilityListEventsErrors, ObservabilityListEventsResponse, ObservabilityListEventsResponses, ObservabilityRetentionSettings, OidcCallbackData, OidcProviderResponse, OidcProvidersListResponse, OidcProviderSummary, OidcProviderUserResponse, OidcRoleMappingResponse, OidcTestConnectionResponse, OnDemandCertAttemptResponse, OnDemandCertRow, OnDemandTlsSettings, OpenAiError, OpenAiErrorResponse, OperatingSystemCount, OperationResultResponse, OperationResultsResponse, OtelDashboardResponse, OtelDashboardsResponse, OtelMetricAlertRuleResponse, OtelMetricAlertsResponse, OtelMetricLabelKeysResponse, OtelMetricLabelValuesResponse, OtelMetricNamesResponse, OtelMetricsResponse, OutlierAlgorithm, OutlierParams, OverprovisioningAssessment, OverprovisioningVerdict, PageActivityBucket, PageCountryStats, PageFlowEntry, PageFlowQuery, PageFlowResponse, PageHourlySessionsQuery, PageHourlySessionsResponse, PagePathDetailQuery, PagePathDetailResponse, PagePathInfo, PagePathSparkline, PagePathSparklinePoint, PagePathsQuery, PagePathsResponse, PagePathsSparklineQuery, PagePathsSparklineResponse, PagePathVisitorsQuery, PagePathVisitorsResponse, PageReferrerStats, PagesComparisonResponse, PageSessionComparison, PageSessionStats, PageSessionStatsQuery, PageTransition, PageVisit, PageVisitorSession, PaginatedEmailsResponse, PaginatedEntitiesResponse, PaginatedErrorEventsResponse, PaginatedErrorGroupsResponse, PaginatedEventsResponse, PaginatedExternalImagesResponse, PaginatedProjectList, PaginatedStaticBundlesResponse, Pagination, PaginationMeta, PaginationParams, PasswordProtectionConfig, PatchAdminGateData, PatchAdminGateErrors, PatchAdminGateResponse, PatchAdminGateResponses, PatchPreviewGatewaySettingsData, PatchPreviewGatewaySettingsResponse, PatchPreviewGatewaySettingsResponses, PatchSettingsRequest, PathVisitors, PathVisitorsAnalyticsQuery, PathVisitorsResponse, PauseDeploymentData, PauseDeploymentErrors, PauseDeploymentResponse, PauseDeploymentResponses, PauseSandboxData, PauseSandboxErrors, PauseSandboxResponse, PauseSandboxResponses, PeerEntry, PeerListResponse, PendingActionResponse, PerformanceMetricsQuery, PerformanceMetricsResponse, PermissionInfo, PgUpgradeLogResponse, PgUpgradeResponse, PipelineStats, PipelineStatsResponse, PlanComplexity, PlanMetadata, PlanRestoreData, PlanRestoreError, PlanRestoreErrors, PlanRestoreResponse, PlanRestoreResponses, PlanSourceBackup, PlanTarget, PlatformInfo, PluginManifest, PortMapping, PostDnsAckData, PostDnsAckErrors, PostDnsAckResponse, PostDnsAckResponses, PostgresWalHealth, PresetConfigSchema, PresetInfo, PresetResponse, PreviewAlertData, PreviewAlertError, PreviewAlertErrors, PreviewAlertResponse, PreviewAlertResponses, PreviewFunnelMetricsData, PreviewFunnelMetricsErrors, PreviewFunnelMetricsResponse, PreviewFunnelMetricsResponses, PreviewGatewaySettings, PreviewGatewaySettingsMasked, PreviewGatewaySettingsResponse, PreviewHostnameModeData, PreviewHostnameModeErrors, PreviewHostnameModeResponse, PreviewHostnameModeResponses, PreviewShareLinkBody, PreviewShareLinkResponse, PricingResponse, ProblemDetails, ProjectAccessResponse, ProjectConfiguration, ProjectDashboardAnalytics, ProjectDsnResponse, ProjectHealthSummary, ProjectInfo, ProjectMonitorHealth, ProjectPresetResponse, ProjectQuery, ProjectRef, ProjectResponse, ProjectSecretEnvironmentInfo, ProjectSecretResponse, ProjectServiceInfo, ProjectsHealthResponse, ProjectsMonitorHealthResponse, ProjectStatisticsResponse, ProjectStatsBreakdown, ProjectType, ProjectUsageInfoResponse, PromoteClusterMemberData, PromoteClusterMemberErrors, PromoteClusterMemberResponses, PromoteDeploymentData, PromoteDeploymentErrors, PromoteDeploymentRequest, PromoteDeploymentResponse, PromoteDeploymentResponses, PropertyBreakdownItem, PropertyBreakdownQuery, PropertyBreakdownResponse, PropertyColumn, PropertyTimelineItem, PropertyTimelineQuery, PropertyTimelineResponse, Protocol, ProviderCatalogDto, ProviderCatalogResponse, ProviderConfig, ProviderConfigMasked, ProviderDeletionCheckResponse, ProviderDescriptor, ProviderKeyResponse, ProviderMetadata, ProviderResponse, ProviderUsage, ProvisionDomainData, ProvisionDomainErrors, ProvisionDomainResponse, ProvisionDomainResponses, ProvisionResponse, ProxyLogResponse, ProxyLogsPaginatedResponse, PublicHostnameStrategy, PublicPresetResponse, PublicRepositoryInfo, PurgeLogsRequest, PurgeProjectLogsData, PurgeProjectLogsError, PurgeProjectLogsErrors, PurgeProjectLogsResponses, PushedExternalImageResponse, PushExternalImageData, PushExternalImageErrors, PushExternalImageResponse, PushExternalImageResponses, PushImageRequest, QueryDataData, QueryDataErrors, QueryDataRequest, QueryDataResponse, QueryDataResponse2, QueryDataResponses, QueryGenaiTracesData, QueryGenaiTracesError, QueryGenaiTracesErrors, QueryGenaiTracesResponse, QueryGenaiTracesResponses, QueryLogsData, QueryLogsError, QueryLogsErrors, QueryLogsResponse, QueryLogsResponses, QueryMetricsData, QueryMetricsError, QueryMetricsErrors, QueryMetricsResponse, QueryMetricsResponses, QueryTracesData, QueryTracesError, QueryTracesErrors, QueryTracesResponse, QueryTracesResponses, QueryTraceSummariesData, QueryTraceSummariesError, QueryTraceSummariesErrors, QueryTraceSummariesResponse, QueryTraceSummariesResponses, QuotaResponse, RateLimitConfig, RateLimitSettings, ReachabilityStatus, ReadFileData, ReadFileErrors, ReadFileResponse, ReadFileResponse2, ReadFileResponses, ReAnalyzeData, ReAnalyzeErrors, ReAnalyzeResponses, RecentActivityQuery, RecentActivityResponse, RecentEventResponse, RecentQueryParams, RecordConsoleEventData, RecordConsoleEventErrors, RecordConsoleEventResponses, RecordEventMetricsData, RecordEventMetricsErrors, RecordEventMetricsResponse, RecordEventMetricsResponses, RecordExposureRequest, RecordExposureResponse, RecordFlagExposureData, RecordFlagExposureErrors, RecordFlagExposureResponse, RecordFlagExposureResponses, RecordListResponse, RecordSpeedMetricsData, RecordSpeedMetricsError, RecordSpeedMetricsErrors, RecordSpeedMetricsResponse, RecordSpeedMetricsResponses, RecoveryTarget, ReferrerCount, ReferrersAnalyticsQuery, RefreshRouteTableData, RefreshRouteTableErrors, RefreshRouteTableResponse, RefreshRouteTableResponses, RegenerateDsnData, RegenerateDsnErrors, RegenerateDsnRequest, RegenerateDsnResponse, RegenerateDsnResponses, RegisterExternalImageData, RegisterExternalImageErrors, RegisterExternalImageResponse, RegisterExternalImageResponses, RegisterImageRequest, RegisterNodeApiRequest, RegisterNodeData, RegisterNodeErrors, RegisterNodeResponse, RegisterNodeResponse2, RegisterNodeResponses, RegisterRequest, ReinstallGitlabWebhookData, ReinstallGitlabWebhookErrors, ReinstallGitlabWebhookResponse, ReinstallGitlabWebhookResponses, ReinstallWebhookResponse, RejectPendingActionData, RejectPendingActionErrors, RejectPendingActionResponse, RejectPendingActionResponses, ReleaseListResponse, ReloadPluginsData, ReloadPluginsErrors, ReloadPluginsResponse, ReloadPluginsResponses, ReloadResponse, RemoteDeploymentResponse, RemoveClusterMemberData, RemoveClusterMemberErrors, RemoveClusterMemberResponse, RemoveClusterMemberResponses, RemoveManagedDomainData, RemoveManagedDomainErrors, RemoveManagedDomainResponse, RemoveManagedDomainResponses, RemoveNodeResponse, RemoveRoleData, RemoveRoleErrors, RemoveRoleResponse, RemoveRoleResponses, RemoveTeamMemberData, RemoveTeamMemberErrors, RemoveTeamMemberResponse, RemoveTeamMemberResponses, RenameConversationData, RenameConversationErrors, RenameConversationRequest, RenameConversationResponse, RenameConversationResponses, RenewDomainData, RenewDomainErrors, RenewDomainResponse, RenewDomainResponses, RepositoryListQuery, RepositoryListResponse, RepositoryPresetResponse, RepositoryResponse, RepositorySyncStartedResponse, RequestPasswordResetData, RequestPasswordResetErrors, RequestPasswordResetResponse, RequestPasswordResetResponses, RequestRow, RequiredPasswordChangeRequest, RequiredPasswordChangeResponse, ResetPasswordData, ResetPasswordErrors, ResetPasswordRequest, ResetPasswordResponse, ResetPasswordResponses, ResetPgStatStatementsRequest, ResetPgStatStatementsResponse, ResizeSandboxBody, ResizeSandboxData, ResizeSandboxErrors, ResizeSandboxResponse, ResizeSandboxResponses, ResolveAlarmData, ResolveAlarmErrors, ResolveAlarmResponses, ResolvedEnvVarResponse, ResolvedEnvVarSource, ResourceCounts, ResourceFootprint, ResourceInfo, ResourceLimitApplyResult, ResourceLimits, ResourceLimitsResponse, ResourceLimitsUpdateResponse, ResourcesBody, RestartContainerData, RestartContainerErrors, RestartContainerResponse, RestartContainerResponses, RestartPreviewGatewayData, RestartPreviewGatewayResponse, RestartPreviewGatewayResponses, RestartSandboxData, RestartSandboxErrors, RestartSandboxResponse, RestartSandboxResponses, RestoreCapabilities, RestoreCapabilitiesResponse, RestoreFlagData, RestoreFlagErrors, RestoreFlagResponse, RestoreFlagResponses, RestorePlan, RestoreRequestMode, RestoreRunView, RestoreUserData, RestoreUserErrors, RestoreUserResponse, RestoreUserResponses, ResumeDeploymentData, ResumeDeploymentErrors, ResumeDeploymentResponse, ResumeDeploymentResponses, ResumeSandboxData, ResumeSandboxErrors, ResumeSandboxResponse, ResumeSandboxResponses, RetentionCleanupFailure, RetentionCleanupReport, RetryClusterData, RetryClusterErrors, RetryClusterRequest, RetryClusterResponse, RetryClusterResponses, RetryDeliveryData, RetryDeliveryErrors, RetryDeliveryResponse, RetryDeliveryResponses, RetryPgUpgradeData, RetryPgUpgradeErrors, RetryPgUpgradeResponse, RetryPgUpgradeResponses, RetryRunData, RetryRunErrors, RetryRunResponse, RetryRunResponses, RevealGlobalMcpConfigData, RevealGlobalMcpConfigErrors, RevealGlobalMcpConfigResponse, RevealGlobalMcpConfigResponses, RevealMcpConfigData, RevealMcpConfigErrors, RevealMcpConfigResponse, RevealMcpConfigResponses, RevealNotificationProviderConfigData, RevealNotificationProviderConfigErrors, RevealNotificationProviderConfigResponse, RevealNotificationProviderConfigResponses, RevealServiceParameterData, RevealServiceParameterErrors, RevealServiceParameterResponse, RevealServiceParameterResponses, RevenueCreateIntegrationData, RevenueCreateIntegrationErrors, RevenueCreateIntegrationResponse, RevenueCreateIntegrationResponses, RevenueDeleteIntegrationData, RevenueDeleteIntegrationResponse, RevenueDeleteIntegrationResponses, RevenueGlobalEventsData, RevenueGlobalEventsResponse, RevenueGlobalEventsResponses, RevenueImportInvoicesCsvData, RevenueImportInvoicesCsvErrors, RevenueImportInvoicesCsvResponse, RevenueImportInvoicesCsvResponses, RevenueImportSubscriptionsCsvData, RevenueImportSubscriptionsCsvErrors, RevenueImportSubscriptionsCsvResponse, RevenueImportSubscriptionsCsvResponses, RevenueListIntegrationsData, RevenueListIntegrationsResponse, RevenueListIntegrationsResponses, RevenueListProvidersData, RevenueListProvidersResponse, RevenueListProvidersResponses, RevenueMetricsCustomersData, RevenueMetricsCustomersResponse, RevenueMetricsCustomersResponses, RevenueMetricsGlobalMrrData, RevenueMetricsGlobalMrrResponse, RevenueMetricsGlobalMrrResponses, RevenueMetricsGlobalSummaryData, RevenueMetricsGlobalSummaryResponse, RevenueMetricsGlobalSummaryResponses, RevenueMetricsMrrData, RevenueMetricsMrrResponse, RevenueMetricsMrrResponses, RevenueMetricsSummaryData, RevenueMetricsSummaryResponse, RevenueMetricsSummaryResponses, RevenueRecentEventsData, RevenueRecentEventsResponse, RevenueRecentEventsResponses, RevenueRotateTokenData, RevenueRotateTokenResponse, RevenueRotateTokenResponses, RevenueRow, RevenueUpdateConfigData, RevenueUpdateConfigErrors, RevenueUpdateConfigResponse, RevenueUpdateConfigResponses, RevenueUpdateSecretData, RevenueUpdateSecretErrors, RevenueUpdateSecretResponse, RevenueUpdateSecretResponses, RevokeDsnData, RevokeDsnErrors, RevokeDsnResponse, RevokeDsnResponses, RevokeEnrollmentTokenData, RevokeEnrollmentTokenErrors, RevokeEnrollmentTokenResponse, RevokeEnrollmentTokenResponses, RevokeJoinTokenData, RevokeJoinTokenErrors, RevokeJoinTokenResponse, RevokeJoinTokenResponses, RevokeProjectAccessData, RevokeProjectAccessErrors, RevokeProjectAccessResponse, RevokeProjectAccessResponses, RiskLevel, RoleInfo, RollbackPgUpgradeData, RollbackPgUpgradeErrors, RollbackPgUpgradeResponse, RollbackPgUpgradeResponses, RollbackToDeploymentData, RollbackToDeploymentErrors, RollbackToDeploymentResponse, RollbackToDeploymentResponses, RootfsCacheEntry, RootfsGcData, RootfsGcReport, RootfsGcResponses, RootfsReport, RootfsReportData, RootfsReportResponses, RootfsVmEntry, RotateApiKeyData, RotateApiKeyErrors, RotateApiKeyResponse, RotateApiKeyResponses, RotateDeploymentTokenData, RotateDeploymentTokenErrors, RotateDeploymentTokenResponse, RotateDeploymentTokenResponses, RouteRefreshResponse, RouteResponse, RouteRole, RouteUser, RouteUserWithRoles, RunBackupForSourceData, RunBackupForSourceError, RunBackupForSourceErrors, RunBackupForSourceResponse, RunBackupForSourceResponses, RunBackupRequest, RunConnectionHealthCheckData, RunConnectionHealthCheckErrors, RunConnectionHealthCheckResponse, RunConnectionHealthCheckResponses, RunExternalServiceBackupData, RunExternalServiceBackupError, RunExternalServiceBackupErrors, RunExternalServiceBackupRequest, RunExternalServiceBackupResponse, RunExternalServiceBackupResponses, RunScheduleNowData, RunScheduleNowError, RunScheduleNowErrors, RunScheduleNowResponse, RunScheduleNowResponses, S3ConnectionTestResponse, S3CredentialsResponse, S3SourceResponse, S3SourceResponseWritable, SandboxCreatePreviewLinkData, SandboxCreatePreviewLinkErrors, SandboxCreatePreviewLinkResponse, SandboxCreatePreviewLinkResponses, SandboxDomainResponse, SandboxEvent, SandboxEventsResponse, SandboxInner, SandboxResponse, SandboxRoute, SandboxStatusResponse, SaveAgentTokenData, SaveAgentTokenErrors, SaveAgentTokenRequest, SaveAgentTokenResponse, SaveAgentTokenResponse2, SaveAgentTokenResponses, SaveAiProviderCredentialData, SaveAiProviderCredentialErrors, SaveAiProviderCredentialResponse, SaveAiProviderCredentialResponses, SaveCredentialRequest, SaveCredentialResponse, ScalewayCredentialsRequest, ScanResponse, ScheduleRunEntry, ScheduleRunJobEntry, ScheduleRunListResponse, ScheduleRunResponse, ScheduleRunSummary, ScheduleRunSummaryList, ScreenshotSettings, SearchLogsData, SearchLogsError, SearchLogsErrors, SearchLogsRequest, SearchLogsResponse, SearchLogsResponse2, SearchLogsResponses, SearchMode, Seasonality, SecretResponse, SecurityConfig, SecurityHeadersConfig, SecurityHeadersSettings, SendEmailData, SendEmailErrors, SendEmailRequestBody, SendEmailResponse, SendEmailResponseBody, SendEmailResponses, SendMessageRequest, SensitiveConfigValueResponse, SensitiveMcpConfigValueResponse, SensitiveValueResponse, SentryChunkUploadResponse, SentryCreateReleaseRequest, SentryEventRequest, SentryEventResponse, SentryReleaseFileResponse, SentryReleaseProjectRef, SentryReleaseResponse, SeriesStateEntry, ServiceAccessInfo, ServiceAction, ServiceAlertRuleResponse, ServiceBackupEntryResponse, ServiceBackupListResponse, ServiceCreateAlertRuleRequest, ServiceHealthResponse, ServiceHealthStatusBatchResponse, ServiceHealthStatusEntryResponse, ServiceMemberInfo, ServiceParameter, ServicePlan, ServiceResourceLimits, ServiceRuntimeReport, ServiceStatsReport, ServiceTypeInfo, ServiceTypeRoute, ServiceUpdateAlertRuleRequest, SesCredentialsRequest, SessionDetails, SessionDetailsQuery, SessionEvent, SessionEventDto, SessionEventsQuery, SessionEventsResponse, SessionLogsQuery, SessionLogsResponse, SessionReplayEventsRequest, SessionReplayInfoDto, SessionReplayInitRequest, SessionReplayInitResponse, SessionReplayWithEventsDto, SessionReplayWithVisitorDto, SessionRequestLog, SessionSummary, SetDefaultS3SourceData, SetDefaultS3SourceError, SetDefaultS3SourceErrors, SetDefaultS3SourceResponse, SetDefaultS3SourceResponses, SetFlagEnvironmentData, SetFlagEnvironmentErrors, SetFlagEnvironmentRequest, SetFlagEnvironmentResponse, SetFlagEnvironmentResponses, SetPreviewPasswordBody, SetPreviewPasswordData, SetPreviewPasswordErrors, SetPreviewPasswordResponse, SetPreviewPasswordResponse2, SetPreviewPasswordResponses, SetRequest, SetResponse, SettingsUpdateResponse, SetupDnsChallengeData, SetupDnsChallengeErrors, SetupDnsChallengeRequest, SetupDnsChallengeResponse, SetupDnsChallengeResponse2, SetupDnsChallengeResponses, SetupDnsData, SetupDnsErrors, SetupDnsRequest, SetupDnsResponse, SetupDnsResponse2, SetupDnsResponses, SetupEmailTrackingData, SetupEmailTrackingErrors, SetupEmailTrackingResponse, SetupEmailTrackingResponses, SetupMfaData, SetupMfaErrors, SetupMfaResponse, SetupMfaResponses, SiblingRef, SkillDefinitionResponse, SlackConfig, SleepEnvironmentData, SleepEnvironmentErrors, SleepEnvironmentResponse, SleepEnvironmentResponses, SlowQueriesResponse, SlowQueryRow, SmartFilter, SmokeTestAgentData, SmokeTestAgentErrors, SmokeTestAgentResponse, SmokeTestAgentResponses, SmokeTestResponse, SmtpCredentialsRequest, SmtpEncryptionRoute, SmtpResult, SourceArchiveUpload, SourceBackupEntry, SourceBackupIndexResponse, SourceBody, SourceFileListResponse, SourceFileResponse, SourceMapListResponse, SourceMapResponse, SourceSandboxData, SourceSandboxErrors, SourceSandboxResponse, SourceSandboxResponses, SourceType, SpanEvent, SpanKind, SpanRecord, SpanRow, SpanStatusCode, SpeedMetricsPayload, SpeedSegmentFilters, StaleSlot, StartAnalysisData, StartAnalysisErrors, StartAnalysisRequest, StartAnalysisResponse, StartAnalysisResponses, StartContainerData, StartContainerErrors, StartContainerResponse, StartContainerResponses, StartFixData, StartFixErrors, StartFixResponses, StartGitProviderOauthData, StartGitProviderOauthErrors, StartOidcLoginBySlugData, StartOidcLoginBySlugErrors, StartPgUpgradeData, StartPgUpgradeErrors, StartPgUpgradeRequest, StartPgUpgradeResponse, StartPgUpgradeResponses, StartRestoreData, StartRestoreError, StartRestoreErrors, StartRestoreRequest, StartRestoreResponse, StartRestoreResponses, StartServiceData, StartServiceErrors, StartServiceResponse, StartServiceResponses, StaticBundleResponse, StaticParams, StaticPresetConfig, StatPathData, StatPathErrors, StatPathResponse, StatPathResponses, StatResponse, StatsFilters, StatusBucket, StatusBucketedResponse, StatusCodeCount, StatusCodesQuery, StatusPageOverview, StepConversionResponse, StepResourceType, StepResult, StepUpResponse, StopContainerData, StopContainerErrors, StopContainerResponse, StopContainerResponses, StopSandboxData, StopSandboxErrors, StopSandboxResponse, StopSandboxResponses, StopSequence, StopServiceData, StopServiceErrors, StopServiceResponse, StopServiceResponses, StorageQuota, StreamContainerMetricsData, StreamContainerMetricsErrors, StreamContainerMetricsResponses, StreamEventsData, StreamEventsErrors, StreamEventsResponses, StreamRunEventsData, StreamRunEventsErrors, StreamRunEventsResponses, StripeConfig, SyncedRepositoryListQuery, SyncRepositoriesData, SyncRepositoriesErrors, SyncRepositoriesResponse, SyncRepositoriesResponses, SyntaxResult, TagInfo, TagListResponse, TailDeploymentJobLogsData, TailDeploymentJobLogsErrors, TailLogsData, TailLogsError, TailLogsErrors, TailLogsRequest, TailLogsResponses, TargetRecommendation, TeamListResponse, TeamMemberResponse, TeamResponse, TeamRole, TeardownDeploymentData, TeardownDeploymentErrors, TeardownDeploymentResponse, TeardownDeploymentResponses, TeardownEnvironmentData, TeardownEnvironmentErrors, TeardownEnvironmentResponse, TeardownEnvironmentResponses, TemplateResponse, TestEmailRequest, TestEmailResponse, TestNotificationProviderData, TestNotificationProviderErrors, TestNotificationProviderResponse, TestNotificationProviderResponses, TestOidcProviderData, TestOidcProviderResponse, TestOidcProviderResponses, TestProviderConnectionData, TestProviderConnectionErrors, TestProviderConnectionResponse, TestProviderConnectionResponses, TestProviderData, TestProviderErrors, TestProviderKeyByIdData, TestProviderKeyByIdError, TestProviderKeyByIdErrors, TestProviderKeyByIdResponse, TestProviderKeyByIdResponses, TestProviderKeyInlineData, TestProviderKeyInlineError, TestProviderKeyInlineErrors, TestProviderKeyInlineResponse, TestProviderKeyInlineResponses, TestProviderKeyRequest, TestProviderKeyResponse, TestProviderResponse, TestProviderResponse2, TestProviderResponses, TestS3ConnectionPreviewData, TestS3ConnectionPreviewError, TestS3ConnectionPreviewErrors, TestS3ConnectionPreviewResponse, TestS3ConnectionPreviewResponses, TestS3SourceConnectionData, TestS3SourceConnectionError, TestS3SourceConnectionErrors, TestS3SourceConnectionResponse, TestS3SourceConnectionResponses, TimeBucketStats, TimeBucketStatsResponse, TimeseriesBucket, TimeseriesQueryParams, TlsMode, TodayStatsResponse, ToggleDeploymentMetricsRequest, ToggleServiceMetricsRequest, TokenRenewalRequest, ToolCallEvent, ToolInfo, ToolResultEvent, TopModelsQueryParams, TraceProjectRef, TracesResponse, TraceSummariesResponse, TraceSummary, TrackClickData, TrackClickErrors, TrackedLinkResponse, TrackingEventResponse, TrackOpenData, TrackOpenErrors, TrackOpenResponses, TriggerAgentData, TriggerAgentErrors, TriggerAgentRequest, TriggerAgentResponse, TriggerAgentResponses, TriggerDigestResponse, TriggerPipelinePayload, TriggerPipelineResponse, TriggerProjectPipelineData, TriggerProjectPipelineErrors, TriggerProjectPipelineResponse, TriggerProjectPipelineResponses, TriggerScanData, TriggerScanError, TriggerScanErrors, TriggerScanRequest, TriggerScanResponse, TriggerScanResponse2, TriggerScanResponses, TriggerServiceHealthCheckData, TriggerServiceHealthCheckErrors, TriggerServiceHealthCheckResponse, TriggerServiceHealthCheckResponses, TriggerWeeklyDigestData, TriggerWeeklyDigestErrors, TriggerWeeklyDigestResponse, TriggerWeeklyDigestResponses, TtlRequest, TtlResponse, TxtRecord, UiManifest, UiRoute, UndrainNodeResponse, UnifiedTrace, UniqueCountsQuery, UniqueCountsResponse, UnlinkServiceFromProjectData, UnlinkServiceFromProjectErrors, UnlinkServiceFromProjectResponse, UnlinkServiceFromProjectResponses, UnsupportedFeature, UpdateAdminGateRequest, UpdateAgentData, UpdateAgentErrors, UpdateAgentResponse, UpdateAgentResponses, UpdateAiProviderData, UpdateAiProviderErrors, UpdateAiProviderRequest, UpdateAiProviderResponse, UpdateAiProviderResponse2, UpdateAiProviderResponses, UpdateAlertData, UpdateAlertError, UpdateAlertErrors, UpdateAlertResponse, UpdateAlertResponses, UpdateAlertRuleData, UpdateAlertRuleErrors, UpdateAlertRuleRequest, UpdateAlertRuleResponse, UpdateAlertRuleResponses, UpdateApiKeyData, UpdateApiKeyErrors, UpdateApiKeyRequest, UpdateApiKeyResponse, UpdateApiKeyResponses, UpdateAutomaticDeployData, UpdateAutomaticDeployErrors, UpdateAutomaticDeployRequest, UpdateAutomaticDeployResponse, UpdateAutomaticDeployResponses, UpdateBackupScheduleData, UpdateBackupScheduleError, UpdateBackupScheduleErrors, UpdateBackupScheduleRequest, UpdateBackupScheduleResponse, UpdateBackupScheduleResponses, UpdateBlobRequest, UpdateBlobResponse, UpdateCloudflareProviderData, UpdateCloudflareProviderErrors, UpdateCloudflareProviderRequest, UpdateCloudflareProviderResponse, UpdateCloudflareProviderResponses, UpdateConfigBody, UpdateConnectionTokenData, UpdateConnectionTokenErrors, UpdateConnectionTokenResponse, UpdateConnectionTokenResponses, UpdateCustomDomainData, UpdateCustomDomainErrors, UpdateCustomDomainRequest, UpdateCustomDomainResponse, UpdateCustomDomainResponses, UpdateDashboardData, UpdateDashboardError, UpdateDashboardErrors, UpdateDashboardRequest, UpdateDashboardResponse, UpdateDashboardResponses, UpdateDeploymentConfigRequest, UpdateDeploymentTokenData, UpdateDeploymentTokenErrors, UpdateDeploymentTokenRequest, UpdateDeploymentTokenResponse, UpdateDeploymentTokenResponses, UpdateDnsProviderRequest, UpdateEmailProviderData, UpdateEmailProviderErrors, UpdateEmailProviderRequest, UpdateEmailProviderResponse, UpdateEmailProviderResponses, UpdateEnvironmentSettingsData, UpdateEnvironmentSettingsErrors, UpdateEnvironmentSettingsRequest, UpdateEnvironmentSettingsResponse, UpdateEnvironmentSettingsResponses, UpdateEnvironmentSubdomainData, UpdateEnvironmentSubdomainErrors, UpdateEnvironmentSubdomainRequest, UpdateEnvironmentSubdomainResponse, UpdateEnvironmentSubdomainResponses, UpdateEnvironmentVariableData, UpdateEnvironmentVariableErrors, UpdateEnvironmentVariableRequest, UpdateEnvironmentVariableResponse, UpdateEnvironmentVariableResponses, UpdateErrorGroupData, UpdateErrorGroupErrors, UpdateErrorGroupRequest, UpdateErrorGroupResponses, UpdateExternalServiceRequest, UpdateFlagData, UpdateFlagErrors, UpdateFlagRequest, UpdateFlagResponse, UpdateFlagResponses, UpdateFunnelData, UpdateFunnelErrors, UpdateFunnelResponses, UpdateGitProviderCredentialsData, UpdateGitProviderCredentialsErrors, UpdateGitProviderCredentialsResponse, UpdateGitProviderCredentialsResponses, UpdateGitSettingsData, UpdateGitSettingsErrors, UpdateGitSettingsRequest, UpdateGitSettingsResponse, UpdateGitSettingsResponses, UpdateGlobalMcpData, UpdateGlobalMcpErrors, UpdateGlobalMcpResponse, UpdateGlobalMcpResponses, UpdateGlobalSkillData, UpdateGlobalSkillErrors, UpdateGlobalSkillResponse, UpdateGlobalSkillResponses, UpdateIncidentStatusData, UpdateIncidentStatusErrors, UpdateIncidentStatusRequest, UpdateIncidentStatusResponse, UpdateIncidentStatusResponses, UpdateIpAccessControlData, UpdateIpAccessControlError, UpdateIpAccessControlErrors, UpdateIpAccessControlRequest, UpdateIpAccessControlResponse, UpdateIpAccessControlResponses, UpdateKvRequest, UpdateKvResponse, UpdateManagedDomainApiRequest, UpdateManagedDomainData, UpdateManagedDomainErrors, UpdateManagedDomainResponse, UpdateManagedDomainResponses, UpdateMcpData, UpdateMcpErrors, UpdateMcpRequest, UpdateMcpResponse, UpdateMcpResponses, UpdateMemberRoleRequest, UpdateMetricAlertRequest, UpdateNotificationEmailProviderData, UpdateNotificationEmailProviderErrors, UpdateNotificationEmailProviderRequest, UpdateNotificationEmailProviderResponse, UpdateNotificationEmailProviderResponses, UpdateNotificationProviderData, UpdateNotificationProviderErrors, UpdateNotificationProviderResponse, UpdateNotificationProviderResponses, UpdateOidcProviderData, UpdateOidcProviderRequest, UpdateOidcProviderResponse, UpdateOidcProviderResponses, UpdatePreferencesData, UpdatePreferencesErrors, UpdatePreferencesRequest, UpdatePreferencesResponse, UpdatePreferencesResponses, UpdateProjectData, UpdateProjectDeploymentConfigData, UpdateProjectDeploymentConfigErrors, UpdateProjectDeploymentConfigResponse, UpdateProjectDeploymentConfigResponses, UpdateProjectErrors, UpdateProjectResponse, UpdateProjectResponses, UpdateProjectSecretData, UpdateProjectSecretErrors, UpdateProjectSecretRequest, UpdateProjectSecretResponse, UpdateProjectSecretResponses, UpdateProjectSettingsData, UpdateProjectSettingsErrors, UpdateProjectSettingsRequest, UpdateProjectSettingsResponse, UpdateProjectSettingsResponses, UpdateProviderCredentialsRequest, UpdateProviderData, UpdateProviderErrors, UpdateProviderKeyData, UpdateProviderKeyError, UpdateProviderKeyErrors, UpdateProviderKeyRequest, UpdateProviderKeyResponse, UpdateProviderKeyResponses, UpdateProviderRequest, UpdateProviderResponse, UpdateProviderResponses, UpdateRouteData, UpdateRouteErrors, UpdateRouteRequest, UpdateRouteResponse, UpdateRouteResponses, UpdateS3SourceData, UpdateS3SourceError, UpdateS3SourceErrors, UpdateS3SourceRequest, UpdateS3SourceResponse, UpdateS3SourceResponses, UpdateSecretBody, UpdateSelfData, UpdateSelfErrors, UpdateSelfRequest, UpdateSelfResponse, UpdateSelfResponses, UpdateServiceData, UpdateServiceErrors, UpdateServiceResourcesData, UpdateServiceResourcesErrors, UpdateServiceResourcesResponse, UpdateServiceResourcesResponses, UpdateServiceResponse, UpdateServiceResponses, UpdateSessionDurationData, UpdateSessionDurationError, UpdateSessionDurationErrors, UpdateSessionDurationRequest, UpdateSessionDurationResponse, UpdateSessionDurationResponse2, UpdateSessionDurationResponses, UpdateSettingsData, UpdateSettingsErrors, UpdateSettingsResponse, UpdateSettingsResponses, UpdateSkillData, UpdateSkillErrors, UpdateSkillRequest, UpdateSkillResponse, UpdateSkillResponses, UpdateSlackProviderData, UpdateSlackProviderErrors, UpdateSlackProviderRequest, UpdateSlackProviderResponse, UpdateSlackProviderResponses, UpdateSpeedMetricsData, UpdateSpeedMetricsError, UpdateSpeedMetricsErrors, UpdateSpeedMetricsPayload, UpdateSpeedMetricsResponse, UpdateSpeedMetricsResponses, UpdateStatusResponse, UpdateTeamData, UpdateTeamErrors, UpdateTeamMemberRoleData, UpdateTeamMemberRoleErrors, UpdateTeamMemberRoleResponse, UpdateTeamMemberRoleResponses, UpdateTeamRequest, UpdateTeamResponse, UpdateTeamResponses, UpdateTokenRequest, UpdateTokenResponse, UpdateUserData, UpdateUserErrors, UpdateUserRequest, UpdateUserResponse, UpdateUserResponses, UpdateWebhookData, UpdateWebhookErrors, UpdateWebhookProviderData, UpdateWebhookProviderErrors, UpdateWebhookProviderRequest, UpdateWebhookProviderResponse, UpdateWebhookProviderResponses, UpdateWebhookRequestBody, UpdateWebhookResponse, UpdateWebhookResponses, UpgradeExternalServiceRequest, UpgradePreviewGatewayData, UpgradePreviewGatewayResponse, UpgradePreviewGatewayResponses, UpgradeRequest, UpgradeServiceData, UpgradeServiceErrors, UpgradeServiceResponse, UpgradeServiceResponses, UploadGlobalSkillData, UploadGlobalSkillErrors, UploadGlobalSkillResponse, UploadGlobalSkillResponses, UploadReleaseFileData, UploadReleaseFileErrors, UploadReleaseFileResponse, UploadReleaseFileResponses, UploadSkillData, UploadSkillErrors, UploadSkillResponse, UploadSkillResponses, UploadSourceFileData, UploadSourceFileErrors, UploadSourceFileResponse, UploadSourceFileResponses, UploadSourceMapData, UploadSourceMapErrors, UploadSourceMapResponse, UploadSourceMapResponses, UploadStaticBundleData, UploadStaticBundleErrors, UploadStaticBundleResponse, UploadStaticBundleResponses, UpsertAgentRequest, UpsertSecretData, UpsertSecretErrors, UpsertSecretRequest, UpsertSecretResponse, UpsertSecretResponses, UptimeDataPoint, UptimeHistoryResponse, UsageFilter, UsageInfo, UsageLogEntry, UsageLogPage, UsageQueryParams, UsageSource, UsageSummary, UserResponse, ValidateConnectionData, ValidateConnectionErrors, ValidateConnectionResponse, ValidateConnectionResponses, ValidateEmailData, ValidateEmailErrors, ValidateEmailRequest, ValidateEmailResponse, ValidateEmailResponse2, ValidateEmailResponses, ValidationLevel, ValidationReport, ValidationResponse, ValidationResult, ValidationStatus, ValidationSummary, VerifyAndEnableMfaData, VerifyAndEnableMfaErrors, VerifyAndEnableMfaResponse, VerifyAndEnableMfaResponses, VerifyDomainData, VerifyDomainErrors, VerifyDomainResponse, VerifyDomainResponses, VerifyEmailData, VerifyEmailErrors, VerifyEmailResponse, VerifyEmailResponses, VerifyManagedDomainData, VerifyManagedDomainErrors, VerifyManagedDomainResponse, VerifyManagedDomainResponses, VerifyMfaChallengeData, VerifyMfaChallengeErrors, VerifyMfaChallengeResponse, VerifyMfaChallengeResponses, VerifyMfaRequest, VerifyStepUpData, VerifyStepUpErrors, VerifyStepUpRequest, VerifyStepUpResponse, VerifyStepUpResponses, ViewItem, ViewsOverTime, ViewsOverTimeQuery, VisitorDetails, VisitorFacets, VisitorFacetsQuery, VisitorFacetValue, VisitorInfo, VisitorJourneyQuery, VisitorJourneyResponse, VisitorLocationsQuery, VisitorRecord, VisitorSegmentFilters, VisitorSessionsQuery, VisitorSessionsResponse, VisitorsListQuery, VisitorsResponse, VisitorStats, VisitorWithGeolocation, VolumeMount, VolumeType, VulnerabilityResponse, WakeEnvironmentData, WakeEnvironmentErrors, WakeEnvironmentResponse, WakeEnvironmentResponses, WalWarning, WalWarningSeverity, WebhookConfig, WebhookDeliveryResponse, WebhookResponse, WebhookTriggerData, WebhookTriggerErrors, WebhookTriggerRequest, WebhookTriggerResponse, WebhookTriggerResponse2, WebhookTriggerResponses, WorkflowDryRunData, WorkflowDryRunErrors, WorkflowDryRunRequest, WorkflowDryRunResponse, WorkflowDryRunResponses, WorkloadDescriptor, WorkloadId, WorkloadStatus, WorkloadType, WriteFileBody, WriteFileData, WriteFileErrors, WriteFileResponse, WriteFileResponses, WriteFilesBody, WriteFilesData, WriteFilesErrors, WriteFilesResponse, WriteFilesResponse2, WriteFilesResponses, ZoneListResponse } from './types.gen'; +export { acknowledgeAlarm, activateAiProvider, activateApiKey, activateConnection, activateProvider, addClusterMember, addContext, addEnvironmentDomain, addEvents, addManagedDomain, addSessionReplayEvents, addTeamMember, adminDrainNode, adminDrainStatus, adminGetNode, adminListNodeContainers, adminListNodes, adminRemoveNode, adminUndrainNode, applyHostnameMode, archiveConversation, archiveFlag, assignRole, attachScheduleServices, blobCopy, blobDelete, blobDisable, blobDownload, blobEnable, blobHead, blobList, blobPut, blobStatus, blobUpdate, cancel, cancelBackup, cancelDeployment, cancelDomainOrder, cancelPgUpgrade, cancelRun, cancelScheduleRun, changePasswordSelf, changeProjectSource, changeRequiredPassword, chatCompletions, checkAnalyticsHasEvents, checkCommitExists, checkDomainStatus, checkExplorerSupport, checkIpBlocked, checkProviderDeletionSafety, chunkUploadOptions, cleanupExpiredBackups, clearPreviewPassword, cliDeviceApprove, cliDeviceDeny, cliDeviceLookup, cliDevicePoll, cliDeviceStart, cliLogout, cmd, cmdKill, cmdLogs, confirmPendingAction, containerMetricsGetHistory, createAgent, createAlert, createAlertRule, createApiKey, createBackupSchedule, createBitbucketProvider, createCloudflareProvider, createConversation, createCustomDomain, createDashboard, createDeploymentToken, createDnsProvider, createDomain, createDsn, createEmailDomain, createEmailProvider, createEnvironment, createEnvironmentVariable, createFlag, createFunnel, createGenericProvider, createGiteaPatProvider, createGithubPatProvider, createGitlabOauthProvider, createGitlabPatProvider, createGitProvider, createGlobalMcp, createGlobalSkill, createIncident, createIpAccessControl, createMcp, createMonitor, createNotificationEmailProvider, createNotificationProvider, createOidcProvider, createOidcRoleMapping, createOrRecreateOrder, createPlan, createPr, createProject, createProjectFromTemplate, createProjectRelease, createProjectSecret, createProviderKey, createRelease, createRoute, createS3Source, createSandbox, createService, createSkill, createSlackProvider, createTeam, createUser, createWebhook, createWebhookProvider, deactivateApiKey, deactivateConnection, deactivateProvider, deleteAgent, deleteAlert, deleteAlertRule, deleteApiKey, deleteBackup, deleteBackupSchedule, deleteConnection, deleteCustomDomain, deleteDashboard, deleteDeploymentToken, deleteDnsProvider, deleteDomain, deleteEmailDomain, deleteEmailProvider, deleteEnvironment, deleteEnvironmentDomain, deleteEnvironmentVariable, deleteExternalImage, deleteFunnel, deleteGitProvider, deleteGlobalMcp, deleteGlobalSkill, deleteIpAccessControl, deleteMcp, deleteMonitor, deleteNotificationProvider, deleteOidcProvider, deleteOidcRoleMapping, deletePreferences, deleteProject, deleteProjectSecret, deleteProviderKey, deleteProviderSafely, deleteReleaseSourceFiles, deleteReleaseSourceMaps, deleteRoute, deleteS3Source, deleteScan, deleteSecret, deleteService, deleteSessionReplay, deleteSkill, deleteSourceMap, deleteStaticBundle, deleteTeam, deleteUser, deleteWebhook, deployFromImage, deployFromImageUpload, deployFromStatic, deployFromUploadedSource, deploymentMetricsGetLatest, deploymentMetricsGetRange, deploymentMetricsToggle, destroySandbox, detachScheduleService, detectPublicPresets, disableBackupSchedule, disableMfa, discoverWorkloads, domain, downloadGlobalSkillArchive, downloadObject, downloadSkillArchive, emailStatus, embeddings, enableBackupSchedule, enrichVisitor, exec, execDetached, executeDeploymentOperation, executeImport, extendTimeout, externalServiceEnablePgStatStatements, externalServiceMetricsByDatabase, externalServiceMetricsCreateAlertRule, externalServiceMetricsDeleteAlertRule, externalServiceMetricsGetAlertRules, externalServiceMetricsGetLatest, externalServiceMetricsGetRange, externalServiceMetricsStatus, externalServiceMetricsToggle, externalServiceMetricsUpdateAlertRule, externalServiceResetPgStatStatements, finalizeOrder, finalizeProjectRelease, findConversation, generateJoinToken, generatePresetDockerfile, getAccessInfo, getActiveVisitors, getActivityGraph, getAdminGate, getAgent, getAggregatedBuckets, getAiAgentBreakdown, getAiAgentPages, getAiAgentTimeline, getAiPageBreakdown, getAiStatusBreakdown, getAlert, getAlertRule, getAllRepositoriesByName, getAnalyticsActiveVisitors, getAnalyticsEventsCount, getAnalyticsSessionEvents, getAnalyticsVisitorSessions, getApiKey, getApiKeyPermissions, getAuditLog, getBackup, getBackupSchedule, getBranchesByRepositoryId, getBucketedIncidents, getBucketedStatus, getChallengeToken, getChatReadiness, getCliStatus, getClusterHealth, getClusterMember, getCmd, getContainerDetail, getContainerEnvironmentVariable, getContainerInfo, getContainerLogs, getContainerLogsById, getContainerMetrics, getConversation, getConversationDetail, getConversations, getCronById, getCronExecutions, getCrossProjectTraceSiblings, getCurrentMonitorStatus, getCurrentUser, getCustomDomain, getDashboard, getDashboardProjectsAnalytics, getDelivery, getDeployment, getDeploymentContainerLogContent, getDeploymentJobLogs, getDeploymentJobs, getDeploymentOperations, getDeploymentOperationStatus, getDeploymentToken, getDiskStatus, getDnsChanges, getDnsProvider, getDomain, getDomainByHost, getDomainById, getDomainByName, getDomainDnsRecords, getDomainOrder, getEmail, getEmailEvents, getEmailLinks, getEmailProvider, getEmailStats, getEmailTracking, getEmailTrackingStatus, getEntityInfo, getEnvironment, getEnvironmentCrons, getEnvironmentDomains, getEnvironments, getEnvironmentVariables, getEnvironmentVariableValue, getErrorDashboardStats, getErrorEvent, getErrorGroup, getErrorStats, getErrorTimeSeries, getEventDetail, getEventEntries, getEventsCount, getEventsTimeline, getEventTypeBreakdown, getEventVisitors, getExternalImage, getFile, getFlag, getFlagSnapshot, getFunnelMetrics, getGenaiTrace, getGeneralStats, getGitProvider, getGlobalEvents, getGlobalEventStats, getGlobalMcp, getGlobalSandboxStatus, getGlobalSkill, getGroupedPageMetrics, getHealth, getHourlyVisits, getHttpChallengeDebug, getImportStatus, getIncident, getIncidentUpdates, getIpAccessControl, getIpGeolocation, getJoinTokenStatus, getLastDeployment, getLatestScan, getLatestScansPerEnvironment, getLiveVisitorsList, getLogContext, getMcp, getMetricsOverTime, getMonitor, getNotificationProvider, getOnDemandCertStatus, getOrCreateDsn, getPageFlow, getPageHourlySessions, getPagePathDetail, getPagePaths, getPagePathsSparklines, getPagePathVisitors, getPendingAction, getPerformanceMetrics, getPgUpgrade, getPgUpgradeLogs, getPipelineStats, getPlatformInfo, getPostgresWalHealth, getPreferences, getPreviewGatewayLogs, getPreviewGatewaySettings, getPreviewGatewayStatus, getPricing, getPrivateIp, getProject, getProjectAlarmsSummary, getProjectBySlug, getProjectDeployments, getProjects, getProjectServiceEnvironmentVariables, getProjectSessionReplays, getProjectsHealth, getProjectsMonitorHealth, getProjectStatistics, getProjectTemplate, getPropertyBreakdown, getPropertyTimeline, getProviderConnections, getProviderMetadata, getProvidersMetadata, getProxyLogById, getProxyLogByRequestId, getProxyLogs, getPublicBranches, getPublicIp, getPublicRepository, getQuota, getRecentActivity, getRemoteExternalImage, getRepositoryBranches, getRepositoryById, getRepositoryByName, getRepositoryPresetByName, getRepositoryPresetLive, getRepositoryTags, getResolvedEnvironmentVariables, getResolvedEnvironmentVariableValue, getRestoreCapabilities, getRestoreRun, getRoute, getRun, getRunWithLogs, getS3Credentials, getS3Source, getSandbox, getSandboxStatus, getScan, getScanByDeployment, getScanVulnerabilities, getService, getServiceBySlug, getServiceEnvironmentVariable, getServiceEnvironmentVariables, getServiceHealthStatus, getServicePreviewEnvironmentVariableNames, getServicePreviewEnvironmentVariablesMasked, getServiceRuntime, getServiceStats, getServiceTypeParameters, getServiceTypes, getSessionDetails, getSessionEvents, getSessionLogs, getSessionReplay, getSessionReplayEvents, getSettings, getSkill, getSlowQueries, getStaticBundle, getStatusOverview, getTagsByRepositoryId, getTeam, getTimeBucketStats, getTodayStats, getTrace, getUnifiedTrace, getUniqueCounts, getUniqueEvents, getUpdateCapability, getUpdateStatus, getUptimeHistory, getUsageByProvider, getUsageRecent, getUsageSummary, getUsageTimeseries, getUsageTopModels, getVisitorByGuid, getVisitorById, getVisitorDetails, getVisitorFacets, getVisitorInfo, getVisitorJourney, getVisitors, getVisitorSessions, getVisitorStats, getWebhook, grantProjectAccess, handleGitProviderOauthCallback, hasAnalyticsEvents, hasErrorGroups, hasPerformanceMetrics, importExternalService, ingestLogs, ingestLogsByPath, ingestMetrics, ingestMetricsByPath, ingestSentryEnvelope, ingestSentryEvent, ingestTraces, ingestTracesByPath, initSessionReplay, inspectDropArchive, jobLogs, jobStatus, killJob, kvDel, kvDisable, kvEnable, kvExpire, kvGet, kvIncr, kvKeys, kvSet, kvStatus, kvTtl, kvUpdate, latestRunForSource, linkCustomDomainToCertificate, linkServiceToProject, listAgentRuns, listAgents, listAiProviders, listAlertRules, listAlerts, listAllConversations, listAllRuns, listApiKeys, listAuditLogs, listAvailableContainers, listBackupAlerts, listBackupChildren, listBackupSchedules, listBackupsForSchedule, listCommitsByRepositoryId, listConnections, listContainers, listContainersAtPath, listConversations, listCustomDomainsForProject, listDashboards, listDeliveries, listDeploymentContainerLogs, listDeploymentTokens, listDnsProviders, listDomains, listDsns, listEmailDomains, listEmailProviders, listEmails, listEnrollmentTokens, listEntities, listErrorEvents, listErrorGroups, listEvents, listEventTypes, listExternalImages, listExternalPlugins, listExternalServiceBackups, listFlags, listFunnels, listGitProviders, listGlobalMcps, listGlobalSkills, listIncidents, listInsights, listIpAccessControl, listJobs, listKnownAiAgents, listManagedDomains, listMcps, listMetricLabelKeys, listMetricLabelValues, listMetricNames, listModels, listMonitors, listNotificationProviders, listOidcProviders, listOidcProviderUsers, listOidcRoleMappings, listOnDemandCerts, listOrders, listPeers, listPendingActions, listPgUpgrades, listPresets, listProjectAccess, listProjectAlarms, listProjectScans, listProjectSecrets, listProjectServices, listProjectTemplates, listProjectTemplateTags, listProviderKeys, listProviderZones, listPublicProviders, listReleaseFiles, listReleases, listRemoteExternalImages, listRepositoriesByConnection, listRepositoriesByProvider, listRestoreRunsForService, listRootContainers, listRoutes, listS3Sources, listSandboxes, listScheduleRunJobs, listScheduleRuns, listScheduleServices, listSecrets, listServiceHealthStatuses, listServiceProjects, listServices, listServiceSchedules, listSkills, listSourceBackups, listSourceFiles, listSourceMaps, listSources, listStaticBundles, listSyncedRepositories, listTeamMembers, listTeamProjects, listTeams, listUsers, listWebhooks, login, logout, lookupDnsARecords, mintEnrollmentToken, mkdir, nodeHeartbeat, nodeMetricsGetRange, observabilityFullEvent, observabilityListEvents, oidcCallback, type Options, patchAdminGate, patchPreviewGatewaySettings, pauseDeployment, pauseSandbox, planRestore, postDnsAck, previewAlert, previewFunnelMetrics, previewHostnameMode, promoteClusterMember, promoteDeployment, provisionDomain, purgeProjectLogs, pushExternalImage, queryData, queryGenaiTraces, queryLogs, queryMetrics, queryTraces, queryTraceSummaries, readFile, reAnalyze, recordConsoleEvent, recordEventMetrics, recordFlagExposure, recordSpeedMetrics, refreshRouteTable, regenerateDsn, registerExternalImage, registerNode, reinstallGitlabWebhook, rejectPendingAction, reloadPlugins, removeClusterMember, removeManagedDomain, removeRole, removeTeamMember, renameConversation, renewDomain, requestPasswordReset, resetPassword, resizeSandbox, resolveAlarm, restartContainer, restartPreviewGateway, restartSandbox, restoreFlag, restoreUser, resumeDeployment, resumeSandbox, retryCluster, retryDelivery, retryPgUpgrade, retryRun, revealGlobalMcpConfig, revealMcpConfig, revealNotificationProviderConfig, revealServiceParameter, revenueCreateIntegration, revenueDeleteIntegration, revenueGlobalEvents, revenueImportInvoicesCsv, revenueImportSubscriptionsCsv, revenueListIntegrations, revenueListProviders, revenueMetricsCustomers, revenueMetricsGlobalMrr, revenueMetricsGlobalSummary, revenueMetricsMrr, revenueMetricsSummary, revenueRecentEvents, revenueRotateToken, revenueUpdateConfig, revenueUpdateSecret, revokeDsn, revokeEnrollmentToken, revokeJoinToken, revokeProjectAccess, rollbackPgUpgrade, rollbackToDeployment, rootfsGc, rootfsReport, rotateApiKey, rotateDeploymentToken, runBackupForSource, runConnectionHealthCheck, runExternalServiceBackup, runScheduleNow, sandboxCreatePreviewLink, saveAgentToken, saveAiProviderCredential, searchLogs, sendEmail, setDefaultS3Source, setFlagEnvironment, setPreviewPassword, setupDns, setupDnsChallenge, setupEmailTracking, setupMfa, sleepEnvironment, smokeTestAgent, sourceSandbox, startAnalysis, startContainer, startFix, startGitProviderOauth, startOidcLoginBySlug, startPgUpgrade, startRestore, startService, startUpdate, statPath, stopContainer, stopSandbox, stopService, streamContainerMetrics, streamEvents, streamRunEvents, syncRepositories, tailDeploymentJobLogs, tailLogs, teardownDeployment, teardownEnvironment, testNotificationProvider, testOidcProvider, testProvider, testProviderConnection, testProviderKeyById, testProviderKeyInline, testS3ConnectionPreview, testS3SourceConnection, trackClick, trackOpen, triggerAgent, triggerProjectPipeline, triggerScan, triggerServiceHealthCheck, triggerWeeklyDigest, unlinkServiceFromProject, updateAgent, updateAiProvider, updateAlert, updateAlertRule, updateApiKey, updateAutomaticDeploy, updateBackupSchedule, updateCloudflareProvider, updateConnectionToken, updateCustomDomain, updateDashboard, updateDeploymentToken, updateEmailProvider, updateEnvironmentSettings, updateEnvironmentSubdomain, updateEnvironmentVariable, updateErrorGroup, updateFlag, updateFunnel, updateGitProviderCredentials, updateGitSettings, updateGlobalMcp, updateGlobalSkill, updateIncidentStatus, updateIpAccessControl, updateManagedDomain, updateMcp, updateNotificationEmailProvider, updateNotificationProvider, updateOidcProvider, updatePreferences, updateProject, updateProjectDeploymentConfig, updateProjectSecret, updateProjectSettings, updateProvider, updateProviderKey, updateRoute, updateS3Source, updateSelf, updateService, updateServiceResources, updateSessionDuration, updateSettings, updateSkill, updateSlackProvider, updateSpeedMetrics, updateTeam, updateTeamMemberRole, updateUser, updateWebhook, updateWebhookProvider, upgradePreviewGateway, upgradeService, uploadGlobalSkill, uploadReleaseFile, uploadSkill, uploadSourceFile, uploadSourceMap, uploadStaticBundle, upsertSecret, validateConnection, validateEmail, verifyAndEnableMfa, verifyDomain, verifyEmail, verifyManagedDomain, verifyMfaChallenge, verifyStepUp, wakeEnvironment, webhookTrigger, workflowDryRun, writeFile, writeFiles } from './sdk.gen'; +export type { AcknowledgeAlarmData, AcknowledgeAlarmErrors, AcknowledgeAlarmResponses, AcmeOrderResponse, ActivateAiProviderData, ActivateAiProviderErrors, ActivateAiProviderResponse, ActivateAiProviderResponses, ActivateApiKeyData, ActivateApiKeyErrors, ActivateApiKeyResponse, ActivateApiKeyResponses, ActivateConnectionData, ActivateConnectionErrors, ActivateConnectionResponses, ActivateProviderData, ActivateProviderErrors, ActivateProviderResponse, ActivateProviderResponses, ActiveVisitor, ActiveVisitorsQuery, ActiveVisitorsResponse, ActivityDay, ActivityEvent, ActivityGraphQuery, ActivityGraphResponse, AddClusterMemberData, AddClusterMemberErrors, AddClusterMemberRequest, AddClusterMemberResponse, AddClusterMemberResponses, AddContextData, AddContextErrors, AddContextRequest, AddContextResponses, AddEnvironmentDomainData, AddEnvironmentDomainErrors, AddEnvironmentDomainRequest, AddEnvironmentDomainResponse, AddEnvironmentDomainResponses, AddEventsData, AddEventsError, AddEventsErrors, AddEventsRequest, AddEventsResponse, AddEventsResponse2, AddEventsResponses, AddManagedDomainApiRequest, AddManagedDomainData, AddManagedDomainErrors, AddManagedDomainResponse, AddManagedDomainResponses, AddSessionReplayEventsData, AddSessionReplayEventsError, AddSessionReplayEventsErrors, AddSessionReplayEventsResponse, AddSessionReplayEventsResponses, AddTeamMemberData, AddTeamMemberErrors, AddTeamMemberResponse, AddTeamMemberResponses, AdminDrainNodeData, AdminDrainNodeErrors, AdminDrainNodeResponse, AdminDrainNodeResponses, AdminDrainStatusData, AdminDrainStatusErrors, AdminDrainStatusResponse, AdminDrainStatusResponses, AdminGateResponse, AdminGateSource, AdminGetNodeData, AdminGetNodeErrors, AdminGetNodeResponse, AdminGetNodeResponses, AdminListNodeContainersData, AdminListNodeContainersErrors, AdminListNodeContainersResponse, AdminListNodeContainersResponses, AdminListNodesData, AdminListNodesErrors, AdminListNodesResponse, AdminListNodesResponses, AdminRemoveNodeData, AdminRemoveNodeErrors, AdminRemoveNodeResponse, AdminRemoveNodeResponses, AdminUndrainNodeData, AdminUndrainNodeErrors, AdminUndrainNodeResponse, AdminUndrainNodeResponses, AgentConfigResponse, AgentRunLogResponse, AgentRunResponse, AgentRunWithLogsResponse, AgentSandboxSettings, AgentSandboxSettingsMasked, AggregatedBucketItem, AggregatedBucketsQuery, AggregatedBucketsResponse, AggregationLevel, AggregationTemporality, AiAgentBreakdownResponse, AiAgentBreakdownRow, AiAgentDescriptor, AiAgentPageRow, AiAgentPagesResponse, AiAgentTimelineResponse, AiAgentTimelineRow, AiChatLimitsSettings, AiConfigSettings, AiPageBreakdownResponse, AiPageBreakdownRow, AiStatusBreakdownResponse, AiStatusBreakdownRow, AlarmListResponse, AlarmResponse, AlarmSummaryResponse, AlertRuleResponse, AllocEntry, AnalyticsSessionEventsResponse, AnnotatedSpan, AnomalyAlgorithm, AnomalyParams, AnomalyPreviewPointResponse, AnomalyPreviewRequest, AnomalyPreviewResponse, ApiKeyListResponse, ApiKeyResponse, ApplyHostnameModeData, ApplyHostnameModeErrors, ApplyHostnameModeRequest, ApplyHostnameModeResponse, ApplyHostnameModeResponses, AppSettings, AppSettingsResponse, ArchiveConversationData, ArchiveConversationErrors, ArchiveConversationResponse, ArchiveConversationResponses, ArchiveFlagData, ArchiveFlagErrors, ArchiveFlagResponse, ArchiveFlagResponse2, ArchiveFlagResponses, ArchiveMode, AssignRoleData, AssignRoleErrors, AssignRoleRequest, AssignRoleResponses, AttachScheduleServicesData, AttachScheduleServicesError, AttachScheduleServicesErrors, AttachScheduleServicesRequest, AttachScheduleServicesResponse, AttachScheduleServicesResponse2, AttachScheduleServicesResponses, AuditLogIpInfo, AuditLogResponse, AuditLogUserInfo, AuthFlavorDto, AuthResponse, AuthStatusResponse, AuthTokenResponse, AutofixerRunResponse, AutofixerRunWithLogsResponse, AutofixRunConfig, AutoWatchParams, AvailableContainerInfo, AvailablePermissions, BackupAlertListResponse, BackupAlertResponse, BackupResponse, BackupScheduleResponse, BitbucketAuthInput, BlobCopyData, BlobCopyError, BlobCopyErrors, BlobCopyResponse, BlobCopyResponses, BlobDeleteData, BlobDeleteError, BlobDeleteErrors, BlobDeleteResponse, BlobDeleteResponses, BlobDisableData, BlobDisableErrors, BlobDisableResponse, BlobDisableResponses, BlobDownloadData, BlobDownloadError, BlobDownloadErrors, BlobDownloadResponses, BlobEnableData, BlobEnableErrors, BlobEnableResponse, BlobEnableResponses, BlobHeadData, BlobHeadError, BlobHeadErrors, BlobHeadResponses, BlobListData, BlobListError, BlobListErrors, BlobListResponse, BlobListResponses, BlobPutData, BlobPutError, BlobPutErrors, BlobPutResponse, BlobPutResponses, BlobResponse, BlobStatusData, BlobStatusErrors, BlobStatusResponse, BlobStatusResponse2, BlobStatusResponses, BlobUpdateData, BlobUpdateErrors, BlobUpdateResponse, BlobUpdateResponses, BranchInfo, BranchListResponse, BrowserCount, BrowsersQuery, BuildConfiguration, BuildLimitsSettings, CancelBackupData, CancelBackupError, CancelBackupErrors, CancelBackupResponse, CancelBackupResponse2, CancelBackupResponses, CancelData, CancelDeploymentData, CancelDeploymentErrors, CancelDeploymentResponse, CancelDeploymentResponses, CancelDomainOrderData, CancelDomainOrderErrors, CancelDomainOrderResponse, CancelDomainOrderResponses, CancelErrors, CancelPgUpgradeData, CancelPgUpgradeErrors, CancelPgUpgradeResponse, CancelPgUpgradeResponses, CancelResponses, CancelRunData, CancelRunErrors, CancelRunResponse, CancelRunResponses, CancelScheduleRunData, CancelScheduleRunError, CancelScheduleRunErrors, CancelScheduleRunResponse, CancelScheduleRunResponses, CertStatusResponse, ChallengeConfig, ChallengeError, ChallengeValidationStatus, ChangePasswordRequest, ChangePasswordSelfData, ChangePasswordSelfErrors, ChangePasswordSelfResponse, ChangePasswordSelfResponses, ChangeProjectSourceData, ChangeProjectSourceErrors, ChangeProjectSourceRequest, ChangeProjectSourceResponse, ChangeProjectSourceResponses, ChangeRequiredPasswordData, ChangeRequiredPasswordErrors, ChangeRequiredPasswordResponse, ChangeRequiredPasswordResponses, ChatCompletionChoice, ChatCompletionRequest, ChatCompletionResponse, ChatCompletionsData, ChatCompletionsError, ChatCompletionsErrors, ChatCompletionsResponse, ChatCompletionsResponses, ChatMessage, ChatReadinessResponse, CheckAnalyticsHasEventsData, CheckAnalyticsHasEventsErrors, CheckAnalyticsHasEventsResponse, CheckAnalyticsHasEventsResponses, CheckCommitExistsData, CheckCommitExistsErrors, CheckCommitExistsResponse, CheckCommitExistsResponses, CheckDomainStatusData, CheckDomainStatusErrors, CheckDomainStatusResponse, CheckDomainStatusResponses, CheckExplorerSupportData, CheckExplorerSupportErrors, CheckExplorerSupportResponse, CheckExplorerSupportResponses, CheckIpBlockedData, CheckIpBlockedError, CheckIpBlockedErrors, CheckIpBlockedResponses, CheckProviderDeletionSafetyData, CheckProviderDeletionSafetyErrors, CheckProviderDeletionSafetyResponse, CheckProviderDeletionSafetyResponses, ChildBackupEntryResponse, ChildBackupListResponse, ChunkUploadOptionsData, ChunkUploadOptionsResponse, ChunkUploadOptionsResponses, CleanupExpiredBackupsData, CleanupExpiredBackupsError, CleanupExpiredBackupsErrors, CleanupExpiredBackupsRequest, CleanupExpiredBackupsResponse, CleanupExpiredBackupsResponses, ClearPreviewPasswordData, ClearPreviewPasswordErrors, ClearPreviewPasswordResponse, ClearPreviewPasswordResponses, CliDeviceApproveData, CliDeviceApproveErrors, CliDeviceApproveRequest, CliDeviceApproveResponse, CliDeviceApproveResponse2, CliDeviceApproveResponses, CliDeviceDenyData, CliDeviceDenyErrors, CliDeviceDenyResponse, CliDeviceDenyResponses, CliDeviceLookupData, CliDeviceLookupErrors, CliDeviceLookupResponse, CliDeviceLookupResponse2, CliDeviceLookupResponses, CliDevicePollData, CliDevicePollErrors, CliDevicePollRequest, CliDevicePollResponse, CliDevicePollResponse2, CliDevicePollResponses, CliDeviceStartData, CliDeviceStartErrors, CliDeviceStartRequest, CliDeviceStartResponse, CliDeviceStartResponse2, CliDeviceStartResponses, ClientOptions, CliLoginRequest, CliLogoutData, CliLogoutErrors, CliLogoutResponse, CliLogoutResponses, CloudflareConfig, CloudProvider, ClusterCapacity, ClusterDnsSettings, ClusterHealthReportResponse, ClusterMemberHealthResponse, ClusterMemberRequest, CmdBody, CmdData, CmdErrors, CmdInner, CmdKillBody, CmdKillData, CmdKillErrors, CmdKillResponse, CmdKillResponses, CmdLogsData, CmdLogsErrors, CmdLogsResponses, CmdResponse, CmdResponse2, CmdResponses, CommitExistsResponse, CommitInfo, CommitListResponse, Comparator, ComposePublicPort, ConfirmPendingActionData, ConfirmPendingActionErrors, ConfirmPendingActionResponse, ConfirmPendingActionResponses, ConnectionListQuery, ConnectionListResponse, ConnectionResponse, ConnectionTestResult, ConsoleEventPayload, ContainerActionResponse, ContainerDetailResponse, ContainerEnvironmentVariableValueResponse, ContainerInfoResponse, ContainerInventoryItem, ContainerListResponse, ContainerLogSettings, ContainerLogsQuery, ContainerMetricHistoryPoint, ContainerMetricsGetHistoryData, ContainerMetricsGetHistoryErrors, ContainerMetricsGetHistoryResponse, ContainerMetricsGetHistoryResponses, ContainerMetricsHistoryQuery, ContainerMetricsResponse, ContainerResponse, ContainerRuntimeInfo, ContainerStatsSample, ContentPart, ContextLine, ContextLogsRequest, ContextLogsResponse, ConversationDetailResponse, ConversationResponse, ConversationsQueryParams, ConversationSummary, CopyBlobRequest, CostAnalysis, CreateAgentData, CreateAgentErrors, CreateAgentResponse, CreateAgentResponses, CreateAlertData, CreateAlertError, CreateAlertErrors, CreateAlertResponse, CreateAlertResponses, CreateAlertRuleData, CreateAlertRuleErrors, CreateAlertRuleRequest, CreateAlertRuleResponse, CreateAlertRuleResponses, CreateApiKeyData, CreateApiKeyErrors, CreateApiKeyRequest, CreateApiKeyResponse, CreateApiKeyResponse2, CreateApiKeyResponses, CreateBackupScheduleData, CreateBackupScheduleError, CreateBackupScheduleErrors, CreateBackupScheduleRequest, CreateBackupScheduleResponse, CreateBackupScheduleResponses, CreateBitbucketProviderData, CreateBitbucketProviderErrors, CreateBitbucketProviderResponse, CreateBitbucketProviderResponses, CreateBitbucketRequest, CreateCloudflareProviderData, CreateCloudflareProviderErrors, CreateCloudflareProviderRequest, CreateCloudflareProviderResponse, CreateCloudflareProviderResponses, CreateConversationData, CreateConversationErrors, CreateConversationRequest, CreateConversationResponse, CreateConversationResponses, CreateCustomDomainData, CreateCustomDomainErrors, CreateCustomDomainResponse, CreateCustomDomainResponses, CreateDashboardData, CreateDashboardError, CreateDashboardErrors, CreateDashboardRequest, CreateDashboardResponse, CreateDashboardResponses, CreateDeploymentTokenData, CreateDeploymentTokenErrors, CreateDeploymentTokenRequest, CreateDeploymentTokenResponse, CreateDeploymentTokenResponse2, CreateDeploymentTokenResponses, CreateDnsProviderData, CreateDnsProviderErrors, CreateDnsProviderRequest, CreateDnsProviderResponse, CreateDnsProviderResponses, CreateDomainData, CreateDomainErrors, CreateDomainRequest, CreateDomainResponse, CreateDomainResponses, CreatedResource, CreateDsnData, CreateDsnErrors, CreateDsnRequest, CreateDsnResponse, CreateDsnResponses, CreateEmailDomainData, CreateEmailDomainErrors, CreateEmailDomainRequest, CreateEmailDomainResponse, CreateEmailDomainResponses, CreateEmailProviderData, CreateEmailProviderErrors, CreateEmailProviderRequest, CreateEmailProviderResponse, CreateEmailProviderResponses, CreateEnvironmentData, CreateEnvironmentErrors, CreateEnvironmentRequest, CreateEnvironmentResponse, CreateEnvironmentResponses, CreateEnvironmentVariableData, CreateEnvironmentVariableErrors, CreateEnvironmentVariableRequest, CreateEnvironmentVariableResponse, CreateEnvironmentVariableResponses, CreateExternalServiceRequest, CreateFlagData, CreateFlagErrors, CreateFlagRequest, CreateFlagResponse, CreateFlagResponses, CreateFunnelData, CreateFunnelErrors, CreateFunnelRequest, CreateFunnelResponse, CreateFunnelResponse2, CreateFunnelResponses, CreateFunnelStep, CreateGenericProviderData, CreateGenericProviderErrors, CreateGenericProviderResponse, CreateGenericProviderResponses, CreateGenericRequest, CreateGiteaPatProviderData, CreateGiteaPatProviderErrors, CreateGiteaPatProviderResponse, CreateGiteaPatProviderResponses, CreateGiteaPatRequest, CreateGithubPatProviderData, CreateGithubPatProviderErrors, CreateGithubPatProviderResponse, CreateGithubPatProviderResponses, CreateGitHubPatRequest, CreateGitlabOauthProviderData, CreateGitlabOauthProviderErrors, CreateGitlabOauthProviderResponse, CreateGitlabOauthProviderResponses, CreateGitLabOAuthRequest, CreateGitlabPatProviderData, CreateGitlabPatProviderErrors, CreateGitlabPatProviderResponse, CreateGitlabPatProviderResponses, CreateGitLabPatRequest, CreateGitProviderData, CreateGitProviderErrors, CreateGitProviderResponse, CreateGitProviderResponses, CreateGlobalMcpData, CreateGlobalMcpErrors, CreateGlobalMcpResponse, CreateGlobalMcpResponses, CreateGlobalSkillData, CreateGlobalSkillErrors, CreateGlobalSkillResponse, CreateGlobalSkillResponses, CreateIncidentData, CreateIncidentErrors, CreateIncidentRequest, CreateIncidentResponse, CreateIncidentResponses, CreateIntegrationBody, CreateIpAccessControlData, CreateIpAccessControlError, CreateIpAccessControlErrors, CreateIpAccessControlRequest, CreateIpAccessControlResponse, CreateIpAccessControlResponses, CreateMcpData, CreateMcpErrors, CreateMcpRequest, CreateMcpResponse, CreateMcpResponses, CreateMetricAlertRequest, CreateMonitorData, CreateMonitorErrors, CreateMonitorRequest, CreateMonitorResponse, CreateMonitorResponses, CreateNotificationEmailProviderData, CreateNotificationEmailProviderErrors, CreateNotificationEmailProviderRequest, CreateNotificationEmailProviderResponse, CreateNotificationEmailProviderResponses, CreateNotificationProviderData, CreateNotificationProviderErrors, CreateNotificationProviderResponse, CreateNotificationProviderResponses, CreateOidcProviderData, CreateOidcProviderErrors, CreateOidcProviderRequest, CreateOidcProviderResponse, CreateOidcProviderResponses, CreateOidcRoleMappingData, CreateOidcRoleMappingRequest, CreateOidcRoleMappingResponse, CreateOidcRoleMappingResponses, CreateOrRecreateOrderData, CreateOrRecreateOrderErrors, CreateOrRecreateOrderResponse, CreateOrRecreateOrderResponses, CreatePlanData, CreatePlanErrors, CreatePlanRequest, CreatePlanResponse, CreatePlanResponse2, CreatePlanResponses, CreatePrData, CreatePrErrors, CreateProjectAccessRequest, CreateProjectData, CreateProjectErrors, CreateProjectFromTemplateData, CreateProjectFromTemplateErrors, CreateProjectFromTemplateRequest, CreateProjectFromTemplateResponse, CreateProjectFromTemplateResponse2, CreateProjectFromTemplateResponses, CreateProjectReleaseData, CreateProjectReleaseErrors, CreateProjectReleaseResponse, CreateProjectReleaseResponses, CreateProjectRequest, CreateProjectResponse, CreateProjectResponses, CreateProjectSecretData, CreateProjectSecretErrors, CreateProjectSecretRequest, CreateProjectSecretResponse, CreateProjectSecretResponses, CreateProviderKeyData, CreateProviderKeyError, CreateProviderKeyErrors, CreateProviderKeyRequest, CreateProviderKeyResponse, CreateProviderKeyResponses, CreateProviderRequest, CreatePrResponse, CreatePrResponse2, CreatePrResponses, CreateReleaseData, CreateReleaseErrors, CreateReleaseResponse, CreateReleaseResponses, CreateRouteData, CreateRouteErrors, CreateRouteRequest, CreateRouteResponse, CreateRouteResponses, CreateS3SourceData, CreateS3SourceError, CreateS3SourceErrors, CreateS3SourceRequest, CreateS3SourceResponse, CreateS3SourceResponses, CreateSandboxBody, CreateSandboxData, CreateSandboxErrors, CreateSandboxResponse, CreateSandboxResponses, CreateServiceData, CreateServiceErrors, CreateServiceResponse, CreateServiceResponses, CreateSkillData, CreateSkillErrors, CreateSkillRequest, CreateSkillResponse, CreateSkillResponses, CreateSlackProviderData, CreateSlackProviderErrors, CreateSlackProviderRequest, CreateSlackProviderResponse, CreateSlackProviderResponses, CreateTeamData, CreateTeamErrors, CreateTeamMemberRequest, CreateTeamRequest, CreateTeamResponse, CreateTeamResponses, CreateUserData, CreateUserErrors, CreateUserRequest, CreateUserResponse, CreateUserResponses, CreateWebhookData, CreateWebhookErrors, CreateWebhookProviderData, CreateWebhookProviderErrors, CreateWebhookProviderRequest, CreateWebhookProviderResponse, CreateWebhookProviderResponses, CreateWebhookRequestBody, CreateWebhookResponse, CreateWebhookResponses, CronExecutionInfo, CronInfo, CrossProjectSiblingRef, CrossProjectTraceResponse, CurrentStatusResponse, CustomDomainRequest, CustomDomainResponse, CustomerMovementResponse, DashboardLayout, DashboardProjectsAnalyticsQuery, DashboardProjectsAnalyticsResponse, DashboardSection, DashboardTile, DatabaseMetricsResponse, DatabaseMetricsRow, DataImplication, DataImplicationSeverity, DeactivateApiKeyData, DeactivateApiKeyErrors, DeactivateApiKeyResponse, DeactivateApiKeyResponses, DeactivateConnectionData, DeactivateConnectionErrors, DeactivateConnectionResponses, DeactivateProviderData, DeactivateProviderErrors, DeactivateProviderResponses, DeleteAgentData, DeleteAgentErrors, DeleteAgentResponse, DeleteAgentResponses, DeleteAlertData, DeleteAlertError, DeleteAlertErrors, DeleteAlertResponse, DeleteAlertResponses, DeleteAlertRuleData, DeleteAlertRuleErrors, DeleteAlertRuleResponse, DeleteAlertRuleResponses, DeleteApiKeyData, DeleteApiKeyErrors, DeleteApiKeyResponse, DeleteApiKeyResponses, DeleteBackupData, DeleteBackupError, DeleteBackupErrors, DeleteBackupResponse, DeleteBackupResponses, DeleteBackupScheduleData, DeleteBackupScheduleError, DeleteBackupScheduleErrors, DeleteBackupScheduleResponse, DeleteBackupScheduleResponses, DeleteBlobRequest, DeleteBlobResponse, DeleteConnectionData, DeleteConnectionErrors, DeleteConnectionResponse, DeleteConnectionResponses, DeleteCustomDomainData, DeleteCustomDomainErrors, DeleteCustomDomainResponse, DeleteCustomDomainResponses, DeleteDashboardData, DeleteDashboardError, DeleteDashboardErrors, DeleteDashboardResponse, DeleteDashboardResponses, DeleteDeploymentTokenData, DeleteDeploymentTokenErrors, DeleteDeploymentTokenResponse, DeleteDeploymentTokenResponses, DeleteDnsProviderData, DeleteDnsProviderErrors, DeleteDnsProviderResponse, DeleteDnsProviderResponses, DeleteDomainData, DeleteDomainErrors, DeleteDomainResponse, DeleteDomainResponses, DeleteEmailDomainData, DeleteEmailDomainErrors, DeleteEmailDomainResponse, DeleteEmailDomainResponses, DeleteEmailProviderData, DeleteEmailProviderErrors, DeleteEmailProviderResponse, DeleteEmailProviderResponses, DeleteEnvironmentData, DeleteEnvironmentDomainData, DeleteEnvironmentDomainErrors, DeleteEnvironmentDomainResponse, DeleteEnvironmentDomainResponses, DeleteEnvironmentErrors, DeleteEnvironmentResponse, DeleteEnvironmentResponses, DeleteEnvironmentVariableData, DeleteEnvironmentVariableErrors, DeleteEnvironmentVariableResponse, DeleteEnvironmentVariableResponses, DeleteExternalImageData, DeleteExternalImageErrors, DeleteExternalImageResponse, DeleteExternalImageResponses, DeleteFunnelData, DeleteFunnelErrors, DeleteFunnelResponses, DeleteGitProviderData, DeleteGitProviderErrors, DeleteGitProviderResponse, DeleteGitProviderResponses, DeleteGlobalMcpData, DeleteGlobalMcpErrors, DeleteGlobalMcpResponse, DeleteGlobalMcpResponses, DeleteGlobalSkillData, DeleteGlobalSkillErrors, DeleteGlobalSkillResponse, DeleteGlobalSkillResponses, DeleteIpAccessControlData, DeleteIpAccessControlError, DeleteIpAccessControlErrors, DeleteIpAccessControlResponse, DeleteIpAccessControlResponses, DeleteMcpData, DeleteMcpErrors, DeleteMcpResponse, DeleteMcpResponses, DeleteMonitorData, DeleteMonitorErrors, DeleteMonitorResponse, DeleteMonitorResponses, DeleteNotificationProviderData, DeleteNotificationProviderErrors, DeleteNotificationProviderResponse, DeleteNotificationProviderResponses, DeleteOidcProviderData, DeleteOidcProviderResponse, DeleteOidcProviderResponses, DeleteOidcRoleMappingData, DeleteOidcRoleMappingResponse, DeleteOidcRoleMappingResponses, DeletePreferencesData, DeletePreferencesErrors, DeletePreferencesResponse, DeletePreferencesResponses, DeleteProjectData, DeleteProjectErrors, DeleteProjectResponse, DeleteProjectResponses, DeleteProjectSecretData, DeleteProjectSecretErrors, DeleteProjectSecretResponse, DeleteProjectSecretResponses, DeleteProviderKeyData, DeleteProviderKeyError, DeleteProviderKeyErrors, DeleteProviderKeyResponse, DeleteProviderKeyResponses, DeleteProviderSafelyData, DeleteProviderSafelyErrors, DeleteProviderSafelyResponse, DeleteProviderSafelyResponses, DeleteReleaseSourceFilesData, DeleteReleaseSourceFilesErrors, DeleteReleaseSourceFilesResponse, DeleteReleaseSourceFilesResponses, DeleteReleaseSourceMapsData, DeleteReleaseSourceMapsErrors, DeleteReleaseSourceMapsResponse, DeleteReleaseSourceMapsResponses, DeleteResponse, DeleteRouteData, DeleteRouteErrors, DeleteRouteResponse, DeleteRouteResponses, DeleteS3SourceData, DeleteS3SourceError, DeleteS3SourceErrors, DeleteS3SourceResponse, DeleteS3SourceResponses, DeleteScanData, DeleteScanError, DeleteScanErrors, DeleteScanResponse, DeleteScanResponses, DeleteSecretData, DeleteSecretErrors, DeleteSecretResponse, DeleteSecretResponses, DeleteServiceData, DeleteServiceErrors, DeleteServiceResponse, DeleteServiceResponses, DeleteSessionReplayData, DeleteSessionReplayError, DeleteSessionReplayErrors, DeleteSessionReplayResponses, DeleteSkillData, DeleteSkillErrors, DeleteSkillResponse, DeleteSkillResponses, DeleteSourceMapData, DeleteSourceMapErrors, DeleteSourceMapResponse, DeleteSourceMapResponses, DeleteStaticBundleData, DeleteStaticBundleErrors, DeleteStaticBundleResponse, DeleteStaticBundleResponses, DeleteTeamData, DeleteTeamErrors, DeleteTeamResponse, DeleteTeamResponses, DeleteUserData, DeleteUserErrors, DeleteUserResponse, DeleteUserResponses, DeleteWebhookData, DeleteWebhookErrors, DeleteWebhookResponse, DeleteWebhookResponses, DelRequest, DelResponse, DeployFromImageData, DeployFromImageErrors, DeployFromImageRequest, DeployFromImageResponse, DeployFromImageResponses, DeployFromImageUploadData, DeployFromImageUploadErrors, DeployFromImageUploadQuery, DeployFromImageUploadResponse, DeployFromImageUploadResponses, DeployFromStaticData, DeployFromStaticErrors, DeployFromStaticRequest, DeployFromStaticResponse, DeployFromStaticResponses, DeployFromUploadedSourceData, DeployFromUploadedSourceErrors, DeployFromUploadedSourceResponse, DeployFromUploadedSourceResponses, DeploymentConfig, DeploymentConfigSnapshot, DeploymentConfiguration, DeploymentContainerLogContentResponse, DeploymentContainerLogResponse, DeploymentContainerLogsListResponse, DeploymentEnvironmentResponse, DeploymentJobResponse, DeploymentJobsResponse, DeploymentListResponse, DeploymentMetadata, DeploymentMetricsGetLatestData, DeploymentMetricsGetLatestErrors, DeploymentMetricsGetLatestResponse, DeploymentMetricsGetLatestResponses, DeploymentMetricsGetRangeData, DeploymentMetricsGetRangeErrors, DeploymentMetricsGetRangeResponse, DeploymentMetricsGetRangeResponses, DeploymentMetricsToggleData, DeploymentMetricsToggleErrors, DeploymentMetricsToggleResponses, DeploymentResponse, DeploymentStateResponse, DeploymentStrategy, DeploymentTokenListResponse, DeploymentTokenResponse, DestroySandboxData, DestroySandboxErrors, DestroySandboxResponse, DestroySandboxResponses, DetachScheduleServiceData, DetachScheduleServiceError, DetachScheduleServiceErrors, DetachScheduleServiceResponse, DetachScheduleServiceResponses, DetectionConfig, DetectPublicPresetsData, DetectPublicPresetsErrors, DetectPublicPresetsResponse, DetectPublicPresetsResponses, DeviceCount, DigestSections, Direction, DisableBackupScheduleData, DisableBackupScheduleErrors, DisableBackupScheduleResponse, DisableBackupScheduleResponses, DisableBlobResponse, DisableKvResponse, DisableMfaData, DisableMfaErrors, DisableMfaRequest, DisableMfaResponse, DisableMfaResponses, DiscoverRequest, DiscoverResponse, DiscoverWorkloadsData, DiscoverWorkloadsErrors, DiscoverWorkloadsResponse, DiscoverWorkloadsResponses, DiskInfo, DiskSpaceAlert, DiskSpaceAlertSettings, DiskSpaceCheckResult, DnsAckRequest, DnsAckResponse, DnsChallengeRecordResult, DnsChangesResponse, DnsCompletionResponse, DnsLookupError, DnsLookupRequest, DnsLookupResponse, DnsProviderCredentials, DnsProviderResponse, DnsProviderSettings, DnsProviderSettingsMasked, DnsProviderType, DnsRecord, DnsRecordChange, DnsRecordContent, DnsRecordResponse, DnsRecordSetupResult, DnsRecordStatusResponse, DnsZone, DockerComposePresetConfig, DockerfilePresetConfig, DockerfileVariant, DockerRegistrySettings, DockerRegistrySettingsMasked, DomainAction, DomainChallengeResponse, DomainData, DomainEnvironmentResponse, DomainError, DomainErrors, DomainPlan, DomainResponse, DomainResponse2, DomainResponses, DownloadGlobalSkillArchiveData, DownloadGlobalSkillArchiveErrors, DownloadGlobalSkillArchiveResponse, DownloadGlobalSkillArchiveResponses, DownloadObjectData, DownloadObjectErrors, DownloadObjectResponse, DownloadObjectResponses, DownloadSkillArchiveData, DownloadSkillArchiveErrors, DownloadSkillArchiveResponse, DownloadSkillArchiveResponses, DrainNodeResponse, DrainStatusResponse, DropArchiveUpload, DropInspectionResponse, DropOffPoint, DropPresetCandidate, EmailConfig, EmailDomainResponse, EmailDomainWithDnsResponse, EmailProviderResponse, EmailProviderTypeRoute, EmailRequest, EmailResponse, EmailStatsResponse, EmailStatusData, EmailStatusErrors, EmailStatusResponse, EmailStatusResponse2, EmailStatusResponses, EmailTrackingResponse, EmailTrackingSetupResponse, EmailTrackingStatusResponse, EmbeddingData, EmbeddingInput, EmbeddingRequest, EmbeddingResponse, EmbeddingsData, EmbeddingsError, EmbeddingsErrors, EmbeddingsResponse, EmbeddingsResponses, EmbeddingUsage, EnableBackupScheduleData, EnableBackupScheduleErrors, EnableBackupScheduleResponse, EnableBackupScheduleResponses, EnableBlobRequest, EnableBlobResponse, EnableKvRequest, EnableKvResponse, EnablePgStatStatementsResponse, EndpointDto, EnqueuedJob, EnrichVisitorData, EnrichVisitorErrors, EnrichVisitorRequest, EnrichVisitorResponse, EnrichVisitorResponse2, EnrichVisitorResponses, EnrollmentTokenInfo, EnrollmentTokenListResponse, EntityInfoResponse, EntityResponse, EnvironmentConfiguration, EnvironmentDomainResponse, EnvironmentInfo, EnvironmentResponse, EnvironmentVariable, EnvironmentVariableInfo, EnvironmentVariableResponse, EnvironmentVariableValueResponse, EnvVarInput, EnvVarIntegrationInfo, EnvVarResponse, EnvVarTemplateResponse, ErrorDashboardStatsQuery, ErrorDashboardStatsResponse, ErrorEventResponse, ErrorGroupResponse, ErrorGroupStatsResponse, ErrorResponse, ErrorRow, ErrorTimeSeriesDataResponse, ErrorTimeSeriesQuery, EventActivityBucket, EventBreakdown, EventBrowserStats, EventCount, EventCountryStats, EventDetailQuery, EventDetailResponse, EventEntriesQuery, EventEntriesResponse, EventEntryInfo, EventKind, EventMetricsPayload, EventReferrerStats, EventsCountQuery, EventsResponse, EventTimeline, EventTimelineQuery, EventType, EventTypeBreakdown, EventTypeBreakdownQuery, EventTypeResponse, EventTypesResponse, EventVisitorInfo, EventVisitorsQuery, EventVisitorsResponse, ExecBody, ExecData, ExecDetachedData, ExecDetachedErrors, ExecDetachedResponse, ExecDetachedResponse2, ExecDetachedResponses, ExecErrors, ExecResponse, ExecResponse2, ExecResponses, ExecuteDeploymentOperationData, ExecuteDeploymentOperationErrors, ExecuteDeploymentOperationResponse, ExecuteDeploymentOperationResponses, ExecuteImportData, ExecuteImportErrors, ExecuteImportRequest, ExecuteImportResponse, ExecuteImportResponse2, ExecuteImportResponses, ExecuteOperationRequest, ExpireRequest, ExpireResponse, ExplorerSupportResponse, ExtendTimeoutBody, ExtendTimeoutData, ExtendTimeoutErrors, ExtendTimeoutResponse, ExtendTimeoutResponses, ExternalImageResponse, ExternalServiceBackupResponse, ExternalServiceDetails, ExternalServiceEnablePgStatStatementsData, ExternalServiceEnablePgStatStatementsErrors, ExternalServiceEnablePgStatStatementsResponse, ExternalServiceEnablePgStatStatementsResponses, ExternalServiceInfo, ExternalServiceMetricsByDatabaseData, ExternalServiceMetricsByDatabaseErrors, ExternalServiceMetricsByDatabaseResponse, ExternalServiceMetricsByDatabaseResponses, ExternalServiceMetricsCreateAlertRuleData, ExternalServiceMetricsCreateAlertRuleErrors, ExternalServiceMetricsCreateAlertRuleResponse, ExternalServiceMetricsCreateAlertRuleResponses, ExternalServiceMetricsDeleteAlertRuleData, ExternalServiceMetricsDeleteAlertRuleErrors, ExternalServiceMetricsDeleteAlertRuleResponse, ExternalServiceMetricsDeleteAlertRuleResponses, ExternalServiceMetricsGetAlertRulesData, ExternalServiceMetricsGetAlertRulesErrors, ExternalServiceMetricsGetAlertRulesResponse, ExternalServiceMetricsGetAlertRulesResponses, ExternalServiceMetricsGetLatestData, ExternalServiceMetricsGetLatestErrors, ExternalServiceMetricsGetLatestResponse, ExternalServiceMetricsGetLatestResponses, ExternalServiceMetricsGetRangeData, ExternalServiceMetricsGetRangeErrors, ExternalServiceMetricsGetRangeResponse, ExternalServiceMetricsGetRangeResponses, ExternalServiceMetricsStatusData, ExternalServiceMetricsStatusErrors, ExternalServiceMetricsStatusResponse, ExternalServiceMetricsStatusResponses, ExternalServiceMetricsToggleData, ExternalServiceMetricsToggleErrors, ExternalServiceMetricsToggleResponses, ExternalServiceMetricsUpdateAlertRuleData, ExternalServiceMetricsUpdateAlertRuleErrors, ExternalServiceMetricsUpdateAlertRuleResponse, ExternalServiceMetricsUpdateAlertRuleResponses, ExternalServiceResetPgStatStatementsData, ExternalServiceResetPgStatStatementsErrors, ExternalServiceResetPgStatStatementsResponse, ExternalServiceResetPgStatStatementsResponses, ExternalServiceSummary, FieldResponse, FinalizeOrderData, FinalizeOrderErrors, FinalizeOrderResponse, FinalizeOrderResponses, FinalizeProjectReleaseData, FinalizeProjectReleaseErrors, FinalizeProjectReleaseResponse, FinalizeProjectReleaseResponses, FindConversationData, FindConversationErrors, FindConversationResponse, FindConversationResponses, FiringSeriesEntry, FlagEnvironmentResponse, FlagListResponse, FlagResponse, FlagSnapshot, FlagSnapshotResponse, FlagValueType, ForecastAlgorithm, ForecastParams, FullError, FullEvent, FullRequest, FunnelMetricsResponse, FunnelResponse, GatewayStatus, GenAiEvent, GenAiSpanDetail, GenAiTraceDetailResponse, GenAiTraceSummariesResponse, GenAiTraceSummary, GeneralStatsQuery, GeneralStatsResponse, GenerateDockerfileRequest, GenerateDockerfileResponse, GenerateJoinTokenData, GenerateJoinTokenErrors, GenerateJoinTokenResponse, GenerateJoinTokenResponse2, GenerateJoinTokenResponses, GeneratePresetDockerfileData, GeneratePresetDockerfileErrors, GeneratePresetDockerfileResponse, GeneratePresetDockerfileResponses, GeoLocationResponse, GeoRestrictionsConfig, GetAccessInfoData, GetAccessInfoErrors, GetAccessInfoResponse, GetAccessInfoResponses, GetActiveVisitorsData, GetActiveVisitorsErrors, GetActiveVisitorsResponse, GetActiveVisitorsResponses, GetActivityGraphData, GetActivityGraphErrors, GetActivityGraphResponse, GetActivityGraphResponses, GetAdminGateData, GetAdminGateErrors, GetAdminGateResponse, GetAdminGateResponses, GetAgentData, GetAgentErrors, GetAgentResponse, GetAgentResponses, GetAggregatedBucketsData, GetAggregatedBucketsErrors, GetAggregatedBucketsResponse, GetAggregatedBucketsResponses, GetAiAgentBreakdownData, GetAiAgentBreakdownError, GetAiAgentBreakdownErrors, GetAiAgentBreakdownResponse, GetAiAgentBreakdownResponses, GetAiAgentPagesData, GetAiAgentPagesError, GetAiAgentPagesErrors, GetAiAgentPagesResponse, GetAiAgentPagesResponses, GetAiAgentTimelineData, GetAiAgentTimelineError, GetAiAgentTimelineErrors, GetAiAgentTimelineResponse, GetAiAgentTimelineResponses, GetAiPageBreakdownData, GetAiPageBreakdownError, GetAiPageBreakdownErrors, GetAiPageBreakdownResponse, GetAiPageBreakdownResponses, GetAiStatusBreakdownData, GetAiStatusBreakdownError, GetAiStatusBreakdownErrors, GetAiStatusBreakdownResponse, GetAiStatusBreakdownResponses, GetAlertData, GetAlertError, GetAlertErrors, GetAlertResponse, GetAlertResponses, GetAlertRuleData, GetAlertRuleErrors, GetAlertRuleResponse, GetAlertRuleResponses, GetAllRepositoriesByNameData, GetAllRepositoriesByNameErrors, GetAllRepositoriesByNameResponse, GetAllRepositoriesByNameResponses, GetAnalyticsActiveVisitorsData, GetAnalyticsActiveVisitorsErrors, GetAnalyticsActiveVisitorsResponse, GetAnalyticsActiveVisitorsResponses, GetAnalyticsEventsCountData, GetAnalyticsEventsCountErrors, GetAnalyticsEventsCountResponse, GetAnalyticsEventsCountResponses, GetAnalyticsSessionEventsData, GetAnalyticsSessionEventsErrors, GetAnalyticsSessionEventsResponse, GetAnalyticsSessionEventsResponses, GetAnalyticsVisitorSessionsData, GetAnalyticsVisitorSessionsErrors, GetAnalyticsVisitorSessionsResponse, GetAnalyticsVisitorSessionsResponses, GetApiKeyData, GetApiKeyErrors, GetApiKeyPermissionsData, GetApiKeyPermissionsErrors, GetApiKeyPermissionsResponse, GetApiKeyPermissionsResponses, GetApiKeyResponse, GetApiKeyResponses, GetAuditLogData, GetAuditLogErrors, GetAuditLogResponse, GetAuditLogResponses, GetBackupData, GetBackupError, GetBackupErrors, GetBackupResponse, GetBackupResponses, GetBackupScheduleData, GetBackupScheduleErrors, GetBackupScheduleResponse, GetBackupScheduleResponses, GetBranchesByRepositoryIdData, GetBranchesByRepositoryIdErrors, GetBranchesByRepositoryIdResponse, GetBranchesByRepositoryIdResponses, GetBucketedIncidentsData, GetBucketedIncidentsErrors, GetBucketedIncidentsResponse, GetBucketedIncidentsResponses, GetBucketedStatusData, GetBucketedStatusErrors, GetBucketedStatusResponse, GetBucketedStatusResponses, GetChallengeTokenData, GetChallengeTokenErrors, GetChallengeTokenResponse, GetChallengeTokenResponses, GetChatReadinessData, GetChatReadinessErrors, GetChatReadinessResponse, GetChatReadinessResponses, GetCliStatusData, GetCliStatusErrors, GetCliStatusResponses, GetClusterHealthData, GetClusterHealthErrors, GetClusterHealthResponse, GetClusterHealthResponses, GetClusterMemberData, GetClusterMemberErrors, GetClusterMemberResponse, GetClusterMemberResponses, GetCmdData, GetCmdErrors, GetCmdResponse, GetCmdResponses, GetContainerDetailData, GetContainerDetailErrors, GetContainerDetailResponse, GetContainerDetailResponses, GetContainerEnvironmentVariableData, GetContainerEnvironmentVariableErrors, GetContainerEnvironmentVariableResponse, GetContainerEnvironmentVariableResponses, GetContainerInfoData, GetContainerInfoErrors, GetContainerInfoResponse, GetContainerInfoResponses, GetContainerLogsByIdData, GetContainerLogsByIdErrors, GetContainerLogsData, GetContainerLogsErrors, GetContainerMetricsData, GetContainerMetricsErrors, GetContainerMetricsResponse, GetContainerMetricsResponses, GetConversationData, GetConversationDetailData, GetConversationDetailError, GetConversationDetailErrors, GetConversationDetailResponse, GetConversationDetailResponses, GetConversationErrors, GetConversationResponse, GetConversationResponses, GetConversationsData, GetConversationsError, GetConversationsErrors, GetConversationsResponse, GetConversationsResponses, GetCronByIdData, GetCronByIdErrors, GetCronByIdResponse, GetCronByIdResponses, GetCronExecutionsData, GetCronExecutionsErrors, GetCronExecutionsResponse, GetCronExecutionsResponses, GetCrossProjectTraceSiblingsData, GetCrossProjectTraceSiblingsError, GetCrossProjectTraceSiblingsErrors, GetCrossProjectTraceSiblingsResponse, GetCrossProjectTraceSiblingsResponses, GetCurrentMonitorStatusData, GetCurrentMonitorStatusErrors, GetCurrentMonitorStatusResponse, GetCurrentMonitorStatusResponses, GetCurrentUserData, GetCurrentUserErrors, GetCurrentUserResponse, GetCurrentUserResponses, GetCustomDomainData, GetCustomDomainErrors, GetCustomDomainResponse, GetCustomDomainResponses, GetDashboardData, GetDashboardError, GetDashboardErrors, GetDashboardProjectsAnalyticsData, GetDashboardProjectsAnalyticsErrors, GetDashboardProjectsAnalyticsResponse, GetDashboardProjectsAnalyticsResponses, GetDashboardResponse, GetDashboardResponses, GetDeliveryData, GetDeliveryErrors, GetDeliveryResponse, GetDeliveryResponses, GetDeploymentContainerLogContentData, GetDeploymentContainerLogContentErrors, GetDeploymentContainerLogContentResponse, GetDeploymentContainerLogContentResponses, GetDeploymentData, GetDeploymentErrors, GetDeploymentJobLogsData, GetDeploymentJobLogsErrors, GetDeploymentJobLogsResponse, GetDeploymentJobLogsResponses, GetDeploymentJobsData, GetDeploymentJobsErrors, GetDeploymentJobsResponse, GetDeploymentJobsResponses, GetDeploymentOperationsData, GetDeploymentOperationsErrors, GetDeploymentOperationsResponse, GetDeploymentOperationsResponses, GetDeploymentOperationStatusData, GetDeploymentOperationStatusErrors, GetDeploymentOperationStatusResponse, GetDeploymentOperationStatusResponses, GetDeploymentResponse, GetDeploymentResponses, GetDeploymentsParams, GetDeploymentTokenData, GetDeploymentTokenErrors, GetDeploymentTokenResponse, GetDeploymentTokenResponses, GetDiskStatusData, GetDiskStatusErrors, GetDiskStatusResponse, GetDiskStatusResponses, GetDnsChangesData, GetDnsChangesErrors, GetDnsChangesResponse, GetDnsChangesResponses, GetDnsProviderData, GetDnsProviderErrors, GetDnsProviderResponse, GetDnsProviderResponses, GetDomainByHostData, GetDomainByHostErrors, GetDomainByHostResponse, GetDomainByHostResponses, GetDomainByIdData, GetDomainByIdErrors, GetDomainByIdResponse, GetDomainByIdResponses, GetDomainByNameData, GetDomainByNameErrors, GetDomainByNameResponse, GetDomainByNameResponses, GetDomainData, GetDomainDnsRecordsData, GetDomainDnsRecordsErrors, GetDomainDnsRecordsResponse, GetDomainDnsRecordsResponses, GetDomainErrors, GetDomainOrderData, GetDomainOrderErrors, GetDomainOrderResponse, GetDomainOrderResponses, GetDomainResponse, GetDomainResponses, GetEmailData, GetEmailErrors, GetEmailEventsData, GetEmailEventsErrors, GetEmailEventsResponse, GetEmailEventsResponses, GetEmailLinksData, GetEmailLinksErrors, GetEmailLinksResponse, GetEmailLinksResponses, GetEmailProviderData, GetEmailProviderErrors, GetEmailProviderResponse, GetEmailProviderResponses, GetEmailResponse, GetEmailResponses, GetEmailStatsData, GetEmailStatsErrors, GetEmailStatsResponse, GetEmailStatsResponses, GetEmailTrackingData, GetEmailTrackingErrors, GetEmailTrackingResponse, GetEmailTrackingResponses, GetEmailTrackingStatusData, GetEmailTrackingStatusErrors, GetEmailTrackingStatusResponse, GetEmailTrackingStatusResponses, GetEntityInfoData, GetEntityInfoErrors, GetEntityInfoResponse, GetEntityInfoResponses, GetEnvironmentCronsData, GetEnvironmentCronsErrors, GetEnvironmentCronsResponse, GetEnvironmentCronsResponses, GetEnvironmentData, GetEnvironmentDomainsData, GetEnvironmentDomainsErrors, GetEnvironmentDomainsResponse, GetEnvironmentDomainsResponses, GetEnvironmentErrors, GetEnvironmentResponse, GetEnvironmentResponses, GetEnvironmentsData, GetEnvironmentsErrors, GetEnvironmentsResponse, GetEnvironmentsResponses, GetEnvironmentVariablesData, GetEnvironmentVariablesErrors, GetEnvironmentVariablesQuery, GetEnvironmentVariablesResponse, GetEnvironmentVariablesResponses, GetEnvironmentVariableValueData, GetEnvironmentVariableValueErrors, GetEnvironmentVariableValueResponse, GetEnvironmentVariableValueResponses, GetErrorDashboardStatsData, GetErrorDashboardStatsErrors, GetErrorDashboardStatsResponse, GetErrorDashboardStatsResponses, GetErrorEventData, GetErrorEventErrors, GetErrorEventResponse, GetErrorEventResponses, GetErrorGroupData, GetErrorGroupErrors, GetErrorGroupResponse, GetErrorGroupResponses, GetErrorStatsData, GetErrorStatsErrors, GetErrorStatsResponse, GetErrorStatsResponses, GetErrorTimeSeriesData, GetErrorTimeSeriesErrors, GetErrorTimeSeriesResponse, GetErrorTimeSeriesResponses, GetEventDetailData, GetEventDetailErrors, GetEventDetailResponse, GetEventDetailResponses, GetEventEntriesData, GetEventEntriesErrors, GetEventEntriesResponse, GetEventEntriesResponses, GetEventsCountData, GetEventsCountErrors, GetEventsCountResponse, GetEventsCountResponses, GetEventsTimelineData, GetEventsTimelineErrors, GetEventsTimelineResponse, GetEventsTimelineResponses, GetEventTypeBreakdownData, GetEventTypeBreakdownErrors, GetEventTypeBreakdownResponse, GetEventTypeBreakdownResponses, GetEventVisitorsData, GetEventVisitorsErrors, GetEventVisitorsResponse, GetEventVisitorsResponses, GetExternalImageData, GetExternalImageErrors, GetExternalImageResponse, GetExternalImageResponses, GetFileData, GetFileErrors, GetFileResponse, GetFileResponses, GetFlagData, GetFlagErrors, GetFlagResponse, GetFlagResponses, GetFlagSnapshotData, GetFlagSnapshotErrors, GetFlagSnapshotResponse, GetFlagSnapshotResponses, GetFunnelMetricsData, GetFunnelMetricsErrors, GetFunnelMetricsQuery, GetFunnelMetricsResponse, GetFunnelMetricsResponses, GetGenaiTraceData, GetGenaiTraceError, GetGenaiTraceErrors, GetGenaiTraceResponse, GetGenaiTraceResponses, GetGeneralStatsData, GetGeneralStatsErrors, GetGeneralStatsResponse, GetGeneralStatsResponses, GetGitProviderData, GetGitProviderErrors, GetGitProviderResponse, GetGitProviderResponses, GetGlobalEventsData, GetGlobalEventsErrors, GetGlobalEventsResponse, GetGlobalEventsResponses, GetGlobalEventStatsData, GetGlobalEventStatsErrors, GetGlobalEventStatsResponse, GetGlobalEventStatsResponses, GetGlobalMcpData, GetGlobalMcpErrors, GetGlobalMcpResponse, GetGlobalMcpResponses, GetGlobalSandboxStatusData, GetGlobalSandboxStatusErrors, GetGlobalSandboxStatusResponse, GetGlobalSandboxStatusResponses, GetGlobalSkillData, GetGlobalSkillErrors, GetGlobalSkillResponse, GetGlobalSkillResponses, GetGroupedPageMetricsData, GetGroupedPageMetricsError, GetGroupedPageMetricsErrors, GetGroupedPageMetricsResponse, GetGroupedPageMetricsResponses, GetHealthData, GetHealthError, GetHealthErrors, GetHealthResponse, GetHealthResponses, GetHourlyVisitsData, GetHourlyVisitsErrors, GetHourlyVisitsResponse, GetHourlyVisitsResponses, GetHttpChallengeDebugData, GetHttpChallengeDebugErrors, GetHttpChallengeDebugResponse, GetHttpChallengeDebugResponses, GetImportStatusData, GetImportStatusErrors, GetImportStatusResponse, GetImportStatusResponses, GetIncidentData, GetIncidentErrors, GetIncidentResponse, GetIncidentResponses, GetIncidentUpdatesData, GetIncidentUpdatesErrors, GetIncidentUpdatesResponse, GetIncidentUpdatesResponses, GetIpAccessControlData, GetIpAccessControlError, GetIpAccessControlErrors, GetIpAccessControlResponse, GetIpAccessControlResponses, GetIpGeolocationData, GetIpGeolocationError, GetIpGeolocationErrors, GetIpGeolocationResponse, GetIpGeolocationResponses, GetJoinTokenStatusData, GetJoinTokenStatusErrors, GetJoinTokenStatusResponse, GetJoinTokenStatusResponses, GetLastDeploymentData, GetLastDeploymentErrors, GetLastDeploymentResponse, GetLastDeploymentResponses, GetLatestScanData, GetLatestScanError, GetLatestScanErrors, GetLatestScanResponse, GetLatestScanResponses, GetLatestScansPerEnvironmentData, GetLatestScansPerEnvironmentError, GetLatestScansPerEnvironmentErrors, GetLatestScansPerEnvironmentResponse, GetLatestScansPerEnvironmentResponses, GetLiveVisitorsListData, GetLiveVisitorsListErrors, GetLiveVisitorsListResponse, GetLiveVisitorsListResponses, GetLogContextData, GetLogContextError, GetLogContextErrors, GetLogContextResponse, GetLogContextResponses, GetMcpData, GetMcpErrors, GetMcpResponse, GetMcpResponses, GetMetricsOverTimeData, GetMetricsOverTimeError, GetMetricsOverTimeErrors, GetMetricsOverTimeResponse, GetMetricsOverTimeResponses, GetMonitorData, GetMonitorErrors, GetMonitorResponse, GetMonitorResponses, GetNotificationProviderData, GetNotificationProviderErrors, GetNotificationProviderResponse, GetNotificationProviderResponses, GetOnDemandCertStatusData, GetOnDemandCertStatusErrors, GetOnDemandCertStatusResponse, GetOnDemandCertStatusResponses, GetOrCreateDsnData, GetOrCreateDsnErrors, GetOrCreateDsnRequest, GetOrCreateDsnResponse, GetOrCreateDsnResponses, GetPageFlowData, GetPageFlowErrors, GetPageFlowResponse, GetPageFlowResponses, GetPageHourlySessionsData, GetPageHourlySessionsErrors, GetPageHourlySessionsResponse, GetPageHourlySessionsResponses, GetPagePathDetailData, GetPagePathDetailErrors, GetPagePathDetailResponse, GetPagePathDetailResponses, GetPagePathsData, GetPagePathsErrors, GetPagePathsResponse, GetPagePathsResponses, GetPagePathsSparklinesData, GetPagePathsSparklinesErrors, GetPagePathsSparklinesResponse, GetPagePathsSparklinesResponses, GetPagePathVisitorsData, GetPagePathVisitorsErrors, GetPagePathVisitorsResponse, GetPagePathVisitorsResponses, GetPendingActionData, GetPendingActionErrors, GetPendingActionResponse, GetPendingActionResponses, GetPerformanceMetricsData, GetPerformanceMetricsError, GetPerformanceMetricsErrors, GetPerformanceMetricsResponse, GetPerformanceMetricsResponses, GetPgUpgradeData, GetPgUpgradeErrors, GetPgUpgradeLogsData, GetPgUpgradeLogsErrors, GetPgUpgradeLogsResponse, GetPgUpgradeLogsResponses, GetPgUpgradeResponse, GetPgUpgradeResponses, GetPipelineStatsData, GetPipelineStatsError, GetPipelineStatsErrors, GetPipelineStatsResponse, GetPipelineStatsResponses, GetPlatformInfoData, GetPlatformInfoErrors, GetPlatformInfoResponse, GetPlatformInfoResponses, GetPostgresWalHealthData, GetPostgresWalHealthErrors, GetPostgresWalHealthResponse, GetPostgresWalHealthResponses, GetPreferencesData, GetPreferencesErrors, GetPreferencesResponse, GetPreferencesResponses, GetPreviewGatewayLogsData, GetPreviewGatewayLogsResponse, GetPreviewGatewayLogsResponses, GetPreviewGatewaySettingsData, GetPreviewGatewaySettingsResponse, GetPreviewGatewaySettingsResponses, GetPreviewGatewayStatusData, GetPreviewGatewayStatusResponse, GetPreviewGatewayStatusResponses, GetPricingData, GetPricingError, GetPricingErrors, GetPricingResponse, GetPricingResponses, GetPrivateIpData, GetPrivateIpErrors, GetPrivateIpResponses, GetProjectAlarmsSummaryData, GetProjectAlarmsSummaryErrors, GetProjectAlarmsSummaryResponse, GetProjectAlarmsSummaryResponses, GetProjectBySlugData, GetProjectBySlugErrors, GetProjectBySlugResponse, GetProjectBySlugResponses, GetProjectData, GetProjectDeploymentsData, GetProjectDeploymentsErrors, GetProjectDeploymentsResponse, GetProjectDeploymentsResponses, GetProjectErrors, GetProjectResponse, GetProjectResponses, GetProjectsData, GetProjectSecretsQuery, GetProjectsErrors, GetProjectServiceEnvironmentVariablesData, GetProjectServiceEnvironmentVariablesErrors, GetProjectServiceEnvironmentVariablesResponse, GetProjectServiceEnvironmentVariablesResponses, GetProjectSessionReplaysData, GetProjectSessionReplaysError, GetProjectSessionReplaysErrors, GetProjectSessionReplaysQuery, GetProjectSessionReplaysResponse, GetProjectSessionReplaysResponse2, GetProjectSessionReplaysResponses, GetProjectsHealthData, GetProjectsHealthError, GetProjectsHealthErrors, GetProjectsHealthResponse, GetProjectsHealthResponses, GetProjectsMonitorHealthData, GetProjectsMonitorHealthErrors, GetProjectsMonitorHealthResponse, GetProjectsMonitorHealthResponses, GetProjectsResponse, GetProjectsResponses, GetProjectStatisticsData, GetProjectStatisticsErrors, GetProjectStatisticsResponse, GetProjectStatisticsResponses, GetProjectTemplateData, GetProjectTemplateErrors, GetProjectTemplateResponse, GetProjectTemplateResponses, GetPropertyBreakdownData, GetPropertyBreakdownErrors, GetPropertyBreakdownResponse, GetPropertyBreakdownResponses, GetPropertyTimelineData, GetPropertyTimelineErrors, GetPropertyTimelineResponse, GetPropertyTimelineResponses, GetProviderConnectionsData, GetProviderConnectionsErrors, GetProviderConnectionsResponse, GetProviderConnectionsResponses, GetProviderMetadataData, GetProviderMetadataErrors, GetProviderMetadataResponse, GetProviderMetadataResponses, GetProvidersMetadataData, GetProvidersMetadataErrors, GetProvidersMetadataResponse, GetProvidersMetadataResponses, GetProxyLogByIdData, GetProxyLogByIdError, GetProxyLogByIdErrors, GetProxyLogByIdResponse, GetProxyLogByIdResponses, GetProxyLogByRequestIdData, GetProxyLogByRequestIdError, GetProxyLogByRequestIdErrors, GetProxyLogByRequestIdResponse, GetProxyLogByRequestIdResponses, GetProxyLogsData, GetProxyLogsError, GetProxyLogsErrors, GetProxyLogsResponse, GetProxyLogsResponses, GetPublicBranchesData, GetPublicBranchesErrors, GetPublicBranchesResponse, GetPublicBranchesResponses, GetPublicIpData, GetPublicIpErrors, GetPublicIpResponses, GetPublicRepositoryData, GetPublicRepositoryErrors, GetPublicRepositoryResponse, GetPublicRepositoryResponses, GetQuotaData, GetQuotaError, GetQuotaErrors, GetQuotaResponse, GetQuotaResponses, GetRecentActivityData, GetRecentActivityErrors, GetRecentActivityResponse, GetRecentActivityResponses, GetRemoteExternalImageData, GetRemoteExternalImageErrors, GetRemoteExternalImageResponse, GetRemoteExternalImageResponses, GetRepositoryBranchesData, GetRepositoryBranchesErrors, GetRepositoryBranchesResponse, GetRepositoryBranchesResponses, GetRepositoryByIdData, GetRepositoryByIdErrors, GetRepositoryByIdResponse, GetRepositoryByIdResponses, GetRepositoryByNameData, GetRepositoryByNameErrors, GetRepositoryByNameResponse, GetRepositoryByNameResponses, GetRepositoryPresetByNameData, GetRepositoryPresetByNameErrors, GetRepositoryPresetByNameResponse, GetRepositoryPresetByNameResponses, GetRepositoryPresetLiveData, GetRepositoryPresetLiveErrors, GetRepositoryPresetLiveResponse, GetRepositoryPresetLiveResponses, GetRepositoryTagsData, GetRepositoryTagsErrors, GetRepositoryTagsResponse, GetRepositoryTagsResponses, GetRequest, GetResolvedEnvironmentVariablesData, GetResolvedEnvironmentVariablesErrors, GetResolvedEnvironmentVariablesResponse, GetResolvedEnvironmentVariablesResponses, GetResolvedEnvironmentVariableValueData, GetResolvedEnvironmentVariableValueErrors, GetResolvedEnvironmentVariableValueResponse, GetResolvedEnvironmentVariableValueResponses, GetResponse, GetRestoreCapabilitiesData, GetRestoreCapabilitiesError, GetRestoreCapabilitiesErrors, GetRestoreCapabilitiesResponse, GetRestoreCapabilitiesResponses, GetRestoreRunData, GetRestoreRunError, GetRestoreRunErrors, GetRestoreRunResponse, GetRestoreRunResponses, GetRouteData, GetRouteErrors, GetRouteResponse, GetRouteResponses, GetRunData, GetRunErrors, GetRunResponse, GetRunResponses, GetRunWithLogsData, GetRunWithLogsErrors, GetRunWithLogsResponse, GetRunWithLogsResponses, GetS3CredentialsData, GetS3CredentialsErrors, GetS3CredentialsResponse, GetS3CredentialsResponses, GetS3SourceData, GetS3SourceError, GetS3SourceErrors, GetS3SourceResponse, GetS3SourceResponses, GetSandboxData, GetSandboxErrors, GetSandboxResponse, GetSandboxResponses, GetSandboxStatusData, GetSandboxStatusErrors, GetSandboxStatusResponse, GetSandboxStatusResponses, GetScanByDeploymentData, GetScanByDeploymentError, GetScanByDeploymentErrors, GetScanByDeploymentResponse, GetScanByDeploymentResponses, GetScanData, GetScanError, GetScanErrors, GetScanResponse, GetScanResponses, GetScanVulnerabilitiesData, GetScanVulnerabilitiesError, GetScanVulnerabilitiesErrors, GetScanVulnerabilitiesResponse, GetScanVulnerabilitiesResponses, GetServiceBySlugData, GetServiceBySlugErrors, GetServiceBySlugResponse, GetServiceBySlugResponses, GetServiceData, GetServiceEnvironmentVariableData, GetServiceEnvironmentVariableErrors, GetServiceEnvironmentVariableResponse, GetServiceEnvironmentVariableResponses, GetServiceEnvironmentVariablesData, GetServiceEnvironmentVariablesErrors, GetServiceEnvironmentVariablesResponse, GetServiceEnvironmentVariablesResponses, GetServiceErrors, GetServiceHealthStatusData, GetServiceHealthStatusErrors, GetServiceHealthStatusResponse, GetServiceHealthStatusResponses, GetServicePreviewEnvironmentVariableNamesData, GetServicePreviewEnvironmentVariableNamesErrors, GetServicePreviewEnvironmentVariableNamesResponse, GetServicePreviewEnvironmentVariableNamesResponses, GetServicePreviewEnvironmentVariablesMaskedData, GetServicePreviewEnvironmentVariablesMaskedErrors, GetServicePreviewEnvironmentVariablesMaskedResponse, GetServicePreviewEnvironmentVariablesMaskedResponses, GetServiceResponse, GetServiceResponses, GetServiceRuntimeData, GetServiceRuntimeErrors, GetServiceRuntimeResponse, GetServiceRuntimeResponses, GetServiceStatsData, GetServiceStatsErrors, GetServiceStatsResponse, GetServiceStatsResponses, GetServiceTypeParametersData, GetServiceTypeParametersErrors, GetServiceTypeParametersResponses, GetServiceTypesData, GetServiceTypesErrors, GetServiceTypesResponse, GetServiceTypesResponses, GetSessionDetailsData, GetSessionDetailsErrors, GetSessionDetailsResponse, GetSessionDetailsResponses, GetSessionEventsData, GetSessionEventsErrors, GetSessionEventsResponse, GetSessionEventsResponses, GetSessionLogsData, GetSessionLogsErrors, GetSessionLogsResponse, GetSessionLogsResponses, GetSessionReplayData, GetSessionReplayError, GetSessionReplayErrors, GetSessionReplayEventsData, GetSessionReplayEventsError, GetSessionReplayEventsErrors, GetSessionReplayEventsResponse, GetSessionReplayEventsResponses, GetSessionReplayResponse, GetSessionReplayResponse2, GetSessionReplayResponses, GetSettingsData, GetSettingsErrors, GetSettingsResponse, GetSettingsResponses, GetSkillData, GetSkillErrors, GetSkillResponse, GetSkillResponses, GetSlowQueriesData, GetSlowQueriesErrors, GetSlowQueriesResponse, GetSlowQueriesResponses, GetStaticBundleData, GetStaticBundleErrors, GetStaticBundleResponse, GetStaticBundleResponses, GetStatusOverviewData, GetStatusOverviewErrors, GetStatusOverviewResponse, GetStatusOverviewResponses, GetTagsByRepositoryIdData, GetTagsByRepositoryIdErrors, GetTagsByRepositoryIdResponse, GetTagsByRepositoryIdResponses, GetTeamData, GetTeamErrors, GetTeamResponse, GetTeamResponses, GetTimeBucketStatsData, GetTimeBucketStatsError, GetTimeBucketStatsErrors, GetTimeBucketStatsResponse, GetTimeBucketStatsResponses, GetTodayStatsData, GetTodayStatsError, GetTodayStatsErrors, GetTodayStatsResponse, GetTodayStatsResponses, GetTraceData, GetTraceError, GetTraceErrors, GetTraceResponse, GetTraceResponses, GetUnifiedTraceData, GetUnifiedTraceError, GetUnifiedTraceErrors, GetUnifiedTraceResponse, GetUnifiedTraceResponses, GetUniqueCountsData, GetUniqueCountsErrors, GetUniqueCountsResponse, GetUniqueCountsResponses, GetUniqueEventsData, GetUniqueEventsErrors, GetUniqueEventsQuery, GetUniqueEventsResponse, GetUniqueEventsResponses, GetUpdateCapabilityData, GetUpdateCapabilityErrors, GetUpdateCapabilityResponse, GetUpdateCapabilityResponses, GetUpdateStatusData, GetUpdateStatusErrors, GetUpdateStatusResponse, GetUpdateStatusResponses, GetUptimeHistoryData, GetUptimeHistoryErrors, GetUptimeHistoryResponse, GetUptimeHistoryResponses, GetUsageByProviderData, GetUsageByProviderError, GetUsageByProviderErrors, GetUsageByProviderResponse, GetUsageByProviderResponses, GetUsageRecentData, GetUsageRecentError, GetUsageRecentErrors, GetUsageRecentResponse, GetUsageRecentResponses, GetUsageSummaryData, GetUsageSummaryError, GetUsageSummaryErrors, GetUsageSummaryResponse, GetUsageSummaryResponses, GetUsageTimeseriesData, GetUsageTimeseriesError, GetUsageTimeseriesErrors, GetUsageTimeseriesResponse, GetUsageTimeseriesResponses, GetUsageTopModelsData, GetUsageTopModelsError, GetUsageTopModelsErrors, GetUsageTopModelsResponse, GetUsageTopModelsResponses, GetVisitorByGuidData, GetVisitorByGuidErrors, GetVisitorByGuidResponse, GetVisitorByGuidResponses, GetVisitorByIdData, GetVisitorByIdErrors, GetVisitorByIdResponse, GetVisitorByIdResponses, GetVisitorDetailsData, GetVisitorDetailsErrors, GetVisitorDetailsResponse, GetVisitorDetailsResponses, GetVisitorFacetsData, GetVisitorFacetsErrors, GetVisitorFacetsResponse, GetVisitorFacetsResponses, GetVisitorInfoData, GetVisitorInfoErrors, GetVisitorInfoResponse, GetVisitorInfoResponses, GetVisitorJourneyData, GetVisitorJourneyErrors, GetVisitorJourneyResponse, GetVisitorJourneyResponses, GetVisitorsData, GetVisitorsErrors, GetVisitorSessionsData, GetVisitorSessionsError, GetVisitorSessionsErrors, GetVisitorSessionsQuery, GetVisitorSessionsResponse, GetVisitorSessionsResponse2, GetVisitorSessionsResponses, GetVisitorsResponse, GetVisitorsResponses, GetVisitorStatsData, GetVisitorStatsErrors, GetVisitorStatsResponse, GetVisitorStatsResponses, GetWebhookData, GetWebhookErrors, GetWebhookResponse, GetWebhookResponses, GitPushEvent, GitRefResponse, GitSourcePlan, GlobalConversationResponse, GlobalEventStatsResponse, GlobalMrrResponse, GlobalRecentEventResponse, GlobalRevenueSummaryResponse, GrantProjectAccessData, GrantProjectAccessErrors, GrantProjectAccessResponse, GrantProjectAccessResponses, GroupedPageMetric, GroupedPageMetricsQuery, GroupedPageMetricsResponse, HandleGitProviderOauthCallbackData, HandleGitProviderOauthCallbackErrors, HasAnalyticsEventsData, HasAnalyticsEventsErrors, HasAnalyticsEventsResponse, HasAnalyticsEventsResponse2, HasAnalyticsEventsResponses, HasErrorGroupsData, HasErrorGroupsErrors, HasErrorGroupsResponse, HasErrorGroupsResponse2, HasErrorGroupsResponses, HasEventsQuery, HasEventsResponse, HasMetricsQuery, HasMetricsResponse, HasPerformanceMetricsData, HasPerformanceMetricsError, HasPerformanceMetricsErrors, HasPerformanceMetricsResponse, HasPerformanceMetricsResponses, HealthCheckConfiguration, HealthCheckEntryResponse, HealthResponse, HealthStatus, HealthSummary, HeartbeatApiRequest, HeartbeatResponse, HierarchyLevel, HistogramSummary, HostnameChange, HostnamePreviewResponse, HourlyPageSessions, HourlyVisitsQuery, HttpChallengeDebugResponse, ImportCredentials, ImportExecutionStatus, ImportExternalServiceData, ImportExternalServiceErrors, ImportExternalServiceRequest, ImportExternalServiceResponse, ImportExternalServiceResponses, ImportOutcomeResponse, ImportPlan, ImportRowErrorResponse, ImportSelector, ImportSource, ImportSourceCapabilities, ImportSourceInfo, ImportStatusResponse, IncidentBucket, IncidentBucketedResponse, IncidentResponse, IncidentUpdateResponse, IncrRequest, IncrResponse, IngestLogsByPathData, IngestLogsByPathError, IngestLogsByPathErrors, IngestLogsByPathResponses, IngestLogsData, IngestLogsError, IngestLogsErrors, IngestLogsResponses, IngestMetricsByPathData, IngestMetricsByPathError, IngestMetricsByPathErrors, IngestMetricsByPathResponses, IngestMetricsData, IngestMetricsError, IngestMetricsErrors, IngestMetricsResponses, IngestSentryEnvelopeData, IngestSentryEnvelopeErrors, IngestSentryEnvelopeResponses, IngestSentryEventData, IngestSentryEventErrors, IngestSentryEventResponse, IngestSentryEventResponses, IngestTracesByPathData, IngestTracesByPathError, IngestTracesByPathErrors, IngestTracesByPathResponses, IngestTracesData, IngestTracesError, IngestTracesErrors, IngestTracesResponses, InitAuthResponse, InitSessionReplayData, InitSessionReplayError, InitSessionReplayErrors, InitSessionReplayResponse, InitSessionReplayResponses, Insight, InsightSeverity, InsightsResponse, InsightStatus, InspectDropArchiveData, InspectDropArchiveErrors, InspectDropArchiveResponse, InspectDropArchiveResponses, IntegrationResponse, IpAccessControlQuery, IpAccessControlResponse, JobLogsData, JobLogsErrors, JobLogsResponses, JobStatusData, JobStatusErrors, JobStatusResponse, JobStatusResponse2, JobStatusResponses, JobSummaryResponse, JoinTokenStatusResponse, JourneyEvent, JourneySession, KeysRequest, KeysResponse, KillJobBody, KillJobData, KillJobErrors, KillJobResponse, KillJobResponses, KnownAiAgentsResponse, KvDelData, KvDelErrors, KvDelResponse, KvDelResponses, KvDisableData, KvDisableErrors, KvDisableResponse, KvDisableResponses, KvEnableData, KvEnableErrors, KvEnableResponse, KvEnableResponses, KvExpireData, KvExpireErrors, KvExpireResponse, KvExpireResponses, KvGetData, KvGetErrors, KvGetResponse, KvGetResponses, KvIncrData, KvIncrErrors, KvIncrResponse, KvIncrResponses, KvKeysData, KvKeysErrors, KvKeysResponse, KvKeysResponses, KvSetData, KvSetErrors, KvSetResponse, KvSetResponses, KvStatusData, KvStatusErrors, KvStatusResponse, KvStatusResponse2, KvStatusResponses, KvTtlData, KvTtlErrors, KvTtlResponse, KvTtlResponses, KvUpdateData, KvUpdateErrors, KvUpdateResponse, KvUpdateResponses, LatestRunForSourceData, LatestRunForSourceErrors, LatestRunForSourceResponse, LatestRunForSourceResponses, LemonSqueezyConfig, LetsEncryptSettings, LineContext, LinkCustomDomainToCertificateData, LinkCustomDomainToCertificateErrors, LinkCustomDomainToCertificateResponse, LinkCustomDomainToCertificateResponses, LinkServiceRequest, LinkServiceToProjectData, LinkServiceToProjectErrors, LinkServiceToProjectResponse, LinkServiceToProjectResponses, ListAgentRunsData, ListAgentRunsErrors, ListAgentRunsResponse, ListAgentRunsResponses, ListAgentsData, ListAgentsErrors, ListAgentsResponse, ListAgentsResponse2, ListAgentsResponses, ListAiProvidersData, ListAiProvidersErrors, ListAiProvidersResponse, ListAiProvidersResponses, ListAlertRulesData, ListAlertRulesErrors, ListAlertRulesResponse, ListAlertRulesResponses, ListAlertsData, ListAlertsError, ListAlertsErrors, ListAlertsResponse, ListAlertsResponses, ListAllConversationsData, ListAllConversationsErrors, ListAllConversationsResponse, ListAllConversationsResponses, ListAllRunsData, ListAllRunsErrors, ListAllRunsResponse, ListAllRunsResponses, ListApiKeysData, ListApiKeysErrors, ListApiKeysQuery, ListApiKeysResponse, ListApiKeysResponses, ListAuditLogsData, ListAuditLogsErrors, ListAuditLogsQuery, ListAuditLogsResponse, ListAuditLogsResponses, ListAvailableContainersData, ListAvailableContainersErrors, ListAvailableContainersResponse, ListAvailableContainersResponses, ListBackupAlertsData, ListBackupAlertsError, ListBackupAlertsErrors, ListBackupAlertsResponse, ListBackupAlertsResponses, ListBackupChildrenData, ListBackupChildrenError, ListBackupChildrenErrors, ListBackupChildrenResponse, ListBackupChildrenResponses, ListBackupSchedulesData, ListBackupSchedulesError, ListBackupSchedulesErrors, ListBackupSchedulesResponse, ListBackupSchedulesResponses, ListBackupsForScheduleData, ListBackupsForScheduleErrors, ListBackupsForScheduleResponse, ListBackupsForScheduleResponses, ListBlobsQuery, ListBlobsResponse, ListCommitsByRepositoryIdData, ListCommitsByRepositoryIdErrors, ListCommitsByRepositoryIdResponse, ListCommitsByRepositoryIdResponses, ListConnectionsData, ListConnectionsErrors, ListConnectionsResponse, ListConnectionsResponses, ListContainersAtPathData, ListContainersAtPathErrors, ListContainersAtPathResponse, ListContainersAtPathResponses, ListContainersData, ListContainersErrors, ListContainersResponse, ListContainersResponses, ListConversationsData, ListConversationsErrors, ListConversationsResponse, ListConversationsResponses, ListCustomDomainsForProjectData, ListCustomDomainsForProjectErrors, ListCustomDomainsForProjectResponse, ListCustomDomainsForProjectResponses, ListCustomDomainsResponse, ListDashboardsData, ListDashboardsError, ListDashboardsErrors, ListDashboardsResponse, ListDashboardsResponses, ListDeliveriesData, ListDeliveriesErrors, ListDeliveriesResponse, ListDeliveriesResponses, ListDeploymentContainerLogsData, ListDeploymentContainerLogsErrors, ListDeploymentContainerLogsResponse, ListDeploymentContainerLogsResponses, ListDeploymentTokensData, ListDeploymentTokensErrors, ListDeploymentTokensQuery, ListDeploymentTokensResponse, ListDeploymentTokensResponses, ListDnsProvidersData, ListDnsProvidersErrors, ListDnsProvidersResponse, ListDnsProvidersResponses, ListDomainsData, ListDomainsErrors, ListDomainsResponse, ListDomainsResponse2, ListDomainsResponses, ListDsnsData, ListDsnsErrors, ListDsnsResponse, ListDsnsResponses, ListEmailDomainsData, ListEmailDomainsErrors, ListEmailDomainsResponse, ListEmailDomainsResponses, ListEmailProvidersData, ListEmailProvidersErrors, ListEmailProvidersResponse, ListEmailProvidersResponses, ListEmailsData, ListEmailsErrors, ListEmailsResponse, ListEmailsResponses, ListEnrollmentTokensData, ListEnrollmentTokensErrors, ListEnrollmentTokensResponse, ListEnrollmentTokensResponses, ListEntitiesData, ListEntitiesErrors, ListEntitiesQuery, ListEntitiesResponse, ListEntitiesResponses, ListErrorEventsData, ListErrorEventsErrors, ListErrorEventsQuery, ListErrorEventsResponse, ListErrorEventsResponses, ListErrorGroupsData, ListErrorGroupsErrors, ListErrorGroupsQuery, ListErrorGroupsResponse, ListErrorGroupsResponses, ListEventsData, ListEventsResponse, ListEventsResponses, ListEventTypesData, ListEventTypesResponse, ListEventTypesResponses, ListExternalImagesData, ListExternalImagesErrors, ListExternalImagesResponse, ListExternalImagesResponses, ListExternalPluginsData, ListExternalPluginsErrors, ListExternalPluginsResponse, ListExternalPluginsResponses, ListExternalServiceBackupsData, ListExternalServiceBackupsError, ListExternalServiceBackupsErrors, ListExternalServiceBackupsResponse, ListExternalServiceBackupsResponses, ListFlagsData, ListFlagsErrors, ListFlagsResponse, ListFlagsResponses, ListFunnelsData, ListFunnelsErrors, ListFunnelsResponse, ListFunnelsResponses, ListGitProvidersData, ListGitProvidersErrors, ListGitProvidersResponse, ListGitProvidersResponses, ListGlobalMcpsData, ListGlobalMcpsErrors, ListGlobalMcpsResponse, ListGlobalMcpsResponses, ListGlobalSkillsData, ListGlobalSkillsErrors, ListGlobalSkillsResponse, ListGlobalSkillsResponses, ListIncidentsData, ListIncidentsErrors, ListIncidentsResponses, ListInsightsData, ListInsightsError, ListInsightsErrors, ListInsightsResponse, ListInsightsResponses, ListIpAccessControlData, ListIpAccessControlError, ListIpAccessControlErrors, ListIpAccessControlResponse, ListIpAccessControlResponses, ListJobsData, ListJobsErrors, ListJobsResponse, ListJobsResponse2, ListJobsResponses, ListKnownAiAgentsData, ListKnownAiAgentsError, ListKnownAiAgentsErrors, ListKnownAiAgentsResponse, ListKnownAiAgentsResponses, ListManagedDomainsData, ListManagedDomainsErrors, ListManagedDomainsResponse, ListManagedDomainsResponses, ListMcpsData, ListMcpsErrors, ListMcpsResponse, ListMcpsResponse2, ListMcpsResponses, ListMetricLabelKeysData, ListMetricLabelKeysError, ListMetricLabelKeysErrors, ListMetricLabelKeysResponse, ListMetricLabelKeysResponses, ListMetricLabelValuesData, ListMetricLabelValuesError, ListMetricLabelValuesErrors, ListMetricLabelValuesResponse, ListMetricLabelValuesResponses, ListMetricNamesData, ListMetricNamesError, ListMetricNamesErrors, ListMetricNamesResponse, ListMetricNamesResponses, ListModelsData, ListModelsError, ListModelsErrors, ListModelsResponse, ListModelsResponses, ListMonitorsData, ListMonitorsErrors, ListMonitorsResponse, ListMonitorsResponses, ListNotificationProvidersData, ListNotificationProvidersErrors, ListNotificationProvidersResponse, ListNotificationProvidersResponses, ListOidcProvidersData, ListOidcProvidersResponse, ListOidcProvidersResponses, ListOidcProviderUsersData, ListOidcProviderUsersErrors, ListOidcProviderUsersResponse, ListOidcProviderUsersResponses, ListOidcRoleMappingsData, ListOidcRoleMappingsResponse, ListOidcRoleMappingsResponses, ListOnDemandCertsData, ListOnDemandCertsErrors, ListOnDemandCertsResponse, ListOnDemandCertsResponse2, ListOnDemandCertsResponses, ListOrdersData, ListOrdersErrors, ListOrdersResponse, ListOrdersResponse2, ListOrdersResponses, ListPeersData, ListPeersErrors, ListPeersResponse, ListPeersResponses, ListPendingActionsData, ListPendingActionsErrors, ListPendingActionsResponse, ListPendingActionsResponses, ListPgUpgradesData, ListPgUpgradesErrors, ListPgUpgradesResponse, ListPgUpgradesResponses, ListPresetsData, ListPresetsErrors, ListPresetsResponse, ListPresetsResponse2, ListPresetsResponses, ListProjectAccessData, ListProjectAccessErrors, ListProjectAccessResponse, ListProjectAccessResponses, ListProjectAlarmsData, ListProjectAlarmsErrors, ListProjectAlarmsResponse, ListProjectAlarmsResponses, ListProjectScansData, ListProjectScansError, ListProjectScansErrors, ListProjectScansResponse, ListProjectScansResponses, ListProjectSecretsData, ListProjectSecretsErrors, ListProjectSecretsResponse, ListProjectSecretsResponses, ListProjectServicesData, ListProjectServicesErrors, ListProjectServicesResponse, ListProjectServicesResponses, ListProjectTemplatesData, ListProjectTemplatesErrors, ListProjectTemplatesResponse, ListProjectTemplatesResponses, ListProjectTemplateTagsData, ListProjectTemplateTagsErrors, ListProjectTemplateTagsResponse, ListProjectTemplateTagsResponses, ListProviderKeysData, ListProviderKeysError, ListProviderKeysErrors, ListProviderKeysResponse, ListProviderKeysResponses, ListProviderZonesData, ListProviderZonesErrors, ListProviderZonesResponse, ListProviderZonesResponses, ListPublicProvidersData, ListPublicProvidersResponse, ListPublicProvidersResponses, ListReleaseFilesData, ListReleaseFilesErrors, ListReleaseFilesResponse, ListReleaseFilesResponses, ListReleasesData, ListReleasesErrors, ListReleasesResponse, ListReleasesResponses, ListRemoteExternalImagesData, ListRemoteExternalImagesErrors, ListRemoteExternalImagesResponse, ListRemoteExternalImagesResponses, ListRepositoriesByConnectionData, ListRepositoriesByConnectionErrors, ListRepositoriesByConnectionResponse, ListRepositoriesByConnectionResponses, ListRepositoriesByProviderData, ListRepositoriesByProviderErrors, ListRepositoriesByProviderResponse, ListRepositoriesByProviderResponses, ListRestoreRunsForServiceData, ListRestoreRunsForServiceResponse, ListRestoreRunsForServiceResponses, ListRootContainersData, ListRootContainersErrors, ListRootContainersResponse, ListRootContainersResponses, ListRoutesData, ListRoutesErrors, ListRoutesResponse, ListRoutesResponses, ListRunsResponse, ListS3SourcesData, ListS3SourcesError, ListS3SourcesErrors, ListS3SourcesResponse, ListS3SourcesResponses, ListSandboxesData, ListSandboxesResponse, ListSandboxesResponse2, ListSandboxesResponses, ListScansQuery, ListScheduleRunJobsData, ListScheduleRunJobsError, ListScheduleRunJobsErrors, ListScheduleRunJobsResponse, ListScheduleRunJobsResponses, ListScheduleRunsData, ListScheduleRunsError, ListScheduleRunsErrors, ListScheduleRunsResponse, ListScheduleRunsResponses, ListScheduleServicesData, ListScheduleServicesError, ListScheduleServicesErrors, ListScheduleServicesResponse, ListScheduleServicesResponses, ListSecretsData, ListSecretsErrors, ListSecretsResponse, ListSecretsResponse2, ListSecretsResponses, ListServiceHealthStatusesData, ListServiceHealthStatusesErrors, ListServiceHealthStatusesResponse, ListServiceHealthStatusesResponses, ListServiceProjectsData, ListServiceProjectsErrors, ListServiceProjectsResponse, ListServiceProjectsResponses, ListServiceSchedulesData, ListServiceSchedulesError, ListServiceSchedulesErrors, ListServiceSchedulesResponse, ListServiceSchedulesResponses, ListServicesData, ListServicesErrors, ListServicesResponse, ListServicesResponses, ListSkillsData, ListSkillsErrors, ListSkillsResponse, ListSkillsResponse2, ListSkillsResponses, ListSourceBackupsData, ListSourceBackupsError, ListSourceBackupsErrors, ListSourceBackupsResponse, ListSourceBackupsResponses, ListSourceFilesData, ListSourceFilesErrors, ListSourceFilesResponse, ListSourceFilesResponses, ListSourceMapsData, ListSourceMapsErrors, ListSourceMapsResponse, ListSourceMapsResponses, ListSourcesData, ListSourcesErrors, ListSourcesResponse, ListSourcesResponses, ListStaticBundlesData, ListStaticBundlesErrors, ListStaticBundlesResponse, ListStaticBundlesResponses, ListSyncedRepositoriesData, ListSyncedRepositoriesErrors, ListSyncedRepositoriesResponse, ListSyncedRepositoriesResponses, ListTagsResponse, ListTeamMembersData, ListTeamMembersErrors, ListTeamMembersResponse, ListTeamMembersResponses, ListTeamProjectsData, ListTeamProjectsErrors, ListTeamProjectsResponse, ListTeamProjectsResponses, ListTeamsData, ListTeamsErrors, ListTeamsResponse, ListTeamsResponses, ListTemplatesQuery, ListTemplatesResponse, ListUsersData, ListUsersErrors, ListUsersResponse, ListUsersResponses, ListVulnerabilitiesQuery, ListWebhooksData, ListWebhooksErrors, ListWebhooksResponse, ListWebhooksResponses, LiveVisitorInfo, LiveVisitorsListResponse, LocationCount, LocationGranularity, LocationInfo, LoginData, LoginErrors, LoginRequest, LoginResponse, LoginResponses, LogLevel, LogoutData, LogoutErrors, LogoutResponses, LogRecord, LogSearchLine, LogSeverity, LogSource, LogsQuery, LogsResponse, LogStream, LookupDnsARecordsData, LookupDnsARecordsError, LookupDnsARecordsErrors, LookupDnsARecordsResponse, LookupDnsARecordsResponses, ManagedDomainResponse, ManualAction, ManualActionTiming, McpDefinitionResponse, MessageContent, MessagePart, MessageResponse, MeteredMode, MetricAggregation, MetricBucket, MetricDataPoint, MetricsOverTimeResponse, MetricsQuery, MetricsRangeQuery, MetricsStatusResponse, MetricsStoreKind, MetricsSummaryResponse, MetricType, MfaRequiredResponse, MfaSetupResponse, MfaVerificationRequest, MigrationStep, MigrationSummary, MintEnrollmentTokenData, MintEnrollmentTokenErrors, MintEnrollmentTokenRequest, MintEnrollmentTokenResponse, MintEnrollmentTokenResponse2, MintEnrollmentTokenResponses, MiscResult, MkdirBody, MkdirData, MkdirErrors, MkdirResponse, MkdirResponses, ModelInfo, ModelListResponse, ModelPricing, ModelUsage, MonitoringSettings, MonitoringSettingsMasked, MonitorResponse, MonitorStatus, MrrBucketResponse, MultiNodeSettings, MultiNodeSettingsMasked, MxResult, NavEntry, NavSection, NetworkConfiguration, NetworkMode, NixpacksPresetConfig, NixpacksProvider, NodeContainerListResponse, NodeContainerResponse, NodeCostInfo, NodeHeartbeatData, NodeHeartbeatErrors, NodeHeartbeatResponse, NodeHeartbeatResponses, NodeInfoResponse, NodeListResponse, NodeMetricsGetRangeData, NodeMetricsGetRangeErrors, NodeMetricsGetRangeResponse, NodeMetricsGetRangeResponses, NotificationPreferencesResponse, NotificationProviderResponse, ObservabilityCompressionSettings, ObservabilityEvent, ObservabilityFullEventData, ObservabilityFullEventError, ObservabilityFullEventErrors, ObservabilityFullEventResponse, ObservabilityFullEventResponses, ObservabilityListEventsData, ObservabilityListEventsError, ObservabilityListEventsErrors, ObservabilityListEventsResponse, ObservabilityListEventsResponses, ObservabilityRetentionSettings, OidcCallbackData, OidcProviderResponse, OidcProvidersListResponse, OidcProviderSummary, OidcProviderUserResponse, OidcRoleMappingResponse, OidcTestConnectionResponse, OnDemandCertAttemptResponse, OnDemandCertRow, OnDemandTlsSettings, OpenAiError, OpenAiErrorResponse, OperatingSystemCount, OperationResultResponse, OperationResultsResponse, OtelDashboardResponse, OtelDashboardsResponse, OtelMetricAlertRuleResponse, OtelMetricAlertsResponse, OtelMetricLabelKeysResponse, OtelMetricLabelValuesResponse, OtelMetricNamesResponse, OtelMetricsResponse, OutlierAlgorithm, OutlierParams, OverprovisioningAssessment, OverprovisioningVerdict, PageActivityBucket, PageCountryStats, PageFlowEntry, PageFlowQuery, PageFlowResponse, PageHourlySessionsQuery, PageHourlySessionsResponse, PagePathDetailQuery, PagePathDetailResponse, PagePathInfo, PagePathSparkline, PagePathSparklinePoint, PagePathsQuery, PagePathsResponse, PagePathsSparklineQuery, PagePathsSparklineResponse, PagePathVisitorsQuery, PagePathVisitorsResponse, PageReferrerStats, PagesComparisonResponse, PageSessionComparison, PageSessionStats, PageSessionStatsQuery, PageTransition, PageVisit, PageVisitorSession, PaginatedEmailsResponse, PaginatedEntitiesResponse, PaginatedErrorEventsResponse, PaginatedErrorGroupsResponse, PaginatedEventsResponse, PaginatedExternalImagesResponse, PaginatedProjectList, PaginatedStaticBundlesResponse, Pagination, PaginationMeta, PaginationParams, PasswordProtectionConfig, PatchAdminGateData, PatchAdminGateErrors, PatchAdminGateResponse, PatchAdminGateResponses, PatchPreviewGatewaySettingsData, PatchPreviewGatewaySettingsResponse, PatchPreviewGatewaySettingsResponses, PatchSettingsRequest, PathVisitors, PathVisitorsAnalyticsQuery, PathVisitorsResponse, PauseDeploymentData, PauseDeploymentErrors, PauseDeploymentResponse, PauseDeploymentResponses, PauseSandboxData, PauseSandboxErrors, PauseSandboxResponse, PauseSandboxResponses, PeerEntry, PeerListResponse, PendingActionResponse, PerformanceMetricsQuery, PerformanceMetricsResponse, PermissionInfo, PgUpgradeLogResponse, PgUpgradeResponse, PipelineStats, PipelineStatsResponse, PlanComplexity, PlanMetadata, PlanRestoreData, PlanRestoreError, PlanRestoreErrors, PlanRestoreResponse, PlanRestoreResponses, PlanSourceBackup, PlanTarget, PlatformInfo, PluginManifest, PortMapping, PostDnsAckData, PostDnsAckErrors, PostDnsAckResponse, PostDnsAckResponses, PostgresWalHealth, PresetConfigSchema, PresetInfo, PresetResponse, PreviewAlertData, PreviewAlertError, PreviewAlertErrors, PreviewAlertResponse, PreviewAlertResponses, PreviewFunnelMetricsData, PreviewFunnelMetricsErrors, PreviewFunnelMetricsResponse, PreviewFunnelMetricsResponses, PreviewGatewaySettings, PreviewGatewaySettingsMasked, PreviewGatewaySettingsResponse, PreviewHostnameModeData, PreviewHostnameModeErrors, PreviewHostnameModeResponse, PreviewHostnameModeResponses, PreviewShareLinkBody, PreviewShareLinkResponse, PricingResponse, ProblemDetails, ProjectAccessResponse, ProjectConfiguration, ProjectDashboardAnalytics, ProjectDsnResponse, ProjectHealthSummary, ProjectInfo, ProjectMonitorHealth, ProjectPresetResponse, ProjectQuery, ProjectRef, ProjectResponse, ProjectSecretEnvironmentInfo, ProjectSecretResponse, ProjectServiceInfo, ProjectsHealthResponse, ProjectsMonitorHealthResponse, ProjectStatisticsResponse, ProjectStatsBreakdown, ProjectType, ProjectUsageInfoResponse, PromoteClusterMemberData, PromoteClusterMemberErrors, PromoteClusterMemberResponses, PromoteDeploymentData, PromoteDeploymentErrors, PromoteDeploymentRequest, PromoteDeploymentResponse, PromoteDeploymentResponses, PropertyBreakdownItem, PropertyBreakdownQuery, PropertyBreakdownResponse, PropertyColumn, PropertyTimelineItem, PropertyTimelineQuery, PropertyTimelineResponse, Protocol, ProviderCatalogDto, ProviderCatalogResponse, ProviderConfig, ProviderConfigMasked, ProviderDeletionCheckResponse, ProviderDescriptor, ProviderKeyResponse, ProviderMetadata, ProviderResponse, ProviderUsage, ProvisionDomainData, ProvisionDomainErrors, ProvisionDomainResponse, ProvisionDomainResponses, ProvisionResponse, ProxyLogResponse, ProxyLogsPaginatedResponse, PublicHostnameStrategy, PublicPresetResponse, PublicRepositoryInfo, PurgeLogsRequest, PurgeProjectLogsData, PurgeProjectLogsError, PurgeProjectLogsErrors, PurgeProjectLogsResponses, PushedExternalImageResponse, PushExternalImageData, PushExternalImageErrors, PushExternalImageResponse, PushExternalImageResponses, PushImageRequest, QueryDataData, QueryDataErrors, QueryDataRequest, QueryDataResponse, QueryDataResponse2, QueryDataResponses, QueryGenaiTracesData, QueryGenaiTracesError, QueryGenaiTracesErrors, QueryGenaiTracesResponse, QueryGenaiTracesResponses, QueryLogsData, QueryLogsError, QueryLogsErrors, QueryLogsResponse, QueryLogsResponses, QueryMetricsData, QueryMetricsError, QueryMetricsErrors, QueryMetricsResponse, QueryMetricsResponses, QueryTracesData, QueryTracesError, QueryTracesErrors, QueryTracesResponse, QueryTracesResponses, QueryTraceSummariesData, QueryTraceSummariesError, QueryTraceSummariesErrors, QueryTraceSummariesResponse, QueryTraceSummariesResponses, QuotaResponse, RateLimitConfig, RateLimitSettings, ReachabilityStatus, ReadFileData, ReadFileErrors, ReadFileResponse, ReadFileResponse2, ReadFileResponses, ReAnalyzeData, ReAnalyzeErrors, ReAnalyzeResponses, RecentActivityQuery, RecentActivityResponse, RecentEventResponse, RecentQueryParams, RecordConsoleEventData, RecordConsoleEventErrors, RecordConsoleEventResponses, RecordEventMetricsData, RecordEventMetricsErrors, RecordEventMetricsResponse, RecordEventMetricsResponses, RecordExposureRequest, RecordExposureResponse, RecordFlagExposureData, RecordFlagExposureErrors, RecordFlagExposureResponse, RecordFlagExposureResponses, RecordListResponse, RecordSpeedMetricsData, RecordSpeedMetricsError, RecordSpeedMetricsErrors, RecordSpeedMetricsResponse, RecordSpeedMetricsResponses, RecoveryTarget, ReferrerCount, ReferrersAnalyticsQuery, RefreshRouteTableData, RefreshRouteTableErrors, RefreshRouteTableResponse, RefreshRouteTableResponses, RegenerateDsnData, RegenerateDsnErrors, RegenerateDsnRequest, RegenerateDsnResponse, RegenerateDsnResponses, RegisterExternalImageData, RegisterExternalImageErrors, RegisterExternalImageResponse, RegisterExternalImageResponses, RegisterImageRequest, RegisterNodeApiRequest, RegisterNodeData, RegisterNodeErrors, RegisterNodeResponse, RegisterNodeResponse2, RegisterNodeResponses, RegisterRequest, ReinstallGitlabWebhookData, ReinstallGitlabWebhookErrors, ReinstallGitlabWebhookResponse, ReinstallGitlabWebhookResponses, ReinstallWebhookResponse, RejectPendingActionData, RejectPendingActionErrors, RejectPendingActionResponse, RejectPendingActionResponses, ReleaseListResponse, ReloadPluginsData, ReloadPluginsErrors, ReloadPluginsResponse, ReloadPluginsResponses, ReloadResponse, RemoteDeploymentResponse, RemoveClusterMemberData, RemoveClusterMemberErrors, RemoveClusterMemberResponse, RemoveClusterMemberResponses, RemoveManagedDomainData, RemoveManagedDomainErrors, RemoveManagedDomainResponse, RemoveManagedDomainResponses, RemoveNodeResponse, RemoveRoleData, RemoveRoleErrors, RemoveRoleResponse, RemoveRoleResponses, RemoveTeamMemberData, RemoveTeamMemberErrors, RemoveTeamMemberResponse, RemoveTeamMemberResponses, RenameConversationData, RenameConversationErrors, RenameConversationRequest, RenameConversationResponse, RenameConversationResponses, RenewDomainData, RenewDomainErrors, RenewDomainResponse, RenewDomainResponses, RepositoryListQuery, RepositoryListResponse, RepositoryPresetResponse, RepositoryResponse, RepositorySyncStartedResponse, RequestPasswordResetData, RequestPasswordResetErrors, RequestPasswordResetResponse, RequestPasswordResetResponses, RequestRow, RequiredPasswordChangeRequest, RequiredPasswordChangeResponse, ResetPasswordData, ResetPasswordErrors, ResetPasswordRequest, ResetPasswordResponse, ResetPasswordResponses, ResetPgStatStatementsRequest, ResetPgStatStatementsResponse, ResizeSandboxBody, ResizeSandboxData, ResizeSandboxErrors, ResizeSandboxResponse, ResizeSandboxResponses, ResolveAlarmData, ResolveAlarmErrors, ResolveAlarmResponses, ResolvedEnvVarResponse, ResolvedEnvVarSource, ResourceCounts, ResourceFootprint, ResourceInfo, ResourceLimitApplyResult, ResourceLimits, ResourceLimitsResponse, ResourceLimitsUpdateResponse, ResourcesBody, RestartContainerData, RestartContainerErrors, RestartContainerResponse, RestartContainerResponses, RestartPreviewGatewayData, RestartPreviewGatewayResponse, RestartPreviewGatewayResponses, RestartSandboxData, RestartSandboxErrors, RestartSandboxResponse, RestartSandboxResponses, RestoreCapabilities, RestoreCapabilitiesResponse, RestoreFlagData, RestoreFlagErrors, RestoreFlagResponse, RestoreFlagResponses, RestorePlan, RestoreRequestMode, RestoreRunView, RestoreUserData, RestoreUserErrors, RestoreUserResponse, RestoreUserResponses, ResumeDeploymentData, ResumeDeploymentErrors, ResumeDeploymentResponse, ResumeDeploymentResponses, ResumeSandboxData, ResumeSandboxErrors, ResumeSandboxResponse, ResumeSandboxResponses, RetentionCleanupFailure, RetentionCleanupReport, RetryClusterData, RetryClusterErrors, RetryClusterRequest, RetryClusterResponse, RetryClusterResponses, RetryDeliveryData, RetryDeliveryErrors, RetryDeliveryResponse, RetryDeliveryResponses, RetryPgUpgradeData, RetryPgUpgradeErrors, RetryPgUpgradeResponse, RetryPgUpgradeResponses, RetryRunData, RetryRunErrors, RetryRunResponse, RetryRunResponses, RevealGlobalMcpConfigData, RevealGlobalMcpConfigErrors, RevealGlobalMcpConfigResponse, RevealGlobalMcpConfigResponses, RevealMcpConfigData, RevealMcpConfigErrors, RevealMcpConfigResponse, RevealMcpConfigResponses, RevealNotificationProviderConfigData, RevealNotificationProviderConfigErrors, RevealNotificationProviderConfigResponse, RevealNotificationProviderConfigResponses, RevealServiceParameterData, RevealServiceParameterErrors, RevealServiceParameterResponse, RevealServiceParameterResponses, RevenueCreateIntegrationData, RevenueCreateIntegrationErrors, RevenueCreateIntegrationResponse, RevenueCreateIntegrationResponses, RevenueDeleteIntegrationData, RevenueDeleteIntegrationResponse, RevenueDeleteIntegrationResponses, RevenueGlobalEventsData, RevenueGlobalEventsResponse, RevenueGlobalEventsResponses, RevenueImportInvoicesCsvData, RevenueImportInvoicesCsvErrors, RevenueImportInvoicesCsvResponse, RevenueImportInvoicesCsvResponses, RevenueImportSubscriptionsCsvData, RevenueImportSubscriptionsCsvErrors, RevenueImportSubscriptionsCsvResponse, RevenueImportSubscriptionsCsvResponses, RevenueListIntegrationsData, RevenueListIntegrationsResponse, RevenueListIntegrationsResponses, RevenueListProvidersData, RevenueListProvidersResponse, RevenueListProvidersResponses, RevenueMetricsCustomersData, RevenueMetricsCustomersResponse, RevenueMetricsCustomersResponses, RevenueMetricsGlobalMrrData, RevenueMetricsGlobalMrrResponse, RevenueMetricsGlobalMrrResponses, RevenueMetricsGlobalSummaryData, RevenueMetricsGlobalSummaryResponse, RevenueMetricsGlobalSummaryResponses, RevenueMetricsMrrData, RevenueMetricsMrrResponse, RevenueMetricsMrrResponses, RevenueMetricsSummaryData, RevenueMetricsSummaryResponse, RevenueMetricsSummaryResponses, RevenueRecentEventsData, RevenueRecentEventsResponse, RevenueRecentEventsResponses, RevenueRotateTokenData, RevenueRotateTokenResponse, RevenueRotateTokenResponses, RevenueRow, RevenueUpdateConfigData, RevenueUpdateConfigErrors, RevenueUpdateConfigResponse, RevenueUpdateConfigResponses, RevenueUpdateSecretData, RevenueUpdateSecretErrors, RevenueUpdateSecretResponse, RevenueUpdateSecretResponses, RevokeDsnData, RevokeDsnErrors, RevokeDsnResponse, RevokeDsnResponses, RevokeEnrollmentTokenData, RevokeEnrollmentTokenErrors, RevokeEnrollmentTokenResponse, RevokeEnrollmentTokenResponses, RevokeJoinTokenData, RevokeJoinTokenErrors, RevokeJoinTokenResponse, RevokeJoinTokenResponses, RevokeProjectAccessData, RevokeProjectAccessErrors, RevokeProjectAccessResponse, RevokeProjectAccessResponses, RiskLevel, RoleInfo, RollbackPgUpgradeData, RollbackPgUpgradeErrors, RollbackPgUpgradeResponse, RollbackPgUpgradeResponses, RollbackToDeploymentData, RollbackToDeploymentErrors, RollbackToDeploymentResponse, RollbackToDeploymentResponses, RootfsCacheEntry, RootfsGcData, RootfsGcReport, RootfsGcResponses, RootfsReport, RootfsReportData, RootfsReportResponses, RootfsVmEntry, RotateApiKeyData, RotateApiKeyErrors, RotateApiKeyResponse, RotateApiKeyResponses, RotateDeploymentTokenData, RotateDeploymentTokenErrors, RotateDeploymentTokenResponse, RotateDeploymentTokenResponses, RouteRefreshResponse, RouteResponse, RouteRole, RouteUser, RouteUserWithRoles, RunBackupForSourceData, RunBackupForSourceError, RunBackupForSourceErrors, RunBackupForSourceResponse, RunBackupForSourceResponses, RunBackupRequest, RunConnectionHealthCheckData, RunConnectionHealthCheckErrors, RunConnectionHealthCheckResponse, RunConnectionHealthCheckResponses, RunExternalServiceBackupData, RunExternalServiceBackupError, RunExternalServiceBackupErrors, RunExternalServiceBackupRequest, RunExternalServiceBackupResponse, RunExternalServiceBackupResponses, RunScheduleNowData, RunScheduleNowError, RunScheduleNowErrors, RunScheduleNowResponse, RunScheduleNowResponses, S3ConnectionTestResponse, S3CredentialsResponse, S3SourceResponse, S3SourceResponseWritable, SandboxCreatePreviewLinkData, SandboxCreatePreviewLinkErrors, SandboxCreatePreviewLinkResponse, SandboxCreatePreviewLinkResponses, SandboxDomainResponse, SandboxEvent, SandboxEventsResponse, SandboxInner, SandboxResponse, SandboxRoute, SandboxStatusResponse, SaveAgentTokenData, SaveAgentTokenErrors, SaveAgentTokenRequest, SaveAgentTokenResponse, SaveAgentTokenResponse2, SaveAgentTokenResponses, SaveAiProviderCredentialData, SaveAiProviderCredentialErrors, SaveAiProviderCredentialResponse, SaveAiProviderCredentialResponses, SaveCredentialRequest, SaveCredentialResponse, ScalewayCredentialsRequest, ScanResponse, ScheduleRunEntry, ScheduleRunJobEntry, ScheduleRunListResponse, ScheduleRunResponse, ScheduleRunSummary, ScheduleRunSummaryList, ScreenshotSettings, SearchLogsData, SearchLogsError, SearchLogsErrors, SearchLogsRequest, SearchLogsResponse, SearchLogsResponse2, SearchLogsResponses, SearchMode, Seasonality, SecretResponse, SecurityConfig, SecurityHeadersConfig, SecurityHeadersSettings, SelfUpdateAttempt, SelfUpdateBlocker, SelfUpdatePhase, SelfUpdateSettings, SelfUpdateStatus, SendEmailData, SendEmailErrors, SendEmailRequestBody, SendEmailResponse, SendEmailResponseBody, SendEmailResponses, SendMessageRequest, SensitiveConfigValueResponse, SensitiveMcpConfigValueResponse, SensitiveValueResponse, SentryChunkUploadResponse, SentryCreateReleaseRequest, SentryEventRequest, SentryEventResponse, SentryReleaseFileResponse, SentryReleaseProjectRef, SentryReleaseResponse, SeriesStateEntry, ServiceAccessInfo, ServiceAction, ServiceAlertRuleResponse, ServiceBackupEntryResponse, ServiceBackupListResponse, ServiceCreateAlertRuleRequest, ServiceHealthResponse, ServiceHealthStatusBatchResponse, ServiceHealthStatusEntryResponse, ServiceMemberInfo, ServiceParameter, ServicePlan, ServiceResourceLimits, ServiceRuntimeReport, ServiceStatsReport, ServiceTypeInfo, ServiceTypeRoute, ServiceUpdateAlertRuleRequest, SesCredentialsRequest, SessionDetails, SessionDetailsQuery, SessionEvent, SessionEventDto, SessionEventsQuery, SessionEventsResponse, SessionLogsQuery, SessionLogsResponse, SessionReplayEventsRequest, SessionReplayInfoDto, SessionReplayInitRequest, SessionReplayInitResponse, SessionReplayWithEventsDto, SessionReplayWithVisitorDto, SessionRequestLog, SessionSummary, SetDefaultS3SourceData, SetDefaultS3SourceError, SetDefaultS3SourceErrors, SetDefaultS3SourceResponse, SetDefaultS3SourceResponses, SetFlagEnvironmentData, SetFlagEnvironmentErrors, SetFlagEnvironmentRequest, SetFlagEnvironmentResponse, SetFlagEnvironmentResponses, SetPreviewPasswordBody, SetPreviewPasswordData, SetPreviewPasswordErrors, SetPreviewPasswordResponse, SetPreviewPasswordResponse2, SetPreviewPasswordResponses, SetRequest, SetResponse, SettingsUpdateResponse, SetupDnsChallengeData, SetupDnsChallengeErrors, SetupDnsChallengeRequest, SetupDnsChallengeResponse, SetupDnsChallengeResponse2, SetupDnsChallengeResponses, SetupDnsData, SetupDnsErrors, SetupDnsRequest, SetupDnsResponse, SetupDnsResponse2, SetupDnsResponses, SetupEmailTrackingData, SetupEmailTrackingErrors, SetupEmailTrackingResponse, SetupEmailTrackingResponses, SetupMfaData, SetupMfaErrors, SetupMfaResponse, SetupMfaResponses, SiblingRef, SkillDefinitionResponse, SlackConfig, SleepEnvironmentData, SleepEnvironmentErrors, SleepEnvironmentResponse, SleepEnvironmentResponses, SlowQueriesResponse, SlowQueryRow, SmartFilter, SmokeTestAgentData, SmokeTestAgentErrors, SmokeTestAgentResponse, SmokeTestAgentResponses, SmokeTestResponse, SmtpCredentialsRequest, SmtpEncryptionRoute, SmtpResult, SourceArchiveUpload, SourceBackupEntry, SourceBackupIndexResponse, SourceBody, SourceFileListResponse, SourceFileResponse, SourceMapListResponse, SourceMapResponse, SourceSandboxData, SourceSandboxErrors, SourceSandboxResponse, SourceSandboxResponses, SourceType, SpanEvent, SpanKind, SpanRecord, SpanRow, SpanStatusCode, SpeedMetricsPayload, SpeedSegmentFilters, StaleSlot, StartAnalysisData, StartAnalysisErrors, StartAnalysisRequest, StartAnalysisResponse, StartAnalysisResponses, StartContainerData, StartContainerErrors, StartContainerResponse, StartContainerResponses, StartFixData, StartFixErrors, StartFixResponses, StartGitProviderOauthData, StartGitProviderOauthErrors, StartOidcLoginBySlugData, StartOidcLoginBySlugErrors, StartPgUpgradeData, StartPgUpgradeErrors, StartPgUpgradeRequest, StartPgUpgradeResponse, StartPgUpgradeResponses, StartRestoreData, StartRestoreError, StartRestoreErrors, StartRestoreRequest, StartRestoreResponse, StartRestoreResponses, StartServiceData, StartServiceErrors, StartServiceResponse, StartServiceResponses, StartUpdateData, StartUpdateError, StartUpdateErrors, StartUpdateRequest, StartUpdateResponse, StartUpdateResponse2, StartUpdateResponses, StaticBundleResponse, StaticParams, StaticPresetConfig, StatPathData, StatPathErrors, StatPathResponse, StatPathResponses, StatResponse, StatsFilters, StatusBucket, StatusBucketedResponse, StatusCodeCount, StatusCodesQuery, StatusPageOverview, StepConversionResponse, StepResourceType, StepResult, StepUpResponse, StopContainerData, StopContainerErrors, StopContainerResponse, StopContainerResponses, StopSandboxData, StopSandboxErrors, StopSandboxResponse, StopSandboxResponses, StopSequence, StopServiceData, StopServiceErrors, StopServiceResponse, StopServiceResponses, StorageQuota, StreamContainerMetricsData, StreamContainerMetricsErrors, StreamContainerMetricsResponses, StreamEventsData, StreamEventsErrors, StreamEventsResponses, StreamRunEventsData, StreamRunEventsErrors, StreamRunEventsResponses, StripeConfig, SupervisorKind, SyncedRepositoryListQuery, SyncRepositoriesData, SyncRepositoriesErrors, SyncRepositoriesResponse, SyncRepositoriesResponses, SyntaxResult, TagInfo, TagListResponse, TailDeploymentJobLogsData, TailDeploymentJobLogsErrors, TailLogsData, TailLogsError, TailLogsErrors, TailLogsRequest, TailLogsResponses, TargetRecommendation, TeamListResponse, TeamMemberResponse, TeamResponse, TeamRole, TeardownDeploymentData, TeardownDeploymentErrors, TeardownDeploymentResponse, TeardownDeploymentResponses, TeardownEnvironmentData, TeardownEnvironmentErrors, TeardownEnvironmentResponse, TeardownEnvironmentResponses, TemplateResponse, TestEmailRequest, TestEmailResponse, TestNotificationProviderData, TestNotificationProviderErrors, TestNotificationProviderResponse, TestNotificationProviderResponses, TestOidcProviderData, TestOidcProviderResponse, TestOidcProviderResponses, TestProviderConnectionData, TestProviderConnectionErrors, TestProviderConnectionResponse, TestProviderConnectionResponses, TestProviderData, TestProviderErrors, TestProviderKeyByIdData, TestProviderKeyByIdError, TestProviderKeyByIdErrors, TestProviderKeyByIdResponse, TestProviderKeyByIdResponses, TestProviderKeyInlineData, TestProviderKeyInlineError, TestProviderKeyInlineErrors, TestProviderKeyInlineResponse, TestProviderKeyInlineResponses, TestProviderKeyRequest, TestProviderKeyResponse, TestProviderResponse, TestProviderResponse2, TestProviderResponses, TestS3ConnectionPreviewData, TestS3ConnectionPreviewError, TestS3ConnectionPreviewErrors, TestS3ConnectionPreviewResponse, TestS3ConnectionPreviewResponses, TestS3SourceConnectionData, TestS3SourceConnectionError, TestS3SourceConnectionErrors, TestS3SourceConnectionResponse, TestS3SourceConnectionResponses, TimeBucketStats, TimeBucketStatsResponse, TimeseriesBucket, TimeseriesQueryParams, TlsMode, TodayStatsResponse, ToggleDeploymentMetricsRequest, ToggleServiceMetricsRequest, TokenRenewalRequest, ToolCallEvent, ToolInfo, ToolResultEvent, TopModelsQueryParams, TraceProjectRef, TracesResponse, TraceSummariesResponse, TraceSummary, TrackClickData, TrackClickErrors, TrackedLinkResponse, TrackingEventResponse, TrackOpenData, TrackOpenErrors, TrackOpenResponses, TriggerAgentData, TriggerAgentErrors, TriggerAgentRequest, TriggerAgentResponse, TriggerAgentResponses, TriggerDigestResponse, TriggerPipelinePayload, TriggerPipelineResponse, TriggerProjectPipelineData, TriggerProjectPipelineErrors, TriggerProjectPipelineResponse, TriggerProjectPipelineResponses, TriggerScanData, TriggerScanError, TriggerScanErrors, TriggerScanRequest, TriggerScanResponse, TriggerScanResponse2, TriggerScanResponses, TriggerServiceHealthCheckData, TriggerServiceHealthCheckErrors, TriggerServiceHealthCheckResponse, TriggerServiceHealthCheckResponses, TriggerWeeklyDigestData, TriggerWeeklyDigestErrors, TriggerWeeklyDigestResponse, TriggerWeeklyDigestResponses, TtlRequest, TtlResponse, TxtRecord, UiManifest, UiRoute, UndrainNodeResponse, UnifiedTrace, UniqueCountsQuery, UniqueCountsResponse, UnlinkServiceFromProjectData, UnlinkServiceFromProjectErrors, UnlinkServiceFromProjectResponse, UnlinkServiceFromProjectResponses, UnsupportedFeature, UpdateAdminGateRequest, UpdateAgentData, UpdateAgentErrors, UpdateAgentResponse, UpdateAgentResponses, UpdateAiProviderData, UpdateAiProviderErrors, UpdateAiProviderRequest, UpdateAiProviderResponse, UpdateAiProviderResponse2, UpdateAiProviderResponses, UpdateAlertData, UpdateAlertError, UpdateAlertErrors, UpdateAlertResponse, UpdateAlertResponses, UpdateAlertRuleData, UpdateAlertRuleErrors, UpdateAlertRuleRequest, UpdateAlertRuleResponse, UpdateAlertRuleResponses, UpdateApiKeyData, UpdateApiKeyErrors, UpdateApiKeyRequest, UpdateApiKeyResponse, UpdateApiKeyResponses, UpdateAutomaticDeployData, UpdateAutomaticDeployErrors, UpdateAutomaticDeployRequest, UpdateAutomaticDeployResponse, UpdateAutomaticDeployResponses, UpdateBackupScheduleData, UpdateBackupScheduleError, UpdateBackupScheduleErrors, UpdateBackupScheduleRequest, UpdateBackupScheduleResponse, UpdateBackupScheduleResponses, UpdateBlobRequest, UpdateBlobResponse, UpdateCapabilityResponse, UpdateCloudflareProviderData, UpdateCloudflareProviderErrors, UpdateCloudflareProviderRequest, UpdateCloudflareProviderResponse, UpdateCloudflareProviderResponses, UpdateConfigBody, UpdateConnectionTokenData, UpdateConnectionTokenErrors, UpdateConnectionTokenResponse, UpdateConnectionTokenResponses, UpdateCustomDomainData, UpdateCustomDomainErrors, UpdateCustomDomainRequest, UpdateCustomDomainResponse, UpdateCustomDomainResponses, UpdateDashboardData, UpdateDashboardError, UpdateDashboardErrors, UpdateDashboardRequest, UpdateDashboardResponse, UpdateDashboardResponses, UpdateDeploymentConfigRequest, UpdateDeploymentTokenData, UpdateDeploymentTokenErrors, UpdateDeploymentTokenRequest, UpdateDeploymentTokenResponse, UpdateDeploymentTokenResponses, UpdateDnsProviderRequest, UpdateEmailProviderData, UpdateEmailProviderErrors, UpdateEmailProviderRequest, UpdateEmailProviderResponse, UpdateEmailProviderResponses, UpdateEnvironmentSettingsData, UpdateEnvironmentSettingsErrors, UpdateEnvironmentSettingsRequest, UpdateEnvironmentSettingsResponse, UpdateEnvironmentSettingsResponses, UpdateEnvironmentSubdomainData, UpdateEnvironmentSubdomainErrors, UpdateEnvironmentSubdomainRequest, UpdateEnvironmentSubdomainResponse, UpdateEnvironmentSubdomainResponses, UpdateEnvironmentVariableData, UpdateEnvironmentVariableErrors, UpdateEnvironmentVariableRequest, UpdateEnvironmentVariableResponse, UpdateEnvironmentVariableResponses, UpdateErrorGroupData, UpdateErrorGroupErrors, UpdateErrorGroupRequest, UpdateErrorGroupResponses, UpdateExternalServiceRequest, UpdateFlagData, UpdateFlagErrors, UpdateFlagRequest, UpdateFlagResponse, UpdateFlagResponses, UpdateFunnelData, UpdateFunnelErrors, UpdateFunnelResponses, UpdateGitProviderCredentialsData, UpdateGitProviderCredentialsErrors, UpdateGitProviderCredentialsResponse, UpdateGitProviderCredentialsResponses, UpdateGitSettingsData, UpdateGitSettingsErrors, UpdateGitSettingsRequest, UpdateGitSettingsResponse, UpdateGitSettingsResponses, UpdateGlobalMcpData, UpdateGlobalMcpErrors, UpdateGlobalMcpResponse, UpdateGlobalMcpResponses, UpdateGlobalSkillData, UpdateGlobalSkillErrors, UpdateGlobalSkillResponse, UpdateGlobalSkillResponses, UpdateIncidentStatusData, UpdateIncidentStatusErrors, UpdateIncidentStatusRequest, UpdateIncidentStatusResponse, UpdateIncidentStatusResponses, UpdateIpAccessControlData, UpdateIpAccessControlError, UpdateIpAccessControlErrors, UpdateIpAccessControlRequest, UpdateIpAccessControlResponse, UpdateIpAccessControlResponses, UpdateKvRequest, UpdateKvResponse, UpdateManagedDomainApiRequest, UpdateManagedDomainData, UpdateManagedDomainErrors, UpdateManagedDomainResponse, UpdateManagedDomainResponses, UpdateMcpData, UpdateMcpErrors, UpdateMcpRequest, UpdateMcpResponse, UpdateMcpResponses, UpdateMemberRoleRequest, UpdateMetricAlertRequest, UpdateNotificationEmailProviderData, UpdateNotificationEmailProviderErrors, UpdateNotificationEmailProviderRequest, UpdateNotificationEmailProviderResponse, UpdateNotificationEmailProviderResponses, UpdateNotificationProviderData, UpdateNotificationProviderErrors, UpdateNotificationProviderResponse, UpdateNotificationProviderResponses, UpdateOidcProviderData, UpdateOidcProviderRequest, UpdateOidcProviderResponse, UpdateOidcProviderResponses, UpdatePreferencesData, UpdatePreferencesErrors, UpdatePreferencesRequest, UpdatePreferencesResponse, UpdatePreferencesResponses, UpdateProjectData, UpdateProjectDeploymentConfigData, UpdateProjectDeploymentConfigErrors, UpdateProjectDeploymentConfigResponse, UpdateProjectDeploymentConfigResponses, UpdateProjectErrors, UpdateProjectResponse, UpdateProjectResponses, UpdateProjectSecretData, UpdateProjectSecretErrors, UpdateProjectSecretRequest, UpdateProjectSecretResponse, UpdateProjectSecretResponses, UpdateProjectSettingsData, UpdateProjectSettingsErrors, UpdateProjectSettingsRequest, UpdateProjectSettingsResponse, UpdateProjectSettingsResponses, UpdateProviderCredentialsRequest, UpdateProviderData, UpdateProviderErrors, UpdateProviderKeyData, UpdateProviderKeyError, UpdateProviderKeyErrors, UpdateProviderKeyRequest, UpdateProviderKeyResponse, UpdateProviderKeyResponses, UpdateProviderRequest, UpdateProviderResponse, UpdateProviderResponses, UpdateRouteData, UpdateRouteErrors, UpdateRouteRequest, UpdateRouteResponse, UpdateRouteResponses, UpdateS3SourceData, UpdateS3SourceError, UpdateS3SourceErrors, UpdateS3SourceRequest, UpdateS3SourceResponse, UpdateS3SourceResponses, UpdateSecretBody, UpdateSelfData, UpdateSelfErrors, UpdateSelfRequest, UpdateSelfResponse, UpdateSelfResponses, UpdateServiceData, UpdateServiceErrors, UpdateServiceResourcesData, UpdateServiceResourcesErrors, UpdateServiceResourcesResponse, UpdateServiceResourcesResponses, UpdateServiceResponse, UpdateServiceResponses, UpdateSessionDurationData, UpdateSessionDurationError, UpdateSessionDurationErrors, UpdateSessionDurationRequest, UpdateSessionDurationResponse, UpdateSessionDurationResponse2, UpdateSessionDurationResponses, UpdateSettingsData, UpdateSettingsErrors, UpdateSettingsResponse, UpdateSettingsResponses, UpdateSkillData, UpdateSkillErrors, UpdateSkillRequest, UpdateSkillResponse, UpdateSkillResponses, UpdateSlackProviderData, UpdateSlackProviderErrors, UpdateSlackProviderRequest, UpdateSlackProviderResponse, UpdateSlackProviderResponses, UpdateSpeedMetricsData, UpdateSpeedMetricsError, UpdateSpeedMetricsErrors, UpdateSpeedMetricsPayload, UpdateSpeedMetricsResponse, UpdateSpeedMetricsResponses, UpdateStatusResponse, UpdateTeamData, UpdateTeamErrors, UpdateTeamMemberRoleData, UpdateTeamMemberRoleErrors, UpdateTeamMemberRoleResponse, UpdateTeamMemberRoleResponses, UpdateTeamRequest, UpdateTeamResponse, UpdateTeamResponses, UpdateTokenRequest, UpdateTokenResponse, UpdateUserData, UpdateUserErrors, UpdateUserRequest, UpdateUserResponse, UpdateUserResponses, UpdateWebhookData, UpdateWebhookErrors, UpdateWebhookProviderData, UpdateWebhookProviderErrors, UpdateWebhookProviderRequest, UpdateWebhookProviderResponse, UpdateWebhookProviderResponses, UpdateWebhookRequestBody, UpdateWebhookResponse, UpdateWebhookResponses, UpgradeExternalServiceRequest, UpgradePreviewGatewayData, UpgradePreviewGatewayResponse, UpgradePreviewGatewayResponses, UpgradeRequest, UpgradeServiceData, UpgradeServiceErrors, UpgradeServiceResponse, UpgradeServiceResponses, UploadGlobalSkillData, UploadGlobalSkillErrors, UploadGlobalSkillResponse, UploadGlobalSkillResponses, UploadReleaseFileData, UploadReleaseFileErrors, UploadReleaseFileResponse, UploadReleaseFileResponses, UploadSkillData, UploadSkillErrors, UploadSkillResponse, UploadSkillResponses, UploadSourceFileData, UploadSourceFileErrors, UploadSourceFileResponse, UploadSourceFileResponses, UploadSourceMapData, UploadSourceMapErrors, UploadSourceMapResponse, UploadSourceMapResponses, UploadStaticBundleData, UploadStaticBundleErrors, UploadStaticBundleResponse, UploadStaticBundleResponses, UpsertAgentRequest, UpsertSecretData, UpsertSecretErrors, UpsertSecretRequest, UpsertSecretResponse, UpsertSecretResponses, UptimeDataPoint, UptimeHistoryResponse, UsageFilter, UsageInfo, UsageLogEntry, UsageLogPage, UsageQueryParams, UsageSource, UsageSummary, UserResponse, ValidateConnectionData, ValidateConnectionErrors, ValidateConnectionResponse, ValidateConnectionResponses, ValidateEmailData, ValidateEmailErrors, ValidateEmailRequest, ValidateEmailResponse, ValidateEmailResponse2, ValidateEmailResponses, ValidationLevel, ValidationReport, ValidationResponse, ValidationResult, ValidationStatus, ValidationSummary, VerifyAndEnableMfaData, VerifyAndEnableMfaErrors, VerifyAndEnableMfaResponse, VerifyAndEnableMfaResponses, VerifyDomainData, VerifyDomainErrors, VerifyDomainResponse, VerifyDomainResponses, VerifyEmailData, VerifyEmailErrors, VerifyEmailResponse, VerifyEmailResponses, VerifyManagedDomainData, VerifyManagedDomainErrors, VerifyManagedDomainResponse, VerifyManagedDomainResponses, VerifyMfaChallengeData, VerifyMfaChallengeErrors, VerifyMfaChallengeResponse, VerifyMfaChallengeResponses, VerifyMfaRequest, VerifyStepUpData, VerifyStepUpErrors, VerifyStepUpRequest, VerifyStepUpResponse, VerifyStepUpResponses, ViewItem, ViewsOverTime, ViewsOverTimeQuery, VisitorDetails, VisitorFacets, VisitorFacetsQuery, VisitorFacetValue, VisitorInfo, VisitorJourneyQuery, VisitorJourneyResponse, VisitorLocationsQuery, VisitorRecord, VisitorSegmentFilters, VisitorSessionsQuery, VisitorSessionsResponse, VisitorsListQuery, VisitorsResponse, VisitorStats, VisitorWithGeolocation, VolumeMount, VolumeType, VulnerabilityResponse, WakeEnvironmentData, WakeEnvironmentErrors, WakeEnvironmentResponse, WakeEnvironmentResponses, WalWarning, WalWarningSeverity, WebhookConfig, WebhookDeliveryResponse, WebhookResponse, WebhookTriggerData, WebhookTriggerErrors, WebhookTriggerRequest, WebhookTriggerResponse, WebhookTriggerResponse2, WebhookTriggerResponses, WorkflowDryRunData, WorkflowDryRunErrors, WorkflowDryRunRequest, WorkflowDryRunResponse, WorkflowDryRunResponses, WorkloadDescriptor, WorkloadId, WorkloadStatus, WorkloadType, WriteFileBody, WriteFileData, WriteFileErrors, WriteFileResponse, WriteFileResponses, WriteFilesBody, WriteFilesData, WriteFilesErrors, WriteFilesResponse, WriteFilesResponse2, WriteFilesResponses, ZoneListResponse } from './types.gen'; diff --git a/web/src/api/client/sdk.gen.ts b/web/src/api/client/sdk.gen.ts index 2bd5a23e0..fb3fedb57 100644 --- a/web/src/api/client/sdk.gen.ts +++ b/web/src/api/client/sdk.gen.ts @@ -2,7 +2,7 @@ import { type Client, type ClientMeta, formDataBodySerializer, type Options as Options2, type RequestResult, type ServerSentEventsResult, type TDataShape } from './client'; import { client } from './client.gen'; -import type { AcknowledgeAlarmData, AcknowledgeAlarmErrors, AcknowledgeAlarmResponses, ActivateAiProviderData, ActivateAiProviderErrors, ActivateAiProviderResponses, ActivateApiKeyData, ActivateApiKeyErrors, ActivateApiKeyResponses, ActivateConnectionData, ActivateConnectionErrors, ActivateConnectionResponses, ActivateProviderData, ActivateProviderErrors, ActivateProviderResponses, AddClusterMemberData, AddClusterMemberErrors, AddClusterMemberResponses, AddContextData, AddContextErrors, AddContextResponses, AddEnvironmentDomainData, AddEnvironmentDomainErrors, AddEnvironmentDomainResponses, AddEventsData, AddEventsErrors, AddEventsResponses, AddManagedDomainData, AddManagedDomainErrors, AddManagedDomainResponses, AddSessionReplayEventsData, AddSessionReplayEventsErrors, AddSessionReplayEventsResponses, AddTeamMemberData, AddTeamMemberErrors, AddTeamMemberResponses, AdminDrainNodeData, AdminDrainNodeErrors, AdminDrainNodeResponses, AdminDrainStatusData, AdminDrainStatusErrors, AdminDrainStatusResponses, AdminGetNodeData, AdminGetNodeErrors, AdminGetNodeResponses, AdminListNodeContainersData, AdminListNodeContainersErrors, AdminListNodeContainersResponses, AdminListNodesData, AdminListNodesErrors, AdminListNodesResponses, AdminRemoveNodeData, AdminRemoveNodeErrors, AdminRemoveNodeResponses, AdminUndrainNodeData, AdminUndrainNodeErrors, AdminUndrainNodeResponses, ApplyHostnameModeData, ApplyHostnameModeErrors, ApplyHostnameModeResponses, ArchiveConversationData, ArchiveConversationErrors, ArchiveConversationResponses, ArchiveFlagData, ArchiveFlagErrors, ArchiveFlagResponses, AssignRoleData, AssignRoleErrors, AssignRoleResponses, AttachScheduleServicesData, AttachScheduleServicesErrors, AttachScheduleServicesResponses, BlobCopyData, BlobCopyErrors, BlobCopyResponses, BlobDeleteData, BlobDeleteErrors, BlobDeleteResponses, BlobDisableData, BlobDisableErrors, BlobDisableResponses, BlobDownloadData, BlobDownloadErrors, BlobDownloadResponses, BlobEnableData, BlobEnableErrors, BlobEnableResponses, BlobHeadData, BlobHeadErrors, BlobHeadResponses, BlobListData, BlobListErrors, BlobListResponses, BlobPutData, BlobPutErrors, BlobPutResponses, BlobStatusData, BlobStatusErrors, BlobStatusResponses, BlobUpdateData, BlobUpdateErrors, BlobUpdateResponses, CancelBackupData, CancelBackupErrors, CancelBackupResponses, CancelData, CancelDeploymentData, CancelDeploymentErrors, CancelDeploymentResponses, CancelDomainOrderData, CancelDomainOrderErrors, CancelDomainOrderResponses, CancelErrors, CancelPgUpgradeData, CancelPgUpgradeErrors, CancelPgUpgradeResponses, CancelResponses, CancelRunData, CancelRunErrors, CancelRunResponses, CancelScheduleRunData, CancelScheduleRunErrors, CancelScheduleRunResponses, ChangePasswordSelfData, ChangePasswordSelfErrors, ChangePasswordSelfResponses, ChangeProjectSourceData, ChangeProjectSourceErrors, ChangeProjectSourceResponses, ChangeRequiredPasswordData, ChangeRequiredPasswordErrors, ChangeRequiredPasswordResponses, ChatCompletionsData, ChatCompletionsErrors, ChatCompletionsResponses, CheckAnalyticsHasEventsData, CheckAnalyticsHasEventsErrors, CheckAnalyticsHasEventsResponses, CheckCommitExistsData, CheckCommitExistsErrors, CheckCommitExistsResponses, CheckDomainStatusData, CheckDomainStatusErrors, CheckDomainStatusResponses, CheckExplorerSupportData, CheckExplorerSupportErrors, CheckExplorerSupportResponses, CheckIpBlockedData, CheckIpBlockedErrors, CheckIpBlockedResponses, CheckProviderDeletionSafetyData, CheckProviderDeletionSafetyErrors, CheckProviderDeletionSafetyResponses, ChunkUploadOptionsData, ChunkUploadOptionsResponses, CleanupExpiredBackupsData, CleanupExpiredBackupsErrors, CleanupExpiredBackupsResponses, ClearPreviewPasswordData, ClearPreviewPasswordErrors, ClearPreviewPasswordResponses, CliDeviceApproveData, CliDeviceApproveErrors, CliDeviceApproveResponses, CliDeviceDenyData, CliDeviceDenyErrors, CliDeviceDenyResponses, CliDeviceLookupData, CliDeviceLookupErrors, CliDeviceLookupResponses, CliDevicePollData, CliDevicePollErrors, CliDevicePollResponses, CliDeviceStartData, CliDeviceStartErrors, CliDeviceStartResponses, CliLogoutData, CliLogoutErrors, CliLogoutResponses, CmdData, CmdErrors, CmdKillData, CmdKillErrors, CmdKillResponses, CmdLogsData, CmdLogsErrors, CmdLogsResponses, CmdResponses, ConfirmPendingActionData, ConfirmPendingActionErrors, ConfirmPendingActionResponses, ContainerMetricsGetHistoryData, ContainerMetricsGetHistoryErrors, ContainerMetricsGetHistoryResponses, CreateAgentData, CreateAgentErrors, CreateAgentResponses, CreateAlertData, CreateAlertErrors, CreateAlertResponses, CreateAlertRuleData, CreateAlertRuleErrors, CreateAlertRuleResponses, CreateApiKeyData, CreateApiKeyErrors, CreateApiKeyResponses, CreateBackupScheduleData, CreateBackupScheduleErrors, CreateBackupScheduleResponses, CreateBitbucketProviderData, CreateBitbucketProviderErrors, CreateBitbucketProviderResponses, CreateCloudflareProviderData, CreateCloudflareProviderErrors, CreateCloudflareProviderResponses, CreateConversationData, CreateConversationErrors, CreateConversationResponses, CreateCustomDomainData, CreateCustomDomainErrors, CreateCustomDomainResponses, CreateDashboardData, CreateDashboardErrors, CreateDashboardResponses, CreateDeploymentTokenData, CreateDeploymentTokenErrors, CreateDeploymentTokenResponses, CreateDnsProviderData, CreateDnsProviderErrors, CreateDnsProviderResponses, CreateDomainData, CreateDomainErrors, CreateDomainResponses, CreateDsnData, CreateDsnErrors, CreateDsnResponses, CreateEmailDomainData, CreateEmailDomainErrors, CreateEmailDomainResponses, CreateEmailProviderData, CreateEmailProviderErrors, CreateEmailProviderResponses, CreateEnvironmentData, CreateEnvironmentErrors, CreateEnvironmentResponses, CreateEnvironmentVariableData, CreateEnvironmentVariableErrors, CreateEnvironmentVariableResponses, CreateFlagData, CreateFlagErrors, CreateFlagResponses, CreateFunnelData, CreateFunnelErrors, CreateFunnelResponses, CreateGenericProviderData, CreateGenericProviderErrors, CreateGenericProviderResponses, CreateGiteaPatProviderData, CreateGiteaPatProviderErrors, CreateGiteaPatProviderResponses, CreateGithubPatProviderData, CreateGithubPatProviderErrors, CreateGithubPatProviderResponses, CreateGitlabOauthProviderData, CreateGitlabOauthProviderErrors, CreateGitlabOauthProviderResponses, CreateGitlabPatProviderData, CreateGitlabPatProviderErrors, CreateGitlabPatProviderResponses, CreateGitProviderData, CreateGitProviderErrors, CreateGitProviderResponses, CreateGlobalMcpData, CreateGlobalMcpErrors, CreateGlobalMcpResponses, CreateGlobalSkillData, CreateGlobalSkillErrors, CreateGlobalSkillResponses, CreateIncidentData, CreateIncidentErrors, CreateIncidentResponses, CreateIpAccessControlData, CreateIpAccessControlErrors, CreateIpAccessControlResponses, CreateMcpData, CreateMcpErrors, CreateMcpResponses, CreateMonitorData, CreateMonitorErrors, CreateMonitorResponses, CreateNotificationEmailProviderData, CreateNotificationEmailProviderErrors, CreateNotificationEmailProviderResponses, CreateNotificationProviderData, CreateNotificationProviderErrors, CreateNotificationProviderResponses, CreateOidcProviderData, CreateOidcProviderErrors, CreateOidcProviderResponses, CreateOidcRoleMappingData, CreateOidcRoleMappingResponses, CreateOrRecreateOrderData, CreateOrRecreateOrderErrors, CreateOrRecreateOrderResponses, CreatePlanData, CreatePlanErrors, CreatePlanResponses, CreatePrData, CreatePrErrors, CreateProjectData, CreateProjectErrors, CreateProjectFromTemplateData, CreateProjectFromTemplateErrors, CreateProjectFromTemplateResponses, CreateProjectReleaseData, CreateProjectReleaseErrors, CreateProjectReleaseResponses, CreateProjectResponses, CreateProjectSecretData, CreateProjectSecretErrors, CreateProjectSecretResponses, CreateProviderKeyData, CreateProviderKeyErrors, CreateProviderKeyResponses, CreatePrResponses, CreateReleaseData, CreateReleaseErrors, CreateReleaseResponses, CreateRouteData, CreateRouteErrors, CreateRouteResponses, CreateS3SourceData, CreateS3SourceErrors, CreateS3SourceResponses, CreateSandboxData, CreateSandboxErrors, CreateSandboxResponses, CreateServiceData, CreateServiceErrors, CreateServiceResponses, CreateSkillData, CreateSkillErrors, CreateSkillResponses, CreateSlackProviderData, CreateSlackProviderErrors, CreateSlackProviderResponses, CreateTeamData, CreateTeamErrors, CreateTeamResponses, CreateUserData, CreateUserErrors, CreateUserResponses, CreateWebhookData, CreateWebhookErrors, CreateWebhookProviderData, CreateWebhookProviderErrors, CreateWebhookProviderResponses, CreateWebhookResponses, DeactivateApiKeyData, DeactivateApiKeyErrors, DeactivateApiKeyResponses, DeactivateConnectionData, DeactivateConnectionErrors, DeactivateConnectionResponses, DeactivateProviderData, DeactivateProviderErrors, DeactivateProviderResponses, DeleteAgentData, DeleteAgentErrors, DeleteAgentResponses, DeleteAlertData, DeleteAlertErrors, DeleteAlertResponses, DeleteAlertRuleData, DeleteAlertRuleErrors, DeleteAlertRuleResponses, DeleteApiKeyData, DeleteApiKeyErrors, DeleteApiKeyResponses, DeleteBackupData, DeleteBackupErrors, DeleteBackupResponses, DeleteBackupScheduleData, DeleteBackupScheduleErrors, DeleteBackupScheduleResponses, DeleteConnectionData, DeleteConnectionErrors, DeleteConnectionResponses, DeleteCustomDomainData, DeleteCustomDomainErrors, DeleteCustomDomainResponses, DeleteDashboardData, DeleteDashboardErrors, DeleteDashboardResponses, DeleteDeploymentTokenData, DeleteDeploymentTokenErrors, DeleteDeploymentTokenResponses, DeleteDnsProviderData, DeleteDnsProviderErrors, DeleteDnsProviderResponses, DeleteDomainData, DeleteDomainErrors, DeleteDomainResponses, DeleteEmailDomainData, DeleteEmailDomainErrors, DeleteEmailDomainResponses, DeleteEmailProviderData, DeleteEmailProviderErrors, DeleteEmailProviderResponses, DeleteEnvironmentData, DeleteEnvironmentDomainData, DeleteEnvironmentDomainErrors, DeleteEnvironmentDomainResponses, DeleteEnvironmentErrors, DeleteEnvironmentResponses, DeleteEnvironmentVariableData, DeleteEnvironmentVariableErrors, DeleteEnvironmentVariableResponses, DeleteExternalImageData, DeleteExternalImageErrors, DeleteExternalImageResponses, DeleteFunnelData, DeleteFunnelErrors, DeleteFunnelResponses, DeleteGitProviderData, DeleteGitProviderErrors, DeleteGitProviderResponses, DeleteGlobalMcpData, DeleteGlobalMcpErrors, DeleteGlobalMcpResponses, DeleteGlobalSkillData, DeleteGlobalSkillErrors, DeleteGlobalSkillResponses, DeleteIpAccessControlData, DeleteIpAccessControlErrors, DeleteIpAccessControlResponses, DeleteMcpData, DeleteMcpErrors, DeleteMcpResponses, DeleteMonitorData, DeleteMonitorErrors, DeleteMonitorResponses, DeleteNotificationProviderData, DeleteNotificationProviderErrors, DeleteNotificationProviderResponses, DeleteOidcProviderData, DeleteOidcProviderResponses, DeleteOidcRoleMappingData, DeleteOidcRoleMappingResponses, DeletePreferencesData, DeletePreferencesErrors, DeletePreferencesResponses, DeleteProjectData, DeleteProjectErrors, DeleteProjectResponses, DeleteProjectSecretData, DeleteProjectSecretErrors, DeleteProjectSecretResponses, DeleteProviderKeyData, DeleteProviderKeyErrors, DeleteProviderKeyResponses, DeleteProviderSafelyData, DeleteProviderSafelyErrors, DeleteProviderSafelyResponses, DeleteReleaseSourceFilesData, DeleteReleaseSourceFilesErrors, DeleteReleaseSourceFilesResponses, DeleteReleaseSourceMapsData, DeleteReleaseSourceMapsErrors, DeleteReleaseSourceMapsResponses, DeleteRouteData, DeleteRouteErrors, DeleteRouteResponses, DeleteS3SourceData, DeleteS3SourceErrors, DeleteS3SourceResponses, DeleteScanData, DeleteScanErrors, DeleteScanResponses, DeleteSecretData, DeleteSecretErrors, DeleteSecretResponses, DeleteServiceData, DeleteServiceErrors, DeleteServiceResponses, DeleteSessionReplayData, DeleteSessionReplayErrors, DeleteSessionReplayResponses, DeleteSkillData, DeleteSkillErrors, DeleteSkillResponses, DeleteSourceMapData, DeleteSourceMapErrors, DeleteSourceMapResponses, DeleteStaticBundleData, DeleteStaticBundleErrors, DeleteStaticBundleResponses, DeleteTeamData, DeleteTeamErrors, DeleteTeamResponses, DeleteUserData, DeleteUserErrors, DeleteUserResponses, DeleteWebhookData, DeleteWebhookErrors, DeleteWebhookResponses, DeployFromImageData, DeployFromImageErrors, DeployFromImageResponses, DeployFromImageUploadData, DeployFromImageUploadErrors, DeployFromImageUploadResponses, DeployFromStaticData, DeployFromStaticErrors, DeployFromStaticResponses, DeployFromUploadedSourceData, DeployFromUploadedSourceErrors, DeployFromUploadedSourceResponses, DeploymentMetricsGetLatestData, DeploymentMetricsGetLatestErrors, DeploymentMetricsGetLatestResponses, DeploymentMetricsGetRangeData, DeploymentMetricsGetRangeErrors, DeploymentMetricsGetRangeResponses, DeploymentMetricsToggleData, DeploymentMetricsToggleErrors, DeploymentMetricsToggleResponses, DestroySandboxData, DestroySandboxErrors, DestroySandboxResponses, DetachScheduleServiceData, DetachScheduleServiceErrors, DetachScheduleServiceResponses, DetectPublicPresetsData, DetectPublicPresetsErrors, DetectPublicPresetsResponses, DisableBackupScheduleData, DisableBackupScheduleErrors, DisableBackupScheduleResponses, DisableMfaData, DisableMfaErrors, DisableMfaResponses, DiscoverWorkloadsData, DiscoverWorkloadsErrors, DiscoverWorkloadsResponses, DomainData, DomainErrors, DomainResponses, DownloadGlobalSkillArchiveData, DownloadGlobalSkillArchiveErrors, DownloadGlobalSkillArchiveResponses, DownloadObjectData, DownloadObjectErrors, DownloadObjectResponses, DownloadSkillArchiveData, DownloadSkillArchiveErrors, DownloadSkillArchiveResponses, EmailStatusData, EmailStatusErrors, EmailStatusResponses, EmbeddingsData, EmbeddingsErrors, EmbeddingsResponses, EnableBackupScheduleData, EnableBackupScheduleErrors, EnableBackupScheduleResponses, EnrichVisitorData, EnrichVisitorErrors, EnrichVisitorResponses, ExecData, ExecDetachedData, ExecDetachedErrors, ExecDetachedResponses, ExecErrors, ExecResponses, ExecuteDeploymentOperationData, ExecuteDeploymentOperationErrors, ExecuteDeploymentOperationResponses, ExecuteImportData, ExecuteImportErrors, ExecuteImportResponses, ExtendTimeoutData, ExtendTimeoutErrors, ExtendTimeoutResponses, ExternalServiceEnablePgStatStatementsData, ExternalServiceEnablePgStatStatementsErrors, ExternalServiceEnablePgStatStatementsResponses, ExternalServiceMetricsByDatabaseData, ExternalServiceMetricsByDatabaseErrors, ExternalServiceMetricsByDatabaseResponses, ExternalServiceMetricsCreateAlertRuleData, ExternalServiceMetricsCreateAlertRuleErrors, ExternalServiceMetricsCreateAlertRuleResponses, ExternalServiceMetricsDeleteAlertRuleData, ExternalServiceMetricsDeleteAlertRuleErrors, ExternalServiceMetricsDeleteAlertRuleResponses, ExternalServiceMetricsGetAlertRulesData, ExternalServiceMetricsGetAlertRulesErrors, ExternalServiceMetricsGetAlertRulesResponses, ExternalServiceMetricsGetLatestData, ExternalServiceMetricsGetLatestErrors, ExternalServiceMetricsGetLatestResponses, ExternalServiceMetricsGetRangeData, ExternalServiceMetricsGetRangeErrors, ExternalServiceMetricsGetRangeResponses, ExternalServiceMetricsStatusData, ExternalServiceMetricsStatusErrors, ExternalServiceMetricsStatusResponses, ExternalServiceMetricsToggleData, ExternalServiceMetricsToggleErrors, ExternalServiceMetricsToggleResponses, ExternalServiceMetricsUpdateAlertRuleData, ExternalServiceMetricsUpdateAlertRuleErrors, ExternalServiceMetricsUpdateAlertRuleResponses, ExternalServiceResetPgStatStatementsData, ExternalServiceResetPgStatStatementsErrors, ExternalServiceResetPgStatStatementsResponses, FinalizeOrderData, FinalizeOrderErrors, FinalizeOrderResponses, FinalizeProjectReleaseData, FinalizeProjectReleaseErrors, FinalizeProjectReleaseResponses, FindConversationData, FindConversationErrors, FindConversationResponses, GenerateJoinTokenData, GenerateJoinTokenErrors, GenerateJoinTokenResponses, GeneratePresetDockerfileData, GeneratePresetDockerfileErrors, GeneratePresetDockerfileResponses, GetAccessInfoData, GetAccessInfoErrors, GetAccessInfoResponses, GetActiveVisitorsData, GetActiveVisitorsErrors, GetActiveVisitorsResponses, GetActivityGraphData, GetActivityGraphErrors, GetActivityGraphResponses, GetAdminGateData, GetAdminGateErrors, GetAdminGateResponses, GetAgentData, GetAgentErrors, GetAgentResponses, GetAggregatedBucketsData, GetAggregatedBucketsErrors, GetAggregatedBucketsResponses, GetAiAgentBreakdownData, GetAiAgentBreakdownErrors, GetAiAgentBreakdownResponses, GetAiAgentPagesData, GetAiAgentPagesErrors, GetAiAgentPagesResponses, GetAiAgentTimelineData, GetAiAgentTimelineErrors, GetAiAgentTimelineResponses, GetAiPageBreakdownData, GetAiPageBreakdownErrors, GetAiPageBreakdownResponses, GetAiStatusBreakdownData, GetAiStatusBreakdownErrors, GetAiStatusBreakdownResponses, GetAlertData, GetAlertErrors, GetAlertResponses, GetAlertRuleData, GetAlertRuleErrors, GetAlertRuleResponses, GetAllRepositoriesByNameData, GetAllRepositoriesByNameErrors, GetAllRepositoriesByNameResponses, GetAnalyticsActiveVisitorsData, GetAnalyticsActiveVisitorsErrors, GetAnalyticsActiveVisitorsResponses, GetAnalyticsEventsCountData, GetAnalyticsEventsCountErrors, GetAnalyticsEventsCountResponses, GetAnalyticsSessionEventsData, GetAnalyticsSessionEventsErrors, GetAnalyticsSessionEventsResponses, GetAnalyticsVisitorSessionsData, GetAnalyticsVisitorSessionsErrors, GetAnalyticsVisitorSessionsResponses, GetApiKeyData, GetApiKeyErrors, GetApiKeyPermissionsData, GetApiKeyPermissionsErrors, GetApiKeyPermissionsResponses, GetApiKeyResponses, GetAuditLogData, GetAuditLogErrors, GetAuditLogResponses, GetBackupData, GetBackupErrors, GetBackupResponses, GetBackupScheduleData, GetBackupScheduleErrors, GetBackupScheduleResponses, GetBranchesByRepositoryIdData, GetBranchesByRepositoryIdErrors, GetBranchesByRepositoryIdResponses, GetBucketedIncidentsData, GetBucketedIncidentsErrors, GetBucketedIncidentsResponses, GetBucketedStatusData, GetBucketedStatusErrors, GetBucketedStatusResponses, GetChallengeTokenData, GetChallengeTokenErrors, GetChallengeTokenResponses, GetChatReadinessData, GetChatReadinessErrors, GetChatReadinessResponses, GetCliStatusData, GetCliStatusErrors, GetCliStatusResponses, GetClusterHealthData, GetClusterHealthErrors, GetClusterHealthResponses, GetClusterMemberData, GetClusterMemberErrors, GetClusterMemberResponses, GetCmdData, GetCmdErrors, GetCmdResponses, GetContainerDetailData, GetContainerDetailErrors, GetContainerDetailResponses, GetContainerEnvironmentVariableData, GetContainerEnvironmentVariableErrors, GetContainerEnvironmentVariableResponses, GetContainerInfoData, GetContainerInfoErrors, GetContainerInfoResponses, GetContainerLogsByIdData, GetContainerLogsByIdErrors, GetContainerLogsData, GetContainerLogsErrors, GetContainerMetricsData, GetContainerMetricsErrors, GetContainerMetricsResponses, GetConversationData, GetConversationDetailData, GetConversationDetailErrors, GetConversationDetailResponses, GetConversationErrors, GetConversationResponses, GetConversationsData, GetConversationsErrors, GetConversationsResponses, GetCronByIdData, GetCronByIdErrors, GetCronByIdResponses, GetCronExecutionsData, GetCronExecutionsErrors, GetCronExecutionsResponses, GetCrossProjectTraceSiblingsData, GetCrossProjectTraceSiblingsErrors, GetCrossProjectTraceSiblingsResponses, GetCurrentMonitorStatusData, GetCurrentMonitorStatusErrors, GetCurrentMonitorStatusResponses, GetCurrentUserData, GetCurrentUserErrors, GetCurrentUserResponses, GetCustomDomainData, GetCustomDomainErrors, GetCustomDomainResponses, GetDashboardData, GetDashboardErrors, GetDashboardProjectsAnalyticsData, GetDashboardProjectsAnalyticsErrors, GetDashboardProjectsAnalyticsResponses, GetDashboardResponses, GetDeliveryData, GetDeliveryErrors, GetDeliveryResponses, GetDeploymentContainerLogContentData, GetDeploymentContainerLogContentErrors, GetDeploymentContainerLogContentResponses, GetDeploymentData, GetDeploymentErrors, GetDeploymentJobLogsData, GetDeploymentJobLogsErrors, GetDeploymentJobLogsResponses, GetDeploymentJobsData, GetDeploymentJobsErrors, GetDeploymentJobsResponses, GetDeploymentOperationsData, GetDeploymentOperationsErrors, GetDeploymentOperationsResponses, GetDeploymentOperationStatusData, GetDeploymentOperationStatusErrors, GetDeploymentOperationStatusResponses, GetDeploymentResponses, GetDeploymentTokenData, GetDeploymentTokenErrors, GetDeploymentTokenResponses, GetDiskStatusData, GetDiskStatusErrors, GetDiskStatusResponses, GetDnsChangesData, GetDnsChangesErrors, GetDnsChangesResponses, GetDnsProviderData, GetDnsProviderErrors, GetDnsProviderResponses, GetDomainByHostData, GetDomainByHostErrors, GetDomainByHostResponses, GetDomainByIdData, GetDomainByIdErrors, GetDomainByIdResponses, GetDomainByNameData, GetDomainByNameErrors, GetDomainByNameResponses, GetDomainData, GetDomainDnsRecordsData, GetDomainDnsRecordsErrors, GetDomainDnsRecordsResponses, GetDomainErrors, GetDomainOrderData, GetDomainOrderErrors, GetDomainOrderResponses, GetDomainResponses, GetEmailData, GetEmailErrors, GetEmailEventsData, GetEmailEventsErrors, GetEmailEventsResponses, GetEmailLinksData, GetEmailLinksErrors, GetEmailLinksResponses, GetEmailProviderData, GetEmailProviderErrors, GetEmailProviderResponses, GetEmailResponses, GetEmailStatsData, GetEmailStatsErrors, GetEmailStatsResponses, GetEmailTrackingData, GetEmailTrackingErrors, GetEmailTrackingResponses, GetEmailTrackingStatusData, GetEmailTrackingStatusErrors, GetEmailTrackingStatusResponses, GetEntityInfoData, GetEntityInfoErrors, GetEntityInfoResponses, GetEnvironmentCronsData, GetEnvironmentCronsErrors, GetEnvironmentCronsResponses, GetEnvironmentData, GetEnvironmentDomainsData, GetEnvironmentDomainsErrors, GetEnvironmentDomainsResponses, GetEnvironmentErrors, GetEnvironmentResponses, GetEnvironmentsData, GetEnvironmentsErrors, GetEnvironmentsResponses, GetEnvironmentVariablesData, GetEnvironmentVariablesErrors, GetEnvironmentVariablesResponses, GetEnvironmentVariableValueData, GetEnvironmentVariableValueErrors, GetEnvironmentVariableValueResponses, GetErrorDashboardStatsData, GetErrorDashboardStatsErrors, GetErrorDashboardStatsResponses, GetErrorEventData, GetErrorEventErrors, GetErrorEventResponses, GetErrorGroupData, GetErrorGroupErrors, GetErrorGroupResponses, GetErrorStatsData, GetErrorStatsErrors, GetErrorStatsResponses, GetErrorTimeSeriesData, GetErrorTimeSeriesErrors, GetErrorTimeSeriesResponses, GetEventDetailData, GetEventDetailErrors, GetEventDetailResponses, GetEventEntriesData, GetEventEntriesErrors, GetEventEntriesResponses, GetEventsCountData, GetEventsCountErrors, GetEventsCountResponses, GetEventsTimelineData, GetEventsTimelineErrors, GetEventsTimelineResponses, GetEventTypeBreakdownData, GetEventTypeBreakdownErrors, GetEventTypeBreakdownResponses, GetEventVisitorsData, GetEventVisitorsErrors, GetEventVisitorsResponses, GetExternalImageData, GetExternalImageErrors, GetExternalImageResponses, GetFileData, GetFileErrors, GetFileResponses, GetFlagData, GetFlagErrors, GetFlagResponses, GetFlagSnapshotData, GetFlagSnapshotErrors, GetFlagSnapshotResponses, GetFunnelMetricsData, GetFunnelMetricsErrors, GetFunnelMetricsResponses, GetGenaiTraceData, GetGenaiTraceErrors, GetGenaiTraceResponses, GetGeneralStatsData, GetGeneralStatsErrors, GetGeneralStatsResponses, GetGitProviderData, GetGitProviderErrors, GetGitProviderResponses, GetGlobalEventsData, GetGlobalEventsErrors, GetGlobalEventsResponses, GetGlobalEventStatsData, GetGlobalEventStatsErrors, GetGlobalEventStatsResponses, GetGlobalMcpData, GetGlobalMcpErrors, GetGlobalMcpResponses, GetGlobalSandboxStatusData, GetGlobalSandboxStatusErrors, GetGlobalSandboxStatusResponses, GetGlobalSkillData, GetGlobalSkillErrors, GetGlobalSkillResponses, GetGroupedPageMetricsData, GetGroupedPageMetricsErrors, GetGroupedPageMetricsResponses, GetHealthData, GetHealthErrors, GetHealthResponses, GetHourlyVisitsData, GetHourlyVisitsErrors, GetHourlyVisitsResponses, GetHttpChallengeDebugData, GetHttpChallengeDebugErrors, GetHttpChallengeDebugResponses, GetImportStatusData, GetImportStatusErrors, GetImportStatusResponses, GetIncidentData, GetIncidentErrors, GetIncidentResponses, GetIncidentUpdatesData, GetIncidentUpdatesErrors, GetIncidentUpdatesResponses, GetIpAccessControlData, GetIpAccessControlErrors, GetIpAccessControlResponses, GetIpGeolocationData, GetIpGeolocationErrors, GetIpGeolocationResponses, GetJoinTokenStatusData, GetJoinTokenStatusErrors, GetJoinTokenStatusResponses, GetLastDeploymentData, GetLastDeploymentErrors, GetLastDeploymentResponses, GetLatestScanData, GetLatestScanErrors, GetLatestScanResponses, GetLatestScansPerEnvironmentData, GetLatestScansPerEnvironmentErrors, GetLatestScansPerEnvironmentResponses, GetLiveVisitorsListData, GetLiveVisitorsListErrors, GetLiveVisitorsListResponses, GetLogContextData, GetLogContextErrors, GetLogContextResponses, GetMcpData, GetMcpErrors, GetMcpResponses, GetMetricsOverTimeData, GetMetricsOverTimeErrors, GetMetricsOverTimeResponses, GetMonitorData, GetMonitorErrors, GetMonitorResponses, GetNotificationProviderData, GetNotificationProviderErrors, GetNotificationProviderResponses, GetOnDemandCertStatusData, GetOnDemandCertStatusErrors, GetOnDemandCertStatusResponses, GetOrCreateDsnData, GetOrCreateDsnErrors, GetOrCreateDsnResponses, GetPageFlowData, GetPageFlowErrors, GetPageFlowResponses, GetPageHourlySessionsData, GetPageHourlySessionsErrors, GetPageHourlySessionsResponses, GetPagePathDetailData, GetPagePathDetailErrors, GetPagePathDetailResponses, GetPagePathsData, GetPagePathsErrors, GetPagePathsResponses, GetPagePathsSparklinesData, GetPagePathsSparklinesErrors, GetPagePathsSparklinesResponses, GetPagePathVisitorsData, GetPagePathVisitorsErrors, GetPagePathVisitorsResponses, GetPendingActionData, GetPendingActionErrors, GetPendingActionResponses, GetPerformanceMetricsData, GetPerformanceMetricsErrors, GetPerformanceMetricsResponses, GetPgUpgradeData, GetPgUpgradeErrors, GetPgUpgradeLogsData, GetPgUpgradeLogsErrors, GetPgUpgradeLogsResponses, GetPgUpgradeResponses, GetPipelineStatsData, GetPipelineStatsErrors, GetPipelineStatsResponses, GetPlatformInfoData, GetPlatformInfoErrors, GetPlatformInfoResponses, GetPostgresWalHealthData, GetPostgresWalHealthErrors, GetPostgresWalHealthResponses, GetPreferencesData, GetPreferencesErrors, GetPreferencesResponses, GetPreviewGatewayLogsData, GetPreviewGatewayLogsResponses, GetPreviewGatewaySettingsData, GetPreviewGatewaySettingsResponses, GetPreviewGatewayStatusData, GetPreviewGatewayStatusResponses, GetPricingData, GetPricingErrors, GetPricingResponses, GetPrivateIpData, GetPrivateIpErrors, GetPrivateIpResponses, GetProjectAlarmsSummaryData, GetProjectAlarmsSummaryErrors, GetProjectAlarmsSummaryResponses, GetProjectBySlugData, GetProjectBySlugErrors, GetProjectBySlugResponses, GetProjectData, GetProjectDeploymentsData, GetProjectDeploymentsErrors, GetProjectDeploymentsResponses, GetProjectErrors, GetProjectResponses, GetProjectsData, GetProjectsErrors, GetProjectServiceEnvironmentVariablesData, GetProjectServiceEnvironmentVariablesErrors, GetProjectServiceEnvironmentVariablesResponses, GetProjectSessionReplaysData, GetProjectSessionReplaysErrors, GetProjectSessionReplaysResponses, GetProjectsHealthData, GetProjectsHealthErrors, GetProjectsHealthResponses, GetProjectsMonitorHealthData, GetProjectsMonitorHealthErrors, GetProjectsMonitorHealthResponses, GetProjectsResponses, GetProjectStatisticsData, GetProjectStatisticsErrors, GetProjectStatisticsResponses, GetProjectTemplateData, GetProjectTemplateErrors, GetProjectTemplateResponses, GetPropertyBreakdownData, GetPropertyBreakdownErrors, GetPropertyBreakdownResponses, GetPropertyTimelineData, GetPropertyTimelineErrors, GetPropertyTimelineResponses, GetProviderConnectionsData, GetProviderConnectionsErrors, GetProviderConnectionsResponses, GetProviderMetadataData, GetProviderMetadataErrors, GetProviderMetadataResponses, GetProvidersMetadataData, GetProvidersMetadataErrors, GetProvidersMetadataResponses, GetProxyLogByIdData, GetProxyLogByIdErrors, GetProxyLogByIdResponses, GetProxyLogByRequestIdData, GetProxyLogByRequestIdErrors, GetProxyLogByRequestIdResponses, GetProxyLogsData, GetProxyLogsErrors, GetProxyLogsResponses, GetPublicBranchesData, GetPublicBranchesErrors, GetPublicBranchesResponses, GetPublicIpData, GetPublicIpErrors, GetPublicIpResponses, GetPublicRepositoryData, GetPublicRepositoryErrors, GetPublicRepositoryResponses, GetQuotaData, GetQuotaErrors, GetQuotaResponses, GetRecentActivityData, GetRecentActivityErrors, GetRecentActivityResponses, GetRemoteExternalImageData, GetRemoteExternalImageErrors, GetRemoteExternalImageResponses, GetRepositoryBranchesData, GetRepositoryBranchesErrors, GetRepositoryBranchesResponses, GetRepositoryByIdData, GetRepositoryByIdErrors, GetRepositoryByIdResponses, GetRepositoryByNameData, GetRepositoryByNameErrors, GetRepositoryByNameResponses, GetRepositoryPresetByNameData, GetRepositoryPresetByNameErrors, GetRepositoryPresetByNameResponses, GetRepositoryPresetLiveData, GetRepositoryPresetLiveErrors, GetRepositoryPresetLiveResponses, GetRepositoryTagsData, GetRepositoryTagsErrors, GetRepositoryTagsResponses, GetResolvedEnvironmentVariablesData, GetResolvedEnvironmentVariablesErrors, GetResolvedEnvironmentVariablesResponses, GetResolvedEnvironmentVariableValueData, GetResolvedEnvironmentVariableValueErrors, GetResolvedEnvironmentVariableValueResponses, GetRestoreCapabilitiesData, GetRestoreCapabilitiesErrors, GetRestoreCapabilitiesResponses, GetRestoreRunData, GetRestoreRunErrors, GetRestoreRunResponses, GetRouteData, GetRouteErrors, GetRouteResponses, GetRunData, GetRunErrors, GetRunResponses, GetRunWithLogsData, GetRunWithLogsErrors, GetRunWithLogsResponses, GetS3CredentialsData, GetS3CredentialsErrors, GetS3CredentialsResponses, GetS3SourceData, GetS3SourceErrors, GetS3SourceResponses, GetSandboxData, GetSandboxErrors, GetSandboxResponses, GetSandboxStatusData, GetSandboxStatusErrors, GetSandboxStatusResponses, GetScanByDeploymentData, GetScanByDeploymentErrors, GetScanByDeploymentResponses, GetScanData, GetScanErrors, GetScanResponses, GetScanVulnerabilitiesData, GetScanVulnerabilitiesErrors, GetScanVulnerabilitiesResponses, GetServiceBySlugData, GetServiceBySlugErrors, GetServiceBySlugResponses, GetServiceData, GetServiceEnvironmentVariableData, GetServiceEnvironmentVariableErrors, GetServiceEnvironmentVariableResponses, GetServiceEnvironmentVariablesData, GetServiceEnvironmentVariablesErrors, GetServiceEnvironmentVariablesResponses, GetServiceErrors, GetServiceHealthStatusData, GetServiceHealthStatusErrors, GetServiceHealthStatusResponses, GetServicePreviewEnvironmentVariableNamesData, GetServicePreviewEnvironmentVariableNamesErrors, GetServicePreviewEnvironmentVariableNamesResponses, GetServicePreviewEnvironmentVariablesMaskedData, GetServicePreviewEnvironmentVariablesMaskedErrors, GetServicePreviewEnvironmentVariablesMaskedResponses, GetServiceResponses, GetServiceRuntimeData, GetServiceRuntimeErrors, GetServiceRuntimeResponses, GetServiceStatsData, GetServiceStatsErrors, GetServiceStatsResponses, GetServiceTypeParametersData, GetServiceTypeParametersErrors, GetServiceTypeParametersResponses, GetServiceTypesData, GetServiceTypesErrors, GetServiceTypesResponses, GetSessionDetailsData, GetSessionDetailsErrors, GetSessionDetailsResponses, GetSessionEventsData, GetSessionEventsErrors, GetSessionEventsResponses, GetSessionLogsData, GetSessionLogsErrors, GetSessionLogsResponses, GetSessionReplayData, GetSessionReplayErrors, GetSessionReplayEventsData, GetSessionReplayEventsErrors, GetSessionReplayEventsResponses, GetSessionReplayResponses, GetSettingsData, GetSettingsErrors, GetSettingsResponses, GetSkillData, GetSkillErrors, GetSkillResponses, GetSlowQueriesData, GetSlowQueriesErrors, GetSlowQueriesResponses, GetStaticBundleData, GetStaticBundleErrors, GetStaticBundleResponses, GetStatusOverviewData, GetStatusOverviewErrors, GetStatusOverviewResponses, GetTagsByRepositoryIdData, GetTagsByRepositoryIdErrors, GetTagsByRepositoryIdResponses, GetTeamData, GetTeamErrors, GetTeamResponses, GetTimeBucketStatsData, GetTimeBucketStatsErrors, GetTimeBucketStatsResponses, GetTodayStatsData, GetTodayStatsErrors, GetTodayStatsResponses, GetTraceData, GetTraceErrors, GetTraceResponses, GetUnifiedTraceData, GetUnifiedTraceErrors, GetUnifiedTraceResponses, GetUniqueCountsData, GetUniqueCountsErrors, GetUniqueCountsResponses, GetUniqueEventsData, GetUniqueEventsErrors, GetUniqueEventsResponses, GetUpdateStatusData, GetUpdateStatusErrors, GetUpdateStatusResponses, GetUptimeHistoryData, GetUptimeHistoryErrors, GetUptimeHistoryResponses, GetUsageByProviderData, GetUsageByProviderErrors, GetUsageByProviderResponses, GetUsageRecentData, GetUsageRecentErrors, GetUsageRecentResponses, GetUsageSummaryData, GetUsageSummaryErrors, GetUsageSummaryResponses, GetUsageTimeseriesData, GetUsageTimeseriesErrors, GetUsageTimeseriesResponses, GetUsageTopModelsData, GetUsageTopModelsErrors, GetUsageTopModelsResponses, GetVisitorByGuidData, GetVisitorByGuidErrors, GetVisitorByGuidResponses, GetVisitorByIdData, GetVisitorByIdErrors, GetVisitorByIdResponses, GetVisitorDetailsData, GetVisitorDetailsErrors, GetVisitorDetailsResponses, GetVisitorFacetsData, GetVisitorFacetsErrors, GetVisitorFacetsResponses, GetVisitorInfoData, GetVisitorInfoErrors, GetVisitorInfoResponses, GetVisitorJourneyData, GetVisitorJourneyErrors, GetVisitorJourneyResponses, GetVisitorsData, GetVisitorsErrors, GetVisitorSessionsData, GetVisitorSessionsErrors, GetVisitorSessionsResponses, GetVisitorsResponses, GetVisitorStatsData, GetVisitorStatsErrors, GetVisitorStatsResponses, GetWebhookData, GetWebhookErrors, GetWebhookResponses, GrantProjectAccessData, GrantProjectAccessErrors, GrantProjectAccessResponses, HandleGitProviderOauthCallbackData, HandleGitProviderOauthCallbackErrors, HasAnalyticsEventsData, HasAnalyticsEventsErrors, HasAnalyticsEventsResponses, HasErrorGroupsData, HasErrorGroupsErrors, HasErrorGroupsResponses, HasPerformanceMetricsData, HasPerformanceMetricsErrors, HasPerformanceMetricsResponses, ImportExternalServiceData, ImportExternalServiceErrors, ImportExternalServiceResponses, IngestLogsByPathData, IngestLogsByPathErrors, IngestLogsByPathResponses, IngestLogsData, IngestLogsErrors, IngestLogsResponses, IngestMetricsByPathData, IngestMetricsByPathErrors, IngestMetricsByPathResponses, IngestMetricsData, IngestMetricsErrors, IngestMetricsResponses, IngestSentryEnvelopeData, IngestSentryEnvelopeErrors, IngestSentryEnvelopeResponses, IngestSentryEventData, IngestSentryEventErrors, IngestSentryEventResponses, IngestTracesByPathData, IngestTracesByPathErrors, IngestTracesByPathResponses, IngestTracesData, IngestTracesErrors, IngestTracesResponses, InitSessionReplayData, InitSessionReplayErrors, InitSessionReplayResponses, InspectDropArchiveData, InspectDropArchiveErrors, InspectDropArchiveResponses, JobLogsData, JobLogsErrors, JobLogsResponses, JobStatusData, JobStatusErrors, JobStatusResponses, KillJobData, KillJobErrors, KillJobResponses, KvDelData, KvDelErrors, KvDelResponses, KvDisableData, KvDisableErrors, KvDisableResponses, KvEnableData, KvEnableErrors, KvEnableResponses, KvExpireData, KvExpireErrors, KvExpireResponses, KvGetData, KvGetErrors, KvGetResponses, KvIncrData, KvIncrErrors, KvIncrResponses, KvKeysData, KvKeysErrors, KvKeysResponses, KvSetData, KvSetErrors, KvSetResponses, KvStatusData, KvStatusErrors, KvStatusResponses, KvTtlData, KvTtlErrors, KvTtlResponses, KvUpdateData, KvUpdateErrors, KvUpdateResponses, LatestRunForSourceData, LatestRunForSourceErrors, LatestRunForSourceResponses, LinkCustomDomainToCertificateData, LinkCustomDomainToCertificateErrors, LinkCustomDomainToCertificateResponses, LinkServiceToProjectData, LinkServiceToProjectErrors, LinkServiceToProjectResponses, ListAgentRunsData, ListAgentRunsErrors, ListAgentRunsResponses, ListAgentsData, ListAgentsErrors, ListAgentsResponses, ListAiProvidersData, ListAiProvidersErrors, ListAiProvidersResponses, ListAlertRulesData, ListAlertRulesErrors, ListAlertRulesResponses, ListAlertsData, ListAlertsErrors, ListAlertsResponses, ListAllConversationsData, ListAllConversationsErrors, ListAllConversationsResponses, ListAllRunsData, ListAllRunsErrors, ListAllRunsResponses, ListApiKeysData, ListApiKeysErrors, ListApiKeysResponses, ListAuditLogsData, ListAuditLogsErrors, ListAuditLogsResponses, ListAvailableContainersData, ListAvailableContainersErrors, ListAvailableContainersResponses, ListBackupAlertsData, ListBackupAlertsErrors, ListBackupAlertsResponses, ListBackupChildrenData, ListBackupChildrenErrors, ListBackupChildrenResponses, ListBackupSchedulesData, ListBackupSchedulesErrors, ListBackupSchedulesResponses, ListBackupsForScheduleData, ListBackupsForScheduleErrors, ListBackupsForScheduleResponses, ListCommitsByRepositoryIdData, ListCommitsByRepositoryIdErrors, ListCommitsByRepositoryIdResponses, ListConnectionsData, ListConnectionsErrors, ListConnectionsResponses, ListContainersAtPathData, ListContainersAtPathErrors, ListContainersAtPathResponses, ListContainersData, ListContainersErrors, ListContainersResponses, ListConversationsData, ListConversationsErrors, ListConversationsResponses, ListCustomDomainsForProjectData, ListCustomDomainsForProjectErrors, ListCustomDomainsForProjectResponses, ListDashboardsData, ListDashboardsErrors, ListDashboardsResponses, ListDeliveriesData, ListDeliveriesErrors, ListDeliveriesResponses, ListDeploymentContainerLogsData, ListDeploymentContainerLogsErrors, ListDeploymentContainerLogsResponses, ListDeploymentTokensData, ListDeploymentTokensErrors, ListDeploymentTokensResponses, ListDnsProvidersData, ListDnsProvidersErrors, ListDnsProvidersResponses, ListDomainsData, ListDomainsErrors, ListDomainsResponses, ListDsnsData, ListDsnsErrors, ListDsnsResponses, ListEmailDomainsData, ListEmailDomainsErrors, ListEmailDomainsResponses, ListEmailProvidersData, ListEmailProvidersErrors, ListEmailProvidersResponses, ListEmailsData, ListEmailsErrors, ListEmailsResponses, ListEnrollmentTokensData, ListEnrollmentTokensErrors, ListEnrollmentTokensResponses, ListEntitiesData, ListEntitiesErrors, ListEntitiesResponses, ListErrorEventsData, ListErrorEventsErrors, ListErrorEventsResponses, ListErrorGroupsData, ListErrorGroupsErrors, ListErrorGroupsResponses, ListEventsData, ListEventsResponses, ListEventTypesData, ListEventTypesResponses, ListExternalImagesData, ListExternalImagesErrors, ListExternalImagesResponses, ListExternalPluginsData, ListExternalPluginsErrors, ListExternalPluginsResponses, ListExternalServiceBackupsData, ListExternalServiceBackupsErrors, ListExternalServiceBackupsResponses, ListFlagsData, ListFlagsErrors, ListFlagsResponses, ListFunnelsData, ListFunnelsErrors, ListFunnelsResponses, ListGitProvidersData, ListGitProvidersErrors, ListGitProvidersResponses, ListGlobalMcpsData, ListGlobalMcpsErrors, ListGlobalMcpsResponses, ListGlobalSkillsData, ListGlobalSkillsErrors, ListGlobalSkillsResponses, ListIncidentsData, ListIncidentsErrors, ListIncidentsResponses, ListInsightsData, ListInsightsErrors, ListInsightsResponses, ListIpAccessControlData, ListIpAccessControlErrors, ListIpAccessControlResponses, ListJobsData, ListJobsErrors, ListJobsResponses, ListKnownAiAgentsData, ListKnownAiAgentsErrors, ListKnownAiAgentsResponses, ListManagedDomainsData, ListManagedDomainsErrors, ListManagedDomainsResponses, ListMcpsData, ListMcpsErrors, ListMcpsResponses, ListMetricLabelKeysData, ListMetricLabelKeysErrors, ListMetricLabelKeysResponses, ListMetricLabelValuesData, ListMetricLabelValuesErrors, ListMetricLabelValuesResponses, ListMetricNamesData, ListMetricNamesErrors, ListMetricNamesResponses, ListModelsData, ListModelsErrors, ListModelsResponses, ListMonitorsData, ListMonitorsErrors, ListMonitorsResponses, ListNotificationProvidersData, ListNotificationProvidersErrors, ListNotificationProvidersResponses, ListOidcProvidersData, ListOidcProvidersResponses, ListOidcProviderUsersData, ListOidcProviderUsersErrors, ListOidcProviderUsersResponses, ListOidcRoleMappingsData, ListOidcRoleMappingsResponses, ListOnDemandCertsData, ListOnDemandCertsErrors, ListOnDemandCertsResponses, ListOrdersData, ListOrdersErrors, ListOrdersResponses, ListPeersData, ListPeersErrors, ListPeersResponses, ListPendingActionsData, ListPendingActionsErrors, ListPendingActionsResponses, ListPgUpgradesData, ListPgUpgradesErrors, ListPgUpgradesResponses, ListPresetsData, ListPresetsErrors, ListPresetsResponses, ListProjectAccessData, ListProjectAccessErrors, ListProjectAccessResponses, ListProjectAlarmsData, ListProjectAlarmsErrors, ListProjectAlarmsResponses, ListProjectScansData, ListProjectScansErrors, ListProjectScansResponses, ListProjectSecretsData, ListProjectSecretsErrors, ListProjectSecretsResponses, ListProjectServicesData, ListProjectServicesErrors, ListProjectServicesResponses, ListProjectTemplatesData, ListProjectTemplatesErrors, ListProjectTemplatesResponses, ListProjectTemplateTagsData, ListProjectTemplateTagsErrors, ListProjectTemplateTagsResponses, ListProviderKeysData, ListProviderKeysErrors, ListProviderKeysResponses, ListProviderZonesData, ListProviderZonesErrors, ListProviderZonesResponses, ListPublicProvidersData, ListPublicProvidersResponses, ListReleaseFilesData, ListReleaseFilesErrors, ListReleaseFilesResponses, ListReleasesData, ListReleasesErrors, ListReleasesResponses, ListRemoteExternalImagesData, ListRemoteExternalImagesErrors, ListRemoteExternalImagesResponses, ListRepositoriesByConnectionData, ListRepositoriesByConnectionErrors, ListRepositoriesByConnectionResponses, ListRepositoriesByProviderData, ListRepositoriesByProviderErrors, ListRepositoriesByProviderResponses, ListRestoreRunsForServiceData, ListRestoreRunsForServiceResponses, ListRootContainersData, ListRootContainersErrors, ListRootContainersResponses, ListRoutesData, ListRoutesErrors, ListRoutesResponses, ListS3SourcesData, ListS3SourcesErrors, ListS3SourcesResponses, ListSandboxesData, ListSandboxesResponses, ListScheduleRunJobsData, ListScheduleRunJobsErrors, ListScheduleRunJobsResponses, ListScheduleRunsData, ListScheduleRunsErrors, ListScheduleRunsResponses, ListScheduleServicesData, ListScheduleServicesErrors, ListScheduleServicesResponses, ListSecretsData, ListSecretsErrors, ListSecretsResponses, ListServiceHealthStatusesData, ListServiceHealthStatusesErrors, ListServiceHealthStatusesResponses, ListServiceProjectsData, ListServiceProjectsErrors, ListServiceProjectsResponses, ListServiceSchedulesData, ListServiceSchedulesErrors, ListServiceSchedulesResponses, ListServicesData, ListServicesErrors, ListServicesResponses, ListSkillsData, ListSkillsErrors, ListSkillsResponses, ListSourceBackupsData, ListSourceBackupsErrors, ListSourceBackupsResponses, ListSourceFilesData, ListSourceFilesErrors, ListSourceFilesResponses, ListSourceMapsData, ListSourceMapsErrors, ListSourceMapsResponses, ListSourcesData, ListSourcesErrors, ListSourcesResponses, ListStaticBundlesData, ListStaticBundlesErrors, ListStaticBundlesResponses, ListSyncedRepositoriesData, ListSyncedRepositoriesErrors, ListSyncedRepositoriesResponses, ListTeamMembersData, ListTeamMembersErrors, ListTeamMembersResponses, ListTeamProjectsData, ListTeamProjectsErrors, ListTeamProjectsResponses, ListTeamsData, ListTeamsErrors, ListTeamsResponses, ListUsersData, ListUsersErrors, ListUsersResponses, ListWebhooksData, ListWebhooksErrors, ListWebhooksResponses, LoginData, LoginErrors, LoginResponses, LogoutData, LogoutErrors, LogoutResponses, LookupDnsARecordsData, LookupDnsARecordsErrors, LookupDnsARecordsResponses, MintEnrollmentTokenData, MintEnrollmentTokenErrors, MintEnrollmentTokenResponses, MkdirData, MkdirErrors, MkdirResponses, NodeHeartbeatData, NodeHeartbeatErrors, NodeHeartbeatResponses, NodeMetricsGetRangeData, NodeMetricsGetRangeErrors, NodeMetricsGetRangeResponses, ObservabilityFullEventData, ObservabilityFullEventErrors, ObservabilityFullEventResponses, ObservabilityListEventsData, ObservabilityListEventsErrors, ObservabilityListEventsResponses, OidcCallbackData, PatchAdminGateData, PatchAdminGateErrors, PatchAdminGateResponses, PatchPreviewGatewaySettingsData, PatchPreviewGatewaySettingsResponses, PauseDeploymentData, PauseDeploymentErrors, PauseDeploymentResponses, PauseSandboxData, PauseSandboxErrors, PauseSandboxResponses, PlanRestoreData, PlanRestoreErrors, PlanRestoreResponses, PostDnsAckData, PostDnsAckErrors, PostDnsAckResponses, PreviewAlertData, PreviewAlertErrors, PreviewAlertResponses, PreviewFunnelMetricsData, PreviewFunnelMetricsErrors, PreviewFunnelMetricsResponses, PreviewHostnameModeData, PreviewHostnameModeErrors, PreviewHostnameModeResponses, PromoteClusterMemberData, PromoteClusterMemberErrors, PromoteClusterMemberResponses, PromoteDeploymentData, PromoteDeploymentErrors, PromoteDeploymentResponses, ProvisionDomainData, ProvisionDomainErrors, ProvisionDomainResponses, PurgeProjectLogsData, PurgeProjectLogsErrors, PurgeProjectLogsResponses, PushExternalImageData, PushExternalImageErrors, PushExternalImageResponses, QueryDataData, QueryDataErrors, QueryDataResponses, QueryGenaiTracesData, QueryGenaiTracesErrors, QueryGenaiTracesResponses, QueryLogsData, QueryLogsErrors, QueryLogsResponses, QueryMetricsData, QueryMetricsErrors, QueryMetricsResponses, QueryTracesData, QueryTracesErrors, QueryTracesResponses, QueryTraceSummariesData, QueryTraceSummariesErrors, QueryTraceSummariesResponses, ReadFileData, ReadFileErrors, ReadFileResponses, ReAnalyzeData, ReAnalyzeErrors, ReAnalyzeResponses, RecordConsoleEventData, RecordConsoleEventErrors, RecordConsoleEventResponses, RecordEventMetricsData, RecordEventMetricsErrors, RecordEventMetricsResponses, RecordFlagExposureData, RecordFlagExposureErrors, RecordFlagExposureResponses, RecordSpeedMetricsData, RecordSpeedMetricsErrors, RecordSpeedMetricsResponses, RefreshRouteTableData, RefreshRouteTableErrors, RefreshRouteTableResponses, RegenerateDsnData, RegenerateDsnErrors, RegenerateDsnResponses, RegisterExternalImageData, RegisterExternalImageErrors, RegisterExternalImageResponses, RegisterNodeData, RegisterNodeErrors, RegisterNodeResponses, ReinstallGitlabWebhookData, ReinstallGitlabWebhookErrors, ReinstallGitlabWebhookResponses, RejectPendingActionData, RejectPendingActionErrors, RejectPendingActionResponses, ReloadPluginsData, ReloadPluginsErrors, ReloadPluginsResponses, RemoveClusterMemberData, RemoveClusterMemberErrors, RemoveClusterMemberResponses, RemoveManagedDomainData, RemoveManagedDomainErrors, RemoveManagedDomainResponses, RemoveRoleData, RemoveRoleErrors, RemoveRoleResponses, RemoveTeamMemberData, RemoveTeamMemberErrors, RemoveTeamMemberResponses, RenameConversationData, RenameConversationErrors, RenameConversationResponses, RenewDomainData, RenewDomainErrors, RenewDomainResponses, RequestPasswordResetData, RequestPasswordResetErrors, RequestPasswordResetResponses, ResetPasswordData, ResetPasswordErrors, ResetPasswordResponses, ResizeSandboxData, ResizeSandboxErrors, ResizeSandboxResponses, ResolveAlarmData, ResolveAlarmErrors, ResolveAlarmResponses, RestartContainerData, RestartContainerErrors, RestartContainerResponses, RestartPreviewGatewayData, RestartPreviewGatewayResponses, RestartSandboxData, RestartSandboxErrors, RestartSandboxResponses, RestoreFlagData, RestoreFlagErrors, RestoreFlagResponses, RestoreUserData, RestoreUserErrors, RestoreUserResponses, ResumeDeploymentData, ResumeDeploymentErrors, ResumeDeploymentResponses, ResumeSandboxData, ResumeSandboxErrors, ResumeSandboxResponses, RetryClusterData, RetryClusterErrors, RetryClusterResponses, RetryDeliveryData, RetryDeliveryErrors, RetryDeliveryResponses, RetryPgUpgradeData, RetryPgUpgradeErrors, RetryPgUpgradeResponses, RetryRunData, RetryRunErrors, RetryRunResponses, RevealGlobalMcpConfigData, RevealGlobalMcpConfigErrors, RevealGlobalMcpConfigResponses, RevealMcpConfigData, RevealMcpConfigErrors, RevealMcpConfigResponses, RevealNotificationProviderConfigData, RevealNotificationProviderConfigErrors, RevealNotificationProviderConfigResponses, RevealServiceParameterData, RevealServiceParameterErrors, RevealServiceParameterResponses, RevenueCreateIntegrationData, RevenueCreateIntegrationErrors, RevenueCreateIntegrationResponses, RevenueDeleteIntegrationData, RevenueDeleteIntegrationResponses, RevenueGlobalEventsData, RevenueGlobalEventsResponses, RevenueImportInvoicesCsvData, RevenueImportInvoicesCsvErrors, RevenueImportInvoicesCsvResponses, RevenueImportSubscriptionsCsvData, RevenueImportSubscriptionsCsvErrors, RevenueImportSubscriptionsCsvResponses, RevenueListIntegrationsData, RevenueListIntegrationsResponses, RevenueListProvidersData, RevenueListProvidersResponses, RevenueMetricsCustomersData, RevenueMetricsCustomersResponses, RevenueMetricsGlobalMrrData, RevenueMetricsGlobalMrrResponses, RevenueMetricsGlobalSummaryData, RevenueMetricsGlobalSummaryResponses, RevenueMetricsMrrData, RevenueMetricsMrrResponses, RevenueMetricsSummaryData, RevenueMetricsSummaryResponses, RevenueRecentEventsData, RevenueRecentEventsResponses, RevenueRotateTokenData, RevenueRotateTokenResponses, RevenueUpdateConfigData, RevenueUpdateConfigErrors, RevenueUpdateConfigResponses, RevenueUpdateSecretData, RevenueUpdateSecretErrors, RevenueUpdateSecretResponses, RevokeDsnData, RevokeDsnErrors, RevokeDsnResponses, RevokeEnrollmentTokenData, RevokeEnrollmentTokenErrors, RevokeEnrollmentTokenResponses, RevokeJoinTokenData, RevokeJoinTokenErrors, RevokeJoinTokenResponses, RevokeProjectAccessData, RevokeProjectAccessErrors, RevokeProjectAccessResponses, RollbackPgUpgradeData, RollbackPgUpgradeErrors, RollbackPgUpgradeResponses, RollbackToDeploymentData, RollbackToDeploymentErrors, RollbackToDeploymentResponses, RootfsGcData, RootfsGcResponses, RootfsReportData, RootfsReportResponses, RotateApiKeyData, RotateApiKeyErrors, RotateApiKeyResponses, RotateDeploymentTokenData, RotateDeploymentTokenErrors, RotateDeploymentTokenResponses, RunBackupForSourceData, RunBackupForSourceErrors, RunBackupForSourceResponses, RunConnectionHealthCheckData, RunConnectionHealthCheckErrors, RunConnectionHealthCheckResponses, RunExternalServiceBackupData, RunExternalServiceBackupErrors, RunExternalServiceBackupResponses, RunScheduleNowData, RunScheduleNowErrors, RunScheduleNowResponses, SandboxCreatePreviewLinkData, SandboxCreatePreviewLinkErrors, SandboxCreatePreviewLinkResponses, SaveAgentTokenData, SaveAgentTokenErrors, SaveAgentTokenResponses, SaveAiProviderCredentialData, SaveAiProviderCredentialErrors, SaveAiProviderCredentialResponses, SearchLogsData, SearchLogsErrors, SearchLogsResponses, SendEmailData, SendEmailErrors, SendEmailResponses, SetDefaultS3SourceData, SetDefaultS3SourceErrors, SetDefaultS3SourceResponses, SetFlagEnvironmentData, SetFlagEnvironmentErrors, SetFlagEnvironmentResponses, SetPreviewPasswordData, SetPreviewPasswordErrors, SetPreviewPasswordResponses, SetupDnsChallengeData, SetupDnsChallengeErrors, SetupDnsChallengeResponses, SetupDnsData, SetupDnsErrors, SetupDnsResponses, SetupEmailTrackingData, SetupEmailTrackingErrors, SetupEmailTrackingResponses, SetupMfaData, SetupMfaErrors, SetupMfaResponses, SleepEnvironmentData, SleepEnvironmentErrors, SleepEnvironmentResponses, SmokeTestAgentData, SmokeTestAgentErrors, SmokeTestAgentResponses, SourceSandboxData, SourceSandboxErrors, SourceSandboxResponses, StartAnalysisData, StartAnalysisErrors, StartAnalysisResponses, StartContainerData, StartContainerErrors, StartContainerResponses, StartFixData, StartFixErrors, StartFixResponses, StartGitProviderOauthData, StartGitProviderOauthErrors, StartOidcLoginBySlugData, StartOidcLoginBySlugErrors, StartPgUpgradeData, StartPgUpgradeErrors, StartPgUpgradeResponses, StartRestoreData, StartRestoreErrors, StartRestoreResponses, StartServiceData, StartServiceErrors, StartServiceResponses, StatPathData, StatPathErrors, StatPathResponses, StopContainerData, StopContainerErrors, StopContainerResponses, StopSandboxData, StopSandboxErrors, StopSandboxResponses, StopServiceData, StopServiceErrors, StopServiceResponses, StreamContainerMetricsData, StreamContainerMetricsErrors, StreamContainerMetricsResponses, StreamEventsData, StreamEventsErrors, StreamEventsResponses, StreamRunEventsData, StreamRunEventsErrors, StreamRunEventsResponses, SyncRepositoriesData, SyncRepositoriesErrors, SyncRepositoriesResponses, TailDeploymentJobLogsData, TailDeploymentJobLogsErrors, TailLogsData, TailLogsErrors, TailLogsResponses, TeardownDeploymentData, TeardownDeploymentErrors, TeardownDeploymentResponses, TeardownEnvironmentData, TeardownEnvironmentErrors, TeardownEnvironmentResponses, TestNotificationProviderData, TestNotificationProviderErrors, TestNotificationProviderResponses, TestOidcProviderData, TestOidcProviderResponses, TestProviderConnectionData, TestProviderConnectionErrors, TestProviderConnectionResponses, TestProviderData, TestProviderErrors, TestProviderKeyByIdData, TestProviderKeyByIdErrors, TestProviderKeyByIdResponses, TestProviderKeyInlineData, TestProviderKeyInlineErrors, TestProviderKeyInlineResponses, TestProviderResponses, TestS3ConnectionPreviewData, TestS3ConnectionPreviewErrors, TestS3ConnectionPreviewResponses, TestS3SourceConnectionData, TestS3SourceConnectionErrors, TestS3SourceConnectionResponses, TrackClickData, TrackClickErrors, TrackOpenData, TrackOpenErrors, TrackOpenResponses, TriggerAgentData, TriggerAgentErrors, TriggerAgentResponses, TriggerProjectPipelineData, TriggerProjectPipelineErrors, TriggerProjectPipelineResponses, TriggerScanData, TriggerScanErrors, TriggerScanResponses, TriggerServiceHealthCheckData, TriggerServiceHealthCheckErrors, TriggerServiceHealthCheckResponses, TriggerWeeklyDigestData, TriggerWeeklyDigestErrors, TriggerWeeklyDigestResponses, UnlinkServiceFromProjectData, UnlinkServiceFromProjectErrors, UnlinkServiceFromProjectResponses, UpdateAgentData, UpdateAgentErrors, UpdateAgentResponses, UpdateAiProviderData, UpdateAiProviderErrors, UpdateAiProviderResponses, UpdateAlertData, UpdateAlertErrors, UpdateAlertResponses, UpdateAlertRuleData, UpdateAlertRuleErrors, UpdateAlertRuleResponses, UpdateApiKeyData, UpdateApiKeyErrors, UpdateApiKeyResponses, UpdateAutomaticDeployData, UpdateAutomaticDeployErrors, UpdateAutomaticDeployResponses, UpdateBackupScheduleData, UpdateBackupScheduleErrors, UpdateBackupScheduleResponses, UpdateCloudflareProviderData, UpdateCloudflareProviderErrors, UpdateCloudflareProviderResponses, UpdateConnectionTokenData, UpdateConnectionTokenErrors, UpdateConnectionTokenResponses, UpdateCustomDomainData, UpdateCustomDomainErrors, UpdateCustomDomainResponses, UpdateDashboardData, UpdateDashboardErrors, UpdateDashboardResponses, UpdateDeploymentTokenData, UpdateDeploymentTokenErrors, UpdateDeploymentTokenResponses, UpdateEmailProviderData, UpdateEmailProviderErrors, UpdateEmailProviderResponses, UpdateEnvironmentSettingsData, UpdateEnvironmentSettingsErrors, UpdateEnvironmentSettingsResponses, UpdateEnvironmentSubdomainData, UpdateEnvironmentSubdomainErrors, UpdateEnvironmentSubdomainResponses, UpdateEnvironmentVariableData, UpdateEnvironmentVariableErrors, UpdateEnvironmentVariableResponses, UpdateErrorGroupData, UpdateErrorGroupErrors, UpdateErrorGroupResponses, UpdateFlagData, UpdateFlagErrors, UpdateFlagResponses, UpdateFunnelData, UpdateFunnelErrors, UpdateFunnelResponses, UpdateGitProviderCredentialsData, UpdateGitProviderCredentialsErrors, UpdateGitProviderCredentialsResponses, UpdateGitSettingsData, UpdateGitSettingsErrors, UpdateGitSettingsResponses, UpdateGlobalMcpData, UpdateGlobalMcpErrors, UpdateGlobalMcpResponses, UpdateGlobalSkillData, UpdateGlobalSkillErrors, UpdateGlobalSkillResponses, UpdateIncidentStatusData, UpdateIncidentStatusErrors, UpdateIncidentStatusResponses, UpdateIpAccessControlData, UpdateIpAccessControlErrors, UpdateIpAccessControlResponses, UpdateManagedDomainData, UpdateManagedDomainErrors, UpdateManagedDomainResponses, UpdateMcpData, UpdateMcpErrors, UpdateMcpResponses, UpdateNotificationEmailProviderData, UpdateNotificationEmailProviderErrors, UpdateNotificationEmailProviderResponses, UpdateNotificationProviderData, UpdateNotificationProviderErrors, UpdateNotificationProviderResponses, UpdateOidcProviderData, UpdateOidcProviderResponses, UpdatePreferencesData, UpdatePreferencesErrors, UpdatePreferencesResponses, UpdateProjectData, UpdateProjectDeploymentConfigData, UpdateProjectDeploymentConfigErrors, UpdateProjectDeploymentConfigResponses, UpdateProjectErrors, UpdateProjectResponses, UpdateProjectSecretData, UpdateProjectSecretErrors, UpdateProjectSecretResponses, UpdateProjectSettingsData, UpdateProjectSettingsErrors, UpdateProjectSettingsResponses, UpdateProviderData, UpdateProviderErrors, UpdateProviderKeyData, UpdateProviderKeyErrors, UpdateProviderKeyResponses, UpdateProviderResponses, UpdateRouteData, UpdateRouteErrors, UpdateRouteResponses, UpdateS3SourceData, UpdateS3SourceErrors, UpdateS3SourceResponses, UpdateSelfData, UpdateSelfErrors, UpdateSelfResponses, UpdateServiceData, UpdateServiceErrors, UpdateServiceResourcesData, UpdateServiceResourcesErrors, UpdateServiceResourcesResponses, UpdateServiceResponses, UpdateSessionDurationData, UpdateSessionDurationErrors, UpdateSessionDurationResponses, UpdateSettingsData, UpdateSettingsErrors, UpdateSettingsResponses, UpdateSkillData, UpdateSkillErrors, UpdateSkillResponses, UpdateSlackProviderData, UpdateSlackProviderErrors, UpdateSlackProviderResponses, UpdateSpeedMetricsData, UpdateSpeedMetricsErrors, UpdateSpeedMetricsResponses, UpdateTeamData, UpdateTeamErrors, UpdateTeamMemberRoleData, UpdateTeamMemberRoleErrors, UpdateTeamMemberRoleResponses, UpdateTeamResponses, UpdateUserData, UpdateUserErrors, UpdateUserResponses, UpdateWebhookData, UpdateWebhookErrors, UpdateWebhookProviderData, UpdateWebhookProviderErrors, UpdateWebhookProviderResponses, UpdateWebhookResponses, UpgradePreviewGatewayData, UpgradePreviewGatewayResponses, UpgradeServiceData, UpgradeServiceErrors, UpgradeServiceResponses, UploadGlobalSkillData, UploadGlobalSkillErrors, UploadGlobalSkillResponses, UploadReleaseFileData, UploadReleaseFileErrors, UploadReleaseFileResponses, UploadSkillData, UploadSkillErrors, UploadSkillResponses, UploadSourceFileData, UploadSourceFileErrors, UploadSourceFileResponses, UploadSourceMapData, UploadSourceMapErrors, UploadSourceMapResponses, UploadStaticBundleData, UploadStaticBundleErrors, UploadStaticBundleResponses, UpsertSecretData, UpsertSecretErrors, UpsertSecretResponses, ValidateConnectionData, ValidateConnectionErrors, ValidateConnectionResponses, ValidateEmailData, ValidateEmailErrors, ValidateEmailResponses, VerifyAndEnableMfaData, VerifyAndEnableMfaErrors, VerifyAndEnableMfaResponses, VerifyDomainData, VerifyDomainErrors, VerifyDomainResponses, VerifyEmailData, VerifyEmailErrors, VerifyEmailResponses, VerifyManagedDomainData, VerifyManagedDomainErrors, VerifyManagedDomainResponses, VerifyMfaChallengeData, VerifyMfaChallengeErrors, VerifyMfaChallengeResponses, VerifyStepUpData, VerifyStepUpErrors, VerifyStepUpResponses, WakeEnvironmentData, WakeEnvironmentErrors, WakeEnvironmentResponses, WebhookTriggerData, WebhookTriggerErrors, WebhookTriggerResponses, WorkflowDryRunData, WorkflowDryRunErrors, WorkflowDryRunResponses, WriteFileData, WriteFileErrors, WriteFileResponses, WriteFilesData, WriteFilesErrors, WriteFilesResponses } from './types.gen'; +import type { AcknowledgeAlarmData, AcknowledgeAlarmErrors, AcknowledgeAlarmResponses, ActivateAiProviderData, ActivateAiProviderErrors, ActivateAiProviderResponses, ActivateApiKeyData, ActivateApiKeyErrors, ActivateApiKeyResponses, ActivateConnectionData, ActivateConnectionErrors, ActivateConnectionResponses, ActivateProviderData, ActivateProviderErrors, ActivateProviderResponses, AddClusterMemberData, AddClusterMemberErrors, AddClusterMemberResponses, AddContextData, AddContextErrors, AddContextResponses, AddEnvironmentDomainData, AddEnvironmentDomainErrors, AddEnvironmentDomainResponses, AddEventsData, AddEventsErrors, AddEventsResponses, AddManagedDomainData, AddManagedDomainErrors, AddManagedDomainResponses, AddSessionReplayEventsData, AddSessionReplayEventsErrors, AddSessionReplayEventsResponses, AddTeamMemberData, AddTeamMemberErrors, AddTeamMemberResponses, AdminDrainNodeData, AdminDrainNodeErrors, AdminDrainNodeResponses, AdminDrainStatusData, AdminDrainStatusErrors, AdminDrainStatusResponses, AdminGetNodeData, AdminGetNodeErrors, AdminGetNodeResponses, AdminListNodeContainersData, AdminListNodeContainersErrors, AdminListNodeContainersResponses, AdminListNodesData, AdminListNodesErrors, AdminListNodesResponses, AdminRemoveNodeData, AdminRemoveNodeErrors, AdminRemoveNodeResponses, AdminUndrainNodeData, AdminUndrainNodeErrors, AdminUndrainNodeResponses, ApplyHostnameModeData, ApplyHostnameModeErrors, ApplyHostnameModeResponses, ArchiveConversationData, ArchiveConversationErrors, ArchiveConversationResponses, ArchiveFlagData, ArchiveFlagErrors, ArchiveFlagResponses, AssignRoleData, AssignRoleErrors, AssignRoleResponses, AttachScheduleServicesData, AttachScheduleServicesErrors, AttachScheduleServicesResponses, BlobCopyData, BlobCopyErrors, BlobCopyResponses, BlobDeleteData, BlobDeleteErrors, BlobDeleteResponses, BlobDisableData, BlobDisableErrors, BlobDisableResponses, BlobDownloadData, BlobDownloadErrors, BlobDownloadResponses, BlobEnableData, BlobEnableErrors, BlobEnableResponses, BlobHeadData, BlobHeadErrors, BlobHeadResponses, BlobListData, BlobListErrors, BlobListResponses, BlobPutData, BlobPutErrors, BlobPutResponses, BlobStatusData, BlobStatusErrors, BlobStatusResponses, BlobUpdateData, BlobUpdateErrors, BlobUpdateResponses, CancelBackupData, CancelBackupErrors, CancelBackupResponses, CancelData, CancelDeploymentData, CancelDeploymentErrors, CancelDeploymentResponses, CancelDomainOrderData, CancelDomainOrderErrors, CancelDomainOrderResponses, CancelErrors, CancelPgUpgradeData, CancelPgUpgradeErrors, CancelPgUpgradeResponses, CancelResponses, CancelRunData, CancelRunErrors, CancelRunResponses, CancelScheduleRunData, CancelScheduleRunErrors, CancelScheduleRunResponses, ChangePasswordSelfData, ChangePasswordSelfErrors, ChangePasswordSelfResponses, ChangeProjectSourceData, ChangeProjectSourceErrors, ChangeProjectSourceResponses, ChangeRequiredPasswordData, ChangeRequiredPasswordErrors, ChangeRequiredPasswordResponses, ChatCompletionsData, ChatCompletionsErrors, ChatCompletionsResponses, CheckAnalyticsHasEventsData, CheckAnalyticsHasEventsErrors, CheckAnalyticsHasEventsResponses, CheckCommitExistsData, CheckCommitExistsErrors, CheckCommitExistsResponses, CheckDomainStatusData, CheckDomainStatusErrors, CheckDomainStatusResponses, CheckExplorerSupportData, CheckExplorerSupportErrors, CheckExplorerSupportResponses, CheckIpBlockedData, CheckIpBlockedErrors, CheckIpBlockedResponses, CheckProviderDeletionSafetyData, CheckProviderDeletionSafetyErrors, CheckProviderDeletionSafetyResponses, ChunkUploadOptionsData, ChunkUploadOptionsResponses, CleanupExpiredBackupsData, CleanupExpiredBackupsErrors, CleanupExpiredBackupsResponses, ClearPreviewPasswordData, ClearPreviewPasswordErrors, ClearPreviewPasswordResponses, CliDeviceApproveData, CliDeviceApproveErrors, CliDeviceApproveResponses, CliDeviceDenyData, CliDeviceDenyErrors, CliDeviceDenyResponses, CliDeviceLookupData, CliDeviceLookupErrors, CliDeviceLookupResponses, CliDevicePollData, CliDevicePollErrors, CliDevicePollResponses, CliDeviceStartData, CliDeviceStartErrors, CliDeviceStartResponses, CliLogoutData, CliLogoutErrors, CliLogoutResponses, CmdData, CmdErrors, CmdKillData, CmdKillErrors, CmdKillResponses, CmdLogsData, CmdLogsErrors, CmdLogsResponses, CmdResponses, ConfirmPendingActionData, ConfirmPendingActionErrors, ConfirmPendingActionResponses, ContainerMetricsGetHistoryData, ContainerMetricsGetHistoryErrors, ContainerMetricsGetHistoryResponses, CreateAgentData, CreateAgentErrors, CreateAgentResponses, CreateAlertData, CreateAlertErrors, CreateAlertResponses, CreateAlertRuleData, CreateAlertRuleErrors, CreateAlertRuleResponses, CreateApiKeyData, CreateApiKeyErrors, CreateApiKeyResponses, CreateBackupScheduleData, CreateBackupScheduleErrors, CreateBackupScheduleResponses, CreateBitbucketProviderData, CreateBitbucketProviderErrors, CreateBitbucketProviderResponses, CreateCloudflareProviderData, CreateCloudflareProviderErrors, CreateCloudflareProviderResponses, CreateConversationData, CreateConversationErrors, CreateConversationResponses, CreateCustomDomainData, CreateCustomDomainErrors, CreateCustomDomainResponses, CreateDashboardData, CreateDashboardErrors, CreateDashboardResponses, CreateDeploymentTokenData, CreateDeploymentTokenErrors, CreateDeploymentTokenResponses, CreateDnsProviderData, CreateDnsProviderErrors, CreateDnsProviderResponses, CreateDomainData, CreateDomainErrors, CreateDomainResponses, CreateDsnData, CreateDsnErrors, CreateDsnResponses, CreateEmailDomainData, CreateEmailDomainErrors, CreateEmailDomainResponses, CreateEmailProviderData, CreateEmailProviderErrors, CreateEmailProviderResponses, CreateEnvironmentData, CreateEnvironmentErrors, CreateEnvironmentResponses, CreateEnvironmentVariableData, CreateEnvironmentVariableErrors, CreateEnvironmentVariableResponses, CreateFlagData, CreateFlagErrors, CreateFlagResponses, CreateFunnelData, CreateFunnelErrors, CreateFunnelResponses, CreateGenericProviderData, CreateGenericProviderErrors, CreateGenericProviderResponses, CreateGiteaPatProviderData, CreateGiteaPatProviderErrors, CreateGiteaPatProviderResponses, CreateGithubPatProviderData, CreateGithubPatProviderErrors, CreateGithubPatProviderResponses, CreateGitlabOauthProviderData, CreateGitlabOauthProviderErrors, CreateGitlabOauthProviderResponses, CreateGitlabPatProviderData, CreateGitlabPatProviderErrors, CreateGitlabPatProviderResponses, CreateGitProviderData, CreateGitProviderErrors, CreateGitProviderResponses, CreateGlobalMcpData, CreateGlobalMcpErrors, CreateGlobalMcpResponses, CreateGlobalSkillData, CreateGlobalSkillErrors, CreateGlobalSkillResponses, CreateIncidentData, CreateIncidentErrors, CreateIncidentResponses, CreateIpAccessControlData, CreateIpAccessControlErrors, CreateIpAccessControlResponses, CreateMcpData, CreateMcpErrors, CreateMcpResponses, CreateMonitorData, CreateMonitorErrors, CreateMonitorResponses, CreateNotificationEmailProviderData, CreateNotificationEmailProviderErrors, CreateNotificationEmailProviderResponses, CreateNotificationProviderData, CreateNotificationProviderErrors, CreateNotificationProviderResponses, CreateOidcProviderData, CreateOidcProviderErrors, CreateOidcProviderResponses, CreateOidcRoleMappingData, CreateOidcRoleMappingResponses, CreateOrRecreateOrderData, CreateOrRecreateOrderErrors, CreateOrRecreateOrderResponses, CreatePlanData, CreatePlanErrors, CreatePlanResponses, CreatePrData, CreatePrErrors, CreateProjectData, CreateProjectErrors, CreateProjectFromTemplateData, CreateProjectFromTemplateErrors, CreateProjectFromTemplateResponses, CreateProjectReleaseData, CreateProjectReleaseErrors, CreateProjectReleaseResponses, CreateProjectResponses, CreateProjectSecretData, CreateProjectSecretErrors, CreateProjectSecretResponses, CreateProviderKeyData, CreateProviderKeyErrors, CreateProviderKeyResponses, CreatePrResponses, CreateReleaseData, CreateReleaseErrors, CreateReleaseResponses, CreateRouteData, CreateRouteErrors, CreateRouteResponses, CreateS3SourceData, CreateS3SourceErrors, CreateS3SourceResponses, CreateSandboxData, CreateSandboxErrors, CreateSandboxResponses, CreateServiceData, CreateServiceErrors, CreateServiceResponses, CreateSkillData, CreateSkillErrors, CreateSkillResponses, CreateSlackProviderData, CreateSlackProviderErrors, CreateSlackProviderResponses, CreateTeamData, CreateTeamErrors, CreateTeamResponses, CreateUserData, CreateUserErrors, CreateUserResponses, CreateWebhookData, CreateWebhookErrors, CreateWebhookProviderData, CreateWebhookProviderErrors, CreateWebhookProviderResponses, CreateWebhookResponses, DeactivateApiKeyData, DeactivateApiKeyErrors, DeactivateApiKeyResponses, DeactivateConnectionData, DeactivateConnectionErrors, DeactivateConnectionResponses, DeactivateProviderData, DeactivateProviderErrors, DeactivateProviderResponses, DeleteAgentData, DeleteAgentErrors, DeleteAgentResponses, DeleteAlertData, DeleteAlertErrors, DeleteAlertResponses, DeleteAlertRuleData, DeleteAlertRuleErrors, DeleteAlertRuleResponses, DeleteApiKeyData, DeleteApiKeyErrors, DeleteApiKeyResponses, DeleteBackupData, DeleteBackupErrors, DeleteBackupResponses, DeleteBackupScheduleData, DeleteBackupScheduleErrors, DeleteBackupScheduleResponses, DeleteConnectionData, DeleteConnectionErrors, DeleteConnectionResponses, DeleteCustomDomainData, DeleteCustomDomainErrors, DeleteCustomDomainResponses, DeleteDashboardData, DeleteDashboardErrors, DeleteDashboardResponses, DeleteDeploymentTokenData, DeleteDeploymentTokenErrors, DeleteDeploymentTokenResponses, DeleteDnsProviderData, DeleteDnsProviderErrors, DeleteDnsProviderResponses, DeleteDomainData, DeleteDomainErrors, DeleteDomainResponses, DeleteEmailDomainData, DeleteEmailDomainErrors, DeleteEmailDomainResponses, DeleteEmailProviderData, DeleteEmailProviderErrors, DeleteEmailProviderResponses, DeleteEnvironmentData, DeleteEnvironmentDomainData, DeleteEnvironmentDomainErrors, DeleteEnvironmentDomainResponses, DeleteEnvironmentErrors, DeleteEnvironmentResponses, DeleteEnvironmentVariableData, DeleteEnvironmentVariableErrors, DeleteEnvironmentVariableResponses, DeleteExternalImageData, DeleteExternalImageErrors, DeleteExternalImageResponses, DeleteFunnelData, DeleteFunnelErrors, DeleteFunnelResponses, DeleteGitProviderData, DeleteGitProviderErrors, DeleteGitProviderResponses, DeleteGlobalMcpData, DeleteGlobalMcpErrors, DeleteGlobalMcpResponses, DeleteGlobalSkillData, DeleteGlobalSkillErrors, DeleteGlobalSkillResponses, DeleteIpAccessControlData, DeleteIpAccessControlErrors, DeleteIpAccessControlResponses, DeleteMcpData, DeleteMcpErrors, DeleteMcpResponses, DeleteMonitorData, DeleteMonitorErrors, DeleteMonitorResponses, DeleteNotificationProviderData, DeleteNotificationProviderErrors, DeleteNotificationProviderResponses, DeleteOidcProviderData, DeleteOidcProviderResponses, DeleteOidcRoleMappingData, DeleteOidcRoleMappingResponses, DeletePreferencesData, DeletePreferencesErrors, DeletePreferencesResponses, DeleteProjectData, DeleteProjectErrors, DeleteProjectResponses, DeleteProjectSecretData, DeleteProjectSecretErrors, DeleteProjectSecretResponses, DeleteProviderKeyData, DeleteProviderKeyErrors, DeleteProviderKeyResponses, DeleteProviderSafelyData, DeleteProviderSafelyErrors, DeleteProviderSafelyResponses, DeleteReleaseSourceFilesData, DeleteReleaseSourceFilesErrors, DeleteReleaseSourceFilesResponses, DeleteReleaseSourceMapsData, DeleteReleaseSourceMapsErrors, DeleteReleaseSourceMapsResponses, DeleteRouteData, DeleteRouteErrors, DeleteRouteResponses, DeleteS3SourceData, DeleteS3SourceErrors, DeleteS3SourceResponses, DeleteScanData, DeleteScanErrors, DeleteScanResponses, DeleteSecretData, DeleteSecretErrors, DeleteSecretResponses, DeleteServiceData, DeleteServiceErrors, DeleteServiceResponses, DeleteSessionReplayData, DeleteSessionReplayErrors, DeleteSessionReplayResponses, DeleteSkillData, DeleteSkillErrors, DeleteSkillResponses, DeleteSourceMapData, DeleteSourceMapErrors, DeleteSourceMapResponses, DeleteStaticBundleData, DeleteStaticBundleErrors, DeleteStaticBundleResponses, DeleteTeamData, DeleteTeamErrors, DeleteTeamResponses, DeleteUserData, DeleteUserErrors, DeleteUserResponses, DeleteWebhookData, DeleteWebhookErrors, DeleteWebhookResponses, DeployFromImageData, DeployFromImageErrors, DeployFromImageResponses, DeployFromImageUploadData, DeployFromImageUploadErrors, DeployFromImageUploadResponses, DeployFromStaticData, DeployFromStaticErrors, DeployFromStaticResponses, DeployFromUploadedSourceData, DeployFromUploadedSourceErrors, DeployFromUploadedSourceResponses, DeploymentMetricsGetLatestData, DeploymentMetricsGetLatestErrors, DeploymentMetricsGetLatestResponses, DeploymentMetricsGetRangeData, DeploymentMetricsGetRangeErrors, DeploymentMetricsGetRangeResponses, DeploymentMetricsToggleData, DeploymentMetricsToggleErrors, DeploymentMetricsToggleResponses, DestroySandboxData, DestroySandboxErrors, DestroySandboxResponses, DetachScheduleServiceData, DetachScheduleServiceErrors, DetachScheduleServiceResponses, DetectPublicPresetsData, DetectPublicPresetsErrors, DetectPublicPresetsResponses, DisableBackupScheduleData, DisableBackupScheduleErrors, DisableBackupScheduleResponses, DisableMfaData, DisableMfaErrors, DisableMfaResponses, DiscoverWorkloadsData, DiscoverWorkloadsErrors, DiscoverWorkloadsResponses, DomainData, DomainErrors, DomainResponses, DownloadGlobalSkillArchiveData, DownloadGlobalSkillArchiveErrors, DownloadGlobalSkillArchiveResponses, DownloadObjectData, DownloadObjectErrors, DownloadObjectResponses, DownloadSkillArchiveData, DownloadSkillArchiveErrors, DownloadSkillArchiveResponses, EmailStatusData, EmailStatusErrors, EmailStatusResponses, EmbeddingsData, EmbeddingsErrors, EmbeddingsResponses, EnableBackupScheduleData, EnableBackupScheduleErrors, EnableBackupScheduleResponses, EnrichVisitorData, EnrichVisitorErrors, EnrichVisitorResponses, ExecData, ExecDetachedData, ExecDetachedErrors, ExecDetachedResponses, ExecErrors, ExecResponses, ExecuteDeploymentOperationData, ExecuteDeploymentOperationErrors, ExecuteDeploymentOperationResponses, ExecuteImportData, ExecuteImportErrors, ExecuteImportResponses, ExtendTimeoutData, ExtendTimeoutErrors, ExtendTimeoutResponses, ExternalServiceEnablePgStatStatementsData, ExternalServiceEnablePgStatStatementsErrors, ExternalServiceEnablePgStatStatementsResponses, ExternalServiceMetricsByDatabaseData, ExternalServiceMetricsByDatabaseErrors, ExternalServiceMetricsByDatabaseResponses, ExternalServiceMetricsCreateAlertRuleData, ExternalServiceMetricsCreateAlertRuleErrors, ExternalServiceMetricsCreateAlertRuleResponses, ExternalServiceMetricsDeleteAlertRuleData, ExternalServiceMetricsDeleteAlertRuleErrors, ExternalServiceMetricsDeleteAlertRuleResponses, ExternalServiceMetricsGetAlertRulesData, ExternalServiceMetricsGetAlertRulesErrors, ExternalServiceMetricsGetAlertRulesResponses, ExternalServiceMetricsGetLatestData, ExternalServiceMetricsGetLatestErrors, ExternalServiceMetricsGetLatestResponses, ExternalServiceMetricsGetRangeData, ExternalServiceMetricsGetRangeErrors, ExternalServiceMetricsGetRangeResponses, ExternalServiceMetricsStatusData, ExternalServiceMetricsStatusErrors, ExternalServiceMetricsStatusResponses, ExternalServiceMetricsToggleData, ExternalServiceMetricsToggleErrors, ExternalServiceMetricsToggleResponses, ExternalServiceMetricsUpdateAlertRuleData, ExternalServiceMetricsUpdateAlertRuleErrors, ExternalServiceMetricsUpdateAlertRuleResponses, ExternalServiceResetPgStatStatementsData, ExternalServiceResetPgStatStatementsErrors, ExternalServiceResetPgStatStatementsResponses, FinalizeOrderData, FinalizeOrderErrors, FinalizeOrderResponses, FinalizeProjectReleaseData, FinalizeProjectReleaseErrors, FinalizeProjectReleaseResponses, FindConversationData, FindConversationErrors, FindConversationResponses, GenerateJoinTokenData, GenerateJoinTokenErrors, GenerateJoinTokenResponses, GeneratePresetDockerfileData, GeneratePresetDockerfileErrors, GeneratePresetDockerfileResponses, GetAccessInfoData, GetAccessInfoErrors, GetAccessInfoResponses, GetActiveVisitorsData, GetActiveVisitorsErrors, GetActiveVisitorsResponses, GetActivityGraphData, GetActivityGraphErrors, GetActivityGraphResponses, GetAdminGateData, GetAdminGateErrors, GetAdminGateResponses, GetAgentData, GetAgentErrors, GetAgentResponses, GetAggregatedBucketsData, GetAggregatedBucketsErrors, GetAggregatedBucketsResponses, GetAiAgentBreakdownData, GetAiAgentBreakdownErrors, GetAiAgentBreakdownResponses, GetAiAgentPagesData, GetAiAgentPagesErrors, GetAiAgentPagesResponses, GetAiAgentTimelineData, GetAiAgentTimelineErrors, GetAiAgentTimelineResponses, GetAiPageBreakdownData, GetAiPageBreakdownErrors, GetAiPageBreakdownResponses, GetAiStatusBreakdownData, GetAiStatusBreakdownErrors, GetAiStatusBreakdownResponses, GetAlertData, GetAlertErrors, GetAlertResponses, GetAlertRuleData, GetAlertRuleErrors, GetAlertRuleResponses, GetAllRepositoriesByNameData, GetAllRepositoriesByNameErrors, GetAllRepositoriesByNameResponses, GetAnalyticsActiveVisitorsData, GetAnalyticsActiveVisitorsErrors, GetAnalyticsActiveVisitorsResponses, GetAnalyticsEventsCountData, GetAnalyticsEventsCountErrors, GetAnalyticsEventsCountResponses, GetAnalyticsSessionEventsData, GetAnalyticsSessionEventsErrors, GetAnalyticsSessionEventsResponses, GetAnalyticsVisitorSessionsData, GetAnalyticsVisitorSessionsErrors, GetAnalyticsVisitorSessionsResponses, GetApiKeyData, GetApiKeyErrors, GetApiKeyPermissionsData, GetApiKeyPermissionsErrors, GetApiKeyPermissionsResponses, GetApiKeyResponses, GetAuditLogData, GetAuditLogErrors, GetAuditLogResponses, GetBackupData, GetBackupErrors, GetBackupResponses, GetBackupScheduleData, GetBackupScheduleErrors, GetBackupScheduleResponses, GetBranchesByRepositoryIdData, GetBranchesByRepositoryIdErrors, GetBranchesByRepositoryIdResponses, GetBucketedIncidentsData, GetBucketedIncidentsErrors, GetBucketedIncidentsResponses, GetBucketedStatusData, GetBucketedStatusErrors, GetBucketedStatusResponses, GetChallengeTokenData, GetChallengeTokenErrors, GetChallengeTokenResponses, GetChatReadinessData, GetChatReadinessErrors, GetChatReadinessResponses, GetCliStatusData, GetCliStatusErrors, GetCliStatusResponses, GetClusterHealthData, GetClusterHealthErrors, GetClusterHealthResponses, GetClusterMemberData, GetClusterMemberErrors, GetClusterMemberResponses, GetCmdData, GetCmdErrors, GetCmdResponses, GetContainerDetailData, GetContainerDetailErrors, GetContainerDetailResponses, GetContainerEnvironmentVariableData, GetContainerEnvironmentVariableErrors, GetContainerEnvironmentVariableResponses, GetContainerInfoData, GetContainerInfoErrors, GetContainerInfoResponses, GetContainerLogsByIdData, GetContainerLogsByIdErrors, GetContainerLogsData, GetContainerLogsErrors, GetContainerMetricsData, GetContainerMetricsErrors, GetContainerMetricsResponses, GetConversationData, GetConversationDetailData, GetConversationDetailErrors, GetConversationDetailResponses, GetConversationErrors, GetConversationResponses, GetConversationsData, GetConversationsErrors, GetConversationsResponses, GetCronByIdData, GetCronByIdErrors, GetCronByIdResponses, GetCronExecutionsData, GetCronExecutionsErrors, GetCronExecutionsResponses, GetCrossProjectTraceSiblingsData, GetCrossProjectTraceSiblingsErrors, GetCrossProjectTraceSiblingsResponses, GetCurrentMonitorStatusData, GetCurrentMonitorStatusErrors, GetCurrentMonitorStatusResponses, GetCurrentUserData, GetCurrentUserErrors, GetCurrentUserResponses, GetCustomDomainData, GetCustomDomainErrors, GetCustomDomainResponses, GetDashboardData, GetDashboardErrors, GetDashboardProjectsAnalyticsData, GetDashboardProjectsAnalyticsErrors, GetDashboardProjectsAnalyticsResponses, GetDashboardResponses, GetDeliveryData, GetDeliveryErrors, GetDeliveryResponses, GetDeploymentContainerLogContentData, GetDeploymentContainerLogContentErrors, GetDeploymentContainerLogContentResponses, GetDeploymentData, GetDeploymentErrors, GetDeploymentJobLogsData, GetDeploymentJobLogsErrors, GetDeploymentJobLogsResponses, GetDeploymentJobsData, GetDeploymentJobsErrors, GetDeploymentJobsResponses, GetDeploymentOperationsData, GetDeploymentOperationsErrors, GetDeploymentOperationsResponses, GetDeploymentOperationStatusData, GetDeploymentOperationStatusErrors, GetDeploymentOperationStatusResponses, GetDeploymentResponses, GetDeploymentTokenData, GetDeploymentTokenErrors, GetDeploymentTokenResponses, GetDiskStatusData, GetDiskStatusErrors, GetDiskStatusResponses, GetDnsChangesData, GetDnsChangesErrors, GetDnsChangesResponses, GetDnsProviderData, GetDnsProviderErrors, GetDnsProviderResponses, GetDomainByHostData, GetDomainByHostErrors, GetDomainByHostResponses, GetDomainByIdData, GetDomainByIdErrors, GetDomainByIdResponses, GetDomainByNameData, GetDomainByNameErrors, GetDomainByNameResponses, GetDomainData, GetDomainDnsRecordsData, GetDomainDnsRecordsErrors, GetDomainDnsRecordsResponses, GetDomainErrors, GetDomainOrderData, GetDomainOrderErrors, GetDomainOrderResponses, GetDomainResponses, GetEmailData, GetEmailErrors, GetEmailEventsData, GetEmailEventsErrors, GetEmailEventsResponses, GetEmailLinksData, GetEmailLinksErrors, GetEmailLinksResponses, GetEmailProviderData, GetEmailProviderErrors, GetEmailProviderResponses, GetEmailResponses, GetEmailStatsData, GetEmailStatsErrors, GetEmailStatsResponses, GetEmailTrackingData, GetEmailTrackingErrors, GetEmailTrackingResponses, GetEmailTrackingStatusData, GetEmailTrackingStatusErrors, GetEmailTrackingStatusResponses, GetEntityInfoData, GetEntityInfoErrors, GetEntityInfoResponses, GetEnvironmentCronsData, GetEnvironmentCronsErrors, GetEnvironmentCronsResponses, GetEnvironmentData, GetEnvironmentDomainsData, GetEnvironmentDomainsErrors, GetEnvironmentDomainsResponses, GetEnvironmentErrors, GetEnvironmentResponses, GetEnvironmentsData, GetEnvironmentsErrors, GetEnvironmentsResponses, GetEnvironmentVariablesData, GetEnvironmentVariablesErrors, GetEnvironmentVariablesResponses, GetEnvironmentVariableValueData, GetEnvironmentVariableValueErrors, GetEnvironmentVariableValueResponses, GetErrorDashboardStatsData, GetErrorDashboardStatsErrors, GetErrorDashboardStatsResponses, GetErrorEventData, GetErrorEventErrors, GetErrorEventResponses, GetErrorGroupData, GetErrorGroupErrors, GetErrorGroupResponses, GetErrorStatsData, GetErrorStatsErrors, GetErrorStatsResponses, GetErrorTimeSeriesData, GetErrorTimeSeriesErrors, GetErrorTimeSeriesResponses, GetEventDetailData, GetEventDetailErrors, GetEventDetailResponses, GetEventEntriesData, GetEventEntriesErrors, GetEventEntriesResponses, GetEventsCountData, GetEventsCountErrors, GetEventsCountResponses, GetEventsTimelineData, GetEventsTimelineErrors, GetEventsTimelineResponses, GetEventTypeBreakdownData, GetEventTypeBreakdownErrors, GetEventTypeBreakdownResponses, GetEventVisitorsData, GetEventVisitorsErrors, GetEventVisitorsResponses, GetExternalImageData, GetExternalImageErrors, GetExternalImageResponses, GetFileData, GetFileErrors, GetFileResponses, GetFlagData, GetFlagErrors, GetFlagResponses, GetFlagSnapshotData, GetFlagSnapshotErrors, GetFlagSnapshotResponses, GetFunnelMetricsData, GetFunnelMetricsErrors, GetFunnelMetricsResponses, GetGenaiTraceData, GetGenaiTraceErrors, GetGenaiTraceResponses, GetGeneralStatsData, GetGeneralStatsErrors, GetGeneralStatsResponses, GetGitProviderData, GetGitProviderErrors, GetGitProviderResponses, GetGlobalEventsData, GetGlobalEventsErrors, GetGlobalEventsResponses, GetGlobalEventStatsData, GetGlobalEventStatsErrors, GetGlobalEventStatsResponses, GetGlobalMcpData, GetGlobalMcpErrors, GetGlobalMcpResponses, GetGlobalSandboxStatusData, GetGlobalSandboxStatusErrors, GetGlobalSandboxStatusResponses, GetGlobalSkillData, GetGlobalSkillErrors, GetGlobalSkillResponses, GetGroupedPageMetricsData, GetGroupedPageMetricsErrors, GetGroupedPageMetricsResponses, GetHealthData, GetHealthErrors, GetHealthResponses, GetHourlyVisitsData, GetHourlyVisitsErrors, GetHourlyVisitsResponses, GetHttpChallengeDebugData, GetHttpChallengeDebugErrors, GetHttpChallengeDebugResponses, GetImportStatusData, GetImportStatusErrors, GetImportStatusResponses, GetIncidentData, GetIncidentErrors, GetIncidentResponses, GetIncidentUpdatesData, GetIncidentUpdatesErrors, GetIncidentUpdatesResponses, GetIpAccessControlData, GetIpAccessControlErrors, GetIpAccessControlResponses, GetIpGeolocationData, GetIpGeolocationErrors, GetIpGeolocationResponses, GetJoinTokenStatusData, GetJoinTokenStatusErrors, GetJoinTokenStatusResponses, GetLastDeploymentData, GetLastDeploymentErrors, GetLastDeploymentResponses, GetLatestScanData, GetLatestScanErrors, GetLatestScanResponses, GetLatestScansPerEnvironmentData, GetLatestScansPerEnvironmentErrors, GetLatestScansPerEnvironmentResponses, GetLiveVisitorsListData, GetLiveVisitorsListErrors, GetLiveVisitorsListResponses, GetLogContextData, GetLogContextErrors, GetLogContextResponses, GetMcpData, GetMcpErrors, GetMcpResponses, GetMetricsOverTimeData, GetMetricsOverTimeErrors, GetMetricsOverTimeResponses, GetMonitorData, GetMonitorErrors, GetMonitorResponses, GetNotificationProviderData, GetNotificationProviderErrors, GetNotificationProviderResponses, GetOnDemandCertStatusData, GetOnDemandCertStatusErrors, GetOnDemandCertStatusResponses, GetOrCreateDsnData, GetOrCreateDsnErrors, GetOrCreateDsnResponses, GetPageFlowData, GetPageFlowErrors, GetPageFlowResponses, GetPageHourlySessionsData, GetPageHourlySessionsErrors, GetPageHourlySessionsResponses, GetPagePathDetailData, GetPagePathDetailErrors, GetPagePathDetailResponses, GetPagePathsData, GetPagePathsErrors, GetPagePathsResponses, GetPagePathsSparklinesData, GetPagePathsSparklinesErrors, GetPagePathsSparklinesResponses, GetPagePathVisitorsData, GetPagePathVisitorsErrors, GetPagePathVisitorsResponses, GetPendingActionData, GetPendingActionErrors, GetPendingActionResponses, GetPerformanceMetricsData, GetPerformanceMetricsErrors, GetPerformanceMetricsResponses, GetPgUpgradeData, GetPgUpgradeErrors, GetPgUpgradeLogsData, GetPgUpgradeLogsErrors, GetPgUpgradeLogsResponses, GetPgUpgradeResponses, GetPipelineStatsData, GetPipelineStatsErrors, GetPipelineStatsResponses, GetPlatformInfoData, GetPlatformInfoErrors, GetPlatformInfoResponses, GetPostgresWalHealthData, GetPostgresWalHealthErrors, GetPostgresWalHealthResponses, GetPreferencesData, GetPreferencesErrors, GetPreferencesResponses, GetPreviewGatewayLogsData, GetPreviewGatewayLogsResponses, GetPreviewGatewaySettingsData, GetPreviewGatewaySettingsResponses, GetPreviewGatewayStatusData, GetPreviewGatewayStatusResponses, GetPricingData, GetPricingErrors, GetPricingResponses, GetPrivateIpData, GetPrivateIpErrors, GetPrivateIpResponses, GetProjectAlarmsSummaryData, GetProjectAlarmsSummaryErrors, GetProjectAlarmsSummaryResponses, GetProjectBySlugData, GetProjectBySlugErrors, GetProjectBySlugResponses, GetProjectData, GetProjectDeploymentsData, GetProjectDeploymentsErrors, GetProjectDeploymentsResponses, GetProjectErrors, GetProjectResponses, GetProjectsData, GetProjectsErrors, GetProjectServiceEnvironmentVariablesData, GetProjectServiceEnvironmentVariablesErrors, GetProjectServiceEnvironmentVariablesResponses, GetProjectSessionReplaysData, GetProjectSessionReplaysErrors, GetProjectSessionReplaysResponses, GetProjectsHealthData, GetProjectsHealthErrors, GetProjectsHealthResponses, GetProjectsMonitorHealthData, GetProjectsMonitorHealthErrors, GetProjectsMonitorHealthResponses, GetProjectsResponses, GetProjectStatisticsData, GetProjectStatisticsErrors, GetProjectStatisticsResponses, GetProjectTemplateData, GetProjectTemplateErrors, GetProjectTemplateResponses, GetPropertyBreakdownData, GetPropertyBreakdownErrors, GetPropertyBreakdownResponses, GetPropertyTimelineData, GetPropertyTimelineErrors, GetPropertyTimelineResponses, GetProviderConnectionsData, GetProviderConnectionsErrors, GetProviderConnectionsResponses, GetProviderMetadataData, GetProviderMetadataErrors, GetProviderMetadataResponses, GetProvidersMetadataData, GetProvidersMetadataErrors, GetProvidersMetadataResponses, GetProxyLogByIdData, GetProxyLogByIdErrors, GetProxyLogByIdResponses, GetProxyLogByRequestIdData, GetProxyLogByRequestIdErrors, GetProxyLogByRequestIdResponses, GetProxyLogsData, GetProxyLogsErrors, GetProxyLogsResponses, GetPublicBranchesData, GetPublicBranchesErrors, GetPublicBranchesResponses, GetPublicIpData, GetPublicIpErrors, GetPublicIpResponses, GetPublicRepositoryData, GetPublicRepositoryErrors, GetPublicRepositoryResponses, GetQuotaData, GetQuotaErrors, GetQuotaResponses, GetRecentActivityData, GetRecentActivityErrors, GetRecentActivityResponses, GetRemoteExternalImageData, GetRemoteExternalImageErrors, GetRemoteExternalImageResponses, GetRepositoryBranchesData, GetRepositoryBranchesErrors, GetRepositoryBranchesResponses, GetRepositoryByIdData, GetRepositoryByIdErrors, GetRepositoryByIdResponses, GetRepositoryByNameData, GetRepositoryByNameErrors, GetRepositoryByNameResponses, GetRepositoryPresetByNameData, GetRepositoryPresetByNameErrors, GetRepositoryPresetByNameResponses, GetRepositoryPresetLiveData, GetRepositoryPresetLiveErrors, GetRepositoryPresetLiveResponses, GetRepositoryTagsData, GetRepositoryTagsErrors, GetRepositoryTagsResponses, GetResolvedEnvironmentVariablesData, GetResolvedEnvironmentVariablesErrors, GetResolvedEnvironmentVariablesResponses, GetResolvedEnvironmentVariableValueData, GetResolvedEnvironmentVariableValueErrors, GetResolvedEnvironmentVariableValueResponses, GetRestoreCapabilitiesData, GetRestoreCapabilitiesErrors, GetRestoreCapabilitiesResponses, GetRestoreRunData, GetRestoreRunErrors, GetRestoreRunResponses, GetRouteData, GetRouteErrors, GetRouteResponses, GetRunData, GetRunErrors, GetRunResponses, GetRunWithLogsData, GetRunWithLogsErrors, GetRunWithLogsResponses, GetS3CredentialsData, GetS3CredentialsErrors, GetS3CredentialsResponses, GetS3SourceData, GetS3SourceErrors, GetS3SourceResponses, GetSandboxData, GetSandboxErrors, GetSandboxResponses, GetSandboxStatusData, GetSandboxStatusErrors, GetSandboxStatusResponses, GetScanByDeploymentData, GetScanByDeploymentErrors, GetScanByDeploymentResponses, GetScanData, GetScanErrors, GetScanResponses, GetScanVulnerabilitiesData, GetScanVulnerabilitiesErrors, GetScanVulnerabilitiesResponses, GetServiceBySlugData, GetServiceBySlugErrors, GetServiceBySlugResponses, GetServiceData, GetServiceEnvironmentVariableData, GetServiceEnvironmentVariableErrors, GetServiceEnvironmentVariableResponses, GetServiceEnvironmentVariablesData, GetServiceEnvironmentVariablesErrors, GetServiceEnvironmentVariablesResponses, GetServiceErrors, GetServiceHealthStatusData, GetServiceHealthStatusErrors, GetServiceHealthStatusResponses, GetServicePreviewEnvironmentVariableNamesData, GetServicePreviewEnvironmentVariableNamesErrors, GetServicePreviewEnvironmentVariableNamesResponses, GetServicePreviewEnvironmentVariablesMaskedData, GetServicePreviewEnvironmentVariablesMaskedErrors, GetServicePreviewEnvironmentVariablesMaskedResponses, GetServiceResponses, GetServiceRuntimeData, GetServiceRuntimeErrors, GetServiceRuntimeResponses, GetServiceStatsData, GetServiceStatsErrors, GetServiceStatsResponses, GetServiceTypeParametersData, GetServiceTypeParametersErrors, GetServiceTypeParametersResponses, GetServiceTypesData, GetServiceTypesErrors, GetServiceTypesResponses, GetSessionDetailsData, GetSessionDetailsErrors, GetSessionDetailsResponses, GetSessionEventsData, GetSessionEventsErrors, GetSessionEventsResponses, GetSessionLogsData, GetSessionLogsErrors, GetSessionLogsResponses, GetSessionReplayData, GetSessionReplayErrors, GetSessionReplayEventsData, GetSessionReplayEventsErrors, GetSessionReplayEventsResponses, GetSessionReplayResponses, GetSettingsData, GetSettingsErrors, GetSettingsResponses, GetSkillData, GetSkillErrors, GetSkillResponses, GetSlowQueriesData, GetSlowQueriesErrors, GetSlowQueriesResponses, GetStaticBundleData, GetStaticBundleErrors, GetStaticBundleResponses, GetStatusOverviewData, GetStatusOverviewErrors, GetStatusOverviewResponses, GetTagsByRepositoryIdData, GetTagsByRepositoryIdErrors, GetTagsByRepositoryIdResponses, GetTeamData, GetTeamErrors, GetTeamResponses, GetTimeBucketStatsData, GetTimeBucketStatsErrors, GetTimeBucketStatsResponses, GetTodayStatsData, GetTodayStatsErrors, GetTodayStatsResponses, GetTraceData, GetTraceErrors, GetTraceResponses, GetUnifiedTraceData, GetUnifiedTraceErrors, GetUnifiedTraceResponses, GetUniqueCountsData, GetUniqueCountsErrors, GetUniqueCountsResponses, GetUniqueEventsData, GetUniqueEventsErrors, GetUniqueEventsResponses, GetUpdateCapabilityData, GetUpdateCapabilityErrors, GetUpdateCapabilityResponses, GetUpdateStatusData, GetUpdateStatusErrors, GetUpdateStatusResponses, GetUptimeHistoryData, GetUptimeHistoryErrors, GetUptimeHistoryResponses, GetUsageByProviderData, GetUsageByProviderErrors, GetUsageByProviderResponses, GetUsageRecentData, GetUsageRecentErrors, GetUsageRecentResponses, GetUsageSummaryData, GetUsageSummaryErrors, GetUsageSummaryResponses, GetUsageTimeseriesData, GetUsageTimeseriesErrors, GetUsageTimeseriesResponses, GetUsageTopModelsData, GetUsageTopModelsErrors, GetUsageTopModelsResponses, GetVisitorByGuidData, GetVisitorByGuidErrors, GetVisitorByGuidResponses, GetVisitorByIdData, GetVisitorByIdErrors, GetVisitorByIdResponses, GetVisitorDetailsData, GetVisitorDetailsErrors, GetVisitorDetailsResponses, GetVisitorFacetsData, GetVisitorFacetsErrors, GetVisitorFacetsResponses, GetVisitorInfoData, GetVisitorInfoErrors, GetVisitorInfoResponses, GetVisitorJourneyData, GetVisitorJourneyErrors, GetVisitorJourneyResponses, GetVisitorsData, GetVisitorsErrors, GetVisitorSessionsData, GetVisitorSessionsErrors, GetVisitorSessionsResponses, GetVisitorsResponses, GetVisitorStatsData, GetVisitorStatsErrors, GetVisitorStatsResponses, GetWebhookData, GetWebhookErrors, GetWebhookResponses, GrantProjectAccessData, GrantProjectAccessErrors, GrantProjectAccessResponses, HandleGitProviderOauthCallbackData, HandleGitProviderOauthCallbackErrors, HasAnalyticsEventsData, HasAnalyticsEventsErrors, HasAnalyticsEventsResponses, HasErrorGroupsData, HasErrorGroupsErrors, HasErrorGroupsResponses, HasPerformanceMetricsData, HasPerformanceMetricsErrors, HasPerformanceMetricsResponses, ImportExternalServiceData, ImportExternalServiceErrors, ImportExternalServiceResponses, IngestLogsByPathData, IngestLogsByPathErrors, IngestLogsByPathResponses, IngestLogsData, IngestLogsErrors, IngestLogsResponses, IngestMetricsByPathData, IngestMetricsByPathErrors, IngestMetricsByPathResponses, IngestMetricsData, IngestMetricsErrors, IngestMetricsResponses, IngestSentryEnvelopeData, IngestSentryEnvelopeErrors, IngestSentryEnvelopeResponses, IngestSentryEventData, IngestSentryEventErrors, IngestSentryEventResponses, IngestTracesByPathData, IngestTracesByPathErrors, IngestTracesByPathResponses, IngestTracesData, IngestTracesErrors, IngestTracesResponses, InitSessionReplayData, InitSessionReplayErrors, InitSessionReplayResponses, InspectDropArchiveData, InspectDropArchiveErrors, InspectDropArchiveResponses, JobLogsData, JobLogsErrors, JobLogsResponses, JobStatusData, JobStatusErrors, JobStatusResponses, KillJobData, KillJobErrors, KillJobResponses, KvDelData, KvDelErrors, KvDelResponses, KvDisableData, KvDisableErrors, KvDisableResponses, KvEnableData, KvEnableErrors, KvEnableResponses, KvExpireData, KvExpireErrors, KvExpireResponses, KvGetData, KvGetErrors, KvGetResponses, KvIncrData, KvIncrErrors, KvIncrResponses, KvKeysData, KvKeysErrors, KvKeysResponses, KvSetData, KvSetErrors, KvSetResponses, KvStatusData, KvStatusErrors, KvStatusResponses, KvTtlData, KvTtlErrors, KvTtlResponses, KvUpdateData, KvUpdateErrors, KvUpdateResponses, LatestRunForSourceData, LatestRunForSourceErrors, LatestRunForSourceResponses, LinkCustomDomainToCertificateData, LinkCustomDomainToCertificateErrors, LinkCustomDomainToCertificateResponses, LinkServiceToProjectData, LinkServiceToProjectErrors, LinkServiceToProjectResponses, ListAgentRunsData, ListAgentRunsErrors, ListAgentRunsResponses, ListAgentsData, ListAgentsErrors, ListAgentsResponses, ListAiProvidersData, ListAiProvidersErrors, ListAiProvidersResponses, ListAlertRulesData, ListAlertRulesErrors, ListAlertRulesResponses, ListAlertsData, ListAlertsErrors, ListAlertsResponses, ListAllConversationsData, ListAllConversationsErrors, ListAllConversationsResponses, ListAllRunsData, ListAllRunsErrors, ListAllRunsResponses, ListApiKeysData, ListApiKeysErrors, ListApiKeysResponses, ListAuditLogsData, ListAuditLogsErrors, ListAuditLogsResponses, ListAvailableContainersData, ListAvailableContainersErrors, ListAvailableContainersResponses, ListBackupAlertsData, ListBackupAlertsErrors, ListBackupAlertsResponses, ListBackupChildrenData, ListBackupChildrenErrors, ListBackupChildrenResponses, ListBackupSchedulesData, ListBackupSchedulesErrors, ListBackupSchedulesResponses, ListBackupsForScheduleData, ListBackupsForScheduleErrors, ListBackupsForScheduleResponses, ListCommitsByRepositoryIdData, ListCommitsByRepositoryIdErrors, ListCommitsByRepositoryIdResponses, ListConnectionsData, ListConnectionsErrors, ListConnectionsResponses, ListContainersAtPathData, ListContainersAtPathErrors, ListContainersAtPathResponses, ListContainersData, ListContainersErrors, ListContainersResponses, ListConversationsData, ListConversationsErrors, ListConversationsResponses, ListCustomDomainsForProjectData, ListCustomDomainsForProjectErrors, ListCustomDomainsForProjectResponses, ListDashboardsData, ListDashboardsErrors, ListDashboardsResponses, ListDeliveriesData, ListDeliveriesErrors, ListDeliveriesResponses, ListDeploymentContainerLogsData, ListDeploymentContainerLogsErrors, ListDeploymentContainerLogsResponses, ListDeploymentTokensData, ListDeploymentTokensErrors, ListDeploymentTokensResponses, ListDnsProvidersData, ListDnsProvidersErrors, ListDnsProvidersResponses, ListDomainsData, ListDomainsErrors, ListDomainsResponses, ListDsnsData, ListDsnsErrors, ListDsnsResponses, ListEmailDomainsData, ListEmailDomainsErrors, ListEmailDomainsResponses, ListEmailProvidersData, ListEmailProvidersErrors, ListEmailProvidersResponses, ListEmailsData, ListEmailsErrors, ListEmailsResponses, ListEnrollmentTokensData, ListEnrollmentTokensErrors, ListEnrollmentTokensResponses, ListEntitiesData, ListEntitiesErrors, ListEntitiesResponses, ListErrorEventsData, ListErrorEventsErrors, ListErrorEventsResponses, ListErrorGroupsData, ListErrorGroupsErrors, ListErrorGroupsResponses, ListEventsData, ListEventsResponses, ListEventTypesData, ListEventTypesResponses, ListExternalImagesData, ListExternalImagesErrors, ListExternalImagesResponses, ListExternalPluginsData, ListExternalPluginsErrors, ListExternalPluginsResponses, ListExternalServiceBackupsData, ListExternalServiceBackupsErrors, ListExternalServiceBackupsResponses, ListFlagsData, ListFlagsErrors, ListFlagsResponses, ListFunnelsData, ListFunnelsErrors, ListFunnelsResponses, ListGitProvidersData, ListGitProvidersErrors, ListGitProvidersResponses, ListGlobalMcpsData, ListGlobalMcpsErrors, ListGlobalMcpsResponses, ListGlobalSkillsData, ListGlobalSkillsErrors, ListGlobalSkillsResponses, ListIncidentsData, ListIncidentsErrors, ListIncidentsResponses, ListInsightsData, ListInsightsErrors, ListInsightsResponses, ListIpAccessControlData, ListIpAccessControlErrors, ListIpAccessControlResponses, ListJobsData, ListJobsErrors, ListJobsResponses, ListKnownAiAgentsData, ListKnownAiAgentsErrors, ListKnownAiAgentsResponses, ListManagedDomainsData, ListManagedDomainsErrors, ListManagedDomainsResponses, ListMcpsData, ListMcpsErrors, ListMcpsResponses, ListMetricLabelKeysData, ListMetricLabelKeysErrors, ListMetricLabelKeysResponses, ListMetricLabelValuesData, ListMetricLabelValuesErrors, ListMetricLabelValuesResponses, ListMetricNamesData, ListMetricNamesErrors, ListMetricNamesResponses, ListModelsData, ListModelsErrors, ListModelsResponses, ListMonitorsData, ListMonitorsErrors, ListMonitorsResponses, ListNotificationProvidersData, ListNotificationProvidersErrors, ListNotificationProvidersResponses, ListOidcProvidersData, ListOidcProvidersResponses, ListOidcProviderUsersData, ListOidcProviderUsersErrors, ListOidcProviderUsersResponses, ListOidcRoleMappingsData, ListOidcRoleMappingsResponses, ListOnDemandCertsData, ListOnDemandCertsErrors, ListOnDemandCertsResponses, ListOrdersData, ListOrdersErrors, ListOrdersResponses, ListPeersData, ListPeersErrors, ListPeersResponses, ListPendingActionsData, ListPendingActionsErrors, ListPendingActionsResponses, ListPgUpgradesData, ListPgUpgradesErrors, ListPgUpgradesResponses, ListPresetsData, ListPresetsErrors, ListPresetsResponses, ListProjectAccessData, ListProjectAccessErrors, ListProjectAccessResponses, ListProjectAlarmsData, ListProjectAlarmsErrors, ListProjectAlarmsResponses, ListProjectScansData, ListProjectScansErrors, ListProjectScansResponses, ListProjectSecretsData, ListProjectSecretsErrors, ListProjectSecretsResponses, ListProjectServicesData, ListProjectServicesErrors, ListProjectServicesResponses, ListProjectTemplatesData, ListProjectTemplatesErrors, ListProjectTemplatesResponses, ListProjectTemplateTagsData, ListProjectTemplateTagsErrors, ListProjectTemplateTagsResponses, ListProviderKeysData, ListProviderKeysErrors, ListProviderKeysResponses, ListProviderZonesData, ListProviderZonesErrors, ListProviderZonesResponses, ListPublicProvidersData, ListPublicProvidersResponses, ListReleaseFilesData, ListReleaseFilesErrors, ListReleaseFilesResponses, ListReleasesData, ListReleasesErrors, ListReleasesResponses, ListRemoteExternalImagesData, ListRemoteExternalImagesErrors, ListRemoteExternalImagesResponses, ListRepositoriesByConnectionData, ListRepositoriesByConnectionErrors, ListRepositoriesByConnectionResponses, ListRepositoriesByProviderData, ListRepositoriesByProviderErrors, ListRepositoriesByProviderResponses, ListRestoreRunsForServiceData, ListRestoreRunsForServiceResponses, ListRootContainersData, ListRootContainersErrors, ListRootContainersResponses, ListRoutesData, ListRoutesErrors, ListRoutesResponses, ListS3SourcesData, ListS3SourcesErrors, ListS3SourcesResponses, ListSandboxesData, ListSandboxesResponses, ListScheduleRunJobsData, ListScheduleRunJobsErrors, ListScheduleRunJobsResponses, ListScheduleRunsData, ListScheduleRunsErrors, ListScheduleRunsResponses, ListScheduleServicesData, ListScheduleServicesErrors, ListScheduleServicesResponses, ListSecretsData, ListSecretsErrors, ListSecretsResponses, ListServiceHealthStatusesData, ListServiceHealthStatusesErrors, ListServiceHealthStatusesResponses, ListServiceProjectsData, ListServiceProjectsErrors, ListServiceProjectsResponses, ListServiceSchedulesData, ListServiceSchedulesErrors, ListServiceSchedulesResponses, ListServicesData, ListServicesErrors, ListServicesResponses, ListSkillsData, ListSkillsErrors, ListSkillsResponses, ListSourceBackupsData, ListSourceBackupsErrors, ListSourceBackupsResponses, ListSourceFilesData, ListSourceFilesErrors, ListSourceFilesResponses, ListSourceMapsData, ListSourceMapsErrors, ListSourceMapsResponses, ListSourcesData, ListSourcesErrors, ListSourcesResponses, ListStaticBundlesData, ListStaticBundlesErrors, ListStaticBundlesResponses, ListSyncedRepositoriesData, ListSyncedRepositoriesErrors, ListSyncedRepositoriesResponses, ListTeamMembersData, ListTeamMembersErrors, ListTeamMembersResponses, ListTeamProjectsData, ListTeamProjectsErrors, ListTeamProjectsResponses, ListTeamsData, ListTeamsErrors, ListTeamsResponses, ListUsersData, ListUsersErrors, ListUsersResponses, ListWebhooksData, ListWebhooksErrors, ListWebhooksResponses, LoginData, LoginErrors, LoginResponses, LogoutData, LogoutErrors, LogoutResponses, LookupDnsARecordsData, LookupDnsARecordsErrors, LookupDnsARecordsResponses, MintEnrollmentTokenData, MintEnrollmentTokenErrors, MintEnrollmentTokenResponses, MkdirData, MkdirErrors, MkdirResponses, NodeHeartbeatData, NodeHeartbeatErrors, NodeHeartbeatResponses, NodeMetricsGetRangeData, NodeMetricsGetRangeErrors, NodeMetricsGetRangeResponses, ObservabilityFullEventData, ObservabilityFullEventErrors, ObservabilityFullEventResponses, ObservabilityListEventsData, ObservabilityListEventsErrors, ObservabilityListEventsResponses, OidcCallbackData, PatchAdminGateData, PatchAdminGateErrors, PatchAdminGateResponses, PatchPreviewGatewaySettingsData, PatchPreviewGatewaySettingsResponses, PauseDeploymentData, PauseDeploymentErrors, PauseDeploymentResponses, PauseSandboxData, PauseSandboxErrors, PauseSandboxResponses, PlanRestoreData, PlanRestoreErrors, PlanRestoreResponses, PostDnsAckData, PostDnsAckErrors, PostDnsAckResponses, PreviewAlertData, PreviewAlertErrors, PreviewAlertResponses, PreviewFunnelMetricsData, PreviewFunnelMetricsErrors, PreviewFunnelMetricsResponses, PreviewHostnameModeData, PreviewHostnameModeErrors, PreviewHostnameModeResponses, PromoteClusterMemberData, PromoteClusterMemberErrors, PromoteClusterMemberResponses, PromoteDeploymentData, PromoteDeploymentErrors, PromoteDeploymentResponses, ProvisionDomainData, ProvisionDomainErrors, ProvisionDomainResponses, PurgeProjectLogsData, PurgeProjectLogsErrors, PurgeProjectLogsResponses, PushExternalImageData, PushExternalImageErrors, PushExternalImageResponses, QueryDataData, QueryDataErrors, QueryDataResponses, QueryGenaiTracesData, QueryGenaiTracesErrors, QueryGenaiTracesResponses, QueryLogsData, QueryLogsErrors, QueryLogsResponses, QueryMetricsData, QueryMetricsErrors, QueryMetricsResponses, QueryTracesData, QueryTracesErrors, QueryTracesResponses, QueryTraceSummariesData, QueryTraceSummariesErrors, QueryTraceSummariesResponses, ReadFileData, ReadFileErrors, ReadFileResponses, ReAnalyzeData, ReAnalyzeErrors, ReAnalyzeResponses, RecordConsoleEventData, RecordConsoleEventErrors, RecordConsoleEventResponses, RecordEventMetricsData, RecordEventMetricsErrors, RecordEventMetricsResponses, RecordFlagExposureData, RecordFlagExposureErrors, RecordFlagExposureResponses, RecordSpeedMetricsData, RecordSpeedMetricsErrors, RecordSpeedMetricsResponses, RefreshRouteTableData, RefreshRouteTableErrors, RefreshRouteTableResponses, RegenerateDsnData, RegenerateDsnErrors, RegenerateDsnResponses, RegisterExternalImageData, RegisterExternalImageErrors, RegisterExternalImageResponses, RegisterNodeData, RegisterNodeErrors, RegisterNodeResponses, ReinstallGitlabWebhookData, ReinstallGitlabWebhookErrors, ReinstallGitlabWebhookResponses, RejectPendingActionData, RejectPendingActionErrors, RejectPendingActionResponses, ReloadPluginsData, ReloadPluginsErrors, ReloadPluginsResponses, RemoveClusterMemberData, RemoveClusterMemberErrors, RemoveClusterMemberResponses, RemoveManagedDomainData, RemoveManagedDomainErrors, RemoveManagedDomainResponses, RemoveRoleData, RemoveRoleErrors, RemoveRoleResponses, RemoveTeamMemberData, RemoveTeamMemberErrors, RemoveTeamMemberResponses, RenameConversationData, RenameConversationErrors, RenameConversationResponses, RenewDomainData, RenewDomainErrors, RenewDomainResponses, RequestPasswordResetData, RequestPasswordResetErrors, RequestPasswordResetResponses, ResetPasswordData, ResetPasswordErrors, ResetPasswordResponses, ResizeSandboxData, ResizeSandboxErrors, ResizeSandboxResponses, ResolveAlarmData, ResolveAlarmErrors, ResolveAlarmResponses, RestartContainerData, RestartContainerErrors, RestartContainerResponses, RestartPreviewGatewayData, RestartPreviewGatewayResponses, RestartSandboxData, RestartSandboxErrors, RestartSandboxResponses, RestoreFlagData, RestoreFlagErrors, RestoreFlagResponses, RestoreUserData, RestoreUserErrors, RestoreUserResponses, ResumeDeploymentData, ResumeDeploymentErrors, ResumeDeploymentResponses, ResumeSandboxData, ResumeSandboxErrors, ResumeSandboxResponses, RetryClusterData, RetryClusterErrors, RetryClusterResponses, RetryDeliveryData, RetryDeliveryErrors, RetryDeliveryResponses, RetryPgUpgradeData, RetryPgUpgradeErrors, RetryPgUpgradeResponses, RetryRunData, RetryRunErrors, RetryRunResponses, RevealGlobalMcpConfigData, RevealGlobalMcpConfigErrors, RevealGlobalMcpConfigResponses, RevealMcpConfigData, RevealMcpConfigErrors, RevealMcpConfigResponses, RevealNotificationProviderConfigData, RevealNotificationProviderConfigErrors, RevealNotificationProviderConfigResponses, RevealServiceParameterData, RevealServiceParameterErrors, RevealServiceParameterResponses, RevenueCreateIntegrationData, RevenueCreateIntegrationErrors, RevenueCreateIntegrationResponses, RevenueDeleteIntegrationData, RevenueDeleteIntegrationResponses, RevenueGlobalEventsData, RevenueGlobalEventsResponses, RevenueImportInvoicesCsvData, RevenueImportInvoicesCsvErrors, RevenueImportInvoicesCsvResponses, RevenueImportSubscriptionsCsvData, RevenueImportSubscriptionsCsvErrors, RevenueImportSubscriptionsCsvResponses, RevenueListIntegrationsData, RevenueListIntegrationsResponses, RevenueListProvidersData, RevenueListProvidersResponses, RevenueMetricsCustomersData, RevenueMetricsCustomersResponses, RevenueMetricsGlobalMrrData, RevenueMetricsGlobalMrrResponses, RevenueMetricsGlobalSummaryData, RevenueMetricsGlobalSummaryResponses, RevenueMetricsMrrData, RevenueMetricsMrrResponses, RevenueMetricsSummaryData, RevenueMetricsSummaryResponses, RevenueRecentEventsData, RevenueRecentEventsResponses, RevenueRotateTokenData, RevenueRotateTokenResponses, RevenueUpdateConfigData, RevenueUpdateConfigErrors, RevenueUpdateConfigResponses, RevenueUpdateSecretData, RevenueUpdateSecretErrors, RevenueUpdateSecretResponses, RevokeDsnData, RevokeDsnErrors, RevokeDsnResponses, RevokeEnrollmentTokenData, RevokeEnrollmentTokenErrors, RevokeEnrollmentTokenResponses, RevokeJoinTokenData, RevokeJoinTokenErrors, RevokeJoinTokenResponses, RevokeProjectAccessData, RevokeProjectAccessErrors, RevokeProjectAccessResponses, RollbackPgUpgradeData, RollbackPgUpgradeErrors, RollbackPgUpgradeResponses, RollbackToDeploymentData, RollbackToDeploymentErrors, RollbackToDeploymentResponses, RootfsGcData, RootfsGcResponses, RootfsReportData, RootfsReportResponses, RotateApiKeyData, RotateApiKeyErrors, RotateApiKeyResponses, RotateDeploymentTokenData, RotateDeploymentTokenErrors, RotateDeploymentTokenResponses, RunBackupForSourceData, RunBackupForSourceErrors, RunBackupForSourceResponses, RunConnectionHealthCheckData, RunConnectionHealthCheckErrors, RunConnectionHealthCheckResponses, RunExternalServiceBackupData, RunExternalServiceBackupErrors, RunExternalServiceBackupResponses, RunScheduleNowData, RunScheduleNowErrors, RunScheduleNowResponses, SandboxCreatePreviewLinkData, SandboxCreatePreviewLinkErrors, SandboxCreatePreviewLinkResponses, SaveAgentTokenData, SaveAgentTokenErrors, SaveAgentTokenResponses, SaveAiProviderCredentialData, SaveAiProviderCredentialErrors, SaveAiProviderCredentialResponses, SearchLogsData, SearchLogsErrors, SearchLogsResponses, SendEmailData, SendEmailErrors, SendEmailResponses, SetDefaultS3SourceData, SetDefaultS3SourceErrors, SetDefaultS3SourceResponses, SetFlagEnvironmentData, SetFlagEnvironmentErrors, SetFlagEnvironmentResponses, SetPreviewPasswordData, SetPreviewPasswordErrors, SetPreviewPasswordResponses, SetupDnsChallengeData, SetupDnsChallengeErrors, SetupDnsChallengeResponses, SetupDnsData, SetupDnsErrors, SetupDnsResponses, SetupEmailTrackingData, SetupEmailTrackingErrors, SetupEmailTrackingResponses, SetupMfaData, SetupMfaErrors, SetupMfaResponses, SleepEnvironmentData, SleepEnvironmentErrors, SleepEnvironmentResponses, SmokeTestAgentData, SmokeTestAgentErrors, SmokeTestAgentResponses, SourceSandboxData, SourceSandboxErrors, SourceSandboxResponses, StartAnalysisData, StartAnalysisErrors, StartAnalysisResponses, StartContainerData, StartContainerErrors, StartContainerResponses, StartFixData, StartFixErrors, StartFixResponses, StartGitProviderOauthData, StartGitProviderOauthErrors, StartOidcLoginBySlugData, StartOidcLoginBySlugErrors, StartPgUpgradeData, StartPgUpgradeErrors, StartPgUpgradeResponses, StartRestoreData, StartRestoreErrors, StartRestoreResponses, StartServiceData, StartServiceErrors, StartServiceResponses, StartUpdateData, StartUpdateErrors, StartUpdateResponses, StatPathData, StatPathErrors, StatPathResponses, StopContainerData, StopContainerErrors, StopContainerResponses, StopSandboxData, StopSandboxErrors, StopSandboxResponses, StopServiceData, StopServiceErrors, StopServiceResponses, StreamContainerMetricsData, StreamContainerMetricsErrors, StreamContainerMetricsResponses, StreamEventsData, StreamEventsErrors, StreamEventsResponses, StreamRunEventsData, StreamRunEventsErrors, StreamRunEventsResponses, SyncRepositoriesData, SyncRepositoriesErrors, SyncRepositoriesResponses, TailDeploymentJobLogsData, TailDeploymentJobLogsErrors, TailLogsData, TailLogsErrors, TailLogsResponses, TeardownDeploymentData, TeardownDeploymentErrors, TeardownDeploymentResponses, TeardownEnvironmentData, TeardownEnvironmentErrors, TeardownEnvironmentResponses, TestNotificationProviderData, TestNotificationProviderErrors, TestNotificationProviderResponses, TestOidcProviderData, TestOidcProviderResponses, TestProviderConnectionData, TestProviderConnectionErrors, TestProviderConnectionResponses, TestProviderData, TestProviderErrors, TestProviderKeyByIdData, TestProviderKeyByIdErrors, TestProviderKeyByIdResponses, TestProviderKeyInlineData, TestProviderKeyInlineErrors, TestProviderKeyInlineResponses, TestProviderResponses, TestS3ConnectionPreviewData, TestS3ConnectionPreviewErrors, TestS3ConnectionPreviewResponses, TestS3SourceConnectionData, TestS3SourceConnectionErrors, TestS3SourceConnectionResponses, TrackClickData, TrackClickErrors, TrackOpenData, TrackOpenErrors, TrackOpenResponses, TriggerAgentData, TriggerAgentErrors, TriggerAgentResponses, TriggerProjectPipelineData, TriggerProjectPipelineErrors, TriggerProjectPipelineResponses, TriggerScanData, TriggerScanErrors, TriggerScanResponses, TriggerServiceHealthCheckData, TriggerServiceHealthCheckErrors, TriggerServiceHealthCheckResponses, TriggerWeeklyDigestData, TriggerWeeklyDigestErrors, TriggerWeeklyDigestResponses, UnlinkServiceFromProjectData, UnlinkServiceFromProjectErrors, UnlinkServiceFromProjectResponses, UpdateAgentData, UpdateAgentErrors, UpdateAgentResponses, UpdateAiProviderData, UpdateAiProviderErrors, UpdateAiProviderResponses, UpdateAlertData, UpdateAlertErrors, UpdateAlertResponses, UpdateAlertRuleData, UpdateAlertRuleErrors, UpdateAlertRuleResponses, UpdateApiKeyData, UpdateApiKeyErrors, UpdateApiKeyResponses, UpdateAutomaticDeployData, UpdateAutomaticDeployErrors, UpdateAutomaticDeployResponses, UpdateBackupScheduleData, UpdateBackupScheduleErrors, UpdateBackupScheduleResponses, UpdateCloudflareProviderData, UpdateCloudflareProviderErrors, UpdateCloudflareProviderResponses, UpdateConnectionTokenData, UpdateConnectionTokenErrors, UpdateConnectionTokenResponses, UpdateCustomDomainData, UpdateCustomDomainErrors, UpdateCustomDomainResponses, UpdateDashboardData, UpdateDashboardErrors, UpdateDashboardResponses, UpdateDeploymentTokenData, UpdateDeploymentTokenErrors, UpdateDeploymentTokenResponses, UpdateEmailProviderData, UpdateEmailProviderErrors, UpdateEmailProviderResponses, UpdateEnvironmentSettingsData, UpdateEnvironmentSettingsErrors, UpdateEnvironmentSettingsResponses, UpdateEnvironmentSubdomainData, UpdateEnvironmentSubdomainErrors, UpdateEnvironmentSubdomainResponses, UpdateEnvironmentVariableData, UpdateEnvironmentVariableErrors, UpdateEnvironmentVariableResponses, UpdateErrorGroupData, UpdateErrorGroupErrors, UpdateErrorGroupResponses, UpdateFlagData, UpdateFlagErrors, UpdateFlagResponses, UpdateFunnelData, UpdateFunnelErrors, UpdateFunnelResponses, UpdateGitProviderCredentialsData, UpdateGitProviderCredentialsErrors, UpdateGitProviderCredentialsResponses, UpdateGitSettingsData, UpdateGitSettingsErrors, UpdateGitSettingsResponses, UpdateGlobalMcpData, UpdateGlobalMcpErrors, UpdateGlobalMcpResponses, UpdateGlobalSkillData, UpdateGlobalSkillErrors, UpdateGlobalSkillResponses, UpdateIncidentStatusData, UpdateIncidentStatusErrors, UpdateIncidentStatusResponses, UpdateIpAccessControlData, UpdateIpAccessControlErrors, UpdateIpAccessControlResponses, UpdateManagedDomainData, UpdateManagedDomainErrors, UpdateManagedDomainResponses, UpdateMcpData, UpdateMcpErrors, UpdateMcpResponses, UpdateNotificationEmailProviderData, UpdateNotificationEmailProviderErrors, UpdateNotificationEmailProviderResponses, UpdateNotificationProviderData, UpdateNotificationProviderErrors, UpdateNotificationProviderResponses, UpdateOidcProviderData, UpdateOidcProviderResponses, UpdatePreferencesData, UpdatePreferencesErrors, UpdatePreferencesResponses, UpdateProjectData, UpdateProjectDeploymentConfigData, UpdateProjectDeploymentConfigErrors, UpdateProjectDeploymentConfigResponses, UpdateProjectErrors, UpdateProjectResponses, UpdateProjectSecretData, UpdateProjectSecretErrors, UpdateProjectSecretResponses, UpdateProjectSettingsData, UpdateProjectSettingsErrors, UpdateProjectSettingsResponses, UpdateProviderData, UpdateProviderErrors, UpdateProviderKeyData, UpdateProviderKeyErrors, UpdateProviderKeyResponses, UpdateProviderResponses, UpdateRouteData, UpdateRouteErrors, UpdateRouteResponses, UpdateS3SourceData, UpdateS3SourceErrors, UpdateS3SourceResponses, UpdateSelfData, UpdateSelfErrors, UpdateSelfResponses, UpdateServiceData, UpdateServiceErrors, UpdateServiceResourcesData, UpdateServiceResourcesErrors, UpdateServiceResourcesResponses, UpdateServiceResponses, UpdateSessionDurationData, UpdateSessionDurationErrors, UpdateSessionDurationResponses, UpdateSettingsData, UpdateSettingsErrors, UpdateSettingsResponses, UpdateSkillData, UpdateSkillErrors, UpdateSkillResponses, UpdateSlackProviderData, UpdateSlackProviderErrors, UpdateSlackProviderResponses, UpdateSpeedMetricsData, UpdateSpeedMetricsErrors, UpdateSpeedMetricsResponses, UpdateTeamData, UpdateTeamErrors, UpdateTeamMemberRoleData, UpdateTeamMemberRoleErrors, UpdateTeamMemberRoleResponses, UpdateTeamResponses, UpdateUserData, UpdateUserErrors, UpdateUserResponses, UpdateWebhookData, UpdateWebhookErrors, UpdateWebhookProviderData, UpdateWebhookProviderErrors, UpdateWebhookProviderResponses, UpdateWebhookResponses, UpgradePreviewGatewayData, UpgradePreviewGatewayResponses, UpgradeServiceData, UpgradeServiceErrors, UpgradeServiceResponses, UploadGlobalSkillData, UploadGlobalSkillErrors, UploadGlobalSkillResponses, UploadReleaseFileData, UploadReleaseFileErrors, UploadReleaseFileResponses, UploadSkillData, UploadSkillErrors, UploadSkillResponses, UploadSourceFileData, UploadSourceFileErrors, UploadSourceFileResponses, UploadSourceMapData, UploadSourceMapErrors, UploadSourceMapResponses, UploadStaticBundleData, UploadStaticBundleErrors, UploadStaticBundleResponses, UpsertSecretData, UpsertSecretErrors, UpsertSecretResponses, ValidateConnectionData, ValidateConnectionErrors, ValidateConnectionResponses, ValidateEmailData, ValidateEmailErrors, ValidateEmailResponses, VerifyAndEnableMfaData, VerifyAndEnableMfaErrors, VerifyAndEnableMfaResponses, VerifyDomainData, VerifyDomainErrors, VerifyDomainResponses, VerifyEmailData, VerifyEmailErrors, VerifyEmailResponses, VerifyManagedDomainData, VerifyManagedDomainErrors, VerifyManagedDomainResponses, VerifyMfaChallengeData, VerifyMfaChallengeErrors, VerifyMfaChallengeResponses, VerifyStepUpData, VerifyStepUpErrors, VerifyStepUpResponses, WakeEnvironmentData, WakeEnvironmentErrors, WakeEnvironmentResponses, WebhookTriggerData, WebhookTriggerErrors, WebhookTriggerResponses, WorkflowDryRunData, WorkflowDryRunErrors, WorkflowDryRunResponses, WriteFileData, WriteFileErrors, WriteFileResponses, WriteFilesData, WriteFilesErrors, WriteFilesResponses } from './types.gen'; export type Options = Options2 & { /** @@ -7217,6 +7217,33 @@ export const downloadGlobalSkillArchive = ...options }); +/** + * Report whether a release update can be applied from the console. + */ +export const getUpdateCapability = (options?: Options): RequestResult => (options?.client ?? client).get({ + security: [{ scheme: 'bearer', type: 'http' }], + url: '/settings/update', + ...options +}); + +/** + * Install a release and restart the server. + * + * Returns as soon as the attempt is accepted: the download and swap run in the + * background and the process then exits so its supervisor restarts it on the + * new binary. Poll `GET /settings/update` for progress — after the restart, + * `last_attempt` carries the outcome. + */ +export const startUpdate = (options: Options): RequestResult => (options.client ?? client).post({ + security: [{ scheme: 'bearer', type: 'http' }], + url: '/settings/update', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); + /** * Report whether a newer temps release is available for this install. */ diff --git a/web/src/api/client/types.gen.ts b/web/src/api/client/types.gen.ts index fb1566cca..561af54ae 100644 --- a/web/src/api/client/types.gen.ts +++ b/web/src/api/client/types.gen.ts @@ -1094,6 +1094,16 @@ export type AppSettings = { require_mfa_for_admins?: boolean; screenshots?: ScreenshotSettings; security_headers?: SecurityHeadersSettings; + /** + * One-click "Update now" from the console. Enabled by default; an admin + * can turn it off here to keep upgrades on the CLI/config-management path. + * + * This is the *soft* switch — it is stored in the database, so whoever can + * write settings can also turn it back on. Operators who need an upgrade + * path that no console session can re-open should start the server with + * `--disable-self-update`, which wins over this field unconditionally. + */ + self_update?: SelfUpdateSettings; /** * Set to `true` by `temps setup` (all modes) once initial configuration * has been applied. The web onboarding wizard reads this from the server @@ -1178,6 +1188,13 @@ export type AppSettingsResponse = { require_mfa_for_admins: boolean; screenshots: ScreenshotSettings; security_headers: SecurityHeadersSettings; + /** + * Whether admins may apply a release from the console. This is the + * database-backed toggle only — a server started with + * `--disable-self-update` refuses regardless of what this says, which + * `GET /settings/update` reports as the authoritative answer. + */ + self_update: SelfUpdateSettings; /** * Whether `temps setup` has been run at least once. The web onboarding * wizard checks this field on load and skips itself when true. @@ -12396,6 +12413,12 @@ export type PropertyBreakdownQuery = { * Property column to group by */ group_by: PropertyColumn; + /** + * Include crawler/bot traffic (default: false). Off by default so the + * breakdown percentages share a denominator with the headline counts, + * which always exclude crawlers. + */ + include_crawlers?: boolean | null; /** * Maximum number of results to return (default: 20, max: 100) */ @@ -12452,6 +12475,11 @@ export type PropertyTimelineQuery = { * Property column to group by */ group_by: PropertyColumn; + /** + * Include crawler/bot traffic (default: false). See + * [`PropertyBreakdownQuery::include_crawlers`]. + */ + include_crawlers?: boolean | null; /** * Start date for the query range */ @@ -14441,6 +14469,73 @@ export type SecurityHeadersSettings = { x_xss_protection?: string; }; +/** + * A single update attempt. Persisted to `/self-update.json` so the + * result survives the restart it causes. + */ +export type SelfUpdateAttempt = { + /** + * Operator-facing failure reason. Always set when `status` is `Failed`. + */ + error?: string | null; + /** + * When the outcome was decided. `None` while still `Pending`. + */ + finished_at?: string | null; + /** + * Version the attempt started from. + */ + from_version: string; + /** + * Where the replaced binary was kept, so a bad release can be reverted by + * hand (`mv `). Set once the swap completes. + */ + previous_binary_path?: string | null; + started_at: string; + status: SelfUpdateStatus; + /** + * Version the attempt targeted. `None` if it failed before resolving one. + */ + to_version?: string | null; + /** + * User who clicked the button. `None` for attempts started by the CLI. + */ + triggered_by_user_id?: number | null; +}; + +/** + * Why a one-click update is unavailable. Exactly one is reported — the most + * fundamental blocker wins, so the operator fixes the real problem first + * rather than clearing one only to hit the next. + */ +export type SelfUpdateBlocker = 'disabled_by_flag' | 'disabled_by_setting' | 'container' | 'no_supervisor' | 'binary_not_writable' | 'unsupported_platform' | 'in_progress'; + +/** + * Where an in-flight update has got to. Polled by the console so a long + * download shows progress instead of an indefinite spinner. + */ +export type SelfUpdatePhase = 'idle' | 'resolving' | 'downloading' | 'verifying' | 'installing' | 'restarting' | 'failed'; + +/** + * Controls the console's one-click "Update now" action. + */ +export type SelfUpdateSettings = { + /** + * Allow admins to apply a release and restart the server from the console. + * `true` by default: the action is permission-gated, audited, and only + * ever installs an official release whose published SHA-256 matches. + * + * Turning this off hides nothing — the console still shows the update + * banner and the manual command, it just refuses to run it for you. + */ + enabled?: boolean; +}; + +/** + * Outcome of an update attempt, as persisted in the journal. + */ +export type SelfUpdateStatus = 'pending' | 'succeeded' | 'failed'; + export type SendEmailRequestBody = { /** * BCC recipients @@ -16010,6 +16105,33 @@ export type StartRestoreRequest = RestoreRequestMode & { s3_source_id?: number | null; }; +/** + * Optional pin for the version to install. + */ +export type StartUpdateRequest = { + /** + * Release tag to install (e.g. `v0.2.0`). Omit to take the newest release + * on the channel this install already tracks. + */ + version?: string | null; +}; + +/** + * Acknowledgement that an update was accepted and is running. + */ +export type StartUpdateResponse = { + /** + * Version the server is running as it accepts this request. + */ + current_version: string; + /** + * How long to allow for the server to come back before treating the + * restart as failed. + */ + estimated_restart_secs: number; + message: string; +}; + export type StatResponse = { exists: boolean; is_dir: boolean; @@ -16236,6 +16358,11 @@ export type StripeConfig = { product_allowlist?: Array; }; +/** + * What (if anything) will restart the process after it exits. + */ +export type SupervisorKind = 'systemd' | 'launchd' | 'container' | 'none'; + export type SyncedRepositoryListQuery = { direction?: string | null; git_provider_connection_id?: number | null; @@ -17162,6 +17289,57 @@ export type UpdateBlobResponse = { success: boolean; }; +/** + * Whether this install can apply a release update on request, and how the last + * attempt went. + * + * Deliberately answerable even when the answer is "no": an operator who cannot + * use the button still needs to know *why* and what to run instead, so this + * never 404s or returns an empty body when the feature is unavailable. + */ +export type UpdateCapabilityResponse = { + /** + * Whether the *caller* holds `platform:update`. Distinct from `can_apply`, + * which describes the server: the console shows the action only when both + * are true, so a reader is never offered a button that would 403. + */ + allowed: boolean; + /** + * Binary that would be replaced. + */ + binary_path: string; + blocker?: null | SelfUpdateBlocker; + /** + * True only when a request would actually download, install and restart. + */ + can_apply: boolean; + /** + * Non-blocking warning to show with the confirmation (split topology). + */ + caveat?: string | null; + last_attempt?: null | SelfUpdateAttempt; + /** + * The equivalent command to run by hand. Always present. + */ + manual_command: string; + /** + * Phase of an in-flight attempt: `idle` when none is running. + */ + phase: SelfUpdatePhase; + /** + * Failure detail while `phase` is `failed`. + */ + phase_error?: string | null; + /** + * Operator-facing explanation of `blocker`. + */ + reason?: string | null; + /** + * What would restart the process: `systemd`, `launchd`, `container`, `none`. + */ + supervisor: SupervisorKind; +}; + export type UpdateCloudflareProviderRequest = { config: CloudflareConfig; enabled?: boolean | null; @@ -40845,6 +41023,10 @@ export type GetPropertyBreakdownData = { * Maximum number of results (default: 20, max: 100) */ limit?: number; + /** + * Include crawler/bot traffic (default: false) + */ + include_crawlers?: boolean; /** * Filter by country (for region/city drill-downs) */ @@ -40938,6 +41120,10 @@ export type GetPropertyTimelineData = { * Time bucket: hour, day, week, month (default: auto-detect) */ bucket_size?: string; + /** + * Include crawler/bot traffic (default: false) + */ + include_crawlers?: boolean; }; url: '/projects/{project_id}/events/properties/timeline'; }; @@ -47085,6 +47271,70 @@ export type DownloadGlobalSkillArchiveResponses = { export type DownloadGlobalSkillArchiveResponse = DownloadGlobalSkillArchiveResponses[keyof DownloadGlobalSkillArchiveResponses]; +export type GetUpdateCapabilityData = { + body?: never; + path?: never; + query?: never; + url: '/settings/update'; +}; + +export type GetUpdateCapabilityErrors = { + /** + * Unauthorized + */ + 401: unknown; + /** + * Insufficient permissions + */ + 403: unknown; +}; + +export type GetUpdateCapabilityResponses = { + /** + * Self-update capability for this install + */ + 200: UpdateCapabilityResponse; +}; + +export type GetUpdateCapabilityResponse = GetUpdateCapabilityResponses[keyof GetUpdateCapabilityResponses]; + +export type StartUpdateData = { + body: StartUpdateRequest; + path?: never; + query?: never; + url: '/settings/update'; +}; + +export type StartUpdateErrors = { + /** + * Unauthorized + */ + 401: unknown; + /** + * Insufficient permissions + */ + 403: unknown; + /** + * Update unavailable or already running + */ + 409: ProblemDetails; + /** + * This process cannot apply updates + */ + 501: ProblemDetails; +}; + +export type StartUpdateError = StartUpdateErrors[keyof StartUpdateErrors]; + +export type StartUpdateResponses = { + /** + * Update accepted; the server will restart + */ + 202: StartUpdateResponse; +}; + +export type StartUpdateResponse2 = StartUpdateResponses[keyof StartUpdateResponses]; + export type GetUpdateStatusData = { body?: never; path?: never; diff --git a/web/src/api/platformSettings.ts b/web/src/api/platformSettings.ts index 44e402665..d186bef1a 100644 --- a/web/src/api/platformSettings.ts +++ b/web/src/api/platformSettings.ts @@ -229,6 +229,10 @@ export async function updatePlatformSettings( monitoring: updated.monitoring, observability_compression: updated.observability_compression, observability_retention: updated.observability_retention, + // Must be sent on every save: the server deserializes `AppSettings` with + // `#[serde(default)]`, so omitting this field would silently re-enable + // console updates whenever any other settings page is saved. + self_update: updated.self_update, } const result = await updateSettings({ body }) if (result.error) { diff --git a/web/src/components/alerts/UpdateAvailableBanner.tsx b/web/src/components/alerts/UpdateAvailableBanner.tsx index 0b83df7b1..e05c34300 100644 --- a/web/src/components/alerts/UpdateAvailableBanner.tsx +++ b/web/src/components/alerts/UpdateAvailableBanner.tsx @@ -1,5 +1,7 @@ import { Button } from '@/components/ui/button' import { useUpdateStatus } from '@/hooks/useUpdateStatus' +import { useSelfUpdateCapability } from '@/hooks/useSelfUpdate' +import { UpdateNowDialog } from '@/components/alerts/UpdateNowDialog' import { ArrowUpCircle, X } from 'lucide-react' import { useState } from 'react' import { cn } from '@/lib/utils' @@ -28,6 +30,17 @@ export function UpdateAvailableBanner() { // Seed from storage once; the setter below keeps render state and storage // in sync when the user dismisses. const [dismissedVersion, setDismissedVersion] = useState(readDismissedVersion) + const [updateOpen, setUpdateOpen] = useState(false) + // Only asked for once there is something to update to, so an up-to-date + // install never pays for the check. + const { data: capability } = useSelfUpdateCapability({ + enabled: Boolean(data?.update_available), + }) + + // Offered to anyone holding `platform:update`, even when the server itself + // cannot apply it — the dialog then explains why and gives the command to + // run instead, which is more use than a button that silently isn't there. + const canOfferUpdate = Boolean(capability?.allowed) if (!data?.update_available || !data.latest_version) { return null @@ -52,53 +65,78 @@ export function UpdateAvailableBanner() { // Informational (not a warning): same thin single-line strip as the // disk-space banner, but with a calm blue treatment. return ( -
- -

- Update available - - {' '}— {data.latest_version} - - - {' '}— temps {data.current_version} →{' '} - {data.latest_version} - {data.channel && ` on the ${data.channel} channel`} - -

- {data.release_url && ( + <> +
+ +

+ Update available + + {' '} + — {data.latest_version} + + + {' '} + — temps + {data.current_version} + →{' '} + {data.latest_version} + {data.channel && ` on the ${data.channel} channel`} + +

+ {canOfferUpdate && ( + + )} + {data.release_url && ( + + Release notes + + )} - Release notes + How to upgrade - )} - - How to upgrade - - -
+ +
+ + {/* Mounted unconditionally with an `open` prop so the dialog keeps its + watch state if the banner re-renders mid-update. */} + + ) } diff --git a/web/src/components/alerts/UpdateNowDialog.tsx b/web/src/components/alerts/UpdateNowDialog.tsx new file mode 100644 index 000000000..5a60dae75 --- /dev/null +++ b/web/src/components/alerts/UpdateNowDialog.tsx @@ -0,0 +1,373 @@ +import { + AlertDialog, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, +} from '@/components/ui/alert-dialog' +import { Button } from '@/components/ui/button' +import { CopyButton } from '@/components/ui/copy-button' +import { + useInvalidateUpdateStatus, + useSelfUpdateCapability, + useStartSelfUpdate, +} from '@/hooks/useSelfUpdate' +import type { SelfUpdateAttempt, SelfUpdatePhase } from '@/api/client/types.gen' +import { + AlertTriangle, + ArrowUpCircle, + CheckCircle2, + Loader2, + Terminal, + XCircle, +} from 'lucide-react' +import { useEffect, useMemo, useRef, useState } from 'react' + +/** How often the server is asked where the update has got to. */ +const POLL_MS = 2000 + +/** Extra time allowed on top of the server's own estimate before we stop + * waiting and tell the user to go look at the host. */ +const RESTART_GRACE_SECS = 60 + +const PHASE_LABEL: Record = { + idle: 'Starting…', + resolving: 'Finding the release…', + downloading: 'Downloading…', + verifying: 'Verifying checksum…', + installing: 'Installing…', + restarting: 'Restarting the server…', + failed: 'Failed', +} + +interface UpdateNowDialogProps { + open: boolean + onOpenChange: (open: boolean) => void + /** Version tag the server reports as newest, for the confirmation copy. */ + latestVersion?: string | null + currentVersion?: string | null +} + +/** + * Confirm-and-watch dialog for applying a release from the console. + * + * The interesting part is what happens after "Update and restart": the server + * deliberately stops answering partway through, so this keeps polling across + * the downtime and reports the recorded outcome once it is back. It never + * closes itself on success — a stale console bundle is still loaded in the + * browser, so the user is offered an explicit reload. + */ +export function UpdateNowDialog({ + open, + onOpenChange, + latestVersion, + currentVersion, +}: UpdateNowDialogProps) { + const [watching, setWatching] = useState(false) + const [waitedTooLong, setWaitedTooLong] = useState(false) + // `last_attempt` as it looked before we started, so a result left over from a + // previous update is never mistaken for this one's. + const baselineAttemptRef = useRef(null) + const deadlineRef = useRef(null) + + const { data: capability, isPending: capabilityPending } = + useSelfUpdateCapability({ + enabled: open, + pollMs: watching ? POLL_MS : undefined, + }) + const startUpdate = useStartSelfUpdate() + const invalidateUpdateStatus = useInvalidateUpdateStatus() + + const attempt = capability?.last_attempt ?? null + const isOurResult = + watching && + attempt != null && + attempt.status !== 'pending' && + attempt.started_at !== baselineAttemptRef.current + + const result: SelfUpdateAttempt | null = isOurResult ? attempt : null + + // Stop polling once the attempt resolves, and refresh the banner's own + // "update available" state so it disappears after a successful upgrade. + useEffect(() => { + if (result) { + setWatching(false) + deadlineRef.current = null + invalidateUpdateStatus() + } + }, [result, invalidateUpdateStatus]) + + // Give up waiting eventually. A server that never comes back is a real + // outcome and must be reported as one, not as a spinner that runs forever. + useEffect(() => { + if (!watching) { + setWaitedTooLong(false) + return + } + const timer = setInterval(() => { + if (deadlineRef.current && Date.now() > deadlineRef.current) { + setWaitedTooLong(true) + } + }, 1000) + return () => clearInterval(timer) + }, [watching]) + + const blockedReason = useMemo(() => { + if (!capability) return null + if (!capability.allowed) { + return 'Your account does not have permission to update the platform (platform:update).' + } + if (!capability.can_apply) { + return capability.reason ?? 'Updating from the console is not available.' + } + return null + }, [capability]) + + const handleStart = async () => { + baselineAttemptRef.current = capability?.last_attempt?.started_at ?? null + setWaitedTooLong(false) + try { + const started = await startUpdate.mutateAsync({ body: {} }) + deadlineRef.current = + Date.now() + + ((started?.estimated_restart_secs ?? 45) + RESTART_GRACE_SECS) * 1000 + setWatching(true) + } catch { + // The mutation's error is rendered below; nothing to do here. + } + } + + const handleClose = (next: boolean) => { + if (!next) { + setWatching(false) + deadlineRef.current = null + } + onOpenChange(next) + } + + const phase = capability?.phase ?? 'idle' + const startError = startUpdate.error + + return ( + + + + + {result?.status === 'succeeded' ? ( + + ) : result?.status === 'failed' ? ( + + ) : ( + + )} + {result?.status === 'succeeded' + ? 'Update complete' + : result?.status === 'failed' + ? 'Update failed' + : watching + ? 'Updating temps' + : 'Update temps'} + + +
+ {result ? ( + + ) : watching ? ( + + ) : ( + + )} + + {startError ? ( +

+ {errorDetail(startError)} +

+ ) : null} +
+
+
+ + + {result?.status === 'succeeded' ? ( + <> + Close + + + ) : watching ? ( + Hide + ) : ( + <> + Cancel + + + )} + +
+
+ ) +} + +function ConfirmBody({ + currentVersion, + latestVersion, + blockedReason, + caveat, + manualCommand, + binaryPath, + loading, +}: { + currentVersion?: string | null + latestVersion?: string | null + blockedReason: string | null + caveat: string | null + manualCommand: string + binaryPath: string + loading: boolean +}) { + return ( + <> +

+ temps will download{' '} + + {latestVersion ?? 'the latest release'} + + , verify its checksum, replace the binary + {currentVersion && ( + <> + {' '} + (currently {currentVersion}) + + )}{' '} + and restart. +

+

+ The server — including proxied traffic to your deployed apps — is + unavailable for a few seconds while it restarts. The previous binary is + kept alongside the new one so you can roll back by hand. +

+ + {caveat && ( +

+ + {caveat} +

+ )} + + {loading ? ( +

Checking this server…

+ ) : ( + blockedReason && ( +
+

+ + {blockedReason} +

+
+ + + {manualCommand} + + +
+
+ ) + )} + + {binaryPath && !blockedReason && ( +

+ Replaces {binaryPath} +

+ )} + + ) +} + +function WatchingBody({ + phase, + waitedTooLong, +}: { + phase: SelfUpdatePhase + waitedTooLong: boolean +}) { + return ( + <> +

+ + {PHASE_LABEL[phase] ?? 'Working…'} +

+

+ The console loses contact with the server while it restarts — that is + expected. This dialog reports the result as soon as it is back. +

+ {waitedTooLong && ( +

+ + + The server has not come back yet. Check the service on the host ( + systemctl status temps and{' '} + journalctl -u temps). The + previous binary was kept as a{' '} + .bak file next to the current + one. + +

+ )} + + ) +} + +function ResultBody({ result }: { result: SelfUpdateAttempt }) { + if (result.status === 'succeeded') { + return ( + <> +

+ temps is now running{' '} + {result.to_version} (was{' '} + {result.from_version}). +

+

+ Reload the console to pick up the matching web assets. +

+ + ) + } + return ( + <> +

{result.error ?? 'The update did not complete.'}

+

+ The server is still running{' '} + {result.from_version}. +

+ + ) +} + +/** Pull the Problem Details `detail` out of a failed mutation. */ +function errorDetail(error: unknown): string { + const problem = error as { detail?: string; message?: string } | null + return problem?.detail ?? problem?.message ?? 'Could not start the update.' +} diff --git a/web/src/components/settings/PlatformUpdatesCard.tsx b/web/src/components/settings/PlatformUpdatesCard.tsx new file mode 100644 index 000000000..5a4f0d357 --- /dev/null +++ b/web/src/components/settings/PlatformUpdatesCard.tsx @@ -0,0 +1,115 @@ +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from '@/components/ui/card' +import { CopyButton } from '@/components/ui/copy-button' +import { Label } from '@/components/ui/label' +import { Switch } from '@/components/ui/switch' +import { useSelfUpdateCapability } from '@/hooks/useSelfUpdate' +import { useSettings, useUpdateSettings } from '@/hooks/useSettings' +import { AlertTriangle, Info, Terminal } from 'lucide-react' +import { toast } from 'sonner' + +/** + * Operator control for the console's "Update now" action. + * + * Shows the toggle *and* what the server independently makes of it — an admin + * who turns this on while the host has no supervisor (or is a container) would + * otherwise be left wondering why the button never appears. + */ +export function PlatformUpdatesCard() { + const { data: settings } = useSettings() + const updateSettings = useUpdateSettings() + const { data: capability } = useSelfUpdateCapability() + + const enabled = settings?.self_update?.enabled ?? true + // A launch flag beats the database, so the toggle is inert (and says so) + // rather than pretending to control something it doesn't. + const overriddenByFlag = capability?.blocker === 'disabled_by_flag' + + const handleToggle = async (next: boolean) => { + try { + await updateSettings.mutateAsync({ + self_update: { enabled: next }, + }) + toast.success( + next + ? 'Updates can now be applied from the console' + : 'Console updates disabled' + ) + } catch { + // useUpdateSettings surfaces the failure toast. + } + } + + return ( + + + Platform updates + + Whether admins can install a new temps release and restart the server + from the console. The update banner and the manual command are shown + either way. + + + +
+
+ +

+ Requires the platform:update{' '} + permission. Every attempt is audited. +

+
+ +
+ + {overriddenByFlag && ( +

+ + + This server was started with{' '} + --disable-self-update, which + overrides this setting. Remove the flag and restart temps to allow + console updates. + +

+ )} + + {capability && !capability.can_apply && !overriddenByFlag && ( +
+

+ + {capability.reason} +

+
+ + + {capability.manual_command} + + +
+
+ )} + + {capability?.can_apply && ( +

+ Managed by{' '} + {capability.supervisor} · + replaces {capability.binary_path} +

+ )} +
+
+ ) +} diff --git a/web/src/hooks/useSelfUpdate.ts b/web/src/hooks/useSelfUpdate.ts new file mode 100644 index 000000000..eaf5c4fd0 --- /dev/null +++ b/web/src/hooks/useSelfUpdate.ts @@ -0,0 +1,60 @@ +import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query' +import { + getUpdateCapabilityOptions, + getUpdateCapabilityQueryKey, + getUpdateStatusQueryKey, + startUpdateMutation, +} from '@/api/client/@tanstack/react-query.gen' + +/** + * Whether this server can install a release on request, and how the last + * attempt went. + * + * Cheap (in-memory state plus one settings read), but not free, so it is only + * fetched where the answer is actually used — pass `enabled: false` to skip it. + * While an update is running, `pollMs` turns this into the progress feed: the + * server reports `phase` as it downloads, verifies and installs. + */ +export function useSelfUpdateCapability({ + enabled = true, + pollMs, +}: { enabled?: boolean; pollMs?: number } = {}) { + return useQuery({ + ...getUpdateCapabilityOptions(), + enabled, + refetchInterval: pollMs, + staleTime: pollMs ? 0 : 60 * 1000, + // Deliberately keep retrying while polling: the server is EXPECTED to stop + // answering mid-update (that is the restart), and giving up on the first + // failure would strand the UI on "connection lost" exactly when the user + // most needs to see the outcome. + retry: pollMs ? true : false, + retryDelay: 2000, + }) +} + +/** + * Start an update. Resolves as soon as the server accepts it — the download and + * restart happen afterwards, observable through {@link useSelfUpdateCapability}. + */ +export function useStartSelfUpdate() { + const queryClient = useQueryClient() + + return useMutation({ + ...startUpdateMutation(), + onSuccess: () => { + // The capability now reports a running attempt; refetch so polling starts + // from the real phase rather than the stale idle snapshot. + queryClient.invalidateQueries({ queryKey: getUpdateCapabilityQueryKey() }) + }, + }) +} + +/** Drop the cached "update available" notice once the server is back. */ +export function useInvalidateUpdateStatus() { + const queryClient = useQueryClient() + return () => { + queryClient.invalidateQueries({ queryKey: getUpdateStatusQueryKey() }) + queryClient.invalidateQueries({ queryKey: getUpdateCapabilityQueryKey() }) + } +} diff --git a/web/src/pages/Settings.tsx b/web/src/pages/Settings.tsx index 05ac50641..320b8df77 100644 --- a/web/src/pages/Settings.tsx +++ b/web/src/pages/Settings.tsx @@ -25,6 +25,7 @@ import { type PlatformSettings, } from '@/hooks/useSettings' import { client } from '@/api/client/client.gen' +import { PlatformUpdatesCard } from '@/components/settings/PlatformUpdatesCard' import { AlertCircle, Globe, @@ -499,6 +500,9 @@ export function Settings() { + {/* Saves on toggle, so it stays out of this form's dirty tracking. */} + + {isDirty && (
From 906cc23559080b6c809e07ccbcc797ca36e2db6a Mon Sep 17 00:00:00 2001 From: David Viejo Date: Thu, 6 Aug 2026 12:39:58 +0200 Subject: [PATCH 2/7] feat(settings): version page, release channels, and install without a restart MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three changes on top of the console update action. **Installing no longer requires a supervisor.** A missing systemd/launchd was treated as a blocker, so the one case where an operator most wants help — a temps they start themselves — got a refusal. Installing the binary was always possible there; only the restart wasn't. The two are now separate: every permitted install proceeds, and `restart_mode` says up front whether temps restarts itself (`automatic`) or keeps serving the old binary until the operator restarts it (`manual`). Containers move the same way, from refusal to an install plus a caveat that recreating the container reverts to the image. The journal gained `installed_pending_restart` for that state. It resolves to `succeeded` when the new version finally boots, and — importantly — stays put rather than failing when the old one boots again, because a restart the operator hasn't done yet is not a failed update. **A Version page** under Settings → Version: the running version, the channel and where it came from, the supervisor and what a restart will do, the binary path, an explicit "Check for updates" that queries the release API instead of waiting for the periodic pass, and the outcome of the last attempt. The platform-updates toggle moves here from the Platform page rather than being duplicated. **Release channels are selectable.** `self_update.channel` pins stable, beta or nightly; unset keeps the previous behaviour of inferring from the running version tag. The background notifier re-reads it every pass, so switching takes effect without a restart. A check that finds nothing newer now clears the shared notice — otherwise moving a nightly box onto stable would leave the old nightly banner up forever, since stable is older and could never overwrite it. Adds `POST /settings/update/check`, with CLI parity as `temps platform update check` and `temps platform update channel [name|auto]`. --- apps/temps-cli/openapi.json | 2 +- apps/temps-cli/src/api/index.ts | 4 +- apps/temps-cli/src/api/sdk.gen.ts | 12 +- apps/temps-cli/src/api/types.gen.ts | 112 ++++- apps/temps-cli/src/commands/platform/index.ts | 132 +++++ crates/temps-cli/src/commands/serve/mod.rs | 5 + .../src/commands/serve/self_update.rs | 412 ++++++++++++--- crates/temps-cli/src/commands/upgrade.rs | 34 +- crates/temps-config/src/handler.rs | 131 ++++- crates/temps-core/src/app_settings.rs | 15 +- crates/temps-core/src/lib.rs | 5 +- crates/temps-core/src/self_update.rs | 159 +++++- crates/temps-core/src/update_status.rs | 22 + web/src/App.tsx | 6 + .../api/client/@tanstack/react-query.gen.ts | 22 +- web/src/api/client/index.ts | 4 +- web/src/api/client/sdk.gen.ts | 12 +- web/src/api/client/types.gen.ts | 112 ++++- web/src/components/alerts/UpdateNowDialog.tsx | 82 ++- web/src/components/dashboard/Sidebar.tsx | 2 + .../settings/PlatformUpdatesCard.tsx | 115 ----- web/src/hooks/useSelfUpdate.ts | 35 +- web/src/pages/Settings.tsx | 4 - web/src/pages/settings/VersionPage.tsx | 473 ++++++++++++++++++ 24 files changed, 1613 insertions(+), 299 deletions(-) delete mode 100644 web/src/components/settings/PlatformUpdatesCard.tsx create mode 100644 web/src/pages/settings/VersionPage.tsx diff --git a/apps/temps-cli/openapi.json b/apps/temps-cli/openapi.json index d4523c0be..2f90ae316 100644 --- a/apps/temps-cli/openapi.json +++ b/apps/temps-cli/openapi.json @@ -1 +1 @@ -{"openapi":"3.1.0","info":{"title":"Temps","description":"An API for managing projects, deployments, and infrastructure resources","contact":{"name":"Temps Support","url":"https://temps.sh"},"version":"1.0.0"},"servers":[{"url":"/api","description":"Base path for all API endpoints"}],"paths":{"/.well-known/temps.json":{"get":{"tags":["Platform"],"summary":"Get platform information","operationId":"get_platform_info","responses":{"200":{"description":"Successfully retrieved platform information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlatformInfo"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/0/organizations/{org_slug}/chunk-upload/":{"get":{"tags":["sentry-compat"],"summary":"Chunk upload options (stub for sentry-cli compatibility).","description":"sentry-cli checks this endpoint to determine if chunk-based upload is supported.\nWe return a response indicating that chunk upload is NOT supported, which forces\nsentry-cli to fall back to the standard file-by-file upload.","operationId":"chunk_upload_options","parameters":[{"name":"org_slug","in":"path","description":"Organization slug (ignored)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Chunk upload options","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryChunkUploadResponse"}}}}}}},"/0/organizations/{org_slug}/releases/":{"post":{"tags":["sentry-compat"],"summary":"Create a release (stub for sentry-cli compatibility).","description":"sentry-cli calls this before uploading files. Since Temps implicitly creates\nreleases when source maps are uploaded, this is a no-op that returns the\nexpected response format.","operationId":"create_release","parameters":[{"name":"org_slug","in":"path","description":"Organization slug (ignored in single-tenant mode)","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryCreateReleaseRequest"}}},"required":true},"responses":{"201":{"description":"Release created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryReleaseResponse"}}}},"401":{"description":"Unauthorized"}}}},"/0/projects/{org_slug}/{project_slug}/releases/":{"post":{"tags":["sentry-compat"],"summary":"Create a release for a specific project (stub for sentry-cli compatibility).","description":"sentry-cli calls this endpoint (instead of /organizations/.../releases/) when\nboth SENTRY_ORG and SENTRY_PROJECT env vars are set. Behaves identically to\nthe organizations endpoint but validates the project slug.","operationId":"create_project_release","parameters":[{"name":"org_slug","in":"path","description":"Organization slug (ignored in single-tenant mode)","required":true,"schema":{"type":"string"}},{"name":"project_slug","in":"path","description":"Project slug or numeric ID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryCreateReleaseRequest"}}},"required":true},"responses":{"201":{"description":"Release created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryReleaseResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Project not found"}}}},"/0/projects/{org_slug}/{project_slug}/releases/{version}/":{"put":{"tags":["sentry-compat"],"summary":"Finalize a release (stub for sentry-cli compatibility).","description":"sentry-cli calls `releases finalize` after uploading source maps. This sets\nthe dateReleased on the release. Since Temps stores source maps independently\nof releases, this is a no-op that returns the expected response.","operationId":"finalize_project_release","parameters":[{"name":"org_slug","in":"path","description":"Organization slug (ignored)","required":true,"schema":{"type":"string"}},{"name":"project_slug","in":"path","description":"Project slug or numeric ID","required":true,"schema":{"type":"string"}},{"name":"version","in":"path","description":"Release version to finalize","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Release finalized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryReleaseResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Project not found"}}}},"/0/projects/{org_slug}/{project_slug}/releases/{version}/files/":{"get":{"tags":["sentry-compat"],"summary":"List files for a release.","description":"Returns all source maps stored for a specific release in sentry-cli compatible format.","operationId":"list_release_files","parameters":[{"name":"org_slug","in":"path","description":"Organization slug (ignored)","required":true,"schema":{"type":"string"}},{"name":"project_slug","in":"path","description":"Project slug or numeric ID","required":true,"schema":{"type":"string"}},{"name":"version","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of release files","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SentryReleaseFileResponse"}}}}},"401":{"description":"Unauthorized"},"404":{"description":"Project not found"}}},"post":{"tags":["sentry-compat"],"summary":"Upload a source map file for a release.","description":"Accepts the same multipart format as the Sentry release files API.\nThe `name` field should be the URL path of the file (e.g., `~/dist/bundle.js.map`).\n\nThe route has a 50 MiB body limit applied at the router level (Fix #4).\nA per-field size check provides an additional defense-in-depth layer.","operationId":"upload_release_file","parameters":[{"name":"org_slug","in":"path","description":"Organization slug (ignored)","required":true,"schema":{"type":"string"}},{"name":"project_slug","in":"path","description":"Project slug or numeric ID","required":true,"schema":{"type":"string"}},{"name":"version","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"201":{"description":"File uploaded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryReleaseFileResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"404":{"description":"Project not found"},"413":{"description":"Source map file exceeds the 50 MiB per-field limit"}}}},"/_temps/event":{"post":{"tags":["Metrics"],"summary":"Record analytics event","operationId":"record_event_metrics","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventMetricsPayload"}}},"required":true},"responses":{"204":{"description":"Event recorded successfully"},"400":{"description":"Bad request"},"500":{"description":"Internal server error"}}}},"/_temps/session-replay/events":{"post":{"tags":["Analytics"],"summary":"Add events to existing session replay","operationId":"add_session_replay_events","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionReplayEventsRequest"}}},"required":true},"responses":{"200":{"description":"Events added successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddEventsResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Session not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/_temps/session-replay/init":{"post":{"tags":["Analytics"],"summary":"Initialize session replay with metadata","operationId":"init_session_replay","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionReplayInitRequest"}}},"required":true},"responses":{"201":{"description":"Session initialized successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionReplayInitResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/_temps/speed":{"post":{"tags":["Performance"],"summary":"Record performance metrics from client","operationId":"record_speed_metrics","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpeedMetricsPayload"}}},"required":true},"responses":{"204":{"description":"Metrics recorded successfully"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Host not found in route table","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/_temps/speed/update":{"post":{"tags":["Performance"],"summary":"Update late performance metrics","operationId":"update_speed_metrics","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSpeedMetricsPayload"}}},"required":true},"responses":{"204":{"description":"Metrics updated successfully"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Host not found or metrics not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/admin/gate-settings":{"get":{"tags":["AdminGate"],"operationId":"get_admin_gate","responses":{"200":{"description":"Current admin gate config","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminGateResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["AdminGate"],"operationId":"patch_admin_gate","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAdminGateRequest"}}},"required":true},"responses":{"200":{"description":"Updated admin gate config","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminGateResponse"}}}},"400":{"description":"Invalid IP/CIDR/host"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"409":{"description":"Env-overridden or would lock out caller"}},"security":[{"bearer_auth":[]}]}},"/admin/oidc/providers":{"get":{"tags":["Authentication"],"operationId":"list_oidc_providers","responses":{"200":{"description":"OIDC providers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/OidcProviderResponse"}}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Authentication"],"operationId":"create_oidc_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateOidcProviderRequest"}}},"required":true},"responses":{"201":{"description":"OIDC provider created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OidcProviderResponse"}}}},"409":{"description":"Another OIDC provider already uses that name"}},"security":[{"bearer_auth":[]}]}},"/admin/oidc/providers/{provider_id}":{"delete":{"tags":["Authentication"],"operationId":"delete_oidc_provider","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"OIDC provider deleted"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Authentication"],"operationId":"update_oidc_provider","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateOidcProviderRequest"}}},"required":true},"responses":{"200":{"description":"OIDC provider updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OidcProviderResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/admin/oidc/providers/{provider_id}/role-mappings":{"get":{"tags":["Authentication"],"operationId":"list_oidc_role_mappings","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"OIDC role mappings","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/OidcRoleMappingResponse"}}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Authentication"],"operationId":"create_oidc_role_mapping","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateOidcRoleMappingRequest"}}},"required":true},"responses":{"201":{"description":"Role mapping created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OidcRoleMappingResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/admin/oidc/providers/{provider_id}/test":{"post":{"tags":["Authentication"],"operationId":"test_oidc_provider","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Connection test result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OidcTestConnectionResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/admin/oidc/providers/{provider_id}/users":{"get":{"tags":["Authentication"],"operationId":"list_oidc_provider_users","parameters":[{"name":"provider_id","in":"path","description":"OIDC provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Users authenticated via this OIDC provider","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/OidcProviderUserResponse"}}}}},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]}},"/admin/oidc/role-mappings/{mapping_id}":{"delete":{"tags":["Authentication"],"operationId":"delete_oidc_role_mapping","parameters":[{"name":"mapping_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Role mapping deleted"}},"security":[{"bearer_auth":[]}]}},"/agents/webhook/{webhook_id}":{"post":{"tags":["Agents"],"summary":"Public webhook endpoint. Authenticated via `X-Webhook-Token` header.","description":"`POST /api/agents/webhook/{webhook_id}`\nHeader: `X-Webhook-Token: `\n\nThe `webhook_id` in the URL is a short non-secret identifier (safe to log).\nThe actual credential is the secret token in the header.\n\nAccepts any JSON body, which is passed as `user_context` to the agent run.","operationId":"webhook_trigger","parameters":[{"name":"webhook_id","in":"path","description":"Webhook ID (non-secret)","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookTriggerRequest"}}},"required":true},"responses":{"202":{"description":"Agent run created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookTriggerResponse"}}}},"401":{"description":"Missing or invalid X-Webhook-Token header"},"404":{"description":"Invalid webhook ID"},"422":{"description":"Agent disabled"}}}},"/ai/conversations":{"get":{"tags":["AI Chat"],"summary":"List every active conversation across all projects, most-recently-active\nfirst, annotated with project name/slug. Powers the unified \"all chats\"\nswitcher in the AI assistant dock.","operationId":"list_all_conversations","responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GlobalConversationResponse"}}}}},"401":{"description":""},"403":{"description":""}},"security":[{"bearer_auth":[]}]}},"/ai/pricing":{"get":{"tags":["AI Gateway Pricing"],"operationId":"get_pricing","responses":{"200":{"description":"Model pricing information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PricingResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/providers":{"get":{"tags":["AI Gateway Admin"],"operationId":"list_provider_keys","responses":{"200":{"description":"List of provider keys","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProviderKeyResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["AI Gateway Admin"],"operationId":"create_provider_key","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProviderKeyRequest"}}},"required":true},"responses":{"201":{"description":"Provider key created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderKeyResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/providers/test":{"post":{"tags":["AI Gateway Admin"],"operationId":"test_provider_key_inline","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestProviderKeyRequest"}}},"required":true},"responses":{"200":{"description":"Test result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestProviderKeyResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/providers/{id}":{"delete":{"tags":["AI Gateway Admin"],"operationId":"delete_provider_key","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Provider key deleted"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["AI Gateway Admin"],"operationId":"update_provider_key","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProviderKeyRequest"}}},"required":true},"responses":{"200":{"description":"Provider key updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderKeyResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/providers/{id}/test":{"post":{"tags":["AI Gateway Admin"],"operationId":"test_provider_key_by_id","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Test result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestProviderKeyResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Provider key not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/usage/by-provider":{"get":{"tags":["AI Gateway Usage"],"operationId":"get_usage_by_provider","parameters":[{"name":"from","in":"query","description":"ISO 8601 start time (defaults to 24h ago)","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","description":"ISO 8601 end time (defaults to now)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Usage broken down by provider","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProviderUsage"}}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/usage/conversations":{"get":{"tags":["AI Gateway Usage"],"operationId":"get_conversations","parameters":[{"name":"from","in":"query","description":"ISO 8601 start time (defaults to 24h ago)","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","description":"ISO 8601 end time (defaults to now)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max results (defaults to 50, max 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"user_id","in":"query","description":"Filter by user ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"tags","in":"query","description":"Filter by tags (comma-separated)","required":false,"schema":{"type":"string"}},{"name":"model","in":"query","description":"Filter by model name","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Conversation summaries","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ConversationSummary"}}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/usage/conversations/{conversation_id}":{"get":{"tags":["AI Gateway Usage"],"operationId":"get_conversation_detail","parameters":[{"name":"conversation_id","in":"path","description":"Conversation ID","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max results (defaults to 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Invocations within a conversation","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/UsageLogEntry"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/usage/recent":{"get":{"tags":["AI Gateway Usage"],"operationId":"get_usage_recent","parameters":[{"name":"limit","in":"query","description":"Page size (defaults to 20, max 50)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"offset","in":"query","description":"Number of results to skip for pagination (defaults to 0)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"provider","in":"query","description":"Filter by provider name","required":false,"schema":{"type":"string"}},{"name":"model","in":"query","description":"Filter by model name","required":false,"schema":{"type":"string"}},{"name":"status","in":"query","description":"Filter by HTTP status code (exact match)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"cost_gte","in":"query","description":"Cost greater-than-or-equal, in microcents","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"cost_gt","in":"query","description":"Cost strictly greater-than, in microcents","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"cost_lte","in":"query","description":"Cost less-than-or-equal, in microcents","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"cost_lt","in":"query","description":"Cost strictly less-than, in microcents","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"tokens_gte","in":"query","description":"Total tokens greater-than-or-equal","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"tokens_gt","in":"query","description":"Total tokens strictly greater-than","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"tokens_lte","in":"query","description":"Total tokens less-than-or-equal","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"tokens_lt","in":"query","description":"Total tokens strictly less-than","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Page of recent usage log entries","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsageLogPage"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/usage/summary":{"get":{"tags":["AI Gateway Usage"],"operationId":"get_usage_summary","parameters":[{"name":"from","in":"query","description":"ISO 8601 start time (defaults to 24h ago)","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","description":"ISO 8601 end time (defaults to now)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Usage summary for the time range","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsageSummary"}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/usage/timeseries":{"get":{"tags":["AI Gateway Usage"],"operationId":"get_usage_timeseries","parameters":[{"name":"from","in":"query","description":"ISO 8601 start time (defaults to 24h ago)","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","description":"ISO 8601 end time (defaults to now)","required":false,"schema":{"type":"string"}},{"name":"bucket","in":"query","description":"Bucket size: hour, day, week (defaults to day)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Time-series usage data","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TimeseriesBucket"}}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/usage/top-models":{"get":{"tags":["AI Gateway Usage"],"operationId":"get_usage_top_models","parameters":[{"name":"from","in":"query","description":"ISO 8601 start time (defaults to 24h ago)","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","description":"ISO 8601 end time (defaults to now)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max results (defaults to 10)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Top models by request count","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ModelUsage"}}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/v1/chat/completions":{"post":{"tags":["AI Gateway"],"operationId":"chat_completions","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatCompletionRequest"}}},"required":true},"responses":{"200":{"description":"Chat completion response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatCompletionResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}},"404":{"description":"Model not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/v1/embeddings":{"post":{"tags":["AI Gateway"],"operationId":"embeddings","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmbeddingRequest"}}},"required":true},"responses":{"200":{"description":"Embedding response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmbeddingResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}},"404":{"description":"Model not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/v1/models":{"get":{"tags":["AI Gateway"],"operationId":"list_models","responses":{"200":{"description":"List of available models","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelListResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/analytics/active-visitors":{"get":{"tags":["Analytics"],"summary":"Get detailed active visitors","operationId":"get_analytics_active_visitors","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Deployment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"window_minutes","in":"query","description":"Time window in minutes for active visitors (default: 5)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved active visitors","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActiveVisitorsResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/event-detail":{"get":{"tags":["Analytics"],"summary":"Get detailed analytics for a specific event","operationId":"get_event_detail","parameters":[{"name":"event_name","in":"query","description":"Event name to get details for","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date (ISO 8601)","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date (ISO 8601)","required":true,"schema":{"type":"string"}},{"name":"bucket_interval","in":"query","description":"Bucket interval: hour, day, week, month (default: auto)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved event details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventDetailResponse"}}}},"400":{"description":"Invalid parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/event-entries":{"get":{"tags":["Analytics"],"summary":"Get paginated list of raw occurrences of a specific event, including custom JSON properties","operationId":"get_event_entries","parameters":[{"name":"event_name","in":"query","description":"Event name to list occurrences for","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date (ISO 8601)","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date (ISO 8601)","required":true,"schema":{"type":"string"}},{"name":"page","in":"query","description":"Page number (1-based, default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Items per page (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Successfully retrieved event entries","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventEntriesResponse"}}}},"400":{"description":"Invalid parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/event-visitors":{"get":{"tags":["Analytics"],"summary":"Get paginated list of visitors who triggered a specific event","operationId":"get_event_visitors","parameters":[{"name":"event_name","in":"query","description":"Event name to list visitors for","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date (ISO 8601)","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date (ISO 8601)","required":true,"schema":{"type":"string"}},{"name":"page","in":"query","description":"Page number (1-based, default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Items per page (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Successfully retrieved event visitors","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventVisitorsResponse"}}}},"400":{"description":"Invalid parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/events":{"get":{"tags":["Analytics"],"operationId":"get_analytics_events_count","parameters":[{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"limit","in":"query","description":"Maximum number of results to return","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"custom_events_only","in":"query","description":"Only return custom events, excluding system events like page_view, page_leave, heartbeat (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"breakdown","in":"query","description":"Breakdown by geography: 'country', 'region', or 'city' (optional)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved event counts","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EventCount"}}}}},"400":{"description":"Invalid date format, missing required parameters, or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/general-stats":{"get":{"tags":["Analytics"],"summary":"Get general statistics across all projects for a time frame","operationId":"get_general_stats","parameters":[{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"project_ids","in":"query","description":"Optional: Filter by specific project IDs (comma-separated)","required":false,"schema":{"type":"array","items":{"type":"integer","format":"int32"}}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"include_project_breakdown","in":"query","description":"Whether to include per-project breakdown (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Successfully retrieved general statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GeneralStatsResponse"}}}},"400":{"description":"Invalid date format or parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/has-events":{"get":{"tags":["Analytics"],"operationId":"check_analytics_has_events","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Analytics events existence check","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HasAnalyticsEventsResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/live-visitors":{"get":{"tags":["Analytics"],"summary":"Get list of currently live visitors from visitor table","operationId":"get_live_visitors_list","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"window_minutes","in":"query","description":"Time window in minutes for live visitors (default: 5)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved live visitors list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LiveVisitorsListResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/page-flow":{"get":{"tags":["Analytics"],"summary":"Get page flow analytics: entry pages, exit pages, drop-off points, and page transitions","operationId":"get_page_flow","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max entry/exit pages to return (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"transitions_limit","in":"query","description":"Max page transitions to return (default: 50, max: 200)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"min_views_for_dropoff","in":"query","description":"Minimum views for drop-off analysis (default: 5)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved page flow analytics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PageFlowResponse"}}}},"400":{"description":"Invalid parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/page-hourly-sessions":{"get":{"tags":["Analytics"],"operationId":"get_page_hourly_sessions","parameters":[{"name":"page_path","in":"query","description":"The page path to get sessions for","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_time","in":"query","description":"Start time in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"bucket_interval","in":"query","description":"Bucket interval: 'hour', 'day', 'week', or 'month' (default: auto-determined based on range)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved page sessions with time buckets","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PageHourlySessionsResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/page-path-detail":{"get":{"tags":["Analytics"],"summary":"Get detailed analytics for a specific page path\nReturns visitors, page views, activity over time, geographic distribution, and referrers","operationId":"get_page_path_detail","parameters":[{"name":"page_path","in":"query","description":"The page path to get details for (URL-encoded)","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"bucket_interval","in":"query","description":"Bucket interval for time series: 'hour', 'day', 'week', 'month' (default: auto based on date range)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved page path detail analytics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PagePathDetailResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/page-path-visitors":{"get":{"tags":["Analytics"],"summary":"Get individual visitor sessions for a specific page path","operationId":"get_page_path_visitors","parameters":[{"name":"page_path","in":"query","description":"The page path to get visitors for (URL-encoded)","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"page","in":"query","description":"Page number (1-based, default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Items per page (default: 50, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Successfully retrieved page path visitors","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PagePathVisitorsResponse"}}}},"400":{"description":"Invalid parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/page-paths":{"get":{"tags":["Analytics"],"operationId":"get_page_paths","parameters":[{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS (optional)","required":false,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS (optional)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Maximum number of page paths to return (default: 100, max: 1000)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved page paths","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PagePathsResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/page-paths-sparklines":{"get":{"tags":["Analytics"],"operationId":"get_page_paths_sparklines","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_time","in":"query","description":"Start time in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"page_paths","in":"query","description":"Comma-separated list of page paths","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sparkline data for all requested page paths","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PagePathsSparklineResponse"}}}},"400":{"description":"Invalid parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/recent-activity":{"get":{"tags":["Analytics"],"summary":"Get recent activity events for real-time activity feed","operationId":"get_recent_activity","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"since_id","in":"query","description":"Return events with ID greater than this (cursor-based polling)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"limit","in":"query","description":"Max events to return (default: 50, max: 100)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved recent activity events","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecentActivityResponse"}}}},"400":{"description":"Invalid parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/sessions/{session_id}":{"get":{"tags":["Analytics"],"summary":"Get detailed information about a specific session including events and request logs","operationId":"get_session_details","parameters":[{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved session details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionDetails"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Session not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/sessions/{session_id}/events":{"get":{"tags":["Analytics"],"operationId":"get_analytics_session_events","parameters":[{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS","required":false,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Number of results to return (default: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"offset","in":"query","description":"Number of results to skip (default: 0)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved session events","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionEventsResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Session not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/sessions/{session_id}/logs":{"get":{"tags":["Analytics"],"operationId":"get_session_logs","parameters":[{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS","required":false,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Number of results to return (default: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"offset","in":"query","description":"Number of results to skip (default: 0)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved session logs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionLogsResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Session not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitor-facets":{"get":{"tags":["Analytics"],"summary":"Get filter dropdown contents for the visitors page. Returns the top\nvalues per dimension with distinct visitor counts so the UI can render\n\"Country — 1,234 visitors\" rows. Each dimension is computed against the\nsegment minus its own filter, so a selected value never collapses its\nown dropdown.","operationId":"get_visitor_facets","parameters":[{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"include_crawlers","in":"query","description":"Include crawlers (default: false)","required":false,"schema":{"type":"boolean"}},{"name":"has_activity_only","in":"query","description":"Hide ghost visitors (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"per_facet_limit","in":"query","description":"Top N values per dimension (default: 50, max: 200)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"filter_country","in":"query","description":"Geolocation country","required":false,"schema":{"type":"string"}},{"name":"filter_region","in":"query","description":"Geolocation region","required":false,"schema":{"type":"string"}},{"name":"filter_city","in":"query","description":"Geolocation city","required":false,"schema":{"type":"string"}},{"name":"filter_channel","in":"query","description":"First-touch channel","required":false,"schema":{"type":"string"}},{"name":"filter_referrer","in":"query","description":"First-touch referrer hostname (use 'Direct' for null)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Top values per dimension","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorFacets"}}}},"400":{"description":"Invalid date format or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors":{"get":{"tags":["Analytics"],"summary":"Get list of visitors with summary information","operationId":"get_visitors","parameters":[{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"include_crawlers","in":"query","description":"Include crawlers (default: false)","required":false,"schema":{"type":"boolean"}},{"name":"limit","in":"query","description":"Maximum number of visitors to return (default: 50)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"offset","in":"query","description":"Number of visitors to skip (default: 0)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"has_activity_only","in":"query","description":"Filter to only include visitors with recorded activity (events/sessions). When true, excludes ghost visitors (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"filter_country","in":"query","description":"Geolocation country","required":false,"schema":{"type":"string"}},{"name":"filter_region","in":"query","description":"Geolocation region","required":false,"schema":{"type":"string"}},{"name":"filter_city","in":"query","description":"Geolocation city","required":false,"schema":{"type":"string"}},{"name":"filter_channel","in":"query","description":"First-touch channel","required":false,"schema":{"type":"string"}},{"name":"filter_referrer","in":"query","description":"First-touch referrer hostname (use 'Direct' for null)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved visitors","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorsResponse"}}}},"400":{"description":"Invalid date format, missing required parameters, or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/guid/{visitor_id}":{"get":{"tags":["Analytics"],"summary":"Get visitor by GUID with geolocation data","operationId":"get_visitor_by_guid","parameters":[{"name":"visitor_id","in":"path","description":"Visitor GUID (supports enc_ prefix for encrypted IDs)","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved visitor with geolocation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorWithGeolocation"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/id/{id}":{"get":{"tags":["Analytics"],"summary":"Get visitor by numeric ID with geolocation data","operationId":"get_visitor_by_id","parameters":[{"name":"id","in":"path","description":"Visitor numeric ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved visitor with geolocation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorWithGeolocation"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/{visitor_id}":{"get":{"tags":["Analytics"],"summary":"Get detailed information about a specific visitor by numeric ID","operationId":"get_visitor_details","parameters":[{"name":"visitor_id","in":"path","description":"Visitor numeric ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved visitor details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorDetails"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/{visitor_id}/enrich":{"put":{"tags":["Analytics"],"operationId":"enrich_visitor","parameters":[{"name":"visitor_id","in":"path","description":"Visitor ID - can be numeric ID, GUID, or encrypted GUID (enc_xxx)","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnrichVisitorRequest"}}},"required":true},"responses":{"200":{"description":"Successfully enriched visitor data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnrichVisitorResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/{visitor_id}/info":{"get":{"tags":["Analytics"],"summary":"Get visitor record from database","operationId":"get_visitor_info","parameters":[{"name":"visitor_id","in":"path","description":"Visitor numeric ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved visitor info","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorRecord"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/{visitor_id}/journey":{"get":{"tags":["Analytics"],"summary":"Get the complete visitor journey: all events across all sessions, grouped by session","operationId":"get_visitor_journey","parameters":[{"name":"visitor_id","in":"path","description":"Visitor numeric ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"limit_sessions","in":"query","description":"Maximum number of sessions to return (default: 50)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved visitor journey","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorJourneyResponse"}}}},"400":{"description":"Invalid parameters"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/{visitor_id}/sessions":{"get":{"tags":["Analytics"],"summary":"Get all sessions for a specific visitor by numeric ID","operationId":"get_analytics_visitor_sessions","parameters":[{"name":"visitor_id","in":"path","description":"Visitor numeric ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"limit","in":"query","description":"Maximum number of sessions to return (default: 100)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved visitor sessions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorSessionsResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/{visitor_id}/stats":{"get":{"tags":["Analytics"],"summary":"Get visitor statistics","operationId":"get_visitor_stats","parameters":[{"name":"visitor_id","in":"path","description":"Visitor numeric ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved visitor statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorStats"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/api-keys":{"get":{"tags":["API Keys"],"operationId":"list_api_keys","parameters":[{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page (default: 20)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"API keys retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["API Keys"],"operationId":"create_api_key","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateApiKeyRequest"}}},"required":true},"responses":{"201":{"description":"API key created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateApiKeyResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"409":{"description":"Conflict - API key name already exists"},"428":{"description":"Recent MFA verification required"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/api-keys/permissions":{"get":{"tags":["API Keys"],"operationId":"get_api_key_permissions","responses":{"200":{"description":"Available permissions and roles retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AvailablePermissions"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/api-keys/{id}":{"get":{"tags":["API Keys"],"operationId":"get_api_key","parameters":[{"name":"id","in":"path","description":"API key ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"API key retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["API Keys"],"operationId":"update_api_key","parameters":[{"name":"id","in":"path","description":"API key ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateApiKeyRequest"}}},"required":true},"responses":{"200":{"description":"API key updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"409":{"description":"Conflict - API key name already exists"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["API Keys"],"operationId":"delete_api_key","parameters":[{"name":"id","in":"path","description":"API key ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"API key deleted successfully"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/api-keys/{id}/activate":{"post":{"tags":["API Keys"],"operationId":"activate_api_key","parameters":[{"name":"id","in":"path","description":"API key ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"API key activated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/api-keys/{id}/deactivate":{"post":{"tags":["API Keys"],"operationId":"deactivate_api_key","parameters":[{"name":"id","in":"path","description":"API key ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"API key deactivated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/api-keys/{id}/rotate":{"post":{"tags":["API Keys"],"operationId":"rotate_api_key","parameters":[{"name":"id","in":"path","description":"API key ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"API key rotated successfully; the response contains the new plaintext secret, shown only once","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateApiKeyResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"428":{"description":"Recent MFA verification required"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/auth/cli/device/approve":{"post":{"tags":["Authentication"],"operationId":"cli_device_approve","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDeviceApproveRequest"}}},"required":true},"responses":{"200":{"description":"Session approved; CLI can now claim the API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDeviceApproveResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Browser session required"},"404":{"description":"Unknown user_code"},"409":{"description":"Already resolved"},"410":{"description":"Session expired"},"428":{"description":"Recent MFA verification required"},"500":{"description":"Internal server error"}},"security":[{"session_token":[]}]}},"/auth/cli/device/deny":{"post":{"tags":["Authentication"],"operationId":"cli_device_deny","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDeviceApproveRequest"}}},"required":true},"responses":{"200":{"description":"Session denied","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDeviceApproveResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Unknown user_code"},"409":{"description":"Already resolved"},"410":{"description":"Session expired"},"500":{"description":"Internal server error"}},"security":[{"session_token":[]}]}},"/auth/cli/device/lookup":{"get":{"tags":["Authentication"],"operationId":"cli_device_lookup","parameters":[{"name":"user_code","in":"query","description":"`user_code` as displayed in the CLI / pasted into the URL.","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Device session metadata","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDeviceLookupResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Unknown user_code"},"410":{"description":"Device session expired"},"500":{"description":"Internal server error"}},"security":[{"session_token":[]}]}},"/auth/cli/device/poll":{"post":{"tags":["Authentication"],"operationId":"cli_device_poll","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDevicePollRequest"}}},"required":true},"responses":{"200":{"description":"Poll result; check `status` field","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDevicePollResponse"}}}},"404":{"description":"Unknown device_code"},"500":{"description":"Internal server error"}}}},"/auth/cli/device/start":{"post":{"tags":["Authentication"],"operationId":"cli_device_start","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDeviceStartRequest"}}},"required":true},"responses":{"200":{"description":"Device session created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDeviceStartResponse"}}}},"500":{"description":"Internal server error"}}}},"/auth/cli/logout":{"post":{"tags":["Authentication"],"operationId":"cli_logout","responses":{"204":{"description":"API key revoked"},"401":{"description":"Not authenticated"},"403":{"description":"Endpoint requires API key authentication"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/auth/email-status":{"get":{"tags":["Authentication"],"operationId":"email_status","responses":{"200":{"description":"Email configuration status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailStatusResponse"}}}},"500":{"description":"Internal server error"}}}},"/auth/login":{"post":{"tags":["Authentication"],"operationId":"login","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginRequest"}}},"required":true},"responses":{"200":{"description":"Login successful, session cookie set","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthResponse"}}}},"401":{"description":"Invalid credentials, or the account's role requires MFA enrollment that has not been completed"},"500":{"description":"Internal server error"}}}},"/auth/oidc/callback":{"get":{"tags":["Authentication"],"operationId":"oidc_callback","parameters":[{"name":"code","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"state","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"error","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"error_description","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"302":{"description":"Redirect to app with session cookie or login error"}}}},"/auth/oidc/login/{slug}":{"get":{"tags":["Authentication"],"operationId":"start_oidc_login_by_slug","parameters":[{"name":"slug","in":"path","description":"OIDC provider slug (from /email-status or /auth/oidc/providers)","required":true,"schema":{"type":"string"}},{"name":"return_to","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"302":{"description":"Redirect to IdP authorize URL"},"404":{"description":"Provider not found"},"503":{"description":"OIDC provider unreachable"}}}},"/auth/oidc/providers":{"get":{"tags":["Authentication"],"operationId":"list_public_providers","responses":{"200":{"description":"Enabled OIDC providers for login page","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OidcProvidersListResponse"}}}}}}},"/auth/password-change-required":{"post":{"tags":["Authentication"],"operationId":"change_required_password","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RequiredPasswordChangeRequest"}}},"required":true},"responses":{"200":{"description":"Required password change completed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RequiredPasswordChangeResponse"}}}},"400":{"description":"Password does not meet requirements"},"401":{"description":"Password-change session is missing or expired"},"500":{"description":"Internal server error"}}}},"/auth/password-reset/request":{"post":{"tags":["Authentication"],"operationId":"request_password_reset","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailRequest"}}},"required":true},"responses":{"200":{"description":"Reset email sent if account exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthResponse"}}}},"503":{"description":"Email service not configured"}}}},"/auth/password-reset/verify":{"post":{"tags":["Authentication"],"operationId":"reset_password","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResetPasswordRequest"}}},"required":true},"responses":{"200":{"description":"Password reset successful","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthResponse"}}}},"400":{"description":"Invalid or expired token"},"500":{"description":"Internal server error"}}}},"/auth/step-up":{"post":{"tags":["Authentication"],"operationId":"verify_step_up","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyStepUpRequest"}}},"required":true},"responses":{"200":{"description":"Session elevated for sensitive actions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StepUpResponse"}}}},"400":{"description":"Verification code is empty"},"401":{"description":"Invalid code or expired session"},"403":{"description":"Browser session required"},"428":{"description":"MFA setup required"},"429":{"description":"Too many verification attempts"},"500":{"description":"Verification infrastructure failed"}},"security":[{"session_token":[]}]}},"/auth/verify-email":{"get":{"tags":["Authentication"],"operationId":"verify_email","parameters":[{"name":"token","in":"query","description":"Email verification token","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Email verified successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthResponse"}}}},"400":{"description":"Invalid or expired token"},"500":{"description":"Internal server error"}}}},"/auth/verify-mfa":{"post":{"tags":["Authentication"],"operationId":"verify_mfa_challenge","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MfaVerificationRequest"}}},"required":true},"responses":{"204":{"description":"MFA verification successful"},"400":{"description":"Invalid request"},"401":{"description":"Invalid MFA code"},"500":{"description":"Internal server error"}}}},"/backups/alerts":{"get":{"tags":["Backups"],"summary":"List open backup alerts.","description":"Returns all alerts that have not yet been resolved, ordered by `opened_at`\ndescending (newest first). The UI renders these as a banner above the\nBackups page content. Alerts are auto-opened by the watcher and\nauto-resolved when the triggering condition clears.\n\n**Schedule overdue** — the backup scheduler did not enqueue a job within\nthe expected window (1 hour past `next_run`). Usually means the scheduler\ntask is dead or wedged.\n\n**Job stalled** — a `backup_jobs` row has been in `state='pending'` for\nmore than 1 hour. The runner never claimed the job. Usually means the\nrunner task is dead or the runner concurrency cap is too low.","operationId":"list_backup_alerts","responses":{"200":{"description":"List of open backup alerts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupAlertListResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/cleanup":{"post":{"tags":["Backups"],"summary":"Preview or run retention using each selected schedule's configured retention days.","operationId":"cleanup_expired_backups","parameters":[{"name":"dry_run","in":"query","description":"Return the backups selected by retention without deleting anything.","required":false,"schema":{"type":"boolean"}},{"name":"schedule_id","in":"query","description":"Limit cleanup to one backup schedule.","required":false,"schema":{"type":["integer","null"],"format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CleanupExpiredBackupsRequest"}}},"required":true},"responses":{"200":{"description":"Retention cleanup completed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RetentionCleanupReport"}}}},"400":{"description":"Missing or invalid preview candidate list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Schedule or backup not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"409":{"description":"Cleanup preview is stale","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Cleanup could not be started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/external-services/{id}/run":{"post":{"tags":["Backups"],"summary":"Run a backup for an external service manually.","description":"Enqueues the backup for asynchronous execution via the `BackupRunner`\n(ADR-014). Returns `202 Accepted` immediately: pending parent and child\nrows are inserted, and a `backup_jobs` row is enqueued for the resolved\nengine. Poll `GET /backups/{id}` to observe `pending → running → completed`.","operationId":"run_external_service_backup","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RunExternalServiceBackupRequest"}}},"required":true},"responses":{"202":{"description":"Backup enqueued for async execution","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceBackupResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"External service or S3 source not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/external-services/{service_id}/backups":{"get":{"tags":["Backups"],"summary":"List all backups for a specific external service (DB-only, no S3 scan).","description":"Returns a paginated list of backups that belong to this service.\nCompletes in <100 ms regardless of S3 endpoint latency because it\nnever touches S3.","operationId":"list_external_service_backups","parameters":[{"name":"service_id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-based). Defaults to 1.","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"page_size","in":"query","description":"Items per page. Defaults to 20, max 100.","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Paginated list of backups for this service","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceBackupListResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/external-services/{service_id}/schedules":{"get":{"tags":["Backups"],"summary":"List the schedules that target a specific external service. Useful for\nthe service detail page (\"which schedules back this DB up?\").","operationId":"list_service_schedules","parameters":[{"name":"service_id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Schedules backing up this service","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BackupScheduleResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Service not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/s3-sources":{"get":{"tags":["Backups"],"summary":"List all S3 sources","operationId":"list_s3_sources","responses":{"200":{"description":"List of S3 sources","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/S3SourceResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Backups"],"summary":"Create a new S3 source","operationId":"create_s3_source","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateS3SourceRequest"}}},"required":true},"responses":{"201":{"description":"S3 source created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/S3SourceResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/s3-sources/test":{"post":{"tags":["Backups"],"summary":"Test S3 connectivity against a prospective source configuration (before creating it).\nThe credentials are NOT persisted. Useful for validating the form in the UI.","operationId":"test_s3_connection_preview","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateS3SourceRequest"}}},"required":true},"responses":{"200":{"description":"Connection test result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/S3ConnectionTestResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/s3-sources/{id}":{"get":{"tags":["Backups"],"summary":"Get an S3 source by ID","operationId":"get_s3_source","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"S3 source details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/S3SourceResponse"}}}},"404":{"description":"S3 source not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Backups"],"summary":"Delete an S3 source","operationId":"delete_s3_source","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"S3 source deleted"},"404":{"description":"S3 source not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Backups"],"summary":"Update an S3 source","operationId":"update_s3_source","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateS3SourceRequest"}}},"required":true},"responses":{"200":{"description":"S3 source updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/S3SourceResponse"}}}},"404":{"description":"S3 source not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/s3-sources/{id}/backups":{"get":{"tags":["Backups"],"summary":"List all backups in an S3 source","operationId":"list_source_backups","parameters":[{"name":"include_s3_scan","in":"query","description":"When `true`, scan the S3 bucket for backups not tracked in the\nlocal database (useful after disaster-recovery from another Temps\ninstance). Defaults to `false` — the fast DB-only path.","required":false,"schema":{"type":"boolean"}},{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of all backups in the source","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceBackupIndexResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"S3 source not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/backups/s3-sources/{id}/run":{"post":{"tags":["Backups"],"summary":"Run a backup immediately for an S3 source.","description":"Enqueues the backup for asynchronous execution via the `BackupRunner`\n(ADR-014). Returns `202 Accepted` immediately: a `backups` row is inserted\nwith `state='pending'` and a `backup_jobs` row is enqueued for the\n`ControlPlaneEngine`. Poll `GET /backups/{id}` to observe\n`pending → running → completed`.","operationId":"run_backup_for_source","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RunBackupRequest"}}},"required":true},"responses":{"202":{"description":"Backup enqueued for async execution","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"S3 source not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/s3-sources/{id}/set-default":{"post":{"tags":["Backups"],"summary":"Mark an S3 source as the default. All new backups/schedules/services that do not\nexplicitly reference a source will use the default. Returns the updated source.","operationId":"set_default_s3_source","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"S3 source marked as default","content":{"application/json":{"schema":{"$ref":"#/components/schemas/S3SourceResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"S3 source not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/s3-sources/{id}/test":{"post":{"tags":["Backups"],"summary":"Test connectivity to an existing S3 source using its stored credentials.","operationId":"test_s3_source_connection","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Connection test result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/S3ConnectionTestResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"S3 source not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedule-runs/{id}/cancel":{"post":{"tags":["Backups"],"summary":"Cancel every non-terminal child backup belonging to a schedule run.","description":"Loops over `state IN ('pending','running')` children and flips each via\nthe same path as the per-backup cancel endpoint. The parent\n`schedule_runs.finished_at` is stamped automatically once no live\nchildren remain. Idempotent: cancelling a run with no live children is\na 200 with `cancelled = 0`.","operationId":"cancel_schedule_run","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Cancel processed (idempotent)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CancelBackupResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Schedule run not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedule-runs/{id}/jobs":{"get":{"tags":["Backups"],"summary":"List the individual backup jobs for a single scheduler run.","description":"Returns each child `backups` row joined with its external service name and\nthe most-recent `backup_jobs` engine key. Used by the schedule detail\naccordion to show per-job detail on row expand.\n\n`page_size` defaults to 50 and is capped at 200.","operationId":"list_schedule_run_jobs","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Jobs for this scheduler run","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ScheduleRunJobEntry"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedules":{"get":{"tags":["Backups"],"summary":"List all backup schedules","operationId":"list_backup_schedules","responses":{"200":{"description":"List of backup schedules","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BackupScheduleResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Backups"],"summary":"Create a new backup schedule","operationId":"create_backup_schedule","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateBackupScheduleRequest"}}},"required":true},"responses":{"201":{"description":"Backup schedule created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupScheduleResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}":{"get":{"tags":["Backups"],"summary":"Get a backup schedule by ID","operationId":"get_backup_schedule","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Backup schedule details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupScheduleResponse"}}}},"404":{"description":"Backup schedule not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Backups"],"summary":"Delete a backup schedule","operationId":"delete_backup_schedule","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Backup schedule deleted"},"404":{"description":"Backup schedule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Backups"],"summary":"Update a backup schedule (partial update).","description":"All request fields are optional; only fields that are present in the\nJSON body are updated. Absent fields leave the corresponding column\nunchanged. If `schedule_expression` is changed, `next_run` is\nrecomputed automatically.","operationId":"update_backup_schedule","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateBackupScheduleRequest"}}},"required":true},"responses":{"200":{"description":"Schedule updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupScheduleResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Schedule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}/backups":{"get":{"tags":["Backups"],"summary":"List backups for a schedule","operationId":"list_backups_for_schedule","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of backups for the schedule","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BackupResponse"}}}}},"404":{"description":"Backup schedule not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}/disable":{"patch":{"tags":["Backups"],"summary":"Disable a backup schedule","operationId":"disable_backup_schedule","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Backup schedule disabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupScheduleResponse"}}}},"404":{"description":"Backup schedule not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}/enable":{"patch":{"tags":["Backups"],"summary":"Enable a backup schedule","operationId":"enable_backup_schedule","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Backup schedule enabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupScheduleResponse"}}}},"404":{"description":"Backup schedule not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}/run":{"post":{"tags":["Backups"],"summary":"Immediately fan-out a run for the given schedule (Run Now).","description":"Creates one `schedule_runs` row, one control-plane backup job, and one\nbackup job per supported external service — all in a single transaction.\nReturns `202 Accepted` with a [`ScheduleRunResponse`] containing the new\n`schedule_run_id` and the list of enqueued jobs. Returns `409 Conflict` if\na run for this schedule is already in flight or if the schedule is disabled.","operationId":"run_schedule_now","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"202":{"description":"Fan-out run enqueued for async execution","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScheduleRunResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Schedule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"409":{"description":"Run already in flight or schedule disabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}/runs":{"get":{"tags":["Backups"],"summary":"Paginated run history for a backup schedule (one row per scheduler tick).","description":"Returns one [`ScheduleRunSummary`] per scheduler tick, with child backup\ncounts aggregated in a single SQL round-trip. Legacy `backups` rows (pre-\nfan-out) are surfaced as synthetic single-job runs so history does not\ndisappear. Ordered by `started_at DESC` (newest first).\n\nUse `GET /backups/schedule-runs/{run_id}/jobs` to drill into a single run.","operationId":"list_schedule_runs","parameters":[{"name":"page","in":"query","description":"Page number (1-based, defaults to 1, clamped to 1 if < 1).","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"page_size","in":"query","description":"Items per page (defaults to 20, clamped to 100 if > 100).","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Paginated run history for the schedule","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScheduleRunSummaryList"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Schedule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}/services":{"get":{"tags":["Backups"],"summary":"List the external services attached to a backup schedule.","operationId":"list_schedule_services","parameters":[{"name":"id","in":"path","description":"Schedule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Services attached to this schedule","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ExternalServiceSummary"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Schedule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Backups"],"summary":"Attach one or more external services to a backup schedule. Idempotent —\nservices that are already attached are silently skipped (`ON CONFLICT\nDO NOTHING`). Returns the count of newly inserted rows + the total\nmembership after the operation.","operationId":"attach_schedule_services","parameters":[{"name":"id","in":"path","description":"Schedule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttachScheduleServicesRequest"}}},"required":true},"responses":{"200":{"description":"Services attached","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttachScheduleServicesResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Schedule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}/services/{service_id}":{"delete":{"tags":["Backups"],"summary":"Detach a single external service from a backup schedule. Idempotent —\nreturns `204` whether or not a row was actually removed.","operationId":"detach_schedule_service","parameters":[{"name":"id","in":"path","description":"Schedule ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"service_id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Service detached (or was not attached)"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/{id}":{"get":{"tags":["Backups"],"summary":"Get a backup by ID","operationId":"get_backup","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Backup details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Backup not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Backups"],"summary":"Permanently delete one terminal backup from object storage and the database.","operationId":"delete_backup","parameters":[{"name":"id","in":"path","description":"Backup UUID","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Backup deleted"},"400":{"description":"Backup artifact cannot be safely attributed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Backup not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"409":{"description":"Backup is running, referenced, or lacks safe artifact identity","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Object storage or database error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/{id}/cancel":{"post":{"tags":["Backups"],"summary":"Cancel a single in-flight backup.","description":"Flips the parent `backups` row + its latest `backup_jobs` row to\n`failed` with reason `\"cancelled by user \"`. The in-process\n`CancellationToken` is observed on the next heartbeat tick (≤5s), so the\nengine exits cleanly and rollback reaps the sidecar. Idempotent: cancelling\nan already-terminal backup is a 200 with `cancelled = 0`.","operationId":"cancel_backup","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Cancel processed (idempotent)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CancelBackupResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Backup not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/{id}/children":{"get":{"tags":["Backups"],"summary":"List the external-service child backups that belong to a parent backup.","description":"Each entry in `children` corresponds to one `external_service_backups` row,\njoined with `external_services` so the caller receives the service name and\ntype without a second request.\n\nReturns an empty `{ \"children\": [] }` — **not 404** — when the parent\nbackup exists but has no children (e.g. control-plane backups).\nReturns 404 when the parent backup itself does not exist.","operationId":"list_backup_children","parameters":[{"name":"id","in":"path","description":"Integer row id of the parent backup","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Child backup list (may be empty)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChildBackupListResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Parent backup not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/blob":{"get":{"tags":["Blob"],"summary":"List blobs","operationId":"blob_list","parameters":[{"name":"limit","in":"query","description":"Maximum number of items to return","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"prefix","in":"query","description":"Prefix to filter by","required":false,"schema":{"type":"string"}},{"name":"cursor","in":"query","description":"Continuation token for pagination","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of blobs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListBlobsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Blob"],"summary":"Upload a blob","operationId":"blob_put","requestBody":{"description":"Binary blob data","content":{"application/octet-stream":{"schema":{"type":"string"}}},"required":true},"responses":{"201":{"description":"Blob uploaded successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlobResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Blob"],"summary":"Delete blobs","operationId":"blob_delete","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteBlobRequest"}}},"required":true},"responses":{"200":{"description":"Blobs deleted successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteBlobResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/blob/copy":{"post":{"tags":["Blob"],"summary":"Copy a blob to a new location","operationId":"blob_copy","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CopyBlobRequest"}}},"required":true},"responses":{"200":{"description":"Blob copied successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlobResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Source blob not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/blob/disable":{"delete":{"tags":["Blob Management"],"summary":"Disable Blob service","operationId":"blob_disable","responses":{"200":{"description":"Blob service disabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DisableBlobResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Blob service not enabled"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/blob/enable":{"post":{"tags":["Blob Management"],"summary":"Enable Blob service","operationId":"blob_enable","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnableBlobRequest"}}},"required":true},"responses":{"200":{"description":"Blob service enabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnableBlobResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/blob/status":{"get":{"tags":["Blob Management"],"summary":"Get Blob service status","operationId":"blob_status","responses":{"200":{"description":"Blob service status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlobStatusResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/blob/update":{"patch":{"tags":["Blob Management"],"summary":"Update Blob service configuration","operationId":"blob_update","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateBlobRequest"}}},"required":true},"responses":{"200":{"description":"Blob service updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateBlobResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Blob service not enabled"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/blob/{project_id}/{path}":{"get":{"tags":["Blob"],"summary":"Download a blob","operationId":"blob_download","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","description":"Blob path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Blob content"},"404":{"description":"Blob not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"head":{"tags":["Blob"],"summary":"Get blob metadata","operationId":"blob_head","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","description":"Blob path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Blob metadata in headers"},"404":{"description":"Blob not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/dashboard/projects-analytics":{"get":{"tags":["Events"],"summary":"Get dashboard analytics for multiple projects in a single batch request","description":"Returns unique visitor counts and hourly sparkline data for all requested projects\nusing only 2 SQL queries instead of 2×N per-project queries.","operationId":"get_dashboard_projects_analytics","parameters":[{"name":"project_ids","in":"query","description":"Comma-separated list of project IDs","required":true,"schema":{"type":"string"}},{"name":"start_date","in":"query","description":"Start date for filtering","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date for filtering","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved batch analytics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DashboardProjectsAnalyticsResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/deployments/activity-graph":{"get":{"tags":["Deployments"],"summary":"Get deployment activity graph showing daily deployment counts\nSimilar to GitHub's contribution graph","operationId":"get_activity_graph","parameters":[{"name":"project_id","in":"query","description":"Filter by project ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"days","in":"query","description":"Number of days to include (default: 365)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved activity graph","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivityGraphResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/deployments/{deployment_id}/vulnerability-scan":{"get":{"tags":["Vulnerability Scans"],"operationId":"get_scan_by_deployment","parameters":[{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Scan for the specified deployment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScanResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"No scan found for deployment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/deployments/{id}/metrics":{"get":{"tags":["Metrics"],"summary":"Fetch a time-series range for a single metric on a deployment.","operationId":"DeploymentMetricsGetRange","parameters":[{"name":"id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"metric","in":"query","description":"Metric name, e.g. `\"pg.connections_active\"`.","required":true,"schema":{"type":"string"}},{"name":"range","in":"query","description":"Time window: `\"1h\"` | `\"6h\"` | `\"24h\"` | `\"7d\"`.","required":false,"schema":{"type":"string"}},{"name":"percentile","in":"query","description":"Optional histogram percentile (0–100). When provided, the endpoint\nfetches histogram buckets and computes the requested quantile.","required":false,"schema":{"type":["number","null"],"format":"double"}}],"responses":{"200":{"description":"Metric time series data points","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MetricDataPoint"}}}}},"400":{"description":"Invalid query parameters"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"},"503":{"description":"Metrics store not available"}},"security":[{"bearer_auth":[]}]}},"/deployments/{id}/metrics/enable":{"patch":{"tags":["Metrics"],"summary":"Enable or disable OTLP metric ingestion for a deployment.","description":"When `enabled=true`, seeds the default container alert rules for the\ndeployment via [`temps_monitoring::seed_default_container_rules`] (idempotent).","operationId":"DeploymentMetricsToggle","parameters":[{"name":"id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToggleDeploymentMetricsRequest"}}},"required":true},"responses":{"200":{"description":"Metrics toggle applied"},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/deployments/{id}/metrics/latest":{"get":{"tags":["Metrics"],"summary":"Fetch the most-recent metric values for a deployment.","operationId":"DeploymentMetricsGetLatest","parameters":[{"name":"id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Map of metric name to latest value","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"number","format":"double"},"propertyNames":{"type":"string"}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"},"503":{"description":"Metrics store not available"}},"security":[{"bearer_auth":[]}]}},"/dns-providers":{"get":{"tags":["DNS Providers"],"summary":"List all DNS providers","operationId":"list_dns_providers","responses":{"200":{"description":"List of DNS providers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/DnsProviderResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["DNS Providers"],"summary":"Create a new DNS provider","description":"The provider's credentials will be tested before creation.\nIf the connection test fails, the provider will not be created.","operationId":"create_dns_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDnsProviderRequest"}}},"required":true},"responses":{"201":{"description":"DNS provider created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsProviderResponse"}}}},"400":{"description":"Invalid request or connection test failed"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{id}":{"get":{"tags":["DNS Providers"],"summary":"Get a DNS provider by ID","operationId":"get_dns_provider","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"DNS provider details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsProviderResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["DNS Providers"],"summary":"Update a DNS provider","description":"If new credentials are supplied, they are tested before the update is\npersisted (same as creation) -- otherwise a provider's credentials (and,\nfor Pebble, its target URL) could be swapped for something invalid or\nunsafe without ever going through validation.","operationId":"update_provider","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDnsProviderRequest"}}},"required":true},"responses":{"200":{"description":"DNS provider updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsProviderResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["DNS Providers"],"summary":"Delete a DNS provider","operationId":"delete_dns_provider","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"DNS provider deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{id}/domains":{"get":{"tags":["DNS Providers"],"summary":"List managed domains for a provider","operationId":"list_managed_domains","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of managed domains","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ManagedDomainResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["DNS Providers"],"summary":"Add a managed domain to a provider","operationId":"add_managed_domain","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddManagedDomainApiRequest"}}},"required":true},"responses":{"201":{"description":"Managed domain added","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagedDomainResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{id}/test":{"post":{"tags":["DNS Providers"],"summary":"Test provider connection","operationId":"test_provider_connection","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Connection test result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectionTestResult"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{id}/zones":{"get":{"tags":["DNS Providers"],"summary":"List zones available in a provider","operationId":"list_provider_zones","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of zones","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ZoneListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{provider_id}/domains/{domain}":{"delete":{"tags":["DNS Providers"],"summary":"Remove a managed domain","operationId":"remove_managed_domain","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Managed domain removed"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["DNS Providers"],"summary":"Update a managed domain's settings (hostname mode, sync opt-in, auto-manage).","operationId":"update_managed_domain","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateManagedDomainApiRequest"}}},"required":true},"responses":{"200":{"description":"Managed domain updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagedDomainResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{provider_id}/domains/{domain}/apply-hostname-mode":{"post":{"tags":["DNS Providers"],"summary":"Apply a hostname mode to a managed domain (persist + optional DNS sync +\nroute reload).","operationId":"apply_hostname_mode","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApplyHostnameModeRequest"}}},"required":true},"responses":{"200":{"description":"Hostname mode applied","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HostnamePreviewResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions or token lacks zone access"},"404":{"description":"Domain not found"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{provider_id}/domains/{domain}/hostname-preview":{"get":{"tags":["DNS Providers"],"summary":"Preview the impact of switching a managed domain's hostname mode.","operationId":"preview_hostname_mode","parameters":[{"name":"mode","in":"query","description":"Target mode: standard|flat","required":true,"schema":{"type":"string"}},{"name":"sync","in":"query","description":"Include DNS record changes","required":false,"schema":{"type":"boolean"}},{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Hostname mode preview","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HostnamePreviewResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{provider_id}/domains/{domain}/verify":{"post":{"tags":["DNS Providers"],"summary":"Verify a managed domain","operationId":"verify_managed_domain","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Domain verification result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagedDomainResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"}},"security":[{"bearer_auth":[]}]}},"/dns/lookup":{"get":{"tags":["DNS"],"summary":"Lookup DNS A records for a domain","operationId":"lookup_dns_a_records","parameters":[{"name":"domain","in":"query","description":"Domain name to lookup","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved DNS A records","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsLookupResponse"}}}},"400":{"description":"Invalid domain name or lookup failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsLookupError"}}}}}}},"/domains":{"get":{"tags":["Domains"],"summary":"List all domains","operationId":"list_domains","parameters":[{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20},{"name":"search","in":"query","description":"Search domains by name (substring match)","required":false,"schema":{"type":["string","null"]},"example":"example.com"}],"responses":{"200":{"description":"Domains retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListDomainsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Domains"],"summary":"Create a new domain","description":"Creates a new domain and automatically requests a Let's Encrypt challenge.\nYou can specify the challenge type (HTTP-01 or DNS-01) in the request.\n\n- **HTTP-01**: Validates domain ownership by placing a file on your web server at `/.well-known/acme-challenge/`\n- **DNS-01**: Validates domain ownership by adding a TXT record to your DNS (required for wildcard domains)","operationId":"create_domain","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDomainRequest"}}},"required":true},"responses":{"201":{"description":"Domain created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainResponse"}}}},"400":{"description":"Invalid input"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/by-host/{hostname}":{"get":{"tags":["Domains"],"summary":"Get domain details by hostname","operationId":"get_domain_by_host","parameters":[{"name":"hostname","in":"path","description":"Domain hostname","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Domain details retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/by-host/{hostname}/cert-status":{"get":{"tags":["Domains"],"summary":"Get on-demand TLS certificate status for a hostname","description":"Returns the current cert lifecycle state for a single hostname (from the\n`domains` row) plus the most recent on-demand issuance attempt (from the\n`on_demand_cert_attempts` audit log). This is the operator's first-line\ndiagnostic, surfaced by `temps domain cert-status` (ADR-018 §5). Returns the\nhostname with `None` fields when no on-demand activity exists for it (never a\n404, so the CLI can render \"no attempts recorded\").","operationId":"get_on_demand_cert_status","parameters":[{"name":"hostname","in":"path","description":"Domain hostname","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"On-demand cert status retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CertStatusResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/on-demand-certs":{"get":{"tags":["Domains"],"summary":"List on-demand TLS certificate attempts","description":"Returns rows from the append-only `on_demand_cert_attempts` audit log\n(ADR-018 §5), newest first, each joined with the current authoritative cert\nstate (`status`, `expiration_time`, `backoff_until`) from the `domains` row.\nThis backs the console \"Certificates\" surface. No certificate or private-key\nmaterial is returned — only audit metadata.","operationId":"list_on_demand_certs","parameters":[{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20}],"responses":{"200":{"description":"On-demand cert attempts retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListOnDemandCertsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain_id}/order":{"get":{"tags":["Domains"],"summary":"Get ACME order for a domain","operationId":"get_domain_order","parameters":[{"name":"domain_id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Order retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AcmeOrderResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Order not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Domains"],"summary":"Create or recreate ACME order for a domain","description":"Creates a new ACME order with Let's Encrypt for the specified domain.\nIf an order already exists, you should cancel it first using the cancel-order endpoint.\nReturns the challenge details that need to be fulfilled (DNS record or HTTP token).","operationId":"create_or_recreate_order","parameters":[{"name":"domain_id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Order created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainChallengeResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Domains"],"summary":"Cancel ACME order for a domain","description":"Cancels the current ACME order for a domain and clears all challenge data.\nThis allows you to start over with a new order if the previous one failed or got stuck.","operationId":"cancel_domain_order","parameters":[{"name":"domain_id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Order cancelled successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain_id}/order/finalize":{"post":{"tags":["Domains"],"summary":"Finalize ACME order for a domain","description":"Finalizes the ACME order by completing the challenge validation and requesting the certificate.\nThis should be called after the challenge has been set up (DNS record added or HTTP token served).","operationId":"finalize_order","parameters":[{"name":"domain_id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Order finalized successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain or order not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain_id}/setup-dns":{"post":{"tags":["Domains"],"summary":"Setup DNS challenge records automatically using a DNS provider","description":"This endpoint automatically creates the required DNS TXT records for ACME DNS-01 challenge\nvalidation using a configured DNS provider. The domain must have an active DNS challenge\npending (created via POST /domains/{id}/order with dns-01 challenge type).\n\nThis is similar to how email domain DNS records are auto-provisioned.","operationId":"setup_dns_challenge","parameters":[{"name":"domain_id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetupDnsChallengeRequest"}}},"required":true},"responses":{"200":{"description":"DNS records created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetupDnsChallengeResponse"}}}},"400":{"description":"Bad request - DNS provider not configured or no challenge pending"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain or DNS provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain}":{"get":{"tags":["Domains"],"summary":"Get domain by ID","operationId":"get_domain_by_id","parameters":[{"name":"domain","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Domain retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Domains"],"summary":"Delete a domain","operationId":"delete_domain","parameters":[{"name":"domain","in":"path","description":"Domain name","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Domain deleted successfully"},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain}/challenge-token":{"get":{"tags":["Domains"],"summary":"Get challenge token for a domain (returns plain text token)","operationId":"get_challenge_token","parameters":[{"name":"domain","in":"path","description":"Domain name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Challenge token retrieved successfully","content":{"text/plain":{"schema":{"type":"string"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Challenge not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain}/http-challenge-debug":{"get":{"tags":["Domains"],"summary":"Get HTTP challenge debug information","description":"Returns detailed debug information for HTTP-01 challenge including:\n- Whether a challenge exists for the domain\n- The challenge token and URL that Let's Encrypt will access\n- DNS resolution information showing where the domain currently points\n\nThis is useful for debugging why HTTP-01 challenges fail.","operationId":"get_http_challenge_debug","parameters":[{"name":"domain","in":"path","description":"Domain name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Debug information retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpChallengeDebugResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain}/provision":{"post":{"tags":["Domains"],"summary":"Provision a domain certificate","operationId":"provision_domain","parameters":[{"name":"domain","in":"path","description":"Domain name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Certificate provisioning initiated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProvisionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain}/renew":{"post":{"tags":["Domains"],"summary":"Renew domain certificate","description":"For HTTP-01 domains: Automatically renews the certificate\nFor DNS-01 domains (wildcards): Creates a new ACME order and returns challenge data","operationId":"renew_domain","parameters":[{"name":"domain","in":"path","description":"Domain name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Certificate renewal initiated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProvisionResponse"}}}},"202":{"description":"DNS challenge created - manual action required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainChallengeResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain}/status":{"get":{"tags":["Domains"],"summary":"Check domain status","operationId":"check_domain_status","parameters":[{"name":"domain","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Domain status retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/drop/inspect":{"post":{"tags":["Projects"],"summary":"Inspect a source ZIP without creating a project or retaining the upload.","operationId":"inspect_drop_archive","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/DropArchiveUpload"}}},"required":true},"responses":{"200":{"description":"Detected deployable project roots","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DropInspectionResponse"}}}},"400":{"description":"Invalid or unsupported archive"}},"security":[{"bearer_auth":[]}]}},"/email-domains":{"get":{"tags":["Email Domains"],"summary":"List all email domains","operationId":"list_email_domains","parameters":[{"name":"provider_id","in":"query","description":"Only return domains belonging to this provider","required":false,"schema":{"type":["integer","null"],"format":"int32"}}],"responses":{"200":{"description":"List of email domains","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EmailDomainResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Email Domains"],"summary":"Create a new email domain","operationId":"create_email_domain","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEmailDomainRequest"}}},"required":true},"responses":{"201":{"description":"Domain created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailDomainWithDnsResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-domains/by-domain/{domain}":{"get":{"tags":["Email Domains"],"summary":"Get an email domain by domain name with DNS records","operationId":"get_domain_by_name","parameters":[{"name":"domain","in":"path","description":"Domain name (e.g., 'mail.example.com')","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Email domain details with DNS records","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailDomainWithDnsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-domains/{id}":{"get":{"tags":["Email Domains"],"summary":"Get an email domain by ID with DNS records","operationId":"get_domain","parameters":[{"name":"id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Email domain details with DNS records","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailDomainWithDnsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Email Domains"],"summary":"Delete an email domain","operationId":"delete_email_domain","parameters":[{"name":"id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Domain deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-domains/{id}/dns-records":{"get":{"tags":["Email Domains"],"summary":"Get DNS records for an email domain","operationId":"get_domain_dns_records","parameters":[{"name":"id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"DNS records for the domain","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/DnsRecordResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-domains/{id}/setup-dns":{"post":{"tags":["Email Domains"],"summary":"Setup DNS records for an email domain using a configured DNS provider","operationId":"setup_dns","parameters":[{"name":"id","in":"path","description":"Email Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetupDnsRequest"}}},"required":true},"responses":{"200":{"description":"DNS records setup result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetupDnsResponse"}}}},"400":{"description":"Invalid request or DNS provider not configured"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-domains/{id}/verify":{"post":{"tags":["Email Domains"],"summary":"Verify an email domain's DNS configuration","operationId":"verify_domain","parameters":[{"name":"id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Domain verification result with DNS records","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailDomainWithDnsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-providers":{"get":{"tags":["Email Providers"],"summary":"List all email providers","operationId":"list_email_providers","responses":{"200":{"description":"List of email providers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EmailProviderResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Email Providers"],"summary":"Create a new email provider","operationId":"create_email_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEmailProviderRequest"}}},"required":true},"responses":{"201":{"description":"Provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailProviderResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-providers/{id}":{"get":{"tags":["Email Providers"],"summary":"Get an email provider by ID","operationId":"get_email_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Email provider details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailProviderResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Email Providers"],"summary":"Delete an email provider","operationId":"delete_email_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Provider deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Email Providers"],"summary":"Update an email provider","description":"Partial update — any field left out keeps its current value. Most importantly,\nomitting the credential block (`ses_credentials`/`scaleway_credentials`/`smtp_credentials`)\npreserves the stored secret, so operators can rename a provider without re-typing\npasswords. `provider_type` is immutable; to switch providers, delete and recreate.","operationId":"update_email_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEmailProviderRequest"}}},"required":true},"responses":{"200":{"description":"Provider updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailProviderResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"},"409":{"description":"Provider type mismatch"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-providers/{id}/test":{"post":{"tags":["Email Providers"],"summary":"Test an email provider by sending a test email to the logged-in user","operationId":"test_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestEmailRequest"}}},"required":true},"responses":{"200":{"description":"Test email result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestEmailResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-providers/{id}/tracking/setup":{"post":{"tags":["Email Providers"],"summary":"One-click AWS-side setup of SES event tracking (SNS topic + webhook\nsubscription + SESv2 event destination), using the provider's stored\ncredentials.","operationId":"setup_email_tracking","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Setup completed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailTrackingSetupResponse"}}}},"400":{"description":"Provider does not support event tracking"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"},"502":{"description":"An AWS call failed — the response detail names the failed step"}},"security":[{"bearer_auth":[]}]}},"/email-providers/{id}/tracking/status":{"get":{"tags":["Email Providers"],"summary":"Live status of SES event tracking for a provider","operationId":"get_email_tracking_status","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Event tracking status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailTrackingStatusResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]}},"/emails":{"get":{"tags":["Emails"],"summary":"List emails with optional filtering","operationId":"list_emails","parameters":[{"name":"domain_id","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"project_id","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"status","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"from_address","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"page","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"page_size","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}}],"responses":{"200":{"description":"List of emails","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedEmailsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Emails"],"summary":"Send an email","operationId":"send_email","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendEmailRequestBody"}}},"required":true},"responses":{"201":{"description":"Email sent successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendEmailResponseBody"}}}},"400":{"description":"Invalid request or domain not verified"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/emails/events":{"get":{"tags":["Email Tracking"],"summary":"GET /emails/events","operationId":"get_global_events","parameters":[{"name":"event_type","in":"query","description":"Filter by event type (open, click)","required":false,"schema":{"type":"string"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Paginated tracking events","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedEventsResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/emails/events/stats":{"get":{"tags":["Email Tracking"],"summary":"GET /emails/events/stats","operationId":"get_global_event_stats","responses":{"200":{"description":"Global tracking statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GlobalEventStatsResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/emails/stats":{"get":{"tags":["Emails"],"summary":"Get email statistics","operationId":"get_email_stats","parameters":[{"name":"domain_id","in":"query","description":"Optional domain ID to filter stats","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Email statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailStatsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/emails/validate":{"post":{"tags":["Email Validation"],"summary":"Validate an email address","operationId":"validate_email","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateEmailRequest"}}},"required":true},"responses":{"200":{"description":"Email validation result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateEmailResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/emails/{email_id}/track/click/{link_index}":{"get":{"tags":["Email Tracking"],"summary":"Track email link click - redirects to original URL","description":"This endpoint replaces original links in tracked emails.\nNo authentication required - it's called when the recipient clicks a link.","operationId":"track_click","parameters":[{"name":"email_id","in":"path","description":"Email ID (UUID)","required":true,"schema":{"type":"string"}},{"name":"link_index","in":"path","description":"Link index","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"302":{"description":"Redirect to original URL"},"404":{"description":"Link not found"}}}},"/emails/{email_id}/track/open":{"get":{"tags":["Email Tracking"],"summary":"Track email open - returns a 1x1 transparent GIF","description":"This endpoint is embedded as an tag in emails.\nNo authentication required - it's called by the email client.","operationId":"track_open","parameters":[{"name":"email_id","in":"path","description":"Email ID (UUID)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"1x1 transparent tracking pixel"},"404":{"description":"Email not found"}}}},"/emails/{id}":{"get":{"tags":["Emails"],"summary":"Get an email by ID","operationId":"get_email","parameters":[{"name":"id","in":"path","description":"Email ID (UUID)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Email details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Email not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/emails/{id}/tracking":{"get":{"tags":["Email Tracking"],"summary":"Get email tracking summary","operationId":"get_email_tracking","parameters":[{"name":"id","in":"path","description":"Email ID (UUID)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Tracking summary","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailTrackingResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Email not found"}},"security":[{"bearer_auth":[]}]}},"/emails/{id}/tracking/events":{"get":{"tags":["Email Tracking"],"summary":"Get email tracking events","operationId":"get_email_events","parameters":[{"name":"id","in":"path","description":"Email ID (UUID)","required":true,"schema":{"type":"string"}},{"name":"event_type","in":"query","description":"Filter by event type (open, click)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Tracking events","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TrackingEventResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Email not found"}},"security":[{"bearer_auth":[]}]}},"/emails/{id}/tracking/links":{"get":{"tags":["Email Tracking"],"summary":"Get tracked links for an email","operationId":"get_email_links","parameters":[{"name":"id","in":"path","description":"Email ID (UUID)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Tracked links","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TrackedLinkResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Email not found"}},"security":[{"bearer_auth":[]}]}},"/external-services":{"get":{"tags":["External Services"],"summary":"Get all external services","operationId":"list_services","parameters":[{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20},{"name":"sort_by","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"List of external services","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}}},"500":{"description":"Internal server error"}}},"post":{"tags":["External Services"],"summary":"Create new external service","operationId":"create_service","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateExternalServiceRequest"}}},"required":true},"responses":{"201":{"description":"Service created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}},"400":{"description":"Invalid request"},"500":{"description":"Internal server error"}}}},"/external-services/available-containers":{"get":{"tags":["External Services"],"summary":"List available Docker containers that can be imported as services","operationId":"list_available_containers","responses":{"200":{"description":"List of available containers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AvailableContainerInfo"}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/by-slug/{slug}":{"get":{"tags":["External Services"],"summary":"Get external service details by slug","operationId":"get_service_by_slug","parameters":[{"name":"slug","in":"path","description":"External service slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"External service details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceDetails"}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/health-status-batch":{"get":{"tags":["External Services"],"summary":"Current health status for many services at once","description":"Powers the status dot on the Storage list page. Pass a comma-separated\nlist of service IDs via `?ids=1,2,3`. Omit to get every service.","operationId":"list_service_health_statuses","parameters":[{"name":"ids","in":"query","description":"Comma-separated service IDs. Omit for all services.","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Batch of current health statuses","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceHealthStatusBatchResponse"}}}},"500":{"description":"Internal server error"}}}},"/external-services/import":{"post":{"tags":["External Services"],"summary":"Import an existing Docker container as a managed external service","operationId":"import_external_service","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportExternalServiceRequest"}}},"required":true},"responses":{"201":{"description":"Service imported successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/projects/{project_id}":{"get":{"tags":["External Services"],"summary":"List services linked to a project","operationId":"list_project_services","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20},{"name":"sort_by","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"List of services linked to project","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProjectServiceInfo"}}}}},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}}},"/external-services/projects/{project_id}/environment":{"get":{"tags":["External Services"],"summary":"Get all environment variables for all services linked to a project","operationId":"get_project_service_environment_variables","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Map of service IDs to their environment variables","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"object","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"propertyNames":{"type":"integer","format":"int32"}}}}},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}}},"/external-services/providers/metadata":{"get":{"tags":["External Services"],"summary":"Get provider metadata (display names, icons, descriptions)","operationId":"get_providers_metadata","responses":{"200":{"description":"List of provider metadata","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProviderMetadata"}}}}},"500":{"description":"Internal server error"}}}},"/external-services/providers/metadata/{service_type}":{"get":{"tags":["External Services"],"summary":"Get metadata for a specific provider","operationId":"get_provider_metadata","parameters":[{"name":"service_type","in":"path","description":"Service type (mongodb, postgres, redis, s3)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Provider metadata","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderMetadata"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}}}},"/external-services/types":{"get":{"tags":["External Services"],"summary":"Get available service types","operationId":"get_service_types","responses":{"200":{"description":"List of available service types","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ServiceTypeRoute"}}}}},"500":{"description":"Internal server error"}}}},"/external-services/types/{service_type}/parameters":{"get":{"tags":["External Services"],"summary":"Get parameter schema for a specific service type","operationId":"get_service_type_parameters","parameters":[{"name":"service_type","in":"path","description":"Service type","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Service type parameter schema"},"404":{"description":"Service type not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}":{"get":{"tags":["External Services"],"summary":"Get external service details","operationId":"get_service","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"External service details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceDetails"}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}},"put":{"tags":["External Services"],"summary":"Update external service","operationId":"update_service","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateExternalServiceRequest"}}},"required":true},"responses":{"200":{"description":"Service updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}},"400":{"description":"Invalid request"},"404":{"description":"Service not found"},"409":{"description":"A major upgrade is in progress for this service"},"500":{"description":"Internal server error"}}},"delete":{"tags":["External Services"],"summary":"Delete external service","operationId":"delete_service","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Service deleted successfully"},"400":{"description":"Cannot delete: service is still linked to projects"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/cluster-health":{"get":{"tags":["External Services"],"summary":"Per-member health for a Postgres HA cluster.","description":"Reads pg_auto_failover's `pgautofailover.node` table from the cluster's\nmonitor (TLS, autoctl_node) and joins each member with its\n`pg_stat_replication` row from the current primary. Returns one row per\ndata member with role/state, sync state, and replay lag.\n\nReturns `200` with `monitor_error` set when the monitor is briefly\nunreachable (UI surfaces it as a banner above the table); the table\nitself is empty in that case. Returns `400` for non-cluster services.","operationId":"get_cluster_health","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Per-member cluster health report","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClusterHealthReportResponse"}}}},"400":{"description":"Service is not a cluster"},"401":{"description":"Unauthorized"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/health-check":{"post":{"tags":["External Services"],"summary":"Run a health check for one service right now","description":"Triggers the same engine-specific probe as the background monitor, writes\na history row, updates the denormalized fields on `external_services`, and\nfires alerts on the Nth consecutive failure (so consecutive-failure state\nstays honest). Returns the fresh snapshot the UI can display immediately.","operationId":"trigger_service_health_check","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Fresh health snapshot after probing","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceHealthResponse"}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"},"503":{"description":"Health monitor not running on this node"}}}},"/external-services/{id}/health-status":{"get":{"tags":["External Services"],"summary":"Persisted health status for an external service","description":"Returns the latest health probe result recorded by\n`ExternalServiceHealthMonitor`, plus recent check history for sparklines\nand a 24-hour uptime percentage. Safe to poll from the UI every 30s.","operationId":"get_service_health_status","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"limit","in":"query","description":"Max number of recent checks (default 50, max 200)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Current health + recent history","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceHealthResponse"}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/members":{"post":{"tags":["External Services"],"summary":"Begin adding a single new member to a running cluster.","description":"Currently only `replica` members can be added at runtime. The\nresponse is **202 Accepted** as soon as the validation passes and\nthe placeholder `service_members` row is inserted. The actual\ncontainer provisioning + DNS registration runs in the background;\npoll `GET /external-services/{id}/members/{member_id}` to watch\n`provisioning_step` advance through the phases.","operationId":"add_cluster_member","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddClusterMemberRequest"}}},"required":true},"responses":{"202":{"description":"Cluster member provisioning started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceMemberInfo"}}}},"400":{"description":"Validation failed (wrong topology, status, or role)"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/members/{member_id}":{"get":{"tags":["External Services"],"summary":"Get a single cluster member's current state.","description":"Used by the add-member page to poll the row every second while the\nbackground provisioning task walks through its phases. The\n`provisioning_step` field advances through `inserting_row` →\n`provisioning_container` → `registering_dns` → `done` (or `failed`\nwith `provisioning_error` set).","operationId":"get_cluster_member","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"member_id","in":"path","description":"Cluster member ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Cluster member details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceMemberInfo"}}}},"404":{"description":"Service or member not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["External Services"],"summary":"Remove a single member from a running cluster.","description":"Refuses to remove the monitor (singleton), the current primary\n(failover first), or any member if the cluster would drop below the\n2-data-member quorum required for HA. Stops + removes the container,\ndeletes the row, and drops the Tier-2 DNS record.","operationId":"remove_cluster_member","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"member_id","in":"path","description":"Cluster member ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Cluster member removed"},"400":{"description":"Validation failed (monitor, primary, or quorum violation)"},"404":{"description":"Service or member not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/members/{member_id}/promote":{"post":{"tags":["External Services"],"summary":"Promote a replica to primary by triggering a pg_auto_failover\nfailover. The monitor demotes the current primary and the chosen\nreplica transitions to primary; the role reconciler then refreshes\nthe role-aliased VIPs (≤30s).","operationId":"promote_cluster_member","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"member_id","in":"path","description":"Cluster member ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"202":{"description":"Promotion initiated"},"400":{"description":"Validation failed (monitor, already primary, not running, etc.)"},"404":{"description":"Service or member not found"},"500":{"description":"pg_autoctl perform promotion failed"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/metrics":{"get":{"tags":["Metrics"],"summary":"Fetch a time-series range for a single metric on an external service.","description":"Pass `percentile` to compute a histogram quantile instead of a plain\ngauge/counter average.","operationId":"ExternalServiceMetricsGetRange","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"metric","in":"query","description":"Metric name, e.g. `\"pg.connections_active\"`.","required":true,"schema":{"type":"string"}},{"name":"range","in":"query","description":"Time window: `\"1h\"` | `\"6h\"` | `\"24h\"` | `\"7d\"`.","required":false,"schema":{"type":"string"}},{"name":"percentile","in":"query","description":"Optional histogram percentile (0–100). When provided, the endpoint\nfetches histogram buckets and computes the requested quantile.","required":false,"schema":{"type":["number","null"],"format":"double"}}],"responses":{"200":{"description":"Metric time series data points","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MetricDataPoint"}}}}},"400":{"description":"Invalid query parameters"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"},"503":{"description":"Metrics store not available"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/metrics/alert-rules":{"get":{"tags":["Metrics"],"summary":"List all monitoring alert rules for an external service.","operationId":"ExternalServiceMetricsGetAlertRules","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of alert rules","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ServiceAlertRuleResponse"}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Metrics"],"summary":"Create a monitoring alert rule for an external service.","description":"If metric collection is enabled and the service engine has default rules,\nseeding is idempotent (ON CONFLICT DO NOTHING).","operationId":"ExternalServiceMetricsCreateAlertRule","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceCreateAlertRuleRequest"}}},"required":true},"responses":{"201":{"description":"Alert rule created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceAlertRuleResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/metrics/alert-rules/{rule_id}":{"put":{"tags":["Metrics"],"summary":"Update an existing monitoring alert rule for an external service.","operationId":"ExternalServiceMetricsUpdateAlertRule","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"rule_id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceUpdateAlertRuleRequest"}}},"required":true},"responses":{"200":{"description":"Updated alert rule","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceAlertRuleResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Alert rule not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Metrics"],"summary":"Delete a monitoring alert rule for an external service.","operationId":"ExternalServiceMetricsDeleteAlertRule","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"rule_id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Alert rule deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Alert rule not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/metrics/by-database":{"get":{"tags":["Metrics"],"summary":"Return the latest per-database metric values for a Postgres service.","description":"Groups `pg_stat_database` / size metrics by `datname` so the UI can show a\nbreakdown table (each database with its own size, cache-hit ratio, etc.)\nrather than collapsing every database into one value.","operationId":"ExternalServiceMetricsByDatabase","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Per-database metric breakdown","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DatabaseMetricsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"},"503":{"description":"Metrics not available"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/metrics/enable":{"patch":{"tags":["Metrics"],"summary":"Enable or disable metric collection for an external service.","description":"When `enabled=true`, seeds the default alert rules for the service's engine\nvia [`temps_monitoring::seed_default_rules`] (idempotent).","operationId":"ExternalServiceMetricsToggle","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToggleServiceMetricsRequest"}}},"required":true},"responses":{"200":{"description":"Metrics toggle applied"},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/metrics/latest":{"get":{"tags":["Metrics"],"summary":"Fetch the most-recent value for every tracked metric on an external service.","operationId":"ExternalServiceMetricsGetLatest","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Map of metric name to latest value","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"number","format":"double"},"propertyNames":{"type":"string"}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"},"503":{"description":"Metrics store not available"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/metrics/status":{"get":{"tags":["Metrics"],"summary":"Return the freshness status (last-received timestamp) for a service.","description":"Cheap O(1) lookup against `service_metrics_status` — used by the UI to show\n\"last received at …\" without scanning the metrics hypertable.","operationId":"ExternalServiceMetricsStatus","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Metrics freshness status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MetricsStatusResponse"}}}},"503":{"description":"Metrics not available"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/parameters/{param_name}":{"get":{"tags":["External Services"],"summary":"Reveal one sensitive service parameter. Service detail responses never\ncontain plaintext values; every successful reveal is recorded separately.","operationId":"reveal_service_parameter","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"param_name","in":"path","description":"Sensitive parameter name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sensitive parameter value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SensitiveValueResponse"}}}},"400":{"description":"Parameter is not sensitive"},"403":{"description":"Caller cannot access a project linked to this service"},"404":{"description":"Service or parameter not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/preview-environment-masked":{"get":{"tags":["External Services"],"summary":"Get environment variables preview with masked sensitive values","operationId":"get_service_preview_environment_variables_masked","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Preview of environment variables with sensitive values masked as ***","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/preview-environment-names":{"get":{"tags":["External Services"],"summary":"Get environment variable names preview (safe - no sensitive values)","operationId":"get_service_preview_environment_variable_names","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of environment variable names that would be provided","content":{"application/json":{"schema":{"type":"array","items":{"type":"string"}}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/projects":{"get":{"tags":["External Services"],"summary":"List projects linked to service","operationId":"list_service_projects","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20},{"name":"sort_by","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"List of linked projects","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProjectServiceInfo"}}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}},"post":{"tags":["External Services"],"summary":"Link service to project","operationId":"link_service_to_project","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LinkServiceRequest"}}},"required":true},"responses":{"201":{"description":"Service linked to project successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectServiceInfo"}}}},"404":{"description":"Service or project not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/projects/{project_id}":{"delete":{"tags":["External Services"],"summary":"Unlink service from project","operationId":"unlink_service_from_project","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Service unlinked from project successfully"},"404":{"description":"Service link not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/projects/{project_id}/environment":{"get":{"tags":["External Services"],"summary":"Get all environment variables for a service-project pair","operationId":"get_service_environment_variables","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of environment variables","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EnvironmentVariableInfo"}}}}},"404":{"description":"Service or project not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/projects/{project_id}/environment/{var_name}":{"get":{"tags":["External Services"],"summary":"Get specific environment variable for a service-project pair","operationId":"get_service_environment_variable","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"var_name","in":"path","description":"Environment variable name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Environment variable value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentVariableInfo"}}}},"403":{"description":"Plaintext secret access is not permitted"},"404":{"description":"Service, project, or variable not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/resources":{"patch":{"tags":["External Services"],"summary":"Update a service's resource limits (memory, CPU caps).","description":"Persists the new caps to the encrypted config AND live-applies them\nvia Docker's update API. Memory and CPU can be hot-changed without a\nrestart on running containers; stopped containers also accept the\nupdate and pick up the new caps on next start.\n\nPass `null` (or omit) any field to leave it unlimited. A request where\nevery field is `null` removes any existing limits.\n\nThe response includes a per-container `applied[]` list so the caller\ncan tell which members got the update and which were skipped (e.g.,\ncontainer not yet created, or `docker update` rejected because the\nnew memory cap is below current usage).","operationId":"update_service_resources","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceResourceLimits"}}},"required":true},"responses":{"200":{"description":"Updated resource limits","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResourceLimitsUpdateResponse"}}}},"400":{"description":"Invalid resource limits"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/restore":{"post":{"tags":["Restore"],"operationId":"start_restore","parameters":[{"name":"id","in":"path","description":"External service id (source for the restore)","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartRestoreRequest"}}},"required":true},"responses":{"202":{"description":"Restore run started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RestoreRunView"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Backup or service not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/restore-capabilities":{"get":{"tags":["Restore"],"operationId":"get_restore_capabilities","parameters":[{"name":"id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Capabilities declared by the service","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RestoreCapabilitiesResponse"}}}},"404":{"description":"Service not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/restore-plan":{"post":{"tags":["Restore"],"operationId":"plan_restore","parameters":[{"name":"id","in":"path","description":"Target service id","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartRestoreRequest"}}},"required":true},"responses":{"200":{"description":"Preview of what the restore will do","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RestorePlan"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Backup or service not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/restore-runs":{"get":{"tags":["Restore"],"operationId":"list_restore_runs_for_service","parameters":[{"name":"id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Recent restore runs for the service","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RestoreRunView"}}}}}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/retry":{"post":{"tags":["External Services"],"summary":"Retry a failed cluster service initialization.","description":"Cleans up any leftover containers from the previous attempt and\nre-runs cluster initialization with the provided member specifications.","operationId":"retry_cluster","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RetryClusterRequest"}}},"required":true},"responses":{"200":{"description":"Cluster retry initiated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}},"400":{"description":"Service is not a failed cluster"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/runtime":{"get":{"tags":["External Services"],"summary":"Inspect a service's container(s): status, restart count, OOM-killed flag,\nexit code, and the cgroup limits actually applied.","operationId":"get_service_runtime","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Container runtime snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceRuntimeReport"}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/start":{"post":{"tags":["External Services"],"summary":"Start an external service","operationId":"start_service","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Service started successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}},"404":{"description":"Service not found"},"409":{"description":"A Postgres major upgrade is in progress for this service"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/stats":{"get":{"tags":["External Services"],"summary":"Sample current CPU/memory usage from each of a service's containers.\nOne-shot sample, no streaming. Cheap to call (single Docker round-trip\nper member) so the UI can poll on a 5–10s interval.","operationId":"get_service_stats","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Container stats snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceStatsReport"}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/stop":{"post":{"tags":["External Services"],"summary":"Stop an external service","operationId":"stop_service","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Service stopped successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/upgrade":{"post":{"tags":["External Services"],"summary":"Upgrade external service to new Docker image with data migration\nThis endpoint uses service-specific upgrade procedures (e.g., pg_upgrade for PostgreSQL)","operationId":"upgrade_service","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpgradeExternalServiceRequest"}}},"required":true},"responses":{"200":{"description":"Service upgraded successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}},"400":{"description":"Invalid request or upgrade not supported"},"404":{"description":"Service not found"},"409":{"description":"A major upgrade is already in progress for this service"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/wal-health":{"get":{"tags":["External Services"],"summary":"Postgres WAL & archive health snapshot","description":"Returns the latest WAL/archive health snapshot recorded by the background\nhealth monitor for a Postgres external service. Powers the warning banner\non the service detail page when the disk is filling up due to stale\nreplication slots, archive backlog, or misconfigured `archive_command`.\n\nReturns 404 when no snapshot exists yet (probe hasn't run, or the service\nisn't Postgres).","operationId":"getPostgresWalHealth","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Latest WAL health snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PostgresWalHealth"}}}},"404":{"description":"Service not found, or no WAL snapshot available"},"500":{"description":"Internal server error"}}}},"/external-services/{service_id}/pg-stat-statements/enable":{"post":{"tags":["External Services"],"summary":"Enable `pg_stat_statements` on a standalone Postgres service.","description":"Stops the container and restarts it so that the\n`shared_preload_libraries=pg_stat_statements` CMD flag (baked into every\nnew standalone Postgres container) takes effect. The named data volume is\nreused unchanged — no data is lost.\n\n**Clustered (HA) services are rejected** with 422 — a blind single-container\nrestart bypasses controlled failover. For clustered services the response\nbody describes the manual rolling-restart steps.\n\nConfirmation is the caller's responsibility (UI dialog / CLI `--yes` flag)\nbefore invoking this endpoint.","operationId":"ExternalServiceEnablePgStatStatements","parameters":[{"name":"service_id","in":"path","description":"ID of the provisioned standalone Postgres service","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Container restarted; pg_stat_statements now active","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnablePgStatStatementsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions (requires external_services:write)"},"404":{"description":"Service not found"},"422":{"description":"Service is not standalone Postgres (cluster or wrong type)"},"500":{"description":"Restart failed"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/pg-stat-statements/reset":{"post":{"tags":["External Services"],"summary":"Reset all statistics accumulated by `pg_stat_statements` for a Postgres\nservice. This affects every user, database, and normalized query tracked by\nthe target Postgres instance and cannot be undone.","operationId":"ExternalServiceResetPgStatStatements","parameters":[{"name":"service_id","in":"path","description":"ID of the provisioned Postgres service","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"Explicit confirmation of the global, irreversible reset","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResetPgStatStatementsRequest"}}},"required":true},"responses":{"200":{"description":"All accumulated pg_stat_statements statistics cleared","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResetPgStatStatementsResponse"}}}},"400":{"description":"Missing or invalid reset confirmation"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions (requires external_services:write)"},"404":{"description":"Service not found"},"422":{"description":"Service is not Postgres"},"502":{"description":"Target Postgres rejected or failed the reset operation"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/pg-stat-statements/slow-queries":{"get":{"tags":["External Services"],"operationId":"get_slow_queries","parameters":[{"name":"service_id","in":"path","description":"ID of the provisioned Postgres service","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-based). Defaults to 1.","required":false,"schema":{"type":["integer","null"],"format":"int32","minimum":0}},{"name":"page_size","in":"query","description":"Number of rows per page (1–100). Defaults to 20.","required":false,"schema":{"type":["integer","null"],"format":"int32","minimum":0}},{"name":"sort_by","in":"query","description":"Column to sort by: one of `calls`, `total_exec_time_ms`,\n`mean_exec_time_ms`, `rows`, `cache_hit_ratio`. Defaults to\n`mean_exec_time_ms`. Applied server-side so ordering stays\nconsistent across pages.","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","description":"Sort direction: `asc` or `desc`. Defaults to `desc`.","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"Paginated slow queries from pg_stat_statements","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SlowQueriesResponse"}}}},"400":{"description":"Invalid pagination or sort parameters"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions (requires external_services:read)"},"404":{"description":"Service not found"},"422":{"description":"Service is not a Postgres service"},"503":{"description":"pg_stat_statements extension not available (container restart required)"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/containers":{"get":{"tags":["External Services - Query"],"summary":"List containers at the root level (databases, keyspaces, etc.)","operationId":"list_root_containers","parameters":[{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of root containers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ContainerResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/containers/{path}":{"get":{"tags":["External Services - Query"],"summary":"List containers at a specific path\nPath segments are separated by forward slashes\nExample: /external-services/1/query/containers/mydb lists schemas in database \"mydb\"","operationId":"list_containers_at_path","parameters":[{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of containers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ContainerResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service or container not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/containers/{path}/entities":{"get":{"tags":["External Services - Query"],"summary":"List entities (tables, collections, etc.) in a container\nExample: /external-services/1/query/containers/mydb/public/entities lists tables in the public schema","operationId":"list_entities","parameters":[{"name":"limit","in":"query","description":"Maximum number of entities to return (default: 100, max: 1000)","required":false,"schema":{"type":"integer","minimum":0}},{"name":"token","in":"query","description":"Continuation token for pagination","required":false,"schema":{"type":"string"}},{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Paginated list of entities","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedEntitiesResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service or container not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/containers/{path}/entities/{entity}":{"get":{"tags":["External Services - Query"],"summary":"Get detailed information about an entity (table schema)","operationId":"get_entity_info","parameters":[{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","required":true,"schema":{"type":"string"}},{"name":"entity","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Entity details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EntityInfoResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service, container, or entity not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/containers/{path}/entities/{entity}/data":{"post":{"tags":["External Services - Query"],"summary":"Query data from an entity with optional filters, pagination, and sorting","operationId":"query_data","parameters":[{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","required":true,"schema":{"type":"string"}},{"name":"entity","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QueryDataRequest"}}},"required":true},"responses":{"200":{"description":"Query results","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QueryDataResponse"}}}},"400":{"description":"Invalid query"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service, container, or entity not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/containers/{path}/entities/{entity}/download":{"get":{"tags":["External Services - Query"],"summary":"Download an object (S3 only) as a streaming response","operationId":"download_object","parameters":[{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","required":true,"schema":{"type":"string"}},{"name":"entity","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Object data stream","content":{"application/octet-stream":{}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Object not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/containers/{path}/info":{"get":{"tags":["External Services - Query"],"summary":"Get information about a specific container","operationId":"get_container_info","parameters":[{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Container information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service or container not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/explorer-support":{"get":{"tags":["External Services - Query"],"summary":"Check if a service supports query explorer functionality","operationId":"check_explorer_support","parameters":[{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Explorer support information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExplorerSupportResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/upgrades":{"get":{"tags":["Postgres Upgrades"],"summary":"List recent upgrades for a single service (newest first, page size 50).","operationId":"list_pg_upgrades","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Recent upgrades","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PgUpgradeResponse"}}}}},"500":{"description":"Internal error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Postgres Upgrades"],"summary":"Start a new PostgreSQL major-version upgrade for a service.","operationId":"start_pg_upgrade","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartPgUpgradeRequest"}}},"required":true},"responses":{"201":{"description":"Upgrade started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PgUpgradeResponse"}}}},"400":{"description":"Invalid request"},"409":{"description":"An upgrade is already running for this service"},"412":{"description":"No default S3 source configured"},"500":{"description":"Internal error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/upgrades/{id}":{"get":{"tags":["Postgres Upgrades"],"summary":"Get a single upgrade by id, scoped to a service.","operationId":"get_pg_upgrade","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"id","in":"path","description":"Upgrade id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Upgrade","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PgUpgradeResponse"}}}},"404":{"description":"Not found"},"500":{"description":"Internal error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/upgrades/{id}/cancel":{"post":{"tags":["Postgres Upgrades"],"summary":"Cancel an in-flight upgrade. The orchestrator stops at its next phase\nboundary; already-terminal upgrades return 409.","operationId":"cancel_pg_upgrade","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"id","in":"path","description":"Upgrade id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Cancellation requested","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PgUpgradeResponse"}}}},"404":{"description":"Not found"},"409":{"description":"Upgrade already terminal"},"500":{"description":"Internal error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/upgrades/{id}/logs":{"get":{"tags":["Postgres Upgrades"],"summary":"Get the accumulated JSONL log content for an upgrade (for dashboard display).","operationId":"get_pg_upgrade_logs","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"id","in":"path","description":"Upgrade id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Log content","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PgUpgradeLogResponse"}}}},"404":{"description":"Not found"},"500":{"description":"Internal error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/upgrades/{id}/retry":{"post":{"tags":["Postgres Upgrades"],"summary":"Retry a failed upgrade. The phase is preserved, so the state machine\nresumes from where it failed.","operationId":"retry_pg_upgrade","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"id","in":"path","description":"Upgrade id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Retry scheduled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PgUpgradeResponse"}}}},"400":{"description":"Upgrade is not in a retriable state"},"404":{"description":"Not found"},"500":{"description":"Internal error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/upgrades/{id}/rollback":{"post":{"tags":["Postgres Upgrades"],"summary":"Roll a completed upgrade back to its pre-upgrade PGDATA volume and old image.\nOnly valid while the rollback retention window is still open (see\n`ROLLBACK_RETENTION_DAYS`) and the rollback volume has not been swept.","operationId":"rollback_pg_upgrade","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"id","in":"path","description":"Upgrade id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Rollback complete","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PgUpgradeResponse"}}}},"404":{"description":"Not found"},"409":{"description":"Upgrade is not in a rollbackable state (not completed, volume swept, or retention expired)"},"500":{"description":"Internal error"}},"security":[{"bearer_auth":[]}]}},"/files/{file_path}":{"get":{"tags":["Files"],"operationId":"get_file","parameters":[{"name":"file_path","in":"path","description":"Relative path to the file from static directory","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"File content retrieved successfully","content":{"application/octet-stream":{}}},"401":{"description":"Authentication required"},"403":{"description":"Access denied - path outside static directory or insufficient permissions"},"404":{"description":"File not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/flags/exposure":{"post":{"tags":["Feature Flags"],"summary":"Record which flags a running app actually evaluated.","description":"This is what makes `last_evaluated_at` mean something. The snapshot\nendpoint hands the SDK every flag in the environment and evaluation then\nhappens locally, so the control plane cannot otherwise tell a flag that is\nreferenced by live code from one nothing has called in a year. Stamping on\nsnapshot fetch would mark every flag as freshly used and defeat the point.\n\nScope comes from the deployment token, never the body. The endpoint writes\nonly `last_evaluated_at` — never a flag's value — so \"a deployment token\ncannot change what a flag serves\" still holds despite this being a write.","operationId":"record_flag_exposure","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecordExposureRequest"}}},"required":true},"responses":{"200":{"description":"Exposure recorded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecordExposureResponse"}}}},"400":{"description":"Deployment token required"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/flags/snapshot":{"get":{"tags":["Feature Flags"],"summary":"Every flag for the caller's environment, collapsed to what the evaluator\nneeds.","description":"Scope comes from the deployment token, never from the URL: a container's\nbaked-in `TEMPS_API_TOKEN` identifies exactly one project (and usually one\nenvironment), so a compromised app cannot read another tenant's flags by\nchanging a path parameter.\n\nSupports `If-None-Match`, so the SDK's background poll is a 304 in the\ncommon case.","operationId":"get_flag_snapshot","parameters":[{"name":"environment_id","in":"query","description":"Required only when the calling token is project-wide rather than scoped\nto a single environment.","required":false,"schema":{"type":["integer","null"],"format":"int32"}}],"responses":{"200":{"description":"Snapshot for the environment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagSnapshotResponse"}}}},"304":{"description":"Snapshot unchanged"},"400":{"description":"Environment could not be determined"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/geo/{ip}":{"get":{"tags":["geo"],"summary":"Get geolocation information for an IP address","operationId":"get_ip_geolocation","parameters":[{"name":"ip","in":"path","description":"IP address to geolocate (IPv4 or IPv6)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Geolocation information retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GeoLocationResponse"}}}},"400":{"description":"Invalid IP address","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"IP address not found in database","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/git-connections":{"get":{"tags":["Git Providers"],"summary":"List user's git provider connections","operationId":"list_connections","parameters":[{"name":"page","in":"query","description":"Page number for pagination (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Number of items per page (default: 30, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"sort","in":"query","description":"Sort field (created_at, updated_at, account_name)","required":false,"schema":{"type":"string"}},{"name":"direction","in":"query","description":"Sort direction (asc, desc), default: desc","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of connections","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectionListResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}":{"delete":{"tags":["Git Providers"],"summary":"Permanently delete a git provider connection","operationId":"delete_connection","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Connection deleted successfully"},"400":{"description":"Connection is in use by projects and cannot be deleted"},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}/activate":{"post":{"tags":["Git Providers"],"summary":"Activate a git provider connection","operationId":"activate_connection","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Connection activated successfully"},"400":{"description":"Provider is deactivated and connection cannot be activated"},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}/deactivate":{"post":{"tags":["Git Providers"],"summary":"Deactivate a git provider connection","operationId":"deactivate_connection","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Connection deactivated successfully"},"400":{"description":"Connection is in use by projects and cannot be deactivated"},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}/health-check":{"post":{"tags":["Git Provider Connections"],"summary":"Run an on-demand health check for a git connection.","description":"Probes the upstream (GitHub App, PAT, or OAuth token), persists the result,\nand fires admin notifications on status transitions. Returns the updated\nconnection.","operationId":"run_connection_health_check","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Health check completed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}/repositories":{"get":{"tags":["Git Providers"],"summary":"List repositories for a specific connection","description":"Fetches repositories from the connected git provider with support for pagination, search, and filtering.\nThis endpoint calls the provider's API directly to get the most up-to-date repository list.","operationId":"list_repositories_by_connection","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"sort","in":"query","description":"Sort field (name, created_at, updated_at, stars, etc.)","required":false,"schema":{"type":"string"}},{"name":"direction","in":"query","description":"Sort direction (asc, desc)","required":false,"schema":{"type":"string"}},{"name":"search","in":"query","description":"Search term to filter repositories","required":false,"schema":{"type":"string"}},{"name":"owner","in":"query","description":"Filter by repository owner","required":false,"schema":{"type":"string"}},{"name":"language","in":"query","description":"Filter by programming language","required":false,"schema":{"type":"string"}},{"name":"private","in":"query","description":"Filter by private status (true/false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of repositories","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositoryListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}/sync":{"post":{"tags":["Git Providers"],"summary":"Start a repository sync for a connection","description":"Kicks off a background sync of the connection's repositories from the\nprovider. Returns `202 Accepted` immediately — the caller should poll\nthe connection endpoint for `syncing` / `synced_repository_count`\nupdates rather than waiting on this response. The sync is guarded by\na hard deadline and always releases the `syncing` flag on exit, so a\nclient that disconnects mid-sync will not leave the connection stuck.","operationId":"sync_repositories","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"202":{"description":"Repository sync started in background","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositorySyncStartedResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"409":{"description":"Sync already in progress"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}/update-token":{"post":{"tags":["Git Provider Connections"],"summary":"Update access token for a connection (when tokens expire or are rotated)","operationId":"update_connection_token","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTokenRequest"}}},"required":true},"responses":{"200":{"description":"Token updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTokenResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}/validate":{"get":{"tags":["Git Provider Connections"],"summary":"Validate a connection by testing the access token","operationId":"validate_connection","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Connection validation result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers":{"get":{"tags":["Git Providers"],"summary":"List all git providers","operationId":"list_git_providers","responses":{"200":{"description":"List of providers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProviderResponse"}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Git Providers"],"summary":"Create a new git provider configuration","operationId":"create_git_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProviderRequest"}}},"required":true},"responses":{"201":{"description":"Provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/bitbucket":{"post":{"tags":["Git Providers"],"summary":"Create a Bitbucket Cloud provider with access token or app password authentication","operationId":"create_bitbucket_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateBitbucketRequest"}}},"required":true},"responses":{"201":{"description":"Bitbucket provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request — missing or invalid auth fields"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/generic":{"post":{"tags":["Git Providers"],"summary":"Create a Generic git provider for self-hosted or arbitrary HTTPS git hosts.\nSupports public repositories (no token) and private repositories (token-based).","operationId":"create_generic_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGenericRequest"}}},"required":true},"responses":{"201":{"description":"Generic git provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request — invalid clone URL or missing fields"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/gitea/pat":{"post":{"tags":["Git Providers"],"summary":"Create a Gitea Personal Access Token provider","operationId":"create_gitea_pat_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGiteaPATRequest"}}},"required":true},"responses":{"201":{"description":"Gitea PAT provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request — invalid URL or missing fields"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/github/pat":{"post":{"tags":["Git Providers"],"summary":"Create a GitHub Personal Access Token provider","operationId":"create_github_pat_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGitHubPATRequest"}}},"required":true},"responses":{"201":{"description":"GitHub PAT provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/gitlab/oauth":{"post":{"tags":["Git Providers"],"summary":"Create a GitLab OAuth provider","operationId":"create_gitlab_oauth_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGitLabOAuthRequest"}}},"required":true},"responses":{"201":{"description":"GitLab OAuth provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/gitlab/pat":{"post":{"tags":["Git Providers"],"summary":"Create a GitLab PAT provider","operationId":"create_gitlab_pat_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGitLabPATRequest"}}},"required":true},"responses":{"201":{"description":"GitLab PAT provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}":{"get":{"tags":["Git Providers"],"summary":"Get a specific git provider","operationId":"get_git_provider","parameters":[{"name":"provider_id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Provider details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Git Providers"],"summary":"Permanently delete a git provider","operationId":"delete_git_provider","parameters":[{"name":"provider_id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Provider deleted successfully"},"400":{"description":"Provider has connections and cannot be deleted"},"401":{"description":"Unauthorized"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/activate":{"post":{"tags":["Git Providers"],"summary":"Activate a git provider","operationId":"activate_provider","parameters":[{"name":"provider_id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Provider activated successfully"},"401":{"description":"Unauthorized"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/callback":{"get":{"tags":["Git Providers"],"summary":"Handle OAuth callback for a git provider","operationId":"handle_git_provider_oauth_callback","parameters":[{"name":"provider_id","in":"path","description":"Git provider ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"code","in":"query","description":"OAuth authorization code","required":true,"schema":{"type":"string"}},{"name":"state","in":"query","description":"CSRF state token","required":true,"schema":{"type":"string"}}],"responses":{"302":{"description":"Redirect to success page"},"400":{"description":"Bad request"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}}}},"/git-providers/{provider_id}/connections":{"get":{"tags":["Git Providers"],"summary":"Get connections for a specific git provider","operationId":"get_provider_connections","parameters":[{"name":"provider_id","in":"path","description":"Provider ID to get connections for","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of connections for the provider","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ConnectionResponse"}}}}},"401":{"description":"Unauthorized"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/credentials":{"patch":{"tags":["Git Providers"],"summary":"Partially update credentials for an existing git provider. Only the fields\nyou send are replaced; omitted fields keep their stored values. Fields that\ndon't apply to the provider's auth method are ignored on the service side.","operationId":"update_git_provider_credentials","parameters":[{"name":"provider_id","in":"path","description":"Git provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProviderCredentialsRequest"}}},"required":true},"responses":{"200":{"description":"Credentials updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/deactivate":{"post":{"tags":["Git Providers"],"summary":"Deactivate a git provider","operationId":"deactivate_provider","parameters":[{"name":"provider_id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Provider deactivated successfully"},"401":{"description":"Unauthorized"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/deletion-check":{"get":{"tags":["Git Providers"],"summary":"Check if a git provider can be safely deleted","operationId":"check_provider_deletion_safety","parameters":[{"name":"provider_id","in":"path","description":"Git provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deletion check result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderDeletionCheckResponse"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/oauth/authorize":{"get":{"tags":["Git Providers"],"summary":"Start OAuth flow for a git provider","operationId":"start_git_provider_oauth","parameters":[{"name":"provider_id","in":"path","description":"Git provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"302":{"description":"Redirect to OAuth provider"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/repositories":{"get":{"tags":["Git Providers"],"summary":"List all repositories for a specific provider","description":"Lists repositories synced to the database across every connection under\nthis provider, with the same pagination/filtering as `/repositories`.","operationId":"list_repositories_by_provider","parameters":[{"name":"provider_id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"sort","in":"query","description":"Sort field (name, created_at, updated_at, stars, watchers, size, issues)","required":false,"schema":{"type":"string"}},{"name":"direction","in":"query","description":"Sort direction (asc, desc)","required":false,"schema":{"type":"string"}},{"name":"search","in":"query","description":"Search term to filter repositories","required":false,"schema":{"type":"string"}},{"name":"owner","in":"query","description":"Filter by repository owner","required":false,"schema":{"type":"string"}},{"name":"language","in":"query","description":"Filter by programming language","required":false,"schema":{"type":"string"}},{"name":"private","in":"query","description":"Filter by private status (true/false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of repositories","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositoryListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/safe-delete":{"delete":{"tags":["Git Providers"],"summary":"Safely delete a git provider (only if no projects are using it)","operationId":"delete_provider_safely","parameters":[{"name":"provider_id","in":"path","description":"Git provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Provider successfully deleted"},"400":{"description":"Cannot delete provider because it's in use"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git/public/{provider}/{owner}/{repo}":{"get":{"tags":["Public Repositories"],"summary":"Get information about a public repository (supports GitHub and GitLab)","operationId":"get_public_repository","parameters":[{"name":"provider","in":"path","description":"Git provider (github or gitlab)","required":true,"schema":{"type":"string"}},{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"repo","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Repository information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicRepositoryInfo"}}}},"400":{"description":"Provider not supported"},"404":{"description":"Repository not found"},"429":{"description":"API rate limit exceeded"},"500":{"description":"Internal server error"}}}},"/git/public/{provider}/{owner}/{repo}/branches":{"get":{"tags":["Public Repositories"],"summary":"Get branches for a public repository (supports GitHub and GitLab)","operationId":"get_public_branches","parameters":[{"name":"provider","in":"path","description":"Git provider (github or gitlab)","required":true,"schema":{"type":"string"}},{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"repo","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}},{"name":"fresh","in":"query","description":"Force fetch fresh data, bypassing cache (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of branches","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BranchListResponse"}}}},"400":{"description":"Provider not supported"},"404":{"description":"Repository not found"},"429":{"description":"API rate limit exceeded"},"500":{"description":"Internal server error"}}}},"/git/public/{provider}/{owner}/{repo}/presets":{"get":{"tags":["Public Repositories"],"summary":"Detect presets for a public repository (supports GitHub and GitLab)","operationId":"detect_public_presets","parameters":[{"name":"provider","in":"path","description":"Git provider (github or gitlab)","required":true,"schema":{"type":"string"}},{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"repo","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}},{"name":"branch","in":"query","description":"Branch name to detect presets for (default: repository's default branch)","required":false,"schema":{"type":["string","null"]}},{"name":"fresh","in":"query","description":"Force fetch fresh data, bypassing cache (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Detected presets","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicPresetResponse"}}}},"400":{"description":"Provider not supported"},"404":{"description":"Repository or branch not found"},"429":{"description":"API rate limit exceeded"},"500":{"description":"Internal server error"}}}},"/imports/discover":{"post":{"tags":["Imports"],"summary":"Discover workloads from a source","operationId":"discover_workloads","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiscoverRequest"}}},"required":true},"responses":{"200":{"description":"List of discovered workloads","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiscoverResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/imports/execute":{"post":{"tags":["Imports"],"summary":"Execute an import","operationId":"execute_import","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecuteImportRequest"}}},"required":true},"responses":{"202":{"description":"Import execution started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecuteImportResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/imports/plan":{"post":{"tags":["Imports"],"summary":"Create an import plan","operationId":"create_plan","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePlanRequest"}}},"required":true},"responses":{"200":{"description":"Import plan created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePlanResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/imports/sources":{"get":{"tags":["Imports"],"summary":"List available import sources","operationId":"list_sources","responses":{"200":{"description":"List of available import sources","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ImportSourceInfo"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/imports/{session_id}":{"get":{"tags":["Imports"],"summary":"Get import status","operationId":"get_import_status","parameters":[{"name":"session_id","in":"path","description":"Import session ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Import status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportStatusResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Import session not found"}},"security":[{"bearer_auth":[]}]}},"/incidents/{incident_id}":{"get":{"tags":["Status Page"],"summary":"Get an incident by ID","operationId":"get_incident","parameters":[{"name":"incident_id","in":"path","description":"Incident ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved incident","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncidentResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Incident not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/incidents/{incident_id}/status":{"patch":{"tags":["Status Page"],"summary":"Update incident status","operationId":"update_incident_status","parameters":[{"name":"incident_id","in":"path","description":"Incident ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateIncidentStatusRequest"}}},"required":true},"responses":{"200":{"description":"Incident status updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncidentResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Incident not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/incidents/{incident_id}/updates":{"get":{"tags":["Status Page"],"summary":"Get incident updates","operationId":"get_incident_updates","parameters":[{"name":"incident_id","in":"path","description":"Incident ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved incident updates","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/IncidentUpdateResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Incident not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/internal/nodes":{"get":{"tags":["Nodes"],"summary":"List all registered nodes (admin — session auth via RequireAuth)","operationId":"admin_list_nodes","responses":{"200":{"description":"List of nodes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NodeListResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/internal/nodes/register":{"post":{"tags":["Nodes"],"summary":"Register a new worker node or reconnect an existing one","operationId":"register_node","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterNodeApiRequest"}}},"required":true},"responses":{"200":{"description":"Node reconnected successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterNodeResponse"}}}},"201":{"description":"Node registered successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterNodeResponse"}}}},"400":{"description":"Validation error"},"500":{"description":"Internal server error"}}}},"/internal/nodes/{node_id}":{"get":{"tags":["Nodes"],"summary":"Get a specific node by ID (admin — session auth via RequireAuth)","operationId":"admin_get_node","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Node details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NodeInfoResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Nodes"],"summary":"Remove a node from the cluster entirely. The node should be drained first\nto ensure containers have been rescheduled. If the node still has active\ncontainers, it will be drained automatically before removal.","operationId":"admin_remove_node","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Node removed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RemoveNodeResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Node not found"},"409":{"description":"Node still has active containers"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/internal/nodes/{node_id}/containers":{"get":{"tags":["Nodes"],"summary":"List all containers running on a specific node","operationId":"admin_list_node_containers","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Containers on this node","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NodeContainerListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/internal/nodes/{node_id}/dns/ack":{"post":{"tags":["Internal DNS"],"summary":"`POST /internal/nodes/{node_id}/dns/ack`","operationId":"post_dns_ack","parameters":[{"name":"node_id","in":"path","description":"Node id, must match the bearer token's node","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsAckRequest"}}},"required":true},"responses":{"200":{"description":"ACK accepted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsAckResponse"}}}},"400":{"description":"ACK higher than server generation"},"401":{"description":"Missing or invalid bearer token"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}}}},"/internal/nodes/{node_id}/dns/changes":{"get":{"tags":["Internal DNS"],"summary":"`GET /internal/nodes/{node_id}/dns/changes?since=N`","operationId":"get_dns_changes","parameters":[{"name":"node_id","in":"path","description":"Node id, must match the bearer token's node","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"since","in":"query","description":"Highest generation the agent has already applied. Pass `0` to\nrequest a full zone snapshot. Defaults to `0` if omitted.","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Diff or full snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsChangesResponse"}}}},"401":{"description":"Missing or invalid bearer token"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}}}},"/internal/nodes/{node_id}/drain":{"get":{"tags":["Nodes"],"summary":"Get the drain status for a node, including migration progress.","description":"Returns container counts and whether the drain is complete.\nCan be polled to track drain progress.","operationId":"admin_drain_status","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Drain status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DrainStatusResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Nodes"],"summary":"Drain a node: mark it as \"draining\" so no new replicas are scheduled on it,\nand trigger redeployment of all affected environments so their containers\nare rescheduled to healthy nodes.","operationId":"admin_drain_node","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Node drain initiated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DrainNodeResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Nodes"],"summary":"Undrain (reactivate) a node so it can accept new deployments again.\nOnly works for nodes in \"draining\" or \"drained\" status.","operationId":"admin_undrain_node","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Node reactivated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UndrainNodeResponse"}}}},"400":{"description":"Node not in drainable state"},"401":{"description":"Unauthorized"},"404":{"description":"Node not found"}},"security":[{"bearer_auth":[]}]}},"/internal/nodes/{node_id}/heartbeat":{"post":{"tags":["Nodes"],"summary":"Receive a heartbeat from a worker node","operationId":"node_heartbeat","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HeartbeatApiRequest"}}},"required":true},"responses":{"200":{"description":"Heartbeat received","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HeartbeatResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}}}},"/internal/nodes/{node_id}/network/peers":{"get":{"tags":["Nodes"],"summary":"`GET /internal/nodes/{node_id}/network/peers`","operationId":"list_peers","parameters":[{"name":"node_id","in":"path","description":"Node id, must match the bearer token's node","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Peer list and self-allocation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PeerListResponse"}}}},"401":{"description":"Missing or invalid bearer token"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}}}},"/internal/nodes/{node_id}/s3-credentials/{s3_source_id}":{"get":{"tags":["Nodes"],"summary":"Get decrypted S3 credentials for a backup/restore operation.","description":"Agents call this endpoint to receive the S3 credentials they need to upload\nor download backups. The credentials are decrypted from the stored S3 source\nand returned over the authenticated TLS/WireGuard channel.","operationId":"get_s3_credentials","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"s3_source_id","in":"path","description":"S3 source ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"S3 credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/S3CredentialsResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"S3 source not found"},"500":{"description":"Internal server error"}}}},"/ip-access-control":{"get":{"tags":["IP Access Control"],"summary":"List all IP access control rules","operationId":"list_ip_access_control","parameters":[{"name":"action","in":"query","description":"Filter by action (\"block\" or \"allow\")","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"List of IP access control rules","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/IpAccessControlResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["IP Access Control"],"summary":"Create a new IP access control rule","operationId":"create_ip_access_control","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateIpAccessControlRequest"}}},"required":true},"responses":{"201":{"description":"IP access control rule created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IpAccessControlResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"409":{"description":"Duplicate IP address","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ip-access-control/check/{ip}":{"get":{"tags":["IP Access Control"],"summary":"Check if an IP address is blocked","operationId":"check_ip_blocked","parameters":[{"name":"ip","in":"path","description":"IP address to check","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"IP block status"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ip-access-control/{id}":{"get":{"tags":["IP Access Control"],"summary":"Get a single IP access control rule by ID","operationId":"get_ip_access_control","parameters":[{"name":"id","in":"path","description":"IP access control rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"IP access control rule details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IpAccessControlResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"IP access control rule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["IP Access Control"],"summary":"Delete an IP access control rule","operationId":"delete_ip_access_control","parameters":[{"name":"id","in":"path","description":"IP access control rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"IP access control rule deleted"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"IP access control rule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["IP Access Control"],"summary":"Update an IP access control rule","operationId":"update_ip_access_control","parameters":[{"name":"id","in":"path","description":"IP access control rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateIpAccessControlRequest"}}},"required":true},"responses":{"200":{"description":"IP access control rule updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IpAccessControlResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"IP access control rule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/kv/del":{"post":{"tags":["KV Store"],"summary":"Delete one or more keys","operationId":"kv_del","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DelRequest"}}},"required":true},"responses":{"200":{"description":"Keys deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DelResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/disable":{"delete":{"tags":["KV Management"],"summary":"Disable KV service","operationId":"kv_disable","responses":{"200":{"description":"KV service disabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DisableKvResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"KV service not enabled"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/enable":{"post":{"tags":["KV Management"],"summary":"Enable KV service","operationId":"kv_enable","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnableKvRequest"}}},"required":true},"responses":{"200":{"description":"KV service enabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnableKvResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/expire":{"post":{"tags":["KV Store"],"summary":"Set expiration on a key","operationId":"kv_expire","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExpireRequest"}}},"required":true},"responses":{"200":{"description":"Expiration set","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExpireResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/get":{"post":{"tags":["KV Store"],"summary":"Get a value by key","operationId":"kv_get","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetRequest"}}},"required":true},"responses":{"200":{"description":"Value retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/incr":{"post":{"tags":["KV Store"],"summary":"Increment a numeric value","operationId":"kv_incr","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncrRequest"}}},"required":true},"responses":{"200":{"description":"Value incremented","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncrResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/keys":{"post":{"tags":["KV Store"],"summary":"Get keys matching a pattern","operationId":"kv_keys","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KeysRequest"}}},"required":true},"responses":{"200":{"description":"Keys retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KeysResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/set":{"post":{"tags":["KV Store"],"summary":"Set a value with optional expiration","operationId":"kv_set","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetRequest"}}},"required":true},"responses":{"200":{"description":"Value set","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/status":{"get":{"tags":["KV Management"],"summary":"Get KV service status","operationId":"kv_status","responses":{"200":{"description":"KV service status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KvStatusResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/ttl":{"post":{"tags":["KV Store"],"summary":"Get time-to-live for a key","operationId":"kv_ttl","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TtlRequest"}}},"required":true},"responses":{"200":{"description":"TTL retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TtlResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/update":{"patch":{"tags":["KV Management"],"summary":"Update KV service configuration","operationId":"kv_update","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateKvRequest"}}},"required":true},"responses":{"200":{"description":"KV service updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateKvResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"KV service not enabled"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/lb/routes":{"get":{"tags":["Load Balancer"],"operationId":"list_routes","responses":{"200":{"description":"List of routes","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RouteResponse"}}}}},"500":{"description":"Internal server error"}}},"post":{"tags":["Load Balancer"],"operationId":"create_route","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRouteRequest"}}},"required":true},"responses":{"201":{"description":"Route created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteResponse"}}}},"400":{"description":"Invalid request"}}}},"/lb/routes/{domain}":{"get":{"tags":["Load Balancer"],"operationId":"get_route","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Route found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteResponse"}}}},"404":{"description":"Route not found"}}},"put":{"tags":["Load Balancer"],"operationId":"update_route","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateRouteRequest"}}},"required":true},"responses":{"200":{"description":"Route updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteResponse"}}}},"404":{"description":"Route not found"}}},"delete":{"tags":["Load Balancer"],"operationId":"delete_route","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Route deleted successfully"},"404":{"description":"Route not found"}}}},"/logout":{"post":{"tags":["Authentication"],"operationId":"logout","responses":{"200":{"description":"Successfully logged out"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"session_token":[]}]}},"/logs/context":{"get":{"tags":["Logs"],"summary":"Get context lines surrounding a specific log line","operationId":"get_log_context","parameters":[{"name":"chunk_id","in":"query","description":"Chunk ID","required":true,"schema":{"type":"string"}},{"name":"line_offset","in":"query","description":"Line offset within the chunk","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"lines","in":"query","description":"Context lines before and after (default: 25)","required":false,"schema":{"type":"integer","format":"int32","minimum":0}}],"responses":{"200":{"description":"Context lines","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContextLogsResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Chunk not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/logs/search":{"post":{"tags":["Logs"],"summary":"Search logs with structured filters and full text search","operationId":"search_logs","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchLogsRequest"}}},"required":true},"responses":{"200":{"description":"Search results","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchLogsResponse"}}}},"400":{"description":"Invalid search parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/logs/tail":{"get":{"tags":["Logs"],"summary":"Live tail logs via Server-Sent Events","operationId":"tail_logs","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"string"}},{"name":"service","in":"query","description":"Service name","required":true,"schema":{"type":"string"}},{"name":"env","in":"query","description":"Environment","required":true,"schema":{"type":"string"}},{"name":"levels","in":"query","description":"Optional level filters","required":true,"schema":{"type":"array","items":{"type":"string"}}},{"name":"text","in":"query","description":"Optional text filter","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"SSE stream of log lines"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/monitors-health/projects":{"get":{"tags":["Status Page"],"summary":"Get monitor-based health summaries for multiple projects in a single query","operationId":"get_projects_monitor_health","parameters":[{"name":"project_ids","in":"query","description":"Comma-separated list of project IDs","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Health summaries per project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectsMonitorHealthResponse"}}}},"400":{"description":"Invalid parameters"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/monitors/{monitor_id}":{"get":{"tags":["Status Page"],"summary":"Get a monitor by ID","operationId":"get_monitor","parameters":[{"name":"monitor_id","in":"path","description":"Monitor ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved monitor","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MonitorResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Monitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Status Page"],"summary":"Delete a monitor","operationId":"delete_monitor","parameters":[{"name":"monitor_id","in":"path","description":"Monitor ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Monitor deleted successfully"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Monitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/monitors/{monitor_id}/bucketed":{"get":{"tags":["Status Page"],"summary":"Get bucketed status data for a monitor using TimescaleDB","operationId":"get_bucketed_status","parameters":[{"name":"monitor_id","in":"path","description":"Monitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"interval","in":"query","description":"Bucket interval: '5min', 'hourly', or 'daily' (default: hourly)","required":false,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601) (default: 24 hours ago)","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (ISO 8601) (default: now)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved bucketed status data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatusBucketedResponse"}}}},"400":{"description":"Invalid parameters"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Monitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/monitors/{monitor_id}/current-status":{"get":{"tags":["Status Page"],"summary":"Get current status and uptime metrics for a monitor","operationId":"get_current_monitor_status","parameters":[{"name":"monitor_id","in":"path","description":"Monitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_time","in":"query","description":"Custom start time (ISO 8601) - overrides timeframe","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"Custom end time (ISO 8601)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved current status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CurrentStatusResponse"}}}},"400":{"description":"Invalid time parameters"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Monitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/monitors/{monitor_id}/uptime":{"get":{"tags":["Status Page"],"summary":"Get uptime history for a monitor","operationId":"get_uptime_history","parameters":[{"name":"monitor_id","in":"path","description":"Monitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"days","in":"query","description":"Number of days of history (default: 60) - ignored if start_time/end_time provided","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601) - overrides days parameter","required":true,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (ISO 8601) - defaults to now","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved uptime history","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UptimeHistoryResponse"}}}},"400":{"description":"Invalid time parameters"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Monitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/nodes/{id}/metrics":{"get":{"tags":["Metrics"],"summary":"Fetch a time-series range for a single metric on a node.","operationId":"NodeMetricsGetRange","parameters":[{"name":"id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"metric","in":"query","description":"Metric name, e.g. `\"pg.connections_active\"`.","required":true,"schema":{"type":"string"}},{"name":"range","in":"query","description":"Time window: `\"1h\"` | `\"6h\"` | `\"24h\"` | `\"7d\"`.","required":false,"schema":{"type":"string"}},{"name":"percentile","in":"query","description":"Optional histogram percentile (0–100). When provided, the endpoint\nfetches histogram buckets and computes the requested quantile.","required":false,"schema":{"type":["number","null"],"format":"double"}}],"responses":{"200":{"description":"Metric time series data points","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MetricDataPoint"}}}}},"400":{"description":"Invalid query parameters"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"},"503":{"description":"Metrics store not available"}},"security":[{"bearer_auth":[]}]}},"/notification-preferences":{"get":{"tags":["Notification Preferences"],"summary":"Get notification preferences","operationId":"get_preferences","responses":{"200":{"description":"Successfully retrieved preferences","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationPreferencesResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Notification Preferences"],"summary":"Update notification preferences","operationId":"update_preferences","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePreferencesRequest"}}},"required":true},"responses":{"200":{"description":"Successfully updated preferences","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationPreferencesResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Notification Preferences"],"summary":"Delete notification preferences","operationId":"delete_preferences","responses":{"204":{"description":"Successfully deleted preferences"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers":{"get":{"tags":["Notification Providers"],"summary":"List all notification providers","operationId":"list_notification_providers","parameters":[{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20},{"name":"sort_by","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"Successfully retrieved providers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}}},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Notification Providers"],"summary":"Create a new notification provider","operationId":"create_notification_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProviderRequest"}}},"required":true},"responses":{"201":{"description":"Successfully created provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"400":{"description":"Invalid request"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/cloudflare":{"post":{"tags":["Notification Providers"],"summary":"Create a new Cloudflare Email Sending notification provider","operationId":"create_cloudflare_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCloudflareProviderRequest"}}},"required":true},"responses":{"201":{"description":"Successfully created Cloudflare provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"400":{"description":"Invalid request"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/cloudflare/{id}":{"put":{"tags":["Notification Providers"],"summary":"Update a Cloudflare Email Sending notification provider","operationId":"update_cloudflare_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCloudflareProviderRequest"}}},"required":true},"responses":{"200":{"description":"Successfully updated Cloudflare provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/email":{"post":{"tags":["Notification Providers"],"summary":"Create a new Email notification provider","operationId":"create_notification_email_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateNotificationEmailProviderRequest"}}},"required":true},"responses":{"201":{"description":"Successfully created Email provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"400":{"description":"Invalid request"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/email/{id}":{"put":{"tags":["Notification Providers"],"summary":"Update an Email notification provider","operationId":"update_notification_email_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateNotificationEmailProviderRequest"}}},"required":true},"responses":{"200":{"description":"Successfully updated Email provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/slack":{"post":{"tags":["Notification Providers"],"summary":"Create a new Slack notification provider","operationId":"create_slack_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSlackProviderRequest"}}},"required":true},"responses":{"201":{"description":"Successfully created Slack provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"400":{"description":"Invalid request"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/slack/{id}":{"put":{"tags":["Notification Providers"],"summary":"Update a Slack notification provider","operationId":"update_slack_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSlackProviderRequest"}}},"required":true},"responses":{"200":{"description":"Successfully updated Slack provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/webhook":{"post":{"tags":["Notification Providers"],"summary":"Create a new Webhook notification provider","description":"Webhook providers send notifications as JSON payloads to any HTTP endpoint.\nYou can configure custom headers for authentication (Bearer tokens, API keys, etc.).\nThe webhook will receive a JSON payload with notification details including:\nid, title, message, type, priority, severity, timestamp, and metadata.","operationId":"create_webhook_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWebhookProviderRequest"}}},"required":true},"responses":{"201":{"description":"Successfully created Webhook provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"400":{"description":"Invalid request"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/webhook/{id}":{"put":{"tags":["Notification Providers"],"summary":"Update a Webhook notification provider","operationId":"update_webhook_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWebhookProviderRequest"}}},"required":true},"responses":{"200":{"description":"Successfully updated Webhook provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/{id}":{"get":{"tags":["Notification Providers"],"summary":"Get a single notification provider","operationId":"get_notification_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Notification Providers"],"summary":"Update a notification provider","operationId":"update_notification_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProviderRequest"}}},"required":true},"responses":{"200":{"description":"Successfully updated provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"400":{"description":"Invalid masked provider configuration"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Notification Providers"],"summary":"Delete a notification provider","operationId":"delete_notification_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Successfully deleted provider"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/{id}/config/{field}":{"get":{"tags":["Notification Providers"],"operationId":"reveal_notification_provider_config","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"field","in":"path","description":"Sensitive field, such as password or headers.Authorization","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sensitive provider configuration value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SensitiveConfigValueResponse"}}}},"400":{"description":"Field is not revealable"},"403":{"description":"Missing secrets:read permission"},"404":{"description":"Provider or field not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/{id}/test":{"post":{"tags":["Notification Providers"],"summary":"Test a notification provider","operationId":"test_notification_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Test result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestProviderResponse"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/orders":{"get":{"tags":["Domains"],"summary":"List all ACME orders","operationId":"list_orders","parameters":[{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20},{"name":"sort_by","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"Orders retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListOrdersResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/otel/alerts":{"get":{"tags":["Alerts"],"summary":"List alert rules for a project (newest first, paginated).","operationId":"list_alerts","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Alert rules for the project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricAlertsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Alerts"],"summary":"Create a new alert rule for a project.","operationId":"create_alert","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMetricAlertRequest"}}},"required":true},"responses":{"201":{"description":"Alert rule created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricAlertRuleResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/alerts/preview":{"post":{"tags":["Alerts"],"summary":"Backtest an anomaly detector over a time range without saving a rule.","description":"Replays the metric against the same band the evaluator would use, returning\nthe per-bucket band + which points would have fired. Powers the form's\n\"would this have fired?\" preview and the explorer band overlay. Read-only.","operationId":"preview_alert","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnomalyPreviewRequest"}}},"required":true},"responses":{"200":{"description":"Per-bucket band + breach points","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnomalyPreviewResponse"}}}},"400":{"description":"Not an anomaly detector / bad input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/alerts/{id}":{"get":{"tags":["Alerts"],"summary":"Fetch a single alert rule by id.","operationId":"get_alert","parameters":[{"name":"id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Owning project ID (scopes the lookup)","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Alert rule","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricAlertRuleResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Alert rule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Alerts"],"summary":"Delete an alert rule.","operationId":"delete_alert","parameters":[{"name":"id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Owning project ID (scopes the delete)","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Alert rule deleted"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Alert rule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Alerts"],"summary":"Update an alert rule's fields.","operationId":"update_alert","parameters":[{"name":"id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Owning project ID (scopes the update)","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMetricAlertRequest"}}},"required":true},"responses":{"200":{"description":"Alert rule updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricAlertRuleResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Alert rule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/dashboards":{"get":{"tags":["Dashboards"],"summary":"List dashboards for a project (newest first, paginated).","operationId":"list_dashboards","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Dashboards for the project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelDashboardsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Dashboards"],"summary":"Create a new dashboard for a project.","operationId":"create_dashboard","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDashboardRequest"}}},"required":true},"responses":{"201":{"description":"Dashboard created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelDashboardResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/dashboards/{id}":{"get":{"tags":["Dashboards"],"summary":"Fetch a single dashboard by id.","operationId":"get_dashboard","parameters":[{"name":"id","in":"path","description":"Dashboard ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Owning project ID (scopes the lookup)","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Dashboard","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelDashboardResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Dashboard not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Dashboards"],"summary":"Delete a dashboard.","operationId":"delete_dashboard","parameters":[{"name":"id","in":"path","description":"Dashboard ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Owning project ID (scopes the delete)","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Dashboard deleted"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Dashboard not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Dashboards"],"summary":"Update a dashboard's name and/or layout.","operationId":"update_dashboard","parameters":[{"name":"id","in":"path","description":"Dashboard ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Owning project ID (scopes the update)","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDashboardRequest"}}},"required":true},"responses":{"200":{"description":"Dashboard updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelDashboardResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Dashboard not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/genai/traces":{"get":{"tags":["GenAI"],"summary":"Query GenAI trace summaries — traces containing spans with `gen_ai.*` attributes.","description":"`duration_ms` is the only field guaranteed to be milliseconds. `gen_ai.*`\nspan attributes (e.g. time-to-first-token, token latency) often follow the\nOTel GenAI semantic conventions, which use **seconds** (a fractional\ndouble), not milliseconds — do not read them as ms without converting.","operationId":"query_genai_traces","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"service_name","in":"query","description":"Filter by service name","required":false,"schema":{"type":"string"}},{"name":"gen_ai_system","in":"query","description":"Filter by AI system (openai, anthropic, etc.)","required":false,"schema":{"type":"string"}},{"name":"gen_ai_model","in":"query","description":"Filter by model (gpt-4, claude-sonnet-4-20250514, etc.)","required":false,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Start time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max traces to return (default: 50, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"offset","in":"query","description":"Offset for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"GenAI trace summaries","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenAiTraceSummariesResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/genai/traces/{project_id}/{trace_id}":{"get":{"tags":["GenAI"],"summary":"Get GenAI span details for a specific trace.","description":"`duration_ms` is the only field guaranteed to be milliseconds. `gen_ai.*`\nspan attributes (e.g. time-to-first-token, token latency) often follow the\nOTel GenAI semantic conventions, which use **seconds** (a fractional\ndouble), not milliseconds — do not read them as ms without converting.","operationId":"get_genai_trace","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"trace_id","in":"path","description":"Trace ID (hex)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"GenAI trace span details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenAiTraceDetailResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/global/traces/{trace_id}":{"get":{"tags":["Traces"],"summary":"Assemble a unified cross-project span waterfall (Phase 2).","description":"Fans out to every project that holds spans for `trace_id` (up to 20\nprojects, 10,000 total spans). Spans are annotated with\n`project_id`/`project_name` and sorted by `start_time ASC`.\n`truncated: true` signals a hit on either cap; `truncated_projects`\nlists the dropped project IDs. See ADR-027 §4 for the full design.","operationId":"getUnifiedTrace","parameters":[{"name":"trace_id","in":"path","description":"Trace ID (32 lowercase hex characters)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Unified cross-project trace waterfall","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnifiedTrace"}}}},"400":{"description":"trace_id is not 32 lowercase hex characters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions or deployment token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/health/{project_id}":{"get":{"tags":["OTel"],"summary":"Get health summaries for a project.","operationId":"get_health","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Health summaries","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/insights/{project_id}":{"get":{"tags":["Insights"],"summary":"List anomaly insights for a project.","operationId":"list_insights","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"status","in":"query","description":"Filter by status (active, resolved)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max insights to return (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"offset","in":"query","description":"Offset for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Insights list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InsightsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/logs":{"get":{"tags":["Telemetry Logs"],"summary":"Query log records with optional filters.","operationId":"query_logs","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"severity","in":"query","description":"Filter by severity (TRACE, DEBUG, INFO, WARN, ERROR, FATAL)","required":false,"schema":{"type":"string"}},{"name":"service_name","in":"query","description":"Filter by service name","required":false,"schema":{"type":"string"}},{"name":"search","in":"query","description":"Full-text search in log body (ILIKE)","required":false,"schema":{"type":"string"}},{"name":"trace_id","in":"query","description":"Filter by correlated trace ID","required":false,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Start time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max logs to return (default: 100, max: 1000)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"offset","in":"query","description":"Offset for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Log records","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LogsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/metric-label-keys":{"get":{"tags":["Telemetry Metrics"],"summary":"List the attribute (label) keys observed on a metric — powers the\nlabel-filter key autocomplete.","operationId":"list_metric_label_keys","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"metric_name","in":"query","description":"Metric to inspect","required":true,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Window start (RFC 3339); defaults to 24h before end","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"Window end (RFC 3339); defaults to now","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Distinct label keys","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricLabelKeysResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/metric-label-values":{"get":{"tags":["Telemetry Metrics"],"summary":"List the distinct values seen for a label key on a metric — powers value\nautocomplete once a key is chosen.","operationId":"list_metric_label_values","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"metric_name","in":"query","description":"Metric to inspect","required":true,"schema":{"type":"string"}},{"name":"label_key","in":"query","description":"Label key whose values to list (must match [a-zA-Z0-9_.:-])","required":true,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Window start (RFC 3339); defaults to 24h before end","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"Window end (RFC 3339); defaults to now","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Distinct label values","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricLabelValuesResponse"}}}},"400":{"description":"Invalid label key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/metric-names/{project_id}":{"get":{"tags":["Telemetry Metrics"],"summary":"List distinct metric names for a project.","operationId":"list_metric_names","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of metric names","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricNamesResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/metrics":{"get":{"tags":["Telemetry Metrics"],"summary":"Query metrics with time bucketing.","operationId":"query_metrics","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"metric_name","in":"query","description":"Filter by metric name","required":false,"schema":{"type":"string"}},{"name":"service_name","in":"query","description":"Filter by service name","required":false,"schema":{"type":"string"}},{"name":"environment","in":"query","description":"Filter by deployment environment","required":false,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Start time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"bucket_interval","in":"query","description":"Bucket interval (e.g. '1 hour', '5 minutes')","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max buckets to return (default: 1000)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"metric_type","in":"query","description":"Filter by metric type (gauge, sum, histogram, exponential_histogram, summary)","required":false,"schema":{"type":"string"}},{"name":"aggregation","in":"query","description":"Per-bucket aggregation: avg (default), sum, min, max, count, rate, p50/p95/p99, quantile:0.95","required":false,"schema":{"type":"string"}},{"name":"label_filters","in":"query","description":"Comma-separated key=value data-point label filters (keys must match [a-zA-Z0-9_.:-])","required":false,"schema":{"type":"string"}},{"name":"group_by","in":"query","description":"Comma-separated label keys to group series by","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Metrics data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricsResponse"}}}},"400":{"description":"Invalid label key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/pipeline-stats":{"get":{"tags":["OTel"],"summary":"Get OTel pipeline statistics (admin/system view).","operationId":"get_pipeline_stats","responses":{"200":{"description":"Pipeline statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PipelineStatsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/quota/{project_id}":{"get":{"tags":["OTel"],"summary":"Get storage quota for a project.","operationId":"get_quota","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Storage quota","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuotaResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/trace-summaries":{"get":{"tags":["Traces"],"summary":"Query trace summaries — one row per trace with span count, error count,\nroot span info, and proper trace-level pagination.","operationId":"query_trace_summaries","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"trace_id","in":"query","description":"Filter by trace ID","required":false,"schema":{"type":"string"}},{"name":"service_name","in":"query","description":"Filter by service name","required":false,"schema":{"type":"string"}},{"name":"status","in":"query","description":"Filter by status (OK, ERROR)","required":false,"schema":{"type":"string"}},{"name":"min_duration_ms","in":"query","description":"Minimum trace duration in ms","required":false,"schema":{"type":"number","format":"double"}},{"name":"start_time","in":"query","description":"Start time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"name_pattern","in":"query","description":"Filter by span name pattern (ILIKE)","required":false,"schema":{"type":"string"}},{"name":"sort_by","in":"query","description":"Sort field: 'start_time' (default) or 'duration'","required":false,"schema":{"type":"string"}},{"name":"sort_order","in":"query","description":"Sort direction: 'asc' or 'desc' (default)","required":false,"schema":{"type":"string"}},{"name":"include_total","in":"query","description":"Compute the `total` count (default: true). Set false to skip the second aggregation when only the page is needed","required":false,"schema":{"type":"boolean"}},{"name":"limit","in":"query","description":"Max traces to return (default: 50, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"offset","in":"query","description":"Offset for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Trace summaries","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TraceSummariesResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/traces":{"get":{"tags":["Traces"],"summary":"Query trace spans with optional filters.","description":"Each returned span has a `duration_ms` field (float, milliseconds) — this is\nthe ONLY field guaranteed to be in milliseconds. Spans also carry an\n`attributes` map of raw key/value pairs exactly as reported by the\ninstrumenting library: numeric attribute values may be seconds, milliseconds,\nmicroseconds, or nanoseconds depending on that library's convention, and\nnothing in this response labels the unit. Never assume an attribute's\nnumeric value shares `duration_ms`'s unit, and never state a duration in\nmilliseconds unless it came from a `duration_ms` field.","operationId":"query_traces","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"trace_id","in":"query","description":"Filter by trace ID","required":false,"schema":{"type":"string"}},{"name":"service_name","in":"query","description":"Filter by service name","required":false,"schema":{"type":"string"}},{"name":"status","in":"query","description":"Filter by status (OK, ERROR, UNSET)","required":false,"schema":{"type":"string"}},{"name":"min_duration_ms","in":"query","description":"Minimum span duration in ms","required":false,"schema":{"type":"number","format":"double"}},{"name":"start_time","in":"query","description":"Start time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"limit","in":"query","description":"Max spans to return (default: 100, max: 1000)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"offset","in":"query","description":"Offset for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Trace spans","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TracesResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/traces/cross-project/{trace_id}":{"get":{"tags":["Traces"],"summary":"Discover sibling projects that share the same `trace_id` (Phase 1 banner).","description":"Returns an empty `siblings` list when the trace is single-project — never\n404. Project names are included so the UI can render navigation links\nwithout a second round-trip. See ADR-027 §3 for the full auth model and\ntopology-disclosure trade-offs.","operationId":"getCrossProjectTraceSiblings","parameters":[{"name":"trace_id","in":"path","description":"Trace ID (32 lowercase hex characters)","required":true,"schema":{"type":"string"}},{"name":"exclude_project_id","in":"query","description":"Project ID to exclude (the caller's own project) so the UI does not render a self-link","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Sibling projects sharing this trace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CrossProjectTraceResponse"}}}},"400":{"description":"trace_id is not 32 lowercase hex characters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions or deployment token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/traces/{project_id}/{trace_id}":{"get":{"tags":["Traces"],"summary":"Get all spans for a specific trace.","description":"Each span has a `duration_ms` field (float, milliseconds) — the ONLY field\nguaranteed to be in milliseconds — plus an `attributes` map of raw\nkey/value pairs exactly as the instrumenting library reported them.\nNumeric attribute values (e.g. connection-pool wait times, queue delays)\nmay be in seconds, milliseconds, microseconds, or nanoseconds depending on\nthat library's own convention; this response never labels the unit. When\nexplaining what a span spent time on, only quote milliseconds from\n`duration_ms` (or from `start_time`/`end_time` deltas) — never assume a raw\nattribute number is already in milliseconds.","operationId":"get_trace","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"trace_id","in":"path","description":"Trace ID (hex)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Trace spans tree","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TracesResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/v1/logs":{"post":{"tags":["OTel Ingest"],"summary":"Ingest log records via OTLP/HTTP protobuf.","description":"Authenticates via API key in header, decompresses, decodes protobuf,\nchecks rate limit and storage quota, routes high-severity logs\nto DB and all logs to S3.","operationId":"ingest_logs","requestBody":{"description":"OTLP ExportLogsServiceRequest (protobuf, optionally gzip/zstd compressed)","content":{"application/x-protobuf":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"Logs accepted (OTLP protobuf response)"},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"413":{"description":"Storage quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"api_key":[]}]}},"/otel/v1/metrics":{"post":{"tags":["OTel Ingest"],"summary":"Ingest metrics via OTLP/HTTP protobuf.","description":"Authenticates via API key in header, decompresses, decodes protobuf,\nchecks rate limit and storage quota, then stores.","operationId":"ingest_metrics","requestBody":{"description":"OTLP ExportMetricsServiceRequest (protobuf, optionally gzip/zstd compressed)","content":{"application/x-protobuf":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"Metrics accepted (OTLP protobuf response)"},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"413":{"description":"Storage quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"api_key":[]}]}},"/otel/v1/traces":{"post":{"tags":["OTel Ingest"],"summary":"Ingest trace spans via OTLP/HTTP protobuf.","description":"Authenticates via API key in header, decompresses, decodes protobuf,\nchecks rate limit and storage quota, then stores spans.","operationId":"ingest_traces","requestBody":{"description":"OTLP ExportTraceServiceRequest (protobuf, optionally gzip/zstd compressed)","content":{"application/x-protobuf":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"Traces accepted (OTLP protobuf response)"},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"413":{"description":"Storage quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"api_key":[]}]}},"/otel/v1/{project_id}/{environment_id}/{deployment_id}/logs":{"post":{"tags":["OTel Ingest"],"summary":"Ingest log records with project/environment/deployment in the URL path.","operationId":"ingest_logs_by_path","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"OTLP ExportLogsServiceRequest (protobuf, optionally gzip/zstd compressed)","content":{"application/x-protobuf":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"Logs accepted (OTLP protobuf response)"},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"413":{"description":"Storage quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"api_key":[]}]}},"/otel/v1/{project_id}/{environment_id}/{deployment_id}/metrics":{"post":{"tags":["OTel Ingest"],"summary":"Ingest metrics with project/environment/deployment in the URL path.","operationId":"ingest_metrics_by_path","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"OTLP ExportMetricsServiceRequest (protobuf, optionally gzip/zstd compressed)","content":{"application/x-protobuf":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"Metrics accepted (OTLP protobuf response)"},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"413":{"description":"Storage quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"api_key":[]}]}},"/otel/v1/{project_id}/{environment_id}/{deployment_id}/traces":{"post":{"tags":["OTel Ingest"],"summary":"Ingest trace spans with project/environment/deployment in the URL path.","operationId":"ingest_traces_by_path","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"OTLP ExportTraceServiceRequest (protobuf, optionally gzip/zstd compressed)","content":{"application/x-protobuf":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"Traces accepted (OTLP protobuf response)"},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"413":{"description":"Storage quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"api_key":[]}]}},"/performance/has-metrics":{"get":{"tags":["Performance"],"summary":"Check if performance metrics exist for a project","operationId":"has_performance_metrics","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully checked performance metrics availability","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HasMetricsResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/performance/metrics":{"get":{"tags":["Performance"],"summary":"Get performance metrics","operationId":"get_performance_metrics","parameters":[{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Deployment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"device_type","in":"query","description":"Device type filter: desktop or mobile (optional)","required":false,"schema":{"type":"string"}},{"name":"include_bots","in":"query","description":"Include crawler/datacenter bot samples (default false)","required":false,"schema":{"type":"boolean"}},{"name":"filter_path","in":"query","description":"Filter to one page pathname (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_country","in":"query","description":"Filter to one country (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_region","in":"query","description":"Filter to one region (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_city","in":"query","description":"Filter to one city (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_browser","in":"query","description":"Filter to one browser (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_operating_system","in":"query","description":"Filter to one operating system (optional)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved performance metrics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PerformanceMetricsResponse"}}}},"400":{"description":"Invalid date format or missing parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/performance/metrics-over-time":{"get":{"tags":["Performance"],"summary":"Get metrics over time","operationId":"get_metrics_over_time","parameters":[{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DDTHH:MM:SSZ","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DDTHH:MM:SSZ","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Deployment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"device_type","in":"query","description":"Device type filter: desktop or mobile (optional)","required":false,"schema":{"type":"string"}},{"name":"include_bots","in":"query","description":"Include crawler/datacenter bot samples (default false)","required":false,"schema":{"type":"boolean"}},{"name":"filter_path","in":"query","description":"Filter to one page pathname (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_country","in":"query","description":"Filter to one country (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_region","in":"query","description":"Filter to one region (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_city","in":"query","description":"Filter to one city (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_browser","in":"query","description":"Filter to one browser (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_operating_system","in":"query","description":"Filter to one operating system (optional)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved metrics over time","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MetricsOverTimeResponse"}}}},"400":{"description":"Invalid date format or missing parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/performance/page-metrics":{"get":{"tags":["Performance"],"summary":"Get grouped page metrics","operationId":"get_grouped_page_metrics","parameters":[{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DDTHH:MM:SSZ","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DDTHH:MM:SSZ","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Deployment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"group_by","in":"query","description":"Group by: path, country, region, city, device_type, browser, operating_system","required":true,"schema":{"type":"string"}},{"name":"device_type","in":"query","description":"Device type filter: desktop or mobile (optional)","required":false,"schema":{"type":"string"}},{"name":"include_bots","in":"query","description":"Include crawler/datacenter bot samples (default false)","required":false,"schema":{"type":"boolean"}},{"name":"filter_path","in":"query","description":"Filter to one page pathname (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_country","in":"query","description":"Filter to one country (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_region","in":"query","description":"Filter to one region (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_city","in":"query","description":"Filter to one city (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_browser","in":"query","description":"Filter to one browser (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_operating_system","in":"query","description":"Filter to one operating system (optional)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved grouped page metrics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GroupedPageMetricsResponse"}}}},"400":{"description":"Invalid date format, missing parameters, or invalid group_by value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/platform/access-info":{"get":{"tags":["Platform"],"summary":"Get information about how the service is being accessed","description":"Returns details about the server's access mode, public IP address, private IP address,\nand domain creation capabilities. Both IP addresses are always included when available.","operationId":"get_access_info","responses":{"200":{"description":"Service access information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceAccessInfo"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/platform/private-ip":{"get":{"tags":["Platform"],"summary":"Get private/local IP address of the server","operationId":"get_private_ip","responses":{"200":{"description":"Successfully retrieved private IP address"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/platform/public-ip":{"get":{"tags":["Platform"],"summary":"Get public IP address of the server","operationId":"get_public_ip","responses":{"200":{"description":"Successfully retrieved public IP address"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/presets":{"get":{"tags":["Presets"],"summary":"List all available presets","operationId":"list_presets","responses":{"200":{"description":"List of available presets","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListPresetsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/presets/{slug}/dockerfile":{"post":{"tags":["Presets"],"summary":"Generate a Dockerfile from a preset","description":"Returns the Dockerfile content and build arguments for a given preset slug.\nThe CLI can use this to build Docker images locally without needing a Dockerfile\nin the project directory, enabling zero-config deployments.","operationId":"generate_preset_dockerfile","parameters":[{"name":"slug","in":"path","description":"Preset slug (e.g., nextjs, vite, python)","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateDockerfileRequest"}}},"required":true},"responses":{"200":{"description":"Generated Dockerfile","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateDockerfileResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Preset not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/preview-gateway/logs":{"get":{"tags":["Preview Gateway"],"operationId":"get_preview_gateway_logs","parameters":[{"name":"tail","in":"query","description":"Lines to tail (default 200, max 2000)","required":false,"schema":{"type":"integer","minimum":0}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LogsResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/preview-gateway/restart":{"post":{"tags":["Preview Gateway"],"operationId":"restart_preview_gateway","responses":{"204":{"description":"Gateway restarted"}},"security":[{"bearer_auth":[]}]}},"/preview-gateway/settings":{"get":{"tags":["Preview Gateway"],"operationId":"get_preview_gateway_settings","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreviewGatewaySettingsResponse"}}}}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Preview Gateway"],"operationId":"patch_preview_gateway_settings","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PatchSettingsRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreviewGatewaySettingsResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/preview-gateway/status":{"get":{"tags":["Preview Gateway"],"operationId":"get_preview_gateway_status","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayStatus"}}}}},"security":[{"bearer_auth":[]}]}},"/preview-gateway/upgrade":{"post":{"tags":["Preview Gateway"],"operationId":"upgrade_preview_gateway","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpgradeRequest"}}},"required":true},"responses":{"204":{"description":"Gateway upgraded"}},"security":[{"bearer_auth":[]}]}},"/projects":{"get":{"tags":["Projects"],"summary":"Get a list of all projects","operationId":"get_projects","parameters":[{"name":"page","in":"query","description":"Page number (1-based)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"per_page","in":"query","description":"Number of items per page","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"List of projects","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedProjectList"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Projects"],"summary":"Create a new project","operationId":"create_project","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectRequest"}}},"required":true},"responses":{"200":{"description":"Project created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"400":{"description":"Invalid input"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/by-slug/{slug}":{"get":{"tags":["Projects"],"summary":"Get details of a specific project by slug","operationId":"get_project_by_slug","parameters":[{"name":"slug","in":"path","description":"Project slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Project details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"404":{"description":"Project not found"}},"security":[{"bearer_auth":[]}]}},"/projects/from-template":{"post":{"tags":["Projects"],"summary":"Create a new project from a template","description":"Creates a new repository from a template and sets up the project with the\nspecified configuration. The template is cloned to a new repository under\nthe authenticated user's account or specified organization.","operationId":"create_project_from_template","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectFromTemplateRequest"}}},"required":true},"responses":{"201":{"description":"Project created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectFromTemplateResponse"}}}},"400":{"description":"Invalid input"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Template not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/statistics":{"get":{"tags":["Projects"],"summary":"Get project statistics","operationId":"get_project_statistics","responses":{"200":{"description":"Project statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectStatisticsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{id}":{"get":{"tags":["Projects"],"summary":"Get details of a specific project","operationId":"get_project","parameters":[{"name":"id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Project details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"404":{"description":"Project not found"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Projects"],"operationId":"update_project","parameters":[{"name":"id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectRequest"}}},"required":true},"responses":{"200":{"description":"Project updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Projects"],"operationId":"delete_project","parameters":[{"name":"id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Project deleted successfully"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{id}/deployments":{"get":{"tags":["Projects"],"operationId":"get_project_deployments","parameters":[{"name":"id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"per_page","in":"query","description":"Items per page","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"environment_id","in":"query","description":"Environment ID filter","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of deployments","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentListResponse"}}}},"404":{"description":"Project not found"}}}},"/projects/{id}/last-deployment":{"get":{"tags":["Deployments"],"summary":"Get the last deployment for a specific project","operationId":"get_last_deployment","parameters":[{"name":"id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Last deployment details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentResponse"}}}},"404":{"description":"Project not found or no deployments"},"500":{"description":"Internal server error"}}}},"/projects/{id}/source":{"patch":{"tags":["Projects"],"summary":"Change a project's source type to a Git-less type (docker_image /\nstatic_files / manual). Switching TO Git is done via the Git settings\nendpoint (`POST /projects/{id}/git`), which also supplies the repository and\nprovider connection.","operationId":"change_project_source","parameters":[{"name":"id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeProjectSourceRequest"}}},"required":true},"responses":{"200":{"description":"Source type changed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"400":{"description":"Invalid source type change (e.g. switching to Git here)"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{id}/trigger-pipeline":{"post":{"tags":["Projects"],"summary":"Trigger pipeline for a specific project","operationId":"trigger_project_pipeline","parameters":[{"name":"id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerPipelinePayload"}}},"required":true},"responses":{"200":{"description":"Pipeline triggered successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerPipelineResponse"}}}},"400":{"description":"Invalid request"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/access":{"get":{"tags":["Teams"],"operationId":"list_project_access","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Access grants","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProjectAccessResponse"}}}}},"403":{"description":"Insufficient permissions or no access to this project"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Teams"],"operationId":"grant_project_access","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectAccessRequest"}}},"required":true},"responses":{"201":{"description":"Access granted (idempotent upsert)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectAccessResponse"}}}},"403":{"description":"Insufficient permissions or no access to this project"},"404":{"description":"Team not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/access/{team_id}":{"delete":{"tags":["Teams"],"operationId":"revoke_project_access","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"team_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Access revoked"},"403":{"description":"Insufficient permissions or no access to this project"},"404":{"description":"Grant not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/active-visitors":{"get":{"tags":["Events"],"summary":"Get active visitors count","operationId":"get_active_visitors","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved active visitors count","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActiveVisitorsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents":{"get":{"tags":["Agents"],"operationId":"list_agents","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of agents for project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListAgentsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Agents"],"operationId":"create_agent","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertAgentRequest"}}},"required":true},"responses":{"201":{"description":"Agent created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentConfigResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/cli-status":{"get":{"tags":["Agents"],"operationId":"get_cli_status","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"provider","in":"query","description":"AI provider: claude_cli or codex_cli","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"CLI status"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/runs":{"get":{"tags":["Agents"],"operationId":"list_all_runs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-based)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (max 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List of all agent runs for a project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListRunsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/runs/latest-for-source":{"get":{"tags":["Agents"],"operationId":"latest_run_for_source","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"trigger_source_type","in":"query","description":"Trigger source type, e.g. 'error_group'","required":true,"schema":{"type":"string"}},{"name":"trigger_source_id","in":"query","description":"Trigger source ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Latest matching run, or null if none","content":{"application/json":{"schema":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AgentRunResponse"}]}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/runs/{run_id}":{"get":{"tags":["Agents"],"operationId":"get_run_with_logs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Run with logs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRunWithLogsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/runs/{run_id}/cancel":{"post":{"tags":["Agents"],"operationId":"cancel_run","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Agent run ID to cancel","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Run cancelled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRunResponse"}}}},"400":{"description":"Run is already in a terminal state"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/runs/{run_id}/retry":{"post":{"tags":["Agents"],"summary":"Retry a completed, failed, cancelled, or no_fix run with the same trigger context.\nCreates a new run record and spawns the executor.","operationId":"retry_run","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID to retry","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"202":{"description":"New run created from retry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRunResponse"}}}},"400":{"description":"Run is still active"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/runs/{run_id}/stream":{"get":{"tags":["Agents"],"summary":"SSE endpoint for real-time streaming of run events.\nPolls the agent_run_logs table every 500ms for new entries and streams them.\nCloses when the run reaches a terminal status.","operationId":"stream_run_events","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Agent run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Server-Sent Events stream of run log events and terminal status","content":{"text/event-stream":{}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/sandbox-status":{"get":{"tags":["Agents"],"operationId":"get_sandbox_status","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Project-scoped sandbox readiness (Docker + agent image)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxStatusResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/smoke-test":{"post":{"tags":["Agents"],"summary":"Run a smoke test to verify the selected AI CLI works in the environment\nwhere agents will actually execute (host or sandbox container). If no\n`provider_id` is supplied the globally active provider is tested.","operationId":"smoke_test_agent","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"provider_id","in":"query","description":"Provider id to test; defaults to the globally active provider","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Smoke test result for the AI CLI in the agent's execution environment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SmokeTestResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/{slug}":{"get":{"tags":["Agents"],"operationId":"get_agent","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Agent slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Agent config","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentConfigResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Agent not found"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Agents"],"operationId":"update_agent","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Agent slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertAgentRequest"}}},"required":true},"responses":{"200":{"description":"Agent updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentConfigResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Agent not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Agents"],"operationId":"delete_agent","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Agent slug","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Agent deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Agent not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/{slug}/runs":{"get":{"tags":["Agents"],"operationId":"list_agent_runs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Agent slug","required":true,"schema":{"type":"string"}},{"name":"page","in":"query","description":"Page number (1-based)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (max 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List of runs for a specific agent","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListRunsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Agent not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/{slug}/trigger":{"post":{"tags":["Agents"],"operationId":"trigger_agent","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Agent slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerAgentRequest"}}},"required":true},"responses":{"202":{"description":"Agent run created and queued","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRunResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"402":{"description":"Daily budget exceeded"},"403":{"description":"Insufficient permissions"},"404":{"description":"Agent not found"},"422":{"description":"AI CLI not installed"},"429":{"description":"Cooldown active"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/aggregated-buckets":{"get":{"tags":["Events"],"summary":"Get aggregated metrics by time bucket","operationId":"get_aggregated_buckets","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date for the query range","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date for the query range","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Optional environment filter","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Optional deployment filter","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"aggregation_level","in":"query","description":"Aggregation level: events, sessions, or visitors (default: events)","required":false,"schema":{"type":"string"}},{"name":"bucket_size","in":"query","description":"Time bucket size: '1 hour', '1 day', '1 week', etc. (default: '1 hour')","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved aggregated buckets","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AggregatedBucketsResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/conversations":{"get":{"tags":["AI Chat"],"summary":"Find the existing chat for a context (returns `null` if none yet). Requires\nthe per-project `ai_debug_chat_enabled` toggle to be on; returns 403 when the\nfeature is disabled so revoking it consistently hides existing chat content.","operationId":"find_conversation","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"context_type","in":"query","required":true,"schema":{"type":"string"}},{"name":"context_id","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ConversationResponse"}]}}}},"401":{"description":""},"403":{"description":""}},"security":[{"bearer_auth":[]}]},"post":{"tags":["AI Chat"],"summary":"Get-or-create the chat for a context (seeds it on first open).","operationId":"create_conversation","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateConversationRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversationResponse"}}}},"401":{"description":""},"403":{"description":""},"404":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/conversations/list":{"get":{"tags":["AI Chat"],"summary":"List all active conversations for a project, most-recently-active first.\nPowers the conversation switcher in the AI assistant sidebar.","operationId":"list_conversations","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ConversationResponse"}}}}},"401":{"description":""},"403":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/conversations/{public_id}":{"get":{"tags":["AI Chat"],"summary":"Full conversation history (excluding the internal system seed).","operationId":"get_conversation","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"public_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversationDetailResponse"}}}},"401":{"description":""},"403":{"description":""},"404":{"description":""}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["AI Chat"],"summary":"Rename a conversation (set its human-facing title).","operationId":"rename_conversation","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"public_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RenameConversationRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversationResponse"}}}},"400":{"description":""},"401":{"description":""},"403":{"description":""},"404":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/conversations/{public_id}/archive":{"post":{"tags":["AI Chat"],"summary":"Archive (soft-delete) a conversation.","operationId":"archive_conversation","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"public_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":""},"401":{"description":""},"403":{"description":""},"404":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/conversations/{public_id}/messages":{"post":{"tags":["AI Chat"],"summary":"Send a user message; stream the assistant reply as Server-Sent Events.","operationId":"send_message","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"public_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendMessageRequest"}}},"required":true},"responses":{"200":{"description":"SSE stream of assistant text deltas","content":{"text/event-stream":{}}},"401":{"description":""},"403":{"description":""},"404":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/conversations/{public_id}/pending-actions":{"get":{"tags":["AI Chat"],"summary":"List all pending actions for a conversation (most-recently-proposed first).","operationId":"list_pending_actions","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"public_id","in":"path","description":"Conversation public id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PendingActionResponse"}}}}},"401":{"description":""},"403":{"description":""},"404":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/pending-actions/{action_public_id}":{"get":{"tags":["AI Chat"],"summary":"Get a single pending action by its public id (scoped to the project).","operationId":"get_pending_action","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"action_public_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PendingActionResponse"}}}},"401":{"description":""},"403":{"description":""},"404":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/pending-actions/{action_public_id}/confirm":{"post":{"tags":["AI Chat"],"summary":"Confirm a proposed AI action: validate permission, atomically claim, execute,\npersist outcome. The execution uses the CONFIRMING user's auth — never the model's.","operationId":"confirm_pending_action","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"action_public_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PendingActionResponse"}}}},"401":{"description":""},"403":{"description":""},"404":{"description":""},"409":{"description":""},"503":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/pending-actions/{action_public_id}/reject":{"post":{"tags":["AI Chat"],"summary":"Reject a proposed AI action (no execution). Status transitions to \"rejected\".","operationId":"reject_pending_action","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"action_public_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PendingActionResponse"}}}},"401":{"description":""},"403":{"description":""},"404":{"description":""},"409":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/readiness":{"get":{"tags":["AI Chat"],"summary":"Report which AI prerequisites this project satisfies.","description":"Read-only and cheap, so the UI can decide up front whether to show a working\nentry point, an onboarding path, or nothing — instead of letting the user\nclick something that fails with a 409 they can't act on.","operationId":"get_chat_readiness","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Which AI prerequisites are met","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatReadinessResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/alarms":{"get":{"tags":["Alarms"],"summary":"List alarms for a project with optional filters.","operationId":"listProjectAlarms","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"alarm_type","in":"query","description":"Filter by alarm type (e.g. `container_restart`, `outage`).","required":false,"schema":{"type":["string","null"]}},{"name":"status","in":"query","description":"Filter by status: `firing`, `acknowledged`, or `resolved`.","required":false,"schema":{"type":["string","null"]}},{"name":"severity","in":"query","description":"Filter by severity: `info`, `warning`, or `critical`.","required":false,"schema":{"type":["string","null"]}},{"name":"environment_id","in":"query","description":"Filter by environment ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"service_id","in":"query","description":"Filter by external service ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"page","in":"query","description":"Page number (1-based, default 1).","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page (default 20, max 100).","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}}],"responses":{"200":{"description":"Paginated list of alarms","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlarmListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/alarms/summary":{"get":{"tags":["Alarms"],"summary":"Get alarm counts by status/severity/type for a project (dashboard summary widget).","operationId":"getProjectAlarmsSummary","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Alarm summary counts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlarmSummaryResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/alarms/{alarm_id}/acknowledge":{"post":{"tags":["Alarms"],"summary":"Acknowledge a firing alarm (marks it as seen but not resolved).","operationId":"acknowledgeAlarm","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"alarm_id","in":"path","description":"Alarm ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Alarm acknowledged"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Alarm not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/alarms/{alarm_id}/resolve":{"post":{"tags":["Alarms"],"summary":"Resolve an alarm.","operationId":"resolveAlarm","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"alarm_id","in":"path","description":"Alarm ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Alarm resolved"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Alarm not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/analyze":{"post":{"tags":["Autofixer"],"summary":"Start an autofixer analysis run for the given error group.\nCreates the run record immediately and spawns analysis in the background.","operationId":"start_analysis","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartAnalysisRequest"}}},"required":true},"responses":{"202":{"description":"Analysis started; returns run_id for streaming","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutofixerRunResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/runs/{run_id}":{"get":{"tags":["Autofixer"],"summary":"Get a single autofixer run with its logs.","operationId":"get_run","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Run with logs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutofixerRunWithLogsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/runs/{run_id}/add-context":{"post":{"tags":["Autofixer"],"summary":"Append a user message to the run's context field.","operationId":"add_context","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddContextRequest"}}},"required":true},"responses":{"200":{"description":"Context appended"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/runs/{run_id}/cancel":{"post":{"tags":["Autofixer"],"summary":"Cancel an autofixer run and clean up the work directory.","operationId":"cancel","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Run cancelled"},"400":{"description":"Run is already in a terminal state"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/runs/{run_id}/create-pr":{"post":{"tags":["Autofixer"],"summary":"Push the fix branch and create a pull request.\nRequires phase == \"fix_ready\".","operationId":"create_pr","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"201":{"description":"PR created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePrResponse"}}}},"400":{"description":"Run not in fix_ready phase"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/runs/{run_id}/fix":{"post":{"tags":["Autofixer"],"summary":"Transition from analysis to fix phase.\nRequires phase == \"analyzed\".","operationId":"start_fix","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"202":{"description":"Fix generation started"},"400":{"description":"Run not in analyzed phase"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/runs/{run_id}/re-analyze":{"post":{"tags":["Autofixer"],"summary":"Continue the conversation with user feedback.\nUses the same Claude session (--continue) in the existing work directory.\nRequires phase == \"analyzed\".","operationId":"re_analyze","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"202":{"description":"Conversation continued with feedback"},"400":{"description":"Run not in analyzed phase"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/runs/{run_id}/stream":{"get":{"tags":["Agents"],"summary":"SSE endpoint: streams run log events in real-time.\nPolls every 500 ms. Keeps the connection open through \"analyzed\" and \"fix_ready\"\nwaiting states; closes only on terminal statuses.","operationId":"stream_events","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Autofixer run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Server-Sent Events stream of autofixer run logs and status updates","content":{"text/event-stream":{}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/automatic-deploy":{"post":{"tags":["Projects"],"summary":"Update automatic deployment setting for a project","operationId":"update_automatic_deploy","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAutomaticDeployRequest"}}},"required":true},"responses":{"200":{"description":"Automatic deployment setting updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/custom-domains":{"get":{"tags":["Custom Domains"],"summary":"List all custom domains for a project","operationId":"list_custom_domains_for_project","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Custom domains retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListCustomDomainsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Custom Domains"],"summary":"Create a custom domain for a project","operationId":"create_custom_domain","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomDomainRequest"}}},"required":true},"responses":{"201":{"description":"Custom domain created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomDomainResponse"}}}},"400":{"description":"Invalid input"},"401":{"description":"Unauthorized"},"409":{"description":"Domain already exists"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/custom-domains/{domain_id}":{"get":{"tags":["Custom Domains"],"summary":"Get a custom domain by ID","operationId":"get_custom_domain","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain_id","in":"path","description":"Custom domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Custom domain retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomDomainResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Custom domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Custom Domains"],"summary":"Update a custom domain","operationId":"update_custom_domain","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain_id","in":"path","description":"Custom domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCustomDomainRequest"}}},"required":true},"responses":{"200":{"description":"Custom domain updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomDomainResponse"}}}},"400":{"description":"Invalid input"},"401":{"description":"Unauthorized"},"404":{"description":"Custom domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Custom Domains"],"summary":"Delete a custom domain","operationId":"delete_custom_domain","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain_id","in":"path","description":"Custom domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Custom domain deleted successfully"},"401":{"description":"Unauthorized"},"404":{"description":"Custom domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/custom-domains/{domain_id}/link-certificate/{certificate_id}":{"post":{"tags":["Custom Domains"],"summary":"Link a custom domain to a certificate","operationId":"link_custom_domain_to_certificate","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain_id","in":"path","description":"Custom domain ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"certificate_id","in":"path","description":"Certificate ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Custom domain linked to certificate successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomDomainResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Custom domain or certificate not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/deployment-config":{"patch":{"tags":["Projects"],"summary":"Update deployment configuration for a project","operationId":"update_project_deployment_config","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDeploymentConfigRequest"}}},"required":true},"responses":{"200":{"description":"Deployment configuration updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"400":{"description":"Invalid deployment configuration"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/deployment-tokens":{"get":{"tags":["Deployment Tokens"],"summary":"List all deployment tokens for a project","operationId":"list_deployment_tokens","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List of deployment tokens","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentTokenListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Deployment Tokens"],"summary":"Create a new deployment token for a project","operationId":"create_deployment_token","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDeploymentTokenRequest"}}},"required":true},"responses":{"201":{"description":"Deployment token created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDeploymentTokenResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"409":{"description":"Token with this name already exists"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/deployment-tokens/{token_id}":{"get":{"tags":["Deployment Tokens"],"summary":"Get a specific deployment token","operationId":"get_deployment_token","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"token_id","in":"path","description":"Deployment token ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deployment token details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentTokenResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Deployment token not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Deployment Tokens"],"summary":"Delete a deployment token","operationId":"delete_deployment_token","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"token_id","in":"path","description":"Deployment token ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Deployment token deleted successfully"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Deployment token not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Deployment Tokens"],"summary":"Update a deployment token","operationId":"update_deployment_token","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"token_id","in":"path","description":"Deployment token ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDeploymentTokenRequest"}}},"required":true},"responses":{"200":{"description":"Deployment token updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentTokenResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Deployment token not found"},"409":{"description":"Token with this name already exists"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/deployment-tokens/{token_id}/rotate":{"post":{"tags":["Deployment Tokens"],"summary":"Rotate a deployment token, invalidating its old secret and issuing a new one","operationId":"rotate_deployment_token","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"token_id","in":"path","description":"Deployment token ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deployment token rotated successfully; the response contains the new plaintext token, shown only once","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDeploymentTokenResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Deployment token not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/deployments/{deployment_id}":{"get":{"tags":["Deployments"],"summary":"Get a specific deployment by ID for a project (identified by ID or slug)","operationId":"get_deployment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deployment details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentResponse"}}}},"404":{"description":"Project or deployment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/deployments/{deployment_id}/cancel":{"post":{"tags":["Projects"],"summary":"Cancel a deployment","operationId":"cancel_deployment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deployment cancelled successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentStateResponse"}}}},"400":{"description":"Deployment cannot be cancelled (already completed, failed, or cancelled)"},"404":{"description":"Project or deployment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/deployments/{deployment_id}/container-logs":{"get":{"tags":["Deployments"],"summary":"List the captured (historical) container-log dumps for a deployment.","description":"Container runtime logs are normally only available live from the running\ncontainer. When a deployment is superseded its containers are torn down and\nthose logs would be lost — so just before teardown we capture each\ncontainer's logs to durable storage. This endpoint lists what was captured\nfor a given (often older) deployment, so a user can read the logs of a\ncontainer that no longer exists.","operationId":"list_deployment_container_logs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Captured container logs for the deployment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentContainerLogsListResponse"}}}},"404":{"description":"Deployment not found in this project"},"500":{"description":"Internal server error"}},"security":[{"bearer_token":[]}]}},"/projects/{project_id}/deployments/{deployment_id}/container-logs/{log_id}":{"get":{"tags":["Deployments"],"summary":"Get the captured text content of a single historical container-log dump.","operationId":"get_deployment_container_log_content","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"log_id","in":"path","description":"Captured log ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Captured container log content","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentContainerLogContentResponse"}}}},"404":{"description":"Captured log not found in this project"},"500":{"description":"Internal server error"}},"security":[{"bearer_token":[]}]}},"/projects/{project_id}/deployments/{deployment_id}/jobs":{"get":{"tags":["Deployments"],"summary":"Get jobs for a specific deployment","description":"Returns all jobs (workflow tasks) for a deployment, ordered by execution order.\nThis replaces the old deployment stages endpoint.","operationId":"get_deployment_jobs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Jobs retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentJobsResponse"}}}},"404":{"description":"Deployment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/deployments/{deployment_id}/jobs/{job_id}/logs":{"get":{"tags":["Deployments"],"summary":"Get logs for a specific deployment job","operationId":"get_deployment_job_logs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"job_id","in":"path","description":"Job ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Job logs retrieved successfully","content":{"text/plain":{"schema":{"type":"string"}}}},"404":{"description":"Job or logs not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_token":[]}]}},"/projects/{project_id}/deployments/{deployment_id}/jobs/{job_id}/logs/tail":{"get":{"tags":["Deployments"],"summary":"Tail logs for a specific deployment job in real-time via WebSocket","description":"**WebSocket Streaming**: Logs are sent as raw text, one line per WebSocket message.\n\n**Authentication**: Requires authentication via session cookie (browser clients)\nor API key (API clients). For browser-based WebSocket connections, ensure the user\nis logged in - the browser automatically includes session cookies in the WebSocket\nupgrade request.\n\n**API Client Authentication**: Include API key in Authorization header:\n```text\nAuthorization: Bearer tk_your_api_key_here\n```","operationId":"tail_deployment_job_logs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"job_id","in":"path","description":"Job ID","required":true,"schema":{"type":"string"}}],"responses":{"101":{"description":"WebSocket connection established for streaming deployment job logs"},"404":{"description":"Job or logs not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_token":[]}]}},"/projects/{project_id}/deployments/{deployment_id}/operations":{"get":{"tags":["Deployments"],"summary":"Get all operations for a deployment","operationId":"get_deployment_operations","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of operations","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperationResultsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Deployment not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Deployments"],"summary":"Execute a deployment operation (deploy, mark_complete, take_screenshot)","operationId":"execute_deployment_operation","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecuteOperationRequest"}}},"required":true},"responses":{"202":{"description":"Operation executed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperationResultResponse"}}}},"400":{"description":"Invalid operation"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Deployment not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/deployments/{deployment_id}/operations/{operation_type}":{"get":{"tags":["Deployments"],"summary":"Get the status of a specific operation type","operationId":"get_deployment_operation_status","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","required":true,"schema":{"type":"string"}},{"name":"operation_type","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Operation status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperationResultResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Operation not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/deployments/{deployment_id}/pause":{"post":{"tags":["Projects"],"summary":"Pause a deployment","operationId":"pause_deployment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deployment paused successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentStateResponse"}}}},"404":{"description":"Project or deployment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/deployments/{deployment_id}/promote":{"post":{"tags":["Deployments"],"summary":"Promote a deployment to another environment","description":"Creates a new deployment in the target environment using the source deployment's\nDocker image. Useful for promoting a validated preview/staging deployment to production.","operationId":"promote_deployment","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Source deployment ID to promote","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PromoteDeploymentRequest"}}},"required":true},"responses":{"200":{"description":"Promotion initiated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentResponse"}}}},"400":{"description":"Invalid deployment state for promotion"},"404":{"description":"Project, deployment, or target environment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/deployments/{deployment_id}/resume":{"post":{"tags":["Projects"],"summary":"Resume a deployment","operationId":"resume_deployment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deployment resumed successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentStateResponse"}}}},"404":{"description":"Project or deployment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/deployments/{deployment_id}/rollback":{"post":{"tags":["Projects"],"operationId":"rollback_to_deployment","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID to rollback to","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Rollback initiated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentResponse"}}}},"404":{"description":"Project or deployment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/deployments/{deployment_id}/teardown":{"delete":{"tags":["Projects"],"summary":"Teardown a specific deployment","operationId":"teardown_deployment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Deployment torn down successfully"},"404":{"description":"Project or deployment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/dsns":{"get":{"tags":[],"summary":"List all DSNs for a project","operationId":"list_dsns","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of DSNs","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProjectDSNResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"post":{"tags":[],"summary":"Create a new DSN for a project","operationId":"create_dsn","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDSNRequest"}}},"required":true},"responses":{"201":{"description":"DSN created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectDSNResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/dsns/get-or-create":{"post":{"tags":[],"summary":"Get or create DSN for a project/environment/deployment combination","operationId":"get_or_create_dsn","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetOrCreateDSNRequest"}}},"required":true},"responses":{"200":{"description":"DSN retrieved or created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectDSNResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/dsns/{dsn_id}/regenerate":{"post":{"tags":[],"summary":"Regenerate DSN keys (rotate keys)","operationId":"regenerate_dsn","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"dsn_id","in":"path","description":"DSN ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegenerateDSNRequest"}}},"required":true},"responses":{"200":{"description":"DSN keys regenerated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectDSNResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"DSN not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/dsns/{dsn_id}/revoke":{"post":{"tags":[],"summary":"Revoke (deactivate) a DSN","operationId":"revoke_dsn","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"dsn_id","in":"path","description":"DSN ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"DSN revoked"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"DSN not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/env-vars":{"get":{"tags":["Projects"],"summary":"Get environment variables for a project, optionally filtered by environment","operationId":"get_environment_variables","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Optional environment ID to filter by","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of environment variables","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EnvironmentVariableResponse"}}}}},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}},"post":{"tags":["Projects"],"summary":"Create a new environment variable","operationId":"create_environment_variable","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEnvironmentVariableRequest"}}},"required":true},"responses":{"201":{"description":"Environment variables created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentVariableResponse"}}}},"400":{"description":"Invalid input"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/env-vars/resolved":{"get":{"tags":["Projects"],"summary":"Resolved env vars for a project (manual + integration-sourced, merged).","description":"Returns the effective set of environment variables a deployment would see,\ncombining manually-defined vars with those contributed by linked external\nservices (Postgres, Redis, S3, etc.). Each entry is tagged with its source\nso the UI can render an integration icon, and manual entries that shadow an\nintegration key carry a reference to the integration they override.\n\nValues are always returned as a masked preview. Use the per-key reveal\nendpoint for plaintext (audit-logged).","operationId":"get_resolved_environment_variables","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Optional environment ID to filter manual vars by","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Resolved environment variables","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ResolvedEnvVarResponse"}}}}},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/env-vars/resolved/{key}/value":{"get":{"tags":["Projects"],"summary":"Reveal the plaintext value of a resolved environment variable.","description":"Mirrors `GET /projects/{id}/env-vars/{key}/value` but handles keys sourced\nfrom linked integrations (which are not stored in the `env_vars` table).\nResolution order mirrors the merged view:\n\n1. Manual env var with this key — this endpoint reads the manual store when\n the key exists there, then writes its own reveal audit event so callers\n can safely use one endpoint regardless of source.\n2. Integration env var supplied by a linked external service.\n\nReturns 404 when neither a manual var nor an integration produces the key.","operationId":"get_resolved_environment_variable_value","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"key","in":"path","description":"Environment variable key","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Optional environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"var_id","in":"query","description":"Exact manual environment-variable row ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"service_id","in":"query","description":"Integration service ID shown by the resolved list","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Resolved environment variable value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentVariableValueResponse"}}}},"403":{"description":"Plaintext secret access is not permitted"},"404":{"description":"Project, key, or integration not found"},"409":{"description":"Environment variable key is ambiguous"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/env-vars/{key}/value":{"get":{"tags":["Projects"],"summary":"Get environment variable value by key","operationId":"get_environment_variable_value","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"key","in":"path","description":"Environment variable key","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Optional environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"var_id","in":"query","description":"Exact environment-variable row ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Environment variable value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentVariableValueResponse"}}}},"403":{"description":"Plaintext secret access is not permitted"},"404":{"description":"Project or variable not found"},"409":{"description":"Environment variable key is ambiguous"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/env-vars/{var_id}":{"put":{"tags":["Projects"],"summary":"Update an environment variable","operationId":"update_environment_variable","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"var_id","in":"path","description":"Environment variable ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEnvironmentVariableRequest"}}},"required":true},"responses":{"200":{"description":"Environment variables updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentVariableResponse"}}}},"400":{"description":"Invalid input"},"404":{"description":"Project or variable not found"},"500":{"description":"Internal server error"}}},"delete":{"tags":["Projects"],"summary":"Delete an environment variable","operationId":"delete_environment_variable","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"var_id","in":"path","description":"Environment variable ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Environment variable deleted successfully"},"404":{"description":"Project or variable not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments":{"get":{"tags":["Projects"],"summary":"Get all environments for a project","operationId":"get_environments","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of environments","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EnvironmentResponse"}}}}},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}},"post":{"tags":["Projects"],"summary":"Create a new environment for a project","operationId":"create_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEnvironmentRequest"}}},"required":true},"responses":{"201":{"description":"Environment created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentResponse"}}}},"400":{"description":"Invalid input"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}":{"get":{"tags":["Projects"],"summary":"Get a specific environment by ID or slug","operationId":"get_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Environment details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentResponse"}}}},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}}},"delete":{"tags":["Projects"],"summary":"Delete an environment permanently","description":"Permanently deletes an environment and all related data. Cannot delete:\n- Production environments (name = \"Production\")\n\nWarning: This action is permanent and cannot be undone.\nActive deployments are automatically cancelled before deletion.","operationId":"delete_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Environment permanently deleted"},"400":{"description":"Cannot delete production environment"},"404":{"description":"Project or environment not found"},"428":{"description":"Recent MFA verification required"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/crons":{"get":{"tags":["Crons"],"operationId":"get_environment_crons","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of cron jobs","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CronInfo"}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/crons/{cron_id}":{"get":{"tags":["Crons"],"operationId":"get_cron_by_id","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"cron_id","in":"path","description":"Cron Job ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Cron job details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CronInfo"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Cron job not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/crons/{cron_id}/executions":{"get":{"tags":["Crons"],"operationId":"get_cron_executions","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"cron_id","in":"path","description":"Cron Job ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"per_page","in":"query","description":"Items per page (default: 20)","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"List of cron job executions","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CronExecutionInfo"}}}}},"401":{"description":"Unauthorized"},"404":{"description":"Cron job not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/domains":{"get":{"tags":["Projects"],"summary":"Get all environment domains for a specific environment","operationId":"get_environment_domains","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of environment domains","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EnvironmentDomainResponse"}}}}},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}}},"post":{"tags":["Projects"],"summary":"Add a new environment domain","operationId":"add_environment_domain","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddEnvironmentDomainRequest"}}},"required":true},"responses":{"201":{"description":"Domain added successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentDomainResponse"}}}},"400":{"description":"Invalid input"},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/domains/{domain_id}":{"delete":{"tags":["Projects"],"summary":"Delete an environment domain","operationId":"delete_environment_domain","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain_id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Domain deleted successfully"},"404":{"description":"Project, environment, or domain not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/settings":{"put":{"tags":["Projects"],"summary":"Update environment settings","operationId":"update_environment_settings","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEnvironmentSettingsRequest"}}},"required":true},"responses":{"200":{"description":"Environment settings updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentResponse"}}}},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/sleep":{"post":{"tags":["Environments"],"summary":"Sleep an on-demand environment","description":"Manually put an on-demand environment to sleep. Stops containers and sets\n`sleeping = true`. If no OnDemandWaker is available, falls back to DB flag only.","operationId":"sleep_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Environment put to sleep","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentResponse"}}}},"400":{"description":"On-demand not enabled for this environment"},"404":{"description":"Environment not found"},"429":{"description":"Too many state transitions, retry after cooldown"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/subdomain":{"patch":{"tags":["Projects"],"summary":"Rename the auto-managed subdomain for an environment.","description":"Replaces the environment's previous subdomain entirely — the old\nhostname stops resolving once the proxy reloads its route table.\nCustom domains attached to the environment are unaffected.","operationId":"update_environment_subdomain","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEnvironmentSubdomainRequest"}}},"required":true},"responses":{"200":{"description":"Subdomain updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentResponse"}}}},"400":{"description":"Invalid subdomain or conflict with another environment"},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/teardown":{"delete":{"tags":["Projects"],"summary":"Teardown an environment and all its active deployments","operationId":"teardown_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Environment torn down successfully"},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/wake":{"post":{"tags":["Environments"],"summary":"Wake a sleeping on-demand environment","description":"Manually wake an environment that has been put to sleep by the on-demand\nidle timeout. Starts containers, waits for health checks, then sets\n`sleeping = false`. If no OnDemandWaker is available (proxy not running\nin same process), falls back to setting the DB flag only.","operationId":"wake_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Environment woken up","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentResponse"}}}},"400":{"description":"On-demand not enabled for this environment"},"404":{"description":"Environment not found"},"429":{"description":"Too many state transitions, retry after cooldown"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{environment_id}/container-logs":{"get":{"tags":["Deployments"],"summary":"Get logs for a container in an environment via WebSocket","operationId":"get_container_logs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date for logs","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"end_date","in":"query","description":"End date for logs","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"tail","in":"query","description":"Number of lines to tail (or 'all')","required":false,"schema":{"type":"string"}},{"name":"container_name","in":"query","description":"Optional container name (defaults to first/primary container)","required":false,"schema":{"type":"string"}},{"name":"timestamps","in":"query","description":"Include timestamps in log output (default: false)","required":false,"schema":{"type":"boolean"}},{"name":"follow","in":"query","description":"Follow log output in real-time (default: true)","required":false,"schema":{"type":"boolean"}}],"responses":{"101":{"description":"WebSocket connection established for streaming container logs"},"400":{"description":"Not a server-type project"},"404":{"description":"Project, deployment, or container not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/containers":{"get":{"tags":["Deployments"],"summary":"List all containers for an environment","operationId":"list_containers","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of containers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerListResponse"}}}},"400":{"description":"Not a server-type project"},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}":{"get":{"tags":["Containers"],"summary":"Get detailed information about a specific container","operationId":"get_container_detail","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Container details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerDetailResponse"}}}},"404":{"description":"Container not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/environment/{variable_name}":{"get":{"tags":["Containers"],"operationId":"get_container_environment_variable","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}},{"name":"variable_name","in":"path","description":"Environment variable name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Environment variable value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerEnvironmentVariableValueResponse"}}}},"403":{"description":"Plaintext secret access is not permitted"},"404":{"description":"Container or environment variable not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/logs":{"get":{"tags":["Deployments"],"summary":"Get logs for a specific container by container ID via WebSocket","operationId":"get_container_logs_by_id","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}},{"name":"start_date","in":"query","description":"Start date for logs","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"end_date","in":"query","description":"End date for logs","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"tail","in":"query","description":"Number of lines to tail (or 'all')","required":false,"schema":{"type":"string"}},{"name":"timestamps","in":"query","description":"Include timestamps in log output (default: false)","required":false,"schema":{"type":"boolean"}},{"name":"follow","in":"query","description":"Follow log output in real-time (default: true)","required":false,"schema":{"type":"boolean"}}],"responses":{"101":{"description":"WebSocket connection established for streaming container logs"},"400":{"description":"Not a server-type project"},"404":{"description":"Project, environment, or container not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/metrics":{"get":{"tags":["Containers"],"summary":"Get metrics/stats for a specific container","operationId":"get_container_metrics","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Container metrics retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerMetricsResponse"}}}},"404":{"description":"Container not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/metrics/history":{"get":{"tags":["Containers"],"summary":"Fetch a time-series range for a single container resource metric\n(recorded by the container health monitor every ~30s).","description":"Useful metric names: `container.cpu_percent`,\n`container.cpu_utilization_percent`, `container.memory_used_bytes`,\n`container.memory_percent`, `container.network_rx_bytes_delta`,\n`container.network_tx_bytes_delta`.","operationId":"ContainerMetricsGetHistory","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}},{"name":"metric","in":"query","description":"Dotted metric name, e.g. `container.cpu_percent` or\n`container.memory_used_bytes`.","required":true,"schema":{"type":"string"}},{"name":"range","in":"query","description":"Time window: `1h`, `6h`, `24h`, or `7d` (defaults to `1h`).","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Metric time series data points","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ContainerMetricHistoryPoint"}}}}},"401":{"description":"Unauthorized"},"404":{"description":"Container not found"},"500":{"description":"Internal server error"},"503":{"description":"Metrics store not available"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/metrics/stream":{"get":{"tags":["Containers"],"summary":"Stream container metrics via Server-Sent Events (SSE)","operationId":"stream_container_metrics","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}},{"name":"interval","in":"query","description":"Update interval in milliseconds (default: 1000)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Metrics stream established (Server-Sent Events)"},"404":{"description":"Container not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/restart":{"post":{"tags":["Containers"],"summary":"Restart a container","operationId":"restart_container","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Container restarted successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerActionResponse"}}}},"404":{"description":"Container not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/start":{"post":{"tags":["Containers"],"summary":"Start a container","operationId":"start_container","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Container started successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerActionResponse"}}}},"404":{"description":"Container not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/stop":{"post":{"tags":["Containers"],"summary":"Stop a specific container","operationId":"stop_container","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Container stopped successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerActionResponse"}}}},"404":{"description":"Container not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{environment_id}/deploy/image":{"post":{"tags":["Deployments"],"summary":"Deploy from an external Docker image","description":"Triggers a deployment using a pre-built Docker image from an external registry.\nThe image will be pulled and deployed to the specified environment.","operationId":"deploy_from_image","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeployFromImageRequest"}}},"required":true},"responses":{"202":{"description":"Deployment started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RemoteDeploymentResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/deploy/image-upload":{"post":{"tags":["Deployments"],"summary":"Deploy from an uploaded Docker image tarball","description":"Uploads a Docker image tarball (from `docker save`) and deploys it directly.\nThe image is imported using `docker load` and then deployed to the specified environment.\nThis is useful when you want to deploy an image without pushing to a registry first.\n\nThe uploaded file should be a tarball created by `docker save myimage:tag > image.tar`\nor `docker save myimage:tag | gzip > image.tar.gz` (gzip compressed tarballs are also supported).","operationId":"deploy_from_image_upload","parameters":[{"name":"tag","in":"query","description":"Tag to apply to the imported image (e.g., \"myapp:v1.0\")\nIf not provided, a unique tag will be generated","required":false,"schema":{"type":["string","null"]}},{"name":"health_check_path","in":"query","description":"Optional HTTP health-check path override (e.g. \"/api/healthz\").\nMust start with '/'. When omitted, defaults to \"/\".","required":false,"schema":{"type":["string","null"]}},{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"202":{"description":"Image imported and deployment started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RemoteDeploymentResponse"}}}},"400":{"description":"Invalid request or unsupported format"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project or environment not found"},"413":{"description":"Image tarball too large"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/deploy/source":{"post":{"tags":["Deployments"],"summary":"Upload source code and immediately start a preset-based deployment.","operationId":"deploy_from_uploaded_source","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/SourceArchiveUpload"}}},"required":true},"responses":{"202":{"description":"Source deployment started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RemoteDeploymentResponse"}}}},"400":{"description":"Invalid source archive"},"404":{"description":"Project or environment not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/deploy/static":{"post":{"tags":["Deployments"],"summary":"Deploy from an uploaded static bundle","description":"Triggers a deployment using a previously uploaded static file bundle.","operationId":"deploy_from_static","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeployFromStaticRequest"}}},"required":true},"responses":{"202":{"description":"Deployment started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RemoteDeploymentResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project, environment, or bundle not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/error-alert-rules":{"get":{"tags":["error-alert-rules"],"summary":"List all alert rules for a project","operationId":"list_alert_rules","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of alert rules","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AlertRuleResponse"}}}}},"500":{"description":"Internal server error"}}},"post":{"tags":["error-alert-rules"],"summary":"Create a new alert rule","operationId":"create_alert_rule","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAlertRuleRequest"}}},"required":true},"responses":{"201":{"description":"Alert rule created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlertRuleResponse"}}}},"400":{"description":"Validation error"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-alert-rules/{rule_id}":{"get":{"tags":["error-alert-rules"],"summary":"Get a specific alert rule","operationId":"get_alert_rule","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"rule_id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Alert rule details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlertRuleResponse"}}}},"404":{"description":"Alert rule not found"},"500":{"description":"Internal server error"}}},"put":{"tags":["error-alert-rules"],"summary":"Update an existing alert rule","operationId":"update_alert_rule","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"rule_id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAlertRuleRequest"}}},"required":true},"responses":{"200":{"description":"Alert rule updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlertRuleResponse"}}}},"400":{"description":"Validation error"},"404":{"description":"Alert rule not found"},"500":{"description":"Internal server error"}}},"delete":{"tags":["error-alert-rules"],"summary":"Delete an alert rule","operationId":"delete_alert_rule","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"rule_id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Alert rule deleted"},"404":{"description":"Alert rule not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-dashboard-stats":{"get":{"tags":["error-tracking"],"summary":"Get error dashboard statistics","operationId":"get_error_dashboard_stats","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_time","in":"query","required":true,"schema":{"type":"string","format":"date-time"}},{"name":"end_time","in":"query","required":true,"schema":{"type":"string","format":"date-time"}},{"name":"environment_id","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"compare_to_previous","in":"query","required":false,"schema":{"type":["boolean","null"]}}],"responses":{"200":{"description":"Error dashboard statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDashboardStatsResponse"}}}},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-groups":{"get":{"tags":["error-tracking"],"summary":"List error groups for a project","operationId":"list_error_groups","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"status","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"environment_id","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"start_date","in":"query","required":false,"schema":{"type":["string","null"],"format":"date-time"}},{"name":"end_date","in":"query","required":false,"schema":{"type":["string","null"],"format":"date-time"}},{"name":"sort_by","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Paginated list of error groups","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedErrorGroupsResponse"}}}},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-groups/{group_id}":{"get":{"tags":["error-tracking"],"summary":"Get a specific error group","operationId":"get_error_group","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"group_id","in":"path","description":"Error group ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Error group details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorGroupResponse"}}}},"404":{"description":"Error group not found"},"500":{"description":"Internal server error"}}},"put":{"tags":["error-tracking"],"summary":"Update error group status","operationId":"update_error_group","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"group_id","in":"path","description":"Error group ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateErrorGroupRequest"}}},"required":true},"responses":{"200":{"description":"Error group updated successfully"},"404":{"description":"Error group not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-groups/{group_id}/events":{"get":{"tags":["error-tracking"],"summary":"List error events for a specific group","operationId":"list_error_events","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"group_id","in":"path","description":"Error group ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Paginated list of error events","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedErrorEventsResponse"}}}},"404":{"description":"Error group not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-groups/{group_id}/events/{event_id}":{"get":{"tags":["error-tracking"],"summary":"Get a specific error event","operationId":"get_error_event","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"group_id","in":"path","description":"Error group ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"event_id","in":"path","description":"Error event ID","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Error event details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEventResponse"}}}},"404":{"description":"Event not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-stats":{"get":{"tags":["error-tracking"],"summary":"Get error statistics for a project","operationId":"get_error_stats","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Error statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorGroupStatsResponse"}}}},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-time-series":{"get":{"tags":["error-tracking"],"summary":"Get error time series data for charts","operationId":"get_error_time_series","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_time","in":"query","required":true,"schema":{"type":"string","format":"date-time"}},{"name":"end_time","in":"query","required":true,"schema":{"type":"string","format":"date-time"}},{"name":"bucket","in":"query","description":"Time bucket size (e.g., \"1h\", \"15m\", \"1d\", \"1 hour\", \"30 minutes\")","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Error time series data","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ErrorTimeSeriesDataResponse"}}}}},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/events":{"get":{"tags":["Events"],"summary":"Get event counts with filtering","operationId":"get_events_count","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date for filtering events","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date for filtering events","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"limit","in":"query","description":"Maximum number of events to return (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"custom_events_only","in":"query","description":"Only return custom events, excluding system events like page_view, page_leave, heartbeat (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"aggregation_level","in":"query","description":"Aggregation level: events, sessions, or visitors (default: events)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved event counts","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EventCount"}}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/events/breakdown":{"get":{"tags":["Events"],"summary":"Get event type breakdown","operationId":"get_event_type_breakdown","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date for filtering events","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date for filtering events","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"aggregation_level","in":"query","description":"Aggregation level: events, sessions, or visitors (default: events)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved event type breakdown","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EventTypeBreakdown"}}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/events/ingest":{"post":{"tags":["Events"],"summary":"Record an analytics event via the console API with explicit project ID.","description":"The app backend forwards the user's encrypted Temps cookies, so visitor/session\nidentity is resolved automatically by middleware. No geolocation or user-agent\nenrichment is performed — this is a lightweight server-side ingestion path.","operationId":"record_console_event","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConsoleEventPayload"}}},"required":true},"responses":{"200":{"description":"Event recorded successfully"},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/events/properties/breakdown":{"get":{"tags":["Events"],"summary":"Get property breakdown by grouping events by a column","operationId":"get_property_breakdown","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in '%Y-%m-%d %H:%M:%S' format","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in '%Y-%m-%d %H:%M:%S' format","required":true,"schema":{"type":"string"}},{"name":"group_by","in":"query","description":"Column to group by (channel, device_type, browser, etc.)","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"event_name","in":"query","description":"Filter by event name","required":false,"schema":{"type":"string"}},{"name":"aggregation_level","in":"query","description":"Aggregation level: events, sessions, or visitors - default: events","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Maximum number of results (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"include_crawlers","in":"query","description":"Include crawler/bot traffic (default: false)","required":false,"schema":{"type":"boolean"}},{"name":"filter_country","in":"query","description":"Filter by country (for region/city drill-downs)","required":false,"schema":{"type":"string"}},{"name":"filter_region","in":"query","description":"Filter by region (for city drill-downs)","required":false,"schema":{"type":"string"}},{"name":"filter_browser","in":"query","description":"Filter by browser name (for version drill-downs)","required":false,"schema":{"type":"string"}},{"name":"filter_os","in":"query","description":"Filter by OS name (for version drill-downs)","required":false,"schema":{"type":"string"}},{"name":"filter_channel","in":"query","description":"Filter by channel name (for channel drill-downs)","required":false,"schema":{"type":"string"}},{"name":"filter_referrer","in":"query","description":"Filter by referrer hostname (for referrer drill-downs)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved property breakdown","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PropertyBreakdownResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/events/properties/timeline":{"get":{"tags":["Events"],"summary":"Get property timeline by grouping events by a column over time","operationId":"get_property_timeline","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in '%Y-%m-%d %H:%M:%S' format","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in '%Y-%m-%d %H:%M:%S' format","required":true,"schema":{"type":"string"}},{"name":"group_by","in":"query","description":"Column to group by (channel, device_type, browser, etc.)","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"event_name","in":"query","description":"Filter by event name","required":false,"schema":{"type":"string"}},{"name":"aggregation_level","in":"query","description":"Aggregation level: events, sessions, or visitors - default: events","required":false,"schema":{"type":"string"}},{"name":"bucket_size","in":"query","description":"Time bucket: hour, day, week, month (default: auto-detect)","required":false,"schema":{"type":"string"}},{"name":"include_crawlers","in":"query","description":"Include crawler/bot traffic (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Successfully retrieved property timeline","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PropertyTimelineResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/events/timeline":{"get":{"tags":["Events"],"summary":"Get events timeline","operationId":"get_events_timeline","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date for filtering events","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date for filtering events","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"event_name","in":"query","description":"Filter by specific event name","required":false,"schema":{"type":"string"}},{"name":"bucket_size","in":"query","description":"Bucket size: hour, day, or week (auto-detected if not specified)","required":false,"schema":{"type":"string"}},{"name":"aggregation_level","in":"query","description":"Aggregation level: events, sessions, or visitors (default: events)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved events timeline","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EventTimeline"}}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/events/unique":{"get":{"tags":["Funnels"],"summary":"Get all unique/distinct event types for a project (paginated)","operationId":"get_unique_events","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page (default: 50, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Unique event types retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventTypesResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/external-images":{"get":{"tags":["External Images"],"summary":"List external images for a project","operationId":"list_remote_external_images","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page (default: 20)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List of external images","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedExternalImagesResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["External Images"],"summary":"Register an external Docker image","description":"Registers an external Docker image reference without triggering a deployment.\nThe image can be deployed later using the deploy/image endpoint.","operationId":"register_external_image","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterImageRequest"}}},"required":true},"responses":{"201":{"description":"Image registered successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalImageResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/external-images/{image_id}":{"get":{"tags":["External Images"],"summary":"Get details of a specific external image","operationId":"get_remote_external_image","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"image_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Image details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalImageResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Image not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["External Images"],"summary":"Delete an external image","operationId":"delete_external_image","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"image_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Image deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Image not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/flags":{"get":{"tags":["Feature Flags"],"operationId":"list_flags","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"include_archived","in":"query","description":"Include archived flags. Defaults to false.","required":false,"schema":{"type":"boolean"}},{"name":"page","in":"query","description":"1-indexed page number. Defaults to 1.","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page. Defaults to 20, capped at 100.","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}}],"responses":{"200":{"description":"Flags listed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Feature Flags"],"operationId":"create_flag","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFlagRequest"}}},"required":true},"responses":{"201":{"description":"Flag created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"409":{"description":"Flag key already exists"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/flags/{key}":{"get":{"tags":["Feature Flags"],"operationId":"get_flag","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"key","in":"path","description":"Flag key","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Flag retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Flag not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Feature Flags"],"operationId":"archive_flag","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"key","in":"path","description":"Flag key","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Flag archived","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArchiveFlagResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Flag not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Feature Flags"],"operationId":"update_flag","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"key","in":"path","description":"Flag key","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateFlagRequest"}}},"required":true},"responses":{"200":{"description":"Flag updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Flag not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/flags/{key}/environments/{environment_id}":{"put":{"tags":["Feature Flags"],"summary":"Set a flag's value in one environment, and/or flip its kill switch.","operationId":"set_flag_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"key","in":"path","description":"Flag key","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetFlagEnvironmentRequest"}}},"required":true},"responses":{"200":{"description":"Environment value set","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagEnvironmentResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Flag or environment not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/flags/{key}/restore":{"post":{"tags":["Feature Flags"],"summary":"Bring an archived flag back.","description":"Archiving is otherwise one-way: the key stays reserved so the flag cannot\neven be re-created under the same name, which makes an accidental archive\nunrecoverable through the API.","operationId":"restore_flag","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"key","in":"path","description":"Flag key","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Flag restored","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Flag not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/funnels":{"get":{"tags":["Funnels"],"summary":"List all funnels for a project","operationId":"list_funnels","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Funnels retrieved successfully","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/FunnelResponse"}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Funnels"],"summary":"Create a new funnel","operationId":"create_funnel","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFunnelRequest"}}},"required":true},"responses":{"201":{"description":"Funnel created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFunnelResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/funnels/preview":{"post":{"tags":["Funnels"],"summary":"Preview funnel metrics without creating the funnel","operationId":"preview_funnel_metrics","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFunnelRequest"}}},"required":true},"responses":{"200":{"description":"Funnel metrics preview","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FunnelMetricsResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/funnels/{funnel_id}":{"put":{"tags":["Funnels"],"summary":"Update a funnel","operationId":"update_funnel","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"funnel_id","in":"path","description":"Funnel ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFunnelRequest"}}},"required":true},"responses":{"200":{"description":"Funnel updated successfully"},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"404":{"description":"Funnel not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Funnels"],"summary":"Delete a funnel","operationId":"delete_funnel","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"funnel_id","in":"path","description":"Funnel ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Funnel deleted successfully"},"401":{"description":"Unauthorized"},"404":{"description":"Funnel not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/funnels/{funnel_id}/metrics":{"get":{"tags":["Funnels"],"summary":"Get funnel metrics","operationId":"get_funnel_metrics","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"funnel_id","in":"path","description":"Funnel ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID filter","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"country_code","in":"query","description":"Country code filter","required":false,"schema":{"type":"string"}},{"name":"start_date","in":"query","description":"Start date filter (ISO 8601)","required":false,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date filter (ISO 8601)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Funnel metrics retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FunnelMetricsResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"404":{"description":"Funnel not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/git":{"post":{"tags":["Projects"],"summary":"Update git settings for a project","operationId":"update_git_settings","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateGitSettingsRequest"}}},"required":true},"responses":{"200":{"description":"Git settings updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"400":{"description":"Invalid git configuration or branch does not exist"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/gitlab/reinstall-webhook":{"post":{"tags":["Projects"],"summary":"Reinstall the GitLab webhook for a project","description":"Removes the existing webhook (if any) and installs a fresh one.\nUse this when a webhook has been manually deleted on the GitLab side\nand automatic deployments have stopped working.","operationId":"reinstall_gitlab_webhook","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Webhook reinstalled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReinstallWebhookResponse"}}}},"400":{"description":"Project is not connected to a GitLab repository"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/has-error-groups":{"get":{"tags":["error-tracking"],"summary":"Check if project has any error groups","operationId":"has_error_groups","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Error groups existence check","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HasErrorGroupsResponse"}}}},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/has-events":{"get":{"tags":["Events"],"summary":"Check if project has any analytics events","operationId":"has_analytics_events","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully checked for events","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HasEventsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/hourly-visits":{"get":{"tags":["Events"],"summary":"Get hourly visits","operationId":"get_hourly_visits","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date for filtering visits","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date for filtering visits","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"aggregation_level","in":"query","description":"Aggregation level: events (page views), sessions (unique sessions), or visitors (unique visitors) - default: events","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved hourly visits","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EventTimeline"}}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/images":{"get":{"tags":["External Images"],"summary":"List all external images for a project","operationId":"list_external_images","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of external images","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PushedExternalImageResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/images/push":{"post":{"tags":["External Images"],"summary":"Push an external Docker image","operationId":"push_external_image","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PushImageRequest"}}},"required":true},"responses":{"201":{"description":"Image pushed successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PushedExternalImageResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/images/{image_id}":{"get":{"tags":["External Images"],"summary":"Get details of a specific external image","operationId":"get_external_image","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"image_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Image details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PushedExternalImageResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Image not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/incidents":{"get":{"tags":["Status Page"],"summary":"List incidents for a project","operationId":"list_incidents","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"status","in":"query","description":"Filter by status","required":false,"schema":{"type":"string"}},{"name":"page","in":"query","description":"Page number","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Successfully retrieved incidents"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Status Page"],"summary":"Create a new incident","operationId":"create_incident","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateIncidentRequest"}}},"required":true},"responses":{"201":{"description":"Incident created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncidentResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/incidents/bucketed":{"get":{"tags":["Status Page"],"summary":"Get bucketed incident data for a project","operationId":"get_bucketed_incidents","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"interval","in":"query","description":"Bucket interval: '5min', 'hourly', or 'daily' (default: hourly)","required":false,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601) (default: 7 days ago)","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (ISO 8601) (default: now)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved bucketed incident data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncidentBucketedResponse"}}}},"400":{"description":"Invalid parameters"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/logs":{"delete":{"tags":["Logs"],"summary":"Purge all logs for a project before a given timestamp","operationId":"purge_project_logs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PurgeLogsRequest"}}},"required":true},"responses":{"200":{"description":"Purge completed"},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/mcp-servers":{"get":{"tags":["Agents"],"operationId":"list_mcps","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListMcpsResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Agents"],"operationId":"create_mcp","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMcpRequest"}}},"required":true},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpDefinitionResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/mcp-servers/{slug}":{"get":{"tags":["Agents"],"operationId":"get_mcp","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"MCP server not found"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Agents"],"operationId":"update_mcp","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMcpRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"MCP server not found"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Agents"],"operationId":"delete_mcp","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"MCP server deleted"},"401":{"description":"Unauthorized"},"404":{"description":"MCP server not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/mcp-servers/{slug}/config/{field}":{"get":{"tags":["Agents"],"operationId":"reveal_mcp_config","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}},{"name":"field","in":"path","description":"Sensitive field path, such as url or env.API_TOKEN","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SensitiveMcpConfigValueResponse"}}}},"400":{"description":"Field is not revealable"},"401":{"description":"Unauthorized"},"403":{"description":"Missing secrets:read permission"},"404":{"description":"MCP server or field not found"},"500":{"description":"Configuration read or audit failed"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/monitors":{"get":{"tags":["Status Page"],"summary":"List monitors for a project","operationId":"list_monitors","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved monitors","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MonitorResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Status Page"],"summary":"Create a new monitor","operationId":"create_monitor","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMonitorRequest"}}},"required":true},"responses":{"201":{"description":"Monitor created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MonitorResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/observe/events":{"get":{"tags":["Observability"],"summary":"List a merged page of observability events for a project.","description":"Each row carries everything the side panel needs to render — no\nfollow-up fetch is required for the common case. Heavy fields\n(stacktraces, headers, span attributes) are truncated server-side and\nexpose a `*_truncated` flag; clients fetch the full row from the\n`/full` endpoint only when the user explicitly clicks \"Show full\".","operationId":"observability_list_events","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"kinds","in":"query","description":"Comma-separated kinds: `log,request,span,error,revenue`. Empty or\nmissing returns every kind.","required":false,"schema":{"type":"string"}},{"name":"from","in":"query","description":"Inclusive lower bound on event timestamp (ISO 8601, `Z` suffix).","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","description":"Inclusive upper bound on event timestamp.","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"deployment_id","in":"query","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"search","in":"query","description":"Free-text substring matched against per-kind summary fields\n(request path / error class / revenue event_type).","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Page size (default 50, max 200).","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"hide_bots","in":"query","description":"When `true`, exclude bot/crawler request rows. When `false`, only\ninclude bot rows. Omitted means \"include everything\" (default).\nOnly affects the `Request` kind.","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Merged event page","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventsResponse"}}}},"400":{"description":"Invalid filter (kinds, time range, …)","content":{"text/plain":{"schema":{"type":"string"}}}},"401":{"description":"Unauthorized","content":{"text/plain":{"schema":{"type":"string"}}}},"403":{"description":"Insufficient permissions","content":{"text/plain":{"schema":{"type":"string"}}}},"500":{"description":"Internal server error","content":{"text/plain":{"schema":{"type":"string"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/observe/events/{kind}/{event_id}/full":{"get":{"tags":["Observability"],"summary":"Fetch the un-truncated form of one event by `(kind, id)`. Side panel\n\"Show full\" action calls this — the list response carries truncated\npreviews + a `*_truncated` flag to let the UI decide whether to fetch.","operationId":"observability_full_event","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"kind","in":"path","description":"Event kind discriminator","required":true,"schema":{"$ref":"#/components/schemas/EventKind"}},{"name":"event_id","in":"path","description":"Per-kind identity: request_id for requests, `{trace_id}:{span_id}` for spans, serial id for errors/revenue","required":true,"schema":{"type":"string"}},{"name":"ts","in":"query","description":"The row's event timestamp as returned by the list endpoint. Optional,\nbut strongly recommended: it bounds the lookup to the storage\npartitions/chunks around that instant instead of scanning the whole\nretention window.","required":false,"schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"Full row","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FullEvent"}}}},"401":{"description":"Unauthorized","content":{"text/plain":{"schema":{"type":"string"}}}},"403":{"description":"Insufficient permissions","content":{"text/plain":{"schema":{"type":"string"}}}},"404":{"description":"Event not found in project","content":{"text/plain":{"schema":{"type":"string"}}}},"500":{"description":"Internal server error","content":{"text/plain":{"schema":{"type":"string"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/releases/{release}/source-files":{"get":{"tags":["source-maps"],"summary":"List uploaded source files for a release (metadata only).","operationId":"list_source_files","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"release","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of source files","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceFileListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["source-maps"],"summary":"Upload a raw source file for a release (native symbolication).","description":"Accepts a multipart form with:\n- `file`: the source file bytes (required)\n- `file_path`: the path of the file as it appears in stack frames (required;\n derived from the uploaded filename if omitted). Normalized with the `~`\n prefix convention, matching source-map storage.\n\nRequires the project's `error_source_context_enabled` toggle to be on.\nUpserts on (project, release, file_path).","operationId":"upload_source_file","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"release","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"201":{"description":"Source file uploaded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceFileResponse"}}}},"400":{"description":"Missing fields"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"409":{"description":"Source context disabled for project"},"413":{"description":"Source file too large"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["source-maps"],"summary":"Delete all uploaded source files for a release.","operationId":"delete_release_source_files","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"release","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Source files deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/releases/{release}/source-maps":{"get":{"tags":["source-maps"],"summary":"List all source maps for a specific release","operationId":"list_source_maps","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"release","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of source maps","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceMapListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["source-maps"],"summary":"Upload a source map for a release.","description":"Accepts a multipart form with:\n- `file`: The .map file (required)\n- `file_path`: The URL path of the minified file as it appears in stack traces (required).\n Uses the ~ prefix convention (e.g., \"~/assets/main.js\").\n If a full URL is provided, it will be normalized automatically.\n- `dist`: Optional distribution identifier\n\nIf a source map already exists for the same (project, release, file_path), it is replaced.","operationId":"upload_source_map","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"release","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"201":{"description":"Source map uploaded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceMapResponse"}}}},"400":{"description":"Invalid source map or missing fields"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"413":{"description":"Source map too large"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["source-maps"],"summary":"Delete all source maps for a specific release","operationId":"delete_release_source_maps","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"release","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Source maps deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/events":{"get":{"tags":["Revenue"],"summary":"Recent ingested events for the activity feed.","operationId":"revenue_recent_events","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RecentEventResponse"}}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/integrations":{"get":{"tags":["Revenue"],"summary":"List revenue integrations for a project.","operationId":"revenue_list_integrations","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/IntegrationResponse"}}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Revenue"],"summary":"Create a new revenue integration. Response contains the generated\nwebhook path that the user must paste into their provider's dashboard.","operationId":"revenue_create_integration","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateIntegrationBody"}}},"required":true},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntegrationResponse"}}}},"400":{"description":"Validation error"},"409":{"description":"Already connected"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/integrations/{integration_id}":{"delete":{"tags":["Revenue"],"summary":"Delete a revenue integration (permanent — use rotate_token to refresh\ncredentials without breaking history).","operationId":"revenue_delete_integration","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"integration_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/integrations/{integration_id}/config":{"post":{"tags":["Revenue"],"summary":"Replace the typed provider config on an integration. Passing `null`\nclears the config back to the accept-everything default. The config's\nprovider tag must match the integration's provider.","operationId":"revenue_update_config","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"integration_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateConfigBody"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntegrationResponse"}}}},"400":{"description":"Validation error"},"404":{"description":"Integration not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/integrations/{integration_id}/import/invoices":{"post":{"tags":["Revenue"],"summary":"Import a Stripe invoices CSV export. Each paid invoice becomes an\n`invoice.paid` event so historical MRR/charge totals populate the\ntimeseries. Ingestion is idempotent: re-uploading the same file is a\nno-op.","operationId":"revenue_import_invoices_csv","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"integration_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportOutcomeResponse"}}}},"400":{"description":"Malformed CSV or wrong provider"},"404":{"description":"Integration not found"},"413":{"description":"CSV too large"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/integrations/{integration_id}/import/subscriptions":{"post":{"tags":["Revenue"],"summary":"Import a Stripe subscriptions CSV export. Use this to backfill MRR /\nactive subscriptions when migrating from Stripe without providing\nAPI keys. Webhooks remain the source of truth for live updates —\nCSV rows never overwrite newer webhook state.","operationId":"revenue_import_subscriptions_csv","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"integration_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportOutcomeResponse"}}}},"400":{"description":"Malformed CSV or wrong provider"},"404":{"description":"Integration not found"},"413":{"description":"CSV too large"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/integrations/{integration_id}/rotate-token":{"post":{"tags":["Revenue"],"summary":"Rotate the webhook path token. Returns the new integration state —\nthe user must paste the new URL into their provider's dashboard.","operationId":"revenue_rotate_token","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"integration_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntegrationResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/integrations/{integration_id}/update-secret":{"post":{"tags":["Revenue"],"summary":"Replace the stored signing secret without rotating the webhook URL.\nUse this after rotating the secret in the provider's dashboard.","operationId":"revenue_update_secret","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"integration_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSecretBody"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntegrationResponse"}}}},"400":{"description":"Validation error"},"404":{"description":"Integration not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/metrics/customers":{"get":{"tags":["Revenue"],"summary":"New + churned customers per bucket.","operationId":"revenue_metrics_customers","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CustomerMovementResponse"}}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/metrics/mrr":{"get":{"tags":["Revenue"],"summary":"Bucketed MRR timeseries for the revenue chart.","operationId":"revenue_metrics_mrr","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MrrBucketResponse"}}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/metrics/summary":{"get":{"tags":["Revenue"],"summary":"Current MRR / ARR / churn / ARPU for a project, in one currency.","operationId":"revenue_metrics_summary","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MetricsSummaryResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/secrets":{"get":{"tags":["Secrets"],"summary":"List project secrets (metadata only — values never returned).","operationId":"listProjectSecrets","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Optional environment filter","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of secrets (metadata only, no values)","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProjectSecretResponse"}}}}},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}},"post":{"tags":["Secrets"],"summary":"Create a new secret. The value is encrypted before storage and will be\nmounted as a file at `/run/secrets/` on the next deployment.\nThe plaintext value is NOT returned — the response carries only metadata.","operationId":"createProjectSecret","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectSecretRequest"}}},"required":true},"responses":{"201":{"description":"Secret created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectSecretResponse"}}}},"400":{"description":"Invalid key or value too large"},"409":{"description":"Key already exists in project"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/secrets/{secret_id}":{"put":{"tags":["Secrets"],"summary":"Update a project secret. Value rotation requires a redeploy to take effect —\nrunning containers keep their currently-mounted values until the next\ndeployment.","operationId":"updateProjectSecret","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"secret_id","in":"path","description":"Secret ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProjectSecretRequest"}}},"required":true},"responses":{"200":{"description":"Secret updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectSecretResponse"}}}},"400":{"description":"Value too large"},"404":{"description":"Secret not found"},"500":{"description":"Internal server error"}}},"delete":{"tags":["Secrets"],"summary":"Delete a project secret. Running containers keep their mounted secret files\nuntil they are redeployed.","operationId":"deleteProjectSecret","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"secret_id","in":"path","description":"Secret ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Secret deleted"},"404":{"description":"Secret not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/settings":{"post":{"tags":["Projects"],"summary":"Update project settings","operationId":"update_project_settings","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProjectSettingsRequest"}}},"required":true},"responses":{"200":{"description":"Project settings updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/skills":{"get":{"tags":["Agents"],"operationId":"list_skills","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListSkillsResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Agents"],"operationId":"create_skill","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSkillRequest"}}},"required":true},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/skills/upload":{"post":{"tags":["Agents"],"summary":"Upload a skill with an archive (tar.gz) — project-scoped.","operationId":"upload_skill","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"type":"string"}}},"required":true},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/skills/{slug}":{"get":{"tags":["Agents"],"operationId":"get_skill","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Agents"],"operationId":"update_skill","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSkillRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Agents"],"operationId":"delete_skill","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Skill deleted"},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/skills/{slug}/archive":{"get":{"tags":["Agents"],"summary":"Download a skill's archive (tar.gz) — project-scoped.","operationId":"download_skill_archive","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Skill archive tar.gz","content":{"application/gzip":{}}},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found or has no archive"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/source-map-releases":{"get":{"tags":["source-maps"],"summary":"List all releases that have source maps for a project","operationId":"list_releases","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of releases","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReleaseListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/source-maps/{source_map_id}":{"delete":{"tags":["source-maps"],"summary":"Delete a specific source map by ID","operationId":"delete_source_map","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"source_map_id","in":"path","description":"Source map ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Source map deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Source map not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/static-bundles":{"get":{"tags":["Static Bundles"],"summary":"List static bundles for a project","operationId":"list_static_bundles","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page (default: 20)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List of static bundles","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedStaticBundlesResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/static-bundles/{bundle_id}":{"get":{"tags":["Static Bundles"],"summary":"Get details of a specific static bundle","operationId":"get_static_bundle","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"bundle_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Bundle details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StaticBundleResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Bundle not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Static Bundles"],"summary":"Delete a static bundle","operationId":"delete_static_bundle","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"bundle_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Bundle deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Bundle not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/status":{"get":{"tags":["Status Page"],"summary":"Get status page overview","operationId":"get_status_overview","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved status overview","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatusPageOverview"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/unique-counts":{"get":{"tags":["Events"],"summary":"Get unique counts over time frame","operationId":"get_unique_counts","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in '%Y-%m-%d %H:%M:%S' format","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in '%Y-%m-%d %H:%M:%S' format","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"metric","in":"query","description":"Metric to count: 'sessions' (unique sessions), 'visitors' (unique visitors), 'returning_visitors' (visitors seen before the range), or 'page_views' (total page views) (default: 'sessions')","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved count","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UniqueCountsResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/upload/static":{"post":{"tags":["Static Bundles"],"summary":"Upload a static bundle for later deployment","description":"Uploads a tar.gz or zip file containing static assets. The bundle can be\ndeployed later using the deploy/static endpoint.","operationId":"upload_static_bundle","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/SourceArchiveUpload"}}},"required":true},"responses":{"201":{"description":"Bundle uploaded successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StaticBundleResponse"}}}},"400":{"description":"Invalid request or unsupported format"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project not found"},"413":{"description":"Bundle too large"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/vulnerability-scans":{"get":{"tags":["Vulnerability Scans"],"operationId":"list_project_scans","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List of vulnerability scans","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ScanResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Vulnerability Scans"],"operationId":"trigger_scan","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerScanRequest"}}},"required":true},"responses":{"202":{"description":"Scan triggered successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerScanResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/vulnerability-scans/environments":{"get":{"tags":["Vulnerability Scans"],"operationId":"get_latest_scans_per_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Latest scans per environment for current deployments","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ScanResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/vulnerability-scans/latest":{"get":{"tags":["Vulnerability Scans"],"operationId":"get_latest_scan","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Latest scan for project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScanResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"No scans found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/webhooks":{"get":{"tags":["Webhooks"],"summary":"List all webhooks for a project","operationId":"list_webhooks","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20},{"name":"sort_by","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"List of webhooks","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/WebhookResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Webhooks"],"summary":"Create a new webhook","operationId":"create_webhook","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWebhookRequestBody"}}},"required":true},"responses":{"201":{"description":"Webhook created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/webhooks/{webhook_id}":{"get":{"tags":["Webhooks"],"summary":"Get a specific webhook","operationId":"get_webhook","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"webhook_id","in":"path","description":"Webhook ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Webhook details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Webhook not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Webhooks"],"summary":"Update a webhook","operationId":"update_webhook","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"webhook_id","in":"path","description":"Webhook ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWebhookRequestBody"}}},"required":true},"responses":{"200":{"description":"Webhook updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Webhook not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Webhooks"],"summary":"Delete a webhook","operationId":"delete_webhook","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"webhook_id","in":"path","description":"Webhook ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Webhook deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Webhook not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/webhooks/{webhook_id}/deliveries":{"get":{"tags":["Webhook Deliveries"],"summary":"List webhook deliveries","operationId":"list_deliveries","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"webhook_id","in":"path","description":"Webhook ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"limit","in":"query","description":"Number of deliveries to return (default: 50)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List of deliveries","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/WebhookDeliveryResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/webhooks/{webhook_id}/deliveries/{delivery_id}":{"get":{"tags":["Webhook Deliveries"],"summary":"Get a specific webhook delivery by ID","operationId":"get_delivery","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"webhook_id","in":"path","description":"Webhook ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"delivery_id","in":"path","description":"Delivery ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Delivery details including full payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDeliveryResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Delivery not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/webhooks/{webhook_id}/deliveries/{delivery_id}/retry":{"post":{"tags":["Webhook Deliveries"],"summary":"Retry a failed delivery","operationId":"retry_delivery","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"webhook_id","in":"path","description":"Webhook ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"delivery_id","in":"path","description":"Delivery ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Delivery retried","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDeliveryResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Delivery not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/workflows/dry-run":{"post":{"tags":["Workflows"],"operationId":"workflow_dry_run","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkflowDryRunRequest"}}},"required":true},"responses":{"202":{"description":"Ephemeral run created and queued","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRunResponse"}}}},"400":{"description":"Validation error (bad YAML, oversized payload, capped limits exceeded)"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/proxy-logs":{"get":{"tags":["Proxy Logs"],"summary":"Get proxy logs with optional filters and pagination","operationId":"get_proxy_logs","parameters":[{"name":"project_id","in":"query","description":"Filter by project ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"session_id","in":"query","description":"Filter by session ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"visitor_id","in":"query","description":"Filter by visitor ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"start_date","in":"query","description":"Start date for filtering (ISO 8601 format).\n\n**Defaults to 1 hour before `end_date` (or before now) when omitted.**\nThe listing is always time-bounded: an unbounded query would have to\nconsider the entire retention window — 100M+ rows on a busy deployment —\nto return a single page. Pass an explicit `start_date` to widen the\nwindow, up to the configured retention horizon.\n\nThe maximum span between `start_date` and `end_date` is 7 days when\n`project_id` is omitted, or 30 days when a single `project_id` is set —\na project-scoped query is bounded by that project's own row count\nrather than the whole deployment's. A wider request is rejected with a\n400 naming the applicable cap.","required":false,"schema":{"type":["string","null"],"format":"date-time"}},{"name":"end_date","in":"query","description":"End date for filtering (ISO 8601 format). Defaults to now.","required":false,"schema":{"type":["string","null"],"format":"date-time"}},{"name":"method","in":"query","description":"Filter by HTTP method (GET, POST, etc.)","required":false,"schema":{"type":["string","null"]}},{"name":"host","in":"query","description":"Filter by host header","required":false,"schema":{"type":["string","null"]}},{"name":"path","in":"query","description":"Filter by path (supports partial match)","required":false,"schema":{"type":["string","null"]}},{"name":"client_ip","in":"query","description":"Filter by client IP address","required":false,"schema":{"type":["string","null"]}},{"name":"status_code","in":"query","description":"Filter by HTTP status code","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"response_time_min","in":"query","description":"Filter by minimum response time in ms","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"response_time_max","in":"query","description":"Filter by maximum response time in ms","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"routing_status","in":"query","description":"Filter by routing status (routed, no_project, error, pending)","required":false,"schema":{"type":["string","null"]}},{"name":"request_source","in":"query","description":"Filter by request source (proxy, api, console, cli)","required":false,"schema":{"type":["string","null"]}},{"name":"is_system_request","in":"query","description":"Filter by system request flag","required":false,"schema":{"type":["boolean","null"]}},{"name":"user_agent","in":"query","description":"Filter by user agent string (partial match)","required":false,"schema":{"type":["string","null"]}},{"name":"browser","in":"query","description":"Filter by browser name","required":false,"schema":{"type":["string","null"]}},{"name":"operating_system","in":"query","description":"Filter by operating system","required":false,"schema":{"type":["string","null"]}},{"name":"device_type","in":"query","description":"Filter by device type (mobile, desktop, tablet)","required":false,"schema":{"type":["string","null"]}},{"name":"is_bot","in":"query","description":"Filter by bot detection","required":false,"schema":{"type":["boolean","null"]}},{"name":"exclude_bots","in":"query","description":"When `true`, exclude rows flagged as bots while KEEPING rows whose\n`is_bot` is NULL (older rows without detection metadata). This is the\ntri-state complement of `is_bot=false`, which matches only rows\nexplicitly detected as non-bots. `false`/omitted is a no-op.","required":false,"schema":{"type":["boolean","null"]}},{"name":"bot_name","in":"query","description":"Filter by bot name","required":false,"schema":{"type":["string","null"]}},{"name":"ai_provider","in":"query","description":"Filter by AI provider (e.g. `OpenAI`, `Anthropic`, `Perplexity`). Matches\nthe canonical provider returned by the AI agent detector.","required":false,"schema":{"type":["string","null"]}},{"name":"ai_agent","in":"query","description":"Filter by AI agent name (e.g. `GPTBot`, `ChatGPT-User`). Equivalent to\nfiltering `bot_name` against a known AI taxonomy.","required":false,"schema":{"type":["string","null"]}},{"name":"is_ai_agent","in":"query","description":"When `true`, only return requests classified as known AI agents\n(regardless of provider/agent). Mutually compatible with the above.","required":false,"schema":{"type":["boolean","null"]}},{"name":"request_size_min","in":"query","description":"Filter by minimum request size in bytes","required":false,"schema":{"type":["integer","null"],"format":"int64"}},{"name":"request_size_max","in":"query","description":"Filter by maximum request size in bytes","required":false,"schema":{"type":["integer","null"],"format":"int64"}},{"name":"response_size_min","in":"query","description":"Filter by minimum response size in bytes","required":false,"schema":{"type":["integer","null"],"format":"int64"}},{"name":"response_size_max","in":"query","description":"Filter by maximum response size in bytes","required":false,"schema":{"type":["integer","null"],"format":"int64"}},{"name":"cache_status","in":"query","description":"Filter by cache status","required":false,"schema":{"type":["string","null"]}},{"name":"container_id","in":"query","description":"Filter by container ID","required":false,"schema":{"type":["string","null"]}},{"name":"upstream_host","in":"query","description":"Filter by upstream host","required":false,"schema":{"type":["string","null"]}},{"name":"has_error","in":"query","description":"Filter by presence of error message","required":false,"schema":{"type":["boolean","null"]}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (default: 20, max: 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"sort_by","in":"query","description":"Sort by field (default: timestamp)","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","description":"Sort order (asc or desc, default: desc)","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"List of proxy logs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProxyLogsPaginatedResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/ai-agents/known":{"get":{"tags":["Proxy Logs"],"summary":"List every AI agent the detector knows how to classify.","description":"Returned in the same order as the internal taxonomy so the UI can use it as\na stable dropdown.","operationId":"list_known_ai_agents","responses":{"200":{"description":"Known AI agents","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KnownAiAgentsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/request/{request_id}":{"get":{"tags":["Proxy Logs"],"summary":"Get a proxy log by request ID (for tracing)","operationId":"get_proxy_log_by_request_id","parameters":[{"name":"request_id","in":"path","description":"Request ID from pingora","required":true,"schema":{"type":"string"}},{"name":"timestamp","in":"query","description":"Event time of the log row (ISO 8601). When provided, the lookup is\nbounded to the hypertable chunks around this instant instead of\nscanning (and decompressing) the whole retention window. The list\nendpoint already returns this value per row — always pass it when\nnavigating from a list.","required":false,"schema":{"type":["string","null"],"format":"date-time"}}],"responses":{"200":{"description":"Proxy log found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProxyLogResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Proxy log not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/ai-agent-pages":{"get":{"tags":["Proxy Logs"],"summary":"Get the top pages accessed by a specific AI agent over a time window.","description":"Returns page paths ranked by request count, scoped to a single canonical\nagent name (e.g. `ChatGPT-User`). Use `GET /proxy-logs/ai-agents/known` to\nlist all valid agent names. Unknown agent names return an empty items array.","operationId":"get_ai_agent_pages","parameters":[{"name":"agent","in":"query","description":"Canonical agent name to filter by (e.g. `ChatGPT-User`, `ClaudeBot`).\nMust be a name returned by `GET /proxy-logs/ai-agents/known`.","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Filter by project ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601). Defaults to `end_time - 7d`.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-22T00:00:00Z"},{"name":"end_time","in":"query","description":"End time (ISO 8601). Defaults to now.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-29T00:00:00Z"},{"name":"limit","in":"query","description":"Maximum rows to return. Capped at 100 server-side.","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}}],"responses":{"200":{"description":"Pages breakdown for the requested agent","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiAgentPagesResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/ai-agents":{"get":{"tags":["Proxy Logs"],"summary":"Get the per-AI-agent breakdown for a project over a time window.","operationId":"get_ai_agent_breakdown","parameters":[{"name":"project_id","in":"query","description":"Filter by project ID (recommended for per-project analytics).","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601). Defaults to `end_time - 7d`.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-22T00:00:00Z"},{"name":"end_time","in":"query","description":"End time (ISO 8601). Defaults to now.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-29T00:00:00Z"},{"name":"limit","in":"query","description":"Maximum rows to return. Capped at 100 server-side.","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"path","in":"query","description":"Optional exact path filter. Only used by the AI pages breakdown — when\nset, returns the single matching page so callers can ask \"how many AI\nagents hit this page?\".","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"AI agent breakdown","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiAgentBreakdownResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/ai-agents/timeline":{"get":{"tags":["Proxy Logs"],"summary":"Time-bucketed AI-agent request volume, split by provider or agent.","description":"Powers the \"AI agents over time\" stacked chart. Same data source as the AI\nagent breakdown (request logs), just bucketed.","operationId":"get_ai_agent_timeline","parameters":[{"name":"project_id","in":"query","description":"Filter by project ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601). Defaults to `end_time - 7d`.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-22T00:00:00Z"},{"name":"end_time","in":"query","description":"End time (ISO 8601). Defaults to now.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-29T00:00:00Z"},{"name":"group_by","in":"query","description":"Grouping dimension: `provider` (default) or `agent`.","required":false,"schema":{"type":["string","null"]},"example":"provider"},{"name":"bucket","in":"query","description":"Bucket interval override (e.g. `1 hour`, `1 day`). Auto-selected from the\nwindow width when omitted.","required":false,"schema":{"type":["string","null"]},"example":"1 hour"}],"responses":{"200":{"description":"AI agent timeline","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiAgentTimelineResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/ai-pages":{"get":{"tags":["Proxy Logs"],"summary":"Get the top pages crawled by AI agents over a time window.","operationId":"get_ai_page_breakdown","parameters":[{"name":"project_id","in":"query","description":"Filter by project ID (recommended for per-project analytics).","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601). Defaults to `end_time - 7d`.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-22T00:00:00Z"},{"name":"end_time","in":"query","description":"End time (ISO 8601). Defaults to now.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-29T00:00:00Z"},{"name":"limit","in":"query","description":"Maximum rows to return. Capped at 100 server-side.","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"path","in":"query","description":"Optional exact path filter. Only used by the AI pages breakdown — when\nset, returns the single matching page so callers can ask \"how many AI\nagents hit this page?\".","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"AI page breakdown","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiPageBreakdownResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/ai-status":{"get":{"tags":["Proxy Logs"],"summary":"HTTP status-class breakdown for AI-agent traffic — are bots being served\n(2xx) or hitting broken/blocked pages (4xx/5xx)?","operationId":"get_ai_status_breakdown","parameters":[{"name":"project_id","in":"query","description":"Filter by project ID (recommended for per-project analytics).","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601). Defaults to `end_time - 7d`.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-22T00:00:00Z"},{"name":"end_time","in":"query","description":"End time (ISO 8601). Defaults to now.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-29T00:00:00Z"},{"name":"limit","in":"query","description":"Maximum rows to return. Capped at 100 server-side.","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"path","in":"query","description":"Optional exact path filter. Only used by the AI pages breakdown — when\nset, returns the single matching page so callers can ask \"how many AI\nagents hit this page?\".","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"AI status breakdown","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiStatusBreakdownResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/projects-health":{"get":{"tags":["Proxy Logs"],"summary":"Get health summaries for multiple projects (last 1 hour)","operationId":"get_projects_health","parameters":[{"name":"project_ids","in":"query","description":"Comma-separated list of project IDs","required":true,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Optional start time (ISO 8601). Defaults to `end_time - 1h`.","required":false,"schema":{"type":["string","null"]},"example":"2025-10-23T00:00:00Z"},{"name":"end_time","in":"query","description":"Optional end time (ISO 8601). Defaults to now.","required":false,"schema":{"type":["string","null"]},"example":"2025-10-23T23:59:59Z"},{"name":"is_bot","in":"query","description":"Filter by bot detection. Pass `false` to exclude bots, `true` for bots only.","required":false,"schema":{"type":["boolean","null"]}}],"responses":{"200":{"description":"Health summaries per project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectsHealthResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/time-buckets":{"get":{"tags":["Proxy Logs"],"summary":"Get time-bucketed statistics with optional filters","operationId":"get_time_bucket_stats","parameters":[{"name":"start_time","in":"query","description":"Start time (ISO 8601 format)","required":true,"schema":{"type":"string"},"example":"2025-10-23T00:00:00Z"},{"name":"end_time","in":"query","description":"End time (ISO 8601 format)","required":true,"schema":{"type":"string"},"example":"2025-10-23T23:59:59Z"},{"name":"bucket_interval","in":"query","description":"Bucket interval (e.g., \"1 hour\", \"1 day\", \"5 minutes\")","required":false,"schema":{"type":"string"}},{"name":"method","in":"query","description":"Filter by HTTP method","required":false,"schema":{"type":"string"}},{"name":"client_ip","in":"query","description":"Filter by client IP","required":false,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Filter by project ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"host","in":"query","description":"Filter by host","required":false,"schema":{"type":"string"}},{"name":"status_code","in":"query","description":"Filter by status code","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"status_code_class","in":"query","description":"Filter by status code class (e.g. \"2xx\", \"3xx\", \"4xx\", \"5xx\")","required":false,"schema":{"type":"string"}},{"name":"routing_status","in":"query","description":"Filter by routing status","required":false,"schema":{"type":"string"}},{"name":"request_source","in":"query","description":"Filter by request source","required":false,"schema":{"type":"string"}},{"name":"is_bot","in":"query","description":"Filter by bot detection","required":false,"schema":{"type":"boolean"}},{"name":"device_type","in":"query","description":"Filter by device type","required":false,"schema":{"type":"string"}},{"name":"has_project","in":"query","description":"When true, only count requests that matched a project\n(project_id IS NOT NULL). Makes chart totals line up with the\nper-project health cards.","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Time-bucketed statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TimeBucketStatsResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/today":{"get":{"tags":["Proxy Logs"],"summary":"Get today's request count with optional filters","operationId":"get_today_stats","parameters":[{"name":"method","in":"query","description":"Filter by HTTP method","required":false,"schema":{"type":["string","null"]}},{"name":"client_ip","in":"query","description":"Filter by client IP","required":false,"schema":{"type":["string","null"]}},{"name":"project_id","in":"query","description":"Filter by project ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"host","in":"query","description":"Filter by host","required":false,"schema":{"type":["string","null"]}},{"name":"status_code","in":"query","description":"Filter by status code","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"status_code_class","in":"query","description":"Filter by status code class (e.g. \"2xx\", \"3xx\", \"4xx\", \"5xx\")","required":false,"schema":{"type":["string","null"]}},{"name":"routing_status","in":"query","description":"Filter by routing status","required":false,"schema":{"type":["string","null"]}},{"name":"request_source","in":"query","description":"Filter by request source","required":false,"schema":{"type":["string","null"]}},{"name":"is_bot","in":"query","description":"Filter by bot detection","required":false,"schema":{"type":["boolean","null"]}},{"name":"device_type","in":"query","description":"Filter by device type","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"Today's request count","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TodayStatsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/{id}":{"get":{"tags":["Proxy Logs"],"summary":"Get a single proxy log by ID","operationId":"get_proxy_log_by_id","parameters":[{"name":"id","in":"path","description":"Proxy log ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"timestamp","in":"query","description":"Event time of the log row (ISO 8601). When provided, the lookup is\nbounded to the hypertable chunks around this instant instead of\nscanning (and decompressing) the whole retention window. The list\nendpoint already returns this value per row — always pass it when\nnavigating from a list.","required":false,"schema":{"type":["string","null"],"format":"date-time"}}],"responses":{"200":{"description":"Proxy log found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProxyLogResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Proxy log not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/repositories":{"get":{"tags":["Git Providers"],"summary":"List synced repositories with advanced filtering","description":"Lists repositories that have been synced to the database with filtering options.\nThis provides fast access to repository metadata with filtering by connection, search, and other criteria.","operationId":"list_synced_repositories","parameters":[{"name":"page","in":"query","description":"Page number for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"sort","in":"query","description":"Sort field (name, created_at, updated_at, stars, watchers, size, issues)","required":false,"schema":{"type":"string"}},{"name":"direction","in":"query","description":"Sort direction (asc, desc)","required":false,"schema":{"type":"string"}},{"name":"search","in":"query","description":"Search term to filter repositories","required":false,"schema":{"type":"string"}},{"name":"owner","in":"query","description":"Filter by repository owner","required":false,"schema":{"type":"string"}},{"name":"language","in":"query","description":"Filter by programming language","required":false,"schema":{"type":"string"}},{"name":"private","in":"query","description":"Filter by private status (true/false)","required":false,"schema":{"type":"boolean"}},{"name":"git_provider_connection_id","in":"query","description":"Filter by git provider connection ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of synced repositories","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositoryListResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repositories/{owner}/{name}":{"get":{"tags":["Git Providers"],"summary":"Get repository by owner and name from any connection","operationId":"get_repository_by_name","parameters":[{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}},{"name":"connection_id","in":"query","description":"Optional specific connection ID to search","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Repository found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositoryResponse"}}}},"404":{"description":"Repository not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repositories/{owner}/{name}/all":{"get":{"tags":["Git Providers"],"summary":"Get all repositories with same owner/name from all git providers","operationId":"get_all_repositories_by_name","parameters":[{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Repositories found from all providers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RepositoryResponse"}}}}},"404":{"description":"No repositories found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repositories/{owner}/{name}/preset":{"get":{"tags":["Git Providers"],"summary":"Get repository preset by owner and name","operationId":"get_repository_preset_by_name","parameters":[{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}},{"name":"branch","in":"query","description":"Git branch to check (defaults to repository's default branch)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Repository preset calculated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositoryPresetResponse"}}}},"404":{"description":"Repository not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repositories/{owner}/{repo}/branches":{"get":{"tags":["Repositories"],"summary":"Get repository branches","operationId":"get_repository_branches","parameters":[{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"repo","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}},{"name":"connection_id","in":"query","description":"Git provider connection ID (required when multiple connections have the same repo)","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"fresh","in":"query","description":"Force fetch fresh data, bypassing cache (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of branches","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BranchListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Repository not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repositories/{owner}/{repo}/tags":{"get":{"tags":["Repositories"],"summary":"Get repository tags","operationId":"get_repository_tags","parameters":[{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"repo","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}},{"name":"connection_id","in":"query","description":"Git provider connection ID (required when multiple connections have the same repo)","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"fresh","in":"query","description":"Force fetch fresh data, bypassing cache (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of tags","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TagListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Repository not found"},"429":{"description":"Fresh tag lookup rate limit exceeded"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repositories/{repository_id}/preset/live":{"get":{"tags":["Git Providers"],"operationId":"get_repository_preset_live","parameters":[{"name":"repository_id","in":"path","description":"Repository ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"branch","in":"query","description":"Git branch to check (defaults to repository's default branch)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Repository presets calculated successfully - includes root preset and projects in subdirectories","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositoryPresetResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"The git provider rejected the stored credential - the connection must be re-authorized"},"404":{"description":"Repository not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repository/{repository_id}":{"get":{"tags":["Git Providers"],"summary":"Get repository by ID","operationId":"get_repository_by_id","parameters":[{"name":"repository_id","in":"path","description":"Repository ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Repository found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositoryResponse"}}}},"404":{"description":"Repository not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repository/{repository_id}/branches":{"get":{"tags":["Repositories"],"summary":"Get repository branches by repository ID","operationId":"get_branches_by_repository_id","parameters":[{"name":"repository_id","in":"path","description":"Repository ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"fresh","in":"query","description":"Force fetch fresh data, bypassing cache (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of branches","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BranchListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Repository not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repository/{repository_id}/commits":{"get":{"tags":["Repositories"],"summary":"List recent commits for a repository branch","operationId":"list_commits_by_repository_id","parameters":[{"name":"repository_id","in":"path","description":"Repository ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"branch","in":"query","description":"Branch name to list commits for","required":true,"schema":{"type":"string"}},{"name":"per_page","in":"query","description":"Number of commits to return (default: 20, max: 100)","required":false,"schema":{"type":["integer","null"],"format":"int32","minimum":0}}],"responses":{"200":{"description":"List of commits","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommitListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Repository not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repository/{repository_id}/commits/{commit_sha}":{"get":{"tags":["Repositories"],"summary":"Check if a commit exists in a repository","operationId":"check_commit_exists","parameters":[{"name":"repository_id","in":"path","description":"Repository ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"commit_sha","in":"path","description":"Commit SHA to check","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Commit existence check result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommitExistsResponse"}}}},"400":{"description":"Invalid commit SHA"},"401":{"description":"Unauthorized"},"404":{"description":"Repository not found"},"429":{"description":"Commit lookup rate limit exceeded"},"500":{"description":"Internal server error"},"502":{"description":"Git provider request failed"}},"security":[{"bearer_auth":[]}]}},"/repository/{repository_id}/tags":{"get":{"tags":["Repositories"],"summary":"Get repository tags by repository ID","operationId":"get_tags_by_repository_id","parameters":[{"name":"repository_id","in":"path","description":"Repository ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"fresh","in":"query","description":"Force fetch fresh data, bypassing cache (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of tags","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TagListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Repository not found"},"429":{"description":"Fresh tag lookup rate limit exceeded"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/restore-runs/{id}":{"get":{"tags":["Restore"],"operationId":"get_restore_run","parameters":[{"name":"id","in":"path","description":"Restore run id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Restore run progress","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RestoreRunView"}}}},"404":{"description":"Restore run not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/revenue/events":{"get":{"tags":["Revenue"],"summary":"Org-wide revenue events across every project. Powers the revenue\ntransactions page. Supports filtering by project, date range, and\nevent type.","operationId":"revenue_global_events","parameters":[{"name":"project_id","in":"query","description":"Filter to a single project","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"from","in":"query","description":"Lower bound (inclusive), ISO-8601","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","description":"Upper bound (inclusive), ISO-8601","required":false,"schema":{"type":"string"}},{"name":"event_types","in":"query","description":"Comma-separated event types (e.g. `invoice.paid,charge.succeeded`)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max rows, default 100, max 500","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GlobalRecentEventResponse"}}}}}},"security":[{"bearer_auth":[]}]}},"/revenue/metrics/global-mrr":{"get":{"tags":["Revenue"],"summary":"Org-wide MRR total, summed across every project in the install.\nPowers the single-number MRR card on the main dashboard.","operationId":"revenue_metrics_global_mrr","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GlobalMrrResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/revenue/metrics/global-summary":{"get":{"tags":["Revenue"],"summary":"Org-wide revenue summary: MRR, paid cash (30d + all-time), refunds,\nactive subscriptions/customers, and transaction count. Powers the\nheader on the Revenue transactions page.","operationId":"revenue_metrics_global_summary","parameters":[{"name":"currency","in":"query","description":"ISO-4217 currency code, default USD","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GlobalRevenueSummaryResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/revenue/providers":{"get":{"tags":["Revenue"],"summary":"List registered providers (what the UI needs to render the \"Connect\"\ndropdown + its wizard instructions).","operationId":"revenue_list_providers","responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProviderDescriptor"}}}}}},"security":[{"bearer_auth":[]}]}},"/session-replays":{"get":{"tags":["Analytics"],"summary":"Get session replays for a project","operationId":"get_project_session_replays","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-based)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Items per page","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Session replays retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetProjectSessionReplaysResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/sessions/{session_id}/events":{"get":{"tags":["Events"],"summary":"Get events for a specific session","operationId":"get_session_events","parameters":[{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved session events","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalyticsSessionEventsResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Session not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings":{"get":{"tags":["Settings"],"summary":"Get application settings","operationId":"get_settings","responses":{"200":{"description":"Application settings with masked sensitive fields","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppSettingsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Settings"],"summary":"Update application settings","operationId":"update_settings","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppSettings"}}},"required":true},"responses":{"200":{"description":"Settings updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SettingsUpdateResponse"}}}},"400":{"description":"Bad request - invalid settings"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/agent-token":{"post":{"tags":["Agents"],"summary":"Save an encrypted AI provider token for use in sandbox containers.","operationId":"save_agent_token","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveAgentTokenRequest"}}},"required":true},"responses":{"200":{"description":"Token encrypted and persisted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveAgentTokenResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Encryption or database error"}},"security":[{"bearer_auth":[]}]}},"/settings/ai-providers":{"get":{"tags":["Agents"],"summary":"List the AI provider catalog. Includes per-provider \"is a credential\nconfigured?\" so the settings UI can render configured/not-configured\nbadges without leaking the encrypted credential.","operationId":"list_ai_providers","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderCatalogResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/settings/ai-providers/{provider_id}":{"patch":{"tags":["Agents"],"summary":"Update provider-scoped settings without touching the saved credential.\nToday that means just `default_model`; future per-provider settings\n(base URL overrides, request headers, etc.) can land here too without\nchanging the shape of `save_credential`.","operationId":"update_ai_provider","parameters":[{"name":"provider_id","in":"path","description":"AI provider ID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAiProviderRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAiProviderResponse"}}}},"400":{"description":"Unknown provider"},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/settings/ai-providers/{provider_id}/activate":{"post":{"tags":["Agents"],"summary":"Activate a provider as the platform-wide default. Refuses to activate a\nprovider that doesn't have a credential saved yet — the UI enforces the\nsame rule on the button, but we re-check server-side so a stale tab\ncan't bypass it.","operationId":"activate_ai_provider","parameters":[{"name":"provider_id","in":"path","description":"AI provider ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivateProviderResponse"}}}},"400":{"description":"Provider not configured"},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/settings/ai-providers/{provider_id}/credential":{"post":{"tags":["Agents"],"summary":"Save (or replace) a provider's credential. The credential is encrypted\nwith `EncryptionService` and stored inside\n`agent_sandbox.providers[provider_id].credentials_encrypted`.","description":"The plaintext shape depends on the flavor's `credential_format`:\n - `ApiKey` / `OauthToken`: the key/token string.\n - `ConfigFile`: the full file body (e.g. OpenCode's `auth.json`).","operationId":"save_ai_provider_credential","parameters":[{"name":"provider_id","in":"path","description":"AI provider ID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveCredentialRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveCredentialResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/settings/disk-status":{"get":{"tags":["Settings"],"summary":"Get current disk usage for the control-plane server","description":"Returns live disk usage for the monitored path along with any disks that\nmeet or exceed the configured alert threshold. Read-only — does not send\nnotifications. Used by the dashboard to surface a low-disk-space warning.","operationId":"get_disk_status","responses":{"200":{"description":"Current disk usage and threshold alerts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiskSpaceCheckResult"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/enrollment-tokens":{"get":{"tags":["Settings"],"summary":"List currently-valid node enrollment tokens (hashes elided).","operationId":"list_enrollment_tokens","responses":{"200":{"description":"Active enrollment tokens","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnrollmentTokenListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Settings"],"summary":"Mint a short-lived, single-use node enrollment token.","operationId":"mint_enrollment_token","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MintEnrollmentTokenRequest"}}},"required":true},"responses":{"200":{"description":"Enrollment token minted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MintEnrollmentTokenResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/enrollment-tokens/{id}":{"delete":{"tags":["Settings"],"summary":"Revoke a node enrollment token by id.","operationId":"revoke_enrollment_token","parameters":[{"name":"id","in":"path","description":"Enrollment token id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Enrollment token revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SettingsUpdateResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Enrollment token not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/join-token":{"delete":{"tags":["Settings"],"summary":"Revoke the current join token","description":"Removes the stored join token hash, allowing any node to register\n(if no other authentication is in place).","operationId":"revoke_join_token","responses":{"200":{"description":"Join token revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SettingsUpdateResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/join-token/generate":{"post":{"tags":["Settings"],"summary":"Generate a new join token for multi-node cluster registration","description":"Creates a random 32-byte hex token, stores the SHA-256 hash in settings,\nand returns the plaintext exactly once. If a token already exists, it is replaced.","operationId":"generate_join_token","responses":{"200":{"description":"Join token generated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateJoinTokenResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/join-token/status":{"get":{"tags":["Settings"],"summary":"Check whether a join token is currently configured","operationId":"get_join_token_status","responses":{"200":{"description":"Join token status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JoinTokenStatusResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/mcp-servers":{"get":{"tags":["Agents"],"operationId":"list_global_mcps","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListMcpsResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Agents"],"operationId":"create_global_mcp","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMcpRequest"}}},"required":true},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpDefinitionResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/settings/mcp-servers/{slug}":{"get":{"tags":["Agents"],"operationId":"get_global_mcp","parameters":[{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"MCP server not found"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Agents"],"operationId":"update_global_mcp","parameters":[{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMcpRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"MCP server not found"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Agents"],"operationId":"delete_global_mcp","parameters":[{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"MCP server deleted"},"401":{"description":"Unauthorized"},"404":{"description":"MCP server not found"}},"security":[{"bearer_auth":[]}]}},"/settings/mcp-servers/{slug}/config/{field}":{"get":{"tags":["Agents"],"operationId":"reveal_global_mcp_config","parameters":[{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}},{"name":"field","in":"path","description":"Sensitive field path, such as url or env.API_TOKEN","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SensitiveMcpConfigValueResponse"}}}},"400":{"description":"Field is not revealable"},"401":{"description":"Unauthorized"},"403":{"description":"Missing secrets:read permission"},"404":{"description":"MCP server or field not found"},"500":{"description":"Configuration read or audit failed"}},"security":[{"bearer_auth":[]}]}},"/settings/routes/refresh":{"post":{"tags":["Settings"],"summary":"Manually refresh the proxy route table","description":"Reloads all routes from the database into the in-memory proxy cache.\nUseful as a workaround when routes are out of sync.","operationId":"refresh_route_table","responses":{"200":{"description":"Route table refreshed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteRefreshResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/sandbox-rebuild":{"post":{"tags":["Agents"],"operationId":"rebuild_sandbox_image","responses":{"200":{"description":"Server-Sent Events stream of rebuild progress; final event `{\"type\":\"done\",\"success\":bool,...}`","content":{"text/event-stream":{}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/settings/sandbox-status":{"get":{"tags":["Agents"],"operationId":"get_global_sandbox_status","responses":{"200":{"description":"Global sandbox readiness for the settings page","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxStatusResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/settings/secrets":{"get":{"tags":["Secrets"],"operationId":"list_secrets","responses":{"200":{"description":"List of global agent secrets","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListSecretsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Secrets"],"operationId":"upsert_secret","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertSecretRequest"}}},"required":true},"responses":{"201":{"description":"Secret created/updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SecretResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/settings/secrets/{name}":{"delete":{"tags":["Secrets"],"operationId":"delete_secret","parameters":[{"name":"name","in":"path","description":"Secret name","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Secret deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Secret not found"}},"security":[{"bearer_auth":[]}]}},"/settings/skills":{"get":{"tags":["Agents"],"operationId":"list_global_skills","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListSkillsResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Agents"],"operationId":"create_global_skill","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSkillRequest"}}},"required":true},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/settings/skills/upload":{"post":{"tags":["Agents"],"summary":"Upload a skill with an archive (tar.gz) — global.","operationId":"upload_global_skill","requestBody":{"content":{"multipart/form-data":{"schema":{"type":"string"}}},"required":true},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/settings/skills/{slug}":{"get":{"tags":["Agents"],"operationId":"get_global_skill","parameters":[{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Agents"],"operationId":"update_global_skill","parameters":[{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSkillRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Agents"],"operationId":"delete_global_skill","parameters":[{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Skill deleted"},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found"}},"security":[{"bearer_auth":[]}]}},"/settings/skills/{slug}/archive":{"get":{"tags":["Agents"],"summary":"Download a skill's archive (tar.gz) — global.","operationId":"download_global_skill_archive","parameters":[{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Skill archive tar.gz","content":{"application/gzip":{}}},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found or has no archive"}},"security":[{"bearer_auth":[]}]}},"/settings/update":{"get":{"tags":["Settings"],"summary":"Report whether a release update can be applied from the console.","operationId":"get_update_capability","responses":{"200":{"description":"Self-update capability for this install","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCapabilityResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Settings"],"summary":"Install a release and restart the server.","description":"Returns as soon as the attempt is accepted: the download and swap run in the\nbackground and the process then exits so its supervisor restarts it on the\nnew binary. Poll `GET /settings/update` for progress — after the restart,\n`last_attempt` carries the outcome.","operationId":"start_update","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartUpdateRequest"}}},"required":true},"responses":{"202":{"description":"Update accepted; the server will restart","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartUpdateResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"409":{"description":"Update unavailable or already running","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"501":{"description":"This process cannot apply updates","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/settings/update-status":{"get":{"tags":["Settings"],"summary":"Report whether a newer temps release is available for this install.","operationId":"get_update_status","responses":{"200":{"description":"Release update status for this install","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateStatusResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/teams":{"get":{"tags":["Teams"],"operationId":"list_teams","parameters":[{"name":"page","in":"query","description":"1-indexed page","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"default 20, max 100","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Paginated teams","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Teams"],"operationId":"create_team","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTeamRequest"}}},"required":true},"responses":{"201":{"description":"Team created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamResponse"}}}},"400":{"description":"Validation error"},"403":{"description":"Insufficient permissions"},"409":{"description":"Slug already taken"}},"security":[{"bearer_auth":[]}]}},"/teams/{team_id}":{"get":{"tags":["Teams"],"operationId":"get_team","parameters":[{"name":"team_id","in":"path","description":"Team id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Team","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamResponse"}}}},"403":{"description":"Insufficient permissions"},"404":{"description":"Team not found"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Teams"],"operationId":"delete_team","parameters":[{"name":"team_id","in":"path","description":"Team id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Team deleted"},"403":{"description":"Insufficient permissions"},"404":{"description":"Team not found"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Teams"],"operationId":"update_team","parameters":[{"name":"team_id","in":"path","description":"Team id","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTeamRequest"}}},"required":true},"responses":{"200":{"description":"Updated team","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamResponse"}}}},"400":{"description":"Validation error"},"403":{"description":"Insufficient permissions"},"404":{"description":"Team not found"}},"security":[{"bearer_auth":[]}]}},"/teams/{team_id}/members":{"get":{"tags":["Teams"],"operationId":"list_team_members","parameters":[{"name":"team_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Members","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TeamMemberResponse"}}}}},"403":{"description":"Insufficient permissions"},"404":{"description":"Team not found"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Teams"],"operationId":"add_team_member","parameters":[{"name":"team_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTeamMemberRequest"}}},"required":true},"responses":{"201":{"description":"Member added","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamMemberResponse"}}}},"403":{"description":"Insufficient permissions"},"404":{"description":"Team not found"},"409":{"description":"User already a member"}},"security":[{"bearer_auth":[]}]}},"/teams/{team_id}/members/{user_id}":{"delete":{"tags":["Teams"],"operationId":"remove_team_member","parameters":[{"name":"team_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"user_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Member removed"},"403":{"description":"Insufficient permissions"},"404":{"description":"Member not found"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Teams"],"operationId":"update_team_member_role","parameters":[{"name":"team_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"user_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMemberRoleRequest"}}},"required":true},"responses":{"200":{"description":"Updated membership","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamMemberResponse"}}}},"403":{"description":"Insufficient permissions"},"404":{"description":"Member not found"}},"security":[{"bearer_auth":[]}]}},"/teams/{team_id}/projects":{"get":{"tags":["Teams"],"operationId":"list_team_projects","parameters":[{"name":"team_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Projects this team has access to","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProjectAccessResponse"}}}}},"403":{"description":"Insufficient permissions"},"404":{"description":"Team not found"}},"security":[{"bearer_auth":[]}]}},"/templates":{"get":{"tags":["Templates"],"summary":"List all available templates","description":"Returns a list of all public templates, optionally filtered by tag or featured status.","operationId":"list_project_templates","parameters":[{"name":"tag","in":"query","description":"Filter templates by tag","required":false,"schema":{"type":"string"}},{"name":"featured","in":"query","description":"Only return featured templates","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of templates","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListTemplatesResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/templates/tags":{"get":{"tags":["Templates"],"summary":"List all available template tags","description":"Returns a list of all unique tags used by public templates.","operationId":"list_project_template_tags","responses":{"200":{"description":"List of tags","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListTagsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/templates/{slug}":{"get":{"tags":["Templates"],"summary":"Get a specific template by slug","description":"Returns detailed information about a single template.","operationId":"get_project_template","parameters":[{"name":"slug","in":"path","description":"Template slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Template details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TemplateResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Template not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/user/me":{"get":{"tags":["Authentication"],"operationId":"get_current_user","responses":{"200":{"description":"Successfully retrieved user information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"session_token":[]}]}},"/users":{"get":{"tags":["Users"],"operationId":"list_users","parameters":[{"name":"include_deleted","in":"query","description":"Include deleted users in the response","required":true,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List all users with their roles","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RouteUserWithRoles"}}}}},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Users"],"summary":"Create a new user with roles","operationId":"create_user","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUserRequest"}}},"required":true},"responses":{"201":{"description":"User created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteUserWithRoles"}}}},"400":{"description":"Invalid input"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/me":{"patch":{"tags":["Users"],"summary":"Update current user's information","operationId":"update_self","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSelfRequest"}}},"required":true},"responses":{"200":{"description":"User updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteUserWithRoles"}}}},"400":{"description":"Invalid input"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/me/mfa":{"delete":{"tags":["Users"],"operationId":"disable_mfa","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DisableMfaRequest"}}},"required":true},"responses":{"204":{"description":"MFA disabled"},"400":{"description":"Invalid verification code"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/me/mfa/setup":{"post":{"tags":["Users"],"operationId":"setup_mfa","responses":{"200":{"description":"MFA setup data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MfaSetupResponse"}}}},"401":{"description":"Unauthorized"},"409":{"description":"MFA is already enabled; verify and disable it before re-enrollment"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/me/mfa/verify":{"post":{"tags":["Users"],"operationId":"verify_and_enable_mfa","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyMfaRequest"}}},"required":true},"responses":{"204":{"description":"MFA verified and enabled"},"400":{"description":"Invalid code"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/me/password":{"post":{"tags":["Users"],"operationId":"change_password_self","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangePasswordRequest"}}},"required":true},"responses":{"204":{"description":"Password updated"},"400":{"description":"Validation error (weak password, same as current, MFA missing)"},"401":{"description":"Current password incorrect or MFA code invalid"},"403":{"description":"Account has no password set (SSO only)"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/{user_id}":{"delete":{"tags":["Users"],"summary":"Delete a user","operationId":"delete_user","parameters":[{"name":"user_id","in":"path","description":"User ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"User deleted successfully"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden - Cannot delete yourself or non-admin attempt"},"404":{"description":"User not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Users"],"summary":"Update user information (admin only)","operationId":"update_user","parameters":[{"name":"user_id","in":"path","description":"User ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUserRequest"}}},"required":true},"responses":{"200":{"description":"User updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteUserWithRoles"}}}},"400":{"description":"Invalid input"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden - Non-admin attempt"},"404":{"description":"User not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/{user_id}/restore":{"post":{"tags":["Users"],"operationId":"restore_user","parameters":[{"name":"user_id","in":"path","description":"User ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"User restored successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteUserWithRoles"}}}},"400":{"description":"User is not deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden - Non-admin attempt"},"404":{"description":"User not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/{user_id}/roles":{"post":{"tags":["Users"],"operationId":"assign_role","parameters":[{"name":"user_id","in":"path","description":"User ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssignRoleRequest"}}},"required":true},"responses":{"200":{"description":"Role assigned successfully"},"400":{"description":"Invalid role type"},"401":{"description":"Unauthorized"},"403":{"description":"Admin role required or self-modification forbidden"},"404":{"description":"User or role not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/{user_id}/roles/{role_type}":{"delete":{"tags":["Users"],"operationId":"remove_role","parameters":[{"name":"user_id","in":"path","description":"User ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"role_type","in":"path","description":"Role type to remove","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Role removed successfully"},"400":{"description":"Invalid role type"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden - Cannot modify own roles or non-admin attempt"},"404":{"description":"User or role not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes":{"get":{"tags":["Sandboxes"],"operationId":"list_sandboxes","parameters":[{"name":"page","in":"query","description":"Page (1-indexed)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page (default 20, max 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List sandboxes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListSandboxesResponse"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Sandboxes"],"operationId":"create_sandbox","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSandboxBody"}}},"required":true},"responses":{"201":{"description":"Sandbox created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/rootfs":{"get":{"tags":["Sandboxes"],"summary":"Inspect rootfs storage: the Firecracker digest-keyed cache (with which\nsandboxes reference each entry) and per-VM disks. Empty on Docker-only\nhosts. Admin/read scope — this exposes host storage layout.","operationId":"rootfs_report","responses":{"200":{"description":"Rootfs storage report"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/rootfs/gc":{"post":{"tags":["Sandboxes"],"summary":"Reclaim rootfs cache entries not backing any live sandbox. Idempotent;\nsafe to call any time (live VMs hold their own per-VM disks).","operationId":"rootfs_gc","responses":{"200":{"description":"Reclaimed cache entries"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}":{"get":{"tags":["Sandboxes"],"operationId":"get_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sandbox details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"404":{"description":"Not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/cmd":{"post":{"tags":["Sandboxes"],"summary":"Run a command inside the sandbox (`@vercel/sandbox`-compatible).","description":"`wait=false` (default) returns `{ command: {..., exitCode: null} }`\nimmediately once the background task is spawned.\n\n`wait=true` streams `application/x-ndjson`: the first line is the\nrunning envelope, the second is the finished envelope with `exitCode`.","operationId":"cmd","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CmdBody"}}},"required":true},"responses":{"200":{"description":"Command started (wait=false) or finished (wait=true)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CmdResponse"}}}},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/cmd/{cmd_id}":{"get":{"tags":["Sandboxes"],"operationId":"get_cmd","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"cmd_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Command snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CmdResponse"}}}},"404":{"description":"Sandbox or command not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/cmd/{cmd_id}/logs":{"get":{"tags":["Sandboxes"],"summary":"Stream a command's stdout/stderr as `application/x-ndjson`\n(`@vercel/sandbox`-compatible). Each line is either\n`{stream:\"stdout\"|\"stderr\", data:\"...\"}` or\n`{stream:\"error\", data:{code, message}}`.","operationId":"cmd_logs","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"cmd_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"NDJSON stream of log events"},"404":{"description":"Sandbox or command not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/destroy":{"post":{"tags":["Sandboxes"],"operationId":"destroy_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Sandbox destroyed (alias for `/stop` with an explicit verb)"},"404":{"description":"Not found"},"409":{"description":"Sandbox belongs to an active agent run — stop the run instead"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/domain":{"get":{"tags":["Sandboxes"],"operationId":"domain","parameters":[{"name":"port","in":"query","description":"Port inside the sandbox (1..=65535)","required":true,"schema":{"type":"integer","format":"int32","minimum":0}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Preview URL for the port","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxDomainResponse"}}}},"400":{"description":"Invalid port"},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/events":{"get":{"tags":["Sandboxes"],"summary":"The operations timeline for a sandbox (lifecycle events only — never\nshell/exec activity), newest first.","operationId":"list_events","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Operations timeline","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxEventsResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/exec":{"post":{"tags":["Sandboxes"],"operationId":"exec","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecBody"}}},"required":true},"responses":{"200":{"description":"Command finished (non-zero exit is NOT an error)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecResponse"}}}},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/exec-detached":{"post":{"tags":["Sandboxes"],"operationId":"exec_detached","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecBody"}}},"required":true},"responses":{"202":{"description":"Command accepted; poll /jobs/{job_id}","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecDetachedResponse"}}}},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/extend-timeout":{"post":{"tags":["Sandboxes"],"operationId":"extend_timeout","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExtendTimeoutBody"}}},"required":true},"responses":{"200":{"description":"Timeout extended","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"400":{"description":"Validation error"},"404":{"description":"Not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/fs/mkdir":{"post":{"tags":["Sandboxes"],"operationId":"mkdir","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MkdirBody"}}},"required":true},"responses":{"204":{"description":"Directory created (or already existed)"},"400":{"description":"Validation error"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/fs/read":{"get":{"tags":["Sandboxes"],"operationId":"read_file","parameters":[{"name":"path","in":"query","description":"Absolute file path inside the sandbox","required":true,"schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"File contents (base64)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReadFileResponse"}}}},"400":{"description":"Validation error"},"404":{"description":"Sandbox or file not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/fs/stat":{"get":{"tags":["Sandboxes"],"operationId":"stat_path","parameters":[{"name":"path","in":"query","description":"Absolute path inside the sandbox","required":true,"schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Stat info (exists=false when missing — not an error)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatResponse"}}}},"400":{"description":"Validation error"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/fs/write":{"post":{"tags":["Sandboxes"],"summary":"Write a file into the sandbox. Accepts two body shapes — the SDK\npicks one based on `Content-Type`:","description":"- **`application/json`** (temps-native): `{path, contents_b64, mode}`\n — one file, base64-encoded.\n- **`application/gzip`** (`@vercel/sandbox`): a gzipped tarball of\n one-or-more entries, with the target extract dir carried in the\n `x-cwd` header. The SDK's `writeFile` and `writeFiles` both post\n here; they differ only in how many entries the tarball contains.\n\nWhy merge them on one route: the SDK is hardcoded to\n`POST /fs/write`, so splitting tar uploads onto a separate path would\nforce us to break SDK compat. Instead we dispatch on Content-Type,\npreserve JSON for native callers, and add tar for SDK callers.","operationId":"write_file","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WriteFileBody"}}},"required":true},"responses":{"204":{"description":"File(s) written"},"400":{"description":"Validation error or invalid base64"},"404":{"description":"Sandbox not found"},"415":{"description":"Unsupported Content-Type (expected application/json or application/gzip)"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/fs/write-batch":{"post":{"tags":["Sandboxes"],"summary":"Batch-write multiple files in a single request. Mirrors\n`@vercel/sandbox` `writeFiles()`. Semantics are fail-fast: if any\nfile errors, previously-written entries are left in place and the\nerror describes which file broke.","operationId":"write_files","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WriteFilesBody"}}},"required":true},"responses":{"200":{"description":"All files written","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WriteFilesResponse"}}}},"400":{"description":"Validation error or invalid base64"},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/jobs":{"get":{"tags":["Sandboxes"],"operationId":"list_jobs","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Detached jobs for this sandbox","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListJobsResponse"}}}},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/jobs/{job_id}":{"get":{"tags":["Sandboxes"],"operationId":"job_status","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"job_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Job status snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobStatusResponse"}}}},"404":{"description":"Sandbox or job not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/jobs/{job_id}/kill":{"post":{"tags":["Sandboxes"],"summary":"Terminate a detached job. Aborts the server-side tracking task and\nsends SIGTERM (or SIGKILL if `force=true`) to any matching processes\ninside the sandbox container. Returns 204 on success; 404 if the\nsandbox or job is unknown.","operationId":"kill_job","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"job_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KillJobBody"}}},"required":true},"responses":{"204":{"description":"Job killed"},"404":{"description":"Sandbox or job not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/jobs/{job_id}/logs":{"get":{"tags":["Sandboxes"],"summary":"SSE endpoint streaming each stdout/stderr line from a detached job\nas it's produced. Mirrors the `Command.logs()` async iterator shape\non `@vercel/sandbox` — events carry `{ stream, data }`.","description":"Late subscribers only see events produced after they connect. The\nJobState snapshot (`GET /jobs/{job_id}`) covers the history.\n\nA \"done\" sentinel event fires when the broadcast channel closes\n(the exec task has exited and dropped the sender), signalling\ncallers they can stop reading.","operationId":"job_logs","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"job_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"SSE stream of log events"},"404":{"description":"Sandbox or job not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/pause":{"post":{"tags":["Sandboxes"],"operationId":"pause_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sandbox paused (container stopped, state preserved)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"404":{"description":"Not found"},"409":{"description":"Sandbox is in an incompatible state (e.g. already destroyed)"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/preview-link":{"post":{"tags":["Sandboxes"],"summary":"Mint a shareable link to a sandbox preview.","description":"`GET /domain` returns the bare preview URL, which is useless to anyone who\ndoes not already hold the sandbox's preview password — so sharing a\nprotected preview meant sharing that password, which is the same secret for\nevery recipient and can only be withdrawn by rotating it for all of them.\n\nThis returns the same URL carrying a short-lived, sandbox-scoped grant. The\nrecipient's browser exchanges it for the ordinary preview cookie and lands\non `path`. The grant never reaches the sandbox, so preview application code\ncannot read it and re-share it.\n\nAnyone holding the returned URL can view the preview until it expires;\nthere is no per-link revocation short of rotating the preview password.","operationId":"sandbox_create_preview_link","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreviewShareLinkBody"}}},"required":true},"responses":{"200":{"description":"Shareable preview link","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreviewShareLinkResponse"}}}},"400":{"description":"Invalid port"},"404":{"description":"Sandbox not found"},"409":{"description":"Sandbox has no preview password"},"500":{"description":"Preview grant minting failed"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/preview-password":{"put":{"tags":["Sandboxes"],"operationId":"set_preview_password","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetPreviewPasswordBody"}}},"required":true},"responses":{"200":{"description":"Preview password set or rotated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetPreviewPasswordResponse"}}}},"400":{"description":"Password too short or too long"},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Sandboxes"],"operationId":"clear_preview_password","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Preview password removed (sandbox is now URL-only protected)"},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/resize":{"post":{"tags":["Sandboxes"],"summary":"Grow a Firecracker sandbox's root disk. Offline resize — the VM reboots\n(filesystem/data persist) rather than resizing fully live.","operationId":"resize_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResizeSandboxBody"}}},"required":true},"responses":{"200":{"description":"Resized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"400":{"description":"Invalid size or unsupported backend"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/restart":{"post":{"tags":["Sandboxes"],"operationId":"restart_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sandbox container restarted in place","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"404":{"description":"Not found"},"409":{"description":"Sandbox is stopped (use /resume) or already destroyed"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/resume":{"post":{"tags":["Sandboxes"],"operationId":"resume_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sandbox resumed; expires_at refreshed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"404":{"description":"Not found"},"409":{"description":"Sandbox is not in a resumable state"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/source":{"post":{"tags":["Sandboxes"],"operationId":"source_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceBody"}}},"required":true},"responses":{"200":{"description":"Source content seeded into the sandbox work dir","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"400":{"description":"Validation error (embedded creds, conflicting fields, etc.)"},"404":{"description":"Sandbox not found"},"409":{"description":"Sandbox is not running"},"500":{"description":"Source seed failed inside sandbox"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/stop":{"post":{"tags":["Sandboxes"],"operationId":"stop_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Sandbox stopped and destroyed"},"404":{"description":"Not found"},"409":{"description":"Sandbox belongs to an active agent run — stop the run instead"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/{cmd_id}/kill":{"post":{"tags":["Sandboxes"],"summary":"Kill a running command (`@vercel/sandbox`-compatible). The SDK\ncalls `POST /v1/sandboxes/{id}/{cmdId}/kill` — note the path has the\ncommand ID directly under the sandbox, NOT under `/jobs/` or `/cmd/`.","operationId":"cmd_kill","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"cmd_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CmdKillBody"}}}},"responses":{"200":{"description":"Command killed; returns final snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CmdResponse"}}}},"404":{"description":"Sandbox or command not found"}},"security":[{"bearer_auth":[]}]}},"/visitors/{visitor_id}/session-replays":{"get":{"tags":["Analytics"],"summary":"Get session replays for a visitor","operationId":"get_visitor_sessions","parameters":[{"name":"visitor_id","in":"path","description":"Visitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-based)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Items per page","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Session replays retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetVisitorSessionsResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/visitors/{visitor_id}/session-replays/{session_id}":{"get":{"tags":["Analytics"],"summary":"Get session replay data with visitor info (without events)","operationId":"get_session_replay","parameters":[{"name":"visitor_id","in":"path","description":"Visitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Session replay retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetSessionReplayResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Session not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Analytics"],"summary":"Delete a session replay","operationId":"delete_session_replay","parameters":[{"name":"visitor_id","in":"path","description":"Visitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Session replay deleted successfully"},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Session not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/visitors/{visitor_id}/session-replays/{session_id}/duration":{"put":{"tags":["Analytics"],"summary":"Update session duration","operationId":"update_session_duration","parameters":[{"name":"visitor_id","in":"path","description":"Visitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSessionDurationRequest"}}},"required":true},"responses":{"200":{"description":"Session duration updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSessionDurationResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Session not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/visitors/{visitor_id}/session-replays/{session_id}/events":{"get":{"tags":["Analytics"],"summary":"Get session replay events (with session and visitor metadata)","operationId":"get_session_replay_events","parameters":[{"name":"visitor_id","in":"path","description":"Visitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Session replay with events retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionReplayWithEventsDto"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Session not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Analytics"],"summary":"Add events to an existing session","operationId":"add_events","parameters":[{"name":"visitor_id","in":"path","description":"Visitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddEventsRequest"}}},"required":true},"responses":{"200":{"description":"Events added successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddEventsResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Session not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/vulnerability-scans/{scan_id}":{"get":{"tags":["Vulnerability Scans"],"operationId":"get_scan","parameters":[{"name":"scan_id","in":"path","description":"Scan ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Scan details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScanResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Scan not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Vulnerability Scans"],"operationId":"delete_scan","parameters":[{"name":"scan_id","in":"path","description":"Scan ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Scan deleted"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Scan not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/vulnerability-scans/{scan_id}/vulnerabilities":{"get":{"tags":["Vulnerability Scans"],"operationId":"get_scan_vulnerabilities","parameters":[{"name":"scan_id","in":"path","description":"Scan ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"severity","in":"query","description":"Filter by severity (CRITICAL, HIGH, MEDIUM, LOW)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of vulnerabilities","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/VulnerabilityResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Scan not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/webhook-event-types":{"get":{"tags":["Webhooks"],"summary":"List available event types","operationId":"list_event_types","responses":{"200":{"description":"List of available event types","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EventTypeResponse"}}}}}}}},"/weekly-digest/trigger":{"post":{"tags":["Notification Preferences"],"summary":"Trigger weekly digest generation manually","operationId":"trigger_weekly_digest","responses":{"200":{"description":"Weekly digest triggered successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerDigestResponse"}}}},"500":{"description":"Failed to generate digest"}},"security":[{"bearer_auth":[]}]}},"/x/plugins":{"get":{"tags":["External Plugins"],"summary":"List all running external plugins and their manifests.","description":"Requires only a valid session/token (no specific permission) since the\nmanifest drives sidebar navigation rendering for every authenticated\nuser, not just admins.","operationId":"list_external_plugins","responses":{"200":{"description":"List of all running external plugins","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PluginManifest"}}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/x/plugins/reload":{"post":{"tags":["External Plugins"],"summary":"Reload all external plugins.","description":"Stops all running plugin processes, re-scans the plugins directory,\nstarts any discovered binaries, and hot-swaps the proxy router so new\nand removed plugins take effect immediately without a server restart.\n\nRequires `SystemAdmin` permission.","operationId":"reload_plugins","responses":{"200":{"description":"Plugins reloaded successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReloadResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/{project_id}/envelope/":{"post":{"tags":["sentry-ingestor"],"summary":"Ingest a Sentry envelope (binary payload)","operationId":"ingest_sentry_envelope","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"Sentry envelope as binary data","content":{"application/octet-stream":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"Envelope ingested"},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"413":{"description":"Request body too large (exceeds 2 MiB)"}}}},"/{project_id}/store/":{"post":{"tags":["sentry-ingestor"],"summary":"Ingest a Sentry event (JSON payload)","operationId":"ingest_sentry_event","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryEventRequest"}}},"required":true},"responses":{"200":{"description":"Event ingested","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryEventResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"413":{"description":"Request body too large (exceeds 2 MiB)"}}}},"audit/logs":{"get":{"tags":["Audit Logs"],"summary":"List audit logs with optional filtering","operationId":"list_audit_logs","parameters":[{"name":"operation_type","in":"query","description":"Filter logs by operation type (omit for all)","required":false,"schema":{"type":"string"},"example":"user.login"},{"name":"user_id","in":"query","description":"Filter logs by user ID (omit for all users)","required":false,"schema":{"type":"integer","format":"int32"},"example":1},{"name":"from","in":"query","description":"Start timestamp (milliseconds since epoch)","required":false,"schema":{"type":"string","format":"date-time"},"example":1},{"name":"to","in":"query","description":"End timestamp (milliseconds since epoch)","required":false,"schema":{"type":"string","format":"date-time"},"example":1},{"name":"limit","in":"query","description":"Maximum number of logs to return","required":false,"schema":{"type":"integer","format":"int32"},"example":100},{"name":"offset","in":"query","description":"Number of logs to skip","required":false,"schema":{"type":"integer","format":"int32"},"example":0}],"responses":{"200":{"description":"List of audit logs","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AuditLogResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"api_key":[]}]}},"audit/logs/{id}":{"get":{"tags":["Audit Logs"],"summary":"Get a specific audit log entry by ID","operationId":"get_audit_log","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Audit log details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuditLogResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Audit log not found"},"500":{"description":"Internal server error"}},"security":[{"api_key":[]}]}}},"components":{"schemas":{"AcmeOrderResponse":{"type":"object","required":["id","order_url","domain_id","email","status","identifiers","created_at","updated_at"],"properties":{"authorizations":{},"certificate_url":{"type":["string","null"]},"challenge_validation":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ChallengeValidationStatus","description":"Live challenge validation status fetched from Let's Encrypt"}]},"created_at":{"type":"integer","format":"int64"},"domain_id":{"type":"integer","format":"int32"},"email":{"type":"string"},"error":{"type":["string","null"]},"error_type":{"type":["string","null"]},"expires_at":{"type":["integer","null"],"format":"int64"},"finalize_url":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"identifiers":{},"order_url":{"type":"string"},"status":{"type":"string"},"updated_at":{"type":"integer","format":"int64"}}},"ActivateProviderResponse":{"type":"object","required":["default_provider"],"properties":{"default_provider":{"type":"string"}}},"ActiveVisitor":{"type":"object","required":["session_id","session_start","last_activity","page_count","event_count","duration_seconds","is_active"],"properties":{"current_page":{"type":["string","null"]},"duration_seconds":{"type":"integer","format":"int64"},"event_count":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"last_activity":{"type":"string"},"page_count":{"type":"integer","format":"int32"},"session_id":{"type":"string"},"session_start":{"type":"string"},"visitor_id":{"type":["string","null"]}}},"ActiveVisitorsQuery":{"type":"object","properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"}}},"ActiveVisitorsResponse":{"type":"object","required":["active_visitors","window_minutes"],"properties":{"active_visitors":{"type":"integer","format":"int64"},"window_minutes":{"type":"integer","format":"int32"}}},"ActivityDay":{"type":"object","description":"Daily activity count for a single day","required":["date","count","level"],"properties":{"count":{"type":"integer","format":"int64","description":"Number of deployments on this day"},"date":{"type":"string","description":"Date in YYYY-MM-DD format","example":"2024-06-15"},"level":{"type":"integer","format":"int32","description":"Intensity level (0-4) for visualization\n0: No activity, 1: Low (1-2), 2: Medium (3-5), 3: High (6-10), 4: Very High (11+)","example":2}}},"ActivityEvent":{"type":"object","description":"A single activity event for the real-time activity feed","required":["id","timestamp","event_type","page_path","is_crawler"],"properties":{"browser":{"type":["string","null"],"description":"Browser"},"city":{"type":["string","null"],"description":"Visitor's city (from ip_geolocations)"},"country":{"type":["string","null"],"description":"Visitor's country (from ip_geolocations)"},"country_code":{"type":["string","null"],"description":"Visitor's country code (from ip_geolocations)"},"device_type":{"type":["string","null"],"description":"Device type"},"event_name":{"type":["string","null"],"description":"Event name (for custom events)"},"event_type":{"type":"string","description":"Event type: \"page_view\", \"custom\", etc."},"id":{"type":"integer","format":"int64","description":"Event ID"},"is_crawler":{"type":"boolean","description":"Whether this event was from a crawler"},"latitude":{"type":["number","null"],"format":"double","description":"Latitude"},"longitude":{"type":["number","null"],"format":"double","description":"Longitude"},"operating_system":{"type":["string","null"],"description":"Operating system"},"page_path":{"type":"string","description":"Page path where the event happened"},"page_title":{"type":["string","null"],"description":"Page title"},"referrer":{"type":["string","null"],"description":"Referrer"},"timestamp":{"type":"string","format":"date-time","description":"When the event occurred"},"visitor_id":{"type":["integer","null"],"format":"int32","description":"Visitor numeric ID"}}},"ActivityGraphQuery":{"type":"object","description":"Query parameters for activity graph endpoint","properties":{"days":{"type":"integer","format":"int32","description":"Number of days to include (default: 365 for last year)"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Optional environment ID to filter activity"},"project_id":{"type":["integer","null"],"format":"int32","description":"Optional project ID to filter activity"}}},"ActivityGraphResponse":{"type":"object","description":"Response for activity graph showing daily deployment activity","required":["days","total_count","start_date","end_date"],"properties":{"days":{"type":"array","items":{"$ref":"#/components/schemas/ActivityDay"},"description":"Array of daily activity counts"},"end_date":{"type":"string","description":"Date range end (YYYY-MM-DD)","example":"2024-12-31"},"start_date":{"type":"string","description":"Date range start (YYYY-MM-DD)","example":"2024-01-01"},"total_count":{"type":"integer","format":"int64","description":"Total count of activities across all days"}}},"AddClusterMemberRequest":{"type":"object","description":"Request body for adding a single member to a running cluster.","required":["role"],"properties":{"node_id":{"type":["integer","null"],"format":"int32","description":"Target worker node ID. Omit or null to run on the control plane."},"role":{"type":"string","description":"Member role. Currently only `replica` is accepted at runtime —\nmonitor is a singleton, primary is elected by pg_auto_failover.","example":"replica"}}},"AddContextRequest":{"type":"object","required":["message"],"properties":{"message":{"type":"string"}}},"AddEnvironmentDomainRequest":{"type":"object","required":["domain","is_primary"],"properties":{"domain":{"type":"string"},"is_primary":{"type":"boolean"}}},"AddEventsRequest":{"type":"object","required":["events"],"properties":{"events":{"type":"string"}}},"AddEventsResponse":{"type":"object","required":["event_count","message"],"properties":{"event_count":{"type":"integer","minimum":0},"message":{"type":"string"}}},"AddManagedDomainApiRequest":{"type":"object","description":"Request to add a managed domain","required":["domain"],"properties":{"auto_manage":{"type":"boolean"},"domain":{"type":"string","example":"example.com"},"generated_hostname_mode":{"type":["string","null"],"description":"Generated hostname layout: `\"standard\"` (default) or `\"flat\"`."},"sync_generated_records":{"type":"boolean","description":"Opt in to reconciling generated hostnames into this domain's DNS zone."}}},"AdminGateResponse":{"type":"object","required":["allowed_ips","allowed_hosts","trust_forwarded_for","source","editable"],"properties":{"allowed_hosts":{"type":"array","items":{"type":"string"},"description":"`Host` header values allowed. Empty = any host."},"allowed_ips":{"type":"array","items":{"type":"string"},"description":"IPs / CIDRs allowed to reach the admin listener. Empty = any source."},"editable":{"type":"boolean","description":"True when the config is writable through this API. False when env\nvars are dictating the active config."},"source":{"$ref":"#/components/schemas/AdminGateSource","description":"Where the active config came from."},"trust_forwarded_for":{"type":"boolean","description":"When true, the gate trusts `X-Forwarded-For` from loopback peers."}}},"AdminGateSource":{"type":"string","description":"Where the active gate configuration came from. Env-supplied configs are\nfrozen at the process level — the UI shows them read-only and refuses to\npersist DB writes. DB-supplied configs are editable at runtime.","enum":["default","db","env"]},"AgentConfigResponse":{"type":"object","description":"Response DTO for a single agent — masks the encrypted API key.","required":["id","project_id","slug","name","source","enabled","trigger_config","ai_provider","api_key_set","max_turns","timeout_seconds","daily_budget_cents","cooldown_minutes","branch_prefix","deliverable","created_at","updated_at"],"properties":{"ai_model":{"type":["string","null"],"description":"Preferred model for the CLI (e.g. \"sonnet\", \"gpt-5-codex\"). `None` means default."},"ai_provider":{"type":"string"},"ai_provider_key_id":{"type":["integer","null"],"format":"int32"},"api_key_set":{"type":"boolean","description":"`true` if an API key is set; `false` otherwise."},"branch_prefix":{"type":"string"},"config_repo_branch":{"type":["string","null"],"description":"Branch of the config repo to use."},"config_repo_url":{"type":["string","null"],"description":"Private config repo containing .claude/ directory (skills, MCP, plugins)."},"cooldown_minutes":{"type":"integer","format":"int32"},"created_at":{"type":"string"},"daily_budget_cents":{"type":"integer","format":"int32"},"deliverable":{"type":"string"},"description":{"type":["string","null"]},"enabled":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"max_turns":{"type":"integer","format":"int32"},"mcp_servers_config":{"description":"MCP servers config (Claude Code settings.json mcpServers format).\nCredential-bearing legacy inline values are write-only and appear as\n`***`. Omit this field on update to preserve their stored values."},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"prompt":{"type":["string","null"]},"sandbox_enabled":{"type":["boolean","null"],"description":"None = use global sandbox setting, true = force on, false = force off"},"skills_config":{"description":"Skills config as JSON array."},"slug":{"type":"string"},"source":{"type":"string"},"timeout_seconds":{"type":"integer","format":"int32"},"tools_config":{"description":"Tools config as JSON array. Legacy custom-tool webhook URLs and headers\nare write-only and appear as `***`. Omit this field on update to\npreserve their stored values."},"trigger_config":{},"updated_at":{"type":"string"},"webhook_token":{"type":["string","null"],"description":"Secret token for the `X-Webhook-Token` header. Shown once when created,\nmasked with `***` prefix in subsequent reads."},"webhook_url":{"type":["string","null"],"description":"Public webhook URL for triggering this agent externally.\nOnly set when `on: { webhook: true }` is configured.\nUsage: `POST {webhook_url}` with header `X-Webhook-Token: {webhook_token}`"}}},"AgentRunLogResponse":{"type":"object","required":["id","run_id","level","message","created_at"],"properties":{"created_at":{"type":"string"},"id":{"type":"integer","format":"int64"},"level":{"type":"string"},"message":{"type":"string"},"metadata":{},"run_id":{"type":"integer","format":"int32"}}},"AgentRunResponse":{"type":"object","required":["id","project_id","source","trigger_type","status","tokens_input","tokens_output","estimated_cost_cents","files_changed","created_at","sandbox_enabled"],"properties":{"agent_name":{"type":["string","null"],"description":"Name of the agent that created this run, if available."},"agent_slug":{"type":["string","null"],"description":"Slug of the agent that created this run, if available."},"ai_model":{"type":["string","null"]},"ai_output":{"type":["string","null"]},"ai_provider":{"type":["string","null"],"description":"AI provider slug that executed this run (e.g. claude_cli, codex_cli, opencode)."},"ai_reasoning":{"type":["string","null"]},"ai_session_id":{"type":["string","null"],"description":"Claude CLI session UUID for resuming conversations via `--resume`."},"analysis":{"type":["string","null"],"description":"Report / analysis text produced by the agent (used for report/notification deliverables)."},"branch_name":{"type":["string","null"]},"commit_sha":{"type":["string","null"]},"completed_at":{"type":["string","null"]},"config_id":{"type":["integer","null"],"format":"int32","description":"Optional. NULL for ephemeral CLI runs (`source = \"cli_ephemeral\"`) and\nhistorical autofixer runs that pre-date the agent_id column."},"created_at":{"type":"string"},"ephemeral_yaml":{"type":["string","null"],"description":"Full WorkflowYamlConfig as YAML text. Populated only when\n`source = \"cli_ephemeral\"`. Used by the web UI to show a \"View YAML\"\nmodal so the user can see exactly what the executor ran."},"error_message":{"type":["string","null"]},"estimated_cost_cents":{"type":"integer","format":"int32"},"files_changed":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"phase":{"type":["string","null"],"description":"Autofixer phase: \"analyzing\", \"analyzed\", \"fixing\", \"fix_ready\", \"no_fix\",\n\"pr_created\", or NULL for non-autofixer runs."},"pr_number":{"type":["integer","null"],"format":"int32"},"pr_url":{"type":["string","null"]},"preview_url":{"type":["string","null"]},"project_id":{"type":"integer","format":"int32"},"prompt_text":{"type":["string","null"],"description":"Final assembled prompt the AI CLI actually saw (trigger context block +\nYAML prompt, with error-group fields interpolated). Captured once per\nrun. `None` for pre-migration rows."},"run_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AutofixRunConfig","description":"Per-run AI options the user chose when starting an autofixer run\n(provider, model, max_turns, branch). NULL for generic agent runs\nand historical rows. Used to prefill the retry dialog."}]},"sandbox_enabled":{"type":"boolean","description":"Legacy field — all runs now execute in a sandbox. Kept for\nbackwards-compatible JSON shape; always `true`."},"source":{"type":"string","description":"`committed` (the run's config lives in `project_agents`) or\n`cli_ephemeral` (the config was uploaded via the CLI for a one-off\ndry run; see `ephemeral_yaml`)."},"started_at":{"type":["string","null"]},"status":{"type":"string"},"tokens_input":{"type":"integer","format":"int32"},"tokens_output":{"type":"integer","format":"int32"},"trigger_source_id":{"type":["integer","null"],"format":"int32"},"trigger_source_type":{"type":["string","null"]},"trigger_type":{"type":"string"},"user_context":{"type":["string","null"],"description":"User-provided context for this run (e.g. webhook payload, manual instructions)."}}},"AgentRunWithLogsResponse":{"type":"object","required":["run","logs"],"properties":{"logs":{"type":"array","items":{"$ref":"#/components/schemas/AgentRunLogResponse"}},"run":{"$ref":"#/components/schemas/AgentRunResponse"}}},"AgentSandboxSettings":{"type":"object","description":"Global agent sandbox settings. Controls whether agent runs are isolated\ninside Docker containers by default. Individual agents can override this.","properties":{"api_key_encrypted":{"type":["string","null"],"description":"DEPRECATED: use `providers[default_provider].credentials_encrypted` instead.","default":null},"auth_type":{"type":"string","description":"DEPRECATED: use `providers[default_provider].auth_type` instead.","default":"subscription"},"cpu_limit":{"type":"number","format":"double","description":"CPU limit in cores for sandbox containers","default":4.0,"example":4.0},"custom_image":{"type":"string","description":"Custom Docker image (only used when runtime is \"custom\").\nMust have git and claude CLI installed.","default":"","example":""},"default_provider":{"type":"string","description":"Default AI provider for agents: \"claude_cli\", \"opencode\", or \"codex_cli\".\nWorkspaces always use this provider — no per-session override.","default":"claude_cli","example":"claude_cli"},"enabled":{"type":"boolean","description":"Sandbox is always enabled — the executor refuses to run any agent\noutside a sandboxed container. Field is retained so existing settings\nrows still deserialize, but it is ignored at runtime.","default":true},"memory_limit_mb":{"type":"integer","format":"int64","description":"Memory limit in MB for sandbox containers","default":8192,"example":8192,"minimum":0},"network_mode":{"type":"string","description":"Network access level: \"full\" (unrestricted), \"restricted\" (Temps network only), \"none\" (no network)","default":"full","example":"full"},"providers":{"type":"object","description":"Per-provider auth + config. Keyed by provider id (e.g. `claude_cli`,\n`codex_cli`, `opencode`). Adding a new provider only requires a new\ncatalog entry on the Rust side — the JSON column stays migration-free.","default":{},"additionalProperties":{"$ref":"#/components/schemas/ProviderConfig"},"propertyNames":{"type":"string"}},"runtime":{"type":"string","description":"Runtime preset: \"node\", \"bun\", \"python\", \"rust\", \"go\", \"full\", or \"custom\"","default":"node","example":"node"},"sandbox_backend":{"type":["string","null"],"description":"Default isolation backend for sandboxes: \"docker\" (default) or\n\"firecracker\" (ADR-029; requires `temps firecracker setup`). Only\nconsulted when the Firecracker backend probes available — otherwise\nDocker is used regardless.","default":null,"example":"docker"}}},"AgentSandboxSettingsMasked":{"type":"object","description":"Agent sandbox settings with masked per-provider credentials.\nEach provider entry reports only whether a credential is saved, not\nthe encrypted blob itself. Non-sensitive fields (auth_type, default_model,\nextra) are passed through so the UI can render provider-specific state.","required":["default_provider","providers","api_key_saved","auth_type","enabled","runtime","custom_image","cpu_limit","memory_limit_mb","network_mode","sandbox_backend"],"properties":{"api_key_saved":{"type":"boolean"},"auth_type":{"type":"string"},"cpu_limit":{"type":"number","format":"double"},"custom_image":{"type":"string"},"default_provider":{"type":"string"},"enabled":{"type":"boolean"},"memory_limit_mb":{"type":"integer","format":"int64","minimum":0},"network_mode":{"type":"string"},"providers":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/ProviderConfigMasked"},"propertyNames":{"type":"string"}},"runtime":{"type":"string"},"sandbox_backend":{"type":"string"}}},"AggregatedBucketItem":{"type":"object","required":["timestamp","count"],"properties":{"count":{"type":"integer","format":"int64"},"timestamp":{"type":"string"}}},"AggregatedBucketsQuery":{"type":"object","description":"Query parameters for aggregated metrics by time bucket","required":["start_date","end_date"],"properties":{"aggregation_level":{"$ref":"#/components/schemas/AggregationLevel","description":"Aggregation level: events, sessions, or visitors"},"bucket_size":{"type":"string","description":"Time bucket size: \"1 hour\", \"1 day\", \"1 week\", etc. (default: \"1 hour\")"},"deployment_id":{"type":["integer","null"],"format":"int32","description":"Optional deployment filter"},"end_date":{"type":"string","format":"date-time","description":"End date for the query range"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Optional environment filter"},"start_date":{"type":"string","format":"date-time","description":"Start date for the query range"}}},"AggregatedBucketsResponse":{"type":"object","required":["bucket_size","aggregation_level","items","total"],"properties":{"aggregation_level":{"type":"string"},"bucket_size":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/AggregatedBucketItem"}},"total":{"type":"integer","format":"int64"}}},"AggregationLevel":{"type":"string","enum":["events","sessions","visitors"]},"AggregationTemporality":{"type":"string","description":"The aggregation temporality of a Sum/Histogram/ExponentialHistogram metric.\n\nMirrors OTel's `AggregationTemporality` proto enum: whether reported values\nare cumulative since the start of the series (Cumulative) or only the delta\nsince the previous report (Delta).","enum":["unspecified","delta","cumulative"]},"AiAgentBreakdownResponse":{"type":"object","description":"Response wrapping the AI agent breakdown rows.","required":["items","start_time","end_time"],"properties":{"end_time":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/AiAgentBreakdownRow"}},"start_time":{"type":"string"}}},"AiAgentBreakdownRow":{"type":"object","description":"One row in the AI-agent analytics breakdown. `agent` is the canonical\ncrawler name (e.g. `GPTBot`, `Claude-User`), `provider` is the vendor used\nfor grouping + logos. The UI mirrors the browsers card and ranks by\n`request_count`.","required":["provider","agent","purpose","request_count","unique_ips"],"properties":{"agent":{"type":"string"},"last_seen":{"type":["string","null"],"description":"Last-seen timestamp in RFC3339 format, or `None` if no rows matched.","example":"2026-05-29T12:00:00Z"},"provider":{"type":"string"},"purpose":{"type":"string"},"request_count":{"type":"integer","format":"int64"},"unique_ips":{"type":"integer","format":"int64"}}},"AiAgentDescriptor":{"type":"object","description":"Static descriptor for one entry in the known-AI-agents taxonomy.","required":["provider","agent","purpose"],"properties":{"agent":{"type":"string"},"provider":{"type":"string"},"purpose":{"type":"string"}}},"AiAgentPageRow":{"type":"object","description":"One row in the pages-by-agent breakdown. Returned by\n[`ProxyLogService::get_ai_agent_pages`] for a single named agent.\n`unique_ips` counts distinct client IPs that hit this path via that agent\n(same definition as the per-agent unique-IPs in [`AiAgentBreakdownRow`]).","required":["path","request_count","unique_ips"],"properties":{"last_seen":{"type":["string","null"],"description":"Last-seen timestamp in RFC3339 format, or `None` if no rows matched.","example":"2026-05-29T12:00:00Z"},"path":{"type":"string"},"request_count":{"type":"integer","format":"int64"},"unique_ips":{"type":"integer","format":"int64"}}},"AiAgentPagesResponse":{"type":"object","description":"Response wrapping the per-agent pages breakdown rows.","required":["agent","items","start_time","end_time"],"properties":{"agent":{"type":"string","description":"The agent name this breakdown is scoped to."},"end_time":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/AiAgentPageRow"}},"start_time":{"type":"string"}}},"AiAgentTimelineResponse":{"type":"object","description":"Response wrapping the AI agent timeline rows.","required":["items","start_time","end_time","bucket","group_by"],"properties":{"bucket":{"type":"string","description":"Bucket interval used for the buckets (so the UI can label the x-axis).","example":"1 hour"},"end_time":{"type":"string"},"group_by":{"type":"string","description":"Echoes the grouping dimension actually applied.","example":"provider"},"items":{"type":"array","items":{"$ref":"#/components/schemas/AiAgentTimelineRow"}},"start_time":{"type":"string"}}},"AiAgentTimelineRow":{"type":"object","description":"One point in the AI-agent timeline: the request count for a single\n(`bucket`, `key`) pair, where `key` is a provider or agent name depending on\nthe requested grouping. The UI pivots these into one stacked series per\n`key` across the shared bucket x-axis.","required":["bucket","key","request_count"],"properties":{"bucket":{"type":"string","description":"Bucket start in RFC3339 format.","example":"2026-05-29T12:00:00Z"},"key":{"type":"string","description":"Provider or agent name this count belongs to.","example":"OpenAI"},"request_count":{"type":"integer","format":"int64"}}},"AiChatLimitsSettings":{"type":"object","description":"Bounds on one AI chat turn.\n\nA turn is bounded by TIME rather than by a number of steps. A step count\nsays nothing about cost or about how long someone has been watching a\nspinner, and it cuts short exactly the long, productive turns the chat\nexists for. The user can already see each tool call and press Stop; the\ndeadline is what guarantees an *unattended* turn still ends.\n\nThe right value is a property of the model, which is why it is configurable\nrather than compiled in: a full alert-suggestion turn takes ~10 minutes\nagainst a slow local model and seconds against a hosted one.","properties":{"turn_timeout_secs":{"type":"integer","format":"int32","description":"How long one turn may run before it is stopped and the partial answer\nreturned, in seconds. The user is told the turn was cut short.\n\nChecked between steps, not mid-call: a model round already in flight\nfinishes, so a turn can overrun by up to one round. Against a slow\nself-hosted model that is a minute or two. Aborting mid-stream would cut\nthe answer off in the middle of a sentence and throw away work already\npaid for, which is worse than a late stop.","default":900,"example":900,"maximum":3600,"minimum":30}}},"AiConfigSettings":{"type":"object","description":"Global AI configuration settings. Controls the default config repo\ncontaining `.claude/` directory (skills, MCP servers, plugins) that\ngets overlaid into every agent sandbox.","properties":{"config_repo":{"type":"string","description":"Global config repo URL in \"owner/repo\" format (e.g. \"myorg/claude-config\").\nCloned at agent run time and overlaid into the sandbox's `.claude/` directory.","default":"","example":""},"config_repo_branch":{"type":"string","description":"Branch of the config repo to use.","default":"main","example":"main"}}},"AiPageBreakdownResponse":{"type":"object","description":"Response wrapping the AI page breakdown rows.","required":["items","start_time","end_time"],"properties":{"end_time":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/AiPageBreakdownRow"}},"start_time":{"type":"string"}}},"AiPageBreakdownRow":{"type":"object","description":"One row in the AI-crawled-pages breakdown. `agent_count` is the number of\n*distinct* AI agents that hit this path, so the UI can show both how heavily\nand how broadly a page is being crawled.","required":["path","request_count","agent_count"],"properties":{"agent_count":{"type":"integer","format":"int64"},"last_seen":{"type":["string","null"],"description":"Last-seen timestamp in RFC3339 format, or `None` if no rows matched.","example":"2026-05-29T12:00:00Z"},"path":{"type":"string"},"request_count":{"type":"integer","format":"int64"}}},"AiStatusBreakdownResponse":{"type":"object","description":"Response wrapping the AI status breakdown rows.","required":["items","start_time","end_time"],"properties":{"end_time":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/AiStatusBreakdownRow"}},"start_time":{"type":"string"}}},"AiStatusBreakdownRow":{"type":"object","description":"One row in the AI-agent HTTP status breakdown: the request count for a\nstatus class (`2xx`/`3xx`/`4xx`/`5xx`/`other`) across crawler traffic.","required":["status_class","request_count"],"properties":{"request_count":{"type":"integer","format":"int64"},"status_class":{"type":"string","description":"Status class label.","example":"2xx"}}},"AlarmListResponse":{"type":"object","description":"Paginated list of alarms.","required":["items","total","page","page_size"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AlarmResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"AlarmResponse":{"type":"object","description":"Full alarm representation returned by list/summary endpoints.","required":["id","project_id","alarm_type","severity","status","title","fired_at","created_at","updated_at"],"properties":{"acknowledged_at":{"type":["string","null"],"description":"ISO-8601 UTC timestamp when the alarm was acknowledged, if any."},"acknowledged_by":{"type":["integer","null"],"format":"int32","description":"User ID who acknowledged the alarm, if any."},"alarm_type":{"type":"string"},"container_id":{"type":["integer","null"],"format":"int32"},"created_at":{"type":"string","description":"ISO-8601 UTC timestamp when the row was created."},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"fired_at":{"type":"string","description":"ISO-8601 UTC timestamp when the alarm fired."},"id":{"type":"integer","format":"int32"},"message":{"type":["string","null"]},"metadata":{"description":"Arbitrary JSON metadata attached by the alarm source."},"project_id":{"type":"integer","format":"int32"},"resolved_at":{"type":["string","null"],"description":"ISO-8601 UTC timestamp when the alarm was resolved, if any."},"service_id":{"type":["integer","null"],"format":"int32"},"severity":{"type":"string"},"status":{"type":"string"},"title":{"type":"string"},"updated_at":{"type":"string","description":"ISO-8601 UTC timestamp when the row was last updated."}}},"AlarmSummaryResponse":{"type":"object","description":"Re-export AlarmSummary for the OpenAPI schema.","required":["total_active","firing","acknowledged","critical","warning","by_type"],"properties":{"acknowledged":{"type":"integer","format":"int32","minimum":0},"by_type":{"type":"object","additionalProperties":{"type":"integer","format":"int32","minimum":0},"propertyNames":{"type":"string"}},"critical":{"type":"integer","format":"int32","minimum":0},"firing":{"type":"integer","format":"int32","minimum":0},"total_active":{"type":"integer","format":"int32","minimum":0},"warning":{"type":"integer","format":"int32","minimum":0}}},"AlertRuleResponse":{"type":"object","required":["id","project_id","name","trigger_type","trigger_config","notification_priority","cooldown_minutes","enabled","created_at","updated_at"],"properties":{"cooldown_minutes":{"type":"integer","format":"int32"},"created_at":{"type":"string"},"enabled":{"type":"boolean"},"environment_filter":{"type":["integer","null"],"format":"int32"},"error_level_filter":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"notification_priority":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"trigger_config":{},"trigger_type":{"type":"string"},"updated_at":{"type":"string"}}},"AllocEntry":{"type":"object","description":"Wire-format allocation. `null` in the JSON when the node hasn't been\nallocated yet — workers should treat that as \"single-host mode, do\nnot bring up the overlay\".","required":["node_id","compute_cidr","bridge_address","underlay_address"],"properties":{"bridge_address":{"type":"string"},"compute_cidr":{"type":"string"},"node_id":{"type":"string","description":"Stable v5 UUID derived from the database node id."},"underlay_address":{"type":"string"}}},"AnalyticsSessionEventsResponse":{"type":"object","required":["session_id","events","total_events"],"properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/SessionEvent"}},"session_id":{"type":"string"},"total_events":{"type":"integer","minimum":0}}},"AnnotatedSpan":{"type":"object","description":"A single span annotated with the project that originally stored it.\nUsed in `UnifiedTrace` to let the UI colour-code spans by project.","required":["project_id","project_name","span"],"properties":{"project_id":{"type":"integer","format":"int32","description":"The project that stored this span (same as `span.project_id`)."},"project_name":{"type":"string","description":"Human-readable project name for waterfall colour-coding and legend."},"span":{"$ref":"#/components/schemas/SpanRecord","description":"Original span data verbatim from storage."}}},"AnomalyAlgorithm":{"type":"string","description":"Anomaly baseline algorithm. Adding one (e.g. a new robust variant) is a\ncode-only enum addition — no migration, since it lives inside the blob.","enum":["robust","basic","agile","ewma"]},"AnomalyParams":{"type":"object","description":"Seasonal anomaly-band detector parameters (stub — not yet evaluated).","properties":{"algorithm":{"$ref":"#/components/schemas/AnomalyAlgorithm","description":"Baseline model. `robust` is the default (seasonal, stable, flags level\nshifts); `ewma`/`agile` adopt level shifts; `basic` is non-seasonal."},"baseline_lookback_days":{"type":["integer","null"],"format":"int32","description":"How far back to build the baseline. `None` = an evaluator default."},"deviations":{"type":"number","format":"double","description":"Band width in robust standard deviations (Datadog's `bounds`)."},"direction":{"$ref":"#/components/schemas/Direction","description":"Which side(s) of the band a deviation must be on to count."},"pct_anomalous":{"type":"number","format":"double","description":"Fraction (0..=1) of points in the window that must be anomalous to fire."},"seasonality":{"$ref":"#/components/schemas/Seasonality","description":"Seasonality model for the baseline."}}},"AnomalyPreviewPointResponse":{"type":"object","required":["bucket","value","lower","upper","breaching"],"properties":{"breaching":{"type":"boolean"},"bucket":{"type":"string","example":"2025-10-12T12:15:47Z"},"lower":{"type":"number","format":"double","description":"Lower edge of the expected band at this point."},"upper":{"type":"number","format":"double","description":"Upper edge of the expected band at this point."},"value":{"type":"number","format":"double"}}},"AnomalyPreviewRequest":{"type":"object","required":["project_id","metric_name","aggregation","window_secs","detection_config"],"properties":{"aggregation":{"type":"string","description":"One of `avg|sum|min|max|count|rate|p50|p90|p95|p99`."},"detection_config":{"$ref":"#/components/schemas/DetectionConfig","description":"The detector to backtest. `static` and `anomaly` are supported — the\nkinds the evaluator actually runs."},"end_time":{"type":["string","null"],"description":"RFC 3339; defaults to now.","example":"2025-10-12T12:15:47Z"},"metric_name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"start_time":{"type":["string","null"],"description":"RFC 3339; defaults to 7 days before `end_time`.","example":"2025-10-12T12:15:47Z"},"window_secs":{"type":"integer","format":"int32"}}},"AnomalyPreviewResponse":{"type":"object","required":["points","breach_count","baseline_samples","sufficient"],"properties":{"baseline_samples":{"type":"integer","format":"int64","description":"Baseline sample count (drives the `sufficient` flag)."},"breach_count":{"type":"integer","format":"int64","description":"How many points in the range would have fired."},"points":{"type":"array","items":{"$ref":"#/components/schemas/AnomalyPreviewPointResponse"}},"sufficient":{"type":"boolean","description":"Whether the baseline had enough history for a trustworthy band."}}},"ApiKeyListResponse":{"type":"object","required":["api_keys","total"],"properties":{"api_keys":{"type":"array","items":{"$ref":"#/components/schemas/ApiKeyResponse"}},"total":{"type":"integer","format":"int64","minimum":0}}},"ApiKeyResponse":{"type":"object","required":["id","name","key_prefix","role_type","is_active","created_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00Z"},"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"key_prefix":{"type":"string"},"last_used_at":{"type":["string","null"],"format":"date-time","example":"2024-01-01T00:00:00Z"},"name":{"type":"string"},"permissions":{"type":["array","null"],"items":{"type":"string"}},"role_type":{"type":"string"}}},"AppSettings":{"type":"object","description":"Application settings stored in the database\nAll fields have sensible defaults for easy onboarding","properties":{"agent_sandbox":{"oneOf":[{"$ref":"#/components/schemas/AgentSandboxSettings"}],"default":{"default_provider":"claude_cli","providers":{},"auth_type":"subscription","api_key_encrypted":null,"enabled":true,"runtime":"node","custom_image":"","cpu_limit":4.0,"memory_limit_mb":8192,"network_mode":"full","sandbox_backend":null}},"ai_chat_limits":{"oneOf":[{"$ref":"#/components/schemas/AiChatLimitsSettings","description":"Limits on a single AI chat turn. Operator-tunable because the right\nvalue depends on the model: a turn against a slow self-hosted model can\nlegitimately take ten minutes, while a hosted one finishes in seconds\nand a shorter ceiling keeps costs predictable."}],"default":{"turn_timeout_secs":900}},"ai_config":{"oneOf":[{"$ref":"#/components/schemas/AiConfigSettings"}],"default":{"config_repo":"","config_repo_branch":"main"}},"build_limits":{"oneOf":[{"$ref":"#/components/schemas/BuildLimitsSettings","description":"Build-time resource limits applied on the control plane to prevent\n`docker build` from saturating host CPU/RAM. Worker nodes are\nintentionally NOT subject to these limits (each worker is dedicated\nhardware that already has its own per-host headroom)."}],"default":{"max_concurrent":2,"cpu_limit_cores":0.0,"memory_limit_mb":0}},"cluster_dns":{"oneOf":[{"$ref":"#/components/schemas/ClusterDnsSettings","description":"Cluster-DNS resolver settings (ADR-024, experimental beta). Off by\ndefault — see `ClusterDnsSettings` for the incident background and\ntrade-offs. Must be explicitly enabled by operators who need\n`*.temps.local` service-to-service resolution inside containers."}],"default":{"enabled":false}},"console_version":{"type":["string","null"],"description":"Binary version tag (e.g. \"v0.1.0\") of the *console* process\n(`temps serve`, role=all or role=console) that last started. Written\non console startup; read by the standalone `temps proxy` to detect\nversion skew during a rolling upgrade (ADR-017 Phase 3). `None` on\ninstalls that never ran a console build carrying this field.\n\nThis is informational state written by the binary itself — NOT an\noperator-tunable setting. It is intentionally absent from\n`AppSettingsResponse` and the PATCH path so an operator cannot\naccidentally overwrite the self-recorded value.","default":null},"container_logs":{"oneOf":[{"$ref":"#/components/schemas/ContainerLogSettings"}],"default":{"max_size":"50m","max_file":3,"service_max_size":"20m","service_max_file":3}},"disk_space_alert":{"oneOf":[{"$ref":"#/components/schemas/DiskSpaceAlertSettings"}],"default":{"enabled":true,"threshold_percent":80,"check_interval_seconds":300,"monitor_path":null}},"dns_provider":{"oneOf":[{"$ref":"#/components/schemas/DnsProviderSettings"}],"default":{"provider":"manual","cloudflare_api_key":null}},"docker_registry":{"oneOf":[{"$ref":"#/components/schemas/DockerRegistrySettings"}],"default":{"enabled":false,"registry_url":null,"username":null,"password":null,"tls_verify":true,"ca_certificate":null}},"edge_target":{"type":["string","null"],"description":"Public edge target that generated DNS records point at when a managed\ndomain opts into automatic record sync. An IPv4/IPv6 address produces an\n`A`/`AAAA` record; anything else is treated as a `CNAME` target. `None`\ndisables DNS record sync regardless of per-domain opt-in.","default":null},"external_url":{"type":["string","null"],"default":null},"insecure_tls":{"type":"boolean","description":"Skip TLS certificate verification on outbound HTTP clients built by the\nserver (deployer, agent, remote service client). Strictly opt-in for\noperators running self-signed control plane / worker certs on a trusted\ninternal network. Worker→control-plane traffic that traverses the public\ninternet must keep this `false` — otherwise a MitM steals the join token.","default":false},"internal_url":{"type":["string","null"],"description":"URL that service containers use to reach the Temps API from *inside*\nthe Docker network (OTLP metrics ingest, agent callbacks, etc.). On\nDocker Desktop this defaults to `http://host.docker.internal:`;\non Linux it requires the `host.docker.internal:host-gateway` host\nmapping (which Temps adds to provisioned containers). Distinct from\n`external_url`, which is the public-facing address.","default":null},"letsencrypt":{"oneOf":[{"$ref":"#/components/schemas/LetsEncryptSettings"}],"default":{"email":null,"environment":"production"}},"monitoring":{"oneOf":[{"$ref":"#/components/schemas/MonitoringSettings","description":"Metrics observability settings. Controls the MetricsStore backend,\nscrape interval, and tiered retention windows."}],"default":{"enabled":false,"store":"timescale_db","scrape_interval_secs":30,"retention_raw_days":7,"retention_hourly_days":90,"retention_daily_years":2,"clickhouse_url":null}},"multi_node":{"oneOf":[{"$ref":"#/components/schemas/MultiNodeSettings"}],"default":{"join_token_hash":null,"private_address":null,"legacy_shared_token_enabled":true,"cluster_ca_cert_pem":null,"cluster_ca_key_encrypted":null,"require_mtls":false,"node_cpu_alert_percent":90.0,"node_memory_alert_percent":90.0,"node_disk_alert_percent":90.0}},"observability_compression":{"oneOf":[{"$ref":"#/components/schemas/ObservabilityCompressionSettings","description":"TimescaleDB compression delays for immutable observability data.\nChanges are applied at runtime by the Settings API."}],"default":{"proxy_logs_after_hours":24,"otel_spans_after_hours":24}},"observability_retention":{"oneOf":[{"$ref":"#/components/schemas/ObservabilityRetentionSettings","description":"Retention windows for raw proxy and OpenTelemetry telemetry.\nTimescaleDB policies are updated at runtime by the Settings API."}],"default":{"proxy_logs_days":30,"otel_spans_days":90,"otel_logs_days":90,"otel_metrics_days":90}},"on_demand_tls":{"oneOf":[{"$ref":"#/components/schemas/OnDemandTlsSettings"}],"default":{"enabled":false,"zone":null,"max_concurrent":3,"hourly_cap":10,"deployment_url_mode":"http"}},"preview_domain":{"type":"string","default":"localho.st"},"preview_gateway":{"oneOf":[{"$ref":"#/components/schemas/PreviewGatewaySettings"}],"default":{"image":"ghcr.io/gotempsh/temps-preview-gateway:latest","host_port":8090,"auto_upgrade":true}},"rate_limiting":{"oneOf":[{"$ref":"#/components/schemas/RateLimitSettings"}],"default":{"enabled":false,"max_requests_per_minute":60,"max_requests_per_hour":1000,"whitelist_ips":[],"blacklist_ips":[]}},"require_mfa_for_admins":{"type":"boolean","description":"When `true`, any user holding the `Admin` role must have MFA enrolled\n(`users.mfa_enabled = true`) to complete a **password** login. Users\nwithout MFA enrolled are rejected with a typed error instructing them\nto enroll before retrying. This only gates the password-login path\n(`AuthService::login`) -- SSO/OIDC logins are handled by a separate\ncode path (`OidcService::resolve_user` + `oidc_handler`) and are\nintentionally unaffected, since federating identity to a\nproperly-hardened IdP is itself an acceptable alternative to local\nTOTP MFA. Modeled as a settings row (not an env var) per CLAUDE.md so\nan operator can flip it at runtime via the Settings API without\nrestarting the binary.","default":false},"screenshots":{"oneOf":[{"$ref":"#/components/schemas/ScreenshotSettings"}],"default":{"enabled":false,"provider":"local","url":""}},"security_headers":{"oneOf":[{"$ref":"#/components/schemas/SecurityHeadersSettings"}],"default":{"enabled":false,"preset":"moderate","content_security_policy":"default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self'; frame-ancestors 'self'","x_frame_options":"SAMEORIGIN","x_content_type_options":"nosniff","x_xss_protection":"1; mode=block","strict_transport_security":"max-age=31536000; includeSubDomains","referrer_policy":"strict-origin-when-cross-origin","permissions_policy":"geolocation=(), microphone=(), camera=()"}},"self_update":{"oneOf":[{"$ref":"#/components/schemas/SelfUpdateSettings","description":"One-click \"Update now\" from the console. Enabled by default; an admin\ncan turn it off here to keep upgrades on the CLI/config-management path.\n\nThis is the *soft* switch — it is stored in the database, so whoever can\nwrite settings can also turn it back on. Operators who need an upgrade\npath that no console session can re-open should start the server with\n`--disable-self-update`, which wins over this field unconditionally."}],"default":{"enabled":true}},"setup_complete":{"type":"boolean","description":"Set to `true` by `temps setup` (all modes) once initial configuration\nhas been applied. The web onboarding wizard reads this from the server\nand skips itself when true, preventing the \"Configure Base Domain\" wall\nfrom appearing on installs that were already configured via the CLI.","default":false}}},"AppSettingsResponse":{"type":"object","description":"Safe response for application settings that masks sensitive fields","required":["preview_domain","screenshots","letsencrypt","dns_provider","security_headers","rate_limiting","docker_registry","disk_space_alert","container_logs","agent_sandbox","ai_config","preview_gateway","multi_node","monitoring","observability_compression","observability_retention","effective_metrics_store","effective_observability_store","insecure_tls","setup_complete","require_mfa_for_admins","cluster_dns","build_limits","ai_chat_limits","self_update"],"properties":{"agent_sandbox":{"$ref":"#/components/schemas/AgentSandboxSettingsMasked"},"ai_chat_limits":{"$ref":"#/components/schemas/AiChatLimitsSettings","description":"Per-turn limits for the AI chat. No sensitive content."},"ai_config":{"$ref":"#/components/schemas/AiConfigSettings"},"build_limits":{"$ref":"#/components/schemas/BuildLimitsSettings","description":"Build-time resource limits (control-plane only). No sensitive content,\npassed through as-is."},"cluster_dns":{"$ref":"#/components/schemas/ClusterDnsSettings","description":"Cluster-DNS resolver settings (ADR-024, experimental beta). No masking\nneeded — `enabled` is a plain bool with no sensitive content. Passed\nthrough as-is so the settings UI can read and toggle the flag."},"container_logs":{"$ref":"#/components/schemas/ContainerLogSettings"},"disk_space_alert":{"$ref":"#/components/schemas/DiskSpaceAlertSettings"},"dns_provider":{"$ref":"#/components/schemas/DnsProviderSettingsMasked"},"docker_registry":{"$ref":"#/components/schemas/DockerRegistrySettingsMasked"},"edge_target":{"type":["string","null"],"description":"Public edge target that synced DNS records point at (IP → A/AAAA, else CNAME)."},"effective_metrics_store":{"$ref":"#/components/schemas/MetricsStoreKind","description":"The storage backend the runtime is **actually** using for metrics,\nafter reconciling the `monitoring.store` toggle with the server's\n`TEMPS_CLICKHOUSE_*` configuration. When `monitoring.store` is\n`click_house` but those env vars are not fully set, the runtime falls\nback to TimescaleDB — in that case this reports `timescale_db` even\nthough `monitoring.store` says `click_house`. The UI shows this as the\neffective backend and warns when it diverges from the configured store."},"effective_observability_store":{"$ref":"#/components/schemas/MetricsStoreKind","description":"Storage backend actually used for proxy logs, OTel spans, and OTel\nmetrics. OTel logs remain TimescaleDB-backed. Unlike resource metrics,\nthese domains switch to ClickHouse whenever the server-level ClickHouse\nconnection is configured; they do not use the monitoring store toggle."},"external_url":{"type":["string","null"]},"insecure_tls":{"type":"boolean"},"internal_url":{"type":["string","null"]},"letsencrypt":{"$ref":"#/components/schemas/LetsEncryptSettings"},"monitored_services_count":{"type":["integer","null"],"format":"int64","description":"Number of enabled, running services the MetricsScraper currently\nincludes. Used for the lightweight storage estimate in the UI.","minimum":0},"monitoring":{"$ref":"#/components/schemas/MonitoringSettingsMasked"},"multi_node":{"$ref":"#/components/schemas/MultiNodeSettingsMasked"},"observability_compression":{"$ref":"#/components/schemas/ObservabilityCompressionSettings","description":"TimescaleDB compression delays for immutable proxy logs and OTel spans."},"observability_retention":{"$ref":"#/components/schemas/ObservabilityRetentionSettings","description":"Retention windows for raw proxy logs and OpenTelemetry data."},"preview_domain":{"type":"string"},"preview_gateway":{"$ref":"#/components/schemas/PreviewGatewaySettingsMasked"},"rate_limiting":{"$ref":"#/components/schemas/RateLimitSettings"},"require_mfa_for_admins":{"type":"boolean","description":"When enabled, Admin-role accounts without MFA enrolled are rejected\nat password login (bherila/temps#32). SSO/OIDC logins are unaffected."},"screenshots":{"$ref":"#/components/schemas/ScreenshotSettings"},"security_headers":{"$ref":"#/components/schemas/SecurityHeadersSettings"},"self_update":{"$ref":"#/components/schemas/SelfUpdateSettings","description":"Whether admins may apply a release from the console. This is the\ndatabase-backed toggle only — a server started with\n`--disable-self-update` refuses regardless of what this says, which\n`GET /settings/update` reports as the authoritative answer."},"setup_complete":{"type":"boolean","description":"Whether `temps setup` has been run at least once. The web onboarding\nwizard checks this field on load and skips itself when true."}}},"ApplyHostnameModeRequest":{"type":"object","description":"Request to apply a hostname mode (recompute + optional DNS sync).","required":["mode"],"properties":{"mode":{"type":"string","description":"Target mode to apply: `\"standard\"` or `\"flat\"`."},"sync_dns":{"type":"boolean","description":"Also reconcile the provider's DNS zone for the affected hostnames."}}},"ArchiveFlagResponse":{"type":"object","required":["key"],"properties":{"archived_at":{"type":["string","null"]},"key":{"type":"string"}}},"ArchiveMode":{"type":"string","enum":["off","on","always","unknown"]},"AssignRoleRequest":{"type":"object","required":["user_id","role_type"],"properties":{"role_type":{"type":"string"},"user_id":{"type":"integer","format":"int32"}}},"AttachScheduleServicesRequest":{"type":"object","description":"Body for `POST /api/backups/schedules/{id}/services` — attach external\nservices to a backup schedule. Idempotent.","required":["service_ids"],"properties":{"service_ids":{"type":"array","items":{"type":"integer","format":"int32"},"description":"External service ids to attach. Duplicates are de-duplicated server-side."}}},"AttachScheduleServicesResponse":{"type":"object","description":"Response for `POST /api/backups/schedules/{id}/services`.","required":["inserted","total_attached"],"properties":{"inserted":{"type":"integer","format":"int64","description":"Number of rows actually inserted (excludes rows skipped by\n`ON CONFLICT DO NOTHING`).","minimum":0},"total_attached":{"type":"integer","description":"Total number of services now attached to the schedule.","minimum":0}}},"AuditLogIpInfo":{"type":"object","description":"IP address information in audit log","required":["ip"],"properties":{"city":{"type":["string","null"],"description":"City name","example":"San Francisco"},"country":{"type":["string","null"],"description":"Country code","example":"US"},"ip":{"type":"string","description":"IP address","example":"192.168.1.1"},"latitude":{"type":["number","null"],"format":"double","description":"Latitude","example":37.7749},"longitude":{"type":["number","null"],"format":"double","description":"Longitude","example":122.4194}}},"AuditLogResponse":{"type":"object","description":"Response type for audit log entries","required":["id","operation_type","audit_date"],"properties":{"audit_date":{"type":"integer","format":"int64","description":"When the action occurred","example":11932193},"data":{"description":"Additional context about the action"},"id":{"type":"integer","format":"int32","description":"Unique identifier for the audit log entry"},"ip_address":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AuditLogIpInfo","description":"IP address details"}]},"operation_type":{"type":"string","description":"The type of action that was performed","example":"USER_LOGIN"},"user":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AuditLogUserInfo","description":"User details who performed the action"}]},"user_id":{"type":["integer","null"],"format":"int32","description":"The user who performed the action (`null` when that account has\nsince been deleted; `data` retains the original actor context)"}}},"AuditLogUserInfo":{"type":"object","description":"User information in audit log","required":["id","name","email"],"properties":{"email":{"type":"string","description":"User's email","example":"john.doe@example.com"},"id":{"type":"integer","format":"int32","description":"User ID"},"name":{"type":"string","description":"User's name","example":"John Doe"}}},"AuthFlavorDto":{"type":"object","description":"One auth flavor surfaced to the UI. Mirrors `AuthFlavor` in the catalog\nbut without the seed-path / env-var fields the frontend doesn't need\n(those are server-side only — exposing them just bloats the response).","required":["id","label","description","format"],"properties":{"description":{"type":"string"},"env_var":{"type":["string","null"],"description":"For `api_key` format: the env var name that will be set inside the\nsandbox. Useful for showing the user \"we'll set OPENAI_API_KEY\" so\nthey know what their key controls."},"format":{"type":"string","description":"`api_key`, `oauth_token`, or `config_file` — drives which input UI\nthe settings page renders (single-line vs. multi-line textarea)."},"id":{"type":"string"},"label":{"type":"string"}}},"AuthResponse":{"type":"object","required":["success","message","mfa_required","mfa_enrollment_required","password_change_required"],"properties":{"message":{"type":"string"},"mfa_enrollment_required":{"type":"boolean"},"mfa_required":{"type":"boolean"},"mfa_setup":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/MfaSetupResponse"}]},"password_change_required":{"type":"boolean"},"success":{"type":"boolean"},"user_id":{"type":["integer","null"],"format":"int32"}}},"AuthStatusResponse":{"type":"object","required":["status"],"properties":{"cli_token":{"type":["string","null"]},"status":{"type":"string"}}},"AuthTokenResponse":{"type":"object","required":["access_token","refresh_token","expires_at"],"properties":{"access_token":{"type":"string"},"expires_at":{"type":"integer","format":"int64"},"refresh_token":{"type":"string"}}},"AutoWatchParams":{"type":"object","description":"Auto-watch (Watchdog-style) detector parameters (stub — not evaluated).","properties":{"direction":{"$ref":"#/components/schemas/Direction","description":"The engine self-tunes the band; the user supplies only the direction."}}},"AutofixRunConfig":{"type":"object","description":"User-chosen per-run options, persisted as JSON in `agent_runs.run_config`.\nEvery field is optional — unset fields fall back to the provider defaults\nin settings, then to built-in defaults.","properties":{"branch":{"type":["string","null"],"description":"Branch to clone instead of the project's main branch.","default":null},"max_turns":{"type":["integer","null"],"format":"int32","description":"Per-run turn cap applied to every phase of this run. Only enforced\nfor CLIs with a turn flag (Claude Code); Codex/OpenCode run to\ncompletion. `None` uses the provider's per-phase defaults.","default":null},"model":{"type":["string","null"],"description":"Model id for the chosen provider. `None` uses the provider's saved\ndefault model, or the CLI's own default.","default":null},"provider":{"type":["string","null"],"description":"AI provider id (\"claude_cli\", \"codex_cli\", \"opencode\"). `None` uses\nthe platform default provider from agent sandbox settings.","default":null}}},"AutofixerRunResponse":{"type":"object","required":["id","project_id","status","tokens_input","tokens_output","files_changed","created_at"],"properties":{"ai_model":{"type":["string","null"]},"ai_output":{"type":["string","null"]},"ai_provider":{"type":["string","null"],"description":"AI provider slug this run executes with (e.g. claude_cli, codex_cli)."},"analysis":{"type":["string","null"]},"branch_name":{"type":["string","null"]},"completed_at":{"type":["string","null"]},"created_at":{"type":"string"},"error_message":{"type":["string","null"]},"files_changed":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"phase":{"type":["string","null"]},"pr_number":{"type":["integer","null"],"format":"int32"},"pr_url":{"type":["string","null"]},"project_id":{"type":"integer","format":"int32"},"run_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AutofixRunConfig","description":"Per-run options the run was started with; used to prefill the\nretry / start-over dialog."}]},"started_at":{"type":["string","null"]},"status":{"type":"string"},"tokens_input":{"type":"integer","format":"int32"},"tokens_output":{"type":"integer","format":"int32"},"trigger_source_id":{"type":["integer","null"],"format":"int32"},"user_context":{"type":["string","null"]}}},"AutofixerRunWithLogsResponse":{"type":"object","required":["run","logs"],"properties":{"logs":{"type":"array","items":{"$ref":"#/components/schemas/AgentRunLogResponse"}},"run":{"$ref":"#/components/schemas/AutofixerRunResponse"}}},"AvailableContainerInfo":{"type":"object","description":"Available Docker container that can be imported as a service","required":["container_id","container_name","image","version","service_type","is_running"],"properties":{"container_id":{"type":"string","description":"Container ID or name","example":"abc123def456"},"container_name":{"type":"string","description":"Container display name","example":"my-postgres"},"exposed_ports":{"type":"array","items":{"type":"integer","format":"int32","minimum":0},"description":"Exposed ports (e.g., [5432] for PostgreSQL, [6379] for Redis)"},"image":{"type":"string","description":"Docker image name (e.g., \"gotempsh/postgres-walg:18-bookworm\")","example":"gotempsh/postgres-walg:18-bookworm"},"is_running":{"type":"boolean","description":"Whether the container is currently running","example":true},"service_type":{"$ref":"#/components/schemas/ServiceTypeRoute","description":"Service type this container represents"},"version":{"type":"string","description":"Extracted version from image","example":"18"}}},"AvailablePermissions":{"type":"object","description":"Response containing all available permissions for frontend validation","required":["permissions","roles"],"properties":{"permissions":{"type":"array","items":{"$ref":"#/components/schemas/PermissionInfo"},"description":"All available permissions in the system"},"roles":{"type":"array","items":{"$ref":"#/components/schemas/RoleInfo"},"description":"All available roles"}}},"BackupAlertListResponse":{"type":"object","description":"Response body for the list-backup-alerts endpoint.","required":["alerts"],"properties":{"alerts":{"type":"array","items":{"$ref":"#/components/schemas/BackupAlertResponse"},"description":"All currently open (unresolved) alerts, newest first."}}},"BackupAlertResponse":{"type":"object","description":"A single open backup alert surfaced in the UI banner.\n\nAlerts are auto-opened by the watcher and auto-resolved when the triggering\ncondition clears. No manual dismiss is required or supported.\n\nThe optional `schedule_s3_source_id` field is included so the UI can\ndeep-link an `overdue_schedule` alert to the S3 source detail page that\nhosts the schedule. `stalled_job` alerts no longer carry a deep-link\ntarget — the alert message text contains the backup id for display.","required":["id","kind","severity","message","opened_at"],"properties":{"id":{"type":"integer","format":"int64","description":"Database id of the alert row."},"kind":{"type":"string","description":"`\"overdue_schedule\"` or `\"stalled_job\"`."},"message":{"type":"string","description":"Human-readable description of the alert condition."},"opened_at":{"type":"string","description":"RFC 3339 timestamp when the alert was opened.","example":"2026-05-15T10:00:00Z"},"schedule_id":{"type":["integer","null"],"format":"int32","description":"FK to `backup_schedules.id`. Set for `overdue_schedule` alerts."},"schedule_name":{"type":["string","null"],"description":"Human-readable name of the linked schedule, if applicable."},"schedule_s3_source_id":{"type":["integer","null"],"format":"int32","description":"FK to `backup_schedules.s3_source_id`. The UI uses this to deep-link\nthe alert to the S3 source detail page that hosts the schedule.\nSet for `overdue_schedule` alerts."},"severity":{"type":"string","description":"`\"warning\"` or `\"critical\"`."}}},"BackupResponse":{"type":"object","description":"Response type for backup","required":["id","name","backup_id","backup_type","state","started_at","s3_source_id","s3_location","metadata","compression_type","created_by","tags"],"properties":{"attempts":{"type":["integer","null"],"format":"int32","description":"How many times this job has been claimed and run. `null` for legacy\nbackups with no `backup_jobs` row."},"backup_id":{"type":"string"},"backup_type":{"type":"string"},"checksum":{"type":["string","null"]},"completed_at":{"type":["integer","null"],"format":"int64"},"compression_type":{"type":"string"},"created_by":{"type":"integer","format":"int32"},"current_step":{"type":["string","null"],"description":"Name of the engine step currently executing (e.g., `\"walg_push\"`).\n`null` when no `backup_jobs` row exists for this backup (legacy rows\npre-dating ADR-014), or when the job has not yet completed its first step."},"error_message":{"type":["string","null"]},"expires_at":{"type":["integer","null"],"format":"int64"},"external_service":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ExternalServiceSummary","description":"External service that owns this backup (Redis, Postgres, etc.).\n`null` for control-plane backups (the Temps server's own database)."}]},"file_count":{"type":["integer","null"],"format":"int32"},"id":{"type":"integer","format":"int32"},"live_size_bytes":{"type":["integer","null"],"format":"int64","description":"Best-effort partial size while a backup is still running, computed\nby listing the S3 prefix. Null when the backup is finished\n(`size_bytes` is authoritative in that case)."},"max_attempts":{"type":["integer","null"],"format":"int32","description":"Maximum attempts before the job is permanently failed. `null` for\nlegacy backups."},"max_runtime_secs":{"type":["integer","null"],"format":"int64","description":"Resolved wall-clock timeout for this backup job (seconds). `null` for\nlegacy backups. Derived from the three-tier resolution order:\ncaller override → schedule override → engine default."},"metadata":{},"name":{"type":"string"},"s3_location":{"type":"string"},"s3_source_id":{"type":"integer","format":"int32"},"schedule_id":{"type":["integer","null"],"format":"int32"},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Final size of the backup once completed. Null while running."},"started_at":{"type":"integer","format":"int64"},"state":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}}}},"BackupScheduleResponse":{"type":"object","description":"Response type for backup schedule","required":["id","name","backup_type","retention_period","s3_source_id","schedule_expression","enabled","created_at","updated_at","tags","target_all_services","include_control_plane"],"properties":{"backup_type":{"type":"string"},"created_at":{"type":"integer","format":"int64"},"description":{"type":["string","null"]},"enabled":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"include_control_plane":{"type":"boolean","description":"When `true`, every run also produces a `control_plane` backup\n(Temps's own Postgres). When `false`, only the external service\nfan-out happens."},"last_run":{"type":["integer","null"],"format":"int64"},"max_runtime_secs":{"type":["integer","null"],"format":"int64","description":"Per-schedule wall-clock timeout override for backup jobs (seconds).\n`null` means the engine-family default is used. See\n`temps_backup_core::timeouts::default_max_runtime_secs`."},"name":{"type":"string"},"next_run":{"type":["integer","null"],"format":"int64"},"retention_period":{"type":"integer","format":"int32"},"s3_source_id":{"type":"integer","format":"int32"},"schedule_expression":{"type":"string","example":"0 0 * * *"},"tags":{"type":"array","items":{"type":"string"}},"target_all_services":{"type":"boolean","description":"When `true`, the schedule auto-includes every external service on\nthe host (and any future ones). When `false`, the schedule only\ntargets services attached via `backup_schedule_services`."},"updated_at":{"type":"integer","format":"int64"}}},"BitbucketAuthInput":{"oneOf":[{"type":"object","description":"Personal / Workspace / Repository Access Token.","required":["token","type"],"properties":{"token":{"type":"string","description":"The Bitbucket access token value."},"type":{"type":"string","enum":["access_token"]}}},{"type":"object","description":"HTTP Basic / App Password authentication.","required":["username","password","type"],"properties":{"password":{"type":"string","description":"App password generated in Bitbucket security settings."},"type":{"type":"string","enum":["app_password"]},"username":{"type":"string","description":"Bitbucket account username."}}}],"description":"Authentication input for a Bitbucket Cloud provider. Use `access_token` for\na Repository or Workspace Access Token (PAT), or `username` + `app_password`\nfor App Password (HTTP Basic) authentication."},"BlobResponse":{"type":"object","description":"Response after uploading a blob","required":["url","pathname","contentType","size","uploadedAt"],"properties":{"contentType":{"type":"string","description":"Content type of the blob","example":"image/png"},"pathname":{"type":"string","description":"Original pathname","example":"images/avatar-abc123.png"},"size":{"type":"integer","format":"int64","description":"Size in bytes","example":12345},"uploadedAt":{"type":"string","format":"date-time","description":"Upload timestamp","example":"2025-01-03T12:00:00Z"},"url":{"type":"string","description":"URL path to access the blob","example":"/api/blob/123/images/avatar-abc123.png"}}},"BlobStatusResponse":{"type":"object","description":"Response for Blob service status","required":["enabled","healthy"],"properties":{"docker_image":{"type":["string","null"],"description":"Docker image being used","example":"ghcr.io/rustfs/rustfs:0.5.0"},"enabled":{"type":"boolean","description":"Whether the Blob service is enabled","example":true},"healthy":{"type":"boolean","description":"Whether the service is healthy","example":true},"version":{"type":["string","null"],"description":"Current version (if running)","example":"0.5.0"}}},"BranchInfo":{"type":"object","required":["name","commit_sha","protected"],"properties":{"commit_sha":{"type":"string"},"name":{"type":"string"},"protected":{"type":"boolean"}}},"BranchListResponse":{"type":"object","required":["branches"],"properties":{"branches":{"type":"array","items":{"$ref":"#/components/schemas/BranchInfo"}}}},"BrowserCount":{"type":"object","required":["browser","count","percentage"],"properties":{"browser":{"type":"string"},"count":{"type":"integer","format":"int64"},"percentage":{"type":"number","format":"double"}}},"BrowsersQuery":{"type":"object","required":["start_date","end_date","project_id"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"BuildConfiguration":{"type":"object","description":"Build configuration (for building images from source)","required":["context","args"],"properties":{"args":{"type":"object","description":"Build arguments","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"context":{"type":"string","description":"Build context (Dockerfile path or buildpack)"},"dockerfile":{"type":["string","null"],"description":"Dockerfile path (relative to context)"},"target":{"type":["string","null"],"description":"Target stage (for multi-stage builds)"}}},"BuildLimitsSettings":{"type":"object","description":"Control-plane build resource limits.\n\nCaps how many builds run concurrently AND how much CPU/memory each build\nis allowed to consume. A single global semaphore in the deployer crate\ngates every `DockerRuntime::build_image` call to `max_concurrent`. When\nthe semaphore is full, additional builds queue and wait — they do not\nfail. Per-build CPU/memory caps are forwarded to Docker via\n`BuildImageOptions { memory, cpuquota, cpuperiod }`.\n\n`cpu_limit_cores = 0.0` or `memory_limit_mb = 0` means \"no explicit cap\"\n— fall back to the legacy 50%-of-host heuristic for backwards\ncompatibility with operators who never visit the settings page.","properties":{"cpu_limit_cores":{"type":"number","format":"float","description":"CPU cores allowed per build (float, e.g. 2.0 = 2 cores, 0.5 = half\na core). 0 means \"use the legacy 50%-of-host default\".","default":0.0,"example":2.0,"minimum":0},"max_concurrent":{"type":"integer","format":"int32","description":"Maximum number of `docker build` operations allowed to run at the\nsame time on the control plane. Additional builds queue. Min 1.","default":2,"example":2,"minimum":1},"memory_limit_mb":{"type":"integer","format":"int32","description":"Memory allowed per build, in megabytes. 0 means \"use the legacy\n50%-of-host default\". Docker enforces this as a hard cap — builds\nthat exceed it OOM-kill.","default":0,"example":2048,"minimum":0}}},"CancelBackupResponse":{"type":"object","description":"Response body for cancel endpoints.","required":["cancelled"],"properties":{"cancelled":{"type":"integer","format":"int64","description":"Number of rows that were actually flipped to `failed`. `0` is a valid\nsuccess and means the backup was already terminal — the call is\nidempotent.","minimum":0}}},"CertStatusResponse":{"type":"object","description":"Current on-demand cert status for a single hostname (ADR-018 §5). Backs\n`GET /domains/by-host/{hostname}/cert-status`.","required":["hostname"],"properties":{"backoff_until":{"type":["integer","null"],"format":"int64","description":"On-demand negative-cache deadline (epoch millis), when in backoff."},"hostname":{"type":"string","description":"SNI hostname."},"last_attempt":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/OnDemandCertAttemptResponse","description":"The most recent on-demand issuance attempt for this hostname, if any."}]},"status":{"type":["string","null"],"description":"Current cert lifecycle status from the `domains` row, when one exists."}}},"ChallengeConfig":{"type":"object","description":"Challenge configuration (future feature)\nFor CAPTCHA, JS challenges, proof-of-work, etc.","required":["challengeType","difficulty"],"properties":{"challengeType":{"type":"string","description":"Challenge type: \"captcha\", \"js_challenge\", \"proof_of_work\""},"difficulty":{"type":"integer","format":"int32","description":"Challenge difficulty level (1-10)","minimum":0},"protectedPaths":{"type":"array","items":{"type":"string"},"description":"Paths that require challenges"}}},"ChallengeError":{"type":"object","required":["type","detail","status"],"properties":{"detail":{"type":"string","description":"Human-readable error description"},"status":{"type":"integer","format":"int32","description":"HTTP status code"},"type":{"type":"string","description":"Error type (e.g., \"urn:ietf:params:acme:error:unauthorized\")"}}},"ChallengeValidationStatus":{"type":"object","required":["type","url","status","token"],"properties":{"error":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ChallengeError","description":"Error details if validation failed"}]},"status":{"type":"string","description":"Challenge status (e.g., \"pending\", \"valid\", \"invalid\")"},"token":{"type":"string","description":"Challenge token"},"type":{"type":"string","description":"Challenge type (e.g., \"dns-01\", \"http-01\")"},"url":{"type":"string","description":"Challenge validation URL"},"validated":{"type":["string","null"],"description":"When the challenge was validated (if successful)"}}},"ChangePasswordRequest":{"type":"object","required":["current_password","new_password"],"properties":{"current_password":{"type":"string","example":"current_password_value"},"mfa_code":{"type":["string","null"],"description":"TOTP code (or recovery code). Required iff the user has MFA enabled.","example":"123456"},"new_password":{"type":"string","example":"new_password_value"},"revoke_other_sessions":{"type":"boolean","description":"When true, every session OTHER than the one making this request is\nrevoked. Defaults to false; the UI surfaces this as a checkbox."}}},"ChangeProjectSourceRequest":{"type":"object","description":"Change a project's source type to a Git-less type (docker_image /\nstatic_files / manual). Switching TO `git` is done via the Git settings\nendpoint (which also supplies the repository + provider connection).","required":["source_type"],"properties":{"source_type":{"$ref":"#/components/schemas/SourceType"}}},"ChatCompletionChoice":{"type":"object","required":["index","message"],"properties":{"finish_reason":{"type":["string","null"]},"index":{"type":"integer","format":"int32"},"message":{"$ref":"#/components/schemas/ChatMessage"}}},"ChatCompletionRequest":{"allOf":[{"type":["object","null"],"description":"Tolerates extra SDK fields (stream_options, logprobs, etc.)","additionalProperties":{},"propertyNames":{"type":"string"}},{"type":"object","required":["model","messages"],"properties":{"frequency_penalty":{"type":["number","null"],"format":"double"},"max_tokens":{"type":["integer","null"],"format":"int64"},"messages":{"type":"array","items":{"$ref":"#/components/schemas/ChatMessage"}},"model":{"type":"string"},"n":{"type":["integer","null"],"format":"int32"},"presence_penalty":{"type":["number","null"],"format":"double"},"response_format":{},"seed":{"type":["integer","null"],"format":"int64"},"stop":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/StopSequence"}]},"stream":{"type":"boolean"},"temperature":{"type":["number","null"],"format":"double"},"tool_choice":{},"tools":{"type":["array","null"],"items":{}},"top_p":{"type":["number","null"],"format":"double"},"user":{"type":["string","null"]}}}],"description":"OpenAI-compatible chat completion request.\nUses `deny_unknown_fields = false` (serde default) so that SDK-specific\nfields like `stream_options`, `logprobs`, `top_logprobs`, `logit_bias`,\n`parallel_tool_calls`, etc. are silently accepted without breaking."},"ChatCompletionResponse":{"type":"object","required":["id","object","created","model","choices"],"properties":{"choices":{"type":"array","items":{"$ref":"#/components/schemas/ChatCompletionChoice"}},"created":{"type":"integer","format":"int64"},"id":{"type":"string"},"model":{"type":"string"},"object":{"type":"string"},"usage":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/UsageInfo"}]}}},"ChatMessage":{"type":"object","required":["role"],"properties":{"content":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/MessageContent"}]},"name":{"type":["string","null"]},"role":{"type":"string"},"tool_call_id":{"type":["string","null"]},"tool_calls":{"type":["array","null"],"items":{}}}},"ChatReadinessResponse":{"type":"object","description":"What still has to be true before an AI chat can run a turn in this project.\n\nThe three gates are independent and fail for different reasons with different\nfixes, so they are reported separately rather than collapsed into one boolean:\nan instance admin configures a provider (instance-wide), while the two toggles\nare per-project. Collapsing them would leave the user with \"AI unavailable\"\nand no idea which of three places to go.","required":["ai_configured","chat_enabled","write_actions_enabled"],"properties":{"ai_configured":{"type":"boolean","description":"An AI provider is configured on this instance. Fixed in\nSettings → AI Providers; instance-wide, not per project."},"chat_enabled":{"type":"boolean","description":"The per-project read-only chat toggle is on (the default)."},"write_actions_enabled":{"type":"boolean","description":"The per-project write-actions opt-in is on. Required for any flow where\nthe assistant *proposes* changes; irrelevant for read-only questions."}}},"ChildBackupEntryResponse":{"type":"object","description":"A single child backup entry in the `GET /backups/{id}/children` response.\n\nEach entry corresponds to one `external_service_backups` row joined with\n`external_services`, providing service metadata without a second request.","required":["id","service_id","service_name","service_type","state","backup_type","started_at","s3_location","compression_type"],"properties":{"backup_type":{"type":"string","description":"Backup variant (e.g. \"full\", \"incremental\")."},"compression_type":{"type":"string","description":"Compression algorithm used (e.g. \"gzip\", \"lz4\")."},"error_message":{"type":["string","null"],"description":"Engine-reported error message when `state = \"failed\"`."},"finished_at":{"type":["string","null"],"description":"When the child backup finished, if known.","example":"2025-01-15T14:35:00.456Z"},"id":{"type":"integer","format":"int32","description":"Row ID from `external_service_backups`."},"s3_location":{"type":"string","description":"Object key or `s3://` URL where the backup data lives."},"service_id":{"type":"integer","format":"int32","description":"FK to `external_services.id`."},"service_name":{"type":"string","description":"Human-readable name of the external service (e.g. \"redis-prod\")."},"service_type":{"type":"string","description":"Service type string (e.g. \"postgres\", \"redis\", \"mongodb\", \"s3\").","example":"postgres"},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Size of the child backup in bytes, if available."},"started_at":{"type":"string","description":"When the child backup started (RFC 3339).","example":"2025-01-15T14:30:00.123Z"},"state":{"type":"string","description":"Current state: \"pending\" | \"running\" | \"completed\" | \"failed\"."}}},"ChildBackupListResponse":{"type":"object","description":"Response body for `GET /backups/{id}/children`.\n\nReturns an empty `children` list (not 404) when the parent backup has no\nchild records (e.g. control-plane backups).","required":["children"],"properties":{"children":{"type":"array","items":{"$ref":"#/components/schemas/ChildBackupEntryResponse"},"description":"Zero or more child backup entries ordered by `external_service_backups.id` ASC."}}},"CleanupExpiredBackupsRequest":{"type":"object","properties":{"expected_backup_ids":{"type":["array","null"],"items":{"type":"string"},"description":"Exact candidates returned by the dry run. Execution fails if the\nretention selection has changed since preview."}}},"CliDeviceApproveRequest":{"type":"object","required":["user_code"],"properties":{"user_code":{"type":"string"}}},"CliDeviceApproveResponse":{"type":"object","required":["user_code","status"],"properties":{"status":{"type":"string"},"user_code":{"type":"string"}}},"CliDeviceLookupResponse":{"type":"object","required":["user_code","status","expires_at"],"properties":{"client_name":{"type":["string","null"]},"expires_at":{"type":"string","format":"date-time"},"requested_ip":{"type":["string","null"]},"status":{"type":"string","description":"`pending` | `approved` | `denied` | `expired`."},"user_code":{"type":"string"}}},"CliDevicePollRequest":{"type":"object","required":["device_code"],"properties":{"device_code":{"type":"string"}}},"CliDevicePollResponse":{"oneOf":[{"type":"object","description":"Still waiting on the user to approve in the browser.","required":["status"],"properties":{"status":{"type":"string","enum":["authorization_pending"]}}},{"type":"object","description":"CLI is polling faster than the server-suggested interval.","required":["status"],"properties":{"status":{"type":"string","enum":["slow_down"]}}},{"type":"object","description":"User denied the request in the browser.","required":["status"],"properties":{"status":{"type":"string","enum":["access_denied"]}}},{"type":"object","description":"The session has expired without approval.","required":["status"],"properties":{"status":{"type":"string","enum":["expired_token"]}}},{"type":"object","description":"The session was approved; this is the only response that carries\nthe API key. The key is returned exactly once and then cleared\nfrom the session row.","required":["user_id","email","role","api_key","key_prefix","status"],"properties":{"api_key":{"type":"string"},"email":{"type":"string"},"expires_at":{"type":["string","null"],"format":"date-time"},"key_prefix":{"type":"string"},"role":{"type":"string"},"status":{"type":"string","enum":["approved"]},"user_id":{"type":"integer","format":"int32"}}}]},"CliDeviceStartRequest":{"type":"object","properties":{"client_name":{"type":["string","null"],"description":"Friendly hostname / client identifier shown in the browser approval\nscreen. Sanitized before display.","example":"dviejo-mac.local"}}},"CliDeviceStartResponse":{"type":"object","required":["device_code","user_code","verification_uri","verification_uri_complete","expires_in","interval"],"properties":{"device_code":{"type":"string","description":"Opaque secret the CLI polls with. Never display to a human."},"expires_in":{"type":"integer","format":"int64","description":"Seconds until the device_code expires."},"interval":{"type":"integer","format":"int64","description":"Suggested polling interval, in seconds."},"user_code":{"type":"string","description":"Short human-readable code the user types into the browser.","example":"ABCD-1234"},"verification_uri":{"type":"string","description":"Base verification URL — the CLI may display this when the\npre-filled URL is too long to be useful.","example":"https://temps.example.com/cli-login"},"verification_uri_complete":{"type":"string","description":"`verification_uri` with `user_code` pre-filled. Open this directly.","example":"https://temps.example.com/cli-login/ABCD-1234"}}},"CliLoginRequest":{"type":"object","required":["username","password"],"properties":{"password":{"type":"string"},"username":{"type":"string"}}},"CloudProvider":{"type":"string","description":"Cloud provider detected from node metadata","enum":["aws","gcp","azure","hetzner","digitalocean","other"]},"CloudflareConfig":{"type":"object","description":"Configuration for a Cloudflare Email Sending notification provider.\n\nNotifications are delivered through Cloudflare's transactional Email Sending\nAPI. Only the account, token, sender and recipients are configured here —\nsubject and body are derived from each notification.","required":["account_id","api_token","from_address","to_addresses"],"properties":{"account_id":{"type":"string","description":"Cloudflare account id that owns the Email Sending configuration.","example":"023e105f4ecef8ad9ca31a8372d0c353"},"api_token":{"type":"string","description":"Cloudflare API token with the Email Sending permission. Encrypted at\nrest and masked in normal API responses."},"from_address":{"type":"string","description":"Verified sender address (must belong to a domain enabled for Cloudflare\nEmail Sending).","example":"welcome@infracf.example.com"},"from_name":{"type":["string","null"],"description":"Optional human-friendly sender name shown in the recipient's inbox."},"to_addresses":{"type":"array","items":{"type":"string"},"description":"Recipients that should receive the notification."}}},"ClusterCapacity":{"type":"object","description":"Total cluster capacity (sum of node allocatable resources)","required":["node_count","cpu_millis","memory_mb"],"properties":{"cpu_millis":{"type":"integer","format":"int64","description":"Total allocatable CPU in millicores"},"memory_mb":{"type":"integer","format":"int64","description":"Total allocatable memory in MB"},"node_count":{"type":"integer","description":"Number of nodes","minimum":0}}},"ClusterDnsSettings":{"type":"object","description":"Cluster-DNS resolver settings (ADR-024, experimental beta).\n\nWhen `enabled`, the Temps control plane starts a Hickory DNS resolver and\ninjects it as the first nameserver into every deployed container via\n`HostConfig.Dns` — giving containers the ability to resolve `*.temps.local`\nFQDNs for service-to-service communication. Worker nodes pick this flag up\nfrom the `/api/internal/nodes/{id}/network/peers` wire response and gate\ntheir own per-node resolver the same way.\n\n**Default: `false` (disabled).**\n\nWhy disabled by default: a production incident showed that when the injected\nHickory resolver was slow or transiently unresponsive for a non-`*.temps.local`\n(external) hostname, glibc's resolver cycled through all three nameservers\n(`172.20.0.1`, `1.1.1.1`, `8.8.8.8`) at ~5 s timeout × 2 attempts each,\ncausing 22–27 s delays for outbound TCP connections. Disabling the injection\nrestores Docker's embedded DNS as the sole resolver, eliminating that failure\nmode. Operators running single/multi-node installs that depend on\n`*.temps.local` resolution must explicitly opt in by setting `enabled: true`.\n\n`bool` defaults to `false` in Rust and JSON (`#[serde(default)]`), so the\nsafe-off behaviour is automatic for new installs and legacy settings rows.","properties":{"enabled":{"type":"boolean","description":"Master switch. When `false` (default), no custom DNS is injected into\ncontainers — they use Docker's embedded DNS which forwards to the host's\nown `resolv.conf`. When `true`, the control-plane Hickory resolver is\nstarted and its bridge IP is injected as the first nameserver so\n`*.temps.local` FQDNs resolve inside containers.","default":false,"example":false}}},"ClusterHealthReportResponse":{"type":"object","description":"Response body for `GET /external-services/{id}/cluster-health`.","required":["checked_at","monitor_response_ms","members"],"properties":{"checked_at":{"type":"string","description":"ISO-8601 wall-clock when the report was generated.","example":"2025-10-12T12:15:47.609192Z"},"members":{"type":"array","items":{"$ref":"#/components/schemas/ClusterMemberHealthResponse"}},"monitor_error":{"type":["string","null"],"description":"Set when the monitor itself was unreachable. UI shows a banner."},"monitor_response_ms":{"type":"integer","format":"int64","description":"Round-trip to query the monitor (ms)."}}},"ClusterMemberHealthResponse":{"type":"object","description":"One row in the cluster Members table — see `GET /external-services/{id}/cluster-health`.","required":["nodename","nodehost","nodeport","reported_state","goal_state","health","seconds_since_report","candidate_priority","replication_quorum"],"properties":{"candidate_priority":{"type":"integer","format":"int32"},"goal_state":{"type":"string","description":"What the monitor *wants* the node to be. Differs from\n`reported_state` mid-transition (failover, demotion, etc.)."},"health":{"type":"integer","format":"int32","description":"pg_auto_failover liveness signal: `1` healthy, `0` unknown\n(no recent report), `-1` unhealthy."},"nodehost":{"type":"string"},"nodename":{"type":"string"},"nodeport":{"type":"integer","format":"int32"},"replay_lag_ms":{"type":["integer","null"],"format":"int64","description":"`replay_lag` from `pg_stat_replication`, in milliseconds."},"replication_quorum":{"type":"boolean"},"reported_state":{"type":"string","description":"What the node *last told the monitor* it was. Stale during outages."},"seconds_since_report":{"type":"integer","format":"int64","description":"Wall-clock seconds since the node last reported in."},"sync_state":{"type":["string","null"],"description":"`sync` / `quorum` / `async` for secondaries; `null` for the primary."}}},"ClusterMemberRequest":{"type":"object","description":"Request spec for a single cluster member.","required":["role"],"properties":{"node_id":{"type":["integer","null"],"format":"int32","description":"Target worker node ID. Omit or null to run on the control plane."},"role":{"type":"string","description":"Service-type-specific role (e.g., \"monitor\", \"primary\", \"replica\")","example":"primary"}}},"CmdBody":{"type":"object","required":["command"],"properties":{"args":{"type":"array","items":{"type":"string"},"description":"Arguments to pass to the binary. Defaults to empty."},"command":{"type":"string","description":"Binary name (argv[0]) — e.g. `\"ls\"`, `\"node\"`. The SDK sends this\nseparately from `args`."},"cwd":{"type":["string","null"],"description":"Working directory override."},"env":{"type":"object","description":"Extra env vars.","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"sudo":{"type":"boolean","description":"When true, the SDK runs the command privileged. We ignore it today\n— the underlying provider always runs as the sandbox's own user."},"wait":{"type":"boolean","description":"When true, the response is an `application/x-ndjson` stream where\nthe first line is the running-command envelope and the second line\nis the finished-command envelope with `exitCode`."}}},"CmdInner":{"type":"object","description":"Inner `command` object — matches the SDK's zod validator exactly.\n`exitCode` is `null` until the command terminates; `startedAt` is Unix\nepoch milliseconds.","required":["id","name","args","cwd","sandboxId","startedAt"],"properties":{"args":{"type":"array","items":{"type":"string"}},"cwd":{"type":"string"},"exitCode":{"type":["integer","null"],"format":"int32"},"id":{"type":"string"},"name":{"type":"string"},"sandboxId":{"type":"string"},"startedAt":{"type":"integer","format":"int64"}}},"CmdKillBody":{"type":"object","description":"SDK-shaped kill body. The SDK sends `{signal: AbortSignal}` but only\nuses the signal for HTTP request abortion client-side; there's no\nsignal name on the wire.","properties":{"force":{"type":"boolean","description":"Optional: when true, SIGKILL instead of SIGTERM."}}},"CmdResponse":{"type":"object","description":"`@vercel/sandbox` envelope: `{ command: {...} }`.","required":["command"],"properties":{"command":{"$ref":"#/components/schemas/CmdInner"}}},"CommitExistsResponse":{"type":"object","required":["exists"],"properties":{"commit":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/CommitInfo","description":"Commit metadata when the requested SHA exists."}]},"commit_sha":{"type":["string","null"]},"exists":{"type":"boolean"}}},"CommitInfo":{"type":"object","required":["sha","message","author","author_email","date"],"properties":{"author":{"type":"string","description":"Author name"},"author_email":{"type":"string","description":"Author email"},"date":{"type":"string","format":"date-time","description":"Commit date in ISO 8601 format","example":"2025-10-12T12:15:47.609192Z"},"message":{"type":"string","description":"Commit message"},"sha":{"type":"string","description":"Commit SHA hash"}}},"CommitListResponse":{"type":"object","required":["commits"],"properties":{"commits":{"type":"array","items":{"$ref":"#/components/schemas/CommitInfo"}}}},"Comparator":{"type":"string","description":"Comparator for static/forecast threshold detectors. Serializes to the\nkeyword forms `gt|gte|lt|lte` (NOT the SQL operators used by\n`temps-monitoring::compare`).","enum":["gt","gte","lt","lte"]},"ComposePublicPort":{"type":"object","description":"A port that should be exposed publicly through the proxy for a compose service.","required":["service","port"],"properties":{"port":{"type":"integer","format":"int32","description":"Container port to expose (e.g. 8123)","minimum":0},"service":{"type":"string","description":"Compose service name (e.g. \"web\", \"clickhouse\")"}}},"ConnectionListQuery":{"type":"object","properties":{"direction":{"type":["string","null"]},"page":{"type":["integer","null"],"format":"int64","minimum":0},"per_page":{"type":["integer","null"],"format":"int64","minimum":0},"sort":{"type":["string","null"]}}},"ConnectionListResponse":{"type":"object","required":["connections","total_count","page","per_page"],"properties":{"connections":{"type":"array","items":{"$ref":"#/components/schemas/ConnectionResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"per_page":{"type":"integer","format":"int64","minimum":0},"total_count":{"type":"integer","minimum":0}}},"ConnectionResponse":{"type":"object","required":["id","provider_id","account_name","account_type","is_active","is_expired","syncing","synced_repository_count","health_status","consecutive_health_failures","created_at","updated_at"],"properties":{"account_name":{"type":"string"},"account_type":{"type":"string"},"consecutive_health_failures":{"type":"integer","format":"int32"},"created_at":{"type":"string","format":"date-time"},"health_message":{"type":["string","null"],"description":"Human-readable reason when health_status is \"unhealthy\"; null otherwise."},"health_status":{"type":"string","description":"Current health status: \"healthy\", \"unhealthy\", or \"unknown\"."},"id":{"type":"integer","format":"int32"},"installation_id":{"type":["string","null"]},"is_active":{"type":"boolean"},"is_expired":{"type":"boolean"},"last_health_check_at":{"type":["string","null"],"format":"date-time"},"last_synced_at":{"type":["string","null"],"format":"date-time"},"provider_id":{"type":"integer","format":"int32"},"synced_repository_count":{"type":"integer","format":"int32","description":"Running count of repositories persisted by the current (or most\nrecent) sync. Resets to 0 when a new sync begins; useful for showing\nlive progress on large syncs."},"syncing":{"type":"boolean"},"updated_at":{"type":"string","format":"date-time"},"user_id":{"type":["integer","null"],"format":"int32"}}},"ConnectionTestResult":{"type":"object","description":"Connection test result","required":["success","message"],"properties":{"message":{"type":"string"},"success":{"type":"boolean"}}},"ConsoleEventPayload":{"type":"object","description":"Payload for server-side event ingestion via the console API.\n\nThe app backend reads the encrypted `_temps_visitor_id` and `_temps_sid`\ncookie values from the user's request and forwards them here.\nTemps decrypts them server-side to resolve visitor/session identity.","required":["event_name","environment_id","deployment_id"],"properties":{"deployment_id":{"type":"integer","format":"int32","description":"Deployment ID to attribute the event to"},"environment_id":{"type":"integer","format":"int32","description":"Environment ID to attribute the event to"},"event_data":{"description":"Arbitrary JSON event data"},"event_name":{"type":"string","description":"Event name (e.g. \"purchase\", \"signup\", custom event names)"},"request_path":{"type":"string","description":"Page path context (defaults to \"/\")"},"request_query":{"type":"string","description":"Query string context"},"session_id":{"type":["string","null"],"description":"Encrypted `_temps_sid` cookie value from the user's browser"},"visitor_id":{"type":["string","null"],"description":"Encrypted `_temps_visitor_id` cookie value from the user's browser"}}},"ContainerActionResponse":{"type":"object","description":"Response indicating success of container state change","required":["container_id","container_name","action","status","message"],"properties":{"action":{"type":"string"},"container_id":{"type":"string"},"container_name":{"type":"string"},"message":{"type":"string"},"status":{"type":"string"}}},"ContainerDetailResponse":{"type":"object","description":"Detailed container information with environment variables and metrics","required":["id","container_id","container_name","image_name","status","deployment_id","created_at","deployed_at","container_port","environment_variables"],"properties":{"container_id":{"type":"string"},"container_name":{"type":"string"},"container_port":{"type":"integer","format":"int32","description":"Port inside the container"},"cpu_limit_cores":{"type":["number","null"],"format":"double","description":"CPU limit in whole cores (e.g. 1.0). None when no limit is configured."},"created_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"deployed_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"deployment_id":{"type":"integer","format":"int32"},"environment_variables":{"type":"array","items":{"$ref":"#/components/schemas/EnvVarResponse"},"description":"Environment variables (sensitive values masked)"},"error_message":{"type":["string","null"],"description":"Free-form error string from Docker's container state on exit."},"exit_code":{"type":["integer","null"],"format":"int32","description":"Process exit code reported by Docker. None while still running."},"exit_reason":{"type":["string","null"],"description":"Human-readable reason the container exited."},"finished_at":{"type":["string","null"],"description":"When the container exited (Docker's FinishedAt). None while running.","example":"2025-10-12T12:16:47.609192Z"},"host_port":{"type":["integer","null"],"format":"int32","description":"Port on the host machine"},"id":{"type":"integer","format":"int32"},"image_name":{"type":"string"},"oom_killed":{"type":["boolean","null"],"description":"True when Docker's OOM killer terminated the container."},"ready_at":{"type":["string","null"],"example":"2025-10-12T12:16:47.609192Z"},"resource_limits":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ResourceLimitsResponse","description":"Resource limits"}]},"restart_count":{"type":["integer","null"],"format":"int64","description":"Container restart count from Docker"},"service_name":{"type":["string","null"],"description":"Compose service name (e.g. \"web\", \"redis\"). None for single-container deployments."},"service_url":{"type":["string","null"],"description":"Per-service URL for compose deployments"},"started_at":{"type":["string","null"],"description":"When the container's main process most recently started.","example":"2025-10-12T12:15:50.000000Z"},"status":{"type":"string"}}},"ContainerEnvironmentVariableValueResponse":{"type":"object","required":["value"],"properties":{"value":{"type":"string"}}},"ContainerInfoResponse":{"type":"object","required":["container_id","container_name","image_name","status","created_at"],"properties":{"container_id":{"type":"string"},"container_name":{"type":"string"},"cpu_limit_cores":{"type":["number","null"],"format":"double","description":"CPU limit in whole cores (e.g. 1.0). None when no limit is configured."},"created_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"error_message":{"type":["string","null"],"description":"Free-form error string from Docker's container state on exit."},"exit_code":{"type":["integer","null"],"format":"int32","description":"Process exit code reported by Docker. None while still running."},"exit_reason":{"type":["string","null"],"description":"Human-readable reason the container exited (e.g. \"OOMKilled\",\n\"Killed by SIGKILL (exit code 137)\", \"Exit code 1\"). None while running."},"finished_at":{"type":["string","null"],"description":"When the container exited (Docker's FinishedAt). None while running.","example":"2025-10-12T12:16:47.609192Z"},"image_name":{"type":"string"},"node_name":{"type":["string","null"],"description":"Node name where this container is running. None for local (single-node) deployments."},"oom_killed":{"type":["boolean","null"],"description":"True when Docker's OOM killer terminated the container."},"restart_count":{"type":["integer","null"],"format":"int64","description":"Container restart count from Docker. The UI shows a chip when this is\n> 0 so a crash loop is visible without opening detail."},"service_name":{"type":["string","null"],"description":"Compose service name (e.g. \"web\", \"redis\"). None for single-container deployments."},"service_url":{"type":["string","null"],"description":"Per-service URL for compose deployments (e.g. \"https://web-myapp.localho.st\")"},"started_at":{"type":["string","null"],"description":"When the container's main process most recently started. The UI uses\nthis for the uptime label so the count resets when a container is\nrestarted in place. None for containers that never started.","example":"2025-10-12T12:15:50.000000Z"},"status":{"type":"string"}}},"ContainerInventoryItem":{"type":"object","description":"A container reported by the agent during heartbeat reconciliation.","required":["container_id","container_name"],"properties":{"container_id":{"type":"string","description":"Docker container ID"},"container_name":{"type":"string","description":"Docker container name"}}},"ContainerListResponse":{"type":"object","required":["containers","total"],"properties":{"containers":{"type":"array","items":{"$ref":"#/components/schemas/ContainerInfoResponse"}},"total":{"type":"integer","minimum":0}}},"ContainerLogSettings":{"type":"object","description":"Docker container log rotation settings\nControls the `--log-opt max-size` and `--log-opt max-file` for containers","properties":{"max_file":{"type":"integer","format":"int32","description":"Maximum number of rotated log files to keep (e.g., 3 means up to 3 x max_size total)","default":3,"example":3,"minimum":0},"max_size":{"type":"string","description":"Maximum size of each log file (e.g., \"50m\", \"100m\", \"1g\")\nDocker default is unlimited; we default to \"50m\" to prevent disk exhaustion","default":"50m","example":"50m"},"service_max_file":{"type":"integer","format":"int32","description":"Maximum rotated log files for external service containers","default":3,"example":3,"minimum":0},"service_max_size":{"type":"string","description":"Maximum size for external service container logs (postgres, redis, etc.)\nDefaults to \"20m\" since services are typically less verbose than app containers","default":"20m","example":"20m"}}},"ContainerLogsQuery":{"type":"object","properties":{"container_name":{"type":["string","null"],"description":"Optional container name to get logs from (if deployment has multiple containers)"},"end_date":{"type":["integer","null"],"format":"int64"},"follow":{"type":"boolean","description":"Follow log output in real-time (default: true for backward compatibility)"},"start_date":{"type":["integer","null"],"format":"int64"},"tail":{"type":["string","null"]},"timestamps":{"type":"boolean","description":"Include timestamps in log output (default: false)"}}},"ContainerMetricHistoryPoint":{"type":"object","description":"One bucketed data point of a container resource metric time series.","required":["time","value"],"properties":{"time":{"type":"string","description":"Bucket timestamp (ISO 8601 with `Z` suffix).","example":"2025-10-12T12:15:00+00:00"},"value":{"type":"number","format":"double","description":"Averaged metric value for the bucket."}}},"ContainerMetricsHistoryQuery":{"type":"object","description":"Query parameters for the container metrics history endpoint.","required":["metric"],"properties":{"metric":{"type":"string","description":"Dotted metric name, e.g. `container.cpu_percent` or\n`container.memory_used_bytes`."},"range":{"type":"string","description":"Time window: `1h`, `6h`, `24h`, or `7d` (defaults to `1h`)."}}},"ContainerMetricsResponse":{"type":"object","description":"Container resource metrics (CPU, memory usage)","required":["container_id","container_name","cpu_percent","memory_bytes","network_rx_bytes","network_tx_bytes","timestamp"],"properties":{"container_id":{"type":"string"},"container_name":{"type":"string"},"cpu_limit_cores":{"type":["number","null"],"format":"double","description":"CPU limit in whole cores (e.g. 1.0). None = no limit."},"cpu_percent":{"type":"number","format":"double","description":"CPU usage as a multi-core percentage (Docker convention: 200 = 2 cores\nfully pinned). Divide by 100 to get cores used."},"memory_bytes":{"type":"integer","format":"int64","description":"Memory usage in bytes","minimum":0},"memory_limit_bytes":{"type":["integer","null"],"format":"int64","description":"Memory limit in bytes (if set)","minimum":0},"memory_percent":{"type":["number","null"],"format":"double","description":"Memory usage percentage (0-100) if limit is set"},"network_rx_bytes":{"type":"integer","format":"int64","description":"Network bytes received","minimum":0},"network_tx_bytes":{"type":"integer","format":"int64","description":"Network bytes transmitted","minimum":0},"timestamp":{"type":"string","description":"Timestamp of metrics collection","example":"2025-10-12T12:15:47.609192Z"}}},"ContainerResponse":{"type":"object","required":["name","container_type","can_contain_containers","can_contain_entities","metadata"],"properties":{"can_contain_containers":{"type":"boolean","description":"Can this container hold other containers?","example":true},"can_contain_entities":{"type":"boolean","description":"Can this container hold entities (tables, collections, etc.)?","example":false},"child_container_type":{"type":["string","null"],"description":"Type of child containers (if can_contain_containers is true)","example":"schema"},"container_type":{"type":"string","description":"Container type (database, schema, keyspace, bucket, etc.)","example":"database"},"entity_count_hint":{"type":["string","null"],"description":"Hint for UI on expected entity count (small = sidebar, large = pagination)","example":"large"},"entity_type_label":{"type":["string","null"],"description":"Label for entity type (if can_contain_entities is true)","example":"table"},"metadata":{"description":"Additional metadata"},"name":{"type":"string","description":"Container name","example":"mydb"}}},"ContainerRuntimeInfo":{"type":"object","description":"Snapshot of a container's lifecycle state from `docker inspect`.\n`restart_count` and `oom_killed` are the load-bearing fields when\ndiagnosing crash loops — the kernel OOM killer never reaches the\napplication's logs, so seeing `oom_killed=true` is the only signal\nthat a memory limit was the cause.","required":["role","container_name","resource_limits"],"properties":{"container_id":{"type":["string","null"],"description":"Container Docker id, when present. None = container does not exist\n(was never created or was removed externally)."},"container_name":{"type":"string","description":"Stable name of the Docker container (e.g. `postgres-mydb`)."},"exit_code":{"type":["integer","null"],"format":"int64","description":"Last container exit code, when known. Non-zero = unclean stop."},"finished_at":{"type":["string","null"],"description":"ISO-8601 timestamp of the most recent termination, when known."},"image":{"type":["string","null"],"description":"Currently-effective Docker image (e.g. `gotempsh/postgres-walg:18-bookworm`)."},"oom_killed":{"type":["boolean","null"],"description":"True when the container's last termination was caused by the\nkernel OOM killer. Set if the user enabled hard memory limits\nand the working set exceeded them."},"resource_limits":{"$ref":"#/components/schemas/ServiceResourceLimits","description":"Currently-applied resource limits read off the container's\n`HostConfig`. Compare this against the user-configured limits to\ndetect drift (an old container that never picked up new caps)."},"restart_count":{"type":["integer","null"],"format":"int64","description":"Total restarts since the container was created. Useful for\ndetecting crash loops — a steady stream means something is killing\nthe container repeatedly (frequently OOM)."},"role":{"type":"string","description":"`service_members.role` for cluster members; \"standalone\" otherwise."},"started_at":{"type":["string","null"],"description":"ISO-8601 timestamp of when the container last started. None when\nit has never started (i.e. created but never run)."},"status":{"type":["string","null"],"description":"Bollard container state (\"running\", \"exited\", \"dead\", etc.). None\nwhen the container does not exist."}}},"ContainerStatsSample":{"type":"object","description":"Live resource usage sample for a single container.\n\n`cpu_percent` is computed by Docker's standard formula:\n ((cpu_delta / system_delta) * online_cpus) * 100\n`memory_percent` is `(memory_usage / memory_limit) * 100` — when no\nmemory limit is set the limit reported by Docker is the host's total\nRAM, so a 5% reading means \"5% of host RAM\", not \"5% of allocated\".","required":["role","container_name"],"properties":{"container_name":{"type":"string"},"cpu_percent":{"type":["number","null"],"format":"double","description":"CPU usage as a percentage. `None` when the container is not running\n(Docker returns no usable counters)."},"memory_limit_bytes":{"type":["integer","null"],"format":"int64","description":"Memory limit in bytes (host RAM if no limit set).","minimum":0},"memory_percent":{"type":["number","null"],"format":"double","description":"Memory usage as a percentage of `memory_limit_bytes`."},"memory_usage_bytes":{"type":["integer","null"],"format":"int64","description":"Resident memory usage in bytes.","minimum":0},"online_cpus":{"type":["integer","null"],"format":"int32","description":"Number of cores Docker observed at sample time. Used by the UI\nto label \"x/y cores\" instead of just a percent.","minimum":0},"role":{"type":"string"}}},"ContentPart":{"type":"object","required":["type"],"properties":{"image_url":{},"text":{"type":["string","null"]},"type":{"type":"string"}}},"ContextLine":{"type":"object","description":"A line in context response","required":["timestamp","level","message","line_offset","is_match"],"properties":{"fields":{},"is_match":{"type":"boolean","description":"Whether this line matched the original search"},"level":{"$ref":"#/components/schemas/LogLevel"},"line_offset":{"type":"integer","format":"int32"},"message":{"type":"string"},"timestamp":{"type":"string"}}},"ContextLogsRequest":{"type":"object","required":["chunk_id","line_offset"],"properties":{"chunk_id":{"type":"string"},"line_offset":{"type":"integer","format":"int32"},"lines":{"type":["integer","null"],"format":"int32","description":"Number of context lines before and after (default: 25)","minimum":0}}},"ContextLogsResponse":{"type":"object","required":["lines","target_index"],"properties":{"lines":{"type":"array","items":{"$ref":"#/components/schemas/ContextLine"}},"target_index":{"type":"integer","minimum":0}}},"ConversationDetailResponse":{"allOf":[{"$ref":"#/components/schemas/ConversationResponse"},{"type":"object","required":["messages"],"properties":{"messages":{"type":"array","items":{"$ref":"#/components/schemas/MessageResponse"},"description":"Turns oldest-first. The `system` seed message is omitted (internal)."}}}]},"ConversationResponse":{"type":"object","required":["public_id","context_type","context_id","status","created_at","last_activity_at"],"properties":{"context_id":{"type":"string"},"context_type":{"type":"string"},"created_at":{"type":"string"},"last_activity_at":{"type":"string"},"public_id":{"type":"string"},"status":{"type":"string"},"title":{"type":["string","null"]}}},"ConversationSummary":{"type":"object","description":"A conversation summary grouping related AI invocations.","required":["conversation_id","message_count","total_input_tokens","total_output_tokens","total_tokens","total_cost_microcents","avg_latency_ms","models_used","first_at","last_at"],"properties":{"avg_latency_ms":{"type":"number","format":"double"},"conversation_id":{"type":"string"},"first_at":{"type":"string"},"last_at":{"type":"string"},"message_count":{"type":"integer","format":"int64"},"models_used":{"type":"array","items":{"type":"string"}},"total_cost_microcents":{"type":"integer","format":"int64"},"total_input_tokens":{"type":"integer","format":"int64"},"total_output_tokens":{"type":"integer","format":"int64"},"total_tokens":{"type":"integer","format":"int64"}}},"ConversationsQueryParams":{"type":"object","properties":{"from":{"type":["string","null"],"description":"ISO 8601 start time (defaults to 24h ago)"},"limit":{"type":["integer","null"],"format":"int64","description":"Max results (defaults to 50, max 100)","minimum":0},"model":{"type":["string","null"],"description":"Filter by model name"},"tags":{"type":["string","null"],"description":"Filter by tags (comma-separated, AND logic)"},"to":{"type":["string","null"],"description":"ISO 8601 end time (defaults to now)"},"user_id":{"type":["integer","null"],"format":"int32","description":"Filter by user ID"}}},"CopyBlobRequest":{"type":"object","description":"Request to copy a blob","required":["fromUrl","toPathname"],"properties":{"fromUrl":{"type":"string","description":"Source blob URL or pathname","example":"/api/blob/10/images/avatar.png"},"projectId":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1},"toPathname":{"type":"string","description":"Destination pathname","example":"images/avatar-copy.png"}}},"CostAnalysis":{"type":"object","description":"Full cluster cost + rightsizing analysis attached to an import plan.","required":["nodes","capacity","requested","usage_source","overprovisioning","recommendation","notes"],"properties":{"actual_usage":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ResourceFootprint","description":"Measured usage from the metrics API (`metrics.k8s.io`).\n`None` when metrics-server is not installed."}]},"capacity":{"$ref":"#/components/schemas/ClusterCapacity","description":"Total cluster capacity (sum of node allocatable resources)"},"control_plane_monthly_usd":{"type":["number","null"],"format":"double","description":"Managed control-plane fee included in `current_monthly_usd` (EKS/GKE\ncharge ~$73/mo per cluster). `None` when not applicable/unknown."},"current_monthly_usd":{"type":["number","null"],"format":"double","description":"Estimated total infrastructure cost per month in USD (compute nodes +\ncontrol-plane fee). `None` when no node could be priced."},"nodes":{"type":"array","items":{"$ref":"#/components/schemas/NodeCostInfo"},"description":"Per-node inventory with price estimates where the instance type is known"},"notes":{"type":"array","items":{"type":"string"},"description":"Honesty notes: what could not be measured, which numbers are\nestimates, and any assumptions made. Always shown to the user."},"overprovisioning":{"$ref":"#/components/schemas/OverprovisioningAssessment","description":"Requests-vs-capacity-vs-usage assessment"},"provider":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/CloudProvider","description":"Detected cloud provider (from node `providerID` prefixes)"}]},"recommendation":{"$ref":"#/components/schemas/TargetRecommendation","description":"The temps/Hetzner target sizing and savings estimate"},"requested":{"$ref":"#/components/schemas/ResourceFootprint","description":"Sum of pod resource *requests* across running pods — what the\nscheduler has reserved, i.e. what the cluster is sized for."},"usage_source":{"$ref":"#/components/schemas/UsageSource","description":"How the usage numbers were obtained (drives UI wording)"}}},"CreateAlertRuleRequest":{"type":"object","required":["name","trigger_type"],"properties":{"cooldown_minutes":{"type":"integer","format":"int32","description":"Minimum minutes between notifications for same rule+group"},"enabled":{"type":"boolean"},"environment_filter":{"type":["integer","null"],"format":"int32","description":"Optional environment ID to filter alerts"},"error_level_filter":{"type":["string","null"],"description":"Optional error type/level filter"},"name":{"type":"string"},"notification_priority":{"type":"string","description":"Notification priority: Low, Normal, High, Critical"},"trigger_config":{"description":"Trigger-specific configuration (e.g., {\"count\": 100, \"window_minutes\": 60} for frequency)"},"trigger_type":{"type":"string","description":"Trigger type: new_issue, regression, frequency, new_user, user_count, status_change"}}},"CreateApiKeyRequest":{"type":"object","required":["name","role_type"],"properties":{"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"name":{"type":"string"},"permissions":{"type":["array","null"],"items":{"type":"string"},"example":["projects:read","deployments:read"]},"role_type":{"type":"string","example":"admin"}}},"CreateApiKeyResponse":{"type":"object","required":["id","name","key_prefix","role_type","api_key","created_at"],"properties":{"api_key":{"type":"string"},"created_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00Z"},"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"id":{"type":"integer","format":"int32"},"key_prefix":{"type":"string"},"name":{"type":"string"},"permissions":{"type":["array","null"],"items":{"type":"string"}},"role_type":{"type":"string"}}},"CreateBackupScheduleRequest":{"type":"object","required":["name","backup_type","retention_period","schedule_expression","enabled","tags"],"properties":{"backup_type":{"type":"string"},"description":{"type":["string","null"]},"enabled":{"type":"boolean"},"include_control_plane":{"type":["boolean","null"],"description":"When `true` (default), every run also produces a `control_plane`\nbackup of Temps's own database. Operators who use Temps purely as\na backup orchestrator for external DBs can set this to `false` to\nkeep the run history focused on those services."},"max_runtime_secs":{"type":["integer","null"],"format":"int64","description":"Optional wall-clock timeout override for jobs created by this schedule\n(seconds). When set, overrides the engine-family default. `null` means\n\"use engine default.\" The per-job `max_runtime_secs` in\n`EnqueueJobParams` can still override this for ad-hoc triggers."},"name":{"type":"string"},"retention_period":{"type":"integer","format":"int32"},"s3_source_id":{"type":["integer","null"],"format":"int32","description":"Optional S3 source. If omitted, the current default S3 source is used."},"schedule_expression":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"target_all_services":{"type":["boolean","null"],"description":"When `true` (default), the schedule backs up every external service\non the host — including databases created in the future. When\n`false`, the schedule backs up only the services explicitly attached\nvia `POST /backups/schedules/{id}/services`. Omit to use the default."}}},"CreateBitbucketRequest":{"type":"object","required":["name","auth"],"properties":{"auth":{"$ref":"#/components/schemas/BitbucketAuthInput","description":"Authentication credentials — either an access token or an app password."},"name":{"type":"string","description":"Display name for this provider."}}},"CreateCloudflareProviderRequest":{"type":"object","required":["name","config"],"properties":{"config":{"$ref":"#/components/schemas/CloudflareConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":"string"}}},"CreateConversationRequest":{"type":"object","required":["context_type","context_id"],"properties":{"context_id":{"type":"string","description":"The entity id (ints stringified)."},"context_type":{"type":"string","description":"e.g. `\"deployment\"`."}}},"CreateDSNRequest":{"type":"object","properties":{"base_url":{"type":["string","null"]},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"name":{"type":["string","null"]}}},"CreateDashboardRequest":{"type":"object","required":["project_id","name","layout"],"properties":{"layout":{"$ref":"#/components/schemas/DashboardLayout"},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"}}},"CreateDeploymentTokenRequest":{"type":"object","required":["name"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32","description":"Optional deployment ID - if set, token is scoped to a specific deployment"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Optional environment ID - if not set, token applies to all environments"},"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"name":{"type":"string"},"permissions":{"type":["array","null"],"items":{"type":"string"},"description":"List of permissions (e.g., [\"visitors:enrich\", \"emails:send\"])\nIf not provided, defaults to full access","example":["visitors:enrich","emails:send"]}}},"CreateDeploymentTokenResponse":{"type":"object","required":["id","project_id","name","token_prefix","token","created_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00Z"},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"permissions":{"type":["array","null"],"items":{"type":"string"}},"project_id":{"type":"integer","format":"int32"},"token":{"type":"string","description":"The full token value - only returned on creation"},"token_prefix":{"type":"string"}}},"CreateDnsProviderRequest":{"type":"object","description":"Request to create a new DNS provider","required":["name","provider_type","credentials"],"properties":{"credentials":{"$ref":"#/components/schemas/DnsProviderCredentials","description":"Provider credentials"},"description":{"type":["string","null"],"description":"Optional description"},"name":{"type":"string","description":"User-friendly name","example":"My Cloudflare"},"provider_type":{"$ref":"#/components/schemas/DnsProviderType","description":"Provider type"}}},"CreateDomainRequest":{"type":"object","required":["domain"],"properties":{"challenge_type":{"type":"string","description":"Challenge type for Let's Encrypt validation. Options: \"http-01\" (default) or \"dns-01\""},"domain":{"type":"string"}}},"CreateEmailDomainRequest":{"type":"object","required":["provider_id","domain"],"properties":{"domain":{"type":"string","description":"Domain name (e.g., \"updates.example.com\")","example":"updates.example.com"},"provider_id":{"type":"integer","format":"int32","description":"Provider ID to use for this domain"}}},"CreateEmailProviderRequest":{"type":"object","required":["name","provider_type","region"],"properties":{"name":{"type":"string","description":"User-friendly name for the provider","example":"My AWS SES"},"provider_type":{"$ref":"#/components/schemas/EmailProviderTypeRoute","description":"Provider type"},"region":{"type":"string","description":"Cloud region. For SMTP this is informational only — the host/port carry the real routing.","example":"us-east-1"},"scaleway_credentials":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ScalewayCredentialsRequest","description":"Scaleway credentials (required if provider_type is scaleway)"}]},"ses_credentials":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SesCredentialsRequest","description":"AWS SES credentials (required if provider_type is ses)"}]},"smtp_credentials":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SmtpCredentialsRequest","description":"Generic SMTP credentials (required if provider_type is smtp). Use when\nyou only have SMTP creds and want to import an already-set-up domain."}]},"sns_topic_arn":{"type":["string","null"],"description":"Exact SNS topic allowed to deliver SES events for this provider."}}},"CreateEnvironmentRequest":{"type":"object","required":["name","branch"],"properties":{"branch":{"type":"string"},"name":{"type":"string"},"set_as_preview":{"type":"boolean","description":"If true, set this environment as the preview environment for the project"}}},"CreateEnvironmentVariableRequest":{"type":"object","required":["key","value","environment_ids"],"properties":{"environment_ids":{"type":"array","items":{"type":"integer","format":"int32"}},"include_in_preview":{"type":"boolean","description":"Include this environment variable in preview environments (default: true)"},"is_secret":{"type":"boolean","description":"When true the variable is treated as write-only: never returned in\nplaintext from the API, masked in the UI, and updates that omit the\nvalue preserve the existing ciphertext. The flag is one-way — secret\nvars cannot be demoted back to regular vars."},"key":{"type":"string"},"value":{"type":"string"}}},"CreateExternalServiceRequest":{"type":"object","required":["name","service_type","parameters"],"properties":{"members":{"type":"array","items":{"$ref":"#/components/schemas/ClusterMemberRequest"},"description":"Cluster member specifications. Required when topology is \"cluster\"."},"name":{"type":"string"},"node_id":{"type":["integer","null"],"format":"int32","description":"Target node ID for the service. Omit or null to run on the control plane."},"parameters":{"type":"object","additionalProperties":{},"propertyNames":{"type":"string"}},"service_type":{"$ref":"#/components/schemas/ServiceTypeRoute"},"topology":{"type":"string","description":"Service topology: \"standalone\" (default) or \"cluster\" (HA multi-member).","example":"standalone"},"version":{"type":["string","null"]}}},"CreateFlagRequest":{"type":"object","required":["key","value_type","default_value"],"properties":{"client_visible":{"type":"boolean","description":"Whether the flag may be exposed on the unauthenticated same-origin\nevaluation endpoint. Defaults to `false`: flags are server-only unless\nexplicitly opted in, because targeting rules can encode business logic."},"default_value":{"description":"Served whenever evaluation cannot do better. Must match `value_type`.\n\nLeft unannotated so utoipa emits a free-form schema: a bool flag's\ndefault is `false`, not an object, and `value_type = Object` would tell\nevery generated client otherwise."},"description":{"type":["string","null"]},"key":{"type":"string","description":"Stable key used in application code. Immutable after create.","example":"checkout.v2"},"value_type":{"$ref":"#/components/schemas/FlagValueType","description":"Fixed at create: retyping would invalidate every stored value and every\ncall site."}}},"CreateFunnelRequest":{"type":"object","required":["name","steps"],"properties":{"description":{"type":["string","null"]},"name":{"type":"string"},"steps":{"type":"array","items":{"$ref":"#/components/schemas/CreateFunnelStep"}}}},"CreateFunnelResponse":{"type":"object","required":["funnel_id","message"],"properties":{"funnel_id":{"type":"integer","format":"int32"},"message":{"type":"string"}}},"CreateFunnelStep":{"type":"object","required":["event_name"],"properties":{"event_filter":{"type":"array","items":{"$ref":"#/components/schemas/SmartFilter"}},"event_name":{"type":"string"}}},"CreateGenericRequest":{"type":"object","required":["name","clone_url"],"properties":{"base_url":{"type":["string","null"],"description":"Optional base URL of the git host for display purposes (no API is called)."},"clone_url":{"type":"string","description":"HTTPS clone URL for the repository, e.g. `https://git.example.com/org/repo.git`."},"name":{"type":"string","description":"Display name for this provider."},"token":{"type":["string","null"],"description":"Access token or password. Omit (or set to `null`) for public repositories."},"token_username":{"type":["string","null"],"description":"HTTP Basic username used with the token. Defaults to `x-access-token` when\nabsent or empty. Ignored for public (unauthenticated) repositories."}}},"CreateGitHubPATRequest":{"type":"object","required":["name","token"],"properties":{"name":{"type":"string"},"token":{"type":"string"}}},"CreateGitLabOAuthRequest":{"type":"object","required":["name","client_id","client_secret","redirect_uri"],"properties":{"base_url":{"type":["string","null"]},"client_id":{"type":"string"},"client_secret":{"type":"string"},"name":{"type":"string"},"redirect_uri":{"type":"string"}}},"CreateGitLabPATRequest":{"type":"object","required":["name","token"],"properties":{"base_url":{"type":["string","null"]},"name":{"type":"string"},"token":{"type":"string"}}},"CreateGiteaPATRequest":{"type":"object","required":["name","token","base_url"],"properties":{"base_url":{"type":"string","description":"HTTPS base URL of the Gitea instance, e.g. `https://git.example.com`."},"name":{"type":"string","description":"Display name for this provider."},"token":{"type":"string","description":"Personal access token issued by the Gitea instance."}}},"CreateIncidentRequest":{"type":"object","required":["title","severity"],"properties":{"description":{"type":["string","null"]},"environment_id":{"type":["integer","null"],"format":"int32"},"monitor_id":{"type":["integer","null"],"format":"int32"},"severity":{"type":"string"},"title":{"type":"string"}}},"CreateIntegrationBody":{"type":"object","required":["provider","signing_secret"],"properties":{"provider":{"type":"string","description":"Registered provider name, e.g. \"stripe\"."},"signing_secret":{"type":"string","description":"Signing secret from the provider's dashboard."}}},"CreateIpAccessControlRequest":{"type":"object","description":"Request to create an IP access control rule","required":["ip_address","action"],"properties":{"action":{"type":"string","description":"Action to take: \"block\" or \"allow\"","example":"block"},"ip_address":{"type":"string","description":"IP address in CIDR notation (e.g., \"192.168.1.1\" or \"10.0.0.0/24\")","example":"192.168.1.100"},"reason":{"type":["string","null"],"description":"Optional reason for the action","example":"Malicious activity detected"}}},"CreateMcpRequest":{"type":"object","required":["slug","name","config"],"properties":{"config":{"type":"object"},"description":{"type":["string","null"]},"name":{"type":"string"},"slug":{"type":"string"}}},"CreateMetricAlertRequest":{"type":"object","required":["project_id","name","metric_name","aggregation","detection_config","window_secs","for_duration_secs","severity","enabled"],"properties":{"aggregation":{"type":"string","description":"One of `avg|sum|min|max|count|rate|p50|p90|p95|p99`."},"detection_config":{"$ref":"#/components/schemas/DetectionConfig","description":"The detector: a discriminated union keyed by `kind`. Today only\n`{ \"kind\": \"static\", \"comparator\": \"gt\", \"threshold\": 500 }` is evaluable."},"dynamic_alerts":{"type":"boolean","description":"When true (and `group_by` is set) fire one independent alarm per breaching\nseries. Static detectors only. Default false."},"enabled":{"type":"boolean"},"for_duration_secs":{"type":"integer","format":"int32"},"group_by":{"type":"array","items":{"type":"string"},"description":"Label keys to break the metric down by, e.g. `[\"endpoint\",\"region\"]`. Empty\n(the default) = one aggregate stream. Max 2 keys; keys must match\n`[a-zA-Z0-9_.:-]`."},"grouped_notification_threshold":{"type":"integer","format":"int32","description":"When more than this many series transition to firing in the same tick, only\nthe first gets the expensive chart/AI enrichment. Range 1–1000, default 5."},"label_filters":{"type":"array","items":{"type":"array","items":false,"prefixItems":[{"type":"string"},{"type":"string"}]},"description":"AND-combined label equality filters: `[[\"key\",\"value\"],…]`. Empty = no\nfiltering (the default). Max 10 pairs; keys must match `[a-zA-Z0-9_.:-]`;\nvalues capped at 500 characters."},"max_series":{"type":"integer","format":"int32","description":"Cardinality cap for dynamic alerting: at most this many series (top by\n`|value|`). Range 1–100, default 20."},"metric_name":{"type":"string"},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"severity":{"type":"string","description":"One of `info|warning|critical`."},"window_secs":{"type":"integer","format":"int32"}}},"CreateMonitorRequest":{"type":"object","required":["name","monitor_type","environment_id"],"properties":{"check_interval_seconds":{"type":["integer","null"],"format":"int32"},"check_path":{"type":["string","null"]},"environment_id":{"type":"integer","format":"int32"},"monitor_type":{"type":"string"},"name":{"type":"string"}}},"CreateNotificationEmailProviderRequest":{"type":"object","required":["name","config"],"properties":{"config":{"$ref":"#/components/schemas/EmailConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":"string"}}},"CreateOidcProviderRequest":{"type":"object","required":["name","issuer_url","client_id","client_secret"],"properties":{"client_id":{"type":"string"},"client_secret":{"type":"string"},"default_role":{"type":"string"},"enabled":{"type":"boolean"},"group_claim":{"type":"string"},"issuer_url":{"type":"string"},"jit_provisioning":{"type":"boolean"},"name":{"type":"string"},"role_claim":{"type":"string"},"scopes":{"type":"string"},"template":{"type":"string"},"trust_idp_email":{"type":"boolean","description":"Defaults false. Set to true only for IdPs where an admin\ncontrols user provisioning (corporate Okta, Azure AD) and\nself-signup of arbitrary emails is not possible — see the\n`trust_idp_email` field on `oidc_providers::Model` for the\nsecurity tradeoff this enables."}}},"CreateOidcRoleMappingRequest":{"type":"object","required":["priority","idp_group","role"],"properties":{"idp_group":{"type":"string"},"priority":{"type":"integer","format":"int32"},"role":{"type":"string"}}},"CreatePlanRequest":{"type":"object","description":"Request to create an import plan","required":["source","workload_id"],"properties":{"credentials":{"$ref":"#/components/schemas/ImportCredentials","description":"Platform credentials (required for cloud platforms like Vercel, Railway)"},"repository_id":{"type":["integer","null"],"format":"int32","description":"Optional repository ID to associate with the import\nIf provided, preset will be detected from the repository"},"source":{"$ref":"#/components/schemas/ImportSource","description":"Source to import from"},"workload_id":{"$ref":"#/components/schemas/WorkloadId","description":"Workload ID to import"}}},"CreatePlanResponse":{"type":"object","description":"Response with created plan","required":["session_id","plan","validation","can_execute"],"properties":{"can_execute":{"type":"boolean","description":"Whether the plan can be executed"},"plan":{"$ref":"#/components/schemas/ImportPlan","description":"Generated import plan"},"session_id":{"type":"string","description":"Session ID for tracking"},"validation":{"$ref":"#/components/schemas/ValidationReport","description":"Validation report"}}},"CreatePrResponse":{"type":"object","required":["run","pr_url","pr_number","branch_name"],"properties":{"branch_name":{"type":"string"},"pr_number":{"type":"integer","format":"int32"},"pr_url":{"type":"string"},"run":{"$ref":"#/components/schemas/AutofixerRunResponse"}}},"CreateProjectAccessRequest":{"type":"object","required":["team_id","role"],"properties":{"role":{"$ref":"#/components/schemas/TeamRole"},"team_id":{"type":"integer","format":"int32"}}},"CreateProjectFromTemplateRequest":{"type":"object","description":"Request to create a project from a template\n\nSupports two deploy modes:\n * **Fork mode** — when `git_provider_connection_id` is set, the template\n repo is cloned into a new repository under the user's Git account and the\n project tracks that fork (git-push deploys, automatic deploy on push).\n * **One-click public-repo mode** — when `git_provider_connection_id` is\n omitted, the project deploys directly from the template's public source\n repository (no fork, no Git account required). This is the activation\n path: a brand-new user with no Git provider connected can still deploy a\n demo in one click. `repository_name` / `repository_owner` are ignored in\n this mode, and automatic-deploy-on-push is unavailable (there is no fork\n to receive webhooks).","required":["template_slug","project_name"],"properties":{"automatic_deploy":{"type":"boolean","description":"Enable automatic deployment on push (defaults to true). Only honoured in\nfork mode; public-repo deploys cannot receive push webhooks."},"environment_variables":{"type":"array","items":{"$ref":"#/components/schemas/EnvVarInput"},"description":"Environment variables to set (key-value pairs)"},"git_provider_connection_id":{"type":["integer","null"],"format":"int32","description":"Git provider connection ID. When omitted, the project deploys directly\nfrom the template's public source repository instead of forking it."},"private":{"type":"boolean","description":"Whether to make the repository private (defaults to true)"},"project_name":{"type":"string","description":"Name for the new project"},"repository_name":{"type":["string","null"],"description":"Name for the new repository to create. Required in fork mode; ignored in\none-click public-repo mode."},"repository_owner":{"type":["string","null"],"description":"Owner/organization for the new repository (defaults to authenticated user)"},"storage_service_ids":{"type":"array","items":{"type":"integer","format":"int32"},"description":"External storage service IDs to attach to the project"},"template_slug":{"type":"string","description":"Template slug to use as the base"}}},"CreateProjectFromTemplateResponse":{"type":"object","description":"Response after creating a project from template","required":["project_id","project_slug","project_name","repository_url","template_slug","message"],"properties":{"message":{"type":"string","description":"Message with additional info"},"project_id":{"type":"integer","format":"int32","description":"ID of the created project"},"project_name":{"type":"string","description":"Name of the created project"},"project_slug":{"type":"string","description":"Slug of the created project"},"repository_url":{"type":"string","description":"URL of the created repository"},"template_slug":{"type":"string","description":"Template that was used"}}},"CreateProjectRequest":{"type":"object","required":["name","directory","main_branch","preset","storage_service_ids"],"properties":{"automatic_deploy":{"type":["boolean","null"]},"build_command":{"type":["string","null"]},"custom_domain":{"type":["string","null"]},"directory":{"type":"string"},"environment_variables":{"type":["array","null"],"items":{"type":"array","items":false,"prefixItems":[{"type":"string"},{"type":"string"}]}},"exposed_port":{"type":["integer","null"],"format":"int32","description":"Port exposed by the container (fallback when image has no EXPOSE directive)\n\nPriority order for port resolution:\n1. Image EXPOSE directive (auto-detected from built image)\n2. Environment-level exposed_port (overrides this value per environment)\n3. This project-level exposed_port (fallback)\n4. Default: 3000\n\nOnly set this if your image doesn't use EXPOSE directive.","example":8080},"git_provider_connection_id":{"type":["integer","null"],"format":"int32"},"git_url":{"type":["string","null"]},"install_command":{"type":["string","null"]},"is_on_demand":{"type":["boolean","null"]},"is_public_repo":{"type":["boolean","null"]},"is_web_app":{"type":["boolean","null"]},"main_branch":{"type":"string"},"name":{"type":"string"},"output_dir":{"type":["string","null"]},"performance_metrics_enabled":{"type":"boolean"},"preset":{"type":"string"},"preset_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PresetConfigSchema","description":"Preset-specific configuration\n\nDifferent presets accept different configuration options:\n- **Dockerfile preset**: Accepts `DockerfilePresetConfig` with `dockerfile_path` and `build_context`\n- **Nixpacks preset**: Accepts ordered `providers` (for example `[\"...\", \"python\"]`)\n and optional inline `nixpacksConfig` TOML\n- **Static presets** (Vite, Next.js, etc.): Accept `StaticPresetConfig` with build commands and output dir\n\nExample for Dockerfile preset:\n```json\n{\n \"dockerfilePath\": \"docker/Dockerfile\",\n \"buildContext\": \"./api\"\n}\n```"}]},"project_type":{"type":["string","null"]},"repo_name":{"type":["string","null"]},"repo_owner":{"type":["string","null"]},"source_type":{"$ref":"#/components/schemas/SourceType","description":"Source type for deployments\n\nDetermines how the project is deployed:\n- **git** (default): Traditional Git-based deployments - source code is pulled, built, and deployed\n- **docker_image**: Deploy pre-built Docker images from external registries (DockerHub, GHCR, etc.)\n- **static_files**: Deploy pre-built static files uploaded as tar.gz or zip bundles\n\nFor `docker_image` and `static_files` source types, `repo_name` and `repo_owner` are optional."},"storage_service_ids":{"type":"array","items":{"type":"integer","format":"int32"}},"use_default_wildcard":{"type":["boolean","null"]}}},"CreateProjectSecretRequest":{"type":"object","description":"Request to create a new project secret.\n\nProject secrets are mounted into the container as files under\n`/run/secrets/` (mode 0400, tmpfs) instead of as environment variables.\nValues are always encrypted at rest and never returned in plaintext from\nthe API after create. Distinct from agent secrets (global `/settings/secrets`).","required":["key","value"],"properties":{"environment_ids":{"type":"array","items":{"type":"integer","format":"int32"}},"include_in_preview":{"type":"boolean","description":"Include this secret in preview environments."},"key":{"type":"string","description":"Identifier for the secret. Becomes the filename at `/run/secrets/`.\nMust start with a letter or underscore and contain only A-Z, a-z, 0-9, _."},"value":{"type":"string","description":"Plaintext value, <= 1 MiB."}}},"CreateProviderKeyRequest":{"type":"object","required":["provider","display_name","api_key"],"properties":{"api_key":{"type":"string"},"base_url":{"type":["string","null"]},"default_model":{"type":["string","null"],"description":"Optional model id to pin for this provider (e.g. \"gpt-4o-mini\")."},"display_name":{"type":"string"},"provider":{"type":"string"}}},"CreateProviderRequest":{"type":"object","required":["name","provider_type","config"],"properties":{"config":{},"enabled":{"type":["boolean","null"]},"name":{"type":"string"},"provider_type":{"type":"string"}}},"CreateRouteRequest":{"type":"object","required":["domain","host","port"],"properties":{"domain":{"type":"string"},"host":{"type":"string"},"port":{"type":"integer","format":"int32"},"route_type":{"type":["string","null"],"description":"Route type: \"http\" (default) matches on HTTP Host header,\n\"tls\" matches on TLS SNI hostname for TCP passthrough"}}},"CreateS3SourceRequest":{"type":"object","required":["name","bucket_name","bucket_path","access_key_id","secret_key","region"],"properties":{"access_key_id":{"type":"string"},"bucket_name":{"type":"string"},"bucket_path":{"type":"string"},"endpoint":{"type":["string","null"],"description":"Optional endpoint URL for S3-compatible services like MinIO","example":"http://minio.example.com:9000"},"force_path_style":{"type":["boolean","null"],"description":"Whether to use path-style addressing (default: true)","example":true},"is_default":{"type":["boolean","null"],"description":"When true, make this the default source (will swap out any existing default).\nThe very first S3 source is always created as default regardless of this flag.","example":false},"name":{"type":"string"},"region":{"type":"string"},"secret_key":{"type":"string"}}},"CreateSandboxBody":{"type":"object","properties":{"_runtime":{"type":["string","null"]},"backend":{"type":["string","null"],"description":"Isolation backend: `\"docker\"` (default) or `\"firecracker\"` (ADR-029,\nhardware-virtualized microVM — requires a host provisioned with\n`temps firecracker setup`). Omit for the platform default; existing\nclients are unaffected. Requesting an unavailable backend fails with\n400 rather than silently downgrading isolation."},"cpu_limit":{"type":["number","null"],"format":"double"},"disk_size_mb":{"type":["integer","null"],"format":"int64","description":"Root disk size in MB (Firecracker only; Docker ignores it). Omit for\nthe platform default (1 GiB).","minimum":0},"env":{"type":"object","description":"Extra env vars baked into the container on create.","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"image":{"type":["string","null"],"description":"Docker image override. `null` uses the platform default."},"memory_limit_mb":{"type":["integer","null"],"format":"int64","minimum":0},"name":{"type":["string","null"]},"networkPolicy":{},"pids_limit":{"type":["integer","null"],"format":"int64"},"ports":{"type":"array","items":{"type":"integer","format":"int32","minimum":0},"description":"Ports the sandbox will listen on. Each port becomes a `routes[]`\nentry in the create/get response so `@vercel/sandbox`'s\n`sandbox.domain(port)` can resolve it client-side without an\nextra round-trip."},"preview_password":{"type":["string","null"],"description":"Optional preview-URL password. When set, every preview URL served\nfor this sandbox is gated behind a login form. 8–256 characters.\nOmit to leave preview URLs open (the sandbox ID remains the only\ngate). The plaintext is never returned; only the last-4 hint is\nsurfaced in `SandboxResponse.preview_password_hint`."},"projectId":{"type":["string","null"]},"resources":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ResourcesBody","description":"`@vercel/sandbox`'s nested resources object. When present, its\n`memory` / `vcpus` populate `memory_limit_mb` / `cpu_limit` if those\nweren't sent directly."}]},"source":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SourceBody","description":"Optional initial content to seed into the work dir. Clones a\nrepo or extracts a tarball after the sandbox is created."}]},"timeout":{"type":["integer","null"],"format":"int64","description":"Idle timeout as sent by `@vercel/sandbox` (milliseconds). Converted\nto seconds when `timeout_secs` is absent.","minimum":0},"timeout_secs":{"type":["integer","null"],"format":"int64","description":"Idle timeout in seconds (temps-native). Clamped to `[60, 86400]`.","minimum":0}}},"CreateSkillRequest":{"type":"object","required":["slug","name","content"],"properties":{"content":{"type":"string"},"description":{"type":["string","null"]},"name":{"type":"string"},"slug":{"type":"string"}}},"CreateSlackProviderRequest":{"type":"object","required":["name","config"],"properties":{"config":{"$ref":"#/components/schemas/SlackConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":"string"}}},"CreateTeamMemberRequest":{"type":"object","required":["user_id","role"],"properties":{"role":{"$ref":"#/components/schemas/TeamRole"},"user_id":{"type":"integer","format":"int32"}}},"CreateTeamRequest":{"type":"object","required":["name","slug"],"properties":{"description":{"type":["string","null"]},"name":{"type":"string"},"slug":{"type":"string"}}},"CreateUserRequest":{"type":"object","required":["username","roles"],"properties":{"email":{"type":["string","null"]},"must_change_password":{"type":"boolean"},"password":{"type":["string","null"]},"roles":{"type":"array","items":{"type":"string"}},"username":{"type":"string"}}},"CreateWebhookProviderRequest":{"type":"object","required":["name","config"],"properties":{"config":{"$ref":"#/components/schemas/WebhookConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":"string"}}},"CreateWebhookRequestBody":{"type":"object","required":["url","events"],"properties":{"enabled":{"type":["boolean","null"],"description":"Whether the webhook is enabled","default":true},"events":{"type":"array","items":{"type":"string"},"description":"Event types to subscribe to","example":["deployment.created","deployment.succeeded"]},"secret":{"type":["string","null"],"description":"Secret for HMAC signature verification (optional)"},"url":{"type":"string","description":"Target URL for webhook delivery","example":"https://example.com/webhook"}}},"CreatedResource":{"type":"object","description":"Resource created during import (for rollback / audit)","required":["resource_type","resource_id","resource_name"],"properties":{"resource_id":{"type":"integer","format":"int32","description":"Resource ID"},"resource_name":{"type":"string","description":"Resource name"},"resource_type":{"type":"string","description":"Resource type (project, environment, deployment, service, domain, etc.)"}}},"CronExecutionInfo":{"type":"object","required":["id","cron_id","executed_at","url","status_code","headers","response_time_ms"],"properties":{"cron_id":{"type":"integer","format":"int32"},"error_message":{"type":["string","null"]},"executed_at":{"type":"string"},"headers":{"type":"string"},"id":{"type":"integer","format":"int32"},"response_time_ms":{"type":"integer","format":"int32"},"status_code":{"type":"integer","format":"int32"},"url":{"type":"string"}}},"CronInfo":{"type":"object","required":["id","project_id","environment_id","path","schedule","created_at","updated_at"],"properties":{"created_at":{"type":"string"},"deleted_at":{"type":["string","null"]},"environment_id":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"next_run":{"type":["string","null"]},"path":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"schedule":{"type":"string"},"updated_at":{"type":"string"}}},"CrossProjectSiblingRef":{"type":"object","description":"A sibling project that shares the same `trace_id`, returned by the\nPhase 1 cross-project banner endpoint.","required":["project_id","project_name","project_slug","first_seen"],"properties":{"first_seen":{"type":"string","format":"date-time","description":"ISO 8601 timestamp (UTC, `Z` suffix) of first span ingest for this\n`(trace_id, project_id)` pair."},"project_id":{"type":"integer","format":"int32"},"project_name":{"type":"string"},"project_slug":{"type":"string","description":"URL slug used to link into the sibling project's single-project trace view."}}},"CrossProjectTraceResponse":{"type":"object","description":"Response body for `GET /otel/traces/cross-project/{trace_id}`.\n\nAn empty `siblings` vec is the normal single-project case — never 404.","required":["trace_id","siblings"],"properties":{"siblings":{"type":"array","items":{"$ref":"#/components/schemas/CrossProjectSiblingRef"},"description":"Projects other than the caller's that hold spans for this trace,\nordered by `first_seen ASC`."},"trace_id":{"type":"string","description":"The trace_id that was queried (echoed back for client convenience)."}}},"CurrentStatusResponse":{"type":"object","required":["monitor_id","current_status","uptime_percentage"],"properties":{"avg_response_time_ms":{"type":["number","null"],"format":"double"},"current_status":{"type":"string"},"last_check_at":{"type":["string","null"],"format":"date-time"},"monitor_id":{"type":"integer","format":"int32"},"uptime_percentage":{"type":"number","format":"double"}}},"CustomDomainRequest":{"type":"object","required":["domain","environment_id"],"properties":{"branch":{"type":["string","null"]},"domain":{"type":"string"},"environment_id":{"type":"integer","format":"int32"},"redirect_to":{"type":["string","null"]},"service_name":{"type":["string","null"],"description":"Docker Compose service name this domain routes to (only for docker-compose projects)"},"status_code":{"type":["integer","null"],"format":"int32"}}},"CustomDomainResponse":{"type":"object","required":["id","project_id","domain","status","created_at","updated_at"],"properties":{"branch":{"type":["string","null"]},"created_at":{"type":"integer","format":"int64"},"domain":{"type":"string"},"domain_id":{"type":["integer","null"],"format":"int32"},"environment":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DomainEnvironmentResponse"}]},"expiration_time":{"type":["integer","null"],"format":"int64"},"id":{"type":"integer","format":"int32"},"last_renewed":{"type":["integer","null"],"format":"int64"},"message":{"type":["string","null"]},"project_id":{"type":"integer","format":"int32"},"redirect_to":{"type":["string","null"]},"service_name":{"type":["string","null"],"description":"Docker Compose service name this domain routes to"},"status":{"type":"string"},"status_code":{"type":["integer","null"],"format":"int32"},"updated_at":{"type":"integer","format":"int64"}}},"CustomerMovementResponse":{"type":"object","required":["bucket","new_customers","churned_customers"],"properties":{"bucket":{"type":"string","format":"date-time"},"churned_customers":{"type":"integer","format":"int64"},"new_customers":{"type":"integer","format":"int64"}}},"DashboardLayout":{"type":"object","description":"The typed layout persisted (as JSONB) in `metric_dashboards.layout`.","required":["sections"],"properties":{"sections":{"type":"array","items":{"$ref":"#/components/schemas/DashboardSection"},"description":"Ordered sections that make up the dashboard."}}},"DashboardProjectsAnalyticsQuery":{"type":"object","description":"Query parameters for batch dashboard analytics","required":["project_ids","start_date","end_date"],"properties":{"end_date":{"type":"string","format":"date-time","description":"End date for the query range"},"project_ids":{"type":"string","description":"Comma-separated list of project IDs"},"start_date":{"type":"string","format":"date-time","description":"Start date for the query range"}}},"DashboardProjectsAnalyticsResponse":{"type":"object","description":"Batch response for dashboard project analytics","required":["projects"],"properties":{"projects":{"type":"object","description":"Map of project_id -> analytics data","additionalProperties":{"$ref":"#/components/schemas/ProjectDashboardAnalytics"},"propertyNames":{"type":"string"}}}},"DashboardSection":{"type":"object","description":"A titled group of tiles within a dashboard.","required":["id","title","tiles"],"properties":{"id":{"type":"string","description":"Stable client-generated section id."},"tiles":{"type":"array","items":{"$ref":"#/components/schemas/DashboardTile"},"description":"Tiles rendered within this section."},"title":{"type":"string","description":"Section heading."}}},"DashboardTile":{"type":"object","description":"A single metric tile within a dashboard section.","required":["id","metric_name","aggregation"],"properties":{"aggregation":{"type":"string","description":"Aggregation applied per bucket: one of\n`avg|sum|min|max|count|rate|p50|p90|p95|p99`."},"group_by":{"type":"array","items":{"type":"string"},"description":"Label keys to break the metric down by (group-by / multi-series view).\nEmpty = single aggregated series (current behavior). Max 2 keys — more\ndimensions are unreadable in a chart (ADR-026 Phase 2). Each key must\nmatch `[a-zA-Z0-9_.:-]`. Wired directly to `MetricQuery.group_by` by\nthe tile query path (separate frontend task)."},"id":{"type":"string","description":"Stable client-generated tile id (used as a React key / for reordering)."},"label_filters":{"type":"array","items":{"type":"array","items":false,"prefixItems":[{"type":"string"},{"type":"string"}]},"description":"AND-combined label equality filters: `[[\"key\",\"value\"],…]`. Empty = no\nfiltering. Max 10 pairs; keys must match `[a-zA-Z0-9_.:-]`; values\ncapped at 500 characters. Not yet wired into the tile query path\n(Phase 1 ADR-026 — field round-trips and validates; query wiring is\na separate frontend task)."},"metric_name":{"type":"string","description":"The metric name to chart (e.g. `http.server.duration`)."},"title":{"type":["string","null"],"description":"Optional display title; falls back to the metric name in the UI."}}},"DataImplication":{"type":"object","description":"A specific data implication the user needs to understand","required":["severity","message"],"properties":{"message":{"type":"string","description":"Human-readable description of what could happen"},"recommended_action":{"type":["string","null"],"description":"What the user should do about it (if anything)"},"severity":{"$ref":"#/components/schemas/DataImplicationSeverity","description":"Severity of this implication"}}},"DataImplicationSeverity":{"type":"string","description":"Severity of a data implication","enum":["info","warning","data-not-migrated","potential-data-loss"]},"DatabaseMetricsResponse":{"type":"object","description":"Response for the per-database metrics breakdown.","required":["databases"],"properties":{"databases":{"type":"array","items":{"$ref":"#/components/schemas/DatabaseMetricsRow"},"description":"One entry per database, sorted by the first metric descending\n(largest first) so the biggest database leads the table."}}},"DatabaseMetricsRow":{"type":"object","description":"Per-database metric values for a Postgres service.\n\nA Postgres instance can host many databases (some unrelated to this\nservice). The collector records per-`datname` series; this groups the\nlatest value of each requested metric by database so the UI can render a\n\"Databases\" breakdown table instead of one collapsed number.","required":["database","metrics"],"properties":{"database":{"type":"string","description":"Database name (`datname`)."},"metrics":{"type":"object","description":"Latest value of each requested metric for this database\n(e.g. `{\"pg.database_size_bytes\": 7943871, \"pg.cache_hit_ratio\": 0.99}`).","additionalProperties":{"type":"number","format":"double"},"propertyNames":{"type":"string"}}}},"DelRequest":{"type":"object","description":"Request to delete keys","required":["keys"],"properties":{"keys":{"type":"array","items":{"type":"string"},"description":"The key(s) to delete","example":["user:123","user:456"]},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1}}},"DelResponse":{"type":"object","description":"Response for delete operation","required":["deleted"],"properties":{"deleted":{"type":"integer","format":"int64","description":"Number of keys deleted","example":2}}},"DeleteBlobRequest":{"type":"object","description":"Request to delete blobs","required":["pathnames"],"properties":{"pathnames":{"type":"array","items":{"type":"string"},"description":"Pathnames to delete (relative to project)","example":["images/avatar.png","documents/file.pdf"]},"projectId":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1}}},"DeleteBlobResponse":{"type":"object","description":"Response after deleting blobs","required":["deleted"],"properties":{"deleted":{"type":"integer","format":"int64","description":"Number of blobs deleted","example":2}}},"DeleteResponse":{"type":"object","required":["deleted"],"properties":{"deleted":{"type":"integer","format":"int64","minimum":0}}},"DeployFromImageRequest":{"type":"object","properties":{"external_image_id":{"type":["integer","null"],"format":"int32","description":"External image ID (if already registered). If provided without image_ref,\nthe image reference will be fetched from the registered external image."},"health_check_path":{"type":["string","null"],"description":"Optional HTTP health-check path override (e.g. \"/api/healthz\").\nImage deploys can't read `.temps.yaml`, so this sets the path the deployer\nprobes after the container starts and the path the environment's uptime\nmonitor checks. Must start with '/'. When omitted, defaults to \"/\".","example":"/api/healthz"},"image_ref":{"type":["string","null"],"description":"Docker image reference (e.g., \"ghcr.io/org/app:v1.0\")\nRequired if external_image_id is not provided","example":"ghcr.io/myorg/myapp:v1.0"},"metadata":{"description":"Optional deployment metadata"}}},"DeployFromImageUploadQuery":{"type":"object","description":"Query parameters for deploying from an uploaded image tarball","properties":{"health_check_path":{"type":["string","null"],"description":"Optional HTTP health-check path override (e.g. \"/api/healthz\").\nMust start with '/'. When omitted, defaults to \"/\".","example":"/api/healthz"},"tag":{"type":["string","null"],"description":"Tag to apply to the imported image (e.g., \"myapp:v1.0\")\nIf not provided, a unique tag will be generated","example":"myapp:v1.0"}}},"DeployFromStaticRequest":{"type":"object","required":["static_bundle_id"],"properties":{"health_check_path":{"type":["string","null"],"description":"Optional HTTP health-check path override (e.g. \"/api/healthz\").\nStatic deploys can't read `.temps.yaml`, so this sets the path the deployer\nprobes after the container starts and the path the environment's uptime\nmonitor checks. Must start with '/'. When omitted, defaults to \"/\".","example":"/api/healthz"},"metadata":{"description":"Optional deployment metadata"},"static_bundle_id":{"type":"integer","format":"int32","description":"Static bundle ID (required)"}}},"DeploymentConfig":{"type":"object","description":"Deployment configuration shared between projects and environments\n\nThis configuration can be set at the project level (as defaults) and\noverridden at the environment level for specific deployments.\n\nNote: Environment variables are managed separately and are not part of this config.","properties":{"antiAffinity":{"type":"boolean","description":"Anti-affinity: spread replicas across different nodes.\n\nWhen enabled, the scheduler avoids placing two replicas of the same\nenvironment on the same node. If there are fewer eligible nodes than\nreplicas, remaining replicas wrap around (best-effort spreading).\n\nDefaults to `true` — replicas spread by default."},"automaticDeploy":{"type":["boolean","null"],"description":"Enable automatic deployments on git push.\n`None` = inherit from project config; `Some(true/false)` = explicit override.\nStored as JSONB so absent key → `None` (inherit), never silently defaults to false."},"containerExecEnabled":{"type":"boolean","description":"Enable container exec/shell access (disabled by default for security)"},"cpuLimit":{"type":["integer","null"],"format":"int32","description":"CPU limit in microcores, where 1_000_000 = 1 full CPU core\n(e.g., 2_000_000 = 2 CPUs). NOT millicores. `None` = uncapped."},"cpuRequest":{"type":["integer","null"],"format":"int32","description":"CPU request in microcores, where 1_000_000 = 1 full CPU core\n(e.g., 100_000 = 0.1 CPU, 500_000 = 0.5 CPU, 2_000_000 = 2 CPUs).\nNOT millicores — the deployer formats this as `{n}u` and converts\n`n / 1_000_000` cores into Docker nano_cpus."},"crossArchitectureBuilds":{"type":["boolean","null"],"description":"Build one image per architecture the eligible nodes run.\n\n`None`/`false` (the default) builds exactly once, on the control\nplane's native platform — byte-for-byte the behaviour of a\nsingle-architecture cluster. When enabled and the nodes this\ndeployment could land on span more than one architecture, the build\njob produces one image per architecture; the non-native ones go\nthrough the daemon's `platform` option, which requires QEMU binfmt\nhandlers registered on the control plane.\n\n**Opt-in on purpose.** Cross-architecture builds are emulated and\nsubstantially slower, and deriving them from cluster topology would\nmean a single node joining silently changes build behaviour for every\ndeployment in the cluster. It also keeps the decision on operator\nconfig rather than on a value each node reports about itself.\n\n`Option` so an environment inherits the project's setting\n(`None`) or overrides it, matching `automatic_deploy`."},"exposedPort":{"type":["integer","null"],"format":"int32","description":"Port exposed by the container\nIf not specified, will be auto-detected from Docker image or default to 3000"},"idleTimeoutSeconds":{"type":"integer","format":"int32","description":"Seconds of inactivity before containers are stopped in on-demand mode.\nOnly used when `on_demand` is true. Min: 60, Max: 86400 (24h).\nDefault: 300 (5 minutes)."},"memoryLimit":{"type":["integer","null"],"format":"int32","description":"Memory limit in megabytes. Three-state semantics:\n- `None` → inherit the parent layer (env inherits project, project\n inherits the seeded default); used by the settings UI's \"Use default\".\n- `Some(0)` → explicit **uncapped**: stop inheriting and run with no\n memory limit. This is the deliberate escape hatch for dedicated\n workloads, distinct from `None`.\n- `Some(n)` → hard cap of `n` MB.\n\n`merge`/resolution keep `Some(0)` as a present value (it wins precedence\nover a parent cap), and the deployer collapses it to \"no limit\" before\ntalking to Docker."},"memoryRequest":{"type":["integer","null"],"format":"int32","description":"Memory request in megabytes (e.g., 128 = 128MB)"},"onDemand":{"type":"boolean","description":"Enable on-demand mode (scale-to-zero).\nWhen enabled, containers are stopped after `idle_timeout_seconds` of no traffic\nand automatically started when a new request arrives."},"performanceMetricsEnabled":{"type":"boolean","description":"Enable performance metrics collection (speed insights)"},"replicas":{"type":"integer","format":"int32","description":"Number of replicas/instances to run\nDefaults to 1 replica"},"security":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SecurityConfig","description":"Security configuration (headers, rate limiting, attack mode, etc.)\nThese settings inherit and override from parent level (Environment > Project > Global)"}]},"sessionRecordingEnabled":{"type":"boolean","description":"Enable session recording for analytics"},"targetLabels":{"description":"Label selector for node-based scheduling. Replicas are only deployed to\nnodes whose labels match the selector.\n\nMatching rules:\n- **Same key, array value** → OR: node must match any value\n- **Different keys** → AND: node must satisfy all keys\n\nExample: `{\"region\": [\"us\", \"asia\"], \"gpu\": \"true\"}`\n→ (region=us OR region=asia) AND gpu=true\n\nApplied after `target_nodes` filtering (they stack)."},"targetNodes":{"type":["array","null"],"items":{"type":"integer","format":"int32"},"description":"Optional list of node IDs to deploy to. When set, replicas are distributed\nonly across these nodes (round-robin). When None, the scheduler distributes\nacross all active nodes (or deploys locally if no nodes exist)."},"wakeTimeoutSeconds":{"type":"integer","format":"int32","description":"Max seconds to wait for containers to start when waking from on-demand sleep.\nRequests return 503 if exceeded. Default: 30."}}},"DeploymentConfigSnapshot":{"type":"object","description":"Deployment configuration snapshot for deployments\n\nThis extends DeploymentConfig with environment variables to capture\nthe complete state of a deployment at the time it was created.","properties":{"automaticDeploy":{"type":"boolean","description":"Enable automatic deployments on git push"},"containerExecEnabled":{"type":"boolean","description":"Enable container exec/shell access"},"cpuLimit":{"type":["integer","null"],"format":"int32","description":"CPU limit in millicores"},"cpuRequest":{"type":["integer","null"],"format":"int32","description":"CPU request in millicores"},"environmentVariables":{"type":"object","description":"Environment variables used for this deployment","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"exposedPort":{"type":["integer","null"],"format":"int32","description":"Port exposed by the container"},"memoryLimit":{"type":["integer","null"],"format":"int32","description":"Memory limit in megabytes"},"memoryRequest":{"type":["integer","null"],"format":"int32","description":"Memory request in megabytes"},"performanceMetricsEnabled":{"type":"boolean","description":"Enable performance metrics collection"},"replicas":{"type":"integer","format":"int32","description":"Number of replicas"},"sessionRecordingEnabled":{"type":"boolean","description":"Enable session recording"}}},"DeploymentConfiguration":{"type":"object","description":"Deployment-level configuration","required":["image","strategy","env_vars","ports","volumes","network","resources"],"properties":{"build":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/BuildConfiguration","description":"Build configuration (if building from source)"}]},"command":{"type":["array","null"],"items":{"type":"string"},"description":"Command override"},"entrypoint":{"type":["array","null"],"items":{"type":"string"},"description":"Entrypoint override"},"env_vars":{"type":"array","items":{"$ref":"#/components/schemas/EnvironmentVariable"},"description":"Environment variables"},"git":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/GitSourcePlan","description":"Where the application's source code lives, when the source platform\nbuilds from a git repository. Execution uses this to link the temps\nproject to the same repository so the real deployment pipeline can\nclone and build it."}]},"health_check":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/HealthCheckConfiguration","description":"Health check configuration"}]},"image":{"type":"string","description":"Image to deploy"},"network":{"$ref":"#/components/schemas/NetworkConfiguration","description":"Network configuration"},"ports":{"type":"array","items":{"$ref":"#/components/schemas/PortMapping"},"description":"Port mappings"},"resources":{"$ref":"#/components/schemas/ResourceLimits","description":"Resource limits"},"strategy":{"$ref":"#/components/schemas/DeploymentStrategy","description":"Deployment strategy"},"volumes":{"type":"array","items":{"$ref":"#/components/schemas/VolumeMount"},"description":"Volume mounts"},"working_dir":{"type":["string","null"],"description":"Working directory"}}},"DeploymentContainerLogContentResponse":{"type":"object","description":"A single captured container-log dump, including its full text content.","required":["id","container_name","size_bytes","truncated","captured_at","content"],"properties":{"captured_at":{"type":"integer","format":"int64"},"container_name":{"type":"string"},"content":{"type":"string","description":"The captured plain-text log content."},"id":{"type":"integer","format":"int32"},"service_name":{"type":["string","null"]},"size_bytes":{"type":"integer","format":"int64"},"truncated":{"type":"boolean"}}},"DeploymentContainerLogResponse":{"type":"object","description":"Metadata for one captured (historical) container-log dump. Listed on the\ndeployment detail page so a user can pick which past container's logs to read.","required":["id","deployment_id","container_id","container_name","size_bytes","truncated","captured_at"],"properties":{"captured_at":{"type":"integer","format":"int64","description":"Unix epoch milliseconds of when the logs were captured (just before\nteardown). Matches the timestamp convention used by `DeploymentResponse`."},"container_id":{"type":"string"},"container_name":{"type":"string"},"deployment_id":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"node_id":{"type":["integer","null"],"format":"int32"},"service_name":{"type":["string","null"]},"size_bytes":{"type":"integer","format":"int64"},"truncated":{"type":"boolean"}}},"DeploymentContainerLogsListResponse":{"type":"object","description":"The list of captured container-log dumps for a deployment.","required":["logs"],"properties":{"logs":{"type":"array","items":{"$ref":"#/components/schemas/DeploymentContainerLogResponse"}}}},"DeploymentEnvironmentResponse":{"type":"object","required":["id","name","slug","domains"],"properties":{"domains":{"type":"array","items":{"type":"string"}},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"slug":{"type":"string"}}},"DeploymentJobResponse":{"type":"object","required":["id","deployment_id","job_id","job_type","name","status","created_at","updated_at","log_id"],"properties":{"created_at":{"type":"integer","format":"int64"},"dependencies":{},"deployment_id":{"type":"integer","format":"int32"},"description":{"type":["string","null"]},"error_message":{"type":["string","null"]},"execution_order":{"type":["integer","null"],"format":"int32"},"finished_at":{"type":["integer","null"],"format":"int64"},"id":{"type":"integer","format":"int32"},"job_config":{"description":"Internal workflow configuration is intentionally redacted. It can\ncontain legacy plaintext secrets or encrypted secret envelopes."},"job_id":{"type":"string"},"job_type":{"type":"string"},"log_id":{"type":"string"},"name":{"type":"string"},"outputs":{},"started_at":{"type":["integer","null"],"format":"int64"},"status":{"type":"string"},"updated_at":{"type":"integer","format":"int64"}}},"DeploymentJobsResponse":{"type":"object","required":["jobs","total"],"properties":{"jobs":{"type":"array","items":{"$ref":"#/components/schemas/DeploymentJobResponse"}},"total":{"type":"integer","minimum":0}}},"DeploymentListResponse":{"type":"object","required":["deployments","total","page","per_page"],"properties":{"deployments":{"type":"array","items":{"$ref":"#/components/schemas/DeploymentResponse"}},"page":{"type":"integer","format":"int64"},"per_page":{"type":"integer","format":"int64"},"total":{"type":"integer","format":"int64"}}},"DeploymentMetadata":{"type":"object","description":"Deployment metadata - typed information about the deployment","properties":{"buildDurationMs":{"type":["integer","null"],"format":"int64","description":"Build duration in milliseconds"},"builder":{"type":["string","null"],"description":"Docker builder used (e.g., \"nixpacks\", \"dockerfile\")"},"deploymentDurationMs":{"type":["integer","null"],"format":"int64","description":"Deployment duration in milliseconds"},"deploymentSourceType":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SourceType","description":"Source type for THIS specific deployment (for Manual/flexible projects)\nThis allows Manual projects to have deployments via different methods\n(docker_image, static_files, or git) while keeping per-deployment tracking"}]},"dockerfilePath":{"type":["string","null"],"description":"Dockerfile path if using Dockerfile builder"},"externalImageId":{"type":["integer","null"],"format":"int32","description":"External image ID (reference to external_images table)"},"externalImageRef":{"type":["string","null"],"description":"External Docker image reference (for docker_image source type)\ne.g., \"ghcr.io/org/app:v1.0\" or \"docker.io/myapp:sha-abc123\""},"fileCount":{"type":["integer","null"],"format":"int32","description":"Number of files in the build output"},"gitPushEvent":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/GitPushEvent","description":"Git push event that triggered this deployment (if from webhook)"}]},"healthCheckPath":{"type":["string","null"],"description":"Explicit deploy-time HTTP health-check path override.\nImage/static deploys can't read `.temps.yaml`, so this lets the deploy\nrequest set a custom path (e.g. \"/api/healthz\"). When present it takes\npriority over any `.temps.yaml` `health.path` value. Always starts with '/'."},"imageSizeBytes":{"type":["integer","null"],"format":"int64","description":"Total size of the built image in bytes"},"imageUploadedLocally":{"type":"boolean","description":"Whether the image was uploaded directly (via docker save/load) rather than pulled from registry\nWhen true, the PullExternalImageJob is skipped since the image is already loaded locally"},"isRollback":{"type":"boolean","description":"Whether this is a rollback deployment"},"labels":{"type":"array","items":{"type":"string"},"description":"Custom labels/tags for the deployment"},"rolledBackFromId":{"type":["integer","null"],"format":"int32","description":"ID of the deployment this was rolled back from (if applicable)"},"sourceBundleContentType":{"type":["string","null"],"description":"Uploaded source archive content type."},"sourceBundleId":{"type":["integer","null"],"format":"int32","description":"Uploaded source archive ID. Source archives are extracted before the\nregular preset build pipeline and do not require Git metadata."},"sourceBundlePath":{"type":["string","null"],"description":"Uploaded source archive path in the Temps data directory."},"staticBundleContentType":{"type":["string","null"],"description":"Static bundle content type (for proper extraction: application/gzip or application/zip)"},"staticBundleId":{"type":["integer","null"],"format":"int32","description":"Static bundle ID (reference to static_bundles table, for static_files source type)"},"staticBundlePath":{"type":["string","null"],"description":"Static bundle path in blob storage (for static_files source type)"},"uploadedImageId":{"type":["string","null"],"description":"Docker image ID of the locally uploaded image (sha256:...)\nUsed to verify the image exists before deployment"}}},"DeploymentResponse":{"type":"object","required":["id","project_id","environment_id","environment","status","url","created_at","is_current"],"properties":{"branch":{"type":["string","null"]},"cancelled_reason":{"type":["string","null"]},"commit_author":{"type":["string","null"]},"commit_date":{"type":["integer","null"],"format":"int64"},"commit_hash":{"type":["string","null"]},"commit_message":{"type":["string","null"]},"created_at":{"type":"integer","format":"int64"},"deployment_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DeploymentConfigSnapshot","description":"Deployment configuration snapshot (CPU, memory, replicas, environment variables, etc.)"}]},"environment":{"$ref":"#/components/schemas/DeploymentEnvironmentResponse"},"environment_id":{"type":"integer","format":"int32"},"finished_at":{"type":["integer","null"],"format":"int64"},"id":{"type":"integer","format":"int32"},"is_current":{"type":"boolean"},"metadata":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DeploymentMetadata","description":"Deployment metadata (build info, git event, etc.)"}]},"project_id":{"type":"integer","format":"int32"},"screenshot_location":{"type":["string","null"]},"started_at":{"type":["integer","null"],"format":"int64"},"status":{"type":"string"},"tag":{"type":["string","null"]},"url":{"type":"string"}}},"DeploymentStateResponse":{"type":"object","required":["id","state","message"],"properties":{"id":{"type":"integer","format":"int32"},"message":{"type":"string"},"state":{"type":"string"}}},"DeploymentStrategy":{"type":"string","description":"Deployment strategy","enum":["replace","blue-green","rolling"]},"DeploymentTokenListResponse":{"type":"object","required":["tokens","total"],"properties":{"tokens":{"type":"array","items":{"$ref":"#/components/schemas/DeploymentTokenResponse"}},"total":{"type":"integer","format":"int64","minimum":0}}},"DeploymentTokenResponse":{"type":"object","required":["id","project_id","name","token_prefix","is_active","created_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00Z"},"created_by":{"type":["integer","null"],"format":"int32"},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"last_used_at":{"type":["string","null"],"format":"date-time","example":"2024-01-01T00:00:00Z"},"name":{"type":"string"},"permissions":{"type":["array","null"],"items":{"type":"string"}},"project_id":{"type":"integer","format":"int32"},"token_prefix":{"type":"string"}}},"DetectionConfig":{"oneOf":[{"allOf":[{"$ref":"#/components/schemas/StaticParams","description":"v0 (shipping): static threshold comparison of the aggregated value."},{"type":"object","required":["kind"],"properties":{"kind":{"type":"string","enum":["static"]}}}],"description":"v0 (shipping): static threshold comparison of the aggregated value."},{"allOf":[{"$ref":"#/components/schemas/AnomalyParams","description":"Seasonal anomaly band (basic/agile/robust/ewma share this variant — the\nalgorithm is a field, not a new kind). Creation rejected until evaluated."},{"type":"object","required":["kind"],"properties":{"kind":{"type":"string","enum":["anomaly"]}}}],"description":"Seasonal anomaly band (basic/agile/robust/ewma share this variant — the\nalgorithm is a field, not a new kind). Creation rejected until evaluated."},{"allOf":[{"$ref":"#/components/schemas/ForecastParams","description":"Predict a future threshold breach (capacity planning). Stub."},{"type":"object","required":["kind"],"properties":{"kind":{"type":"string","enum":["forecast"]}}}],"description":"Predict a future threshold breach (capacity planning). Stub."},{"allOf":[{"$ref":"#/components/schemas/OutlierParams","description":"Cross-series population outlier (one host misbehaving vs its peers). Stub."},{"type":"object","required":["kind"],"properties":{"kind":{"type":"string","enum":["outlier"]}}}],"description":"Cross-series population outlier (one host misbehaving vs its peers). Stub."},{"allOf":[{"$ref":"#/components/schemas/AutoWatchParams","description":"Watchdog-style self-tuning auto-watch (engine picks bounds). Stub."},{"type":"object","required":["kind"],"properties":{"kind":{"type":"string","enum":["auto_watch"]}}}],"description":"Watchdog-style self-tuning auto-watch (engine picks bounds). Stub."}],"description":"The typed detector definition stored (as jsonb) in\n`metric_alert_rules.detection_config`.\n\nToday only [`DetectionConfig::Static`] is evaluable; the other variants are\nschema-present (so the SDK/UI and storage are already future-shaped) but\nrejected by [`DetectionConfig::validate`] until their evaluator lands. Each is\nthen enabled code-only, with no schema migration."},"DeviceCount":{"type":"object","required":["device_type","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"device_type":{"type":"string"},"percentage":{"type":"number","format":"double"}}},"DigestSections":{"type":"object","description":"Sections that can be included in the weekly digest\nNote: `#[serde(default)]` allows backward compatibility when deserializing\nold data that may have `security` and `resources` fields instead of `projects`","properties":{"deployments":{"type":"boolean","default":true},"errors":{"type":"boolean","default":true},"funnels":{"type":"boolean","default":true},"performance":{"type":"boolean","default":true},"projects":{"type":"boolean","default":true}}},"Direction":{"type":"string","description":"Which side(s) of an anomaly band count as a deviation.","enum":["both","above","below"]},"DisableBlobResponse":{"type":"object","description":"Response after disabling Blob service","required":["success","message"],"properties":{"message":{"type":"string","description":"Human-readable message","example":"Blob service disabled successfully"},"success":{"type":"boolean","description":"Whether the operation succeeded","example":true}}},"DisableKvResponse":{"type":"object","description":"Response after disabling KV service","required":["success","message"],"properties":{"message":{"type":"string","description":"Status message","example":"KV service disabled successfully"},"success":{"type":"boolean","description":"Whether the service was successfully disabled"}}},"DisableMfaRequest":{"type":"object","required":["code"],"properties":{"code":{"type":"string"}}},"DiscoverRequest":{"type":"object","description":"Request to discover workloads","required":["source"],"properties":{"credentials":{"$ref":"#/components/schemas/ImportCredentials","description":"Platform credentials (required for cloud platforms like Vercel, Railway)"},"selector":{"$ref":"#/components/schemas/ImportSelector","description":"Optional selector to filter workloads"},"source":{"$ref":"#/components/schemas/ImportSource","description":"Source to discover from"}}},"DiscoverResponse":{"type":"object","description":"Response with discovered workloads","required":["workloads"],"properties":{"workloads":{"type":"array","items":{"$ref":"#/components/schemas/WorkloadDescriptor"},"description":"Discovered workloads"}}},"DiskInfo":{"type":"object","description":"Disk space information for a single disk/partition","required":["mount_point","total_bytes","used_bytes","available_bytes","usage_percent","file_system"],"properties":{"available_bytes":{"type":"integer","format":"int64","description":"Available space in bytes","minimum":0},"file_system":{"type":"string","description":"File system type (e.g., \"ext4\", \"apfs\")"},"mount_point":{"type":"string","description":"Mount point of the disk"},"total_bytes":{"type":"integer","format":"int64","description":"Total space in bytes","minimum":0},"usage_percent":{"type":"number","format":"double","description":"Usage percentage (0-100)"},"used_bytes":{"type":"integer","format":"int64","description":"Used space in bytes","minimum":0}}},"DiskSpaceAlert":{"type":"object","description":"Alert for a disk that exceeds the threshold","required":["mount_point","usage_percent","threshold_percent","available_bytes","available_human"],"properties":{"available_bytes":{"type":"integer","format":"int64","description":"Available space in bytes","minimum":0},"available_human":{"type":"string","description":"Human-readable available space"},"mount_point":{"type":"string","description":"Mount point of the disk"},"threshold_percent":{"type":"integer","format":"int32","description":"Configured threshold percentage","minimum":0},"usage_percent":{"type":"number","format":"double","description":"Current usage percentage"}}},"DiskSpaceAlertSettings":{"type":"object","description":"Disk space alert settings for monitoring disk usage","properties":{"check_interval_seconds":{"type":"integer","format":"int64","description":"Interval in seconds between disk space checks","default":300,"example":300,"minimum":60},"enabled":{"type":"boolean","description":"Whether disk space alerts are enabled","default":true},"monitor_path":{"type":["string","null"],"description":"Restrict monitoring to the disk backing this path. When unset (the\ndefault), every mounted writable volume is monitored — including\ndedicated volumes such as `/var/lib/docker`.","default":null},"threshold_percent":{"type":"integer","format":"int32","description":"Threshold percentage (0-100) at which to trigger alerts","default":80,"example":80,"maximum":100,"minimum":0}}},"DiskSpaceCheckResult":{"type":"object","description":"Result of a disk space check","required":["checked_at","enabled","threshold_percent","disks","alerts"],"properties":{"alerts":{"type":"array","items":{"$ref":"#/components/schemas/DiskSpaceAlert"},"description":"Disks that meet or exceed the threshold"},"checked_at":{"type":"string","format":"date-time","description":"Timestamp of the check (ISO 8601, UTC)","example":"2026-05-28T12:15:47.609192Z"},"disks":{"type":"array","items":{"$ref":"#/components/schemas/DiskInfo"},"description":"List of all monitored disks"},"enabled":{"type":"boolean","description":"Whether disk space monitoring is enabled in settings"},"threshold_percent":{"type":"integer","format":"int32","description":"Configured alert threshold percentage (0-100)","minimum":0}}},"DnsAckRequest":{"type":"object","required":["applied_generation"],"properties":{"applied_generation":{"type":"integer","format":"int64","description":"Highest generation the agent has actually applied locally."}}},"DnsAckResponse":{"type":"object","required":["node_id","applied_generation","server_generation"],"properties":{"applied_generation":{"type":"integer","format":"int64"},"node_id":{"type":"integer","format":"int32"},"server_generation":{"type":"integer","format":"int64"}}},"DnsChallengeRecordResult":{"type":"object","description":"Result of a single DNS TXT record creation for ACME challenge","required":["name","value","success","message"],"properties":{"message":{"type":"string","description":"Human-readable message about the operation"},"name":{"type":"string","description":"TXT record name (e.g., \"_acme-challenge.example.com\")","example":"_acme-challenge.example.com"},"success":{"type":"boolean","description":"Whether the record was created successfully"},"value":{"type":"string","description":"TXT record value (the ACME challenge token)","example":"abc123..."}}},"DnsChangesResponse":{"type":"object","required":["generation","full_snapshot","records","removed_ids"],"properties":{"full_snapshot":{"type":"boolean","description":"`true` ⇒ replace the local zone with `records`. `false` ⇒ merge\n`records` into the existing zone (and remove `removed_ids`)."},"generation":{"type":"integer","format":"int64","description":"Highest generation included in this response. Agent ACKs this back."},"records":{"type":"array","items":{"$ref":"#/components/schemas/EndpointDto"}},"removed_ids":{"type":"array","items":{"type":"integer","format":"int64"},"description":"IDs the agent should remove from its zone. Always empty in the v1\nprotocol — the resolver reconciles by name on snapshot mode. Kept\nin the wire format so a future tombstone-based protocol doesn't\nrequire a breaking change."}}},"DnsCompletionResponse":{"type":"object","required":["domain","status"],"properties":{"domain":{"type":"string"},"status":{"type":"string"}}},"DnsLookupError":{"type":"object","description":"Error response for DNS lookup failures","required":["error","domain"],"properties":{"domain":{"type":"string","description":"Domain name that failed","example":"nonexistent.com"},"error":{"type":"string","description":"Error message","example":"DNS lookup failed: domain not found"}}},"DnsLookupRequest":{"type":"object","description":"Request to lookup DNS A records for a domain","required":["domain"],"properties":{"domain":{"type":"string","description":"Domain name to lookup","example":"example.com"}}},"DnsLookupResponse":{"type":"object","description":"Response containing DNS A records","required":["domain","records","count","dns_servers"],"properties":{"count":{"type":"integer","description":"Number of records found","example":1,"minimum":0},"dns_servers":{"type":"array","items":{"type":"string"},"description":"DNS servers used for the lookup","example":["8.8.8.8","8.8.4.4"]},"domain":{"type":"string","description":"Domain name that was queried","example":"example.com"},"records":{"type":"array","items":{"type":"string"},"description":"List of A record IP addresses","example":["93.184.216.34"]}}},"DnsProviderCredentials":{"oneOf":[{"type":"object","required":["api_token","type"],"properties":{"account_id":{"type":["string","null"]},"api_token":{"type":"string","example":"your-api-token"},"type":{"type":"string","enum":["cloudflare"]}}},{"type":"object","required":["api_user","api_key","type"],"properties":{"api_key":{"type":"string","example":"your-api-key"},"api_user":{"type":"string","example":"your-username"},"client_ip":{"type":["string","null"]},"sandbox":{"type":"boolean"},"type":{"type":"string","enum":["namecheap"]}}},{"type":"object","required":["access_key_id","secret_access_key","type"],"properties":{"access_key_id":{"type":"string","example":"AKIAIOSFODNN7EXAMPLE"},"region":{"type":["string","null"],"example":"us-east-1"},"secret_access_key":{"type":"string","example":"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"},"session_token":{"type":["string","null"]},"type":{"type":"string","enum":["route53"]}}},{"type":"object","required":["api_token","type"],"properties":{"api_token":{"type":"string","example":"dop_v1_your-token"},"type":{"type":"string","enum":["digitalocean"]}}},{"type":"object","required":["service_account_email","private_key","project_id","type"],"properties":{"private_key":{"type":"string","example":"-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----"},"project_id":{"type":"string","example":"my-gcp-project"},"service_account_email":{"type":"string","example":"dns-admin@myproject.iam.gserviceaccount.com"},"type":{"type":"string","enum":["gcp"]}}},{"type":"object","required":["tenant_id","client_id","client_secret","subscription_id","resource_group","type"],"properties":{"client_id":{"type":"string","example":"00000000-0000-0000-0000-000000000000"},"client_secret":{"type":"string"},"resource_group":{"type":"string","example":"my-resource-group"},"subscription_id":{"type":"string","example":"00000000-0000-0000-0000-000000000000"},"tenant_id":{"type":"string","example":"00000000-0000-0000-0000-000000000000"},"type":{"type":"string","enum":["azure"]}}},{"type":"object","description":"Pebble challtestsrv mock DNS (LOCAL DEV/TEST ONLY)","required":["management_url","type"],"properties":{"management_url":{"type":"string","example":"http://localhost:8055"},"type":{"type":"string","enum":["pebble"]}}}],"description":"DNS provider credentials (API-facing)"},"DnsProviderResponse":{"type":"object","description":"DNS provider response","required":["id","name","provider_type","credentials","is_active","flat_hostnames_supported","created_at","updated_at"],"properties":{"created_at":{"type":"string"},"credentials":{"description":"Masked credentials for display"},"description":{"type":["string","null"]},"flat_hostnames_supported":{"type":"boolean","description":"Whether this provider benefits from the flat hostname mode (e.g. Cloudflare\nUniversal SSL). The UI surfaces/recommends the Flat toggle when true."},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"last_error":{"type":["string","null"]},"last_used_at":{"type":["string","null"]},"name":{"type":"string"},"provider_type":{"type":"string"},"updated_at":{"type":"string"}}},"DnsProviderSettings":{"type":"object","properties":{"cloudflare_api_key":{"type":["string","null"],"default":null},"provider":{"type":"string","default":"manual"}}},"DnsProviderSettingsMasked":{"type":"object","description":"DNS provider settings with masked sensitive fields","required":["provider"],"properties":{"cloudflare_api_key":{"type":["string","null"]},"provider":{"type":"string"}}},"DnsProviderType":{"type":"string","description":"Supported DNS provider types","enum":["cloudflare","namecheap","route53","digitalocean","gcp","azure","manual","pebble"]},"DnsRecord":{"type":"object","description":"A DNS record","required":["zone","name","fqdn","content","ttl"],"properties":{"content":{"$ref":"#/components/schemas/DnsRecordContent","description":"Record content"},"fqdn":{"type":"string","description":"Fully qualified domain name","example":"www.example.com"},"id":{"type":["string","null"],"description":"Provider-specific record ID (if exists)","example":"abc123"},"metadata":{"type":"object","description":"Provider-specific metadata","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"name":{"type":"string","description":"Record name (without zone, e.g., \"www\" or \"@\" for root)","example":"www"},"proxied":{"type":"boolean","description":"Whether this record is proxied (Cloudflare-specific)"},"ttl":{"type":"integer","format":"int32","description":"Time to live in seconds","example":300,"minimum":0},"zone":{"type":"string","description":"Zone/domain this record belongs to","example":"example.com"}}},"DnsRecordChange":{"type":"object","description":"A single DNS record change the Cloudflare sync would make.","required":["action","name","record_type","value"],"properties":{"action":{"type":"string","description":"`\"create\"`, `\"update\"`, or `\"delete\"`."},"name":{"type":"string"},"record_type":{"type":"string","description":"Record type, e.g. `\"A\"` or `\"CNAME\"`."},"value":{"type":"string"}}},"DnsRecordContent":{"oneOf":[{"type":"object","description":"A record - IPv4 address (as string, e.g., \"192.0.2.1\")","required":["value","type"],"properties":{"type":{"type":"string","enum":["A"]},"value":{"type":"object","description":"A record - IPv4 address (as string, e.g., \"192.0.2.1\")","required":["address"],"properties":{"address":{"type":"string","example":"192.0.2.1"}}}}},{"type":"object","description":"AAAA record - IPv6 address (as string, e.g., \"2001:db8::1\")","required":["value","type"],"properties":{"type":{"type":"string","enum":["AAAA"]},"value":{"type":"object","description":"AAAA record - IPv6 address (as string, e.g., \"2001:db8::1\")","required":["address"],"properties":{"address":{"type":"string","example":"2001:db8::1"}}}}},{"type":"object","description":"CNAME record - canonical name","required":["value","type"],"properties":{"type":{"type":"string","enum":["CNAME"]},"value":{"type":"object","description":"CNAME record - canonical name","required":["target"],"properties":{"target":{"type":"string"}}}}},{"type":"object","description":"TXT record - text content","required":["value","type"],"properties":{"type":{"type":"string","enum":["TXT"]},"value":{"type":"object","description":"TXT record - text content","required":["content"],"properties":{"content":{"type":"string"}}}}},{"type":"object","description":"MX record - mail exchange","required":["value","type"],"properties":{"type":{"type":"string","enum":["MX"]},"value":{"type":"object","description":"MX record - mail exchange","required":["priority","target"],"properties":{"priority":{"type":"integer","format":"int32","minimum":0},"target":{"type":"string"}}}}},{"type":"object","description":"NS record - nameserver","required":["value","type"],"properties":{"type":{"type":"string","enum":["NS"]},"value":{"type":"object","description":"NS record - nameserver","required":["nameserver"],"properties":{"nameserver":{"type":"string"}}}}},{"type":"object","description":"SRV record - service","required":["value","type"],"properties":{"type":{"type":"string","enum":["SRV"]},"value":{"type":"object","description":"SRV record - service","required":["priority","weight","port","target"],"properties":{"port":{"type":"integer","format":"int32","minimum":0},"priority":{"type":"integer","format":"int32","minimum":0},"target":{"type":"string"},"weight":{"type":"integer","format":"int32","minimum":0}}}}},{"type":"object","description":"CAA record - certification authority authorization","required":["value","type"],"properties":{"type":{"type":"string","enum":["CAA"]},"value":{"type":"object","description":"CAA record - certification authority authorization","required":["flags","tag","value"],"properties":{"flags":{"type":"integer","format":"int32","minimum":0},"tag":{"type":"string"},"value":{"type":"string"}}}}},{"type":"object","description":"PTR record - pointer","required":["value","type"],"properties":{"type":{"type":"string","enum":["PTR"]},"value":{"type":"object","description":"PTR record - pointer","required":["target"],"properties":{"target":{"type":"string"}}}}}],"description":"DNS record content - varies by record type"},"DnsRecordResponse":{"type":"object","required":["record_type","name","value","status"],"properties":{"name":{"type":"string","description":"DNS record name (host)","example":"temps._domainkey.example.com"},"priority":{"type":["integer","null"],"format":"int32","description":"Priority (for MX records)","example":"10","minimum":0},"record_type":{"type":"string","description":"Record type: TXT, CNAME, MX","example":"TXT"},"status":{"$ref":"#/components/schemas/DnsRecordStatusResponse","description":"Verification status: unknown, verified, pending, failed"},"value":{"type":"string","description":"DNS record value","example":"v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3..."}}},"DnsRecordSetupResult":{"type":"object","description":"Result of a single DNS record creation","required":["record_type","name","success","automatic","message"],"properties":{"automatic":{"type":"boolean","description":"Whether the operation was automatic or manual"},"message":{"type":"string","description":"Human-readable message"},"name":{"type":"string","description":"Record name"},"record_type":{"type":"string","description":"Record type (TXT, CNAME, MX)"},"success":{"type":"boolean","description":"Whether the record was created successfully"}}},"DnsRecordStatusResponse":{"type":"string","description":"DNS record verification status","enum":["unknown","verified","pending","failed"]},"DnsZone":{"type":"object","description":"A DNS zone (domain managed by the provider)","required":["id","name","status","nameservers"],"properties":{"id":{"type":"string","description":"Provider-specific zone ID","example":"zone123"},"metadata":{"type":"object","description":"Provider-specific metadata","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"name":{"type":"string","description":"Zone name (domain)","example":"example.com"},"nameservers":{"type":"array","items":{"type":"string"},"description":"Nameservers for this zone"},"status":{"type":"string","description":"Zone status","example":"active"}}},"DockerComposePresetConfig":{"type":"object","description":"Configuration for Docker Compose deployments.","properties":{"composeOverride":{"type":["string","null"],"description":"User-provided docker-compose.override.yml content."},"composePath":{"type":["string","null"],"description":"Path to the Compose file relative to the project directory."},"publicPorts":{"type":"array","items":{"$ref":"#/components/schemas/ComposePublicPort"},"description":"Compose service ports that should be publicly routed."}}},"DockerRegistrySettings":{"type":"object","properties":{"ca_certificate":{"type":["string","null"],"default":null},"enabled":{"type":"boolean","default":false},"password":{"type":["string","null"],"default":null},"registry_url":{"type":["string","null"],"default":null},"tls_verify":{"type":"boolean","default":true},"username":{"type":["string","null"],"default":null}}},"DockerRegistrySettingsMasked":{"type":"object","description":"Docker registry settings with masked sensitive fields","required":["enabled","tls_verify"],"properties":{"ca_certificate":{"type":["string","null"]},"enabled":{"type":"boolean"},"password":{"type":["string","null"]},"registry_url":{"type":["string","null"]},"tls_verify":{"type":"boolean"},"username":{"type":["string","null"]}}},"DockerfilePresetConfig":{"type":"object","description":"Configuration for Dockerfile preset\nAllows customizing the Dockerfile path and build context for Docker-based deployments","properties":{"buildContext":{"type":["string","null"],"description":"Custom build context path (relative to repository root)\nIf not specified, uses the project's directory setting","example":"./api"},"dockerfilePath":{"type":["string","null"],"description":"Custom Dockerfile path (relative to build context)\nIf not specified, defaults to \"Dockerfile\" in the build context","example":"docker/Dockerfile"},"variant":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DockerfileVariant","description":"Catalog variant. Normally omitted; `custom` selects the generated\nDockerfile compatibility preset."}]}}},"DockerfileVariant":{"type":"string","description":"Catalog variant persisted under the canonical Dockerfile preset.\n\nExisting rows predate this discriminator and therefore deserialize as\n[`DockerfileVariant::File`].","enum":["file","custom"]},"DomainAction":{"type":"string","description":"What to do with a domain during migration","enum":["import","skip"]},"DomainChallengeResponse":{"type":"object","required":["domain","txt_records","status"],"properties":{"domain":{"type":"string"},"status":{"type":"string"},"txt_records":{"type":"array","items":{"$ref":"#/components/schemas/TxtRecord"},"description":"Array of TXT records to add to DNS. For wildcards, multiple records are required."}}},"DomainEnvironmentResponse":{"type":"object","required":["id","name","slug"],"properties":{"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"slug":{"type":"string"}}},"DomainError":{"type":"object","required":["message","code"],"properties":{"code":{"type":"string"},"details":{"type":["string","null"]},"message":{"type":"string"}}},"DomainPlan":{"type":"object","description":"Plan for migrating a single custom domain","required":["domain","environment","action","action_description"],"properties":{"action":{"$ref":"#/components/schemas/DomainAction","description":"What to do with this domain"},"action_description":{"type":"string","description":"Human-readable explanation"},"domain":{"type":"string","description":"Full domain name"},"environment":{"type":"string","description":"Which environment to associate with (\"production\")"},"redirect_to":{"type":["string","null"],"description":"Redirect target (if this is a redirect domain)"},"replacement":{"type":["string","null"],"description":"The temps-side address that replaces this domain when it is skipped.\n\nSource-generated domains (sslip.io / traefik.me / platform subdomains)\nembed the source server's IP and would keep pointing at the old\nmachine — this tells the user where the app will be reachable on\ntemps instead."},"status_code":{"type":["integer","null"],"format":"int32","description":"Redirect status code"}}},"DomainResponse":{"type":"object","required":["id","domain","status","is_wildcard","verification_method","created_at","updated_at"],"properties":{"certificate":{"type":["string","null"],"description":"The PEM-encoded certificate chain (can be displayed in browser or downloaded)"},"created_at":{"type":"integer","format":"int64"},"dns_challenge_token":{"type":["string","null"]},"dns_challenge_value":{"type":["string","null"]},"domain":{"type":"string"},"expiration_time":{"type":["integer","null"],"format":"int64"},"id":{"type":"integer","format":"int32"},"is_wildcard":{"type":"boolean"},"last_error":{"type":["string","null"]},"last_error_type":{"type":["string","null"]},"last_renewed":{"type":["integer","null"],"format":"int64"},"on_demand_backoff_until":{"type":["integer","null"],"format":"int64","description":"On-demand TLS negative-cache deadline (epoch millis), when this hostname's\non-demand HTTP-01 issuance is in backoff after a failure (ADR-018 §4).\n`None` means no active backoff."},"status":{"type":"string"},"updated_at":{"type":"integer","format":"int64"},"verification_method":{"type":"string"}}},"DrainNodeResponse":{"type":"object","required":["id","name","status","affected_environments","message"],"properties":{"affected_environments":{"type":"integer","minimum":0},"id":{"type":"integer","format":"int32"},"message":{"type":"string"},"name":{"type":"string"},"status":{"type":"string"}}},"DrainStatusResponse":{"type":"object","description":"Progress of a node drain operation.","required":["node_id","node_name","status","remaining_containers","drain_complete","can_remove","message"],"properties":{"can_remove":{"type":"boolean","description":"Can the node be safely removed?"},"drain_complete":{"type":"boolean","description":"Whether the drain is complete (all containers migrated)"},"message":{"type":"string"},"node_id":{"type":"integer","format":"int32"},"node_name":{"type":"string"},"remaining_containers":{"type":"integer","description":"Number of containers still on this node","minimum":0},"status":{"type":"string"}}},"DropArchiveUpload":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary"}}},"DropInspectionResponse":{"type":"object","required":["suggestedName","candidates"],"properties":{"candidates":{"type":"array","items":{"$ref":"#/components/schemas/DropPresetCandidate"}},"suggestedName":{"type":"string"}}},"DropOffPoint":{"type":"object","description":"Drop-off point: pages where visitors leave the site","required":["page_path","exit_count","total_views","exit_rate"],"properties":{"exit_count":{"type":"integer","format":"int64","description":"Number of exits from this page"},"exit_rate":{"type":"number","format":"double","description":"Exit rate for this page (exit_count / total_views)"},"page_path":{"type":"string","description":"The page path where visitors drop off"},"total_views":{"type":"integer","format":"int64","description":"Total views of this page"}}},"DropPresetCandidate":{"type":"object","required":["directory","preset","label","confidence","reason","isStatic"],"properties":{"confidence":{"type":"string"},"directory":{"type":"string"},"isStatic":{"type":"boolean"},"label":{"type":"string"},"preset":{"type":"string"},"reason":{"type":"string"}}},"EmailConfig":{"type":"object","required":["smtp_host","smtp_port","username","password","from_address","to_addresses"],"properties":{"accept_invalid_certs":{"type":"boolean"},"from_address":{"type":"string"},"from_name":{"type":["string","null"]},"password":{"type":"string"},"smtp_host":{"type":"string"},"smtp_port":{"type":"integer","format":"int32","minimum":0},"starttls_required":{"type":"boolean"},"tls_mode":{"$ref":"#/components/schemas/TlsMode"},"to_addresses":{"type":"array","items":{"type":"string"}},"username":{"type":"string"}}},"EmailDomainResponse":{"type":"object","required":["id","provider_id","domain","status","created_at","updated_at"],"properties":{"created_at":{"type":"string","example":"2025-12-03T10:30:00Z"},"domain":{"type":"string","example":"updates.example.com"},"id":{"type":"integer","format":"int32"},"last_verified_at":{"type":["string","null"]},"provider_id":{"type":"integer","format":"int32"},"status":{"type":"string","example":"verified"},"updated_at":{"type":"string","example":"2025-12-03T10:30:00Z"},"verification_error":{"type":["string","null"]}}},"EmailDomainWithDnsResponse":{"type":"object","required":["domain","dns_records"],"properties":{"dns_records":{"type":"array","items":{"$ref":"#/components/schemas/DnsRecordResponse"}},"domain":{"$ref":"#/components/schemas/EmailDomainResponse"}}},"EmailProviderResponse":{"type":"object","required":["id","name","provider_type","region","is_active","credentials","created_at","updated_at"],"properties":{"created_at":{"type":"string","example":"2025-12-03T10:30:00Z"},"credentials":{"description":"Masked credentials for display"},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"name":{"type":"string","example":"My AWS SES"},"provider_type":{"$ref":"#/components/schemas/EmailProviderTypeRoute"},"region":{"type":"string","example":"us-east-1"},"sns_topic_arn":{"type":["string","null"]},"updated_at":{"type":"string","example":"2025-12-03T10:30:00Z"}}},"EmailProviderTypeRoute":{"type":"string","enum":["ses","scaleway","smtp"]},"EmailRequest":{"type":"object","description":"Request body carrying just an email address (password-reset request).","required":["email"],"properties":{"email":{"type":"string"}}},"EmailResponse":{"type":"object","required":["id","from_address","to_addresses","subject","status","created_at","track_opens","track_clicks","open_count","click_count"],"properties":{"bcc_addresses":{"type":["array","null"],"items":{"type":"string"}},"cc_addresses":{"type":["array","null"],"items":{"type":"string"}},"click_count":{"type":"integer","format":"int32","description":"Number of times links in the email were clicked"},"created_at":{"type":"string","example":"2025-12-03T10:30:00Z"},"domain_id":{"type":["integer","null"],"format":"int32"},"error_message":{"type":["string","null"]},"first_clicked_at":{"type":["string","null"],"description":"When a link was first clicked"},"first_opened_at":{"type":["string","null"],"description":"When the email was first opened"},"from_address":{"type":"string","example":"hello@updates.example.com"},"from_name":{"type":["string","null"]},"headers":{"type":["object","null"],"additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"html_body":{"type":["string","null"]},"id":{"type":"string","example":"550e8400-e29b-41d4-a716-446655440000"},"open_count":{"type":"integer","format":"int32","description":"Number of times the email was opened"},"project_id":{"type":["integer","null"],"format":"int32"},"provider_message_id":{"type":["string","null"]},"reply_to":{"type":["string","null"]},"sent_at":{"type":["string","null"]},"status":{"type":"string","example":"sent"},"subject":{"type":"string"},"tags":{"type":["array","null"],"items":{"type":"string"}},"text_body":{"type":["string","null"]},"to_addresses":{"type":"array","items":{"type":"string"}},"track_clicks":{"type":"boolean","description":"Whether click tracking is enabled"},"track_opens":{"type":"boolean","description":"Whether open tracking is enabled"},"tracked_html_body":{"type":["string","null"],"description":"The final HTML sent to the provider (with tracking pixel and rewritten links)"}}},"EmailStatsResponse":{"type":"object","required":["total","sent","failed","queued","captured"],"properties":{"captured":{"type":"integer","format":"int64","description":"Emails captured without sending (Mailhog mode - no provider configured)","minimum":0},"failed":{"type":"integer","format":"int64","minimum":0},"queued":{"type":"integer","format":"int64","minimum":0},"sent":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"EmailStatusResponse":{"type":"object","required":["email_configured","password_reset_available","oidc_providers"],"properties":{"email_configured":{"type":"boolean"},"oidc_providers":{"type":"array","items":{"$ref":"#/components/schemas/OidcProviderSummary"}},"password_reset_available":{"type":"boolean"}}},"EmailTrackingResponse":{"type":"object","description":"Email tracking summary","required":["email_id","track_opens","track_clicks","open_count","click_count","unique_opens","unique_clicks","links"],"properties":{"click_count":{"type":"integer","format":"int32"},"email_id":{"type":"string"},"first_clicked_at":{"type":["string","null"]},"first_opened_at":{"type":["string","null"]},"links":{"type":"array","items":{"$ref":"#/components/schemas/TrackedLinkResponse"}},"open_count":{"type":"integer","format":"int32"},"track_clicks":{"type":"boolean"},"track_opens":{"type":"boolean"},"unique_clicks":{"type":"integer","format":"int64","minimum":0},"unique_opens":{"type":"integer","format":"int64","minimum":0}}},"EmailTrackingSetupResponse":{"type":"object","description":"Result of the one-click AWS-side event-tracking setup.","required":["topic_arn","webhook_url","subscription_requested","event_destination_attached"],"properties":{"event_destination_attached":{"type":"boolean","description":"The SESv2 event destination (bounce/complaint/delivery) is attached\nto the `temps-tracking` configuration set."},"subscription_requested":{"type":"boolean","description":"The webhook subscription was requested; SNS confirms it\nasynchronously through the webhook itself."},"topic_arn":{"type":"string","example":"arn:aws:sns:us-east-1:123456789012:temps-email-events-1"},"webhook_url":{"type":"string"}}},"EmailTrackingStatusResponse":{"type":"object","description":"Live status of the SES event-tracking pipeline for one provider.","required":["webhook_url","supports_event_tracking"],"properties":{"last_event_at":{"type":["string","null"],"description":"Most recent delivered/bounced/complained event recorded for an email\nsent through this provider. `null` means no provider feedback has\narrived yet.","example":"2026-07-18T10:31:00Z"},"sns_topic_arn":{"type":["string","null"]},"subscription_confirmed_at":{"type":["string","null"],"description":"When the SNS subscription for the current topic was confirmed.\n`null` with a topic set usually means the subscription is still\npending — most often because the endpoint was subscribed before the\ntopic ARN was saved here.","example":"2026-07-18T10:30:00Z"},"supports_event_tracking":{"type":"boolean","description":"Only SES providers support SNS event tracking."},"webhook_url":{"type":"string","description":"Public webhook endpoint SNS must deliver events to.","example":"https://temps.example.com/api/t/webhook/ses"}}},"EmbeddingData":{"type":"object","required":["object","embedding","index"],"properties":{"embedding":{"type":"array","items":{"type":"number","format":"double"}},"index":{"type":"integer","format":"int32"},"object":{"type":"string"}}},"EmbeddingInput":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]},"EmbeddingRequest":{"type":"object","required":["model","input"],"properties":{"dimensions":{"type":["integer","null"],"format":"int32"},"encoding_format":{"type":["string","null"]},"input":{"$ref":"#/components/schemas/EmbeddingInput"},"model":{"type":"string"}}},"EmbeddingResponse":{"type":"object","required":["object","data","model","usage"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/EmbeddingData"}},"model":{"type":"string"},"object":{"type":"string"},"usage":{"$ref":"#/components/schemas/EmbeddingUsage"}}},"EmbeddingUsage":{"type":"object","required":["prompt_tokens","total_tokens"],"properties":{"prompt_tokens":{"type":"integer","format":"int64"},"total_tokens":{"type":"integer","format":"int64"}}},"EnableBlobRequest":{"type":"object","description":"Request to enable Blob service","properties":{"docker_image":{"type":["string","null"],"description":"Docker image to use (optional, defaults to RustFS)","example":"ghcr.io/rustfs/rustfs:0.5.0"},"root_password":{"type":["string","null"],"description":"Root password for S3 access"},"root_user":{"type":["string","null"],"description":"Root user for S3 access"}}},"EnableBlobResponse":{"type":"object","description":"Response after enabling Blob service","required":["success","message","status"],"properties":{"message":{"type":"string","description":"Human-readable message","example":"Blob service enabled successfully"},"status":{"$ref":"#/components/schemas/BlobStatusResponse","description":"Current status"},"success":{"type":"boolean","description":"Whether the operation succeeded","example":true}}},"EnableKvRequest":{"type":"object","description":"Request to enable the KV service","properties":{"docker_image":{"type":["string","null"],"description":"Docker image to use (optional, uses default if not provided)","example":"gotempsh/redis-walg:8-bookworm"},"max_memory":{"type":["string","null"],"description":"Maximum memory allocation (e.g., \"256mb\", \"1gb\")","example":"256mb"},"persistence":{"type":"boolean","description":"Enable data persistence"}}},"EnableKvResponse":{"type":"object","description":"Response after enabling KV service","required":["success","message","status"],"properties":{"message":{"type":"string","description":"Status message","example":"KV service enabled successfully"},"status":{"$ref":"#/components/schemas/KvStatusResponse","description":"Current service status"},"success":{"type":"boolean","description":"Whether the service was successfully enabled"}}},"EnablePgStatStatementsResponse":{"type":"object","description":"Response for the enable pg_stat_statements endpoint.","required":["message"],"properties":{"message":{"type":"string","description":"Human-readable message confirming the action."}}},"EndpointDto":{"type":"object","description":"One DNS record on the wire. Mirrors `service_endpoints::Model` but\nkeeps the API stable across entity evolution. `target_ip` is a string\n(v4 or v6 literal, or CNAME target hostname) parsed by the resolver.","required":["id","fqdn","record_type","ttl","owner_kind","owner_id","generation"],"properties":{"fqdn":{"type":"string"},"generation":{"type":"integer","format":"int64"},"id":{"type":"integer","format":"int64"},"node_id":{"type":["integer","null"],"format":"int32"},"owner_id":{"type":"integer","format":"int64"},"owner_kind":{"type":"string"},"record_type":{"type":"string"},"target_ip":{"type":["string","null"]},"target_port":{"type":["integer","null"],"format":"int32"},"ttl":{"type":"integer","format":"int32"}}},"EnqueuedJob":{"type":"object","description":"A single job that was successfully enqueued during a fan-out run.","required":["backup_id","job_id","engine"],"properties":{"backup_id":{"type":"integer","format":"int32","description":"FK to `backups.id` for this job."},"engine":{"type":"string","description":"Engine key (e.g. `\"control_plane\"`, `\"redis\"`, `\"postgres_pgdump\"`)."},"job_id":{"type":"integer","format":"int64","description":"FK to `backup_jobs.id` for this job."},"target_service_id":{"type":["integer","null"],"format":"int32","description":"FK to `external_services.id` when this is an external-service job.\n`None` for the control-plane job."}}},"EnrichVisitorRequest":{"type":"object","required":["custom_data"],"properties":{"custom_data":{"type":"object"}}},"EnrichVisitorResponse":{"type":"object","required":["success","visitor_id","message"],"properties":{"message":{"type":"string"},"success":{"type":"boolean"},"visitor_id":{"type":"string"}}},"EnrollmentTokenInfo":{"type":"object","required":["id","expires_at","used_count","max_uses","created_at"],"properties":{"bound_node_name":{"type":["string","null"]},"created_at":{"type":"string"},"expires_at":{"type":"string"},"id":{"type":"integer","format":"int32"},"max_uses":{"type":"integer","format":"int32"},"used_count":{"type":"integer","format":"int32"}}},"EnrollmentTokenListResponse":{"type":"object","required":["tokens"],"properties":{"tokens":{"type":"array","items":{"$ref":"#/components/schemas/EnrollmentTokenInfo"}}}},"EntityInfoResponse":{"type":"object","required":["container_path","entity","entity_type","fields"],"properties":{"container_path":{"type":"array","items":{"type":"string"},"description":"Full container path","example":["mydb","public"]},"entity":{"type":"string","description":"Entity name","example":"users"},"entity_type":{"type":"string","description":"Entity type","example":"table"},"fields":{"type":"array","items":{"$ref":"#/components/schemas/FieldResponse"},"description":"Field definitions"},"metadata":{"description":"Additional metadata (content_type, last_modified, etag, etc.)"},"row_count":{"type":["integer","null"],"description":"Approximate row count (for tables/collections)","example":1234,"minimum":0},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Size in bytes (for objects/files)","example":1048576,"minimum":0},"sort_schema":{"description":"JSON Schema for sort options (if supported)"}}},"EntityResponse":{"type":"object","required":["name","entity_type"],"properties":{"entity_type":{"type":"string","description":"Entity type (table, view, collection, etc.)","example":"table"},"name":{"type":"string","description":"Entity name (table/collection)","example":"users"},"row_count":{"type":["integer","null"],"description":"Approximate row count","example":1234,"minimum":0},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Size in bytes (for files/objects)","example":1048576,"minimum":0}}},"EnvVarInput":{"type":"object","description":"Input for environment variable","required":["name","value"],"properties":{"name":{"type":"string","description":"Variable name"},"value":{"type":"string","description":"Variable value"}}},"EnvVarIntegrationInfo":{"type":"object","required":["service_id","service_name","service_type","service_updated_at"],"properties":{"service_id":{"type":"integer","format":"int32"},"service_name":{"type":"string"},"service_slug":{"type":["string","null"]},"service_type":{"type":"string"},"service_updated_at":{"type":"string"}}},"EnvVarResponse":{"type":"object","description":"Environment variable with masked sensitive values","required":["key","value","is_masked"],"properties":{"is_masked":{"type":"boolean","description":"Whether this is a sensitive/masked value"},"key":{"type":"string"},"value":{"type":"string"}}},"EnvVarTemplateResponse":{"type":"object","description":"Environment variable template response","required":["name","required"],"properties":{"default":{"type":["string","null"],"description":"Default value if not provided by user"},"default_generator":{"type":["string","null"],"description":"Frontend-side generator hint for the default value\n(e.g. `app_url`, `random_secret`, `random_hex_32`)"},"description":{"type":["string","null"],"description":"Description of what this variable is used for"},"example":{"type":["string","null"],"description":"Example value for documentation"},"name":{"type":"string","description":"Name of the environment variable"},"required":{"type":"boolean","description":"Whether this variable is required"}}},"EnvironmentConfiguration":{"type":"object","description":"Environment-level configuration","required":["name","subdomain","resources"],"properties":{"name":{"type":"string","description":"Environment name"},"resources":{"$ref":"#/components/schemas/ResourceLimits","description":"Resource limits for environment"},"subdomain":{"type":"string","description":"Proposed subdomain"}}},"EnvironmentDomainResponse":{"type":"object","required":["id","environment_id","domain","created_at","url"],"properties":{"created_at":{"type":"integer","format":"int64"},"domain":{"type":"string"},"environment_id":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"url":{"type":"string","description":"Full URL for this domain (e.g., https://buildtolearndev-production.example.com)","example":"https://buildtolearndev-production.example.com"}}},"EnvironmentInfo":{"type":"object","required":["id","name","main_url"],"properties":{"current_deployment_id":{"type":["integer","null"],"format":"int32"},"id":{"type":"integer","format":"int32"},"main_url":{"type":"string"},"name":{"type":"string"}}},"EnvironmentResponse":{"type":"object","required":["id","project_id","name","slug","main_url","subdomain","created_at","updated_at","is_preview","protected","sleeping"],"properties":{"attack_mode":{"type":["boolean","null"],"description":"Per-environment CAPTCHA attack-mode override.\n`null` means inherit the project-level `attack_mode`; `true`/`false`\nexplicitly enable/disable the challenge for this environment. Always\nserialized (NOT skipped) so the UI can distinguish `null` from `false`."},"branch":{"type":["string","null"]},"created_at":{"type":"integer","format":"int64"},"current_deployment_id":{"type":["integer","null"],"format":"int32"},"deployment_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DeploymentConfig","description":"Deployment configuration for this environment (overrides project-level config)"}]},"estimated_sleep_at":{"type":["integer","null"],"format":"int64","description":"Estimated time (epoch millis) when the environment will go to sleep\nbased on last activity + idle timeout. NULL when sleeping or on-demand disabled."},"force_https":{"type":["boolean","null"],"description":"Per-environment HTTP→HTTPS redirect override.\n`null` means inherit the proxy default (redirect only when the host has\nan active TLS certificate); `true` always redirects plain HTTP for this\nenvironment, `false` never does. Always serialized (NOT skipped) so the\nUI can distinguish `null` from `false`."},"id":{"type":"integer","format":"int32"},"is_preview":{"type":"boolean","description":"Indicates if this is a preview environment (auto-created per branch)\nFor preview environments, 'branch' contains the feature branch name"},"last_activity_at":{"type":["integer","null"],"format":"int64","description":"Last proxied request timestamp (epoch millis) for on-demand environments.\nNULL when on-demand is disabled or no traffic has been received yet."},"main_url":{"type":"string"},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"protected":{"type":"boolean","description":"When true, git pushes do NOT auto-deploy to this environment.\nDeployments must be promoted from another environment."},"sleeping":{"type":"boolean","description":"When true, the environment's containers are currently stopped due to\ninactivity (on-demand mode) and will start on the next request."},"slug":{"type":"string"},"subdomain":{"type":"string","description":"The host label stored for this environment (e.g.\n`myproject-production`). This is the prefix that is combined with the\nplatform's preview domain at request time to produce `main_url`. Edit\nthis via the rename-subdomain endpoint, not the full URL."},"updated_at":{"type":"integer","format":"int64"}}},"EnvironmentVariable":{"type":"object","description":"Environment variable","required":["key","value","is_secret"],"properties":{"is_secret":{"type":"boolean","description":"Whether this is a secret (should be encrypted)"},"key":{"type":"string","description":"Variable name"},"source_description":{"type":["string","null"],"description":"Where this env var originates from (for traceability)"},"value":{"type":"string","description":"Variable value (may be redacted for secrets)"}}},"EnvironmentVariableInfo":{"type":"object","required":["name","value","sensitive"],"properties":{"name":{"type":"string"},"sensitive":{"type":"boolean","description":"Whether this variable contains sensitive data (passwords, keys, tokens)","example":false},"value":{"type":"string"}}},"EnvironmentVariableResponse":{"type":"object","required":["id","key","created_at","updated_at","environments","include_in_preview","is_secret"],"properties":{"created_at":{"type":"integer","format":"int64"},"environments":{"type":"array","items":{"$ref":"#/components/schemas/EnvironmentInfo"}},"id":{"type":"integer","format":"int32"},"include_in_preview":{"type":"boolean","description":"Include this environment variable in preview environments"},"is_secret":{"type":"boolean","description":"Whether the variable is a write-only secret. Secrets always have\n`value: None` in responses."},"key":{"type":"string"},"updated_at":{"type":"integer","format":"int64"},"value":{"type":["string","null"],"description":"Plaintext value for non-secret vars (or `\"***\"` mask for list responses).\n`None` for secret vars — secrets are write-only."}}},"EnvironmentVariableValueResponse":{"type":"object","required":["value"],"properties":{"value":{"type":"string"}}},"ErrorDashboardStatsQuery":{"type":"object","required":["start_time","end_time"],"properties":{"compare_to_previous":{"type":["boolean","null"]},"end_time":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"start_time":{"type":"string","format":"date-time"}}},"ErrorDashboardStatsResponse":{"type":"object","required":["total_errors","total_errors_previous_period","total_errors_change_percent","error_groups","error_groups_previous_period","start_time","end_time"],"properties":{"comparison_end_time":{"type":["string","null"],"format":"date-time"},"comparison_start_time":{"type":["string","null"],"format":"date-time"},"end_time":{"type":"string","format":"date-time"},"error_groups":{"type":"integer","format":"int64"},"error_groups_previous_period":{"type":"integer","format":"int64"},"start_time":{"type":"string","format":"date-time"},"total_errors":{"type":"integer","format":"int64"},"total_errors_change_percent":{"type":"number","format":"double"},"total_errors_previous_period":{"type":"integer","format":"int64"}}},"ErrorEventResponse":{"type":"object","required":["id","error_group_id","timestamp","created_at"],"properties":{"created_at":{"type":"string"},"data":{"description":"Full error event data (contains raw Sentry event or custom error data)"},"error_group_id":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int64"},"source":{"type":["string","null"],"description":"Source of the error event (e.g., \"sentry\", \"custom\", \"bugsnag\")"},"timestamp":{"type":"string"}}},"ErrorGroupResponse":{"type":"object","required":["id","title","error_type","first_seen","last_seen","total_count","status","project_id","created_at","updated_at"],"properties":{"assigned_to":{"type":["string","null"]},"created_at":{"type":"string"},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"error_type":{"type":"string"},"first_seen":{"type":"string"},"id":{"type":"integer","format":"int32"},"last_seen":{"type":"string"},"message_template":{"type":["string","null"]},"project_id":{"type":"integer","format":"int32"},"status":{"type":"string"},"title":{"type":"string"},"total_count":{"type":"integer","format":"int32"},"updated_at":{"type":"string"},"visitor_id":{"type":["integer","null"],"format":"int32"}}},"ErrorGroupStatsResponse":{"type":"object","required":["total_groups","unresolved_groups","resolved_groups","ignored_groups"],"properties":{"ignored_groups":{"type":"integer","format":"int64"},"resolved_groups":{"type":"integer","format":"int64"},"total_groups":{"type":"integer","format":"int64"},"unresolved_groups":{"type":"integer","format":"int64"}}},"ErrorResponse":{"type":"object","required":["error"],"properties":{"details":{"type":["string","null"]},"error":{"type":"string"}}},"ErrorRow":{"type":"object","required":["id","ts","error_group_id","fingerprint","error_class","stacktrace_preview","stacktrace_truncated"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"error_class":{"type":"string"},"error_group_id":{"type":"integer","format":"int32"},"fingerprint":{"type":"string"},"id":{"type":"integer","format":"int64"},"message":{"type":["string","null"]},"stacktrace_preview":{},"stacktrace_truncated":{"type":"boolean"},"trace_id":{"type":["string","null"]},"ts":{"type":"string","format":"date-time"}}},"ErrorTimeSeriesDataResponse":{"type":"object","required":["timestamp","count"],"properties":{"count":{"type":"integer","format":"int64"},"timestamp":{"type":"string"}}},"ErrorTimeSeriesQuery":{"type":"object","required":["start_time","end_time"],"properties":{"bucket":{"type":"string","description":"Time bucket size (e.g., \"1h\", \"15m\", \"1d\", \"1 hour\", \"30 minutes\")","example":"1h"},"end_time":{"type":"string","format":"date-time"},"start_time":{"type":"string","format":"date-time"}}},"EventActivityBucket":{"type":"object","description":"Time bucket data point for event activity graph","required":["timestamp","count","unique_visitors"],"properties":{"count":{"type":"integer","format":"int64","description":"Number of event occurrences in this bucket"},"timestamp":{"type":"string","description":"Timestamp for this bucket (ISO 8601)"},"unique_visitors":{"type":"integer","format":"int64","description":"Number of unique visitors in this bucket"}}},"EventBreakdown":{"type":"string","enum":["country","region","city"]},"EventBrowserStats":{"type":"object","description":"Browser stats for an event","required":["browser","count","percentage"],"properties":{"browser":{"type":"string","description":"Browser name"},"count":{"type":"integer","format":"int64","description":"Number of event occurrences from this browser"},"percentage":{"type":"number","format":"double","description":"Percentage of total events"}}},"EventCount":{"type":"object","required":["event_name","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"event_name":{"type":"string"},"percentage":{"type":"number","format":"double"}}},"EventCountryStats":{"type":"object","description":"Country stats for an event","required":["country","count","percentage"],"properties":{"count":{"type":"integer","format":"int64","description":"Number of event occurrences from this country"},"country":{"type":"string","description":"Country name"},"country_code":{"type":["string","null"],"description":"ISO country code (2-letter)"},"percentage":{"type":"number","format":"double","description":"Percentage of total events"}}},"EventDetailQuery":{"type":"object","description":"Query parameters for event detail analytics","required":["event_name","project_id","start_date","end_date"],"properties":{"bucket_interval":{"type":["string","null"],"description":"Bucket interval for time series: 'hour', 'day', 'week', 'month' (default: auto)"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"event_name":{"type":"string","description":"The specific event name to get details for"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"EventDetailResponse":{"type":"object","description":"Summary response for a specific event's analytics","required":["event_name","total_count","unique_visitors","unique_sessions","activity_over_time","referrers","countries","browsers","bucket_interval"],"properties":{"activity_over_time":{"type":"array","items":{"$ref":"#/components/schemas/EventActivityBucket"},"description":"Time series data for event activity graph"},"browsers":{"type":"array","items":{"$ref":"#/components/schemas/EventBrowserStats"},"description":"Browser distribution of visitors who triggered this event"},"bucket_interval":{"type":"string","description":"Bucket interval used for time series ('hour', 'day', etc.)"},"countries":{"type":"array","items":{"$ref":"#/components/schemas/EventCountryStats"},"description":"Geographic distribution of visitors who triggered this event"},"event_name":{"type":"string","description":"The event name being analyzed"},"referrers":{"type":"array","items":{"$ref":"#/components/schemas/EventReferrerStats"},"description":"Top referrer hostnames for visitors who triggered this event"},"total_count":{"type":"integer","format":"int64","description":"Total number of times this event was triggered in the date range"},"unique_sessions":{"type":"integer","format":"int64","description":"Number of unique sessions where this event occurred"},"unique_visitors":{"type":"integer","format":"int64","description":"Number of unique visitors who triggered this event"}}},"EventEntriesQuery":{"type":"object","description":"Query parameters for the raw event entries list","required":["event_name","project_id","start_date","end_date"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"event_name":{"type":"string","description":"The specific event name to list occurrences for"},"page":{"type":["integer","null"],"format":"int64","description":"Page number (1-based, default: 1)","minimum":0},"per_page":{"type":["integer","null"],"format":"int64","description":"Items per page (default: 20, max: 100)","minimum":0},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"EventEntriesResponse":{"type":"object","description":"Paginated response for raw event entries","required":["event_name","total_count","page","per_page","entries"],"properties":{"entries":{"type":"array","items":{"$ref":"#/components/schemas/EventEntryInfo"},"description":"Individual event occurrences, most recent first"},"event_name":{"type":"string","description":"The event name"},"page":{"type":"integer","format":"int64","description":"Current page number","minimum":0},"per_page":{"type":"integer","format":"int64","description":"Items per page","minimum":0},"total_count":{"type":"integer","format":"int64","description":"Total number of occurrences of this event in the date range"}}},"EventEntryInfo":{"type":"object","description":"A single raw occurrence of an event, including its custom JSON properties","required":["id","timestamp","page_path","href"],"properties":{"browser":{"type":["string","null"],"description":"Browser name"},"city":{"type":["string","null"],"description":"City of the visitor at the time of the event"},"country":{"type":["string","null"],"description":"Country of the visitor at the time of the event"},"country_code":{"type":["string","null"],"description":"ISO country code (2-letter)"},"device_type":{"type":["string","null"],"description":"Device type (Desktop, Mobile, Tablet)"},"href":{"type":"string","description":"Full URL where the event was triggered"},"id":{"type":"integer","format":"int64","description":"Event row ID"},"page_path":{"type":"string","description":"Page path where the event was triggered"},"props":{"type":["object","null"],"description":"Custom event properties as JSON (null when the event carried no data)"},"session_id":{"type":["string","null"],"description":"Session ID the event belongs to (if any)"},"timestamp":{"type":"string","format":"date-time","description":"When the event occurred"},"visitor_id":{"type":["integer","null"],"format":"int32","description":"Visitor numeric ID (if known)"},"visitor_uuid":{"type":["string","null"],"description":"Visitor UUID (if known)"}}},"EventKind":{"type":"string","description":"Tag enum for filter parameters and routing. Matches the variant\ndiscriminator used by `ObservabilityEvent`.","enum":["request","span","error","revenue"]},"EventMetricsPayload":{"type":"object","required":["event_name","event_data","request_path","request_query"],"properties":{"cls":{"type":["number","null"],"format":"float","description":"Cumulative Layout Shift (score)"},"event_data":{},"event_name":{"type":"string"},"fcp":{"type":["number","null"],"format":"float","description":"First Contentful Paint (milliseconds)"},"fid":{"type":["number","null"],"format":"float","description":"First Input Delay (milliseconds)"},"inp":{"type":["number","null"],"format":"float","description":"Interaction to Next Paint (milliseconds)"},"language":{"type":["string","null"]},"lcp":{"type":["number","null"],"format":"float","description":"Largest Contentful Paint (milliseconds)"},"page_title":{"type":["string","null"]},"referrer":{"type":["string","null"],"description":"Referrer URL (falls back to Referer header if not provided)"},"request_path":{"type":"string"},"request_query":{"type":"string"},"screen_height":{"type":["integer","null"],"format":"int32","minimum":0},"screen_width":{"type":["integer","null"],"format":"int32","minimum":0},"ttfb":{"type":["number","null"],"format":"float","description":"Time to First Byte (milliseconds)"},"viewport_height":{"type":["integer","null"],"format":"int32","minimum":0},"viewport_width":{"type":["integer","null"],"format":"int32","minimum":0}}},"EventReferrerStats":{"type":"object","description":"Referrer stats for an event","required":["referrer","count","percentage"],"properties":{"count":{"type":"integer","format":"int64","description":"Number of event occurrences from this referrer"},"percentage":{"type":"number","format":"double","description":"Percentage of total events"},"referrer":{"type":"string","description":"Referrer hostname or \"Direct\""}}},"EventTimeline":{"type":"object","required":["date","count"],"properties":{"count":{"type":"integer","format":"int64"},"date":{"type":"string","format":"date-time"}}},"EventTimelineQuery":{"type":"object","required":["start_date","end_date"],"properties":{"aggregation_level":{"$ref":"#/components/schemas/AggregationLevel","description":"Aggregation level: events (raw count), sessions (unique sessions), or visitors (unique visitors)"},"bucket_size":{"type":["string","null"],"description":"Bucket size: hour, day, or week (auto-detected if not specified)"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"event_name":{"type":["string","null"]},"start_date":{"type":"string","format":"date-time"}}},"EventType":{"type":"object","required":["name","count"],"properties":{"count":{"type":"integer","format":"int64"},"name":{"type":"string"}}},"EventTypeBreakdown":{"type":"object","required":["event_type","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"event_type":{"type":"string"},"percentage":{"type":"number","format":"double"}}},"EventTypeBreakdownQuery":{"type":"object","required":["start_date","end_date"],"properties":{"aggregation_level":{"$ref":"#/components/schemas/AggregationLevel","description":"Aggregation level: events (raw count), sessions (unique sessions), or visitors (unique visitors)"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"EventTypeResponse":{"type":"object","required":["event_type","description","category"],"properties":{"category":{"type":"string"},"description":{"type":"string"},"event_type":{"type":"string"}}},"EventTypesResponse":{"type":"object","required":["events","total","page","page_size"],"properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/EventType"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"EventVisitorInfo":{"type":"object","description":"A visitor who triggered a specific event","required":["visitor_id","visitor_uuid","event_count","first_triggered","last_triggered"],"properties":{"browser":{"type":["string","null"],"description":"Browser name"},"city":{"type":["string","null"],"description":"Visitor's city"},"country":{"type":["string","null"],"description":"Visitor's country"},"country_code":{"type":["string","null"],"description":"Visitor's country code"},"device_type":{"type":["string","null"],"description":"Device type (Desktop, Mobile, Tablet)"},"event_count":{"type":"integer","format":"int64","description":"Number of times this visitor triggered the event"},"first_triggered":{"type":"string","format":"date-time","description":"When the visitor first triggered the event in the date range"},"last_triggered":{"type":"string","format":"date-time","description":"When the visitor last triggered the event in the date range"},"referrer_hostname":{"type":["string","null"],"description":"Referrer hostname for the event"},"visitor_id":{"type":"integer","format":"int32","description":"Visitor numeric ID"},"visitor_uuid":{"type":"string","description":"Visitor UUID"}}},"EventVisitorsQuery":{"type":"object","description":"Query parameters for event visitors list","required":["event_name","project_id","start_date","end_date"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"event_name":{"type":"string","description":"The specific event name to list visitors for"},"page":{"type":["integer","null"],"format":"int64","description":"Page number (1-based, default: 1)","minimum":0},"per_page":{"type":["integer","null"],"format":"int64","description":"Items per page (default: 20, max: 100)","minimum":0},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"EventVisitorsResponse":{"type":"object","description":"Paginated response for event visitors","required":["event_name","total_count","page","per_page","visitors"],"properties":{"event_name":{"type":"string","description":"The event name"},"page":{"type":"integer","format":"int64","description":"Current page number","minimum":0},"per_page":{"type":"integer","format":"int64","description":"Items per page","minimum":0},"total_count":{"type":"integer","format":"int64","description":"Total number of unique visitors who triggered this event"},"visitors":{"type":"array","items":{"$ref":"#/components/schemas/EventVisitorInfo"},"description":"Individual visitors who triggered this event"}}},"EventsCountQuery":{"type":"object","required":["start_date","end_date"],"properties":{"aggregation_level":{"$ref":"#/components/schemas/AggregationLevel","description":"Aggregation level: events (raw count), sessions (unique sessions), or visitors (unique visitors)"},"custom_events_only":{"type":["boolean","null"],"description":"Only return custom events, excluding system events like page_view, page_leave, heartbeat (default: true)"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"EventsResponse":{"type":"object","required":["events","applied_kinds"],"properties":{"applied_kinds":{"type":"array","items":{"$ref":"#/components/schemas/EventKind"},"description":"Echo of the kinds filter actually applied (server-resolved). Useful\nfor clients that pass `kinds=` empty and want to know what they got."},"events":{"type":"array","items":{"$ref":"#/components/schemas/ObservabilityEvent"}}}},"ExecBody":{"type":"object","required":["cmd"],"properties":{"cmd":{"type":"array","items":{"type":"string"}},"cwd":{"type":["string","null"]},"env":{"type":"object","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}}},"additionalProperties":false},"ExecDetachedResponse":{"type":"object","required":["job_id"],"properties":{"job_id":{"type":"string"}}},"ExecResponse":{"type":"object","required":["exit_code","stdout","stderr"],"properties":{"exit_code":{"type":"integer","format":"int32"},"stderr":{"type":"string"},"stdout":{"type":"string"}}},"ExecuteImportRequest":{"type":"object","description":"Request to execute an import","required":["session_id","project_name","preset","directory","main_branch"],"properties":{"directory":{"type":"string","description":"Project directory","example":"."},"dry_run":{"type":["boolean","null"],"description":"Dry run mode (don't create resources)"},"main_branch":{"type":"string","description":"Main branch name","example":"main"},"preset":{"type":"string","description":"Preset to use for the project (e.g., \"nextjs\", \"express\", \"docker\")"},"project_name":{"type":"string","description":"Project name to use (overrides the name from the plan)","example":"my-app"},"session_id":{"type":"string","description":"Session ID from plan creation"}}},"ExecuteImportResponse":{"type":"object","description":"Response from import execution","required":["session_id","status","step_results"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32","description":"Created deployment ID (if completed)"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Created environment ID (if completed)"},"project_id":{"type":["integer","null"],"format":"int32","description":"Created project ID (if completed)"},"session_id":{"type":"string","description":"Session ID"},"status":{"$ref":"#/components/schemas/ImportExecutionStatus","description":"Execution status"},"step_results":{"type":"array","items":{"$ref":"#/components/schemas/StepResult"},"description":"Per-step results (in execution order)"}}},"ExecuteOperationRequest":{"type":"object","required":["operation"],"properties":{"operation":{"type":"string"}}},"ExpireRequest":{"type":"object","description":"Request to set expiration on a key","required":["key","seconds"],"properties":{"key":{"type":"string","description":"The key to set expiration on","example":"session:abc"},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1},"seconds":{"type":"integer","format":"int64","description":"Expiration time in seconds","example":3600}}},"ExpireResponse":{"type":"object","description":"Response for expire operation","required":["success"],"properties":{"success":{"type":"boolean","description":"True if expiration was set, false if key doesn't exist"}}},"ExplorerSupportResponse":{"type":"object","required":["supported","service_type","capabilities","hierarchy"],"properties":{"capabilities":{"type":"array","items":{"type":"string"},"description":"Capabilities supported by this service","example":["sql"]},"filter_schema":{"description":"JSON Schema for filter format with embedded UI hints (if supported)"},"hierarchy":{"type":"array","items":{"$ref":"#/components/schemas/HierarchyLevel"},"description":"Hierarchy levels (describes the navigation structure)"},"reason":{"type":["string","null"],"description":"Reason why explorer is not supported (if applicable)"},"service_type":{"type":"string","description":"Service type","example":"postgres"},"supported":{"type":"boolean","description":"Whether the service supports query explorer functionality","example":true}}},"ExtendTimeoutBody":{"type":"object","properties":{"duration":{"type":["integer","null"],"format":"int64","description":"`@vercel/sandbox`-compatible alternative — duration in milliseconds.\nUsed when `extra_secs` is absent.","minimum":0},"extra_secs":{"type":["integer","null"],"format":"int64","description":"Extra seconds to add to the existing `expires_at` (temps-native).","minimum":0}}},"ExternalImageResponse":{"type":"object","required":["id","project_id","image_ref","pushed_at","created_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"digest":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"image_ref":{"type":"string"},"metadata":{},"project_id":{"type":"integer","format":"int32"},"pushed_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"size_bytes":{"type":["integer","null"],"format":"int64"},"tag":{"type":["string","null"]}}},"ExternalServiceBackupResponse":{"type":"object","description":"Response type for external service backup","required":["id","service_id","backup_id","backup_type","state","started_at","s3_location","metadata","compression_type","created_by"],"properties":{"backup_id":{"type":"integer","format":"int32"},"backup_type":{"type":"string"},"checksum":{"type":["string","null"]},"compression_type":{"type":"string"},"created_by":{"type":"integer","format":"int32"},"error_message":{"type":["string","null"]},"expires_at":{"type":["string","null"],"example":"2025-02-15T14:30:00.123Z"},"finished_at":{"type":["string","null"],"example":"2025-01-15T14:35:00.456Z"},"id":{"type":"integer","format":"int32"},"metadata":{},"s3_location":{"type":"string"},"service_id":{"type":"integer","format":"int32"},"size_bytes":{"type":["integer","null"],"format":"int64"},"started_at":{"type":"string","example":"2025-01-15T14:30:00.123Z"},"state":{"type":"string"}}},"ExternalServiceDetails":{"type":"object","required":["service","sensitive_parameters"],"properties":{"current_parameters":{"type":["object","null"],"additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"parameter_schema":{},"sensitive_parameters":{"type":"array","items":{"type":"string"},"description":"Parameter names whose values are masked in `current_parameters` and\nmay be fetched only through the audited reveal endpoint."},"service":{"$ref":"#/components/schemas/ExternalServiceInfo"}}},"ExternalServiceInfo":{"type":"object","required":["id","name","service_type","status","created_at","updated_at","topology"],"properties":{"connection_info":{"type":["string","null"]},"created_at":{"type":"string"},"error_message":{"type":["string","null"],"description":"Error message from failed initialization."},"id":{"type":"integer","format":"int32"},"members":{"type":"array","items":{"$ref":"#/components/schemas/ServiceMemberInfo"},"description":"Cluster members (empty for standalone services)."},"metrics_enabled":{"type":"boolean","description":"Whether metric collection is enabled for this service. The UI uses this\nto decide whether to poll the monitoring endpoints."},"name":{"type":"string"},"node_id":{"type":["integer","null"],"format":"int32","description":"Node ID where the service runs. Null means control plane (local)."},"service_type":{"$ref":"#/components/schemas/ServiceTypeRoute"},"status":{"type":"string"},"topology":{"type":"string","description":"Service topology: \"standalone\" (single container) or \"cluster\" (HA multi-member).","example":"standalone"},"updated_at":{"type":"string"},"version":{"type":["string","null"]}}},"ExternalServiceSummary":{"type":"object","description":"Summary of the external service that owns a backup. Only populated for\nexternal-service backups (Redis, Postgres, etc.); absent for control-plane\nbackups.","required":["id","name","service_type"],"properties":{"id":{"type":"integer","format":"int32","description":"Database id of the external service."},"name":{"type":"string","description":"Human-readable service name (e.g. \"redis-prod\")."},"service_type":{"type":"string","description":"Service type string (e.g. \"postgres\", \"redis\", \"mongodb\").","example":"postgres"}}},"FieldResponse":{"type":"object","required":["name","field_type","nullable"],"properties":{"field_type":{"type":"string","description":"Field type (Int32, String, Timestamp, etc.)","example":"Int64"},"name":{"type":"string","description":"Field name","example":"id"},"nullable":{"type":"boolean","description":"Whether the field is nullable","example":false}}},"FiringSeriesEntry":{"type":"object","description":"A single currently-firing series for a dynamic alert rule, snapshotted from\nthe evaluator's in-memory per-series firing map at read time (ADR-026 Phase 3).","required":["series_key","series_label"],"properties":{"alarm_id":{"type":["integer","null"],"format":"int32","description":"The open alarm's id, when one was created (absent if suppressed)."},"series_key":{"type":"array","items":{"type":"array","items":false,"prefixItems":[{"type":"string"},{"type":"string"}]},"description":"The series' label pairs, e.g. `[[\"endpoint\",\"/checkout\"],[\"region\",\"eu-west\"]]`."},"series_label":{"type":"string","description":"The human-readable joined label, e.g. `endpoint=/checkout, region=eu-west`."}}},"FlagEnvironmentResponse":{"type":"object","required":["environment_id","enabled"],"properties":{"enabled":{"type":"boolean"},"environment_id":{"type":"integer","format":"int32"},"value":{}}},"FlagListResponse":{"type":"object","description":"Note the absence of `salt`: it is never exposed. Publishing the bucketing\nsalt would let a client predict, and self-select into, a rollout cohort.","required":["flags","total","page","page_size","total_pages"],"properties":{"flags":{"type":"array","items":{"$ref":"#/components/schemas/FlagResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","description":"Total flags matching the filter, across all pages.","minimum":0},"total_pages":{"type":"integer","format":"int64","minimum":0}}},"FlagResponse":{"type":"object","required":["id","key","value_type","default_value","client_visible","created_at","updated_at","environments"],"properties":{"archived_at":{"type":["string","null"]},"client_visible":{"type":"boolean"},"created_at":{"type":"string"},"default_value":{},"description":{"type":["string","null"]},"environments":{"type":"array","items":{"$ref":"#/components/schemas/FlagEnvironmentResponse"},"description":"Per-environment overrides. Empty means the flag inherits its default\neverywhere."},"id":{"type":"integer","format":"int32"},"key":{"type":"string"},"last_evaluated_at":{"type":["string","null"],"description":"When an app last actually evaluated this flag. `None` means never seen,\nwhich is a real answer rather than missing data."},"updated_at":{"type":"string"},"value_type":{"type":"string"}}},"FlagSnapshot":{"type":"object","description":"A single flag, already resolved down to one environment. This is what the\nevaluator sees and what the SDK caches in memory.","required":["key","value_type","default_value","enabled"],"properties":{"default_value":{"description":"Served whenever evaluation cannot do better. Genuinely polymorphic by\ndesign — the surrounding struct carries the type."},"enabled":{"type":"boolean","description":"False means the kill switch is engaged for this environment."},"environment_value":{"description":"`None` means \"inherit `default_value`\"."},"key":{"type":"string"},"value_type":{"$ref":"#/components/schemas/FlagValueType"}}},"FlagSnapshotResponse":{"type":"object","required":["environment_id","flags"],"properties":{"environment_id":{"type":"integer","format":"int32"},"flags":{"type":"array","items":{"$ref":"#/components/schemas/FlagSnapshot"},"description":"Flags collapsed to what the evaluator needs, sorted by key so the\nserialized form — and therefore the ETag — is stable."}}},"FlagValueType":{"type":"string","description":"The declared type of a flag's value. Fixed at create time.","enum":["bool","string","number","json"]},"ForecastAlgorithm":{"type":"string","description":"Forecast model family.","enum":["linear","seasonal"]},"ForecastParams":{"type":"object","description":"Forecast detector parameters (stub — not yet evaluated).","required":["forecast_horizon_secs","comparator","threshold"],"properties":{"algorithm":{"$ref":"#/components/schemas/ForecastAlgorithm"},"comparator":{"$ref":"#/components/schemas/Comparator","description":"Comparator + threshold the *forecast* is checked against."},"deviations":{"type":"number","format":"double"},"forecast_horizon_secs":{"type":"integer","format":"int32","description":"How far ahead to project before checking the breach condition."},"threshold":{"type":"number","format":"double"}}},"FullError":{"type":"object","required":["id","ts","error_group_id","fingerprint","error_class"],"properties":{"data":{"description":"Full JSONB blob from `error_events.data` — stack trace, breadcrumbs,\nrequest context, everything. Schema is documented per source SDK."},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"error_class":{"type":"string"},"error_group_id":{"type":"integer","format":"int32"},"fingerprint":{"type":"string"},"id":{"type":"integer","format":"int64"},"message":{"type":["string","null"]},"trace_id":{"type":["string","null"]},"ts":{"type":"string","format":"date-time"}}},"FullEvent":{"oneOf":[{"allOf":[{"$ref":"#/components/schemas/FullRequest"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["request"]}}}]},{"allOf":[{"$ref":"#/components/schemas/FullError"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["error"]}}}]},{"allOf":[{"$ref":"#/components/schemas/RevenueRow"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["revenue"]}}}]},{"allOf":[{"$ref":"#/components/schemas/SpanRow","description":"`SpanRow.attributes` is the truncated form; re-fetching returns\nthe same shape so the panel has a stable contract."},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["span"]}}}],"description":"`SpanRow.attributes` is the truncated form; re-fetching returns\nthe same shape so the panel has a stable contract."}],"description":"One un-truncated row, returned by the `/full/{type}/{id}` endpoint when\nthe user clicks \"Show full\". Same shape as the list rows, but with the\nraw heavy fields restored (no truncation flags) so the side panel can\nrender the long form."},"FullRequest":{"type":"object","required":["id","ts","method","host","path","status"],"properties":{"client_ip":{"type":["string","null"]},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"error_group_id":{"type":["integer","null"],"format":"int32"},"host":{"type":"string"},"id":{"type":"string","description":"The request's unique `request_id` — same identity the list rows carry\n(backend-agnostic; ClickHouse rows have no serial PK)."},"latency_ms":{"type":["integer","null"],"format":"int32"},"method":{"type":"string"},"path":{"type":"string"},"referrer":{"type":["string","null"]},"request_headers":{},"response_headers":{},"status":{"type":"integer","format":"int32"},"trace_id":{"type":["string","null"]},"ts":{"type":"string","format":"date-time"},"user_agent":{"type":["string","null"]}}},"FunnelMetricsResponse":{"type":"object","required":["funnel_id","funnel_name","total_entries","step_conversions","overall_conversion_rate","average_completion_time_seconds"],"properties":{"average_completion_time_seconds":{"type":"number","format":"double"},"funnel_id":{"type":"integer","format":"int32"},"funnel_name":{"type":"string"},"overall_conversion_rate":{"type":"number","format":"double"},"step_conversions":{"type":"array","items":{"$ref":"#/components/schemas/StepConversionResponse"}},"total_entries":{"type":"integer","format":"int64","minimum":0}}},"FunnelResponse":{"type":"object","required":["id","name","is_active","created_at","updated_at"],"properties":{"created_at":{"type":"string"},"description":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"name":{"type":"string"},"updated_at":{"type":"string"}}},"GatewayStatus":{"type":"object","description":"Detailed gateway container status surfaced to the settings UI.","required":["present","running","health","container_name","expected_image","drift","auto_upgrade"],"properties":{"auto_upgrade":{"type":"boolean","description":"True if `auto_upgrade` is enabled in settings."},"container_name":{"type":"string","description":"Container name."},"drift":{"type":"boolean","description":"True when `image != expected_image` and the container is present."},"expected_image":{"type":"string","description":"The image the supervisor *expects* (from settings/constant). If this\ndiffers from `image`, the UI shows a \"drift\" badge."},"health":{"type":"string","description":"Higher-level health label: \"running\" | \"restarting\" | \"crash_looping\"\n| \"stopped\" | \"missing\". UI should prefer this over `running`."},"host_port":{"type":["integer","null"],"format":"int32","description":"Host port that the container's :8080 is published on.","minimum":0},"image":{"type":["string","null"],"description":"Image reference the container was created with (e.g.\n`ghcr.io/gotempsh/temps-preview-gateway:latest`)."},"image_digest":{"type":["string","null"],"description":"Image digest if available (e.g. `sha256:…`)."},"last_error":{"type":["string","null"],"description":"Error string Docker recorded for the container (e.g. startup failure)."},"last_exit_code":{"type":["integer","null"],"format":"int64","description":"Exit code of the last run, if the container is not currently running."},"network":{"type":["string","null"],"description":"Network the container is attached to (should be `temps-sandbox-net`)."},"present":{"type":"boolean","description":"Whether the container exists at all."},"restart_count":{"type":["integer","null"],"format":"int64","description":"Number of times Docker has restarted the container."},"running":{"type":"boolean","description":"Whether the container is currently running."},"started_at":{"type":["string","null"],"description":"ISO 8601 timestamp the container was started at, if running."}}},"GenAiEvent":{"type":"object","description":"A GenAI-related event extracted from span events.\n\nCovers `gen_ai.client.inference.operation.details` and `gen_ai.evaluation.result`\nevents per the OTel GenAI semantic conventions.","required":["span_id","trace_id","event_name","timestamp","attributes"],"properties":{"attributes":{"type":"object","description":"All event attributes.","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"event_name":{"type":"string"},"span_id":{"type":"string"},"timestamp":{"type":"string","format":"date-time"},"trace_id":{"type":"string"}}},"GenAiSpanDetail":{"type":"object","description":"A single GenAI span with extracted semantic convention fields.\n\nFields are aligned with the OpenTelemetry GenAI Semantic Conventions spec:\n","required":["span_id","name","kind","start_time","duration_ms","status_code","attributes"],"properties":{"agent_description":{"type":["string","null"],"description":"Agent description from `gen_ai.agent.description`."},"agent_id":{"type":["string","null"],"description":"Agent identifier from `gen_ai.agent.id`."},"agent_name":{"type":["string","null"],"description":"Agent name from `gen_ai.agent.name`."},"agent_version":{"type":["string","null"],"description":"Agent version from `gen_ai.agent.version`."},"attributes":{"type":"object","description":"All span attributes for extensibility.","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"aws_bedrock_guardrail_id":{"type":["string","null"],"description":"AWS Bedrock guardrail ID from `aws.bedrock.guardrail.id`."},"aws_bedrock_knowledge_base_id":{"type":["string","null"],"description":"AWS Bedrock knowledge base ID from `aws.bedrock.knowledge_base.id`."},"azure_resource_provider_namespace":{"type":["string","null"],"description":"Azure resource provider namespace from `azure.resource_provider.namespace`."},"cache_creation_input_tokens":{"type":["integer","null"],"format":"int64","description":"Tokens written to provider cache from `gen_ai.usage.cache_creation.input_tokens`."},"cache_read_input_tokens":{"type":["integer","null"],"format":"int64","description":"Tokens served from provider cache from `gen_ai.usage.cache_read.input_tokens`."},"conversation_id":{"type":["string","null"],"description":"Unique conversation/session/thread ID from `gen_ai.conversation.id`."},"data_source_id":{"type":["string","null"],"description":"Data source identifier from `gen_ai.data_source.id`."},"duration_ms":{"type":"number","format":"double"},"embeddings_dimension_count":{"type":["integer","null"],"format":"int64","description":"Output embedding dimensions from `gen_ai.embeddings.dimension.count`."},"error_type":{"type":["string","null"],"description":"Error type from `error.type` when the span status is ERROR."},"gen_ai_model":{"type":["string","null"],"description":"The requested model from `gen_ai.request.model`."},"gen_ai_operation":{"type":["string","null"],"description":"The operation type from `gen_ai.operation.name` (e.g. \"chat\", \"embeddings\", \"execute_tool\")."},"gen_ai_response_model":{"type":["string","null"],"description":"The model that actually generated the response from `gen_ai.response.model`."},"gen_ai_system":{"type":["string","null"],"description":"The GenAI provider from `gen_ai.provider.name` (falls back to deprecated `gen_ai.system`)."},"input_messages":{"type":["string","null"],"description":"Chat history input from `gen_ai.input.messages` (opt-in, JSON string)."},"input_tokens":{"type":["integer","null"],"format":"int64"},"kind":{"$ref":"#/components/schemas/SpanKind"},"name":{"type":"string"},"openai_api_type":{"type":["string","null"],"description":"OpenAI API type from `openai.api.type` (chat_completions, responses)."},"openai_request_service_tier":{"type":["string","null"],"description":"Requested service tier from `openai.request.service_tier`."},"openai_response_service_tier":{"type":["string","null"],"description":"Actual service tier from `openai.response.service_tier`."},"openai_system_fingerprint":{"type":["string","null"],"description":"System fingerprint from `openai.response.system_fingerprint`."},"output_messages":{"type":["string","null"],"description":"Model output from `gen_ai.output.messages` (opt-in, JSON string)."},"output_tokens":{"type":["integer","null"],"format":"int64"},"output_type":{"type":["string","null"],"description":"Output content type from `gen_ai.output.type` (text, json, image, speech)."},"parent_span_id":{"type":["string","null"]},"request_choice_count":{"type":["integer","null"],"format":"int64","description":"Number of choices requested from `gen_ai.request.choice.count`."},"request_encoding_formats":{"type":["array","null"],"items":{"type":"string"},"description":"Requested encoding formats from `gen_ai.request.encoding_formats`."},"request_frequency_penalty":{"type":["number","null"],"format":"double","description":"Frequency penalty from `gen_ai.request.frequency_penalty`."},"request_max_tokens":{"type":["integer","null"],"format":"int64","description":"Max tokens from `gen_ai.request.max_tokens`."},"request_presence_penalty":{"type":["number","null"],"format":"double","description":"Presence penalty from `gen_ai.request.presence_penalty`."},"request_seed":{"type":["integer","null"],"format":"int64","description":"Seed for reproducibility from `gen_ai.request.seed`."},"request_stop_sequences":{"type":["array","null"],"items":{"type":"string"},"description":"Stop sequences from `gen_ai.request.stop_sequences`."},"request_temperature":{"type":["number","null"],"format":"double","description":"Temperature setting from `gen_ai.request.temperature`."},"request_top_k":{"type":["number","null"],"format":"double","description":"Top-k setting from `gen_ai.request.top_k`."},"request_top_p":{"type":["number","null"],"format":"double","description":"Top-p setting from `gen_ai.request.top_p`."},"response_finish_reasons":{"type":["array","null"],"items":{"type":"string"},"description":"Reasons the model stopped from `gen_ai.response.finish_reasons` (e.g. [\"stop\"])."},"response_id":{"type":["string","null"],"description":"Unique completion ID from `gen_ai.response.id` (e.g. \"chatcmpl-123\")."},"retrieval_documents":{"type":["string","null"],"description":"Retrieved documents from `gen_ai.retrieval.documents` (opt-in, JSON string)."},"retrieval_query_text":{"type":["string","null"],"description":"Retrieval query text from `gen_ai.retrieval.query.text` (opt-in)."},"server_address":{"type":["string","null"],"description":"GenAI server address from `server.address`."},"server_port":{"type":["integer","null"],"format":"int64","description":"GenAI server port from `server.port`."},"span_id":{"type":"string"},"start_time":{"type":"string","format":"date-time"},"status_code":{"$ref":"#/components/schemas/SpanStatusCode"},"system_instructions":{"type":["string","null"],"description":"System instructions from `gen_ai.system_instructions` (opt-in, JSON string)."},"tool_call_arguments":{"type":["string","null"],"description":"Tool call arguments from `gen_ai.tool.call.arguments` (opt-in, JSON string)."},"tool_call_id":{"type":["string","null"],"description":"Tool call ID from `gen_ai.tool.call.id`."},"tool_call_result":{"type":["string","null"],"description":"Tool call result from `gen_ai.tool.call.result` (opt-in, JSON string)."},"tool_definitions":{"type":["string","null"],"description":"Tool definitions from `gen_ai.tool.definitions` (opt-in, JSON string)."},"tool_description":{"type":["string","null"],"description":"Tool description from `gen_ai.tool.description`."},"tool_name":{"type":["string","null"],"description":"Tool name from `gen_ai.tool.name`."},"tool_type":{"type":["string","null"],"description":"Tool type from `gen_ai.tool.type` (function, extension, datastore)."}}},"GenAiTraceDetailResponse":{"type":"object","required":["trace_id","spans","span_count","events","event_count"],"properties":{"event_count":{"type":"integer","minimum":0},"events":{"type":"array","items":{"$ref":"#/components/schemas/GenAiEvent"}},"span_count":{"type":"integer","minimum":0},"spans":{"type":"array","items":{"$ref":"#/components/schemas/GenAiSpanDetail"}},"trace_id":{"type":"string"}}},"GenAiTraceSummariesResponse":{"type":"object","required":["data","total"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/GenAiTraceSummary"}},"total":{"type":"integer","format":"int64","minimum":0}}},"GenAiTraceSummary":{"type":"object","description":"Summary of a GenAI conversation — aggregated from OTel spans with `gen_ai.*` attributes.","required":["trace_id","root_span_name","service_name","start_time","duration_ms","span_count","error_count"],"properties":{"duration_ms":{"type":"number","format":"double"},"error_count":{"type":"integer","format":"int64"},"gen_ai_model":{"type":["string","null"],"description":"The requested model from `gen_ai.request.model`."},"gen_ai_operation":{"type":["string","null"],"description":"The operation type from `gen_ai.operation.name` (e.g. \"chat\", \"embeddings\")."},"gen_ai_system":{"type":["string","null"],"description":"The GenAI provider (e.g. \"openai\", \"anthropic\") from `gen_ai.provider.name`."},"root_span_name":{"type":"string"},"service_name":{"type":"string"},"span_count":{"type":"integer","format":"int64"},"start_time":{"type":"string","format":"date-time"},"total_cache_creation_input_tokens":{"type":["integer","null"],"format":"int64","description":"Total cache-creation input tokens across all spans."},"total_cache_read_input_tokens":{"type":["integer","null"],"format":"int64","description":"Total cache-read input tokens across all spans."},"total_input_tokens":{"type":["integer","null"],"format":"int64","description":"Total input tokens across all spans in this trace."},"total_output_tokens":{"type":["integer","null"],"format":"int64","description":"Total output tokens across all spans in this trace."},"trace_id":{"type":"string"}}},"GeneralStatsQuery":{"type":"object","required":["start_date","end_date"],"properties":{"end_date":{"type":"string","format":"date-time"},"start_date":{"type":"string","format":"date-time"}}},"GeneralStatsResponse":{"type":"object","required":["total_unique_visitors","total_visits","total_page_views","total_events","total_projects","avg_bounce_rate","avg_engagement_rate","project_breakdown"],"properties":{"avg_bounce_rate":{"type":"number","format":"double"},"avg_engagement_rate":{"type":"number","format":"double"},"page_views_trend_percentage":{"type":["number","null"],"format":"double","description":"Percentage change in page views vs previous period"},"previous_page_views":{"type":["integer","null"],"format":"int64","description":"Previous period page views"},"previous_unique_visitors":{"type":["integer","null"],"format":"int64","description":"Previous period unique visitors (same duration, shifted back)"},"project_breakdown":{"type":"array","items":{"$ref":"#/components/schemas/ProjectStatsBreakdown"}},"total_events":{"type":"integer","format":"int64"},"total_page_views":{"type":"integer","format":"int64"},"total_projects":{"type":"integer","format":"int64"},"total_unique_visitors":{"type":"integer","format":"int64"},"total_visits":{"type":"integer","format":"int64"},"visitors_trend_percentage":{"type":["number","null"],"format":"double","description":"Percentage change in unique visitors vs previous period"}}},"GenerateDockerfileRequest":{"type":"object","description":"Request body for generating a Dockerfile from a preset","properties":{"build_command":{"type":["string","null"],"description":"Custom build command (overrides preset default)","example":"npm run build"},"install_command":{"type":["string","null"],"description":"Custom install command (overrides preset default)","example":"npm ci"},"output_dir":{"type":["string","null"],"description":"Output directory for static builds","example":"dist"},"package_manager":{"type":["string","null"],"description":"Package manager used by the project (npm, yarn, pnpm, bun)\nIf not provided, defaults to npm","example":"npm"},"project_name":{"type":["string","null"],"description":"Project name/slug used for container naming","example":"my-app"},"use_buildkit":{"type":"boolean","description":"Whether to use BuildKit cache mounts for faster builds"}}},"GenerateDockerfileResponse":{"type":"object","description":"Response containing a generated Dockerfile and build arguments","required":["dockerfile","build_args","preset"],"properties":{"build_args":{"type":"object","description":"Build arguments to pass to `docker build --build-arg KEY=VALUE`","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"dockerfile":{"type":"string","description":"The generated Dockerfile content"},"preset":{"type":"string","description":"The preset slug used for generation"}}},"GenerateJoinTokenResponse":{"type":"object","description":"Response returned when a join token is generated (plaintext shown once)","required":["token","message"],"properties":{"message":{"type":"string"},"token":{"type":"string","description":"The plaintext join token — shown only once, save it now"}}},"GeoLocationResponse":{"type":"object","description":"Response containing geolocation information for an IP address","required":["ip","is_eu"],"properties":{"city":{"type":["string","null"],"description":"City name","example":"Mountain View"},"country":{"type":["string","null"],"description":"Country name","example":"United States"},"country_code":{"type":["string","null"],"description":"ISO country code (2 letters)","example":"US"},"ip":{"type":"string","description":"IP address that was geolocated","example":"8.8.8.8"},"is_eu":{"type":"boolean","description":"Whether the IP is in the European Union","example":false},"latitude":{"type":["number","null"],"format":"double","description":"Latitude coordinate","example":37.386},"longitude":{"type":["number","null"],"format":"double","description":"Longitude coordinate","example":-122.0838},"region":{"type":["string","null"],"description":"Region/state name","example":"California"},"timezone":{"type":["string","null"],"description":"Timezone identifier","example":"America/Los_Angeles"}}},"GeoRestrictionsConfig":{"type":"object","description":"Geographic restrictions configuration (future feature)","properties":{"allowedCountries":{"type":"array","items":{"type":"string"},"description":"Allow traffic only from specific countries"},"blockedCountries":{"type":"array","items":{"type":"string"},"description":"Block traffic from specific countries (ISO 3166-1 alpha-2 codes)"}}},"GetDeploymentsParams":{"type":"object","properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"page":{"type":["integer","null"],"format":"int64"},"per_page":{"type":["integer","null"],"format":"int64"}}},"GetEnvironmentVariablesQuery":{"type":"object","properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"service_id":{"type":["integer","null"],"format":"int32","description":"Required by integration-value reveals to bind the plaintext response to\nthe exact service displayed by the client."},"var_id":{"type":["integer","null"],"format":"int32","description":"Exact manual env-var row to reveal. Required by the dashboard so\nduplicate keys on disjoint environments cannot cross-reveal."}}},"GetFunnelMetricsQuery":{"type":"object","properties":{"country_code":{"type":["string","null"]},"end_date":{"type":["string","null"],"format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"start_date":{"type":["string","null"],"format":"date-time"}}},"GetOrCreateDSNRequest":{"type":"object","properties":{"base_url":{"type":["string","null"]},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"}}},"GetProjectSecretsQuery":{"type":"object","properties":{"environment_id":{"type":["integer","null"],"format":"int32"}}},"GetProjectSessionReplaysQuery":{"type":"object","required":["project_id"],"properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"page":{"type":["integer","null"],"format":"int64","minimum":0},"per_page":{"type":["integer","null"],"format":"int64","minimum":0},"project_id":{"type":"integer","format":"int32"}}},"GetProjectSessionReplaysResponse":{"type":"object","required":["sessions","page","per_page","total_count"],"properties":{"page":{"type":"integer","format":"int64","minimum":0},"per_page":{"type":"integer","format":"int64","minimum":0},"sessions":{"type":"array","items":{"$ref":"#/components/schemas/SessionReplayWithVisitorDto"}},"total_count":{"type":"integer","format":"int64","minimum":0}}},"GetRequest":{"type":"object","description":"Request to get a value by key","required":["key"],"properties":{"key":{"type":"string","description":"The key to retrieve","example":"user:123"},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1}}},"GetResponse":{"type":"object","description":"Response for get operation","properties":{"value":{"description":"The value, or null if not found"}}},"GetSessionReplayResponse":{"type":"object","required":["session"],"properties":{"session":{"$ref":"#/components/schemas/SessionReplayWithVisitorDto"}}},"GetUniqueEventsQuery":{"type":"object","properties":{"page":{"type":["integer","null"],"format":"int64","minimum":0},"page_size":{"type":["integer","null"],"format":"int64","minimum":0}}},"GetVisitorSessionsQuery":{"type":"object","properties":{"page":{"type":["integer","null"],"format":"int64","minimum":0},"per_page":{"type":["integer","null"],"format":"int64","minimum":0}}},"GetVisitorSessionsResponse":{"type":"object","required":["sessions","page","per_page","total_count"],"properties":{"page":{"type":"integer","format":"int64","minimum":0},"per_page":{"type":"integer","format":"int64","minimum":0},"sessions":{"type":"array","items":{"$ref":"#/components/schemas/SessionReplayWithVisitorDto"}},"total_count":{"type":"integer","minimum":0}}},"GitPushEvent":{"type":"object","description":"Git push event information that triggered the deployment","required":["repo","owner","branch","commit"],"properties":{"branch":{"type":"string","description":"Branch that was pushed"},"commit":{"type":"string","description":"Commit SHA"},"owner":{"type":"string","description":"Repository owner/organization"},"repo":{"type":"string","description":"Repository name"}}},"GitRefResponse":{"type":"object","description":"Git repository reference response","required":["url","ref"],"properties":{"path":{"type":["string","null"],"description":"Path within the repository (for monorepos)"},"ref":{"type":"string","description":"Git reference (branch, tag, or commit)"},"url":{"type":"string","description":"Git repository URL"}}},"GitSourcePlan":{"type":"object","description":"Git repository the source platform deploys from","required":["owner","repo","branch","is_public"],"properties":{"branch":{"type":"string","description":"Branch the source platform deploys"},"clone_url":{"type":["string","null"],"description":"Full clone URL, e.g. `https://github.com/owner/repo.git`"},"is_public":{"type":"boolean","description":"True when the repository is public (no credentials on the source\nplatform) — the project can then build without a git provider\nconnection."},"owner":{"type":"string","description":"Repository owner (organization or user)"},"repo":{"type":"string","description":"Repository name"}}},"GlobalConversationResponse":{"type":"object","description":"A conversation in the unified cross-project switcher: carries the project it\nbelongs to (name/slug) so the UI can show where the chat was started and\nlink back to the source.","required":["public_id","project_id","context_type","context_id","status","created_at","last_activity_at"],"properties":{"context_id":{"type":"string"},"context_type":{"type":"string"},"created_at":{"type":"string"},"last_activity_at":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"project_name":{"type":["string","null"]},"project_slug":{"type":["string","null"]},"public_id":{"type":"string"},"status":{"type":"string"},"title":{"type":["string","null"]}}},"GlobalEventStatsResponse":{"type":"object","required":["delivered","opened","clicked","bounced","complained"],"properties":{"bounce_rate":{"type":["number","null"],"format":"double"},"bounced":{"type":"integer","format":"int64","minimum":0},"click_rate":{"type":["number","null"],"format":"double"},"clicked":{"type":"integer","format":"int64","minimum":0},"complained":{"type":"integer","format":"int64","minimum":0},"delivered":{"type":"integer","format":"int64","minimum":0},"open_rate":{"type":["number","null"],"format":"double"},"opened":{"type":"integer","format":"int64","minimum":0}}},"GlobalMrrResponse":{"type":"object","required":["currency","current_mrr_minor","previous_mrr_minor"],"properties":{"change_percentage":{"type":["number","null"],"format":"double","description":"Percentage change vs 24h ago. Null when previous MRR is zero\n(no baseline to compare against)."},"currency":{"type":"string"},"current_mrr_minor":{"type":"integer","format":"int64"},"previous_mrr_minor":{"type":"integer","format":"int64","description":"MRR 24h before now, reconstructed from the event log."}}},"GlobalRecentEventResponse":{"type":"object","required":["id","project_id","project_name","occurred_at","event_type"],"properties":{"amount_minor":{"type":["integer","null"],"format":"int64"},"currency":{"type":["string","null"]},"customer_ref":{"type":["string","null"]},"event_type":{"type":"string"},"id":{"type":"integer","format":"int64"},"mrr_minor":{"type":["integer","null"],"format":"int64"},"occurred_at":{"type":"string","format":"date-time"},"project_id":{"type":"integer","format":"int32"},"project_name":{"type":"string"}}},"GlobalRevenueSummaryResponse":{"type":"object","required":["currency","current_mrr_minor","paid_last_30d_minor","refunded_last_30d_minor","paid_all_time_minor","refunded_all_time_minor","active_subscriptions","active_customers","transactions_last_30d"],"properties":{"active_customers":{"type":"integer","format":"int64"},"active_subscriptions":{"type":"integer","format":"int64"},"currency":{"type":"string"},"current_mrr_minor":{"type":"integer","format":"int64"},"paid_all_time_minor":{"type":"integer","format":"int64"},"paid_last_30d_minor":{"type":"integer","format":"int64"},"refunded_all_time_minor":{"type":"integer","format":"int64"},"refunded_last_30d_minor":{"type":"integer","format":"int64"},"transactions_last_30d":{"type":"integer","format":"int64"}}},"GroupedPageMetric":{"type":"object","required":["group_key","events"],"properties":{"cls":{"type":["number","null"],"format":"float"},"country_code":{"type":["string","null"],"description":"ISO 3166-1 alpha-2 code of the group's country. Populated for the\ngeographic dimensions (country/region/city) so clients can match map\ngeometries without name-based lookups; null otherwise."},"events":{"type":"integer","format":"int64"},"fcp":{"type":["number","null"],"format":"float"},"group_key":{"type":"string"},"inp":{"type":["number","null"],"format":"float"},"lcp":{"type":["number","null"],"format":"float"},"ttfb":{"type":["number","null"],"format":"float"}}},"GroupedPageMetricsQuery":{"allOf":[{"$ref":"#/components/schemas/SpeedSegmentFilters","description":"Segment filters — same shape as `PerformanceMetricsQuery`."},{"type":"object","required":["start_date","end_date","project_id","group_by"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"device_type":{"type":["string","null"],"description":"Device type filter: \"desktop\" or \"mobile\""},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"group_by":{"type":"string"},"include_bots":{"type":["boolean","null"],"description":"Include crawler/datacenter (bot) samples. Defaults to false."},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}}]},"GroupedPageMetricsResponse":{"type":"object","required":["groups","total_events","grouped_by"],"properties":{"grouped_by":{"type":"string"},"groups":{"type":"array","items":{"$ref":"#/components/schemas/GroupedPageMetric"}},"total_events":{"type":"integer","format":"int64"}}},"HasAnalyticsEventsResponse":{"type":"object","required":["has_events"],"properties":{"has_events":{"type":"boolean"}}},"HasErrorGroupsResponse":{"type":"object","required":["has_error_groups"],"properties":{"has_error_groups":{"type":"boolean"}}},"HasEventsQuery":{"type":"object","required":["project_id"],"properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"}}},"HasEventsResponse":{"type":"object","required":["has_events"],"properties":{"has_events":{"type":"boolean"}}},"HasMetricsQuery":{"type":"object","required":["project_id"],"properties":{"project_id":{"type":"integer","format":"int32"}}},"HasMetricsResponse":{"type":"object","required":["has_metrics"],"properties":{"has_metrics":{"type":"boolean"}}},"HealthCheckConfiguration":{"type":"object","description":"Health check configuration","required":["port","interval","timeout","retries"],"properties":{"http_path":{"type":["string","null"],"description":"HTTP path to check (if applicable)"},"interval":{"type":"integer","format":"int32","description":"Interval between checks (seconds)","minimum":0},"port":{"type":"integer","format":"int32","description":"Port to check","minimum":0},"retries":{"type":"integer","format":"int32","description":"Number of retries before marking unhealthy","minimum":0},"timeout":{"type":"integer","format":"int32","description":"Timeout for each check (seconds)","minimum":0}}},"HealthCheckEntryResponse":{"type":"object","required":["checked_at","status"],"properties":{"checked_at":{"type":"string","description":"ISO 8601 timestamp of when the probe ran.","example":"2026-04-22T11:30:00Z"},"error_message":{"type":["string","null"],"description":"Present only when the probe failed or was degraded."},"response_time_ms":{"type":["integer","null"],"format":"int32","description":"TCP connect latency in milliseconds."},"status":{"type":"string","description":"\"operational\" | \"degraded\" | \"down\"","example":"operational"}}},"HealthResponse":{"type":"object","required":["summaries"],"properties":{"summaries":{"type":"array","items":{"$ref":"#/components/schemas/HealthSummary"}}}},"HealthStatus":{"type":"string","description":"Overall health status.","enum":["healthy","degraded","down","unknown"]},"HealthSummary":{"type":"object","description":"Pre-computed health summary for a project environment.","required":["project_id","service_name","status","uptime_pct","error_rate","p95_latency_ms","cpu_usage_pct","memory_usage_pct","computed_at"],"properties":{"computed_at":{"type":"string","format":"date-time"},"cpu_usage_pct":{"type":"number","format":"double"},"environment_id":{"type":["integer","null"],"format":"int32"},"error_rate":{"type":"number","format":"double"},"last_deploy_at":{"type":["string","null"],"format":"date-time"},"last_deploy_id":{"type":["integer","null"],"format":"int32"},"memory_usage_pct":{"type":"number","format":"double"},"p95_latency_ms":{"type":"number","format":"double"},"project_id":{"type":"integer","format":"int32"},"service_name":{"type":"string"},"status":{"$ref":"#/components/schemas/HealthStatus"},"uptime_pct":{"type":"number","format":"double"}}},"HeartbeatApiRequest":{"type":"object","properties":{"architecture":{"type":["string","null"],"description":"Container platform of this node's Docker daemon (`linux/amd64`,\n`linux/arm64`), read from `docker info` by the agent. Absent from\npre-multi-arch agents; the stored value is then left untouched."},"capacity":{"description":"Resource capacity/usage info as JSON (cpu_usage, memory_usage, etc.)"},"containers":{"type":["array","null"],"items":{"$ref":"#/components/schemas/ContainerInventoryItem"},"description":"Container inventory for reconciliation (sent on first heartbeat after agent startup).\nEach entry has `container_id` and `container_name` of temps-managed containers."},"labels":{"description":"Updated node labels for scheduling (allows runtime label changes)."}}},"HeartbeatResponse":{"type":"object","required":["status","message"],"properties":{"message":{"type":"string"},"status":{"type":"string"}}},"HierarchyLevel":{"type":"object","description":"Describes a level in the data source hierarchy","required":["level","name","container_type","can_list_containers","can_list_entities"],"properties":{"can_list_containers":{"type":"boolean","description":"Can list containers at this level?","example":true},"can_list_entities":{"type":"boolean","description":"Can list entities at this level?","example":false},"container_type":{"type":"string","description":"Type of container at this level","example":"database"},"level":{"type":"integer","format":"int32","description":"Level number (0 = root)","example":0,"minimum":0},"name":{"type":"string","description":"Human-readable name for this level","example":"root"}}},"HistogramSummary":{"type":"object","description":"An explicit-bucket histogram aggregated over a time bucket.\n\nCarries the reduced scalars (count/sum/min/max) plus the explicit bucket\nlayout — `bounds` (the upper bounds) and `bucket_counts` (observation counts,\nsummed element-wise across the window; length is `bounds.len() + 1`, the last\nentry being the +Inf overflow bucket). With these, a caller can reconstruct\nany quantile (e.g. p95) via cumulative-count interpolation.","required":["count","sum","bounds","bucket_counts"],"properties":{"bounds":{"type":"array","items":{"type":"number","format":"double"},"description":"Explicit bucket upper bounds (OTLP `explicit_bounds`), ascending."},"bucket_counts":{"type":"array","items":{"type":"integer","format":"int64","minimum":0},"description":"Per-bucket observation counts summed element-wise across the window.\nLength is `bounds.len() + 1` (the trailing element is the +Inf bucket)."},"count":{"type":"integer","format":"int64","description":"Total observation count summed across the bucket window.","minimum":0},"max":{"type":["number","null"],"format":"double","description":"Maximum observed value, when reported by the producer."},"min":{"type":["number","null"],"format":"double","description":"Minimum observed value, when reported by the producer."},"sum":{"type":"number","format":"double","description":"Sum of observed values across the bucket window."}}},"HostnameChange":{"type":"object","description":"A single generated-hostname change in a flatten preview/apply.","required":["kind","id","old","new"],"properties":{"id":{"type":"integer","format":"int32","description":"Row id of the affected record."},"kind":{"type":"string","description":"`\"deployment\"` or `\"environment\"`."},"new":{"type":"string"},"old":{"type":"string"}}},"HostnamePreviewResponse":{"type":"object","description":"Combined preview of a hostname-mode change.","required":["hostname_changes","dns_changes","total"],"properties":{"dns_changes":{"type":"array","items":{"$ref":"#/components/schemas/DnsRecordChange"}},"hostname_changes":{"type":"array","items":{"$ref":"#/components/schemas/HostnameChange"}},"total":{"type":"integer","minimum":0},"zone_access_ok":{"type":["boolean","null"],"description":"Whether the provider token can manage this zone (None if not checked)."}}},"HourlyPageSessions":{"type":"object","required":["timestamp","session_count","event_count","avg_duration_seconds"],"properties":{"avg_duration_seconds":{"type":"number","format":"double"},"event_count":{"type":"integer","format":"int64"},"session_count":{"type":"integer","format":"int64"},"timestamp":{"type":"string"}}},"HourlyVisitsQuery":{"type":"object","required":["start_date","end_date"],"properties":{"aggregation_level":{"$ref":"#/components/schemas/AggregationLevel","description":"Aggregation level: events (page views), sessions (unique sessions), or visitors (unique visitors)"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"HttpChallengeDebugResponse":{"type":"object","required":["domain","challenge_exists","dns_a_records","dns_aaaa_records"],"properties":{"challenge_exists":{"type":"boolean"},"challenge_token":{"type":["string","null"]},"challenge_url":{"type":["string","null"],"description":"The full URL that Let's Encrypt will try to access to validate the challenge"},"dns_a_records":{"type":"array","items":{"type":"string"},"description":"IPv4 addresses the domain points to"},"dns_aaaa_records":{"type":"array","items":{"type":"string"},"description":"IPv6 addresses the domain points to"},"dns_error":{"type":["string","null"],"description":"Any DNS resolution errors"},"domain":{"type":"string"},"validation_url":{"type":["string","null"],"description":"The ACME validation URL (internal to ACME protocol)"}}},"ImportCredentials":{"type":"object","description":"Platform-specific credentials for accessing the source system.\n\nFor platforms like Vercel and Railway, this contains the API token.\nFor self-hosted platforms like Coolify and Dokploy, this also contains\nthe `base_url` of the instance.\n\nLocal importers (Docker) can use `ImportCredentials::none()`.","properties":{"base_url":{"type":["string","null"],"description":"Base URL override (for self-hosted platforms like Coolify, Dokploy)\n\nExample: `https://coolify.example.com`"},"extra":{"type":"object","description":"Additional platform-specific parameters","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"team_id":{"type":["string","null"],"description":"Team or organization ID (for platforms with team scoping like Vercel)"},"token":{"type":["string","null"],"description":"API token / bearer token for the source platform"}}},"ImportExecutionStatus":{"type":"string","description":"Import execution status","enum":["pending","inprogress","completed","failed"]},"ImportExternalServiceRequest":{"type":"object","description":"Request to import a Docker container as a managed service","required":["name","service_type","parameters","container_id"],"properties":{"container_id":{"type":"string","description":"Container ID or name to import","example":"abc123def456"},"name":{"type":"string","description":"Name to register the service as in Temps","example":"production-database"},"parameters":{"type":"object","description":"Service configuration parameters","additionalProperties":{},"propertyNames":{"type":"string"}},"service_type":{"$ref":"#/components/schemas/ServiceTypeRoute","description":"Service type"},"version":{"type":["string","null"],"description":"Optional version override"}}},"ImportOutcomeResponse":{"type":"object","required":["rows_read","inserted","updated","skipped_stale","skipped_invalid","errors"],"properties":{"errors":{"type":"array","items":{"$ref":"#/components/schemas/ImportRowErrorResponse"}},"inserted":{"type":"integer","minimum":0},"rows_read":{"type":"integer","minimum":0},"skipped_invalid":{"type":"integer","minimum":0},"skipped_stale":{"type":"integer","minimum":0},"updated":{"type":"integer","minimum":0}}},"ImportPlan":{"type":"object","description":"Complete import plan describing all operations to onboard a workload.\n\nThe plan is generated from a snapshot and presented to the user for review\nbefore any resources are created. Users can modify individual items\n(skip services, change actions) before approving execution.","required":["version","source","source_id","project","environment","deployment","summary","metadata"],"properties":{"additional_deployments":{"type":"array","items":{"$ref":"#/components/schemas/DeploymentConfiguration"},"description":"Additional deployments (workers, cron jobs, etc.)"},"cost_analysis":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/CostAnalysis","description":"Cost, overprovisioning, and savings analysis. Populated by importers\nthat can observe the whole source cluster (currently Kubernetes);\n`None` for container/platform imports."}]},"deployment":{"$ref":"#/components/schemas/DeploymentConfiguration","description":"Primary deployment configuration"},"domains":{"type":"array","items":{"$ref":"#/components/schemas/DomainPlan"},"description":"Custom domains to migrate"},"environment":{"$ref":"#/components/schemas/EnvironmentConfiguration","description":"Environment configuration"},"metadata":{"$ref":"#/components/schemas/PlanMetadata","description":"Plan metadata"},"project":{"$ref":"#/components/schemas/ProjectConfiguration","description":"Project configuration"},"services":{"type":"array","items":{"$ref":"#/components/schemas/ServicePlan"},"description":"Services to migrate (databases, caches, blob stores)\n\nEach service has an `action` field the user can change before execution."},"source":{"type":"string","description":"Source system this plan was generated from"},"source_id":{"type":"string","description":"Source workload / project ID in the source system"},"steps":{"type":"array","items":{"$ref":"#/components/schemas/MigrationStep"},"description":"Ordered list of migration steps that will be executed.\n\nThis is the human-readable execution plan. Each step describes what\nwill happen, what risks are involved, and what the user should verify.\nSteps are executed in order. If a step fails, execution stops and\nalready-created resources are reported for manual cleanup."},"summary":{"$ref":"#/components/schemas/MigrationSummary","description":"Human-readable summary of the entire migration"},"version":{"type":"string","description":"Plan version for compatibility tracking"}}},"ImportRowErrorResponse":{"type":"object","required":["row","reason"],"properties":{"reason":{"type":"string"},"row":{"type":"integer","minimum":0}}},"ImportSelector":{"type":"object","description":"Selector for discovering workloads","properties":{"label_filter":{"type":["object","null"],"description":"Filter by labels/tags","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"limit":{"type":["integer","null"],"description":"Limit number of results","minimum":0},"name_pattern":{"type":["string","null"],"description":"Filter by name pattern (glob/regex)"},"status_filter":{"type":["array","null"],"items":{"type":"string"},"description":"Filter by status (running, stopped, deployed, etc.)"},"workload_type_filter":{"type":["array","null"],"items":{"type":"string"},"description":"Filter by workload type (container, function, static-site, etc.)"}}},"ImportSource":{"type":"string","description":"Import source identifier","enum":["docker","coolify","dokploy","vercel","netlify","railway","render","fly","kubernetes","caprover","portainer","kamal","custom"]},"ImportSourceCapabilities":{"type":"object","description":"Source capabilities","required":["supports_volumes","supports_networks","supports_health_checks","supports_resource_limits","supports_build","supports_services","supports_domains","supports_project_snapshot","supports_cost_analysis","requires_credentials"],"properties":{"requires_credentials":{"type":"boolean","description":"Whether this source requires API credentials (token, base URL)"},"supports_build":{"type":"boolean"},"supports_cost_analysis":{"type":"boolean","description":"Supports cluster cost + overprovisioning analysis in the plan"},"supports_domains":{"type":"boolean","description":"Supports custom domain migration"},"supports_health_checks":{"type":"boolean"},"supports_networks":{"type":"boolean"},"supports_project_snapshot":{"type":"boolean","description":"Supports full project-level snapshots"},"supports_resource_limits":{"type":"boolean"},"supports_services":{"type":"boolean","description":"Supports service migration (databases, caches, etc.)"},"supports_volumes":{"type":"boolean"}}},"ImportSourceInfo":{"type":"object","description":"Information about an import source","required":["source","name","version","available","capabilities"],"properties":{"available":{"type":"boolean","description":"Whether the source is currently available"},"capabilities":{"$ref":"#/components/schemas/ImportSourceCapabilities","description":"Capabilities"},"name":{"type":"string","description":"Human-readable name"},"source":{"$ref":"#/components/schemas/ImportSource","description":"Source identifier"},"version":{"type":"string","description":"Source version"}}},"ImportStatusResponse":{"type":"object","description":"Response with import status","required":["session_id","status","errors","warnings","created_at","updated_at"],"properties":{"created_at":{"type":"string","format":"date-time","description":"Created at timestamp"},"deployment_id":{"type":["integer","null"],"format":"int32","description":"Created deployment ID"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Created environment ID"},"errors":{"type":"array","items":{"type":"string"},"description":"Errors (if any)"},"plan":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ImportPlan","description":"Import plan"}]},"project_id":{"type":["integer","null"],"format":"int32","description":"Created project ID"},"session_id":{"type":"string","description":"Session ID"},"status":{"$ref":"#/components/schemas/ImportExecutionStatus","description":"Current status"},"updated_at":{"type":"string","format":"date-time","description":"Updated at timestamp"},"validation":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ValidationReport","description":"Validation report"}]},"warnings":{"type":"array","items":{"type":"string"},"description":"Warnings (if any)"}}},"IncidentBucket":{"type":"object","required":["bucket_start","total_incidents","minor_incidents","major_incidents","critical_incidents","resolved_incidents","active_incidents"],"properties":{"active_incidents":{"type":"integer","format":"int64"},"avg_resolution_time_minutes":{"type":["number","null"],"format":"double"},"bucket_start":{"type":"string","format":"date-time"},"critical_incidents":{"type":"integer","format":"int64"},"major_incidents":{"type":"integer","format":"int64"},"minor_incidents":{"type":"integer","format":"int64"},"resolved_incidents":{"type":"integer","format":"int64"},"total_incidents":{"type":"integer","format":"int64"}}},"IncidentBucketedResponse":{"type":"object","required":["project_id","interval","buckets"],"properties":{"buckets":{"type":"array","items":{"$ref":"#/components/schemas/IncidentBucket"}},"environment_id":{"type":["integer","null"],"format":"int32"},"interval":{"type":"string"},"project_id":{"type":"integer","format":"int32"}}},"IncidentResponse":{"type":"object","required":["id","project_id","title","severity","status","started_at","created_at","updated_at"],"properties":{"created_at":{"type":"string","format":"date-time"},"description":{"type":["string","null"]},"environment_id":{"type":["integer","null"],"format":"int32"},"id":{"type":"integer","format":"int32"},"monitor_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"resolved_at":{"type":["string","null"],"format":"date-time"},"severity":{"type":"string"},"started_at":{"type":"string","format":"date-time"},"status":{"type":"string"},"title":{"type":"string"},"updated_at":{"type":"string","format":"date-time"}}},"IncidentUpdateResponse":{"type":"object","required":["id","incident_id","status","message","created_at"],"properties":{"created_at":{"type":"string","format":"date-time"},"id":{"type":"integer","format":"int32"},"incident_id":{"type":"integer","format":"int32"},"message":{"type":"string"},"status":{"type":"string"}}},"IncrRequest":{"type":"object","description":"Request to increment a value","required":["key"],"properties":{"amount":{"type":["integer","null"],"format":"int64","description":"Amount to increment by (default: 1)"},"key":{"type":"string","description":"The key to increment","example":"counter"},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1}}},"IncrResponse":{"type":"object","description":"Response for increment operation","required":["value"],"properties":{"value":{"type":"integer","format":"int64","description":"New value after increment","example":42}}},"InitAuthResponse":{"type":"object","required":["auth_url","session_token"],"properties":{"auth_url":{"type":"string"},"session_token":{"type":"string"}}},"Insight":{"type":"object","description":"An anomaly insight.","required":["id","project_id","service_name","severity","status","title","description","anomaly_ids","started_at","created_at","updated_at"],"properties":{"anomaly_ids":{"type":"array","items":{"type":"integer","format":"int64"}},"correlated_deploy_id":{"type":["integer","null"],"format":"int32"},"created_at":{"type":"string","format":"date-time"},"description":{"type":"string"},"environment":{"type":["string","null"]},"id":{"type":"integer","format":"int64"},"metric_name":{"type":["string","null"]},"project_id":{"type":"integer","format":"int32"},"resolved_at":{"type":["string","null"],"format":"date-time"},"service_name":{"type":"string"},"severity":{"$ref":"#/components/schemas/InsightSeverity"},"started_at":{"type":"string","format":"date-time"},"status":{"$ref":"#/components/schemas/InsightStatus"},"title":{"type":"string"},"updated_at":{"type":"string","format":"date-time"}}},"InsightSeverity":{"type":"string","description":"Severity of an anomaly insight.","enum":["low","medium","high","critical"]},"InsightStatus":{"type":"string","description":"Status of an insight.","enum":["active","resolved"]},"InsightsResponse":{"type":"object","required":["data","count"],"properties":{"count":{"type":"integer","minimum":0},"data":{"type":"array","items":{"$ref":"#/components/schemas/Insight"}}}},"IntegrationResponse":{"type":"object","required":["id","project_id","provider","webhook_path_token","webhook_path","status","has_secret","created_at"],"properties":{"config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ProviderConfig","description":"Typed provider config — allowlist and metered-billing mode. Null\nwhen the operator hasn't configured one yet (accept everything)."}]},"created_at":{"type":"string","format":"date-time"},"has_secret":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"last_event_at":{"type":["string","null"],"format":"date-time"},"project_id":{"type":"integer","format":"int32"},"provider":{"type":"string"},"status":{"type":"string"},"webhook_path":{"type":"string","description":"Relative path the UI can display and copy. The frontend builds\nthe full URL by prefixing its own origin."},"webhook_path_token":{"type":"string","description":"Unguessable token embedded in the public webhook URL. The full\nURL is `{api_origin}/webhooks/revenue/{provider}/{webhook_path_token}`."}}},"IpAccessControlQuery":{"type":"object","description":"Query parameters for listing IP access control rules","properties":{"action":{"type":["string","null"],"description":"Filter by action (\"block\" or \"allow\")"}}},"IpAccessControlResponse":{"type":"object","description":"Response model for IP access control rules","required":["id","ip_address","action","created_at","updated_at"],"properties":{"action":{"type":"string"},"created_at":{"type":"string","example":"2025-10-12T12:15:47.609Z"},"created_by":{"type":["integer","null"],"format":"int32"},"id":{"type":"integer","format":"int32"},"ip_address":{"type":"string"},"reason":{"type":["string","null"]},"updated_at":{"type":"string","example":"2025-10-12T12:15:47.609Z"}}},"JobStatusResponse":{"type":"object","description":"Snapshot of a background job. `status` is one of \"running\" | \"exited\"\n| \"failed\"; `exit_code` is populated only when `status == \"exited\"`.","required":["status","stdout","stderr"],"properties":{"exit_code":{"type":["integer","null"],"format":"int32"},"reason":{"type":["string","null"]},"status":{"type":"string"},"stderr":{"type":"string"},"stdout":{"type":"string"}}},"JobSummaryResponse":{"type":"object","description":"Row in the jobs list. Omits stdout/stderr so a noisy dev server doesn't\nbloat the list payload — callers drill into `GET /jobs/{id}` for the\nfull buffer.","required":["id","status","cmd","started_at"],"properties":{"cmd":{"type":"string"},"exit_code":{"type":["integer","null"],"format":"int32"},"id":{"type":"string"},"reason":{"type":["string","null"]},"started_at":{"type":"string"},"status":{"type":"string"}}},"JoinTokenStatusResponse":{"type":"object","description":"Response for join token status check","required":["has_token"],"properties":{"has_token":{"type":"boolean","description":"Whether a join token has been configured"}}},"JourneyEvent":{"type":"object","description":"A single event in the visitor journey timeline","required":["id","event_type","event_name","occurred_at","is_entry","is_exit","is_bounce"],"properties":{"event_data":{"description":"Custom event properties (for custom events)"},"event_name":{"type":"string","description":"Resolved event name (event_name for custom events, event_type for system events)"},"event_type":{"type":"string","description":"Event type: \"page_view\", \"page_leave\", \"custom\", \"web_vitals\""},"id":{"type":"integer","format":"int64","description":"Event ID"},"is_bounce":{"type":"boolean","description":"Whether this was a bounce"},"is_entry":{"type":"boolean","description":"Whether this is the entry page of the session"},"is_exit":{"type":"boolean","description":"Whether this is the exit page of the session"},"occurred_at":{"type":"string","format":"date-time","description":"When the event occurred"},"page_path":{"type":["string","null"],"description":"Page path where the event happened"},"page_title":{"type":["string","null"],"description":"Page title (if available)"},"referrer":{"type":["string","null"],"description":"Referrer URL for this event"},"scroll_depth":{"type":["integer","null"],"format":"int32","description":"Scroll depth percentage (0-100)"},"session_page_number":{"type":["integer","null"],"format":"int32","description":"Page number within the session (1-indexed)"},"time_on_page":{"type":["integer","null"],"format":"int32","description":"Time spent on page in seconds (computed, not from column)"}}},"JourneySession":{"type":"object","description":"A session within the visitor journey, grouping events","required":["session_id","started_at","duration_seconds","page_views","events_count","is_bounced","is_engaged","events"],"properties":{"channel":{"type":["string","null"],"description":"Traffic source: channel (e.g. \"organic\", \"direct\", \"social\")"},"duration_seconds":{"type":"integer","format":"int64","description":"Session duration in seconds"},"ended_at":{"type":["string","null"],"format":"date-time","description":"When the session ended"},"entry_path":{"type":["string","null"],"description":"Entry page path"},"events":{"type":"array","items":{"$ref":"#/components/schemas/JourneyEvent"},"description":"Events within this session, ordered chronologically"},"events_count":{"type":"integer","format":"int64","description":"Total events in this session"},"exit_path":{"type":["string","null"],"description":"Exit page path"},"is_bounced":{"type":"boolean","description":"Whether the session was a bounce"},"is_engaged":{"type":"boolean","description":"Whether the visitor was engaged (had non-pageview events)"},"page_views":{"type":"integer","format":"int64","description":"Number of page views in this session"},"referrer":{"type":["string","null"],"description":"Traffic source: referrer URL"},"referrer_hostname":{"type":["string","null"],"description":"Traffic source: referrer hostname"},"session_id":{"type":"integer","format":"int32","description":"Session internal ID"},"started_at":{"type":"string","format":"date-time","description":"When the session started"},"utm_campaign":{"type":["string","null"],"description":"UTM campaign parameter"},"utm_medium":{"type":["string","null"],"description":"UTM medium parameter"},"utm_source":{"type":["string","null"],"description":"UTM source parameter"}}},"KeysRequest":{"type":"object","description":"Request to get keys matching a pattern","required":["pattern"],"properties":{"pattern":{"type":"string","description":"Pattern to match (supports * and ? wildcards)","example":"user:*"},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1}}},"KeysResponse":{"type":"object","description":"Response for keys operation","required":["keys"],"properties":{"keys":{"type":"array","items":{"type":"string"},"description":"List of matching keys","example":["user:1","user:2","user:3"]}}},"KillJobBody":{"type":"object","properties":{"force":{"type":"boolean","description":"When true, sends SIGKILL immediately. Defaults to SIGTERM so the\nprocess gets a chance to flush (mirrors `Command.kill()` in\n`@vercel/sandbox`, which also accepts a signal override)."}},"additionalProperties":false},"KnownAiAgentsResponse":{"type":"object","description":"Response listing every AI agent the detector knows about.","required":["items"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AiAgentDescriptor"}}}},"KvStatusResponse":{"type":"object","description":"Response for KV service status","required":["enabled","healthy"],"properties":{"docker_image":{"type":["string","null"],"description":"Docker image being used","example":"gotempsh/redis-walg:8-bookworm"},"enabled":{"type":"boolean","description":"Whether the KV service is enabled"},"healthy":{"type":"boolean","description":"Whether the underlying Redis service is healthy"},"version":{"type":["string","null"],"description":"Service version","example":"7.2"}}},"LemonSqueezyConfig":{"type":"object","properties":{"product_allowlist":{"type":"array","items":{"type":"string"}},"variant_allowlist":{"type":"array","items":{"type":"string"}}}},"LetsEncryptSettings":{"type":"object","properties":{"email":{"type":["string","null"],"default":null},"environment":{"type":"string","default":"production"}}},"LineContext":{"type":"object","description":"Raw surrounding lines for a single match (grep -C style).","required":["before","after"],"properties":{"after":{"type":"array","items":{"$ref":"#/components/schemas/ContextLine"},"description":"Lines immediately after the match, oldest-first."},"before":{"type":"array","items":{"$ref":"#/components/schemas/ContextLine"},"description":"Lines immediately before the match, oldest-first."}}},"LinkServiceRequest":{"type":"object","required":["project_id"],"properties":{"project_id":{"type":"integer","format":"int32"}}},"ListAgentsResponse":{"type":"object","required":["items","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AgentConfigResponse"}},"total":{"type":"integer","minimum":0}}},"ListApiKeysQuery":{"type":"object","properties":{"page":{"type":["integer","null"],"format":"int64","minimum":0},"page_size":{"type":["integer","null"],"format":"int64","minimum":0}}},"ListAuditLogsQuery":{"type":"object","description":"Query parameters for listing audit logs.\n\nEvery field is optional — omitting one means \"don't filter on it\". Deriving\n`IntoParams` makes utoipa render them as optional query params with the\ncorrect types; the previous hand-written `params((\"operation_type\", Query,\n…))` tuples defaulted every param to `required: true, type: string`, which\nmisled both API clients and the AI `describe_api`/`call_api` tools into\nthinking all filters were mandatory.","properties":{"from":{"type":["string","null"],"format":"date-time","description":"Start timestamp (milliseconds since epoch)"},"limit":{"type":["integer","null"],"format":"int32","description":"Maximum number of logs to return"},"offset":{"type":["integer","null"],"format":"int32","description":"Number of logs to skip"},"operation_type":{"type":["string","null"],"description":"Filter logs by operation type (omit for all)"},"to":{"type":["string","null"],"format":"date-time","description":"End timestamp (milliseconds since epoch)"},"user_id":{"type":["integer","null"],"format":"int32","description":"Filter logs by user ID (omit for all users)"}}},"ListBlobsQuery":{"type":"object","description":"Query parameters for listing blobs","properties":{"cursor":{"type":["string","null"],"description":"Continuation token for pagination"},"limit":{"type":["integer","null"],"format":"int32","description":"Maximum number of items to return","example":100},"prefix":{"type":["string","null"],"description":"Prefix to filter by","example":"images/"},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1}}},"ListBlobsResponse":{"type":"object","description":"Response for listing blobs","required":["blobs","hasMore"],"properties":{"blobs":{"type":"array","items":{"$ref":"#/components/schemas/BlobResponse"},"description":"List of blobs"},"cursor":{"type":["string","null"],"description":"Continuation token for next page"},"hasMore":{"type":"boolean","description":"Whether there are more results","example":false}}},"ListCustomDomainsResponse":{"type":"object","required":["domains","total"],"properties":{"domains":{"type":"array","items":{"$ref":"#/components/schemas/CustomDomainResponse"}},"total":{"type":"integer","minimum":0}}},"ListDeploymentTokensQuery":{"type":"object","properties":{"page":{"type":["integer","null"],"format":"int64","example":1,"minimum":0},"page_size":{"type":["integer","null"],"format":"int64","example":20,"minimum":0}}},"ListDomainsResponse":{"type":"object","required":["domains","total","page","page_size"],"properties":{"domains":{"type":"array","items":{"$ref":"#/components/schemas/DomainResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"ListEntitiesQuery":{"type":"object","properties":{"limit":{"type":"integer","description":"Maximum number of entities to return","example":100,"minimum":0},"token":{"type":["string","null"],"description":"Continuation token for pagination (backend-specific)"}}},"ListErrorEventsQuery":{"type":"object","properties":{"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0}}},"ListErrorGroupsQuery":{"type":"object","properties":{"end_date":{"type":["string","null"],"format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"sort_by":{"type":["string","null"]},"sort_order":{"type":"string"},"start_date":{"type":["string","null"],"format":"date-time"},"status":{"type":["string","null"]}}},"ListJobsResponse":{"type":"object","required":["items"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/JobSummaryResponse"}}}},"ListMcpsResponse":{"type":"object","description":"Concrete list wrapper for MCP server definitions (utoipa requires non-generic types).","required":["items","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/McpDefinitionResponse"}},"total":{"type":"integer","minimum":0}}},"ListOnDemandCertsResponse":{"type":"object","description":"Paginated list of on-demand cert attempts (ADR-018 §5 console \"Certificates\"\nsurface). Joined with current `domains.status`, newest first.","required":["certs","total","page","page_size"],"properties":{"certs":{"type":"array","items":{"$ref":"#/components/schemas/OnDemandCertRow"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"ListOrdersResponse":{"type":"object","required":["orders"],"properties":{"orders":{"type":"array","items":{"$ref":"#/components/schemas/AcmeOrderResponse"}}}},"ListPresetsResponse":{"type":"object","required":["presets","total"],"properties":{"presets":{"type":"array","items":{"$ref":"#/components/schemas/PresetResponse"}},"total":{"type":"integer","minimum":0}}},"ListRunsResponse":{"type":"object","required":["items","total","page","page_size"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AgentRunResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"ListSandboxesResponse":{"type":"object","description":"SDK list response: `{ sandboxes: [...], pagination: {...} }`.","required":["sandboxes","pagination"],"properties":{"pagination":{"$ref":"#/components/schemas/Pagination"},"sandboxes":{"type":"array","items":{"$ref":"#/components/schemas/SandboxInner"}}}},"ListScansQuery":{"type":"object","properties":{"page":{"type":["integer","null"],"format":"int64","example":1,"minimum":0},"page_size":{"type":["integer","null"],"format":"int64","example":20,"minimum":0}}},"ListSecretsResponse":{"type":"object","required":["items","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/SecretResponse"}},"total":{"type":"integer","minimum":0}}},"ListSkillsResponse":{"type":"object","description":"Concrete list wrapper for skill definitions (utoipa requires non-generic types).","required":["items","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/SkillDefinitionResponse"}},"total":{"type":"integer","minimum":0}}},"ListTagsResponse":{"type":"object","description":"Response for listing tags","required":["tags","total"],"properties":{"tags":{"type":"array","items":{"type":"string"},"description":"List of available tags"},"total":{"type":"integer","description":"Total number of tags","minimum":0}}},"ListTemplatesQuery":{"type":"object","description":"Query parameters for listing templates","properties":{"featured":{"type":["boolean","null"],"description":"Only return featured templates"},"tag":{"type":["string","null"],"description":"Filter templates by tag"}}},"ListTemplatesResponse":{"type":"object","description":"Response for listing templates","required":["templates","total"],"properties":{"templates":{"type":"array","items":{"$ref":"#/components/schemas/TemplateResponse"},"description":"List of templates"},"total":{"type":"integer","description":"Total number of templates","minimum":0}}},"ListVulnerabilitiesQuery":{"type":"object","properties":{"page":{"type":["integer","null"],"format":"int64","example":1,"minimum":0},"page_size":{"type":["integer","null"],"format":"int64","example":20,"minimum":0},"severity":{"type":["string","null"],"example":"CRITICAL"}}},"LiveVisitorInfo":{"type":"object","required":["id","visitor_id","project_id","environment_id","first_seen","last_seen","is_crawler"],"properties":{"city":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"crawler_name":{"type":["string","null"]},"current_page":{"type":["string","null"],"description":"Most recent page path visited by this visitor"},"custom_data":{},"environment_id":{"type":"integer","format":"int32"},"first_channel":{"type":["string","null"],"description":"Marketing channel from the first visit (e.g. \"Organic Search\", \"Direct\")"},"first_referrer":{"type":["string","null"],"description":"Full referrer URL from the visitor's first session"},"first_referrer_hostname":{"type":["string","null"],"description":"Hostname extracted from first_referrer"},"first_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"id":{"type":"integer","format":"int32"},"ip_address":{"type":["string","null"]},"ip_address_id":{"type":["integer","null"],"format":"int32"},"is_crawler":{"type":"boolean"},"is_eu":{"type":["boolean","null"]},"last_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"latitude":{"type":["number","null"],"format":"double"},"longitude":{"type":["number","null"],"format":"double"},"project_id":{"type":"integer","format":"int32"},"region":{"type":["string","null"]},"timezone":{"type":["string","null"]},"user_agent":{"type":["string","null"]},"visitor_id":{"type":"string"}}},"LiveVisitorsListResponse":{"type":"object","required":["total_count","visitors","window_minutes"],"properties":{"total_count":{"type":"integer","format":"int64"},"visitors":{"type":"array","items":{"$ref":"#/components/schemas/LiveVisitorInfo"}},"window_minutes":{"type":"integer","format":"int32"}}},"LocationCount":{"type":"object","required":["location","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"location":{"type":"string"},"percentage":{"type":"number","format":"double"}}},"LocationGranularity":{"type":"string","enum":["country","region","city"]},"LocationInfo":{"type":"object","properties":{"city":{"type":["string","null"]},"country":{"type":["string","null"]},"region":{"type":["string","null"]}}},"LogLevel":{"type":"string","description":"Normalized log level","enum":["TRACE","DEBUG","INFO","WARN","ERROR"]},"LogRecord":{"type":"object","description":"A single log record ready for storage.","required":["project_id","resource","timestamp","observed_timestamp","severity","severity_text","body","attributes"],"properties":{"attributes":{"type":"object","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"body":{"type":"string"},"deployment_id":{"type":["integer","null"],"format":"int32"},"observed_timestamp":{"type":"string","format":"date-time"},"project_id":{"type":"integer","format":"int32"},"resource":{"$ref":"#/components/schemas/ResourceInfo"},"severity":{"$ref":"#/components/schemas/LogSeverity"},"severity_text":{"type":"string"},"span_id":{"type":["string","null"]},"timestamp":{"type":"string","format":"date-time"},"trace_id":{"type":["string","null"]}}},"LogSearchLine":{"type":"object","description":"A single line in search results","required":["timestamp","level","service","message","chunk_id","line_offset"],"properties":{"chunk_id":{"type":"string"},"container_id":{"type":"string","description":"Container this line came from — lets the UI tag/group lines by container\nin a combined (\"show all\") multi-container view."},"context":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/LineContext","description":"Raw surrounding lines (grep -C). `None` unless `context_lines > 0` was\nrequested. Overlapping windows between nearby matches are merged: the\nshared neighbors appear on the earlier match only, so the frontend can\nrender one continuous block without duplicated lines."}]},"deploy_id":{"type":["integer","null"],"format":"int32"},"fields":{},"level":{"$ref":"#/components/schemas/LogLevel"},"line_offset":{"type":"integer","format":"int32"},"message":{"type":"string"},"node_id":{"type":["integer","null"],"format":"int32","description":"Worker node the line came from (`None` = control-plane-local)."},"node_name":{"type":["string","null"],"description":"Human-readable node name for display."},"service":{"type":"string"},"timestamp":{"type":"string"}}},"LogSeverity":{"type":"string","description":"Log severity level (simplified from OTel's 24 levels).","enum":["TRACE","DEBUG","INFO","WARN","ERROR","FATAL"]},"LogSource":{"type":"object","description":"A distinct log source (container) seen in the queried scope. Used to populate\nthe history filter dropdowns with the *full* set of containers/nodes for the\nproject + env + deployment + time window — independent of the active\ncontainer/node/service filter, so the user can switch between them.","required":["container_id","service"],"properties":{"container_id":{"type":"string"},"node_id":{"type":["integer","null"],"format":"int32"},"node_name":{"type":["string","null"]},"service":{"type":"string"}}},"LogStream":{"type":"string","description":"Log output stream","enum":["stdout","stderr"]},"LoginRequest":{"type":"object","required":["email","password"],"properties":{"email":{"type":"string"},"password":{"type":"string"}}},"LogsQuery":{"type":"object","properties":{"tail":{"type":["integer","null"],"description":"Number of lines to return from the tail. Defaults to 200, capped at 2000.","minimum":0}}},"LogsResponse":{"type":"object","required":["data","count"],"properties":{"count":{"type":"integer","minimum":0},"data":{"type":"array","items":{"$ref":"#/components/schemas/LogRecord"}}}},"ManagedDomainResponse":{"type":"object","description":"Managed domain response","required":["id","provider_id","domain","auto_manage","verified","generated_hostname_mode","sync_generated_records","created_at","updated_at"],"properties":{"auto_manage":{"type":"boolean"},"created_at":{"type":"string"},"domain":{"type":"string"},"generated_hostname_mode":{"type":"string","description":"Generated hostname layout: `\"standard\"` or `\"flat\"`."},"id":{"type":"integer","format":"int32"},"provider_id":{"type":"integer","format":"int32"},"sync_generated_records":{"type":"boolean","description":"Whether generated hostnames are reconciled into the provider's DNS zone."},"updated_at":{"type":"string"},"verification_error":{"type":["string","null"]},"verified":{"type":"boolean"},"verified_at":{"type":["string","null"]},"zone_access_error":{"type":["string","null"],"description":"Detail for a failed zone-access check."},"zone_access_ok":{"type":["boolean","null"],"description":"Last token zone-access check: `Some(true)`/`Some(false)`/`None` (unchecked)."},"zone_id":{"type":["string","null"]}}},"ManualAction":{"type":"object","description":"A manual action the user must perform outside of the automated migration","required":["timing","description","reason"],"properties":{"description":{"type":"string","description":"Human-readable description"},"reason":{"type":"string","description":"Why this can't be automated"},"timing":{"$ref":"#/components/schemas/ManualActionTiming","description":"When this action needs to happen"}}},"ManualActionTiming":{"type":"string","description":"When a manual action needs to happen relative to migration","enum":["before-migration","after-migration","within-hours"]},"McpDefinitionResponse":{"type":"object","required":["id","slug","name","config","created_at","updated_at"],"properties":{"config":{"type":"object"},"created_at":{"type":"string"},"description":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"project_id":{"type":["integer","null"],"format":"int32"},"slug":{"type":"string"},"updated_at":{"type":"string"}}},"MessageContent":{"oneOf":[{"type":"string"},{"type":"array","items":{"$ref":"#/components/schemas/ContentPart"}}]},"MessagePart":{"oneOf":[{"type":"object","required":["text","type"],"properties":{"text":{"type":"string"},"type":{"type":"string","enum":["text"]}}},{"type":"object","required":["tool","type"],"properties":{"tool":{"$ref":"#/components/schemas/ToolInfo"},"type":{"type":"string","enum":["tool"]}}}],"description":"One ordered segment of an assistant turn: a chunk of prose, or a tool\ninvocation. Mirrors the `metadata.parts` persisted by the chat service."},"MessageResponse":{"type":"object","required":["role","content","created_at"],"properties":{"content":{"type":"string"},"created_at":{"type":"string"},"parts":{"type":["array","null"],"items":{"$ref":"#/components/schemas/MessagePart"},"description":"Ordered render segments (text / tool, in the order they occurred) so a\nreloaded chat shows the same interleaving as the live stream. Absent for\nolder messages persisted before parts were tracked; the client then falls\nback to `tools` (rendered first) + `content`."},"role":{"type":"string"},"tools":{"type":["array","null"],"items":{"$ref":"#/components/schemas/ToolInfo"},"description":"Tools the assistant ran on this turn (persisted in message metadata), so\nthe chat replays its tool work after a reload. Absent for plain turns."}}},"MeteredMode":{"type":"string","description":"How to treat metered-billing subscriptions when computing MRR.\n\n* `DeriveFromInvoices` (default): ignore the subscription row's\n `mrr_minor` for metered items and rely on the per-invoice\n [`NormalizedEventType::MrrRealized`] events instead. Correct for\n pure-metered, hybrid, tiered, and flat — recommended.\n* `UseSubscription`: trust whatever MRR the subscription parser\n returns (0 for metered). Legacy behavior.\n* `Ignore`: drop metered subscriptions from MRR entirely.","enum":["derive_from_invoices","use_subscription","ignore"]},"MetricAggregation":{"oneOf":[{"type":"string","description":"Arithmetic mean of the scalar value in each bucket. The default.","enum":["avg"]},{"type":"string","description":"Sum of the scalar value in each bucket.","enum":["sum"]},{"type":"string","description":"Minimum scalar value in each bucket.","enum":["min"]},{"type":"string","description":"Maximum scalar value in each bucket.","enum":["max"]},{"type":"string","description":"Number of points in each bucket.","enum":["count"]},{"type":"string","description":"Per-second rate of change of a cumulative monotonic counter, computed as\n`(max - min) / window_seconds` within each bucket. Non-monotonic series\nfall back to a simple delta.","enum":["rate_per_sec"]},{"type":"object","description":"A quantile of the scalar value in each bucket. The carried `f64` is the\nrequested quantile in `[0.0, 1.0]`.","required":["quantile"],"properties":{"quantile":{"type":"number","format":"double","description":"A quantile of the scalar value in each bucket. The carried `f64` is the\nrequested quantile in `[0.0, 1.0]`."}}}],"description":"The aggregation applied when reducing raw metric points into a time bucket.\n\nStore-neutral: every storage backend (ClickHouse today, TimescaleDB later)\nmust be able to satisfy this contract. `Quantile(q)` carries the requested\nquantile in `[0.0, 1.0]` (e.g. `0.95` for p95)."},"MetricBucket":{"type":"object","description":"A time-bucketed metric aggregate for chart display.\n\nStore-neutral response contract. The legacy scalar fields\n(`avg_value`/`min_value`/`max_value`/`count`) are always populated for chart\nback-compat. The richer fields describe the explicitly-requested\n[`MetricAggregation`] (`value`), optional `quantiles`, an optional\n`histogram_summary`, and a `series_key` identifying the label-set when the\nquery used `group_by`.","required":["bucket","avg_value","min_value","max_value","count"],"properties":{"avg_value":{"type":"number","format":"double"},"bucket":{"type":"string","format":"date-time"},"count":{"type":"integer","format":"int64"},"histogram_summary":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/HistogramSummary","description":"A reduced histogram summary when the bucketed metric is a histogram."}]},"max_value":{"type":"number","format":"double"},"min_value":{"type":"number","format":"double"},"quantiles":{"type":"array","items":{"type":"array","items":false,"prefixItems":[{"type":"number","format":"double"},{"type":"number","format":"double"}]},"description":"Computed quantile/value pairs `(quantile, value)` when the query asked for\nquantile aggregation; otherwise empty."},"series_key":{"type":["array","null"],"items":{"type":"array","items":false,"prefixItems":[{"type":"string"},{"type":"string"}]},"description":"The label-set this bucket belongs to, as ordered `(key, value)` pairs,\nwhen the query grouped by labels. Empty/`None` = the single ungrouped\naggregate stream."},"value":{"type":"number","format":"double","description":"The value of the requested [`MetricAggregation`] for this bucket. For the\ndefault `Avg` aggregation this equals `avg_value`. `#[serde(default)]` so\npre-existing payloads (which only carried avg/min/max/count) still parse."}}},"MetricDataPoint":{"type":"object","description":"A single `(timestamp, value)` data point in a metric series.","required":["time","value"],"properties":{"time":{"type":"string","description":"ISO 8601 timestamp with `Z` suffix."},"value":{"type":"number","format":"double","description":"Metric value at this bucket."}}},"MetricType":{"type":"string","description":"The type of an OTel metric.","enum":["gauge","sum","histogram","exponential_histogram","summary"]},"MetricsOverTimeResponse":{"type":"object","required":["timestamps","ttfb","lcp","fid","fcp","cls","inp"],"properties":{"cls":{"type":"array","items":{"type":["number","null"],"format":"float"}},"cls_p75":{"type":["number","null"],"format":"float"},"cls_p90":{"type":["number","null"],"format":"float"},"cls_p95":{"type":["number","null"],"format":"float"},"cls_p99":{"type":["number","null"],"format":"float"},"fcp":{"type":"array","items":{"type":["number","null"],"format":"float"}},"fcp_p75":{"type":["number","null"],"format":"float"},"fcp_p90":{"type":["number","null"],"format":"float"},"fcp_p95":{"type":["number","null"],"format":"float"},"fcp_p99":{"type":["number","null"],"format":"float"},"fid":{"type":"array","items":{"type":["number","null"],"format":"float"}},"fid_p75":{"type":["number","null"],"format":"float"},"fid_p90":{"type":["number","null"],"format":"float"},"fid_p95":{"type":["number","null"],"format":"float"},"fid_p99":{"type":["number","null"],"format":"float"},"inp":{"type":"array","items":{"type":["number","null"],"format":"float"}},"inp_p75":{"type":["number","null"],"format":"float"},"inp_p90":{"type":["number","null"],"format":"float"},"inp_p95":{"type":["number","null"],"format":"float"},"inp_p99":{"type":["number","null"],"format":"float"},"lcp":{"type":"array","items":{"type":["number","null"],"format":"float"}},"lcp_p75":{"type":["number","null"],"format":"float"},"lcp_p90":{"type":["number","null"],"format":"float"},"lcp_p95":{"type":["number","null"],"format":"float"},"lcp_p99":{"type":["number","null"],"format":"float"},"timestamps":{"type":"array","items":{"type":"string"}},"ttfb":{"type":"array","items":{"type":["number","null"],"format":"float"}},"ttfb_p75":{"type":["number","null"],"format":"float"},"ttfb_p90":{"type":["number","null"],"format":"float"},"ttfb_p95":{"type":["number","null"],"format":"float"},"ttfb_p99":{"type":["number","null"],"format":"float"}}},"MetricsQuery":{"type":"object","required":["start_date","end_date","project_id"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"MetricsRangeQuery":{"type":"object","description":"Query params for range metric queries.","required":["metric"],"properties":{"metric":{"type":"string","description":"Metric name, e.g. `\"pg.connections_active\"`."},"percentile":{"type":["number","null"],"format":"double","description":"Optional histogram percentile (0–100). When provided, the endpoint\nfetches histogram buckets and computes the requested quantile."},"range":{"type":"string","description":"Time window: `\"1h\"` | `\"6h\"` | `\"24h\"` | `\"7d\"`."}}},"MetricsStatusResponse":{"type":"object","description":"Freshness status: when metrics were last received for this service.","properties":{"last_received_at":{"type":["string","null"],"description":"ISO 8601 timestamp of the most recent metric row, or null if none yet."}}},"MetricsStoreKind":{"type":"string","description":"Which storage backend to use for the MetricsStore.","enum":["timescale_db","click_house"]},"MetricsSummaryResponse":{"type":"object","required":["currency","current_mrr_minor","current_arr_minor","active_subscriptions","active_customers","churned_last_30d","arpu_minor"],"properties":{"active_customers":{"type":"integer","format":"int64"},"active_subscriptions":{"type":"integer","format":"int64"},"arpu_minor":{"type":"integer","format":"int64"},"churned_last_30d":{"type":"integer","format":"int64"},"currency":{"type":"string"},"current_arr_minor":{"type":"integer","format":"int64"},"current_mrr_minor":{"type":"integer","format":"int64"}}},"MfaRequiredResponse":{"type":"object","required":["requires_mfa","session_token"],"properties":{"requires_mfa":{"type":"boolean"},"session_token":{"type":"string"}}},"MfaSetupResponse":{"type":"object","required":["secret_key","qr_code","recovery_codes"],"properties":{"qr_code":{"type":"string"},"recovery_codes":{"type":"array","items":{"type":"string"}},"secret_key":{"type":"string"}}},"MfaVerificationRequest":{"type":"object","required":["code"],"properties":{"code":{"type":"string"}}},"MigrationStep":{"type":"object","description":"A single step in the migration execution plan.\n\nSteps are presented to the user before execution so they know exactly\nwhat will happen. During execution, each step runs in order and reports\nits outcome before proceeding to the next.","required":["order","id","title","description","resource_type","risk","skippable","reversible"],"properties":{"data_implications":{"type":"array","items":{"$ref":"#/components/schemas/DataImplication"},"description":"Data implications — what could go wrong or what the user needs to know"},"description":{"type":"string","description":"Detailed description of what this step does"},"estimated_duration":{"type":["string","null"],"description":"Estimated duration hint (e.g., \"< 1 second\", \"10-30 seconds\")"},"id":{"type":"string","description":"Machine-readable step identifier (e.g., \"create-project\", \"create-service-postgres\")"},"order":{"type":"integer","description":"Step number (1-based, for display)","minimum":0},"post_conditions":{"type":"array","items":{"type":"string"},"description":"Things the user should verify AFTER this step completes"},"pre_conditions":{"type":"array","items":{"type":"string"},"description":"Things the user should verify BEFORE this step runs"},"resource_type":{"$ref":"#/components/schemas/StepResourceType","description":"What kind of resource this step creates/modifies"},"reversible":{"type":"boolean","description":"Whether this step is reversible (can be cleaned up on failure)"},"risk":{"$ref":"#/components/schemas/RiskLevel","description":"Risk level for this step"},"skippable":{"type":"boolean","description":"Whether this step can be skipped by the user"},"skipped":{"type":"boolean","description":"Whether the user has chosen to skip this step (set during review)"},"title":{"type":"string","description":"Human-readable title (e.g., \"Create project 'my-app'\")"}}},"MigrationSummary":{"type":"object","description":"Human-readable summary of the entire migration plan","required":["headline","overall_risk","resource_counts"],"properties":{"critical_warnings":{"type":"array","items":{"type":"string"},"description":"Critical warnings that must be acknowledged before proceeding.\nThese are the most important things the user needs to know."},"headline":{"type":"string","description":"One-line summary (e.g., \"Migrate 'my-app' from Vercel with 1 database, 2 domains\")"},"manual_actions_required":{"type":"array","items":{"$ref":"#/components/schemas/ManualAction"},"description":"Manual actions the user must perform (before or after migration)"},"overall_risk":{"$ref":"#/components/schemas/RiskLevel","description":"Overall risk assessment for the migration"},"resource_counts":{"$ref":"#/components/schemas/ResourceCounts","description":"Resource counts for quick overview"},"unsupported_features":{"type":"array","items":{"$ref":"#/components/schemas/UnsupportedFeature"},"description":"Features from the source platform that cannot be migrated"}}},"MintEnrollmentTokenRequest":{"type":"object","properties":{"bound_node_name":{"type":["string","null"],"description":"Optional: restrict the token to register one specific node name."},"max_uses":{"type":["integer","null"],"format":"int32","description":"Maximum registrations this token may authorize (default 1)."},"ttl_secs":{"type":["integer","null"],"format":"int64","description":"Time-to-live in seconds (default 3600 = 1h)."}}},"MintEnrollmentTokenResponse":{"type":"object","required":["id","token","expires_at","max_uses","message"],"properties":{"ca_fingerprint":{"type":["string","null"],"description":"SHA-256 fingerprint of the cluster CA (if mTLS is set up). Pass it to the\nworker as `temps join --ca-fingerprint ` to verify the CA on join."},"expires_at":{"type":"string"},"id":{"type":"integer","format":"int32"},"max_uses":{"type":"integer","format":"int32"},"message":{"type":"string"},"token":{"type":"string","description":"The plaintext enrollment token — shown only once, save it now."}}},"MiscResult":{"type":"object","description":"Miscellaneous validation result","required":["is_disposable","is_role_account","is_b2c"],"properties":{"gravatar_url":{"type":["string","null"],"description":"Gravatar URL if available"},"is_b2c":{"type":"boolean","description":"Whether the email provider is a B2C (consumer) email provider"},"is_disposable":{"type":"boolean","description":"Whether the email is from a disposable email provider"},"is_role_account":{"type":"boolean","description":"Whether the email is a role-based account (e.g., admin@, info@)"}}},"MkdirBody":{"type":"object","required":["path"],"properties":{"path":{"type":"string"}},"additionalProperties":false},"ModelInfo":{"type":"object","required":["id","object","owned_by"],"properties":{"id":{"type":"string"},"object":{"type":"string"},"owned_by":{"type":"string"}}},"ModelListResponse":{"type":"object","required":["object","data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ModelInfo"}},"object":{"type":"string"}}},"ModelPricing":{"type":"object","description":"Pricing for a single model, all values in USD per 1M tokens.\nFields are optional because not every provider supports every pricing tier.","required":["model","display_name","provider","input_per_million","output_per_million"],"properties":{"batch_input_per_million":{"type":["number","null"],"format":"double","description":"Batch API input cost per 1M tokens (if provider offers batch pricing)"},"batch_output_per_million":{"type":["number","null"],"format":"double","description":"Batch API output cost per 1M tokens"},"cache_hit_per_million":{"type":["number","null"],"format":"double","description":"Cache hit / refresh cost per 1M tokens"},"cache_write_1h_per_million":{"type":["number","null"],"format":"double","description":"1-hour cache write cost per 1M tokens"},"cache_write_5m_per_million":{"type":["number","null"],"format":"double","description":"5-minute cache write cost per 1M tokens (Anthropic-style prompt caching)"},"deprecated":{"type":"boolean","description":"Whether the model is deprecated"},"display_name":{"type":"string","description":"Human-readable model name (e.g. \"Claude Sonnet 4.6\")"},"input_per_million":{"type":"number","format":"double","description":"Base input token cost per 1M tokens"},"model":{"type":"string","description":"Model identifier (e.g. \"gpt-5.4\", \"claude-sonnet-4-6\")"},"output_per_million":{"type":"number","format":"double","description":"Output token cost per 1M tokens"},"provider":{"type":"string","description":"Provider ID (e.g. \"openai\", \"anthropic\")"}}},"ModelUsage":{"type":"object","required":["model","provider","request_count","input_tokens","output_tokens","total_tokens","avg_latency_ms"],"properties":{"avg_latency_ms":{"type":"number","format":"double"},"input_tokens":{"type":"integer","format":"int64"},"model":{"type":"string"},"output_tokens":{"type":"integer","format":"int64"},"provider":{"type":"string"},"request_count":{"type":"integer","format":"int64"},"total_tokens":{"type":"integer","format":"int64"}}},"MonitorResponse":{"type":"object","required":["id","project_id","name","monitor_type","monitor_url","check_interval_seconds","is_active","created_at","updated_at"],"properties":{"check_interval_seconds":{"type":"integer","format":"int32"},"check_path":{"type":["string","null"]},"created_at":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"monitor_type":{"type":"string"},"monitor_url":{"type":"string"},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"updated_at":{"type":"string","format":"date-time"}}},"MonitorStatus":{"type":"object","required":["monitor","current_status","uptime_percentage"],"properties":{"avg_response_time_ms":{"type":["integer","null"],"format":"int32"},"current_status":{"type":"string"},"monitor":{"$ref":"#/components/schemas/MonitorResponse"},"uptime_percentage":{"type":"number","format":"double"}}},"MonitoringSettings":{"type":"object","description":"Global metrics observability configuration.\n\nControls whether the MetricsScraper and AlertEvaluator background tasks\nare active, which storage backend they write to, and how long data is kept\nat each retention tier.","properties":{"clickhouse_url":{"type":["string","null"],"description":"ClickHouse DSN (legacy, optional). The runtime metrics store is built\nfrom the `TEMPS_CLICKHOUSE_*` env vars, never from this field; it is\nretained for compatibility and operator reference only.\nExample: `\"http://localhost:8123\"`.","default":null},"enabled":{"type":"boolean","description":"Enable or disable all metrics collection (scraping + alerting).\nDefaults to `false` so new installs don't write to TimescaleDB until\nan operator explicitly enables the feature.","default":false},"retention_daily_years":{"type":"integer","format":"int32","description":"How many years of daily-aggregate data to keep (converted to days internally).","default":2,"example":2,"maximum":10,"minimum":1},"retention_hourly_days":{"type":"integer","format":"int32","description":"How many days of hourly-aggregate data to keep.","default":90,"example":90,"minimum":1},"retention_raw_days":{"type":"integer","format":"int32","description":"How many days of raw (30 s resolution) metric data to keep.","default":7,"example":7,"minimum":1},"scrape_interval_secs":{"type":"integer","format":"int64","description":"How often the MetricsScraper collects data from all sources, in seconds.\nMinimum effective value is 10 s; values below that are clamped at runtime.","default":30,"example":30,"minimum":10},"store":{"oneOf":[{"$ref":"#/components/schemas/MetricsStoreKind","description":"Storage backend for metric data."}],"default":"timescale_db"}}},"MonitoringSettingsMasked":{"type":"object","description":"Monitoring settings with the ClickHouse DSN masked.\n\n`clickhouse_url` can embed credentials (`http://user:pass@host`), so it is\nreported only as a boolean (`clickhouse_url_set`) rather than echoed back —\nconsistent with how the DNS API key and Docker registry password are masked.","required":["enabled","store","scrape_interval_secs","retention_raw_days","retention_hourly_days","retention_daily_years","clickhouse_url_set"],"properties":{"clickhouse_url_set":{"type":"boolean","description":"True when a ClickHouse DSN is configured. The DSN itself is never\nreturned over HTTP because it may contain credentials."},"enabled":{"type":"boolean"},"retention_daily_years":{"type":"integer","format":"int32","minimum":0},"retention_hourly_days":{"type":"integer","format":"int32","minimum":0},"retention_raw_days":{"type":"integer","format":"int32","minimum":0},"scrape_interval_secs":{"type":"integer","format":"int64","minimum":0},"store":{"$ref":"#/components/schemas/MetricsStoreKind"}}},"MrrBucketResponse":{"type":"object","required":["bucket","mrr_minor","charge_total_minor","refund_total_minor","charge_count"],"properties":{"bucket":{"type":"string","format":"date-time"},"charge_count":{"type":"integer","format":"int64"},"charge_total_minor":{"type":"integer","format":"int64"},"mrr_minor":{"type":"integer","format":"int64"},"refund_total_minor":{"type":"integer","format":"int64"}}},"MultiNodeSettings":{"type":"object","description":"Multi-node cluster settings","properties":{"cluster_ca_cert_pem":{"type":["string","null"],"description":"Per-cluster CA certificate (PEM) for multi-node mTLS (ADR-020 WS-2.1).\nPublic — distributed to nodes as the trust root and used by the control\nplane as the root for verifying agent server certs. Minted lazily on the\nfirst CSR-bearing registration.","default":null},"cluster_ca_key_encrypted":{"type":["string","null"],"description":"Per-cluster CA private key, AES-256-GCM ciphertext (EncryptionService).\nSECRET — never returned over HTTP (elided in the masked response).","default":null},"join_token_hash":{"type":["string","null"],"description":"SHA-256 hash of the join token (never store plaintext)","default":null},"legacy_shared_token_enabled":{"type":"boolean","description":"Whether the legacy single shared join token is still accepted for node\nregistration (ADR-020 WS-1.1). Defaults to `true` so existing clusters\nkeep working on upgrade; fresh installs should set it `false` and rely on\nshort-lived, single-use enrollment tokens instead.","default":true},"node_cpu_alert_percent":{"type":["number","null"],"format":"double","description":"CPU-usage percent above which a worker node raises a resource alert\n(ADR-020 / monitoring). `None` disables CPU alerting. Default 90.","default":90.0},"node_disk_alert_percent":{"type":["number","null"],"format":"double","description":"Disk-usage percent above which a worker node raises a resource alert.\n`None` disables disk alerting. Default 90.","default":90.0},"node_memory_alert_percent":{"type":["number","null"],"format":"double","description":"Memory-usage percent above which a worker node raises a resource alert.\n`None` disables memory alerting. Default 90.","default":90.0},"private_address":{"type":["string","null"],"description":"Private/WireGuard IP address of the control plane node.\nUsed by remote worker nodes to reach services (databases, etc.) running on the control plane.\nSet via `--private-address` or `TEMPS_PRIVATE_ADDRESS`.","default":null},"require_mtls":{"type":"boolean","description":"Whether to enforce multi-node mTLS (ADR-020 WS-2.1). When `false`\n(default), the control plane ignores join-time CSRs and nodes keep\nserving plaintext HTTP — zero behavior change. When `true`, the CP signs\nnode CSRs, nodes serve mutual TLS, and every CP→agent call uses the\ncluster client cert. Observe-then-enforce: flip this on only once all\nworkers have re-enrolled with certs.","default":false}}},"MultiNodeSettingsMasked":{"type":"object","description":"Multi-node settings with `join_token_hash` elided.","required":["has_join_token","require_mtls","legacy_shared_token_enabled"],"properties":{"cluster_ca_fingerprint":{"type":["string","null"],"description":"SHA-256 fingerprint of the cluster CA certificate (public — operators can\nverify it out of band; the CA private key is never exposed)."},"has_join_token":{"type":"boolean"},"legacy_shared_token_enabled":{"type":"boolean","description":"Whether the deprecated shared join token is still accepted."},"node_cpu_alert_percent":{"type":["number","null"],"format":"double","description":"Node resource-alert thresholds (percent); `None` = that alert disabled."},"node_disk_alert_percent":{"type":["number","null"],"format":"double"},"node_memory_alert_percent":{"type":["number","null"],"format":"double"},"private_address":{"type":["string","null"]},"require_mtls":{"type":"boolean","description":"Whether control-plane↔agent mutual TLS is enforced."}}},"MxResult":{"type":"object","description":"MX (Mail Exchange) validation result","required":["accepts_mail","records"],"properties":{"accepts_mail":{"type":"boolean","description":"Whether the domain accepts mail"},"error":{"type":["string","null"],"description":"Error message if MX lookup failed"},"records":{"type":"array","items":{"type":"string"},"description":"List of MX records for the domain","example":["alt1.gmail-smtp-in.l.google.com.","gmail-smtp-in.l.google.com."]}}},"NavEntry":{"type":"object","description":"A navigation entry that the plugin contributes to the Temps UI.","required":["label","icon","section","path","order"],"properties":{"icon":{"type":"string","description":"Lucide icon name (e.g., \"puzzle\", \"database\", \"activity\")"},"label":{"type":"string","description":"Display label in the sidebar"},"order":{"type":"integer","format":"int32","description":"Sort order within the section (lower = higher in list)","minimum":0},"path":{"type":"string","description":"Client-side route path (e.g., \"/my-plugin\")"},"section":{"$ref":"#/components/schemas/NavSection","description":"Which sidebar section this entry belongs to"}}},"NavSection":{"type":"string","description":"Where the plugin's nav entry appears in the Temps UI sidebar.","enum":["platform","settings","project"]},"NetworkConfiguration":{"type":"object","description":"Network configuration","required":["mode","dns_servers"],"properties":{"dns_servers":{"type":"array","items":{"type":"string"},"description":"DNS servers"},"hostname":{"type":["string","null"],"description":"Hostname"},"mode":{"$ref":"#/components/schemas/NetworkMode","description":"Network mode"}}},"NetworkMode":{"oneOf":[{"type":"string","enum":["bridge"]},{"type":"string","enum":["host"]},{"type":"string","enum":["none"]},{"type":"object","required":["custom"],"properties":{"custom":{"type":"string"}}}],"description":"Network mode"},"NixpacksPresetConfig":{"type":"object","description":"Configuration for Nixpacks preset\nNixpacks provider and inline build-plan configuration.","properties":{"nixpacksConfig":{"type":["string","null"],"description":"Optional inline nixpacks.toml contents."},"providers":{"type":"array","items":{"$ref":"#/components/schemas/NixpacksProvider"},"description":"Ordered Nixpacks providers. Empty means repository config or auto-detect;\ninclude `...` to combine auto-detection with explicit providers."}}},"NixpacksProvider":{"type":"string","description":"A Nixpacks build provider.\n\n`Auto` serializes as the native Nixpacks `...` marker, which includes the\nprovider detected from the project alongside any explicitly listed\nproviders.","enum":["...","node","python","rust","go","java","php","ruby","deno","elixir","csharp","fsharp","dart","swift","zig","scala","haskell","clojure","crystal","cobol","gleam","lunatic","scheme","static"]},"NodeContainerListResponse":{"type":"object","required":["containers","total"],"properties":{"containers":{"type":"array","items":{"$ref":"#/components/schemas/NodeContainerResponse"}},"total":{"type":"integer","minimum":0}}},"NodeContainerResponse":{"type":"object","description":"A container running on a specific node, enriched with project/environment context.","required":["container_id","container_name","image_name","status","created_at","deployment_id","project_id","project_name","environment_id","environment_name"],"properties":{"container_id":{"type":"string"},"container_name":{"type":"string"},"created_at":{"type":"string"},"deployment_id":{"type":"integer","format":"int32"},"environment_id":{"type":"integer","format":"int32"},"environment_name":{"type":"string"},"image_name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"project_name":{"type":"string"},"status":{"type":"string"}}},"NodeCostInfo":{"type":"object","description":"One cluster node with capacity and (when priceable) a cost estimate","required":["name","cpu_millis","memory_mb"],"properties":{"cpu_millis":{"type":"integer","format":"int64","description":"CPU capacity in millicores"},"instance_type":{"type":["string","null"],"description":"Instance type from `node.kubernetes.io/instance-type` (e.g. \"m5.xlarge\")"},"memory_mb":{"type":"integer","format":"int64","description":"Memory capacity in MB"},"monthly_usd":{"type":["number","null"],"format":"double","description":"Estimated on-demand monthly price in USD. `None` when the instance\ntype is unknown or not in the price table."},"name":{"type":"string","description":"Node name"},"region":{"type":["string","null"],"description":"Region from `topology.kubernetes.io/region`"}}},"NodeInfoResponse":{"type":"object","required":["id","name","address","private_address","role","status","labels","capacity","created_at"],"properties":{"address":{"type":"string"},"architecture":{"type":["string","null"],"description":"Container platform this node runs (`linux/amd64`, `linux/arm64`).\n`None` until an agent that reports it has heartbeated."},"capacity":{"description":"Resource capacity/usage metrics from the latest heartbeat"},"created_at":{"type":"string"},"id":{"type":"integer","format":"int32"},"labels":{},"last_heartbeat":{"type":["string","null"]},"name":{"type":"string"},"private_address":{"type":"string"},"role":{"type":"string"},"status":{"type":"string"}}},"NodeListResponse":{"type":"object","required":["nodes","total"],"properties":{"nodes":{"type":"array","items":{"$ref":"#/components/schemas/NodeInfoResponse"}},"total":{"type":"integer","minimum":0}}},"NotificationPreferencesResponse":{"type":"object","required":["email_enabled","slack_enabled","batch_similar_notifications","minimum_severity","deployment_failures_enabled","build_errors_enabled","runtime_errors_enabled","error_threshold","error_time_window","ssl_expiration_enabled","ssl_days_before_expiration","domain_expiration_enabled","dns_changes_enabled","backup_failures_enabled","backup_successes_enabled","s3_connection_issues_enabled","retention_policy_violations_enabled","route_downtime_enabled","load_balancer_issues_enabled","weekly_digest_enabled","digest_send_day","digest_send_time","digest_sections"],"properties":{"backup_failures_enabled":{"type":"boolean"},"backup_successes_enabled":{"type":"boolean"},"batch_similar_notifications":{"type":"boolean"},"build_errors_enabled":{"type":"boolean"},"deployment_failures_enabled":{"type":"boolean"},"digest_sections":{"$ref":"#/components/schemas/DigestSections"},"digest_send_day":{"type":"string"},"digest_send_time":{"type":"string"},"dns_changes_enabled":{"type":"boolean"},"domain_expiration_enabled":{"type":"boolean"},"email_enabled":{"type":"boolean"},"error_threshold":{"type":"integer","format":"int32"},"error_time_window":{"type":"integer","format":"int32"},"load_balancer_issues_enabled":{"type":"boolean"},"minimum_severity":{"type":"string"},"retention_policy_violations_enabled":{"type":"boolean"},"route_downtime_enabled":{"type":"boolean"},"runtime_errors_enabled":{"type":"boolean"},"s3_connection_issues_enabled":{"type":"boolean"},"slack_enabled":{"type":"boolean"},"ssl_days_before_expiration":{"type":"integer","format":"int32"},"ssl_expiration_enabled":{"type":"boolean"},"weekly_digest_enabled":{"type":"boolean"}}},"NotificationProviderResponse":{"type":"object","required":["id","name","provider_type","config","enabled","created_at","updated_at"],"properties":{"config":{},"created_at":{"type":"integer","format":"int64"},"enabled":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"provider_type":{"type":"string"},"updated_at":{"type":"integer","format":"int64"}}},"ObservabilityCompressionSettings":{"type":"object","description":"TimescaleDB compression policy configuration for append-only observability\ntables. Values are expressed in hours so operators can choose sub-day\nwindows while keeping the API representation unambiguous.","properties":{"otel_spans_after_hours":{"type":"integer","format":"int32","description":"Compress OpenTelemetry span chunks after this many hours. Defaults to\n24 hours.","default":24,"example":24,"maximum":2160,"minimum":1},"proxy_logs_after_hours":{"type":"integer","format":"int32","description":"Compress proxy-log chunks after this many hours. Defaults to 24 hours.","default":24,"example":24,"maximum":720,"minimum":1}}},"ObservabilityEvent":{"oneOf":[{"allOf":[{"$ref":"#/components/schemas/RequestRow"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["request"]}}}]},{"allOf":[{"$ref":"#/components/schemas/SpanRow"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["span"]}}}]},{"allOf":[{"$ref":"#/components/schemas/ErrorRow"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["error"]}}}]},{"allOf":[{"$ref":"#/components/schemas/RevenueRow"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["revenue"]}}}]}],"description":"Discriminated union of every row that can appear in the Observe list.\n\nSerializes to `{ \"type\": \"request\" | \"span\" | ... , ...rest }` so the UI\ncan switch on `event.type` without ambiguity.\n\n**No `Log` variant**: runtime stdout/stderr lines live on a dedicated\nLogs page rather than Observe. Logs are too high-volume to interleave\nwith business signals (requests, errors, revenue) without dominating\nthe timeline, and they have their own retention/storage constraints\n(TimescaleDB hypertable + chunked file/S3 store) that don't compose\nwith the merge service's per-kind LIMIT strategy."},"ObservabilityRetentionSettings":{"type":"object","description":"Retention policy configuration for raw observability tables. Values are in\ndays. The Settings API applies them to TimescaleDB; ClickHouse-backed proxy\nlogs and spans retain their storage-level per-row TTL behavior.","properties":{"otel_logs_days":{"type":"integer","format":"int32","description":"Retain OpenTelemetry log events for this many days.","default":90,"example":90,"maximum":3650,"minimum":1},"otel_metrics_days":{"type":"integer","format":"int32","description":"Retain OpenTelemetry metric points for this many days.","default":90,"example":90,"maximum":3650,"minimum":1},"otel_spans_days":{"type":"integer","format":"int32","description":"Retain OpenTelemetry spans (traces) for this many days.","default":90,"example":90,"maximum":3650,"minimum":1},"proxy_logs_days":{"type":"integer","format":"int32","description":"Retain proxy request logs for this many days.","default":30,"example":30,"maximum":3650,"minimum":1}}},"OidcProviderResponse":{"type":"object","required":["id","name","issuer_url","client_id","client_secret","scopes","jit_provisioning","enabled","template","group_claim","role_claim","default_role","trust_idp_email"],"properties":{"client_id":{"type":"string"},"client_secret":{"type":"string","description":"Always masked — the secret is never returned after creation."},"default_role":{"type":"string"},"enabled":{"type":"boolean"},"group_claim":{"type":"string"},"id":{"type":"integer","format":"int32"},"issuer_url":{"type":"string"},"jit_provisioning":{"type":"boolean"},"name":{"type":"string"},"role_claim":{"type":"string"},"scopes":{"type":"string"},"template":{"type":"string"},"trust_idp_email":{"type":"boolean","description":"When true, the resolver skips the `email_verified` claim gate\nduring SSO login. Only safe for IdPs where an admin controls\nuser provisioning — see `oidc_providers::Model::trust_idp_email`."}}},"OidcProviderSummary":{"type":"object","required":["slug","name","template"],"properties":{"name":{"type":"string"},"slug":{"type":"string","description":"Stable opaque slug — use this as the path parameter when initiating\nOIDC login (`/auth/oidc/login/{slug}`). The integer database ID is\nintentionally omitted from this public endpoint to prevent provider\nenumeration."},"template":{"type":"string","description":"The template the provider was created from — e.g. `keycloak`,\n`okta`, `auth0`, `google`, `azure-ad`, or `generic`. Surfaced on\nthe public login endpoint so the unauthenticated login page can\nrender the right brand logo on the \"Sign in with X\" button.\nNever sensitive — the template name is part of the provider's\npublic identity, not configuration."}}},"OidcProviderUserResponse":{"type":"object","description":"A user that has logged in via a given OIDC provider. Used by the\nadmin \"Users for provider\" panel — the `oidc_subject` is the\nIdP-side identifier we matched on, useful when diagnosing why a\nuser can or can't log in.","required":["id","name","email","email_verified","mfa_enabled","created_at","updated_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2024-01-15T14:30:00Z"},"email":{"type":"string"},"email_verified":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"mfa_enabled":{"type":"boolean"},"name":{"type":"string"},"oidc_subject":{"type":["string","null"]},"updated_at":{"type":"string","format":"date-time","example":"2024-01-15T14:30:00Z"}}},"OidcProvidersListResponse":{"type":"object","required":["providers"],"properties":{"providers":{"type":"array","items":{"$ref":"#/components/schemas/OidcProviderSummary"}}}},"OidcRoleMappingResponse":{"type":"object","required":["id","provider_id","priority","idp_group","role"],"properties":{"id":{"type":"integer","format":"int32"},"idp_group":{"type":"string"},"priority":{"type":"integer","format":"int32"},"provider_id":{"type":"integer","format":"int32"},"role":{"type":"string"}}},"OidcTestConnectionResponse":{"type":"object","required":["success","message"],"properties":{"message":{"type":"string"},"success":{"type":"boolean"}}},"OnDemandCertAttemptResponse":{"type":"object","description":"A single on-demand HTTP-01 issuance attempt from the append-only\n`on_demand_cert_attempts` audit log. Carries the full forensic detail for one\nattempt; the current cert state lives on the enclosing row's domain fields.\n\nContains no private-key or certificate material — only audit metadata — so it\nis safe to return without masking.","required":["id","hostname","trigger","outcome","created_at"],"properties":{"acme_request_sent":{"type":["boolean","null"],"description":"Did we reach the Let's Encrypt API?"},"acme_response_status":{"type":["string","null"],"description":"HTTP status or ACME error type returned by Let's Encrypt, when known."},"challenge_served":{"type":["boolean","null"],"description":"Did the proxy serve the `/.well-known/acme-challenge/` request?"},"created_at":{"type":"integer","format":"int64","description":"When the attempt was recorded (epoch millis)."},"duration_ms":{"type":["integer","null"],"format":"int32","description":"End-to-end issuance duration in milliseconds (0/None for skipped)."},"error_category":{"type":["string","null"],"description":"Coarse error category for UI labelling: `\"rate_limited\"`, `\"dns_failure\"`,\n`\"acme_order_expired\"`, `\"challenge_mismatch\"`, `\"timeout\"`, `\"internal\"`."},"error_chain":{"type":["string","null"],"description":"Full `Display` chain of the error (all `source()` levels), when failed."},"hostname":{"type":"string","description":"SNI hostname that triggered the attempt."},"id":{"type":"integer","format":"int32"},"outcome":{"type":"string","description":"Final outcome: `\"issued\"`, `\"failed\"`, `\"skipped_duplicate\"`,\n`\"skipped_gate\"`, `\"skipped_rate_limit\"`, or `\"skipped_no_route\"`."},"trigger":{"type":"string","description":"What triggered the attempt (always `\"tls_callback\"` today)."}}},"OnDemandCertRow":{"type":"object","description":"One row of the on-demand certificates list: the most-recent attempt for a\nhostname plus the current authoritative cert state from its `domains` row.","required":["hostname","attempt"],"properties":{"attempt":{"$ref":"#/components/schemas/OnDemandCertAttemptResponse","description":"The audit record for the attempt this row represents (newest first in\nthe list)."},"backoff_until":{"type":["integer","null"],"format":"int64","description":"On-demand negative-cache deadline (epoch millis), when in backoff."},"expiration_time":{"type":["integer","null"],"format":"int64","description":"Certificate expiration (epoch millis), when an active cert exists."},"hostname":{"type":"string","description":"SNI hostname."},"status":{"type":["string","null"],"description":"Current cert lifecycle status from the `domains` row, when one exists:\n`on_demand_pending`, `on_demand_issuing`, `active`, `on_demand_failed`,\netc. `None` when no `domains` row exists yet for this hostname."}}},"OnDemandTlsSettings":{"type":"object","description":"On-demand (lazy) HTTP-01 TLS issuance settings (ADR-018).\n\nWhen `enabled`, the proxy's `certificate_callback` triggers ACME HTTP-01\nissuance for allowlisted, STABLE hostnames (per-environment aliases and the\nconsole host) that have no active cert, rather than silently failing the\nhandshake. Ephemeral per-deployment hostnames are NEVER certed (ADR §2).\n\nOff by default — operators opt in explicitly, except QuickStart (`sslip.io`)\ninstalls where `temps setup` auto-enables it and derives `zone`.","properties":{"deployment_url_mode":{"type":"string","description":"How ephemeral per-deployment hostnames behave when they have no cert\n(they are NEVER certed — see ADR §2). One of:\n - `\"http\"` (default): serve plain HTTP on :80.\n - `\"redirect_to_env\"`: 308-redirect to the stable per-environment URL,\n which IS certed.","default":"http","example":"http"},"enabled":{"type":"boolean","description":"Master switch. When `false` (default) the proxy's on-demand cert gate\nrejects every SNI and no issuance is ever triggered.","default":false,"example":false},"hourly_cap":{"type":"integer","format":"int32","description":"Global cap on total on-demand issuances per hour across all hostnames\n(ADR §4 Layer 3). The operator's self-imposed safety net, separate from\nthe Let's Encrypt rate limit.","default":10,"example":10,"minimum":1},"max_concurrent":{"type":"integer","format":"int32","description":"Maximum number of ACME issuance flows allowed to run simultaneously\n(the concurrent-issuance semaphore, ADR §4 Layer 1). Min 1.","default":3,"example":3,"minimum":1},"zone":{"type":["string","null"],"description":"Zone suffix for the allowlist gate. A hostname passes the gate only if\nit is a direct subdomain of this zone (e.g. zone `1.2.3.4.sslip.io`\nadmits `myapp.1.2.3.4.sslip.io` but not `deep.sub.1.2.3.4.sslip.io`).\n`None` (default) means \"auto-derive from `external_url`\"; if no zone can\nbe derived the gate rejects all SNI, disabling the feature.","default":null,"example":"1.2.3.4.sslip.io"}}},"OpenAiError":{"type":"object","required":["message","type"],"properties":{"code":{"type":["string","null"]},"message":{"type":"string"},"type":{"type":"string"}}},"OpenAiErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"$ref":"#/components/schemas/OpenAiError"}}},"OperatingSystemCount":{"type":"object","required":["operating_system","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"operating_system":{"type":"string"},"percentage":{"type":"number","format":"double"}}},"OperationResultResponse":{"type":"object","required":["operation","success","message","executed_at"],"properties":{"data":{},"executed_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"message":{"type":"string"},"operation":{"type":"string"},"success":{"type":"boolean"}}},"OperationResultsResponse":{"type":"object","required":["deployment_id","operations"],"properties":{"deployment_id":{"type":"string"},"operations":{"type":"array","items":{"$ref":"#/components/schemas/OperationResultResponse"}}}},"OtelDashboardResponse":{"type":"object","required":["id","project_id","name","layout","created_at","updated_at"],"properties":{"created_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"id":{"type":"integer","format":"int32"},"layout":{"$ref":"#/components/schemas/DashboardLayout"},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"updated_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"}}},"OtelDashboardsResponse":{"type":"object","required":["data","total"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/OtelDashboardResponse"}},"total":{"type":"integer","format":"int64","minimum":0}}},"OtelMetricAlertRuleResponse":{"type":"object","required":["id","project_id","name","metric_name","aggregation","detection_kind","detection_config","window_secs","for_duration_secs","severity","enabled","last_state","label_filters","group_by","dynamic_alerts","max_series","grouped_notification_threshold","last_dropped_series_count","series_states","created_at","updated_at"],"properties":{"aggregation":{"type":"string"},"created_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"detection_config":{"$ref":"#/components/schemas/DetectionConfig","description":"The typed detector definition (discriminated union keyed by `kind`)."},"detection_kind":{"type":"string","description":"Coarse detector discriminator: `static|anomaly|forecast|outlier|auto_watch`."},"dynamic_alerts":{"type":"boolean","description":"Whether per-series (\"dynamic\") alerting is enabled for this rule."},"enabled":{"type":"boolean"},"firing_series":{"type":"array","items":{"$ref":"#/components/schemas/FiringSeriesEntry"},"description":"Currently-firing series for a dynamic rule, snapshotted from the evaluator's\nin-memory firing map at read time. Empty for static/aggregate rules or when\nnothing is firing."},"for_duration_secs":{"type":"integer","format":"int32"},"group_by":{"type":"array","items":{"type":"string"},"description":"Label keys the rule breaks the metric down by. Empty = one aggregate stream."},"grouped_notification_threshold":{"type":"integer","format":"int32","description":"Notification-grouping threshold: when more than this many series fire in the\nsame tick, only the first gets chart/AI enrichment (1–1000)."},"id":{"type":"integer","format":"int32"},"label_filters":{"type":"array","items":{"type":"array","items":false,"prefixItems":[{"type":"string"},{"type":"string"}]},"description":"AND-combined label equality filters applied when evaluating this rule.\nEmpty = no filtering (matches all series)."},"last_dropped_series_count":{"type":"integer","format":"int32","description":"Number of series dropped by the cardinality cap on the latest dynamic tick\n(0 when nothing was dropped or for static/aggregate rules). Lets a UI warn\n\"N series were dropped this tick\" without reading server logs."},"last_evaluated_at":{"type":["string","null"],"example":"2025-10-12T12:15:47.609192Z"},"last_state":{"type":"string","description":"One of `ok|firing|unknown`."},"last_value":{"type":["number","null"],"format":"double"},"max_series":{"type":"integer","format":"int32","description":"Cardinality cap for dynamic alerting (1–100)."},"metric_name":{"type":"string"},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"series_states":{"type":"object","description":"Full per-series state snapshot persisted after the latest dynamic-rule tick,\nkeyed by the human-readable series label (`endpoint=/checkout`). Empty for\nstatic/aggregate rules. Unlike `firing_series` (a live in-memory snapshot),\nthis is decoded from the persisted `series_states` jsonb column, so an\nexternal consumer that only reads the rule row still sees per-series detail.","additionalProperties":{"$ref":"#/components/schemas/SeriesStateEntry"},"propertyNames":{"type":"string"}},"severity":{"type":"string"},"updated_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"window_secs":{"type":"integer","format":"int32"}}},"OtelMetricAlertsResponse":{"type":"object","required":["data","total"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/OtelMetricAlertRuleResponse"}},"total":{"type":"integer","format":"int64","minimum":0}}},"OtelMetricLabelKeysResponse":{"type":"object","required":["keys"],"properties":{"keys":{"type":"array","items":{"type":"string"}}}},"OtelMetricLabelValuesResponse":{"type":"object","required":["values"],"properties":{"values":{"type":"array","items":{"type":"string"}}}},"OtelMetricNamesResponse":{"type":"object","required":["names"],"properties":{"names":{"type":"array","items":{"type":"string"}}}},"OtelMetricsResponse":{"type":"object","required":["data","count"],"properties":{"count":{"type":"integer","minimum":0},"data":{"type":"array","items":{"$ref":"#/components/schemas/MetricBucket"}}}},"OutlierAlgorithm":{"type":"string","description":"Outlier detection algorithm.","enum":["dbscan","scaled_dbscan","mad","scaled_mad"]},"OutlierParams":{"type":"object","description":"Outlier (cross-series population) detector parameters (stub — not evaluated).","required":["peer_group_key"],"properties":{"algorithm":{"$ref":"#/components/schemas/OutlierAlgorithm"},"peer_group_key":{"type":"string","description":"Label key defining the peer population compared across series (e.g. `host`)."},"tolerance":{"type":"number","format":"double","description":"Sensitivity; higher tolerates larger spread before flagging."}}},"OverprovisioningAssessment":{"type":"object","description":"Requests-vs-capacity-vs-usage assessment","required":["verdict","explanation"],"properties":{"cpu_request_inflation_ratio":{"type":["number","null"],"format":"double","description":"Ratio of requested CPU to measured CPU usage (e.g. 40.0 = requests\nreserve 40× what the workloads actually use). `None` without metrics."},"cpu_requested_pct":{"type":["number","null"],"format":"double","description":"Requested CPU as % of cluster capacity"},"cpu_utilization_pct":{"type":["number","null"],"format":"double","description":"Measured CPU usage as % of cluster capacity (`None` without metrics)"},"explanation":{"type":"string","description":"Human-readable explanation of the verdict, e.g. \"Cluster capacity is\n8 vCPU but measured usage is 0.3 vCPU (3.7%) — severely overprovisioned\""},"memory_request_inflation_ratio":{"type":["number","null"],"format":"double","description":"Ratio of requested memory to measured memory usage"},"memory_requested_pct":{"type":["number","null"],"format":"double","description":"Requested memory as % of cluster capacity"},"memory_utilization_pct":{"type":["number","null"],"format":"double","description":"Measured memory usage as % of cluster capacity (`None` without metrics)"},"verdict":{"$ref":"#/components/schemas/OverprovisioningVerdict","description":"Overall verdict"}}},"OverprovisioningVerdict":{"type":"string","description":"Overall overprovisioning verdict","enum":["severe","moderate","reasonable","unknown"]},"PageActivityBucket":{"type":"object","description":"Time bucket data point for page activity graph","required":["timestamp","visitors","page_views","avg_time_seconds"],"properties":{"avg_time_seconds":{"type":"number","format":"double","description":"Average time on page in seconds"},"page_views":{"type":"integer","format":"int64","description":"Number of page views in this bucket"},"timestamp":{"type":"string","description":"Timestamp for this bucket (ISO 8601)"},"visitors":{"type":"integer","format":"int64","description":"Number of unique visitors in this bucket"}}},"PageCountryStats":{"type":"object","description":"Geographic distribution of visitors for a page","required":["country","visitors","page_views","percentage"],"properties":{"country":{"type":"string","description":"Country name"},"country_code":{"type":["string","null"],"description":"ISO country code (2-letter)"},"page_views":{"type":"integer","format":"int64","description":"Number of page views from this country"},"percentage":{"type":"number","format":"double","description":"Percentage of total visitors"},"visitors":{"type":"integer","format":"int64","description":"Number of unique visitors from this country"}}},"PageFlowEntry":{"type":"object","description":"A single page with its entry/exit/bounce statistics","required":["page_path","entry_count","exit_count","bounce_count","total_views","entry_rate","exit_rate","bounce_rate"],"properties":{"avg_time_on_page":{"type":["number","null"],"format":"double","description":"Average time spent on this page in seconds"},"bounce_count":{"type":"integer","format":"int64","description":"Number of times visitors bounced on this page"},"bounce_rate":{"type":"number","format":"double","description":"Bounce rate: bounce_count / entry_count (only meaningful for entry pages)"},"entry_count":{"type":"integer","format":"int64","description":"Number of times this page was the entry page of a session"},"entry_rate":{"type":"number","format":"double","description":"Entry rate: entry_count / total_views"},"exit_count":{"type":"integer","format":"int64","description":"Number of times this page was the exit page of a session"},"exit_rate":{"type":"number","format":"double","description":"Exit rate: exit_count / total_views"},"page_path":{"type":"string","description":"The page path (e.g. \"/pricing\", \"/docs/getting-started\")"},"total_views":{"type":"integer","format":"int64","description":"Total page views for this page"}}},"PageFlowQuery":{"type":"object","description":"Query parameters for page flow analytics","required":["project_id","start_date","end_date"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32","description":"Maximum number of entry/exit pages to return (default: 20)"},"min_views_for_dropoff":{"type":["integer","null"],"format":"int32","description":"Minimum views for drop-off analysis (default: 5)"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"},"transitions_limit":{"type":["integer","null"],"format":"int32","description":"Maximum number of transitions to return (default: 50)"}}},"PageFlowResponse":{"type":"object","description":"Complete page flow analytics response","required":["top_entry_pages","top_exit_pages","drop_off_points","transitions","total_pages","total_sessions"],"properties":{"drop_off_points":{"type":"array","items":{"$ref":"#/components/schemas/DropOffPoint"},"description":"Top drop-off points (highest exit rates with meaningful traffic)"},"top_entry_pages":{"type":"array","items":{"$ref":"#/components/schemas/PageFlowEntry"},"description":"Top entry pages (where visitors land), sorted by entry_count DESC"},"top_exit_pages":{"type":"array","items":{"$ref":"#/components/schemas/PageFlowEntry"},"description":"Top exit pages (where visitors leave), sorted by exit_count DESC"},"total_pages":{"type":"integer","format":"int64","description":"Total unique pages seen in the period"},"total_sessions":{"type":"integer","format":"int64","description":"Total sessions in the period"},"transitions":{"type":"array","items":{"$ref":"#/components/schemas/PageTransition"},"description":"Page-to-page transitions (most common navigation paths)"}}},"PageHourlySessionsQuery":{"type":"object","description":"Query parameters for page hourly sessions endpoint","required":["page_path","project_id","start_time","end_time"],"properties":{"bucket_interval":{"type":["string","null"]},"end_time":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"page_path":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"start_time":{"type":"string","format":"date-time"}}},"PageHourlySessionsResponse":{"type":"object","required":["page_path","hourly_data","total_sessions","hours"],"properties":{"hourly_data":{"type":"array","items":{"$ref":"#/components/schemas/HourlyPageSessions"}},"hours":{"type":"integer","format":"int32"},"page_path":{"type":"string"},"total_sessions":{"type":"integer","format":"int64"}}},"PagePathDetailQuery":{"type":"object","description":"Query parameters for page path detail analytics","required":["page_path","project_id","start_date","end_date"],"properties":{"bucket_interval":{"type":["string","null"],"description":"Bucket interval for time series: 'hour', 'day', 'week', 'month' (default: auto)"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"page_path":{"type":"string","description":"The specific page path to get details for (URL-encoded)"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"PagePathDetailResponse":{"type":"object","description":"Detailed analytics response for a specific page path","required":["page_path","unique_visitors","total_page_views","avg_time_on_page","bounce_rate","entry_rate","exit_rate","activity_over_time","countries","referrers","bucket_interval"],"properties":{"activity_over_time":{"type":"array","items":{"$ref":"#/components/schemas/PageActivityBucket"},"description":"Time series data for activity graph"},"avg_time_on_page":{"type":"number","format":"double","description":"Average time on page in seconds"},"bounce_rate":{"type":"number","format":"double","description":"Bounce rate percentage (0-100)"},"bucket_interval":{"type":"string","description":"Bucket interval used for time series ('hour', 'day', etc.)"},"countries":{"type":"array","items":{"$ref":"#/components/schemas/PageCountryStats"},"description":"Geographic distribution of visitors"},"entry_rate":{"type":"number","format":"double","description":"Entry rate - percentage of sessions that started on this page"},"exit_rate":{"type":"number","format":"double","description":"Exit rate - percentage of sessions that ended on this page"},"page_path":{"type":"string","description":"The page path being analyzed"},"referrers":{"type":"array","items":{"$ref":"#/components/schemas/PageReferrerStats"},"description":"Top referrers to this page"},"total_page_views":{"type":"integer","format":"int64","description":"Total page views in the date range"},"unique_visitors":{"type":"integer","format":"int64","description":"Total unique visitors to this page in the date range"}}},"PagePathInfo":{"type":"object","required":["page_path","session_count","page_view_count","first_seen","last_seen"],"properties":{"avg_time_seconds":{"type":["number","null"],"format":"double"},"first_seen":{"type":"string"},"last_seen":{"type":"string"},"page_path":{"type":"string"},"page_view_count":{"type":"integer","format":"int64"},"session_count":{"type":"integer","format":"int64"}}},"PagePathSparkline":{"type":"object","required":["page_path","points"],"properties":{"page_path":{"type":"string"},"points":{"type":"array","items":{"$ref":"#/components/schemas/PagePathSparklinePoint"}}}},"PagePathSparklinePoint":{"type":"object","required":["timestamp","session_count"],"properties":{"session_count":{"type":"integer","format":"int64"},"timestamp":{"type":"string"}}},"PagePathVisitorsQuery":{"type":"object","description":"Query parameters for page path visitors","required":["page_path","project_id","start_date","end_date"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"page":{"type":["integer","null"],"format":"int64","description":"Page number (1-based, default: 1)","minimum":0},"page_path":{"type":"string","description":"The specific page path to get visitors for"},"per_page":{"type":["integer","null"],"format":"int64","description":"Items per page (default: 50, max: 100)","minimum":0},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"PagePathVisitorsResponse":{"type":"object","description":"Response for page path visitors endpoint","required":["page_path","total_count","page","per_page","sessions"],"properties":{"page":{"type":"integer","format":"int64","description":"Current page number","minimum":0},"page_path":{"type":"string","description":"The page path"},"per_page":{"type":"integer","format":"int64","description":"Items per page","minimum":0},"sessions":{"type":"array","items":{"$ref":"#/components/schemas/PageVisitorSession"},"description":"Individual visitor sessions"},"total_count":{"type":"integer","format":"int64","description":"Total number of visitor sessions matching the query"}}},"PagePathsQuery":{"type":"object","required":["project_id"],"properties":{"end_date":{"type":["string","null"],"format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":["string","null"],"format":"date-time"}}},"PagePathsResponse":{"type":"object","required":["page_paths","total_count"],"properties":{"page_paths":{"type":"array","items":{"$ref":"#/components/schemas/PagePathInfo"}},"total_count":{"type":"integer","minimum":0}}},"PagePathsSparklineQuery":{"type":"object","description":"Query parameters for batch page paths sparkline endpoint","required":["project_id","start_time","end_time","page_paths"],"properties":{"end_time":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"page_paths":{"type":"string","description":"Comma-separated list of page paths"},"project_id":{"type":"integer","format":"int32"},"start_time":{"type":"string","format":"date-time"}}},"PagePathsSparklineResponse":{"type":"object","required":["sparklines"],"properties":{"sparklines":{"type":"array","items":{"$ref":"#/components/schemas/PagePathSparkline"}}}},"PageReferrerStats":{"type":"object","description":"Referrer source for the page","required":["referrer","visits","percentage"],"properties":{"percentage":{"type":"number","format":"double","description":"Percentage of total visits"},"referrer":{"type":"string","description":"Referrer URL or domain"},"visits":{"type":"integer","format":"int64","description":"Number of visits from this referrer"}}},"PageSessionComparison":{"type":"object","required":["page_path","date","session_count","event_count","avg_duration_seconds"],"properties":{"avg_duration_seconds":{"type":"number","format":"double"},"date":{"type":"string"},"event_count":{"type":"integer","format":"int64"},"page_path":{"type":"string"},"session_count":{"type":"integer","format":"int64"}}},"PageSessionStats":{"type":"object","required":["page_path","total_sessions","avg_time_seconds","min_time_seconds","max_time_seconds","total_page_views","avg_page_views_per_session"],"properties":{"avg_page_views_per_session":{"type":"number","format":"double"},"avg_time_seconds":{"type":"number","format":"double"},"max_time_seconds":{"type":"number","format":"double"},"min_time_seconds":{"type":"number","format":"double"},"page_path":{"type":"string"},"total_page_views":{"type":"integer","format":"int64"},"total_sessions":{"type":"integer","format":"int64"}}},"PageSessionStatsQuery":{"type":"object","required":["page_path","project_id","start_date","end_date"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"page_path":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"PageTransition":{"type":"object","description":"A page-to-page transition with count","required":["from_page","to_page","transition_count","percentage"],"properties":{"from_page":{"type":"string","description":"The source page path"},"percentage":{"type":"number","format":"double","description":"Percentage of transitions from the source page that go to this destination"},"to_page":{"type":"string","description":"The destination page path"},"transition_count":{"type":"integer","format":"int64","description":"Number of times this transition occurred"}}},"PageVisit":{"type":"object","required":["path","visits"],"properties":{"path":{"type":"string"},"visits":{"type":"integer","format":"int64"}}},"PageVisitorSession":{"type":"object","description":"Individual visitor session that viewed a specific page","required":["visitor_id","visitor_uuid","viewed_at","is_entry","is_exit","is_bounce"],"properties":{"browser":{"type":["string","null"],"description":"Browser name"},"city":{"type":["string","null"],"description":"Visitor's city"},"country":{"type":["string","null"],"description":"Visitor's country"},"country_code":{"type":["string","null"],"description":"Visitor's country code"},"device_type":{"type":["string","null"],"description":"Device type (Desktop, Mobile, Tablet)"},"is_bounce":{"type":"boolean","description":"Whether this was a bounce"},"is_entry":{"type":"boolean","description":"Whether this was the entry page for the session"},"is_exit":{"type":"boolean","description":"Whether this was the exit page for the session"},"operating_system":{"type":["string","null"],"description":"Operating system"},"referrer":{"type":["string","null"],"description":"Referrer URL"},"session_id":{"type":["string","null"],"description":"Session ID"},"session_page_number":{"type":["integer","null"],"format":"int32","description":"Page number in session flow"},"time_on_page":{"type":["integer","null"],"format":"int32","description":"Time spent on this page in seconds"},"viewed_at":{"type":"string","format":"date-time","description":"When the page was viewed"},"visitor_id":{"type":"integer","format":"int32","description":"Visitor numeric ID"},"visitor_uuid":{"type":"string","description":"Visitor UUID"}}},"PagesComparisonResponse":{"type":"object","required":["comparisons","page_paths"],"properties":{"comparisons":{"type":"array","items":{"$ref":"#/components/schemas/PageSessionComparison"}},"page_paths":{"type":"array","items":{"type":"string"}}}},"PaginatedEmailsResponse":{"type":"object","required":["data","total","page","page_size"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/EmailResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"PaginatedEntitiesResponse":{"type":"object","required":["entities","count","limit","has_more"],"properties":{"count":{"type":"integer","description":"Number of entities returned","minimum":0},"entities":{"type":"array","items":{"$ref":"#/components/schemas/EntityResponse"},"description":"List of entities"},"has_more":{"type":"boolean","description":"Whether there are more entities available"},"limit":{"type":"integer","description":"Limit used for this request","minimum":0},"next_token":{"type":["string","null"],"description":"Continuation token for next page (S3, etc.)"},"total":{"type":["integer","null"],"description":"Total number of entities (if available)","minimum":0}}},"PaginatedErrorEventsResponse":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ErrorEventResponse"}},"pagination":{"$ref":"#/components/schemas/PaginationMeta"}}},"PaginatedErrorGroupsResponse":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ErrorGroupResponse"}},"pagination":{"$ref":"#/components/schemas/PaginationMeta"}}},"PaginatedEventsResponse":{"type":"object","required":["events","total","page","page_size"],"properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/TrackingEventResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"PaginatedExternalImagesResponse":{"type":"object","required":["data","total","page","page_size"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ExternalImageResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"PaginatedProjectList":{"type":"object","required":["projects","total","page","per_page"],"properties":{"page":{"type":"integer","format":"int64"},"per_page":{"type":"integer","format":"int64"},"projects":{"type":"array","items":{"$ref":"#/components/schemas/ProjectResponse"}},"total":{"type":"integer","format":"int64"}}},"PaginatedStaticBundlesResponse":{"type":"object","required":["data","total","page","page_size"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/StaticBundleResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"Pagination":{"type":"object","description":"SDK pagination cursor. We use opaque page numbers internally but\nexpose `count`/`next`/`prev` the way `@vercel/sandbox` expects.","required":["count"],"properties":{"count":{"type":"integer","format":"int64","minimum":0},"next":{"type":["integer","null"],"format":"int64","minimum":0},"prev":{"type":["integer","null"],"format":"int64","minimum":0}}},"PaginationMeta":{"type":"object","required":["page","page_size","total_count","total_pages"],"properties":{"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total_count":{"type":"integer","format":"int64","minimum":0},"total_pages":{"type":"integer","format":"int64","minimum":0}}},"PaginationParams":{"type":"object","properties":{"page":{"type":"integer","format":"int64"},"per_page":{"type":"integer","format":"int64"}}},"PasswordProtectionConfig":{"type":"object","description":"Password protection configuration\n\nWhen enabled, the proxy shows an HTML password form before allowing access.\nAfter the user enters the correct password, an HMAC-signed cookie is set\nso subsequent requests pass through without re-entering the password.","required":["enabled","passwordHash"],"properties":{"enabled":{"type":"boolean","description":"Whether password protection is enabled"},"passwordHash":{"type":"string","description":"The bcrypt-hashed password (never stored or returned in plaintext)"}}},"PatchSettingsRequest":{"type":"object","properties":{"auto_upgrade":{"type":["boolean","null"]},"host_port":{"type":["integer","null"],"format":"int32","minimum":0},"image":{"type":["string","null"]}}},"PathVisitors":{"type":"object","required":["name","visitors","percentage"],"properties":{"name":{"type":"string"},"percentage":{"type":"number","format":"double"},"visitors":{"type":"integer","format":"int64"}}},"PathVisitorsAnalyticsQuery":{"type":"object","required":["start_date","end_date","project_id"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"PathVisitorsResponse":{"type":"object","required":["results"],"properties":{"results":{"type":"array","items":{"$ref":"#/components/schemas/PathVisitors"}}}},"PeerEntry":{"type":"object","description":"Wire-format peer entry. Matches `temps_network::config::Peer` but\nuses strings on the wire to keep the API stable across underlying\ntype evolution.","required":["node_id","compute_cidr","underlay_address"],"properties":{"compute_cidr":{"type":"string","description":"Per-node CIDR (e.g. `\"172.20.5.0/24\"`)."},"node_id":{"type":"string","description":"Stable v5 UUID derived from the database node id. Workers use\nthis as the kernel-layer identifier when calling\n`NetworkManager::reconcile_peers`."},"underlay_address":{"type":"string","description":"Address the local node should use to reach this peer over the\nunderlay (private VPC IP for same-DC, public IP for cross-DC)."}}},"PeerListResponse":{"type":"object","description":"Response body for `GET /internal/nodes/{node_id}/network/peers`.","required":["peers","cluster_dns_enabled"],"properties":{"alloc":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AllocEntry","description":"Caller's own allocation, or `null` if multi-host networking has\nnot been enabled for this node yet."}]},"cluster_dns_enabled":{"type":"boolean","description":"Whether the cluster-DNS resolver is enabled on this control plane\n(`AppSettings.cluster_dns.enabled`). Workers should start their\nper-node resolver and write `overlay_bridge_address` only when this\nis `true`. Always serialized (never `skip_serializing_if`) so older\nand newer version skew degrades to the safe default of `false`."},"peers":{"type":"array","items":{"$ref":"#/components/schemas/PeerEntry"},"description":"All other nodes with a `compute_cidr` set, excluding the caller."}}},"PendingActionResponse":{"type":"object","description":"A proposed AI write action awaiting human confirmation.","required":["public_id","operation_id","method","summary","status","step_index","params","created_at"],"properties":{"confirmed_at":{"type":["string","null"]},"created_at":{"type":"string"},"error":{"type":["string","null"]},"executed_at":{"type":["string","null"]},"method":{"type":"string"},"operation_id":{"type":"string"},"params":{"description":"The flat params to be replayed at execute time (shown pre-execution for review)."},"plan_public_id":{"type":["string","null"],"description":"Set when this action is one step of a multi-step plan (chained actions);\nall steps of the plan share this id. Absent for standalone single actions."},"public_id":{"type":"string"},"required_permission":{"type":["string","null"]},"result":{},"status":{"type":"string"},"step_index":{"type":"integer","format":"int32","description":"0-based order of this step within its plan (0 for standalone actions)."},"summary":{"type":"string"}}},"PerformanceMetricsQuery":{"allOf":[{"$ref":"#/components/schemas/SpeedSegmentFilters","description":"Segment filters (filter_path, filter_country, filter_region,\nfilter_city, filter_browser, filter_operating_system) — flattened so\neach remains a top-level query string param."},{"type":"object","required":["start_date","end_date","project_id"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"device_type":{"type":["string","null"],"description":"Device type filter: \"desktop\" or \"mobile\""},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"include_bots":{"type":["boolean","null"],"description":"Include crawler/datacenter (bot) samples. Defaults to false — bots\nare excluded from the read view but always stored at ingest."},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}}]},"PerformanceMetricsResponse":{"type":"object","properties":{"cls":{"type":["number","null"],"format":"float"},"cls_p75":{"type":["number","null"],"format":"float"},"cls_p90":{"type":["number","null"],"format":"float"},"cls_p95":{"type":["number","null"],"format":"float"},"cls_p99":{"type":["number","null"],"format":"float"},"fcp":{"type":["number","null"],"format":"float"},"fcp_p75":{"type":["number","null"],"format":"float"},"fcp_p90":{"type":["number","null"],"format":"float"},"fcp_p95":{"type":["number","null"],"format":"float"},"fcp_p99":{"type":["number","null"],"format":"float"},"fid":{"type":["number","null"],"format":"float"},"fid_p75":{"type":["number","null"],"format":"float"},"fid_p90":{"type":["number","null"],"format":"float"},"fid_p95":{"type":["number","null"],"format":"float"},"fid_p99":{"type":["number","null"],"format":"float"},"inp":{"type":["number","null"],"format":"float"},"inp_p75":{"type":["number","null"],"format":"float"},"inp_p90":{"type":["number","null"],"format":"float"},"inp_p95":{"type":["number","null"],"format":"float"},"inp_p99":{"type":["number","null"],"format":"float"},"lcp":{"type":["number","null"],"format":"float"},"lcp_p75":{"type":["number","null"],"format":"float"},"lcp_p90":{"type":["number","null"],"format":"float"},"lcp_p95":{"type":["number","null"],"format":"float"},"lcp_p99":{"type":["number","null"],"format":"float"},"ttfb":{"type":["number","null"],"format":"float"},"ttfb_p75":{"type":["number","null"],"format":"float"},"ttfb_p90":{"type":["number","null"],"format":"float"},"ttfb_p95":{"type":["number","null"],"format":"float"},"ttfb_p99":{"type":["number","null"],"format":"float"}}},"PermissionInfo":{"type":"object","description":"Information about a single permission","required":["name","description","category"],"properties":{"category":{"type":"string","description":"Category of the permission (e.g., \"Projects\", \"Deployments\")"},"description":{"type":"string","description":"Human-readable description of the permission"},"name":{"type":"string","description":"The permission identifier (e.g., \"projects:read\")"}}},"PgUpgradeLogResponse":{"type":"object","required":["log_id","content"],"properties":{"content":{"type":"string"},"log_id":{"type":"string"}}},"PgUpgradeResponse":{"type":"object","required":["id","service_id","from_version","to_version","from_image","to_image","status","phase","log_id","attempt","created_at"],"properties":{"attempt":{"type":"integer","format":"int32"},"created_at":{"type":"string"},"error_message":{"type":["string","null"]},"finished_at":{"type":["string","null"]},"from_image":{"type":"string"},"from_version":{"type":"string"},"id":{"type":"integer","format":"int32"},"log_id":{"type":"string"},"phase":{"type":"string"},"pre_upgrade_backup_id":{"type":["integer","null"],"format":"int32"},"rollback_volume_name":{"type":["string","null"]},"service_id":{"type":"integer","format":"int32"},"started_at":{"type":["string","null"]},"status":{"type":"string"},"to_image":{"type":"string"},"to_version":{"type":"string"}}},"PipelineStats":{"type":"object","description":"Internal pipeline statistics for self-observability.","required":["metrics_received","metrics_stored","metrics_dropped","spans_received","spans_stored","spans_dropped","logs_received","logs_stored_db","logs_stored_s3","logs_dropped","ingest_errors"],"properties":{"ingest_errors":{"type":"integer","format":"int64","minimum":0},"logs_dropped":{"type":"integer","format":"int64","minimum":0},"logs_received":{"type":"integer","format":"int64","minimum":0},"logs_stored_db":{"type":"integer","format":"int64","minimum":0},"logs_stored_s3":{"type":"integer","format":"int64","minimum":0},"metrics_dropped":{"type":"integer","format":"int64","minimum":0},"metrics_received":{"type":"integer","format":"int64","minimum":0},"metrics_stored":{"type":"integer","format":"int64","minimum":0},"spans_dropped":{"type":"integer","format":"int64","minimum":0},"spans_received":{"type":"integer","format":"int64","minimum":0},"spans_stored":{"type":"integer","format":"int64","minimum":0}}},"PipelineStatsResponse":{"type":"object","required":["stats"],"properties":{"stats":{"$ref":"#/components/schemas/PipelineStats"}}},"PlanComplexity":{"type":"string","description":"Plan complexity indicator","enum":["low","medium","high"]},"PlanMetadata":{"type":"object","description":"Plan metadata","required":["generated_at","generator_version","complexity","warnings"],"properties":{"complexity":{"$ref":"#/components/schemas/PlanComplexity","description":"Estimated complexity (low, medium, high)"},"generated_at":{"type":"string","format":"date-time","description":"When the plan was generated"},"generator_version":{"type":"string","description":"Generator (importer) version"},"warnings":{"type":"array","items":{"type":"string"},"description":"Warnings detected during planning"}}},"PlanSourceBackup":{"type":"object","required":["location","location_was_resolved","format"],"properties":{"created_at":{"type":["string","null"]},"format":{"type":"string","description":"\"walg\", \"pg_dump\", \"unknown\"."},"id":{"type":["integer","null"],"format":"int32","description":"DB id, absent for orphan (S3-scan) backups."},"location":{"type":"string","description":"Resolved S3 location the orchestrator will actually use."},"location_was_resolved":{"type":"boolean","description":"True when the original row's `s3_location` was empty and we resolved\na location by probing S3. The UI shows this as a warning."},"origin_service_name":{"type":["string","null"],"description":"Service that originally produced the backup, if known."},"size_bytes":{"type":["integer","null"],"format":"int64"}}},"PlanTarget":{"type":"object","required":["id","name","container"],"properties":{"container":{"type":"string","description":"Expected Docker container name."},"id":{"type":"integer","format":"int32"},"name":{"type":"string"}}},"PlatformInfo":{"type":"object","description":"Platform compatibility information","required":["os_type","architecture","platforms"],"properties":{"architecture":{"type":"string","description":"System architecture (e.g., \"x86_64\", \"aarch64\")"},"os_type":{"type":"string","description":"Operating system type (e.g., \"linux\", \"windows\", \"darwin\")"},"platforms":{"type":"array","items":{"type":"string"},"description":"List of supported platforms in \"os/arch\" format (e.g., [\"linux/amd64\"])"}}},"PluginManifest":{"type":"object","description":"The complete plugin manifest — the handshake contract.","required":["name","version"],"properties":{"description":{"type":["string","null"],"description":"Short description of what the plugin does"},"display_name":{"type":["string","null"],"description":"Human-readable display name"},"events":{"type":"array","items":{"type":"string"},"description":"Platform event types the plugin subscribes to.\n\nWhen specified, Temps will POST matching events to the plugin's\n`/_events` endpoint. Uses dot-notation event names matching the\nwebhook event types (e.g., \"deployment.succeeded\", \"project.created\").\n\nAvailable events:\n- `deployment.created`, `deployment.succeeded`, `deployment.failed`,\n `deployment.cancelled`, `deployment.ready`\n- `project.created`, `project.deleted`\n- `domain.created`, `domain.provisioned`"},"health_path":{"type":"string","description":"Health check endpoint path (relative to plugin root)"},"name":{"type":"string","description":"Unique plugin identifier (kebab-case, e.g., \"backup-manager\")"},"nav":{"type":"array","items":{"$ref":"#/components/schemas/NavEntry"},"description":"Navigation entries for the UI sidebar"},"requires_db":{"type":"boolean","description":"Whether the plugin needs database access"},"ui":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/UiManifest","description":"UI bundle manifest (if the plugin has a UI)"}]},"version":{"type":"string","description":"SemVer version string"}}},"PortMapping":{"type":"object","description":"Port mapping","required":["container_port","protocol","is_primary"],"properties":{"container_port":{"type":"integer","format":"int32","description":"Container port","minimum":0},"host_port":{"type":["integer","null"],"format":"int32","description":"Host port (optional - can be assigned dynamically)","minimum":0},"is_primary":{"type":"boolean","description":"Whether this is the primary HTTP port"},"protocol":{"$ref":"#/components/schemas/Protocol","description":"Protocol (tcp, udp)"}}},"PostgresWalHealth":{"type":"object","required":["probed_at","pg_wal_bytes","max_wal_size_bytes","archive_mode","archive_backlog","stale_slots","oldest_wal_age_secs","warnings"],"properties":{"archive_backlog":{"type":"integer","format":"int64","description":"Number of `archive_status/*.ready` files — un-shipped WAL segments."},"archive_command":{"type":["string","null"],"description":"The literal `archive_command` setting. May be empty or `/bin/true`\nwhen archiving is effectively disabled despite `archive_mode = on`."},"archive_mode":{"$ref":"#/components/schemas/ArchiveMode"},"archiver_failed_count":{"type":["integer","null"],"format":"int64"},"archiver_last_failed_at":{"type":["string","null"],"format":"date-time"},"max_wal_size_bytes":{"type":"integer","format":"int64","description":"`max_wal_size` setting in bytes (parsed from `pg_settings`)."},"oldest_wal_age_secs":{"type":"integer","format":"int64","description":"Age of the oldest WAL file in `pg_wal/` (seconds)."},"pg_wal_bytes":{"type":"integer","format":"int64","description":"Total size of files under `pg_wal/`, from `pg_ls_waldir()`."},"probed_at":{"type":"string","format":"date-time","description":"When the snapshot was taken."},"stale_slots":{"type":"array","items":{"$ref":"#/components/schemas/StaleSlot"}},"warnings":{"type":"array","items":{"$ref":"#/components/schemas/WalWarning"},"description":"Computed warnings, ordered by severity (critical first)."}}},"PresetConfigSchema":{"oneOf":[{"$ref":"#/components/schemas/DockerfilePresetConfig","description":"Configuration for Dockerfile preset"},{"$ref":"#/components/schemas/DockerComposePresetConfig","description":"Configuration for Docker Compose"},{"$ref":"#/components/schemas/NixpacksPresetConfig","description":"Configuration for Nixpacks provider selection and inline build plan"},{"$ref":"#/components/schemas/StaticPresetConfig","description":"Configuration for static site presets (Vite, Next.js, etc.)"}],"description":"Union type for preset configurations\nUse the appropriate configuration type based on your preset"},"PresetInfo":{"type":"object","description":"Detected preset information","required":["path","preset","preset_label","project_type"],"properties":{"compose_files":{"type":["array","null"],"items":{"type":"string"},"description":"Compose file paths found in the repository (only for docker-compose preset)"},"exposed_port":{"type":["integer","null"],"format":"int32","description":"Default exposed port for this preset"},"icon_url":{"type":["string","null"],"description":"Icon URL for this preset"},"path":{"type":"string","description":"Path where preset was detected (empty for root)"},"preset":{"type":"string","description":"Preset slug (e.g., \"nextjs\", \"fastapi\")"},"preset_label":{"type":"string","description":"Human-readable preset label"},"project_type":{"type":"string","description":"Project type (e.g., \"frontend\", \"backend\", \"fullstack\")"}}},"PresetResponse":{"type":"object","required":["slug","label","icon_url","project_type","description"],"properties":{"default_port":{"type":["integer","null"],"format":"int32","description":"Default port the application listens on (None for static sites)","example":3000,"minimum":0},"description":{"type":"string","description":"Description of what this preset does"},"icon_url":{"type":"string","description":"Icon URL for the preset"},"label":{"type":"string","description":"Display name/label for the preset"},"project_type":{"type":"string","description":"Project type (server or static)"},"slug":{"type":"string","description":"Unique identifier slug for the preset"}}},"PreviewGatewaySettings":{"type":"object","description":"Workspace preview gateway settings.\n\nThe preview gateway is a single shared Docker container that lives on the\n`temps-sandbox-net` network and routes requests to workspace sandbox dev\nservers based on the `Host` header (`ws--.`).\n`temps serve` reconciles this container on startup; these settings let an\noperator override the image, host port, and auto-upgrade behavior.","properties":{"auto_upgrade":{"type":"boolean","description":"When true (default), the supervisor will pull and apply the image\npinned in the Temps binary on every startup. When false, the\ncurrently-running image is left alone — operators upgrade manually\nfrom the settings UI.","default":true,"example":true},"host_port":{"type":"integer","format":"int32","description":"Host port to publish the gateway on (always bound to 127.0.0.1).\nPingora forwards `ws-*` traffic to this port after authenticating.","default":8090,"example":8090,"minimum":0},"image":{"type":"string","description":"Docker image reference for the gateway. Pinned per Temps release.\nOperators can override this to test a custom build.","default":"ghcr.io/gotempsh/temps-preview-gateway:latest","example":"ghcr.io/gotempsh/temps-preview-gateway:latest"},"shared_secret":{"type":"string","description":"Shared secret the host-side Pingora sends on every forwarded preview\nrequest via `X-Temps-Preview-Token`; the gateway rejects requests\nwithout it. Auto-generated on first boot, persisted in DB so the\nsecret is stable across `temps serve` restarts regardless of cwd,\n`TEMPS_DATA_DIR`, or data-dir changes. MUST be masked (`***`) in any\nAPI response — never expose it over HTTP.","default":"","example":""}}},"PreviewGatewaySettingsMasked":{"type":"object","description":"Preview gateway settings with `shared_secret` elided.","required":["image","host_port","auto_upgrade","shared_secret_set"],"properties":{"auto_upgrade":{"type":"boolean"},"host_port":{"type":"integer","format":"int32","minimum":0},"image":{"type":"string"},"shared_secret_set":{"type":"boolean"}}},"PreviewGatewaySettingsResponse":{"type":"object","required":["image","host_port","auto_upgrade","default_image","default_host_port"],"properties":{"auto_upgrade":{"type":"boolean"},"default_host_port":{"type":"integer","format":"int32","description":"The compile-time default host port.","minimum":0},"default_image":{"type":"string","description":"The compile-time default image — exposed so the UI can offer a\n\"Reset to default\" link without round-tripping."},"host_port":{"type":"integer","format":"int32","minimum":0},"image":{"type":"string"}}},"PreviewShareLinkBody":{"type":"object","description":"Request body for minting a preview share link.","required":["port"],"properties":{"path":{"type":["string","null"],"description":"Path the recipient lands on. Must be same-origin (start with a single\n`/`); anything else is replaced with `/` so a share link can never be\nturned into an open redirect."},"port":{"type":"integer","format":"int32","description":"Port inside the sandbox the preview serves on.","minimum":0},"ttl_seconds":{"type":["integer","null"],"format":"int64","description":"How long the link stays usable, in seconds. Clamped to 24 hours.\nDefaults to one hour — long enough to send to a reviewer, short enough\nthat a link pasted in a ticket does not stay live indefinitely.","minimum":0}}},"PreviewShareLinkResponse":{"type":"object","required":["url","expires_at"],"properties":{"expires_at":{"type":"integer","format":"int64","description":"Unix seconds after which the link stops working.","minimum":0},"url":{"type":"string","description":"The full link. Its fragment contains the grant and must be treated as a\ncredential; URL fragments are not sent to servers or in Referer headers."}}},"PricingResponse":{"type":"object","required":["models"],"properties":{"models":{"type":"array","items":{"$ref":"#/components/schemas/ModelPricing"}}}},"ProblemDetails":{"type":"object","description":"Representation of a Problem error to return to the client.\nFollows RFC 7807 - Problem Details for HTTP APIs","required":["title","extensions"],"properties":{"detail":{"type":["string","null"],"description":"A human-readable explanation specific to this occurrence of the problem","example":"The server encountered an unexpected condition"},"extensions":{"type":"object","description":"Additional properties of the problem","additionalProperties":true},"instance":{"type":["string","null"],"description":"A URI reference that identifies the specific occurrence of the problem","example":"/account/12345/msgs/abc"},"title":{"type":"string","description":"A short, human-readable summary of the problem type","example":"Internal Server Error"},"type":{"type":["string","null"],"description":"A URI reference that identifies the problem type","example":"https://example.com/probs/out-of-memory"}},"example":{"type":"https://example.com/probs/out-of-memory","title":"Internal Server Error","detail":"The server encountered an unexpected condition","instance":"/account/12345/msgs/abc","additional_info":"Custom field with additional details"}},"ProjectAccessResponse":{"type":"object","required":["id","project_id","team_id","role","granted_by","created_at","updated_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2026-07-30T12:15:47.609192Z"},"granted_by":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"project_id":{"type":"integer","format":"int32"},"role":{"$ref":"#/components/schemas/TeamRole"},"team_id":{"type":"integer","format":"int32"},"updated_at":{"type":"string","format":"date-time","example":"2026-07-30T12:15:47.609192Z"}}},"ProjectConfiguration":{"type":"object","description":"Project-level configuration","required":["name","slug","project_type","is_web_app"],"properties":{"is_web_app":{"type":"boolean","description":"Whether this is a web application"},"name":{"type":"string","description":"Proposed project name"},"project_type":{"$ref":"#/components/schemas/ProjectType","description":"Project type"},"slug":{"type":"string","description":"Proposed slug (URL-safe identifier)"}}},"ProjectDSNResponse":{"type":"object","required":["id","project_id","name","public_key","dsn","created_at","is_active","event_count"],"properties":{"created_at":{"type":"string"},"deployment_id":{"type":["integer","null"],"format":"int32"},"dsn":{"type":"string"},"environment_id":{"type":["integer","null"],"format":"int32"},"event_count":{"type":"integer","format":"int64"},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"public_key":{"type":"string"}}},"ProjectDashboardAnalytics":{"type":"object","description":"Analytics data for a single project in the dashboard batch response","required":["project_id","unique_visitors","previous_unique_visitors","hourly_visits"],"properties":{"hourly_visits":{"type":"array","items":{"$ref":"#/components/schemas/EventTimeline"},"description":"Hourly sparkline data points"},"previous_unique_visitors":{"type":"integer","format":"int64","description":"Unique visitor count in the previous period (same duration, shifted back)"},"project_id":{"type":"integer","format":"int32"},"trend_percentage":{"type":["number","null"],"format":"double","description":"Percentage change from previous period (positive = growth, negative = decline)\nNull when previous period had zero visitors (no baseline to compare)"},"unique_visitors":{"type":"integer","format":"int64","description":"Unique visitor count in the current time range"}}},"ProjectHealthSummary":{"type":"object","description":"Health summary for a single project (last 1 hour)","required":["project_id","total_requests","total_errors","avg_response_time_ms","error_rate","status"],"properties":{"avg_response_time_ms":{"type":"number","format":"double","description":"Average response time in ms"},"error_rate":{"type":"number","format":"double","description":"Error rate as a percentage (0-100)"},"project_id":{"type":"integer","format":"int32"},"status":{"type":"string","description":"Health status: \"healthy\", \"degraded\", \"down\", \"unknown\""},"total_errors":{"type":"integer","format":"int64","description":"Total server errors (status >= 500) in the period"},"total_requests":{"type":"integer","format":"int64","description":"Total requests in the period"}}},"ProjectInfo":{"type":"object","required":["id","slug","created_at"],"properties":{"created_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"id":{"type":"integer","format":"int32"},"slug":{"type":"string"}}},"ProjectMonitorHealth":{"type":"object","description":"Health summary for a single project based on its production monitors","required":["project_id","status"],"properties":{"project_id":{"type":"integer","format":"int32"},"status":{"type":"string","description":"Overall status: \"operational\", \"degraded\", \"down\", or \"no_monitors\""}}},"ProjectPresetResponse":{"type":"object","required":["path","preset","presetLabel","projectType"],"properties":{"composeFiles":{"type":["array","null"],"items":{"type":"string"},"description":"Compose file paths found in the repository (only for docker-compose preset)"},"exposedPort":{"type":["integer","null"],"format":"int32","description":"Default exposed port for this preset (e.g., 3000 for Next.js, 8000 for FastAPI)"},"iconUrl":{"type":["string","null"],"description":"Icon URL for the preset"},"path":{"type":"string"},"preset":{"type":"string"},"presetLabel":{"type":"string"},"projectType":{"type":"string","description":"Project type category (e.g., \"frontend\", \"backend\", \"fullstack\")"}}},"ProjectQuery":{"type":"object","required":["project_id"],"properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"}}},"ProjectRef":{"type":"object","description":"A lightweight project descriptor included in `UnifiedTrace`.","required":["project_id","project_name","project_slug"],"properties":{"project_id":{"type":"integer","format":"int32"},"project_name":{"type":"string"},"project_slug":{"type":"string","description":"URL slug used to link a span back into its owning project's trace view."}}},"ProjectResponse":{"type":"object","required":["id","slug","name","directory","main_branch","created_at","updated_at","deployment_config","attack_mode","ai_write_actions_enabled","error_source_context_enabled","enable_preview_environments","preview_envs_on_demand","preview_envs_idle_timeout_seconds","preview_envs_wake_timeout_seconds","source_type","cross_project_trace_sharing"],"properties":{"ai_alert_summaries_enabled":{"type":["boolean","null"],"description":"Opt-in to AI summarization of metric alert notifications (NULL/false = off)."},"ai_debug_chat_enabled":{"type":["boolean","null"],"description":"Opt-in to AI debugging chat, e.g. on deployment failures (NULL/false = off)."},"ai_write_actions_enabled":{"type":"boolean","description":"Opt-in to AI propose-then-confirm write capability (false = off)."},"attack_mode":{"type":"boolean","description":"Attack mode - when enabled, requires CAPTCHA verification for all project environments"},"created_at":{"type":"integer","format":"int64"},"cross_project_trace_sharing":{"type":"boolean","description":"ADR-027 Phase 3 opt-out: when false, this project's traces are suppressed\nfrom cross-project discovery results. Default true (consistent with the\nOSS global-observability model where any OtelRead holder can query any\nproject's telemetry)."},"deployment_config":{"$ref":"#/components/schemas/DeploymentConfig","description":"Deployment configuration (resources, autoscaling, features)"},"directory":{"type":"string"},"enable_preview_environments":{"type":"boolean","description":"Enable automatic preview environment creation for each branch"},"error_source_context_enabled":{"type":"boolean","description":"Opt-in to native error-tracking source context (false = off). When on,\nTemps stores uploaded source files and shows source code in stack traces."},"error_source_root":{"type":["string","null"],"description":"Where auto-capture reads source from (relative to the checkout). Null =\nthe deployment's Docker build context."},"git_provider_connection_id":{"type":["integer","null"],"format":"int32"},"git_url":{"type":["string","null"],"description":"Git clone URL for the repository (used for public repos without a provider connection)"},"gitlab_webhook_id":{"type":["integer","null"],"format":"int32","description":"GitLab webhook ID installed on the connected repository.\n`null` when no GitLab webhook is installed (not connected to GitLab,\nor webhook was removed / never created).","example":42},"id":{"type":"integer","format":"int32"},"last_deployment":{"type":["integer","null"],"format":"int64"},"main_branch":{"type":"string"},"name":{"type":"string"},"preset":{"type":["string","null"]},"preset_config":{"description":"Preset-specific configuration (Dockerfile path, build context, etc.)"},"preview_envs_idle_timeout_seconds":{"type":"integer","format":"int32","description":"Idle timeout (seconds) for on-demand preview environments."},"preview_envs_on_demand":{"type":"boolean","description":"When true, newly-created preview environments default to on-demand mode\n(containers stop after the configured idle timeout to save resources)."},"preview_envs_wake_timeout_seconds":{"type":"integer","format":"int32","description":"Wake timeout (seconds) for on-demand preview environments."},"repo_name":{"type":["string","null"]},"repo_owner":{"type":["string","null"]},"slug":{"type":"string"},"source_type":{"$ref":"#/components/schemas/SourceType","description":"Source type for deployments (git, docker_image, or static_files)"},"updated_at":{"type":"integer","format":"int64"}}},"ProjectSecretEnvironmentInfo":{"type":"object","required":["id","name","main_url"],"properties":{"id":{"type":"integer","format":"int32"},"main_url":{"type":"string"},"name":{"type":"string"}}},"ProjectSecretResponse":{"type":"object","description":"Project secret metadata. There is deliberately no `value` field — secret\nplaintext is never returned after creation. Callers that need the value\nmust read it from the mounted file inside the container.","required":["id","project_id","key","include_in_preview","created_at","updated_at","environments"],"properties":{"created_at":{"type":"integer","format":"int64"},"environments":{"type":"array","items":{"$ref":"#/components/schemas/ProjectSecretEnvironmentInfo"}},"id":{"type":"integer","format":"int32"},"include_in_preview":{"type":"boolean"},"key":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"updated_at":{"type":"integer","format":"int64"}}},"ProjectServiceInfo":{"type":"object","required":["id","project","service"],"properties":{"id":{"type":"integer","format":"int32"},"project":{"$ref":"#/components/schemas/ProjectInfo"},"service":{"$ref":"#/components/schemas/ExternalServiceInfo"}}},"ProjectStatisticsResponse":{"type":"object","required":["total_count"],"properties":{"total_count":{"type":"integer","format":"int64"}}},"ProjectStatsBreakdown":{"type":"object","required":["project_id","unique_visitors","total_visits","total_page_views","bounce_rate","engagement_rate"],"properties":{"bounce_rate":{"type":"number","format":"double"},"engagement_rate":{"type":"number","format":"double"},"project_id":{"type":"integer","format":"int32"},"project_name":{"type":["string","null"]},"total_page_views":{"type":"integer","format":"int64"},"total_visits":{"type":"integer","format":"int64"},"unique_visitors":{"type":"integer","format":"int64"}}},"ProjectType":{"type":"string","description":"Project type enumeration","enum":["static","docker","buildpack","git"]},"ProjectUsageInfoResponse":{"type":"object","required":["id","name","slug","connection_id","connection_name"],"properties":{"connection_id":{"type":"integer","format":"int32"},"connection_name":{"type":"string"},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"slug":{"type":"string"}}},"ProjectsHealthResponse":{"type":"object","description":"Batch health summary response","required":["projects"],"properties":{"projects":{"type":"object","description":"Health summaries keyed by project ID","additionalProperties":{"$ref":"#/components/schemas/ProjectHealthSummary"},"propertyNames":{"type":"string"}}}},"ProjectsMonitorHealthResponse":{"type":"object","description":"Batch response for projects health","required":["projects"],"properties":{"projects":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/ProjectMonitorHealth"},"propertyNames":{"type":"string"}}}},"PromoteDeploymentRequest":{"type":"object","required":["target_environment_id"],"properties":{"target_environment_id":{"type":"integer","format":"int32","description":"Target environment ID to promote the deployment to"}}},"PropertyBreakdownItem":{"type":"object","required":["value","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"percentage":{"type":"number","format":"double"},"value":{"type":"string"}}},"PropertyBreakdownQuery":{"type":"object","description":"Query parameters for property breakdown (group by column)","required":["start_date","end_date","group_by"],"properties":{"aggregation_level":{"$ref":"#/components/schemas/AggregationLevel","description":"Aggregation level"},"deployment_id":{"type":["integer","null"],"format":"int32","description":"Optional deployment filter"},"end_date":{"type":"string","format":"date-time","description":"End date for the query range"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Optional environment filter"},"event_name":{"type":["string","null"],"description":"Optional event name filter (e.g., \"page_view\", \"click\")"},"filter_browser":{"type":["string","null"],"description":"Filter by browser name (for browser version drill-downs)"},"filter_channel":{"type":["string","null"],"description":"Filter by channel name (for channel -> referrer drill-downs)"},"filter_country":{"type":["string","null"],"description":"Filter by country (for region/city drill-downs). Requires geolocation join."},"filter_os":{"type":["string","null"],"description":"Filter by operating system name (for OS version drill-downs)"},"filter_referrer":{"type":["string","null"],"description":"Filter by referrer hostname (for referrer -> pages drill-downs)"},"filter_region":{"type":["string","null"],"description":"Filter by region (for city drill-downs). Requires geolocation join."},"group_by":{"$ref":"#/components/schemas/PropertyColumn","description":"Property column to group by"},"include_crawlers":{"type":["boolean","null"],"description":"Include crawler/bot traffic (default: false). Off by default so the\nbreakdown percentages share a denominator with the headline counts,\nwhich always exclude crawlers."},"limit":{"type":["integer","null"],"format":"int32","description":"Maximum number of results to return (default: 20, max: 100)"},"start_date":{"type":"string","format":"date-time","description":"Start date for the query range"}}},"PropertyBreakdownResponse":{"type":"object","required":["property","items","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/PropertyBreakdownItem"}},"property":{"type":"string"},"total":{"type":"integer","format":"int64"}}},"PropertyColumn":{"type":"string","enum":["channel","device_type","browser","browser_version","operating_system","operating_system_version","utm_source","utm_medium","utm_campaign","utm_term","utm_content","referrer_hostname","language","event_type","event_name","page_path","pathname","country","region","city"]},"PropertyTimelineItem":{"type":"object","required":["timestamp","value","count"],"properties":{"count":{"type":"integer","format":"int64"},"timestamp":{"type":"string"},"value":{"type":"string"}}},"PropertyTimelineQuery":{"type":"object","description":"Query parameters for property timeline (group by column over time)","required":["start_date","end_date","group_by"],"properties":{"aggregation_level":{"$ref":"#/components/schemas/AggregationLevel","description":"Aggregation level"},"bucket_size":{"type":["string","null"],"description":"Time bucket size: \"hour\", \"day\", \"week\", \"month\" (default: auto-detect)"},"deployment_id":{"type":["integer","null"],"format":"int32","description":"Optional deployment filter"},"end_date":{"type":"string","format":"date-time","description":"End date for the query range"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Optional environment filter"},"event_name":{"type":["string","null"],"description":"Optional event name filter"},"group_by":{"$ref":"#/components/schemas/PropertyColumn","description":"Property column to group by"},"include_crawlers":{"type":["boolean","null"],"description":"Include crawler/bot traffic (default: false). See\n[`PropertyBreakdownQuery::include_crawlers`]."},"start_date":{"type":"string","format":"date-time","description":"Start date for the query range"}}},"PropertyTimelineResponse":{"type":"object","required":["property","bucket_size","items"],"properties":{"bucket_size":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/PropertyTimelineItem"}},"property":{"type":"string"}}},"Protocol":{"type":"string","description":"Network protocol","enum":["tcp","udp"]},"ProviderCatalogDto":{"type":"object","description":"One catalog entry rendered for the settings UI.","required":["id","name","install_command","auth_command","auth_flavors","models","credential_saved","supports_max_turns"],"properties":{"auth_command":{"type":"string"},"auth_flavors":{"type":"array","items":{"$ref":"#/components/schemas/AuthFlavorDto"}},"credential_saved":{"type":"boolean","description":"True when a credential is currently saved for this provider in the\nsettings JSON. Lets the UI render \"Configured\" badges without the\nfrontend having to inspect the encrypted blob."},"current_auth_type":{"type":["string","null"],"description":"Currently saved auth flavor id (when `credential_saved` is true).\n`None` when no credential is saved yet."},"default_model":{"type":["string","null"],"description":"Currently saved default model id for this provider, if one was\npicked. `None` means \"use the CLI's own default\" — the UI renders\nthat as \"Use provider default\"."},"id":{"type":"string"},"install_command":{"type":"string"},"max_turns_analysis":{"type":["integer","null"],"format":"int32","description":"Default max turns for the autofixer analysis phase. `None` = built-in\ndefault (10). Only enforced for CLIs with a turn flag (Claude Code)."},"max_turns_feedback":{"type":["integer","null"],"format":"int32","description":"Default max turns for autofixer feedback rounds. `None` = built-in\ndefault (10)."},"max_turns_fix":{"type":["integer","null"],"format":"int32","description":"Default max turns for the autofixer fix phase. `None` = built-in\ndefault (20)."},"models":{"type":"array","items":{"type":"string"},"description":"Model ids this provider accepts, in display order. The first entry is\nthe recommended default. Empty when the provider doesn't expose model\nselection (e.g. OpenCode), which the UI uses to hide the dropdown."},"name":{"type":"string"},"supports_max_turns":{"type":"boolean","description":"True when this provider's CLI supports enforcing a turn cap. False\nfor Codex/OpenCode, which run to completion — the UI labels their\nmax-turns inputs accordingly."}}},"ProviderCatalogResponse":{"type":"object","required":["default_provider","providers"],"properties":{"default_provider":{"type":"string","description":"Active provider id from `agent_sandbox.default_provider`. The settings\nUI uses this to highlight which card is the active one."},"providers":{"type":"array","items":{"$ref":"#/components/schemas/ProviderCatalogDto"}}}},"ProviderConfig":{"oneOf":[{"allOf":[{"$ref":"#/components/schemas/StripeConfig"},{"type":"object","required":["provider"],"properties":{"provider":{"type":"string","enum":["stripe"]}}}]},{"allOf":[{"$ref":"#/components/schemas/LemonSqueezyConfig"},{"type":"object","required":["provider"],"properties":{"provider":{"type":"string","enum":["lemon_squeezy"]}}}]}],"description":"Provider-specific integration settings persisted in\n`revenue_integrations.config`.\n\nThe tag is the lowercase provider name, so adding a new provider\nmeans adding a new variant and the existing rows are untouched.\nOld rows (pre-config) and rows with `NULL` config are treated as\n\"accept all events, no filtering\" via [`ProviderConfig::default_for`]."},"ProviderConfigMasked":{"type":"object","required":["auth_type","credential_saved","extra"],"properties":{"auth_type":{"type":"string"},"credential_saved":{"type":"boolean","description":"True if a credential is stored for this provider. The encrypted blob\nis never returned over HTTP."},"default_model":{"type":["string","null"]},"extra":{}}},"ProviderDeletionCheckResponse":{"type":"object","required":["can_delete","projects_in_use","message"],"properties":{"can_delete":{"type":"boolean"},"message":{"type":"string"},"projects_in_use":{"type":"array","items":{"$ref":"#/components/schemas/ProjectUsageInfoResponse"}}}},"ProviderDescriptor":{"type":"object","required":["name","display_name","recommended_events"],"properties":{"display_name":{"type":"string"},"name":{"type":"string"},"recommended_events":{"type":"array","items":{"type":"string"}}}},"ProviderKeyResponse":{"type":"object","required":["id","provider","display_name","api_key_masked","is_active","created_at","updated_at"],"properties":{"api_key_masked":{"type":"string","description":"Masked API key (only last 4 chars visible)"},"base_url":{"type":["string","null"]},"created_at":{"type":"string"},"default_model":{"type":["string","null"],"description":"Model id this provider serves (NULL → per-provider default)."},"display_name":{"type":"string"},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"provider":{"type":"string"},"updated_at":{"type":"string"}}},"ProviderMetadata":{"type":"object","required":["service_type","display_name","description","icon_url","color"],"properties":{"color":{"type":"string","example":"#336791"},"description":{"type":"string","example":"Relational database management system"},"display_name":{"type":"string","example":"PostgreSQL"},"icon_url":{"type":"string","example":"https://cdn.simpleicons.org/postgresql"},"service_type":{"$ref":"#/components/schemas/ServiceTypeRoute"}}},"ProviderResponse":{"type":"object","required":["id","name","provider_type","auth_method","is_active","is_default","created_at","updated_at"],"properties":{"auth_method":{"type":"string"},"base_url":{"type":["string","null"]},"created_at":{"type":"string","format":"date-time"},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"is_default":{"type":"boolean"},"name":{"type":"string"},"provider_type":{"type":"string"},"updated_at":{"type":"string","format":"date-time"}}},"ProviderUsage":{"type":"object","required":["provider","request_count","input_tokens","output_tokens","avg_latency_ms","error_count"],"properties":{"avg_latency_ms":{"type":"number","format":"double"},"error_count":{"type":"integer","format":"int64"},"input_tokens":{"type":"integer","format":"int64"},"output_tokens":{"type":"integer","format":"int64"},"provider":{"type":"string"},"request_count":{"type":"integer","format":"int64"}}},"ProvisionResponse":{"oneOf":[{"allOf":[{"$ref":"#/components/schemas/DomainError"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["error"]}}}]},{"allOf":[{"$ref":"#/components/schemas/DomainResponse"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["complete"]}}}]},{"allOf":[{"$ref":"#/components/schemas/DomainChallengeResponse"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["pending"]}}}]}]},"ProxyLogResponse":{"type":"object","description":"Response model for proxy logs","required":["id","timestamp","method","path","host","status_code","request_source","is_system_request","routing_status","request_id"],"properties":{"bot_name":{"type":["string","null"]},"browser":{"type":["string","null"]},"browser_version":{"type":["string","null"]},"cache_status":{"type":["string","null"]},"client_ip":{"type":["string","null"]},"container_id":{"type":["string","null"]},"deployment_id":{"type":["integer","null"],"format":"int32"},"device_type":{"type":["string","null"]},"environment_id":{"type":["integer","null"],"format":"int32"},"error_message":{"type":["string","null"]},"host":{"type":"string"},"id":{"type":"integer","format":"int32"},"ip_geolocation_id":{"type":["integer","null"],"format":"int32"},"is_bot":{"type":["boolean","null"]},"is_system_request":{"type":"boolean"},"method":{"type":"string"},"operating_system":{"type":["string","null"]},"path":{"type":"string"},"project_id":{"type":["integer","null"],"format":"int32"},"query_string":{"type":["string","null"]},"referrer":{"type":["string","null"]},"request_id":{"type":"string"},"request_size_bytes":{"type":["integer","null"],"format":"int64"},"request_source":{"type":"string"},"response_size_bytes":{"type":["integer","null"],"format":"int64"},"response_time_ms":{"type":["integer","null"],"format":"int32"},"routing_status":{"type":"string"},"session_id":{"type":["integer","null"],"format":"int32"},"status_code":{"type":"integer","format":"int32"},"timestamp":{"type":"string"},"upstream_host":{"type":["string","null"]},"user_agent":{"type":["string","null"]},"visitor_id":{"type":["integer","null"],"format":"int32"}}},"ProxyLogsPaginatedResponse":{"type":"object","description":"Paginated response for proxy logs","required":["logs","total","page","page_size","total_pages"],"properties":{"logs":{"type":"array","items":{"$ref":"#/components/schemas/ProxyLogResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0},"total_pages":{"type":"integer","format":"int64","minimum":0}}},"PublicHostnameStrategy":{"type":"string","description":"Public hostname generation mode for Temps-managed preview routes.\n\nThe mode is stored per managed domain (`dns_managed_domains.generated_hostname_mode`)\nrather than globally, so a provider such as Cloudflare can offer the flat layout\nrequired by its Universal SSL wildcard cert without changing every domain's behaviour.","enum":["standard","flat"]},"PublicPresetResponse":{"type":"object","description":"Response for preset detection","required":["branch","presets"],"properties":{"branch":{"type":"string","description":"Branch name where presets were detected"},"presets":{"type":"array","items":{"$ref":"#/components/schemas/PresetInfo"},"description":"List of detected presets"}}},"PublicRepositoryInfo":{"type":"object","description":"Public repository information","required":["owner","name","full_name","default_branch","stars","forks"],"properties":{"default_branch":{"type":"string","description":"Default branch name"},"description":{"type":["string","null"],"description":"Repository description"},"forks":{"type":"integer","format":"int32","description":"Fork count"},"full_name":{"type":"string","description":"Full repository name (owner/repo)"},"language":{"type":["string","null"],"description":"Primary programming language"},"name":{"type":"string","description":"Repository name"},"owner":{"type":"string","description":"Repository owner"},"stars":{"type":"integer","format":"int32","description":"Star count"}}},"PurgeLogsRequest":{"type":"object","required":["before"],"properties":{"before":{"type":"string","description":"Delete all logs before this timestamp (ISO 8601)"}}},"PushImageRequest":{"type":"object","description":"Request to push an external image","required":["image_ref"],"properties":{"image_ref":{"type":"string"},"metadata":{}}},"PushedExternalImageResponse":{"type":"object","description":"Response for in-memory external image operations (legacy push flow).\n\nRenamed to avoid shadowing the richer database-backed `ExternalImageResponse`\nin `handlers/remote_deployments.rs`. The two types serve different routes\n(`/images` ephemeral push vs `/external-images` registered images).","required":["id","image_ref","pushed_at"],"properties":{"digest":{"type":["string","null"]},"id":{"type":"string"},"image_ref":{"type":"string"},"pushed_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"size":{"type":["integer","null"],"format":"int64","minimum":0}}},"QueryDataRequest":{"type":"object","properties":{"filters":{"description":"JSON filters (backend-specific format)"},"limit":{"type":"integer","description":"Maximum number of rows to return","example":100,"minimum":0},"offset":{"type":"integer","description":"Number of rows to skip","example":0,"minimum":0},"sort_by":{"type":["string","null"],"description":"Sort by field name"},"sort_order":{"type":["string","null"],"description":"Sort order (asc/desc)"}}},"QueryDataResponse":{"type":"object","required":["fields","rows","total_count","returned_count","execution_time_ms"],"properties":{"execution_time_ms":{"type":"integer","format":"int64","description":"Query execution time in milliseconds","example":45,"minimum":0},"fields":{"type":"array","items":{"$ref":"#/components/schemas/FieldResponse"},"description":"Field definitions"},"returned_count":{"type":"integer","description":"Number of rows returned in this response","example":100,"minimum":0},"rows":{"type":"array","items":{},"description":"Data rows (array of JSON objects)"},"total_count":{"type":"integer","format":"int64","description":"Total number of rows matching the query (before limit/offset)","example":1234,"minimum":0}}},"QuotaResponse":{"type":"object","required":["quota"],"properties":{"quota":{"$ref":"#/components/schemas/StorageQuota"}}},"RateLimitConfig":{"type":"object","description":"Rate limiting configuration (subset of global RateLimitSettings)","properties":{"blacklistIps":{"type":"array","items":{"type":"string"},"description":"Blacklist specific IPs for this project/environment"},"maxRequestsPerHour":{"type":["integer","null"],"format":"int32","description":"Override rate limit per hour","minimum":0},"maxRequestsPerMinute":{"type":["integer","null"],"format":"int32","description":"Override rate limit per minute","minimum":0},"whitelistIps":{"type":"array","items":{"type":"string"},"description":"Whitelist specific IPs for this project/environment"}}},"RateLimitSettings":{"type":"object","properties":{"blacklist_ips":{"type":"array","items":{"type":"string"},"default":[]},"enabled":{"type":"boolean","default":false},"max_requests_per_hour":{"type":"integer","format":"int32","default":1000,"minimum":0},"max_requests_per_minute":{"type":"integer","format":"int32","default":60,"minimum":0},"whitelist_ips":{"type":"array","items":{"type":"string"},"default":[]}}},"ReachabilityStatus":{"type":"string","description":"Email reachability status","enum":["safe","risky","invalid","unknown"]},"ReadFileResponse":{"type":"object","required":["path","contents_b64","size"],"properties":{"contents_b64":{"type":"string","description":"File contents, base64-encoded. Symmetric with `WriteFileBody`."},"path":{"type":"string"},"size":{"type":"integer","format":"int64","minimum":0}}},"RecentActivityQuery":{"type":"object","description":"Query parameters for recent activity endpoint","required":["project_id"],"properties":{"environment_id":{"type":["integer","null"],"format":"int32","description":"Environment ID (optional)"},"limit":{"type":["integer","null"],"format":"int32","description":"Max number of events to return (default: 50, max: 100)"},"project_id":{"type":"integer","format":"int32","description":"Project ID"},"since_id":{"type":["integer","null"],"format":"int64","description":"Return events with ID greater than this (for cursor-based polling)"}}},"RecentActivityResponse":{"type":"object","description":"Response for recent activity events endpoint","required":["events","count"],"properties":{"count":{"type":"integer","description":"Total events returned","minimum":0},"events":{"type":"array","items":{"$ref":"#/components/schemas/ActivityEvent"},"description":"Recent events, newest first"}}},"RecentEventResponse":{"type":"object","required":["occurred_at","event_type"],"properties":{"amount_minor":{"type":["integer","null"],"format":"int64"},"currency":{"type":["string","null"]},"customer_ref":{"type":["string","null"]},"event_type":{"type":"string"},"mrr_minor":{"type":["integer","null"],"format":"int64"},"occurred_at":{"type":"string","format":"date-time"}}},"RecentQueryParams":{"type":"object","properties":{"conversation_id":{"type":["string","null"],"description":"Filter by conversation ID"},"cost_gt":{"type":["integer","null"],"format":"int64","description":"Cost strictly greater-than, in microcents"},"cost_gte":{"type":["integer","null"],"format":"int64","description":"Cost greater-than-or-equal, in microcents"},"cost_lt":{"type":["integer","null"],"format":"int64","description":"Cost strictly less-than, in microcents"},"cost_lte":{"type":["integer","null"],"format":"int64","description":"Cost less-than-or-equal, in microcents"},"limit":{"type":["integer","null"],"format":"int64","description":"Page size (defaults to 20, max 50)","minimum":0},"model":{"type":["string","null"],"description":"Filter by model name"},"offset":{"type":["integer","null"],"format":"int64","description":"Number of results to skip for pagination (defaults to 0)","minimum":0},"provider":{"type":["string","null"],"description":"Filter by provider name"},"status":{"type":["integer","null"],"format":"int32","description":"Filter by HTTP status code (exact match)"},"tags":{"type":["string","null"],"description":"Filter by tags (comma-separated, AND logic)"},"tokens_gt":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) strictly greater-than"},"tokens_gte":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) greater-than-or-equal"},"tokens_lt":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) strictly less-than"},"tokens_lte":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) less-than-or-equal"},"user_id":{"type":["integer","null"],"format":"int32","description":"Filter by user ID"}}},"RecordExposureRequest":{"type":"object","description":"Keys a running app actually evaluated since its last report.","required":["keys"],"properties":{"keys":{"type":"array","items":{"type":"string"},"description":"Flag keys evaluated since the last report. Unknown keys are ignored.","example":["checkout.v2","api.rate_limit"]}}},"RecordExposureResponse":{"type":"object","required":["recorded"],"properties":{"recorded":{"type":"integer","format":"int64","description":"How many keys were accepted for processing.\n\nDeliberately not the number of rows updated: echoing that back would\nlet a caller post a single candidate key and read the result as \"this\nflag exists\", turning the endpoint into an existence oracle.","minimum":0}}},"RecordListResponse":{"type":"object","description":"Record list response","required":["records"],"properties":{"records":{"type":"array","items":{"$ref":"#/components/schemas/DnsRecord"}}}},"RecoveryTarget":{"oneOf":[{"type":"object","description":"Recover to a specific timestamp.","required":["time","kind"],"properties":{"kind":{"type":"string","enum":["time"]},"time":{"type":"string","format":"date-time"}}},{"type":"object","description":"Recover to a specific transaction id (Postgres).","required":["xid","kind"],"properties":{"kind":{"type":"string","enum":["xid"]},"xid":{"type":"string"}}},{"type":"object","description":"Recover to a specific log sequence number (Postgres).","required":["lsn","kind"],"properties":{"kind":{"type":"string","enum":["lsn"]},"lsn":{"type":"string"}}},{"type":"object","description":"Recover to a named restore point created via `pg_create_restore_point` (Postgres).","required":["name","kind"],"properties":{"kind":{"type":"string","enum":["name"]},"name":{"type":"string"}}}],"description":"Engine-specific recovery target for PITR.\n\nPostgres honors all variants; Redis/Mongo/S3 will likely reject non-Time\nvariants or define their own semantics when they grow PITR support."},"ReferrerCount":{"type":"object","required":["referrer","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"percentage":{"type":"number","format":"double"},"referrer":{"type":"string"}}},"ReferrersAnalyticsQuery":{"type":"object","required":["start_date","end_date","project_id"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"RegenerateDSNRequest":{"type":"object","properties":{"base_url":{"type":["string","null"]}}},"RegisterImageRequest":{"type":"object","required":["image_ref"],"properties":{"digest":{"type":["string","null"],"description":"Image digest (sha256:...)","example":"sha256:abc123def456"},"image_ref":{"type":"string","description":"Docker image reference (e.g., \"ghcr.io/org/app:v1.0\")","example":"ghcr.io/myorg/myapp:v1.0"},"metadata":{"description":"Additional metadata"},"tag":{"type":["string","null"],"description":"Image tag","example":"v1.0"}}},"RegisterNodeApiRequest":{"type":"object","required":["name","token","address","private_address"],"properties":{"address":{"type":"string","description":"Node's reachable address (e.g., \"10.100.0.2\" or \"192.168.1.50\")"},"architecture":{"type":["string","null"],"description":"Container platform of this node's Docker daemon (`linux/amd64`,\n`linux/arm64`). Optional: agents older than multi-arch support omit it\nand the value is learned from the first heartbeat instead."},"csr_pem":{"type":["string","null"],"description":"Node-generated certificate signing request (PEM) for multi-node mTLS\n(ADR-020 WS-2.1). When present, the control plane signs it with the\ncluster CA and returns the leaf + CA cert. Optional — token-only nodes\n(legacy / edge) still register without one."},"edge_public_key":{"type":["string","null"],"description":"X25519 public key for ECIES certificate encryption (base64-encoded, edge nodes only)"},"join_token":{"type":["string","null"],"description":"Join token to authorize this registration (must match the token generated in Settings)"},"labels":{"description":"Labels for scheduling (e.g., {\"region\": \"us-east\", \"gpu\": \"true\"})"},"name":{"type":"string","description":"Unique name for this node"},"prior_token":{"type":["string","null"],"description":"The node's *current* token, supplied to prove possession when\nre-registering (changing the identity of) a node that already exists.\nOptional; only needed to rebind a still-live node. (ADR-020 WS-1.2.)"},"private_address":{"type":"string","description":"Private/WireGuard address for inter-node communication"},"public_endpoint":{"type":["string","null"],"description":"Public endpoint for WireGuard (e.g., \"203.0.113.1:51820\")"},"role":{"type":["string","null"],"description":"Node role (default: \"worker\")"},"token":{"type":"string","description":"Registration token (plaintext, will be hashed before storage)"},"wg_public_key":{"type":["string","null"],"description":"WireGuard public key"}}},"RegisterNodeResponse":{"type":"object","required":["id","name","status","message"],"properties":{"ca_cert_pem":{"type":["string","null"],"description":"The cluster CA certificate (PEM) the node pins as its trust root.\nPresent only when a `csr_pem` was supplied. (ADR-020 WS-2.1.)"},"cert_pem":{"type":["string","null"],"description":"The signed per-node leaf certificate (PEM) the agent serves as its TLS\nserver cert. Present only when a `csr_pem` was supplied. (ADR-020 WS-2.1.)"},"id":{"type":"integer","format":"int32"},"message":{"type":"string"},"name":{"type":"string"},"status":{"type":"string"}}},"RegisterRequest":{"type":"object","required":["email","password","name"],"properties":{"email":{"type":"string"},"name":{"type":"string"},"password":{"type":"string"}}},"ReinstallWebhookResponse":{"type":"object","description":"Response for `POST /projects/{project_id}/gitlab/reinstall-webhook`","required":["hook_id","message"],"properties":{"hook_id":{"type":"integer","format":"int32","description":"The new GitLab hook ID that was installed."},"message":{"type":"string","description":"Human-readable status message."}}},"ReleaseListResponse":{"type":"object","required":["releases"],"properties":{"releases":{"type":"array","items":{"type":"string"}}}},"ReloadResponse":{"type":"object","description":"Response from the reload endpoint.","required":["loaded","plugins","message"],"properties":{"loaded":{"type":"integer","description":"Number of plugins successfully loaded after reload","minimum":0},"message":{"type":"string","description":"Human-readable status message"},"plugins":{"type":"array","items":{"type":"string"},"description":"Names of loaded plugins"}}},"RemoteDeploymentResponse":{"type":"object","required":["id","project_id","environment_id","slug","state","source_type","created_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"environment_id":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"project_id":{"type":"integer","format":"int32"},"slug":{"type":"string"},"source_type":{"type":"string"},"state":{"type":"string"}}},"RemoveNodeResponse":{"type":"object","required":["id","message"],"properties":{"id":{"type":"integer","format":"int32"},"message":{"type":"string"}}},"RenameConversationRequest":{"type":"object","required":["title"],"properties":{"title":{"type":"string","description":"New human-facing title. Trimmed; must be non-empty after trimming."}}},"RepositoryListQuery":{"type":"object","properties":{"direction":{"type":["string","null"]},"language":{"type":["string","null"]},"owner":{"type":["string","null"]},"page":{"type":["integer","null"],"format":"int64","minimum":0},"per_page":{"type":["integer","null"],"format":"int64","minimum":0},"private":{"type":["boolean","null"]},"search":{"type":["string","null"]},"sort":{"type":["string","null"]}}},"RepositoryListResponse":{"type":"object","required":["repositories","total_count"],"properties":{"repositories":{"type":"array","items":{"$ref":"#/components/schemas/RepositoryResponse"}},"total_count":{"type":"integer","minimum":0}}},"RepositoryPresetResponse":{"type":"object","required":["repository_id","owner","name","presets","calculated_at"],"properties":{"calculated_at":{"type":"string","format":"date-time"},"name":{"type":"string"},"owner":{"type":"string"},"presets":{"type":"array","items":{"$ref":"#/components/schemas/ProjectPresetResponse"}},"repository_id":{"type":"integer","format":"int32"}}},"RepositoryResponse":{"type":"object","required":["id","owner","name","full_name","private","default_branch","created_at","updated_at","pushed_at","git_provider_connection_id"],"properties":{"clone_url":{"type":["string","null"],"description":"HTTPS clone URL (e.g., https://github.com/owner/repo.git)"},"created_at":{"type":"string","format":"date-time"},"default_branch":{"type":"string"},"description":{"type":["string","null"]},"full_name":{"type":"string"},"git_provider_connection_id":{"type":"integer","format":"int32","description":"ID of the git provider connection this repository was synced from."},"id":{"type":"integer","format":"int32"},"language":{"type":["string","null"]},"name":{"type":"string"},"owner":{"type":"string"},"preset":{"type":["array","null"],"items":{"$ref":"#/components/schemas/ProjectPresetResponse"}},"private":{"type":"boolean"},"pushed_at":{"type":"string","format":"date-time"},"ssh_url":{"type":["string","null"],"description":"SSH clone URL (e.g., git@github.com:owner/repo.git)"},"updated_at":{"type":"string","format":"date-time"}}},"RepositorySyncStartedResponse":{"type":"object","description":"Returned by `POST /git-connections/{id}/sync` to acknowledge that a\nsync has been kicked off in the background. Clients should poll the\nconnection's `syncing` and `synced_repository_count` fields to track\nprogress rather than waiting on this response.","required":["connection_id","syncing","started_at"],"properties":{"connection_id":{"type":"integer","format":"int32"},"started_at":{"type":"string","format":"date-time"},"syncing":{"type":"boolean"}}},"RequestRow":{"type":"object","required":["id","ts","method","host","path","status","request_headers","response_headers","headers_truncated"],"properties":{"client_ip":{"type":["string","null"]},"country":{"type":["string","null"]},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"error_group_id":{"type":["integer","null"],"format":"int32"},"headers_truncated":{"type":"boolean"},"host":{"type":"string"},"id":{"type":"string","description":"The request's unique `request_id` (assigned by the proxy). Used as the\nrow identity instead of the storage PK because the ClickHouse backend\nhas no serial id (rows come back with `id = 0`) while `request_id` is\nunique and present on both backends."},"latency_ms":{"type":["integer","null"],"format":"int32"},"method":{"type":"string"},"path":{"type":"string"},"query_string":{"type":["string","null"]},"referrer":{"type":["string","null"]},"request_headers":{},"response_headers":{},"status":{"type":"integer","format":"int32"},"trace_id":{"type":["string","null"]},"ts":{"type":"string","format":"date-time"},"user_agent":{"type":["string","null"]}}},"RequiredPasswordChangeRequest":{"type":"object","required":["new_password"],"properties":{"new_password":{"type":"string"}}},"RequiredPasswordChangeResponse":{"type":"object","required":["success","message","user_id","mfa_enrollment_required"],"properties":{"message":{"type":"string"},"mfa_enrollment_required":{"type":"boolean"},"mfa_setup":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/MfaSetupResponse"}]},"success":{"type":"boolean"},"user_id":{"type":"integer","format":"int32"}}},"ResetPasswordRequest":{"type":"object","required":["token","new_password"],"properties":{"new_password":{"type":"string"},"token":{"type":"string"}}},"ResetPgStatStatementsRequest":{"type":"object","description":"Explicit confirmation required for the destructive statistics reset.\n\nRequiring JSON makes the endpoint non-simple for browsers, preventing a\ndeployed same-site application from triggering it with a plain HTML form.","required":["confirm"],"properties":{"confirm":{"type":"boolean","description":"Must be `true` to acknowledge the global, irreversible reset."}}},"ResetPgStatStatementsResponse":{"type":"object","description":"Response for the pg_stat_statements reset endpoint.","required":["message"],"properties":{"message":{"type":"string","description":"Human-readable message confirming the destructive action."}}},"ResizeSandboxBody":{"type":"object","required":["disk_size_mb"],"properties":{"disk_size_mb":{"type":"integer","format":"int64","description":"New root disk size in MB. Grow-only; must exceed the current size.","minimum":0}},"additionalProperties":false},"ResolvedEnvVarResponse":{"type":"object","description":"One entry in the computed env-var view that merges manual and integration\nsources and tags each result with its origin. `value_preview` is always\nmasked — plaintext must be fetched per-key via the existing reveal endpoint,\nwhich is audit-logged.","required":["key","value_preview","source","environments","include_in_preview"],"properties":{"environments":{"type":"array","items":{"$ref":"#/components/schemas/EnvironmentInfo"},"description":"Environments this var applies to. For integration-sourced vars this\nreflects every environment of the project (integrations are global)."},"include_in_preview":{"type":"boolean","description":"Whether the var would be auto-applied to preview environments.\nIntegration vars always surface in preview; manual vars follow the flag."},"key":{"type":"string"},"source":{"$ref":"#/components/schemas/ResolvedEnvVarSource"},"value_preview":{"type":"string","description":"Masked or truncated preview. Never the raw value."}}},"ResolvedEnvVarSource":{"oneOf":[{"type":"object","description":"Manually-defined env var. If `overrides_service` is set, this key would\notherwise have been supplied by an integration — the UI should show the\nintegration icon plus an \"overridden\" indicator.","required":["var_id","type"],"properties":{"overrides_service":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/EnvVarIntegrationInfo"}]},"type":{"type":"string","enum":["manual"]},"var_id":{"type":"integer","format":"int32"}}},{"type":"object","description":"Supplied by a linked external service (Postgres, Redis, S3, etc.).","required":["service","type"],"properties":{"service":{"$ref":"#/components/schemas/EnvVarIntegrationInfo"},"type":{"type":"string","enum":["integration"]}}}],"description":"Where a resolved env var comes from. Integration-sourced vars may be\n\"shadowed\" by a manual entry with the same key, in which case the response\ncarries `Manual` with `overrides_service` populated so the UI can still show\nthe integration icon."},"ResourceCounts":{"type":"object","description":"Quick count of resources involved in the migration","required":["projects","environments","deployments","environment_variables","services","domains"],"properties":{"deployments":{"type":"integer","minimum":0},"domains":{"type":"integer","minimum":0},"environment_variables":{"type":"integer","minimum":0},"environments":{"type":"integer","minimum":0},"projects":{"type":"integer","minimum":0},"services":{"type":"integer","minimum":0}}},"ResourceFootprint":{"type":"object","description":"A CPU + memory footprint (requests or measured usage)","required":["cpu_millis","memory_mb"],"properties":{"cpu_millis":{"type":"integer","format":"int64","description":"CPU in millicores"},"memory_mb":{"type":"integer","format":"int64","description":"Memory in MB"}}},"ResourceInfo":{"type":"object","description":"Resource attributes extracted from OTel resource descriptors.","required":["service_name","attributes"],"properties":{"attributes":{"type":"object"},"deployment_environment":{"type":["string","null"]},"service_name":{"type":"string"},"service_version":{"type":["string","null"]}}},"ResourceLimitApplyResult":{"type":"object","description":"Per-container outcome of a live `docker update` call. Surfaced from the\nPATCH /resources endpoint so the UI can tell the operator whether the\nnew caps are already in effect or whether they only apply on next\nrecreate (e.g., container was missing).","required":["role","container_name","outcome"],"properties":{"container_name":{"type":"string"},"error":{"type":["string","null"],"description":"Populated only when `outcome == \"failed\"`."},"outcome":{"type":"string","description":"One of:\n- \"applied\" — Docker accepted the update; caps are live now.\n- \"missing\" — container does not exist; caps stored, will apply on next start.\n- \"stopped\" — container exists but isn't running; Docker still\n accepts the update (the new caps apply on next start).\n- \"failed\" — `docker update` returned an error (see `error`)."},"role":{"type":"string","description":"`service_members.role` for cluster members; \"standalone\" otherwise."}}},"ResourceLimits":{"type":"object","description":"Resource limits and requests","properties":{"cpu_limit":{"type":["integer","null"],"format":"int32","description":"CPU limit (millicores)"},"cpu_request":{"type":["integer","null"],"format":"int32","description":"CPU request (millicores)"},"memory_limit":{"type":["integer","null"],"format":"int32","description":"Memory limit (MB)"},"memory_request":{"type":["integer","null"],"format":"int32","description":"Memory request (MB)"}}},"ResourceLimitsResponse":{"type":"object","description":"Container resource limits","properties":{"cpu_limit":{"type":["integer","null"],"format":"int32"},"cpu_request":{"type":["integer","null"],"format":"int32"},"memory_limit":{"type":["integer","null"],"format":"int32"},"memory_request":{"type":["integer","null"],"format":"int32"}}},"ResourceLimitsUpdateResponse":{"type":"object","description":"Response from PATCH /external-services/{id}/resources.","required":["limits","applied"],"properties":{"applied":{"type":"array","items":{"$ref":"#/components/schemas/ResourceLimitApplyResult"},"description":"Per-container result of trying to apply the limits live."},"limits":{"$ref":"#/components/schemas/ServiceResourceLimits","description":"The limits that were persisted to the encrypted config."}}},"ResourcesBody":{"type":"object","description":"Nested `resources: { memory, vcpus }` as sent by `@vercel/sandbox`.\n`memory` is in MB, `vcpus` is fractional CPU count.","properties":{"memory":{"type":["integer","null"],"format":"int64","minimum":0},"vcpus":{"type":["number","null"],"format":"double"}}},"RestoreCapabilities":{"type":"object","description":"Capabilities a service exposes for the generic restore framework.\n\nEach engine overrides `ExternalService::restore_capabilities` to declare\nwhat it supports. The handler layer uses this to validate requests and\nthe UI uses it to conditionally show options (e.g., PITR picker).","required":["restore_in_place","restore_to_new_service","pitr"],"properties":{"earliest_pitr_time":{"type":["string","null"],"format":"date-time","description":"Earliest recoverable timestamp, if `pitr` is true. Derived from\nengine-specific archive metadata (e.g., `pg_stat_archiver`)."},"latest_pitr_time":{"type":["string","null"],"format":"date-time","description":"Latest recoverable timestamp, if `pitr` is true."},"pitr":{"type":"boolean","description":"Point-in-time recovery using engine-specific continuous archives\n(WAL for Postgres, AOF for Redis, oplog for MongoDB, object versions for S3)."},"restore_in_place":{"type":"boolean","description":"Restore a backup onto the same running service (destructive)."},"restore_to_new_service":{"type":"boolean","description":"Restore a backup into a freshly provisioned service."}}},"RestoreCapabilitiesResponse":{"allOf":[{"$ref":"#/components/schemas/RestoreCapabilities","description":"Trait-declared capabilities."},{"type":"object","required":["suggested_new_service_name"],"properties":{"suggested_new_service_name":{"type":"string","description":"Suggested name for the new service when creating a clone. Safe to\npre-fill into the UI dialog; the user can edit before submitting."}}}]},"RestorePlan":{"type":"object","description":"Preview of a restore operation. Answers \"what will happen if I click\nstart?\" with engine-level specificity so the user can confirm before\ncommitting to a destructive action.","required":["engine","target_service","source_backup","strategy","steps","warnings","errors","destructive","mode"],"properties":{"destructive":{"type":"boolean","description":"Whether any step overwrites existing data on the target service."},"engine":{"type":"string","description":"Target engine (\"postgres\", etc.)."},"errors":{"type":"array","items":{"type":"string"},"description":"Blocking problems. The UI disables the Start button when non-empty."},"mode":{"type":"string","description":"Echo of the requested mode for the UI."},"source_backup":{"$ref":"#/components/schemas/PlanSourceBackup","description":"Backup we'll read from."},"steps":{"type":"array","items":{"type":"string"},"description":"Ordered list of human-readable actions the orchestrator will take."},"strategy":{"type":"string","description":"How the restore will be performed: \"walg_restore\", \"pg_dump_restore\",\nor \"unsupported\"."},"target_service":{"$ref":"#/components/schemas/PlanTarget","description":"Service we'll operate on (or provision a sibling of)."},"warnings":{"type":"array","items":{"type":"string"},"description":"Non-blocking caveats the user should see (cross-service, empty\nlocation that will be auto-resolved, missing engine metadata, ...)."}}},"RestoreRequestMode":{"oneOf":[{"type":"object","description":"Restore the backup onto the existing service (destructive).","required":["mode"],"properties":{"mode":{"type":"string","enum":["in_place"]}}},{"type":"object","description":"Provision a new service and restore into it.","required":["name","mode"],"properties":{"mode":{"type":"string","enum":["new_service"]},"name":{"type":"string","description":"Name for the new service. Orchestrator auto-suggests\n`{source}-restore-{yyyymmdd-hhmm}` if caller omits, but we require\nan explicit value at the API boundary."},"parameter_overrides":{"description":"Optional parameter overrides (port, docker_image, database)."}}},{"type":"object","description":"Point-in-time recovery. Only valid on WAL-G backups (Postgres).","required":["to_new_service","target","mode"],"properties":{"mode":{"type":"string","enum":["pitr"]},"new_service_name":{"type":["string","null"],"description":"Required when `to_new_service` is true."},"target":{"$ref":"#/components/schemas/RecoveryTarget","description":"Recovery target kind + value."},"to_new_service":{"type":"boolean","description":"Whether PITR restores in place or creates a new service."}}}],"description":"What the caller wants to do. Mirrors `externalsvc::RestoreMode` but\nflattened for JSON over the wire."},"RestoreRunView":{"type":"object","required":["id","source_backup_id","source_service_id","mode","status","phase","created_at"],"properties":{"created_at":{"type":"string"},"error_message":{"type":["string","null"]},"finished_at":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"mode":{"type":"string"},"phase":{"type":"string"},"recovery_target":{},"source_backup_id":{"type":"integer","format":"int32"},"source_service_id":{"type":"integer","format":"int32"},"started_at":{"type":["string","null"]},"status":{"type":"string"},"target_service_id":{"type":["integer","null"],"format":"int32"},"target_service_name":{"type":["string","null"]}}},"RetentionCleanupFailure":{"type":"object","required":["backup_id","reason","partial","deleted_objects"],"properties":{"backup_id":{"type":"string"},"deleted_objects":{"type":"integer","format":"int64","minimum":0},"partial":{"type":"boolean"},"reason":{"type":"string"}}},"RetentionCleanupReport":{"type":"object","required":["dry_run","expired","deleted","failed","failures","deleted_backup_ids","deleted_backup_ids_truncated","partially_deleted_backup_ids","partially_deleted_backup_ids_truncated","candidate_backup_ids","candidate_backup_ids_truncated"],"properties":{"candidate_backup_ids":{"type":"array","items":{"type":"string"},"description":"Capped sample of backups selected by the retention policy."},"candidate_backup_ids_truncated":{"type":"boolean"},"deleted":{"type":"integer","format":"int64","minimum":0},"deleted_backup_ids":{"type":"array","items":{"type":"string"},"description":"Capped sample of deleted backup UUIDs for audit attribution."},"deleted_backup_ids_truncated":{"type":"boolean"},"dry_run":{"type":"boolean","description":"True when this report is a non-destructive preview."},"expired":{"type":"integer","format":"int64","minimum":0},"failed":{"type":"integer","format":"int64","minimum":0},"failures":{"type":"array","items":{"$ref":"#/components/schemas/RetentionCleanupFailure"},"description":"Capped diagnostic sample; `failed` remains the authoritative total."},"partially_deleted_backup_ids":{"type":"array","items":{"type":"string"}},"partially_deleted_backup_ids_truncated":{"type":"boolean"},"schedule_id":{"type":["integer","null"],"format":"int32","description":"Schedule scope, or `None` when every schedule was considered."}}},"RetryClusterRequest":{"type":"object","description":"Request body for retrying a failed cluster initialization.","properties":{"members":{"type":"array","items":{"$ref":"#/components/schemas/ClusterMemberRequest"},"description":"Cluster member specifications (same format as create).\nIf omitted, the original member configuration is reconstructed from\nthe preserved service_members records."}}},"RevenueRow":{"type":"object","required":["id","ts","provider","event_type"],"properties":{"amount_minor":{"type":["integer","null"],"format":"int64"},"currency":{"type":["string","null"]},"customer_ref":{"type":["string","null"]},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"event_type":{"type":"string"},"id":{"type":"integer","format":"int64"},"provider":{"type":"string"},"trace_id":{"type":["string","null"]},"ts":{"type":"string","format":"date-time"}}},"RiskLevel":{"type":"string","description":"Risk level for a migration step","enum":["none","low","medium","high","critical"]},"RoleInfo":{"type":"object","description":"Information about a role","required":["name","description","permissions"],"properties":{"description":{"type":"string","description":"Human-readable description of the role"},"name":{"type":"string","description":"The role identifier (e.g., \"admin\")"},"permissions":{"type":"array","items":{"type":"string"},"description":"Permissions included in this role"}}},"RootfsCacheEntry":{"type":"object","description":"A cached rootfs image (Firecracker backend). Digest-keyed build artifact\nshared by all VMs created from the same image.","required":["digest","bytes","referenced_by"],"properties":{"bytes":{"type":"integer","format":"int64","description":"Actual on-disk size in bytes (sparse-aware).","minimum":0},"digest":{"type":"string","description":"Image digest this rootfs was built from (the cache key)."},"referenced_by":{"type":"array","items":{"type":"string"},"description":"IDs of live sandboxes whose per-VM disk was cloned from this entry.\nEmpty means the entry is reclaimable — no sandbox needs it."}}},"RootfsGcReport":{"type":"object","description":"Outcome of a rootfs garbage-collection pass.","required":["removed_digests","freed_bytes"],"properties":{"freed_bytes":{"type":"integer","format":"int64","minimum":0},"removed_digests":{"type":"array","items":{"type":"string"},"description":"Digests of cache entries removed because no sandbox referenced them."}}},"RootfsReport":{"type":"object","description":"Snapshot of a backend's rootfs storage for the management API. Backends\nwithout a rootfs concept (Docker, local) return an empty report.","required":["cache_bytes","cache","vm_bytes","vms"],"properties":{"cache":{"type":"array","items":{"$ref":"#/components/schemas/RootfsCacheEntry"}},"cache_bytes":{"type":"integer","format":"int64","minimum":0},"vm_bytes":{"type":"integer","format":"int64","minimum":0},"vms":{"type":"array","items":{"$ref":"#/components/schemas/RootfsVmEntry"}}}},"RootfsVmEntry":{"type":"object","description":"A per-sandbox rootfs disk (Firecracker backend). One per non-destroyed\nsandbox — the authoritative storage, independent of the cache.","required":["sandbox_name","bytes","running"],"properties":{"bytes":{"type":"integer","format":"int64","minimum":0},"running":{"type":"boolean"},"sandbox_name":{"type":"string"}}},"RouteRefreshResponse":{"type":"object","required":["route_count","message"],"properties":{"message":{"type":"string","description":"Human-readable message"},"route_count":{"type":"integer","description":"Number of routes loaded","minimum":0}}},"RouteResponse":{"type":"object","required":["id","domain","host","port","enabled","route_type","created_at","updated_at"],"properties":{"created_at":{"type":"integer","format":"int64"},"domain":{"type":"string"},"enabled":{"type":"boolean"},"host":{"type":"string"},"id":{"type":"integer","format":"int32"},"port":{"type":"integer","format":"int32"},"route_type":{"type":"string","description":"Route type: \"http\" or \"tls\""},"updated_at":{"type":"integer","format":"int64"}}},"RouteRole":{"type":"object","required":["id","name","created_at","updated_at"],"properties":{"created_at":{"type":"integer","format":"int64","example":"1683900000000"},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"updated_at":{"type":"integer","format":"int64","example":"1683900000000"}}},"RouteUser":{"type":"object","required":["id","name","username","email","image","mfa_enabled","email_verified","must_change_password","created_at","updated_at"],"properties":{"created_at":{"type":"integer","format":"int64","example":"1683900000000"},"deleted_at":{"type":["integer","null"],"format":"int64"},"email":{"type":"string"},"email_verified":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"image":{"type":"string"},"mfa_enabled":{"type":"boolean"},"must_change_password":{"type":"boolean"},"name":{"type":"string"},"updated_at":{"type":"integer","format":"int64","example":"1683900000000"},"username":{"type":"string"}}},"RouteUserWithRoles":{"type":"object","required":["user","roles"],"properties":{"roles":{"type":"array","items":{"$ref":"#/components/schemas/RouteRole"}},"user":{"$ref":"#/components/schemas/RouteUser"}}},"RunBackupRequest":{"type":"object","required":["backup_type"],"properties":{"backup_type":{"type":"string","description":"Type of backup to perform","example":"full"}}},"RunExternalServiceBackupRequest":{"type":"object","properties":{"backup_type":{"type":["string","null"],"description":"Type of backup to perform (e.g., \"full\", \"incremental\")","example":"full"},"s3_source_id":{"type":["integer","null"],"format":"int32","description":"ID of the S3 source to store the backup. If omitted, the current default S3 source is used.","example":1}}},"S3ConnectionTestResponse":{"type":"object","description":"Response body for an S3 connection test.","required":["ok","message"],"properties":{"message":{"type":"string","description":"Human-readable message (success confirmation or error detail)."},"ok":{"type":"boolean","description":"Whether the connection and credentials worked."}}},"S3CredentialsResponse":{"type":"object","description":"S3 credentials distributed to agents for backup/restore operations.","required":["access_key_id","secret_key","region","bucket_name","force_path_style"],"properties":{"access_key_id":{"type":"string"},"bucket_name":{"type":"string"},"endpoint":{"type":["string","null"]},"force_path_style":{"type":"boolean"},"region":{"type":"string"},"secret_key":{"type":"string"}}},"S3SourceResponse":{"type":"object","description":"Response type for S3 source","required":["id","name","bucket_name","bucket_path","access_key_id","secret_key","region","is_default","created_at","updated_at"],"properties":{"access_key_id":{"type":"string","example":"AKIAXXXXXXXXXXXXXXXX"},"bucket_name":{"type":"string"},"bucket_path":{"type":"string"},"created_at":{"type":"integer","format":"int64"},"endpoint":{"type":["string","null"],"example":"http://minio.example.com:9000"},"force_path_style":{"type":["boolean","null"]},"id":{"type":"integer","format":"int32"},"is_default":{"type":"boolean"},"name":{"type":"string"},"region":{"type":"string"},"secret_key":{"type":"string","writeOnly":true},"updated_at":{"type":"integer","format":"int64"}}},"SandboxDomainResponse":{"type":"object","required":["url"],"properties":{"url":{"type":"string"}}},"SandboxEvent":{"type":"object","description":"One entry in a sandbox's operations timeline.","required":["event_type","at"],"properties":{"at":{"type":"integer","format":"int64","description":"Unix epoch milliseconds."},"detail":{"description":"Optional structured context (shape depends on `event_type`)."},"event_type":{"type":"string","description":"Machine-readable operation (`created`, `stopped`, `resumed`,\n`restarted`, `timeout_extended`, `resized`, `preview_password_set`,\n`preview_password_cleared`, `preview_share_link_created`, `source_seeded`,\n`destroyed`)."}}},"SandboxEventsResponse":{"type":"object","required":["events"],"properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/SandboxEvent"}}}},"SandboxInner":{"type":"object","description":"Inner `sandbox` object in `@vercel/sandbox` responses. Strict shape —\nthe SDK's zod validator rejects missing required fields.","required":["id","memory","vcpus","region","runtime","timeout","status","requestedAt","createdAt","updatedAt","cwd","name","preview_url_template"],"properties":{"agent_run_id":{"type":["integer","null"],"format":"int32","description":"Agent run this sandbox executes (autofixer / workflow agent).\n`None` for sandboxes created via this API."},"backend":{"type":["string","null"],"description":"Isolation backend: \"docker\" | \"firecracker\". `None` on legacy rows\ncreated before the backend was recorded."},"createdAt":{"type":"integer","format":"int64"},"cwd":{"type":"string"},"disk_size_mb":{"type":["integer","null"],"format":"int64","description":"Configured root disk size in MB (Firecracker). `None` when unknown or\nthe default.","minimum":0},"id":{"type":"string"},"image":{"type":["string","null"]},"memory":{"type":"integer","format":"int64","minimum":0},"name":{"type":"string"},"preview_password_hint":{"type":["string","null"]},"preview_url_template":{"type":"string"},"region":{"type":"string"},"requestedAt":{"type":"integer","format":"int64","description":"Creation time as Unix epoch milliseconds."},"runtime":{"type":"string"},"status":{"type":"string"},"timeout":{"type":"integer","format":"int64","description":"Idle timeout in milliseconds (SDK convention).","minimum":0},"updatedAt":{"type":"integer","format":"int64"},"vcpus":{"type":"number","format":"double"}}},"SandboxResponse":{"type":"object","description":"`@vercel/sandbox` wraps every single-sandbox response as\n`{ sandbox: {...}, routes: [...] }`. The SDK reads both.","required":["sandbox","routes"],"properties":{"routes":{"type":"array","items":{"$ref":"#/components/schemas/SandboxRoute"}},"sandbox":{"$ref":"#/components/schemas/SandboxInner"}}},"SandboxRoute":{"type":"object","description":"A single preview route, one per declared port. We don't know ports\nupfront, so we surface an empty array by default — SDK clients use\ntheir own port when calling `sandbox.domain(port)`.","required":["url","subdomain","port"],"properties":{"port":{"type":"integer","format":"int32","minimum":0},"subdomain":{"type":"string"},"url":{"type":"string"}}},"SandboxStatusResponse":{"type":"object","required":["docker_available","image_ready","image_name","firecracker_available"],"properties":{"docker_available":{"type":"boolean"},"error":{"type":["string","null"]},"firecracker_available":{"type":"boolean"},"image_name":{"type":"string"},"image_ready":{"type":"boolean"}}},"SaveAgentTokenRequest":{"type":"object","required":["token"],"properties":{"token":{"type":"string","description":"The OAuth token from `claude setup-token` or an API key.\nWill be encrypted before storage."}}},"SaveAgentTokenResponse":{"type":"object","required":["saved"],"properties":{"saved":{"type":"boolean"}}},"SaveCredentialRequest":{"type":"object","required":["auth_type","credential"],"properties":{"auth_type":{"type":"string","description":"Auth flavor id (must match one of the provider's catalog entries)."},"credential":{"type":"string","description":"Plaintext credential body (API key, OAuth token, or full config file\ncontents). Encrypted with `EncryptionService` before being persisted\ninside the `agent_sandbox.providers` JSON map."}}},"SaveCredentialResponse":{"type":"object","required":["saved","provider_id","auth_type"],"properties":{"auth_type":{"type":"string"},"provider_id":{"type":"string"},"saved":{"type":"boolean"}}},"ScalewayCredentialsRequest":{"type":"object","required":["api_key","project_id"],"properties":{"api_key":{"type":"string","example":"scw-secret-key-12345"},"project_id":{"type":"string","example":"12345678-1234-1234-1234-123456789012"}}},"ScanResponse":{"type":"object","required":["id","project_id","scanner_type","status","total_count","critical_count","high_count","medium_count","low_count","unknown_count","started_at","created_at","updated_at"],"properties":{"branch":{"type":["string","null"]},"commit_hash":{"type":["string","null"]},"completed_at":{"type":["string","null"],"example":"2025-12-08T12:15:47.609192Z"},"created_at":{"type":"string","example":"2025-12-08T12:15:47.609192Z"},"critical_count":{"type":"integer","format":"int32"},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"error_message":{"type":["string","null"]},"high_count":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"low_count":{"type":"integer","format":"int32"},"medium_count":{"type":"integer","format":"int32"},"project_id":{"type":"integer","format":"int32"},"scanner_type":{"type":"string"},"scanner_version":{"type":["string","null"]},"started_at":{"type":"string","example":"2025-12-08T12:15:47.609192Z"},"status":{"type":"string"},"total_count":{"type":"integer","format":"int32"},"unknown_count":{"type":"integer","format":"int32"},"updated_at":{"type":"string","example":"2025-12-08T12:15:47.609192Z"}}},"ScheduleRunEntry":{"type":"object","description":"A single run-history entry for the schedule detail page (deliverable 1).\n\nCombines one `backups` row with the most-recent `backup_jobs` row for that\nbackup via a lateral JOIN. Fields from `backup_jobs` are `None` for legacy\nbackup rows that pre-date ADR-014.","required":["backup_id","backup_uuid","state","started_at","s3_location"],"properties":{"attempts":{"type":["integer","null"],"format":"int32","description":"Number of claim-and-run attempts so far. `None` for legacy rows."},"backup_id":{"type":"integer","format":"int32","description":"DB id of the `backups` row."},"backup_uuid":{"type":"string","description":"UUID string (`backups.backup_id`)."},"current_step":{"type":["string","null"],"description":"Last completed step reported by the engine (e.g. `\"upload\"`).\n`None` when no step has been persisted yet."},"error_message":{"type":["string","null"],"description":"Engine-reported error message when `state = \"failed\"`."},"finished_at":{"type":["string","null"],"description":"When the backup finished, if known."},"job_id":{"type":["integer","null"],"format":"int64","description":"Most recent `backup_jobs.id` for this backup. `None` for legacy rows."},"s3_location":{"type":"string","description":"S3 object key or URL where the backup data lives."},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Final size in bytes once completed. `None` while running."},"started_at":{"type":"string","description":"When the backup was started (ISO 8601 / RFC 3339)."},"state":{"type":"string","description":"Current state: `\"pending\"`, `\"running\"`, `\"completed\"`, `\"failed\"`."}}},"ScheduleRunJobEntry":{"type":"object","description":"A single job entry inside an expanded schedule run, returned by\n[`BackupService::list_schedule_run_jobs`].","required":["backup_id","backup_uuid","engine","service_name","state","started_at","s3_source_id"],"properties":{"backup_id":{"type":"integer","format":"int32","description":"`backups.id` for this job."},"backup_uuid":{"type":"string","description":"`backups.backup_id` UUID string."},"engine":{"type":"string","description":"Engine key (e.g. `\"control_plane\"`, `\"redis\"`)."},"error_message":{"type":["string","null"],"description":"Engine-reported error message when `state = \"failed\"`."},"finished_at":{"type":["string","null"],"description":"When this child backup finished, if known."},"s3_source_id":{"type":"integer","format":"int32","description":"FK to `s3_sources.id` — needed for the backup detail link."},"service_id":{"type":["integer","null"],"format":"int32","description":"`external_services.id` — `NULL` for the control-plane job."},"service_name":{"type":"string","description":"Name of the external service, or `\"control plane\"` for the\ncontrol-plane job."},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Size in bytes once completed; `None` while running."},"started_at":{"type":"string","description":"When this child backup started (ISO 8601 / RFC 3339)."},"state":{"type":"string","description":"Current state of this child backup."}}},"ScheduleRunListResponse":{"type":"object","description":"Paginated run-history response for a backup schedule (deliverable 1).","required":["runs","total","page","page_size"],"properties":{"page":{"type":"integer","format":"int64","description":"Current page (1-based)."},"page_size":{"type":"integer","format":"int64","description":"Number of items per page (clamped to 1–100)."},"runs":{"type":"array","items":{"$ref":"#/components/schemas/ScheduleRunEntry"},"description":"Run entries, newest first."},"total":{"type":"integer","format":"int64","description":"Total number of runs across all pages."}}},"ScheduleRunResponse":{"type":"object","description":"HTTP response body for `POST /api/backups/schedules/{id}/run` (fan-out).","required":["schedule_run_id","jobs"],"properties":{"jobs":{"type":"array","items":{"$ref":"#/components/schemas/EnqueuedJob"},"description":"All jobs that were enqueued in this fan-out."},"schedule_run_id":{"type":"integer","format":"int64","description":"The `schedule_runs.id` of the newly created run."}}},"ScheduleRunSummary":{"type":"object","description":"Summary of one scheduler tick (or one \"Run now\" click), returned by\n[`BackupService::list_schedule_runs`].\n\nThe `aggregate_state` is computed at read time from child backup counts:\n- `\"running\"` — at least one child is `\"pending\"` or `\"running\"`.\n- `\"failed\"` — at least one child is `\"failed\"` and none are running.\n- `\"completed\"` — all children are `\"completed\"`.","required":["run_id","schedule_id","triggered_by","started_at","aggregate_state","total_jobs","completed_jobs","failed_jobs","running_jobs","pending_jobs"],"properties":{"aggregate_state":{"type":"string","description":"Aggregate state computed from child counts (see struct docs)."},"completed_jobs":{"type":"integer","format":"int64","description":"Number of children in `state = \"completed\"`."},"failed_jobs":{"type":"integer","format":"int64","description":"Number of children in `state = \"failed\"`."},"finished_at":{"type":["string","null"],"description":"When all children reached a terminal state. `None` while any child is\nstill `\"pending\"` or `\"running\"`."},"pending_jobs":{"type":"integer","format":"int64","description":"Number of children in `state = \"pending\"`."},"run_id":{"type":"integer","format":"int64","description":"`schedule_runs.id` for this tick."},"running_jobs":{"type":"integer","format":"int64","description":"Number of children in `state = \"running\"`."},"schedule_id":{"type":"integer","format":"int32","description":"FK to `backup_schedules.id`."},"started_at":{"type":"string","description":"When the fan-out started (ISO 8601 / RFC 3339)."},"total_jobs":{"type":"integer","format":"int64","description":"Total number of child backup jobs in this run."},"triggered_by":{"type":"string","description":"How the run was triggered: `\"cron\"` or `\"manual\"`."}}},"ScheduleRunSummaryList":{"type":"object","description":"Paginated list of schedule run summaries returned by the new\n[`BackupService::list_schedule_runs`].","required":["runs","total","page","page_size"],"properties":{"page":{"type":"integer","format":"int64","description":"Current page (1-based)."},"page_size":{"type":"integer","format":"int64","description":"Number of items per page."},"runs":{"type":"array","items":{"$ref":"#/components/schemas/ScheduleRunSummary"},"description":"Run summaries, newest first. Includes synthetic single-job rows for\nlegacy `backups` rows that have `schedule_id` set but no\n`schedule_run_id` (pre-fan-out history)."},"total":{"type":"integer","format":"int64","description":"Total number of run entries across all pages."}}},"ScreenshotSettings":{"type":"object","properties":{"enabled":{"type":"boolean","default":false},"provider":{"type":"string","default":"local"},"url":{"type":"string","default":""}}},"SearchLogsRequest":{"type":"object","required":["project_id"],"properties":{"container_ids":{"type":"array","items":{"type":"string"},"description":"Filter to specific containers (Docker container IDs). Empty = all\ncontainers. Drives \"filter by container / show all\" in a project's\nhistory, which spans multiple deployments and containers."},"context_lines":{"type":["integer","null"],"format":"int32","description":"grep -C: number of raw context lines to include before and after each\nmatch (0 = none, default). Clamped to 50 server-side. The surrounding\nlines ignore the level/text filters — they are the actual adjacent log\nlines, merged across overlapping matches.","minimum":0},"cursor":{"type":["string","null"],"description":"Pagination cursor"},"deploy_id":{"type":["integer","null"],"format":"int32","description":"Filter by deployment ID (deployments.id)"},"end_time":{"type":["string","null"],"description":"End of time range (ISO 8601). Defaults to now."},"envs":{"type":"array","items":{"type":"string"},"description":"Filter by environments"},"external_service_id":{"type":["integer","null"],"format":"int32","description":"When set, search an imported/managed external service's logs instead\nof a project's. `project_id` is ignored in this mode."},"levels":{"type":"array","items":{"type":"string"},"description":"Filter by log levels"},"node_ids":{"type":"array","items":{"type":"integer","format":"int32"},"description":"Filter to specific worker nodes (node_id). Empty = all nodes, including\ncontrol-plane-local logs."},"page_size":{"type":["integer","null"],"format":"int32","description":"Page size (default: 100, max: 500)","minimum":0},"project_id":{"type":"integer","format":"int32","description":"Project ID (integer, as used by the rest of the platform)"},"services":{"type":"array","items":{"type":"string"},"description":"Filter by services"},"start_time":{"type":["string","null"],"description":"Start of time range (ISO 8601). Defaults to 1 hour ago."},"text":{"type":["string","null"],"description":"Full text search query"}}},"SearchLogsResponse":{"type":"object","required":["lines","search_mode","total_scanned"],"properties":{"available_sources":{"type":"array","items":{"$ref":"#/components/schemas/LogSource"},"description":"Distinct containers/nodes/services available in the queried scope, for\nthe filter dropdowns. Populated on the first page (no cursor)."},"lines":{"type":"array","items":{"$ref":"#/components/schemas/LogSearchLine"}},"next_cursor":{"type":["string","null"]},"search_mode":{"$ref":"#/components/schemas/SearchMode"},"total_scanned":{"type":"integer","format":"int64","minimum":0}}},"SearchMode":{"type":"string","description":"Search execution mode","enum":["index","archive"]},"Seasonality":{"type":"string","description":"Seasonality model for an anomaly baseline.","enum":["none","hourly","daily","weekly"]},"SecretResponse":{"type":"object","required":["id","name","secret_type","value","created_at","updated_at"],"properties":{"created_at":{"type":"string"},"description":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"mount_path":{"type":["string","null"]},"name":{"type":"string"},"secret_type":{"type":"string"},"updated_at":{"type":"string"},"value":{"type":"string","description":"Always masked in responses"}}},"SecurityConfig":{"type":"object","description":"Security configuration for projects and environments\n\nThis configuration can be set at three levels:\n1. Global (in settings table) - applies to all projects\n2. Project level - overrides global settings for specific project\n3. Environment level - overrides project settings for specific environment\n\nThe inheritance chain: Environment > Project > Global","properties":{"attackMode":{"type":["string","null"],"description":"Attack mode configuration (future: \"off\", \"challenge\", \"block\")\nPlaceholder for DDoS protection, bot detection, etc."},"challengeConfig":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ChallengeConfig","description":"Challenge configuration (future: CAPTCHA, JS challenge, etc.)"}]},"enabled":{"type":["boolean","null"],"description":"Enable/disable security features at this level\nIf None, inherits from parent level"},"geoRestrictions":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/GeoRestrictionsConfig","description":"Geographic restrictions (future: country blocking, etc.)"}]},"headers":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SecurityHeadersConfig","description":"Security headers configuration"}]},"passwordProtection":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PasswordProtectionConfig","description":"Password protection: shows an HTML password form before allowing access"}]},"rateLimiting":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/RateLimitConfig","description":"Rate limiting configuration"}]}}},"SecurityHeadersConfig":{"type":"object","description":"Security headers configuration (subset of global SecurityHeadersSettings)","properties":{"contentSecurityPolicy":{"type":["string","null"],"description":"Custom CSP (only used if preset is \"custom\")"},"preset":{"type":["string","null"],"description":"Use a preset: \"strict\", \"moderate\", \"permissive\", \"disabled\", \"custom\""},"referrerPolicy":{"type":["string","null"],"description":"Referrer-Policy override"},"strictTransportSecurity":{"type":["string","null"],"description":"HSTS override"},"xFrameOptions":{"type":["string","null"],"description":"X-Frame-Options override"}}},"SecurityHeadersSettings":{"type":"object","properties":{"content_security_policy":{"type":["string","null"],"default":"default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self'; frame-ancestors 'self'"},"enabled":{"type":"boolean","default":false},"permissions_policy":{"type":["string","null"],"default":"geolocation=(), microphone=(), camera=()"},"preset":{"type":"string","default":"moderate"},"referrer_policy":{"type":"string","default":"strict-origin-when-cross-origin"},"strict_transport_security":{"type":"string","default":"max-age=31536000; includeSubDomains"},"x_content_type_options":{"type":"string","default":"nosniff"},"x_frame_options":{"type":"string","default":"SAMEORIGIN"},"x_xss_protection":{"type":"string","default":"1; mode=block"}}},"SelfUpdateAttempt":{"type":"object","description":"A single update attempt. Persisted to `/self-update.json` so the\nresult survives the restart it causes.","required":["from_version","status","started_at"],"properties":{"error":{"type":["string","null"],"description":"Operator-facing failure reason. Always set when `status` is `Failed`."},"finished_at":{"type":["string","null"],"format":"date-time","description":"When the outcome was decided. `None` while still `Pending`."},"from_version":{"type":"string","description":"Version the attempt started from."},"previous_binary_path":{"type":["string","null"],"description":"Where the replaced binary was kept, so a bad release can be reverted by\nhand (`mv `). Set once the swap completes."},"started_at":{"type":"string","format":"date-time","example":"2026-08-06T09:12:31Z"},"status":{"$ref":"#/components/schemas/SelfUpdateStatus"},"to_version":{"type":["string","null"],"description":"Version the attempt targeted. `None` if it failed before resolving one."},"triggered_by_user_id":{"type":["integer","null"],"format":"int32","description":"User who clicked the button. `None` for attempts started by the CLI."}}},"SelfUpdateBlocker":{"type":"string","description":"Why a one-click update is unavailable. Exactly one is reported — the most\nfundamental blocker wins, so the operator fixes the real problem first\nrather than clearing one only to hit the next.","enum":["disabled_by_flag","disabled_by_setting","container","no_supervisor","binary_not_writable","unsupported_platform","in_progress"]},"SelfUpdatePhase":{"type":"string","description":"Where an in-flight update has got to. Polled by the console so a long\ndownload shows progress instead of an indefinite spinner.","enum":["idle","resolving","downloading","verifying","installing","restarting","failed"]},"SelfUpdateSettings":{"type":"object","description":"Controls the console's one-click \"Update now\" action.","properties":{"enabled":{"type":"boolean","description":"Allow admins to apply a release and restart the server from the console.\n`true` by default: the action is permission-gated, audited, and only\never installs an official release whose published SHA-256 matches.\n\nTurning this off hides nothing — the console still shows the update\nbanner and the manual command, it just refuses to run it for you.","default":true,"example":true}}},"SelfUpdateStatus":{"type":"string","description":"Outcome of an update attempt, as persisted in the journal.","enum":["pending","succeeded","failed"]},"SendEmailRequestBody":{"type":"object","required":["from","to","subject"],"properties":{"bcc":{"type":["array","null"],"items":{"type":"string"},"description":"BCC recipients"},"cc":{"type":["array","null"],"items":{"type":"string"},"description":"CC recipients"},"from":{"type":"string","description":"Sender email address (domain will be auto-extracted for lookup)","example":"hello@updates.example.com"},"from_name":{"type":["string","null"],"description":"Sender display name","example":"My App"},"headers":{"type":["object","null"],"description":"Custom headers","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"html":{"type":["string","null"],"description":"HTML body content","example":"

Hello World

"},"reply_to":{"type":["string","null"],"description":"Reply-to address"},"subject":{"type":"string","description":"Email subject","example":"Welcome to our platform!"},"tags":{"type":["array","null"],"items":{"type":"string"},"description":"Tags for categorization","example":["welcome","onboarding"]},"text":{"type":["string","null"],"description":"Plain text body content","example":"Hello World"},"to":{"type":"array","items":{"type":"string"},"description":"Recipient email addresses","example":["user@example.com"]},"track_clicks":{"type":["boolean","null"],"description":"Enable click tracking (link rewriting). Defaults to false."},"track_opens":{"type":["boolean","null"],"description":"Enable open tracking (tracking pixel injection). Defaults to false."}}},"SendEmailResponseBody":{"type":"object","required":["id","status"],"properties":{"id":{"type":"string","description":"Email ID","example":"550e8400-e29b-41d4-a716-446655440000"},"provider_message_id":{"type":["string","null"],"description":"Provider message ID"},"status":{"type":"string","description":"Email status","example":"sent"}}},"SendMessageRequest":{"type":"object","required":["content"],"properties":{"content":{"type":"string"},"page_context":{"type":["string","null"],"description":"Optional, client-supplied description of the page/entity the user is\ncurrently viewing (e.g. a trace in a project). Injected into the model's\nview of this turn only — never stored or shown in history. Capped server\nside; oversized values are ignored rather than rejected."}}},"SensitiveConfigValueResponse":{"type":"object","required":["value"],"properties":{"value":{"type":"string"}}},"SensitiveMcpConfigValueResponse":{"type":"object","required":["value"],"properties":{"value":{"type":"string"}}},"SensitiveValueResponse":{"type":"object","required":["value"],"properties":{"value":{"type":"string"}}},"SentryChunkUploadResponse":{"type":"object","required":["url","chunkSize","chunksPerRequest","maxFileSize","maxRequestSize","concurrency","hashAlgorithm","compression","accept"],"properties":{"accept":{"type":"array","items":{"type":"string"}},"chunkSize":{"type":"integer","format":"int64","minimum":0},"chunksPerRequest":{"type":"integer","format":"int32","minimum":0},"compression":{"type":"array","items":{"type":"string"}},"concurrency":{"type":"integer","format":"int32","minimum":0},"hashAlgorithm":{"type":"string"},"maxFileSize":{"type":"integer","format":"int64","minimum":0},"maxRequestSize":{"type":"integer","format":"int64","minimum":0},"url":{"type":"string"}}},"SentryCreateReleaseRequest":{"type":"object","required":["version"],"properties":{"projects":{"type":"array","items":{"type":"string"},"description":"Project slugs this release belongs to"},"version":{"type":"string","description":"Release version identifier"}}},"SentryEventRequest":{"type":"object","properties":{"event_id":{"type":["string","null"]},"message":{"type":["string","null"]},"platform":{"type":["string","null"]},"timestamp":{"type":["string","null"]}}},"SentryEventResponse":{"type":"object","required":["id"],"properties":{"id":{"type":"string"}}},"SentryReleaseFileResponse":{"type":"object","required":["id","name","headers","size","sha1","dateCreated"],"properties":{"dateCreated":{"type":"string"},"dist":{"type":["string","null"]},"headers":{},"id":{"type":"string"},"name":{"type":"string"},"sha1":{"type":"string"},"size":{"type":"integer","format":"int64"}}},"SentryReleaseProjectRef":{"type":"object","required":["name","slug"],"properties":{"name":{"type":"string"},"slug":{"type":"string"}}},"SentryReleaseResponse":{"type":"object","required":["version","dateCreated","shortVersion","projects"],"properties":{"dateCreated":{"type":"string"},"dateReleased":{"type":["string","null"]},"projects":{"type":"array","items":{"$ref":"#/components/schemas/SentryReleaseProjectRef"}},"shortVersion":{"type":"string"},"version":{"type":"string"}}},"SeriesStateEntry":{"type":"object","description":"One series' persisted state snapshot for a dynamic rule (ADR-026 follow-up):\nthe state after the latest tick, the value evaluated this tick, and the open\nalarm id (when firing). Serialized into the `series_states` jsonb column keyed\nby the human-readable [`series_label`]; the alert response decodes it back.","required":["state","value"],"properties":{"alarm_id":{"type":["integer","null"],"format":"int32","description":"The open alarm's id when the series is firing; `null` when ok."},"state":{"type":"string","description":"`firing` or `ok` for this series after the latest tick."},"value":{"type":"number","format":"double","description":"The value the rule evaluated for this series this tick."}}},"ServiceAccessInfo":{"type":"object","description":"Response containing information about how the service is being accessed","required":["access_mode","can_create_domains"],"properties":{"access_mode":{"type":"string","description":"Mode of access: \"local\", \"direct\", \"nat\", or \"cloudflare_tunnel\""},"can_create_domains":{"type":"boolean","description":"Whether domain creation is allowed in this mode"},"domain_creation_error":{"type":["string","null"],"description":"Error message if domain creation is not allowed"},"private_ip":{"type":["string","null"],"description":"Server's private/local IP address (always returned if available)"},"public_ip":{"type":["string","null"],"description":"Server's public IP address (always returned if available)"}}},"ServiceAction":{"type":"string","description":"What to do with a service during migration","enum":["create","link-external","skip"]},"ServiceAlertRuleResponse":{"type":"object","description":"Wire representation of a monitoring alert rule.\n\nRegistered under a domain-prefixed OpenAPI schema name to avoid colliding\nwith `temps-error-tracking`'s unrelated `AlertRuleResponse` (utoipa keys\nschemas by their bare struct name, so without `as = ...` the last crate to\nregister would silently shadow this one in the merged spec / generated SDK).","required":["id","name","metric_name","threshold","comparator","severity","for_duration_secs","enabled"],"properties":{"comparator":{"type":"string"},"deployment_id":{"type":["integer","null"],"format":"int32"},"enabled":{"type":"boolean"},"for_duration_secs":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"metric_name":{"type":"string"},"name":{"type":"string"},"service_id":{"type":["integer","null"],"format":"int32"},"severity":{"type":"string"},"silenced_until":{"type":["string","null"]},"threshold":{"type":"number","format":"double"}}},"ServiceBackupEntryResponse":{"type":"object","description":"A single backup entry in the per-service backup list.","required":["id","backup_id","name","state","backup_type","started_at","s3_location","compression_type","s3_source_id","s3_source_name","external_service_backup_id"],"properties":{"backup_id":{"type":"string","description":"UUID string assigned at backup creation time."},"backup_type":{"type":"string","description":"Backup variant (e.g. \"full\", \"incremental\")."},"compression_type":{"type":"string","description":"Compression algorithm used (e.g. \"gzip\")."},"error_message":{"type":["string","null"],"description":"Engine-reported error message, populated when `state = \"failed\"`."},"external_service_backup_id":{"type":"integer","format":"int32","description":"Row ID from `external_service_backups`."},"finished_at":{"type":["string","null"],"description":"ISO 8601 timestamp when the backup finished, if known.","example":"2025-01-15T14:35:00Z"},"id":{"type":"integer","format":"int32","description":"Row ID from the `backups` table."},"name":{"type":"string","description":"Human-friendly display name."},"s3_location":{"type":"string","description":"Object key or `s3://` URL for the backup data."},"s3_source_id":{"type":"integer","format":"int32","description":"FK to `s3_sources.id`."},"s3_source_name":{"type":"string","description":"Human-readable name of the S3 source."},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Size of the backup in bytes, if available."},"started_at":{"type":"string","description":"ISO 8601 timestamp when the backup started.","example":"2025-01-15T14:30:00Z"},"state":{"type":"string","description":"Current state: \"completed\", \"running\", \"failed\"."}}},"ServiceBackupListResponse":{"type":"object","description":"Paginated list of backups for a specific external service.\n\nReturned by `GET /backups/external-services/{service_id}/backups`.","required":["backups","total","page","page_size"],"properties":{"backups":{"type":"array","items":{"$ref":"#/components/schemas/ServiceBackupEntryResponse"},"description":"Backups belonging to this service, newest first."},"page":{"type":"integer","format":"int64","description":"Current page (1-based)."},"page_size":{"type":"integer","format":"int64","description":"Number of items per page."},"total":{"type":"integer","format":"int64","description":"Total number of backups for this service across all pages."}}},"ServiceCreateAlertRuleRequest":{"type":"object","description":"Request body for creating an alert rule on an external service.\n\nDomain-prefixed schema name — see [`AlertRuleResponse`] for why.","required":["name","metric_name","threshold","comparator","severity"],"properties":{"comparator":{"type":"string","description":"One of `>`, `<`, `>=`, `<=`."},"enabled":{"type":"boolean"},"for_duration_secs":{"type":"integer","format":"int32","description":"Seconds the breach must persist before the alarm fires (0 = immediate)."},"metric_name":{"type":"string"},"name":{"type":"string"},"severity":{"type":"string","description":"`\"warning\"` or `\"critical\"`."},"threshold":{"type":"number","format":"double"}}},"ServiceHealthResponse":{"type":"object","required":["service_id","consecutive_failures","recent_checks"],"properties":{"consecutive_failures":{"type":"integer","format":"int32","description":"Consecutive failed probes. Alert fires at 3."},"last_checked_at":{"type":["string","null"]},"last_error":{"type":["string","null"]},"recent_checks":{"type":"array","items":{"$ref":"#/components/schemas/HealthCheckEntryResponse"},"description":"Most recent checks, newest-first (capped at `limit`)."},"response_time_ms":{"type":["integer","null"],"format":"int32"},"service_id":{"type":"integer","format":"int32"},"status":{"type":["string","null"],"description":"Current health. `null` if the service has not been probed yet.","example":"operational"},"uptime_24h_percent":{"type":["number","null"],"format":"double","description":"Uptime percentage over the last 24 hours (0.0 — 100.0).\n`null` when there is not enough history."}}},"ServiceHealthStatusBatchResponse":{"type":"object","required":["statuses"],"properties":{"statuses":{"type":"array","items":{"$ref":"#/components/schemas/ServiceHealthStatusEntryResponse"}}}},"ServiceHealthStatusEntryResponse":{"type":"object","required":["service_id","consecutive_failures"],"properties":{"consecutive_failures":{"type":"integer","format":"int32"},"last_checked_at":{"type":["string","null"]},"service_id":{"type":"integer","format":"int32"},"status":{"type":["string","null"],"description":"\"operational\" | \"degraded\" | \"down\". `null` when the service has not\nbeen probed yet.","example":"operational"}}},"ServiceMemberInfo":{"type":"object","description":"Public info about a cluster member.","required":["id","role","container_name","status","ordinal"],"properties":{"compute_ip":{"type":["string","null"],"description":"Container's IP on the `temps-overlay` multi-host network. Populated\nby the lifecycle hook (ADR-011 Phase 3); `None` on single-host\nclusters where the overlay isn't attached."},"container_name":{"type":"string"},"hostname":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"live_state":{"type":["string","null"],"description":"Live FSM state from the pg_auto_failover monitor (`primary`,\n`secondary`, `catchingup`, `report_lsn`, …). `None` when the\nmonitor is unreachable, the service is not a cluster, or the row\nis the monitor itself.\n\n**The UI must render the role badge from this field**, falling\nback to `role` only when `live_state` is null. `role` is now\nconfig-only (`monitor` or `replica`); flipping the badge to\n\"primary\" when the monitor elects a new one used to require a\nreconciler that lagged ~5s behind real failovers — and during\nthat window the UI showed two primaries. `live_state` is read\ndirectly from the monitor on every list, so it can never lag."},"node_id":{"type":["integer","null"],"format":"int32"},"ordinal":{"type":"integer","format":"int32"},"port":{"type":["integer","null"],"format":"int32"},"provisioning_error":{"type":["string","null"],"description":"Most recent provisioning failure message, when `status='failed'`.\nSet by the background task so the UI can show *why* the new\nreplica didn't come up."},"provisioning_step":{"type":["string","null"],"description":"Last-attempted phase of the async `add_cluster_member` background\ntask (e.g. `validating`, `provisioning_container`, `done`,\n`failed`). `None` for members not created through that flow —\nthe UI falls back to the `status` column for those."},"role":{"type":"string"},"status":{"type":"string"}}},"ServiceParameter":{"type":"object","required":["name","required","encrypted","description"],"properties":{"choices":{"type":["array","null"],"items":{"type":"string"}},"default_value":{"type":["string","null"]},"description":{"type":"string"},"encrypted":{"type":"boolean"},"name":{"type":"string"},"required":{"type":"boolean"},"validation_pattern":{"type":["string","null"]}}},"ServicePlan":{"type":"object","description":"Plan for migrating a single service (database, cache, etc.)","required":["name","service_type","action","action_description"],"properties":{"action":{"$ref":"#/components/schemas/ServiceAction","description":"What to do with this service"},"action_description":{"type":"string","description":"Human-readable explanation of what this action means"},"data_implications":{"type":"array","items":{"$ref":"#/components/schemas/DataImplication"},"description":"Data implications specific to this service"},"env_var_mappings":{"type":"object","description":"Environment variable key mappings: source_key -> temps_key\n\nFor example, Vercel's `POSTGRES_URL` might map to Temps' `DATABASE_URL`.\nBoth keys will be set during migration so the app works with either.","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"name":{"type":"string","description":"Human-readable service name"},"parameters":{"type":"object","description":"Parameters for creating the service in Temps","additionalProperties":{},"propertyNames":{"type":"string"}},"service_type":{"type":"string","description":"Service type (maps to temps-providers ServiceType)"},"version":{"type":["string","null"],"description":"Service version to create (e.g., \"16\" for Postgres 16)"}}},"ServiceResourceLimits":{"type":"object","description":"Optional cgroup resource limits applied to a service container.\n\nAll fields are `Option`: `None` means \"no limit\" (the kernel default),\nmatching Docker's behavior when the corresponding `HostConfig` field is\nleft at zero. Operators opt in to limits explicitly through the\n`PATCH /external-services/{id}/resources` endpoint or by writing the\n`resources` block into `ServiceConfig::parameters` at create time.\n\nThese map directly onto bollard fields:\n- `memory_mb` → `HostConfig.memory` (bytes)\n- `memory_swap_mb`→ `HostConfig.memory_swap` (bytes; ≥ memory)\n- `nano_cpus` → `HostConfig.nano_cpus` (1e9 = 1 full CPU)\n- `cpu_shares` → `HostConfig.cpu_shares` (relative weight, default 1024)\n- `shm_size_mb` → `HostConfig.shm_size` (bytes; default 64 MiB)\n\nIMPORTANT: enabling hard memory limits causes the kernel OOM killer to\nterminate the container when the working set exceeds the limit. The\ncontainer will restart (RestartPolicy::ALWAYS) but in-flight queries\nfail. Surface this clearly in any UI that lets users set limits.","properties":{"cpu_shares":{"type":["integer","null"],"format":"int64","description":"Relative CPU weight (default 1024). Only used when `nano_cpus` is None."},"memory_mb":{"type":["integer","null"],"format":"int64","description":"Hard memory limit in MiB. None = unlimited."},"memory_swap_mb":{"type":["integer","null"],"format":"int64","description":"Memory + swap limit in MiB. None = unlimited.\nMUST be >= memory_mb when both are set; Docker rejects the request otherwise.\nSet equal to `memory_mb` to disable swap entirely."},"nano_cpus":{"type":["integer","null"],"format":"int64","description":"CPU quota in nano-cpus. 1_000_000_000 = 1 full CPU core. None = unlimited."},"shm_size_mb":{"type":["integer","null"],"format":"int64","description":"Shared memory (/dev/shm) size in MiB. None = Docker default (64 MiB).\nMaps to HostConfig.shm_size (bytes). PostgreSQL uses /dev/shm for parallel\nquery workers and large work_mem; the 64 MiB default causes \"could not\nresize shared memory segment ... No space left on device\" under load.\nNOTE: shm_size is fixed at container-create time — Docker's live update\nAPI cannot change it, so changing this value recreates the container."}}},"ServiceRuntimeReport":{"type":"object","description":"Aggregate runtime info for an external service. For standalone services,\n`members` has exactly one entry. For clusters, one entry per member.","required":["service_id","topology","members"],"properties":{"members":{"type":"array","items":{"$ref":"#/components/schemas/ContainerRuntimeInfo"}},"service_id":{"type":"integer","format":"int32"},"topology":{"type":"string"}}},"ServiceStatsReport":{"type":"object","required":["service_id","topology","members"],"properties":{"members":{"type":"array","items":{"$ref":"#/components/schemas/ContainerStatsSample"}},"service_id":{"type":"integer","format":"int32"},"topology":{"type":"string"}}},"ServiceTypeInfo":{"type":"object","required":["service_type","parameters"],"properties":{"parameters":{"type":"array","items":{"$ref":"#/components/schemas/ServiceParameter"},"example":"[{\"name\": \"host\", \"required\": true, \"encrypted\": false, \"description\": \"Database host\"}]"},"service_type":{"$ref":"#/components/schemas/ServiceTypeRoute"}}},"ServiceTypeRoute":{"type":"string","enum":["mariadb","mongodb","postgres","redis","s3","kv","blob","rustfs","minio"]},"ServiceUpdateAlertRuleRequest":{"type":"object","description":"Request body for updating an existing alert rule.\n\nDomain-prefixed schema name — see [`AlertRuleResponse`] for why.","properties":{"comparator":{"type":["string","null"]},"enabled":{"type":["boolean","null"]},"for_duration_secs":{"type":["integer","null"],"format":"int32"},"metric_name":{"type":["string","null"]},"name":{"type":["string","null"]},"severity":{"type":["string","null"]},"threshold":{"type":["number","null"],"format":"double"}}},"SesCredentialsRequest":{"type":"object","required":["access_key_id","secret_access_key"],"properties":{"access_key_id":{"type":"string","example":"AKIAIOSFODNN7EXAMPLE"},"secret_access_key":{"type":"string","example":"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"}}},"SessionDetails":{"type":"object","required":["session_id","visitor_id","started_at","duration_seconds","is_bounced","is_engaged","page_views"],"properties":{"duration_seconds":{"type":"integer","format":"int64"},"ended_at":{"type":["string","null"],"format":"date-time","example":"2024-01-01T00:00:00"},"entry_path":{"type":["string","null"]},"exit_path":{"type":["string","null"]},"is_bounced":{"type":"boolean"},"is_engaged":{"type":"boolean"},"page_views":{"type":"integer","format":"int64"},"referrer":{"type":["string","null"]},"session_id":{"type":"integer","format":"int32"},"started_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"visitor_id":{"type":"string"}}},"SessionDetailsQuery":{"type":"object","required":["project_id"],"properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"}}},"SessionEvent":{"type":"object","required":["id","timestamp"],"properties":{"event_data":{},"event_name":{"type":["string","null"]},"event_type":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"page_title":{"type":["string","null"]},"page_url":{"type":["string","null"]},"timestamp":{"type":"string"}}},"SessionEventDto":{"type":"object","required":["id","session_id","data","timestamp"],"properties":{"data":{},"event_type":{"type":["integer","null"],"format":"int32"},"id":{"type":"integer","format":"int32"},"session_id":{"type":"integer","format":"int32"},"timestamp":{"type":"integer","format":"int64"}}},"SessionEventsQuery":{"type":"object","required":["project_id"],"properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"}}},"SessionEventsResponse":{"type":"object","required":["session_id","events","total_count","offset","limit"],"properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/SessionEvent"}},"limit":{"type":"integer","format":"int32"},"offset":{"type":"integer","format":"int32"},"session_id":{"type":"integer","format":"int32"},"total_count":{"type":"integer","format":"int64"}}},"SessionLogsQuery":{"type":"object","required":["project_id"],"properties":{"end_date":{"type":["string","null"],"format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32"},"offset":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"sort_order":{"type":["string","null"]},"start_date":{"type":["string","null"],"format":"date-time"},"visitor_id":{"type":["integer","null"],"format":"int32"}}},"SessionLogsResponse":{"type":"object","required":["session_id","logs","total_count","offset","limit"],"properties":{"limit":{"type":"integer","format":"int32"},"logs":{"type":"array","items":{"$ref":"#/components/schemas/SessionRequestLog"}},"offset":{"type":"integer","format":"int32"},"session_id":{"type":"integer","format":"int32"},"total_count":{"type":"integer","format":"int64"}}},"SessionReplayEventsRequest":{"type":"object","required":["sessionId","events"],"properties":{"events":{"type":"string"},"sessionId":{"type":"string"}}},"SessionReplayInfoDto":{"type":"object","required":["id","visitor_id"],"properties":{"created_at":{"type":["string","null"]},"duration":{"type":["integer","null"],"format":"int32"},"id":{"type":"string"},"language":{"type":["string","null"]},"screen_height":{"type":["integer","null"],"format":"int32"},"screen_width":{"type":["integer","null"],"format":"int32"},"timezone":{"type":["string","null"]},"url":{"type":["string","null"]},"user_agent":{"type":["string","null"]},"viewport_height":{"type":["integer","null"],"format":"int32"},"viewport_width":{"type":["integer","null"],"format":"int32"},"visitor_id":{"type":"integer","format":"int32"}}},"SessionReplayInitRequest":{"type":"object","required":["sessionId"],"properties":{"colorDepth":{"type":["integer","null"],"format":"int32","minimum":0},"language":{"type":["string","null"]},"screenHeight":{"type":["integer","null"],"format":"int32","minimum":0},"screenWidth":{"type":["integer","null"],"format":"int32","minimum":0},"sessionId":{"type":"string"},"timestamp":{"type":["string","null"]},"timezone":{"type":["string","null"]},"url":{"type":["string","null"]},"userAgent":{"type":["string","null"]},"viewportHeight":{"type":["integer","null"],"format":"int32","minimum":0},"viewportWidth":{"type":["integer","null"],"format":"int32","minimum":0}}},"SessionReplayInitResponse":{"type":"object","required":["session_id","message"],"properties":{"message":{"type":"string"},"session_id":{"type":"string"}}},"SessionReplayWithEventsDto":{"type":"object","required":["session","events"],"properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/SessionEventDto"}},"session":{"$ref":"#/components/schemas/SessionReplayWithVisitorDto"}}},"SessionReplayWithVisitorDto":{"type":"object","required":["id","session_replay_id","visitor_id","visitor_uuid","visitor_project_id","visitor_environment_id","visitor_first_seen","visitor_last_seen","visitor_is_crawler"],"properties":{"browser":{"type":["string","null"]},"browser_version":{"type":["string","null"]},"created_at":{"type":["string","null"]},"device_type":{"type":["string","null"]},"duration":{"type":["integer","null"],"format":"int32"},"id":{"type":"integer","format":"int32"},"language":{"type":["string","null"]},"operating_system":{"type":["string","null"]},"operating_system_version":{"type":["string","null"]},"screen_height":{"type":["integer","null"],"format":"int32"},"screen_width":{"type":["integer","null"],"format":"int32"},"session_replay_id":{"type":"string"},"timezone":{"type":["string","null"]},"url":{"type":["string","null"]},"user_agent":{"type":["string","null"]},"viewport_height":{"type":["integer","null"],"format":"int32"},"viewport_width":{"type":["integer","null"],"format":"int32"},"visitor_city":{"type":["string","null"]},"visitor_country":{"type":["string","null"]},"visitor_country_code":{"type":["string","null"]},"visitor_crawler_name":{"type":["string","null"]},"visitor_custom_data":{},"visitor_environment_id":{"type":"integer","format":"int32"},"visitor_first_seen":{"type":"string"},"visitor_id":{"type":"integer","format":"int32"},"visitor_is_crawler":{"type":"boolean"},"visitor_last_seen":{"type":"string"},"visitor_project_id":{"type":"integer","format":"int32"},"visitor_region":{"type":["string","null"]},"visitor_uuid":{"type":"string"}}},"SessionRequestLog":{"type":"object","required":["id","method","path","status_code","created_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"id":{"type":"integer","format":"int32"},"method":{"type":"string"},"path":{"type":"string"},"referrer":{"type":["string","null"]},"request_headers":{"type":["string","null"]},"response_headers":{"type":["string","null"]},"response_time_ms":{"type":["integer","null"],"format":"int32"},"status_code":{"type":"integer","format":"int32"},"user_agent":{"type":["string","null"]}}},"SessionSummary":{"type":"object","required":["session_id","started_at","duration_seconds","page_views","events_count","requests_count","is_bounced","is_engaged"],"properties":{"duration_seconds":{"type":"integer","format":"int64"},"ended_at":{"type":["string","null"],"format":"date-time","example":"2024-01-01T00:00:00"},"entry_path":{"type":["string","null"]},"events_count":{"type":"integer","format":"int64"},"exit_path":{"type":["string","null"]},"is_bounced":{"type":"boolean"},"is_engaged":{"type":"boolean"},"page_views":{"type":"integer","format":"int64"},"referrer":{"type":["string","null"]},"requests_count":{"type":"integer","format":"int64"},"session_id":{"type":"integer","format":"int32"},"started_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"}}},"SetFlagEnvironmentRequest":{"type":"object","properties":{"enabled":{"type":["boolean","null"],"description":"The kill switch. `false` makes the flag serve its default regardless of\nany override — and, once targeting exists, regardless of any rule."},"value":{"description":"Tri-state: absent leaves the override, `null` clears it (inherit the\nflag default), anything else sets it. Must match `value_type`."}}},"SetPreviewPasswordBody":{"type":"object","required":["password"],"properties":{"password":{"type":"string","description":"Plaintext password to protect the sandbox's preview URLs. Hashed\nserver-side with argon2id — we never persist or echo this back.\nMust be between 8 and 256 characters."}}},"SetPreviewPasswordResponse":{"type":"object","required":["preview_password_hint"],"properties":{"preview_password_hint":{"type":"string","description":"Last 4 chars of the password we just stored. Surface in the UI so\nusers can confirm which password is live without re-entering it."}}},"SetRequest":{"type":"object","description":"Request to set a value","required":["key","value"],"properties":{"ex":{"type":["integer","null"],"format":"int64","description":"Expire in seconds","example":3600},"key":{"type":"string","description":"The key to set","example":"user:123"},"nx":{"type":"boolean","description":"Only set if key does not exist"},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1},"px":{"type":["integer","null"],"format":"int64","description":"Expire in milliseconds"},"value":{"description":"The value to store (can be any JSON value)"},"xx":{"type":"boolean","description":"Only set if key exists"}}},"SetResponse":{"type":"object","description":"Response for set operation","required":["result"],"properties":{"result":{"type":"string","description":"Always \"OK\" on success","example":"OK"}}},"SettingsUpdateResponse":{"type":"object","description":"Response for successful settings update","required":["message"],"properties":{"message":{"type":"string"}}},"SetupDnsChallengeRequest":{"type":"object","description":"Request to setup DNS challenge records using a configured DNS provider","required":["dns_provider_id"],"properties":{"dns_provider_id":{"type":"integer","format":"int32","description":"The ID of the DNS provider to use for creating the TXT records"}}},"SetupDnsChallengeResponse":{"type":"object","description":"Response from DNS challenge setup operation","required":["success","records_created","total_records","results","message"],"properties":{"message":{"type":"string","description":"Human-readable summary message"},"records_created":{"type":"integer","format":"int32","description":"Number of TXT records that were successfully created","minimum":0},"results":{"type":"array","items":{"$ref":"#/components/schemas/DnsChallengeRecordResult"},"description":"Results for each individual TXT record"},"success":{"type":"boolean","description":"Overall success status (true if all records were created)"},"total_records":{"type":"integer","format":"int32","description":"Total number of TXT records required for the challenge","minimum":0}}},"SetupDnsRequest":{"type":"object","description":"Request to setup DNS records using a configured DNS provider","required":["dns_provider_id"],"properties":{"dns_provider_id":{"type":"integer","format":"int32","description":"The ID of the DNS provider to use for creating records"}}},"SetupDnsResponse":{"type":"object","description":"Response from DNS setup operation","required":["success","records_created","total_records","results","message"],"properties":{"message":{"type":"string","description":"Human-readable summary message"},"records_created":{"type":"integer","format":"int32","description":"Number of records that were successfully created","minimum":0},"results":{"type":"array","items":{"$ref":"#/components/schemas/DnsRecordSetupResult"},"description":"Results for each individual record"},"success":{"type":"boolean","description":"Overall success status"},"total_records":{"type":"integer","format":"int32","description":"Total number of records attempted","minimum":0}}},"SiblingRef":{"type":"object","description":"A sibling project that shares the same `trace_id` and has opted in to\ncross-project trace sharing (`cross_project_trace_sharing = TRUE`).\n\nReturned by `CrossProjectTraceService::find_sibling_projects` and exposed\nby the Phase 1 `GET /otel/traces/cross-project/{trace_id}` endpoint.","required":["project_id","project_name","project_slug","first_seen"],"properties":{"first_seen":{"type":"string","format":"date-time"},"project_id":{"type":"integer","format":"int32"},"project_name":{"type":"string"},"project_slug":{"type":"string","description":"URL slug used to link into the sibling project's single-project trace view."}}},"SkillDefinitionResponse":{"type":"object","required":["id","slug","name","content","has_archive","created_at","updated_at"],"properties":{"content":{"type":"string"},"created_at":{"type":"string"},"description":{"type":["string","null"]},"has_archive":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"project_id":{"type":["integer","null"],"format":"int32"},"slug":{"type":"string"},"updated_at":{"type":"string"}}},"SlackConfig":{"type":"object","required":["webhook_url"],"properties":{"channel":{"type":["string","null"]},"webhook_url":{"type":"string"}}},"SlowQueriesResponse":{"type":"object","description":"Response envelope for the slow-queries list endpoint.","required":["queries","page","page_size","total_count"],"properties":{"page":{"type":"integer","format":"int32","description":"Current page number (1-based).","minimum":0},"page_size":{"type":"integer","format":"int32","description":"Number of rows per page used for this request.","minimum":0},"queries":{"type":"array","items":{"$ref":"#/components/schemas/SlowQueryRow"},"description":"Ordered list of query stats, slowest first by mean_exec_time_ms."},"total_count":{"type":"integer","format":"int64","description":"Total number of qualifying rows across all pages.","minimum":0}}},"SlowQueryRow":{"type":"object","description":"A single entry from `pg_stat_statements`, representing one normalized\nquery fingerprint and its aggregate execution stats.","required":["query","database","calls","total_exec_time_ms","mean_exec_time_ms","rows"],"properties":{"cache_hit_ratio":{"type":["number","null"],"format":"double","description":"Shared block cache hit ratio (0.0–1.0).\n`None` when total block accesses are zero (e.g. function-only queries)."},"calls":{"type":"integer","format":"int64","description":"Number of times this query was executed."},"database":{"type":"string","description":"Name of the database this query ran against. `(dropped database)`\nwhen the originating database no longer exists but\n`pg_stat_statements` still holds stats for it."},"mean_exec_time_ms":{"type":"number","format":"double","description":"Average wall-clock time per execution, in milliseconds."},"query":{"type":"string","description":"Normalized query text (parameter literals replaced with `$N`)."},"rows":{"type":"integer","format":"int64","description":"Total number of rows returned or affected."},"total_exec_time_ms":{"type":"number","format":"double","description":"Total wall-clock time spent executing this query, in milliseconds."}}},"SmartFilter":{"oneOf":[{"type":"object","description":"Match specific page path","required":["value","type"],"properties":{"type":{"type":"string","enum":["page_path"]},"value":{"type":"string","description":"Match specific page path"}}},{"type":"object","description":"Match specific hostname","required":["value","type"],"properties":{"type":{"type":"string","enum":["hostname"]},"value":{"type":"string","description":"Match specific hostname"}}},{"type":"object","description":"Match UTM source","required":["value","type"],"properties":{"type":{"type":"string","enum":["utm_source"]},"value":{"type":"string","description":"Match UTM source"}}},{"type":"object","description":"Match UTM campaign","required":["value","type"],"properties":{"type":{"type":"string","enum":["utm_campaign"]},"value":{"type":"string","description":"Match UTM campaign"}}},{"type":"object","description":"Match UTM medium","required":["value","type"],"properties":{"type":{"type":"string","enum":["utm_medium"]},"value":{"type":"string","description":"Match UTM medium"}}},{"type":"object","description":"Match referrer hostname","required":["value","type"],"properties":{"type":{"type":"string","enum":["referrer_hostname"]},"value":{"type":"string","description":"Match referrer hostname"}}},{"type":"object","description":"Match specific channel (organic, paid, direct, referral, etc.)","required":["value","type"],"properties":{"type":{"type":"string","enum":["channel"]},"value":{"type":"string","description":"Match specific channel (organic, paid, direct, referral, etc.)"}}},{"type":"object","description":"Match device type (mobile, desktop, tablet)","required":["value","type"],"properties":{"type":{"type":"string","enum":["device_type"]},"value":{"type":"string","description":"Match device type (mobile, desktop, tablet)"}}},{"type":"object","description":"Match browser","required":["value","type"],"properties":{"type":{"type":"string","enum":["browser"]},"value":{"type":"string","description":"Match browser"}}},{"type":"object","description":"Match operating system","required":["value","type"],"properties":{"type":{"type":"string","enum":["operating_system"]},"value":{"type":"string","description":"Match operating system"}}},{"type":"object","description":"Match language","required":["value","type"],"properties":{"type":{"type":"string","enum":["language"]},"value":{"type":"string","description":"Match language"}}},{"type":"object","description":"Match custom event_data by JSON path\nFormat: {\"path\": \"user.plan\", \"value\": \"premium\"}\nThis will match events where event_data->'user'->>'plan' = 'premium'","required":["value","type"],"properties":{"type":{"type":"string","enum":["custom_data"]},"value":{"type":"object","description":"Match custom event_data by JSON path\nFormat: {\"path\": \"user.plan\", \"value\": \"premium\"}\nThis will match events where event_data->'user'->>'plan' = 'premium'","required":["path","value"],"properties":{"path":{"type":"string"},"value":{"type":"string"}}}}}],"description":"Smart filter presets for common funnel patterns"},"SmokeTestResponse":{"type":"object","required":["passed","environment","cli_installed","cli_authenticated"],"properties":{"auth_info":{"type":["string","null"],"description":"Auth email / method"},"cli_authenticated":{"type":"boolean","description":"Claude CLI authenticated?"},"cli_installed":{"type":"boolean","description":"Claude CLI installed?"},"cli_version":{"type":["string","null"],"description":"Claude CLI version"},"detail":{"type":["string","null"],"description":"Full output for debugging"},"environment":{"type":"string","description":"Where the test ran: \"host\" or \"sandbox\""},"passed":{"type":"boolean","description":"Whether the smoke test passed"},"setup_hint":{"type":["string","null"],"description":"What the user needs to do if the test failed"}}},"SmtpCredentialsRequest":{"type":"object","description":"Generic SMTP credentials request body.\n\nWorks with any SMTP relay — AWS SES SMTP endpoints, Sendgrid, Mailgun,\nPostmark, or a self-hosted Postfix. Use this when you only have SMTP\ncredentials (i.e. you cannot create identities via the upstream API).","required":["host","port"],"properties":{"accept_invalid_certs":{"type":"boolean","description":"Accept self-signed certificates. Only safe for local testing."},"encryption":{"$ref":"#/components/schemas/SmtpEncryptionRoute","description":"TLS mode. Defaults to STARTTLS."},"host":{"type":"string","description":"SMTP host, e.g. `email-smtp.eu-west-1.amazonaws.com`.","example":"email-smtp.eu-west-1.amazonaws.com"},"password":{"type":["string","null"],"description":"SMTP password / API token. Required when `username` is set."},"port":{"type":"integer","format":"int32","description":"SMTP port (587 for STARTTLS, 465 for implicit TLS, 25/1025 for plain).","example":587,"minimum":0},"username":{"type":["string","null"],"description":"SMTP username. Leave empty for unauthenticated relays.","example":"AKIAIOSFODNN7EXAMPLE"}}},"SmtpEncryptionRoute":{"type":"string","description":"TLS mode for the SMTP relay.","enum":["starttls","tls","none"]},"SmtpResult":{"type":"object","description":"SMTP validation result","required":["can_connect_smtp","has_full_inbox","is_catch_all","is_deliverable","is_disabled"],"properties":{"can_connect_smtp":{"type":"boolean","description":"Whether we could connect to the SMTP server"},"error":{"type":["string","null"],"description":"Error message if SMTP check failed"},"has_full_inbox":{"type":"boolean","description":"Whether the mailbox appears to have a full inbox"},"is_catch_all":{"type":"boolean","description":"Whether this is a catch-all domain"},"is_deliverable":{"type":"boolean","description":"Whether the email is deliverable"},"is_disabled":{"type":"boolean","description":"Whether the mailbox is disabled"}}},"SourceArchiveUpload":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary"}}},"SourceBackupEntry":{"type":"object","description":"Entry in the source backup index. Covers both DB-tracked backups\n(have a row in `backups`) and S3-scan discoveries (raw S3 objects with\nno DB row — used for disaster-recovery from another Temps instance).","required":["id","backup_id","name","backup_type","created_at","location","metadata_location","source","state"],"properties":{"backup_id":{"type":"string","description":"UUID identifier from the DB row. Empty for S3-scan entries.","example":"550e8400-e29b-41d4-a716-446655440000"},"backup_type":{"type":"string","description":"Backup variant as recorded by the backup pipeline (e.g. \"full\").","example":"full"},"created_at":{"type":"string","description":"When the backup was created. For S3-scan entries this is the\nobject's LastModified time.","example":"2024-01-15T14:30:00.123Z"},"engine":{"type":["string","null"],"description":"Engine that produced the backup (\"postgres\", \"redis\", \"mongodb\",\n\"s3\", \"rustfs\"). Used by the UI to mark engine-compat with the\ntarget service.","example":"postgres"},"format":{"type":["string","null"],"description":"Storage format: \"walg\" for continuous-archive (PITR-capable),\n\"pg_dump\" for point-in-time dumps, \"\" for non-postgres.","example":"walg"},"id":{"type":"integer","format":"int32","description":"DB row id. Zero for S3-scan entries that have no DB row.","example":1},"location":{"type":"string","description":"Raw S3 URL / key where the backup sits. For Postgres WAL-G backups\nthis starts with `s3://`; for pg_dump-style backups it's the\nrelative object key.","example":"s3://bucket/external_services/postgres/svc-name/walg"},"metadata_location":{"type":"string","description":"Sidecar metadata.json location, if any. Empty when none.","example":""},"name":{"type":"string","description":"Human-friendly display name (\"postgres backup (svc-name)\" for DB\nrows, or a synthesized label derived from the S3 path for scans).","example":"postgres backup (postgres-n4ea)"},"origin_service_name":{"type":["string","null"],"description":"Name of the service that produced the backup. For S3-scan entries\nthis is parsed from the S3 path.","example":"postgres-n4ea"},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Size of the backup in bytes, if known.","example":1024000},"source":{"type":"string","description":"Provenance: \"db\" for rows in this Temps, \"s3_scan\" for objects\ndiscovered by the S3 bucket walk (e.g., backups made by another\nTemps instance).","example":"db"},"state":{"type":"string","description":"Observed state (\"completed\", \"running\", \"failed\") — DB only.\nEmpty string for S3-scan entries.","example":"completed"}}},"SourceBackupIndexResponse":{"type":"object","description":"Response type for source backup index","required":["backups","last_updated"],"properties":{"backups":{"type":"array","items":{"$ref":"#/components/schemas/SourceBackupEntry"},"description":"List of backups in the source"},"last_updated":{"type":"string","description":"When the index was last updated","example":"2024-01-15T14:30:00.123Z"}}},"SourceBody":{"oneOf":[{"type":"object","required":["url","type"],"properties":{"depth":{"type":["integer","null"],"format":"int32","minimum":0},"git_connection_id":{"type":["integer","null"],"format":"int32"},"password":{"type":["string","null"]},"revision":{"type":["string","null"]},"type":{"type":"string","enum":["git"]},"url":{"type":"string"},"username":{"type":["string","null"]}}},{"type":"object","required":["url","type"],"properties":{"type":{"type":"string","enum":["tarball"]},"url":{"type":"string"}}}],"description":"Initial content to seed into the sandbox work dir. Mirrors the\n`@vercel/sandbox` `source` option. `type` is one of:\n- `git` — clone `url`; optionally check out `revision`\n- `tarball` — download `url` (must be tar or tar.gz) and extract\n\nFor private git repos, pass credentials one of two ways:\n1. **Inline (SDK-compatible):** `username` + `password`. GitHub\n tokens use `username: \"x-access-token\"`.\n2. **Stored connection (temps-native):** `git_connection_id`\n references a row in the caller's git provider connections. Temps\n resolves the token server-side and injects it safely.\n\n`git_connection_id` is mutually exclusive with `username`/`password`."},"SourceFileListResponse":{"type":"object","required":["source_files","total"],"properties":{"source_files":{"type":"array","items":{"$ref":"#/components/schemas/SourceFileResponse"}},"total":{"type":"integer","minimum":0}}},"SourceFileResponse":{"type":"object","required":["id","project_id","release","file_path","size_bytes","created_at"],"properties":{"checksum":{"type":["string","null"]},"created_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"file_path":{"type":"string"},"id":{"type":"integer","format":"int32"},"project_id":{"type":"integer","format":"int32"},"release":{"type":"string"},"size_bytes":{"type":"integer","format":"int64"}}},"SourceMapListResponse":{"type":"object","required":["source_maps","total"],"properties":{"source_maps":{"type":"array","items":{"$ref":"#/components/schemas/SourceMapResponse"}},"total":{"type":"integer","minimum":0}}},"SourceMapResponse":{"type":"object","required":["id","project_id","release","file_path","size_bytes","created_at"],"properties":{"checksum":{"type":["string","null"]},"created_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"dist":{"type":["string","null"]},"file_path":{"type":"string"},"id":{"type":"integer","format":"int32"},"project_id":{"type":"integer","format":"int32"},"release":{"type":"string"},"size_bytes":{"type":"integer","format":"int64"}}},"SourceType":{"type":"string","description":"Source type for project deployments\n\nDetermines where the deployment artifacts come from:\n- `Git`: Source code from a Git repository (traditional flow)\n- `DockerImage`: Pre-built Docker image from external registry\n- `StaticFiles`: Pre-built static files uploaded as a bundle\n- `UploadedSource`: Source archive uploaded without a Git repository\n- `Manual`: Flexible type that accepts any deployment method","enum":["git","docker_image","static_files","uploaded_source","manual"]},"SpanEvent":{"type":"object","description":"A span event (log-like annotation on a span).","required":["timestamp","name","attributes"],"properties":{"attributes":{"type":"object","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"name":{"type":"string"},"timestamp":{"type":"string","format":"date-time"}}},"SpanKind":{"type":"string","description":"Span kind.","enum":["UNSPECIFIED","INTERNAL","SERVER","CLIENT","PRODUCER","CONSUMER"]},"SpanRecord":{"type":"object","description":"A single trace span ready for storage.","required":["project_id","resource","trace_id","span_id","name","kind","start_time","end_time","duration_ms","status_code","status_message","attributes","events"],"properties":{"attributes":{"type":"object","description":"Raw key/value pairs exactly as reported by the instrumenting library.\nNumeric values are NOT guaranteed to share `duration_ms`'s unit — they\nmay be seconds, milliseconds, microseconds, or nanoseconds depending on\nthe exporter's own convention, and the unit is not labeled here.","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"deployment_id":{"type":["integer","null"],"format":"int32"},"duration_ms":{"type":"number","format":"double","description":"Span duration in milliseconds. The only field on this struct guaranteed\nto be in milliseconds."},"end_time":{"type":"string","format":"date-time"},"events":{"type":"array","items":{"$ref":"#/components/schemas/SpanEvent"}},"kind":{"$ref":"#/components/schemas/SpanKind"},"name":{"type":"string"},"parent_span_id":{"type":["string","null"]},"project_id":{"type":"integer","format":"int32"},"resource":{"$ref":"#/components/schemas/ResourceInfo"},"span_id":{"type":"string"},"start_time":{"type":"string","format":"date-time"},"status_code":{"$ref":"#/components/schemas/SpanStatusCode"},"status_message":{"type":"string"},"trace_id":{"type":"string"}}},"SpanRow":{"type":"object","required":["id","ts","trace_id","span_id","service","operation","attributes","attributes_truncated"],"properties":{"attributes":{},"attributes_truncated":{"type":"boolean"},"deployment_id":{"type":["integer","null"],"format":"int32"},"duration_ms":{"type":["number","null"],"format":"double"},"environment_id":{"type":["integer","null"],"format":"int32"},"id":{"type":"string"},"operation":{"type":"string"},"parent_span_id":{"type":["string","null"]},"service":{"type":"string"},"span_id":{"type":"string"},"status":{"type":["string","null"]},"trace_id":{"type":"string"},"ts":{"type":"string","format":"date-time"}}},"SpanStatusCode":{"type":"string","description":"Span status code.","enum":["UNSET","OK","ERROR"]},"SpeedMetricsPayload":{"type":"object","description":"Speed metrics payload for recording web vitals","properties":{"cls":{"type":["number","null"],"format":"float","description":"Cumulative Layout Shift (score)"},"fcp":{"type":["number","null"],"format":"float","description":"First Contentful Paint (milliseconds)"},"fid":{"type":["number","null"],"format":"float","description":"First Input Delay (milliseconds)"},"inp":{"type":["number","null"],"format":"float","description":"Interaction to Next Paint (milliseconds)"},"language":{"type":["string","null"],"description":"Browser language"},"lcp":{"type":["number","null"],"format":"float","description":"Largest Contentful Paint (milliseconds)"},"pathname":{"type":["string","null"],"description":"Page pathname"},"query":{"type":["string","null"],"description":"Query string"},"screenHeight":{"type":["integer","null"],"format":"int32","description":"Screen height in pixels"},"screenWidth":{"type":["integer","null"],"format":"int32","description":"Screen width in pixels"},"ttfb":{"type":["number","null"],"format":"float","description":"Time to First Byte (milliseconds)"},"viewportHeight":{"type":["integer","null"],"format":"int32","description":"Viewport height in pixels"},"viewportWidth":{"type":["integer","null"],"format":"int32","description":"Viewport width in pixels"}}},"SpeedSegmentFilters":{"type":"object","description":"Optional segment filters for the performance read endpoints, mirroring\nanalytics' `VisitorSegmentFilters`. Each filter narrows results to samples\nmatching the dimension value, so metrics can be scoped to e.g. one page,\none browser, or one country. Geographic filters resolve via\n`ip_geolocations`; the rest live directly on `performance_metrics`.","properties":{"filter_browser":{"type":["string","null"],"description":"Browser name (matches `performance_metrics.browser`)"},"filter_city":{"type":["string","null"],"description":"Geolocation city (matches `ip_geolocations.city`)"},"filter_country":{"type":["string","null"],"description":"Geolocation country (matches `ip_geolocations.country`)"},"filter_operating_system":{"type":["string","null"],"description":"Operating system (matches `performance_metrics.operating_system`)"},"filter_path":{"type":["string","null"],"description":"Page pathname (matches `performance_metrics.pathname`)"},"filter_region":{"type":["string","null"],"description":"Geolocation region (matches `ip_geolocations.region`)"}}},"StaleSlot":{"type":"object","required":["slot_name","active","retained_bytes"],"properties":{"active":{"type":"boolean"},"retained_bytes":{"type":"integer","format":"int64"},"slot_name":{"type":"string"}}},"StartAnalysisRequest":{"type":"object","required":["error_group_id"],"properties":{"branch":{"type":["string","null"],"description":"Branch to clone instead of the project's main branch."},"error_group_id":{"type":"integer","format":"int32"},"max_turns":{"type":["integer","null"],"format":"int32","description":"Per-run turn cap applied to every phase (1–200). Only enforced for\nCLIs with a turn flag (Claude Code). `None` uses the provider's\nconfigured defaults."},"model":{"type":["string","null"],"description":"Model id for the chosen provider. `None` uses the provider's saved\ndefault model."},"provider":{"type":["string","null"],"description":"AI provider id (\"claude_cli\", \"codex_cli\", \"opencode\"). `None` uses\nthe platform default provider."},"user_context":{"type":["string","null"],"description":"Free-text notes for the model (extra context about the error, retry\nguidance, constraints). Included verbatim in the analysis prompt."}}},"StartPgUpgradeRequest":{"type":"object","required":["from_version","to_version","from_image","to_image"],"properties":{"from_image":{"type":"string","example":"postgres:16-bookworm"},"from_version":{"type":"string","example":"16"},"to_image":{"type":"string","example":"postgres:17-bookworm"},"to_version":{"type":"string","example":"17"}}},"StartRestoreRequest":{"allOf":[{"$ref":"#/components/schemas/RestoreRequestMode","description":"Requested restore mode. See `RestoreRequestMode`."},{"type":"object","properties":{"backup_engine":{"type":["string","null"],"description":"Engine of the backup when specified by `backup_location`\n(\"postgres\", \"redis\", \"mongodb\", \"s3\"). Ignored when `backup_id`\nis used — we infer from the DB row."},"backup_id":{"type":["integer","null"],"format":"int32","description":"DB id of the backup to restore from. Either `backup_id` or\n`backup_location` MUST be provided. Use `backup_id` when restoring\na backup this Temps instance recorded."},"backup_location":{"type":["string","null"],"description":"Raw S3 URL / key of the backup — used when restoring a backup\ndiscovered by S3 scan (i.e., produced by another Temps instance).\nRequires `backup_engine` and `s3_source_id` to also be set."},"s3_source_id":{"type":["integer","null"],"format":"int32","description":"S3 source the `backup_location` lives in. Ignored when `backup_id`\nis used."}}}]},"StartUpdateRequest":{"type":"object","description":"Optional pin for the version to install.","properties":{"version":{"type":["string","null"],"description":"Release tag to install (e.g. `v0.2.0`). Omit to take the newest release\non the channel this install already tracks."}}},"StartUpdateResponse":{"type":"object","description":"Acknowledgement that an update was accepted and is running.","required":["current_version","estimated_restart_secs","message"],"properties":{"current_version":{"type":"string","description":"Version the server is running as it accepts this request."},"estimated_restart_secs":{"type":"integer","format":"int64","description":"How long to allow for the server to come back before treating the\nrestart as failed.","minimum":0},"message":{"type":"string"}}},"StatResponse":{"type":"object","required":["path","exists","is_dir","is_file","size"],"properties":{"exists":{"type":"boolean"},"is_dir":{"type":"boolean"},"is_file":{"type":"boolean"},"path":{"type":"string"},"size":{"type":"integer","format":"int64","minimum":0}}},"StaticBundleResponse":{"type":"object","required":["id","project_id","blob_path","content_type","size_bytes","uploaded_at","created_at"],"properties":{"blob_path":{"type":"string"},"checksum":{"type":["string","null"]},"content_type":{"type":"string"},"created_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"format":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"metadata":{},"original_filename":{"type":["string","null"]},"project_id":{"type":"integer","format":"int32"},"size_bytes":{"type":"integer","format":"int64"},"uploaded_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"}}},"StaticParams":{"type":"object","description":"Static threshold detector: compare the aggregated `value` against `threshold`.","required":["comparator","threshold"],"properties":{"comparator":{"$ref":"#/components/schemas/Comparator","description":"How `value` is compared against `threshold`."},"threshold":{"type":"number","format":"double","description":"The threshold the aggregated value is compared against."}}},"StaticPresetConfig":{"type":"object","description":"Configuration for static site presets (Vite, Next.js, Docusaurus, etc.)\nThese presets build static sites that are served via a web server","properties":{"buildCommand":{"type":["string","null"],"description":"Custom build command (overrides preset default)","example":"npm run build:production"},"buildContext":{"type":["string","null"],"description":"Custom build context path (relative to repository root)\nUseful for monorepo setups where the app is in a subdirectory","example":"./apps/frontend"},"installCommand":{"type":["string","null"],"description":"Custom install command (overrides auto-detected package manager)","example":"npm ci"},"outputDir":{"type":["string","null"],"description":"Custom output directory (overrides preset default)\nCommon values: \"dist\", \"build\", \".next\", \"out\"","example":"dist"}}},"StatsFilters":{"type":"object","description":"Filters for statistics queries","properties":{"client_ip":{"type":["string","null"]},"deployment_id":{"type":["integer","null"],"format":"int32"},"device_type":{"type":["string","null"]},"environment_id":{"type":["integer","null"],"format":"int32"},"has_project":{"type":["boolean","null"],"description":"When true, only count requests that matched a project (project_id IS NOT NULL).\nUsed by the health dashboard so totals match the per-project cards."},"host":{"type":["string","null"]},"is_bot":{"type":["boolean","null"]},"method":{"type":["string","null"]},"project_id":{"type":["integer","null"],"format":"int32"},"request_source":{"type":["string","null"]},"routing_status":{"type":["string","null"]},"status_code":{"type":["integer","null"],"format":"int32"},"status_code_class":{"type":["string","null"],"description":"Filter by status code class (e.g. \"2xx\", \"3xx\", \"4xx\", \"5xx\")"}}},"StatusBucket":{"type":"object","required":["bucket_start","status","total_checks","operational_count","degraded_count","down_count","uptime_percentage"],"properties":{"avg_response_time_ms":{"type":["number","null"],"format":"double"},"bucket_start":{"type":"string","format":"date-time"},"degraded_count":{"type":"integer","format":"int64"},"down_count":{"type":"integer","format":"int64"},"max_response_time_ms":{"type":["number","null"],"format":"double"},"min_response_time_ms":{"type":["number","null"],"format":"double"},"operational_count":{"type":"integer","format":"int64"},"p50_response_time_ms":{"type":["number","null"],"format":"double"},"p95_response_time_ms":{"type":["number","null"],"format":"double"},"p99_response_time_ms":{"type":["number","null"],"format":"double"},"status":{"type":"string"},"total_checks":{"type":"integer","format":"int64"},"uptime_percentage":{"type":"number","format":"double"}}},"StatusBucketedResponse":{"type":"object","required":["monitor_id","interval","buckets"],"properties":{"buckets":{"type":"array","items":{"$ref":"#/components/schemas/StatusBucket"}},"interval":{"type":"string"},"monitor_id":{"type":"integer","format":"int32"}}},"StatusCodeCount":{"type":"object","required":["status_code","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"percentage":{"type":"number","format":"double"},"status_code":{"type":"integer","format":"int32"}}},"StatusCodesQuery":{"type":"object","required":["start_date","end_date","project_id"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"StatusPageOverview":{"type":"object","required":["status","monitors","recent_incidents"],"properties":{"monitors":{"type":"array","items":{"$ref":"#/components/schemas/MonitorStatus"}},"recent_incidents":{"type":"array","items":{"$ref":"#/components/schemas/IncidentResponse"}},"status":{"type":"string"}}},"StepConversionResponse":{"type":"object","required":["step_id","step_name","step_order","completions","conversion_rate","drop_off_rate","average_time_to_complete_seconds"],"properties":{"average_time_to_complete_seconds":{"type":"number","format":"double"},"completions":{"type":"integer","format":"int64","minimum":0},"conversion_rate":{"type":"number","format":"double"},"drop_off_rate":{"type":"number","format":"double"},"step_id":{"type":"integer","format":"int32"},"step_name":{"type":"string"},"step_order":{"type":"integer","format":"int32"}}},"StepResourceType":{"type":"string","description":"What kind of resource a migration step operates on","enum":["project","environment","deployment","environment-variable","service","domain","git-link","other"]},"StepResult":{"type":"object","description":"Result of executing a single migration step","required":["step_id","step_title","success","skipped","message","created_resources","duration_seconds"],"properties":{"created_resources":{"type":"array","items":{"$ref":"#/components/schemas/CreatedResource"},"description":"Resources created by this step"},"duration_seconds":{"type":"number","format":"double","description":"Duration of this step"},"message":{"type":"string","description":"Human-readable message about what happened"},"skipped":{"type":"boolean","description":"Whether this step was skipped"},"step_id":{"type":"string","description":"Step ID (matches `MigrationStep.id`)"},"step_title":{"type":"string","description":"Step title (for display)"},"success":{"type":"boolean","description":"Whether this step succeeded"}}},"StepUpResponse":{"type":"object","required":["expires_at"],"properties":{"expires_at":{"type":"string","format":"date-time","description":"ISO 8601 timestamp after which sensitive actions require verification\nagain."}}},"StopSequence":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]},"StorageQuota":{"type":"object","description":"Quota usage information for a project.","required":["project_id","metrics_bytes","traces_bytes","logs_bytes","total_bytes","limit_bytes","usage_pct"],"properties":{"limit_bytes":{"type":"integer","format":"int64","minimum":0},"logs_bytes":{"type":"integer","format":"int64","minimum":0},"metrics_bytes":{"type":"integer","format":"int64","minimum":0},"project_id":{"type":"integer","format":"int32"},"total_bytes":{"type":"integer","format":"int64","minimum":0},"traces_bytes":{"type":"integer","format":"int64","minimum":0},"usage_pct":{"type":"number","format":"double"}}},"StripeConfig":{"type":"object","properties":{"include_unpriced_charges":{"type":"boolean","description":"When an allowlist is set, should we still ingest charges that\nlack a price reference (e.g. standalone `charge.succeeded` without\na subscription)? Default true — charges don't belong to a SKU."},"metered_mode":{"$ref":"#/components/schemas/MeteredMode","description":"How to compute MRR for metered / tiered / hybrid subscriptions."},"price_allowlist":{"type":"array","items":{"type":"string"},"description":"Only events tagged with one of these Stripe price IDs are ingested.\nEmpty = accept all prices."},"product_allowlist":{"type":"array","items":{"type":"string"},"description":"Only events tagged with one of these Stripe product IDs are\ningested. Empty = accept all products. Combined with\n`price_allowlist` via OR — if either list has a match, accept."}}},"SupervisorKind":{"type":"string","description":"What (if anything) will restart the process after it exits.","enum":["systemd","launchd","container","none"]},"SyncedRepositoryListQuery":{"type":"object","properties":{"direction":{"type":["string","null"]},"git_provider_connection_id":{"type":["integer","null"],"format":"int32"},"language":{"type":["string","null"]},"owner":{"type":["string","null"]},"page":{"type":["integer","null"],"format":"int64","minimum":0},"per_page":{"type":["integer","null"],"format":"int64","minimum":0},"private":{"type":["boolean","null"]},"search":{"type":["string","null"]},"sort":{"type":["string","null"]}}},"SyntaxResult":{"type":"object","description":"Syntax validation result","required":["is_valid_syntax"],"properties":{"domain":{"type":["string","null"],"description":"The domain part of the email","example":"gmail.com"},"is_valid_syntax":{"type":"boolean","description":"Whether the email syntax is valid"},"suggestion":{"type":["string","null"],"description":"Suggested email correction if available"},"username":{"type":["string","null"],"description":"The username part of the email","example":"someone"}}},"TagInfo":{"type":"object","required":["name","commit_sha"],"properties":{"commit_sha":{"type":"string"},"name":{"type":"string"}}},"TagListResponse":{"type":"object","required":["tags"],"properties":{"tags":{"type":"array","items":{"$ref":"#/components/schemas/TagInfo"}}}},"TailLogsRequest":{"type":"object","required":["project_id","service","env"],"properties":{"env":{"type":"string"},"external_service_id":{"type":["integer","null"],"format":"int32","description":"When set, tail an imported/managed external service's logs instead of\na project's (`project_id` is ignored in this mode)."},"levels":{"type":"array","items":{"type":"string"}},"project_id":{"type":"integer","format":"int32","description":"Project ID (integer, as used by the rest of the platform)"},"service":{"type":"string"},"text":{"type":["string","null"]}}},"TargetRecommendation":{"type":"object","description":"The temps/Hetzner target sizing and savings estimate","required":["server_type","vcpus","memory_gb","monthly_eur","fits_single_node","sizing_basis","rationale"],"properties":{"fits_single_node":{"type":"boolean","description":"Whether the workloads fit a single recommended server. When `false`,\nthe rationale explains the multi-node option (temps worker nodes)."},"memory_gb":{"type":"integer","format":"int32","description":"Memory (GB) of the recommended server"},"monthly_eur":{"type":"number","format":"double","description":"Estimated monthly price of the recommended server in EUR"},"monthly_savings_usd":{"type":["number","null"],"format":"double","description":"Estimated monthly savings in USD (current cost minus target cost,\ntreating EUR≈USD for the rough comparison — disclaimed in `notes`).\n`None` when the current cost is unknown."},"rationale":{"type":"string","description":"Human-readable recommendation summary"},"server_type":{"type":"string","description":"Recommended Hetzner server type (e.g. \"cpx32\")"},"sizing_basis":{"type":"string","description":"What the sizing was based on, e.g. \"2× measured usage + temps\nplatform overhead\" or \"resource requests (no metrics available)\""},"vcpus":{"type":"integer","format":"int32","description":"vCPUs of the recommended server"},"yearly_savings_usd":{"type":["number","null"],"format":"double","description":"`monthly_savings_usd × 12`"}}},"TeamListResponse":{"type":"object","required":["teams","total","page","page_size"],"properties":{"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"teams":{"type":"array","items":{"$ref":"#/components/schemas/TeamResponse"}},"total":{"type":"integer","format":"int64","minimum":0}}},"TeamMemberResponse":{"type":"object","required":["id","team_id","user_id","role","added_by","created_at","updated_at"],"properties":{"added_by":{"type":"integer","format":"int32"},"created_at":{"type":"string","format":"date-time","example":"2026-07-30T12:15:47.609192Z"},"id":{"type":"integer","format":"int32"},"role":{"$ref":"#/components/schemas/TeamRole","description":"The source of this member's project-scoped permissions, intersected\nwith `project_team_access.role`."},"team_id":{"type":"integer","format":"int32"},"updated_at":{"type":"string","format":"date-time","example":"2026-07-30T12:15:47.609192Z"},"user_email":{"type":["string","null"],"description":"The member's email, joined from `users`."},"user_id":{"type":"integer","format":"int32"},"user_name":{"type":["string","null"],"description":"The member's display name, joined from `users`. `None` if the\nreferenced user no longer exists."}}},"TeamResponse":{"type":"object","required":["id","name","slug","created_by","created_at","updated_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2026-07-30T12:15:47.609192Z"},"created_by":{"type":"integer","format":"int32"},"description":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"slug":{"type":"string"},"updated_at":{"type":"string","format":"date-time","example":"2026-07-30T12:15:47.609192Z"}}},"TeamRole":{"type":"string","description":"Role a user holds within a team, or that a team holds on a project.\n\nNamed `TeamRole` rather than `Role` to keep it distinct from\n`temps_auth::permissions::Role`, which is the instance-wide role\n(Admin/User/…) attached to a session. The two are orthogonal: the\ninstance-wide role decides whether you may touch a resource *kind* at\nall, `TeamRole` decides what you may do *within a project* you have\nteam access to. See `temps_teams::fixed_role_permissions` for the\nproject-scoped permission set each variant maps to.\n\nStored as a `varchar(32)` rather than a Postgres enum so the role set\ncan evolve in pure migration code without a schema-level enum\nalteration blocking a downgrade.","enum":["owner","admin","deployer","viewer"]},"TemplateResponse":{"type":"object","description":"Response type for a single template","required":["slug","name","git","preset","tags","features","services","env_vars","is_featured"],"properties":{"description":{"type":["string","null"],"description":"Short description"},"env_vars":{"type":"array","items":{"$ref":"#/components/schemas/EnvVarTemplateResponse"},"description":"Environment variables template"},"exposed_port":{"type":["integer","null"],"format":"int32","description":"Container port the prebuilt image listens on (image deploys only)."},"features":{"type":"array","items":{"type":"string"},"description":"Feature highlights"},"git":{"$ref":"#/components/schemas/GitRefResponse","description":"Git repository reference"},"health_check_path":{"type":["string","null"],"description":"HTTP health-check path probed after the container starts (image deploys)."},"image":{"type":["string","null"],"description":"Prebuilt Docker image reference. When set, the one-click deploy pulls and\nruns this image directly (no build); when absent it builds from `git`."},"image_url":{"type":["string","null"],"description":"URL to template image/icon"},"is_featured":{"type":"boolean","description":"Whether the template is featured/promoted"},"name":{"type":"string","description":"Display name"},"preset":{"type":"string","description":"Framework/preset to use"},"screenshot_url":{"type":["string","null"],"description":"URL to a wide screenshot/banner preview of the deployed template.\nAbsent for templates that don't have one captured yet."},"services":{"type":"array","items":{"type":"string"},"description":"Required external services"},"slug":{"type":"string","description":"Unique identifier for the template (used in URLs)"},"tags":{"type":"array","items":{"type":"string"},"description":"Tags/categories for filtering"}}},"TestEmailRequest":{"type":"object","description":"Request body for testing an email provider","required":["from"],"properties":{"from":{"type":"string","description":"Sender email address (must be verified with the provider)","example":"test@example.com"},"from_name":{"type":["string","null"],"description":"Sender display name","example":"My App"}}},"TestEmailResponse":{"type":"object","description":"Response for test email endpoint","required":["success","sent_to"],"properties":{"error":{"type":["string","null"],"description":"Error message if the test failed"},"provider_message_id":{"type":["string","null"],"description":"Provider message ID if successful"},"sent_to":{"type":"string","description":"The email address the test was sent to","example":"user@example.com"},"success":{"type":"boolean","description":"Whether the test email was sent successfully"}}},"TestProviderKeyRequest":{"type":"object","required":["provider","api_key"],"properties":{"api_key":{"type":"string","description":"The raw API key to test"},"base_url":{"type":["string","null"],"description":"Optional custom base URL"},"provider":{"type":"string","description":"Provider ID: \"openai\", \"anthropic\", \"xai\", \"gemini\""}}},"TestProviderKeyResponse":{"type":"object","required":["success","provider","latency_ms"],"properties":{"error":{"type":["string","null"],"description":"Error message if the test failed"},"latency_ms":{"type":"integer","format":"int64","description":"Response time in milliseconds","minimum":0},"provider":{"type":"string"},"success":{"type":"boolean"}}},"TestProviderResponse":{"type":"object","required":["success"],"properties":{"message":{"type":["string","null"]},"success":{"type":"boolean"}}},"TimeBucketStats":{"type":"object","description":"Time bucket statistics response","required":["bucket","request_count","avg_response_time_ms","error_count","total_request_bytes","total_response_bytes"],"properties":{"avg_response_time_ms":{"type":"number","format":"double","description":"Average response time in milliseconds"},"bucket":{"type":"string","description":"Bucket timestamp in RFC3339 format","example":"2025-10-23T12:00:00Z"},"error_count":{"type":"integer","format":"int64","description":"Number of errors (status >= 400)"},"request_count":{"type":"integer","format":"int64","description":"Total number of requests in this bucket"},"total_request_bytes":{"type":"integer","format":"int64","description":"Total request bytes"},"total_response_bytes":{"type":"integer","format":"int64","description":"Total response bytes"}}},"TimeBucketStatsResponse":{"type":"object","description":"Response for time bucket stats","required":["stats","start_time","end_time","bucket_interval"],"properties":{"bucket_interval":{"type":"string"},"end_time":{"type":"string"},"start_time":{"type":"string"},"stats":{"type":"array","items":{"$ref":"#/components/schemas/TimeBucketStats"}}}},"TimeseriesBucket":{"type":"object","required":["bucket","request_count","input_tokens","output_tokens","avg_latency_ms"],"properties":{"avg_latency_ms":{"type":"number","format":"double"},"bucket":{"type":"string","description":"ISO 8601 timestamp"},"input_tokens":{"type":"integer","format":"int64"},"output_tokens":{"type":"integer","format":"int64"},"request_count":{"type":"integer","format":"int64"}}},"TimeseriesQueryParams":{"type":"object","properties":{"bucket":{"type":["string","null"],"description":"Bucket size: \"hour\", \"day\", \"week\" (defaults to \"day\")"},"conversation_id":{"type":["string","null"],"description":"Filter by conversation ID"},"from":{"type":["string","null"],"description":"ISO 8601 start time (defaults to 24h ago)"},"model":{"type":["string","null"],"description":"Filter by model name"},"provider":{"type":["string","null"],"description":"Filter by provider name"},"tags":{"type":["string","null"],"description":"Filter by tags (comma-separated, AND logic)"},"to":{"type":["string","null"],"description":"ISO 8601 end time (defaults to now)"},"user_id":{"type":["integer","null"],"format":"int32","description":"Filter by user ID"}}},"TlsMode":{"type":"string","enum":["None","Starttls","Tls"]},"TodayStatsResponse":{"type":"object","description":"Today's stats response","required":["total_requests","date"],"properties":{"date":{"type":"string","description":"Date for which stats are returned","example":"2025-10-23"},"total_requests":{"type":"integer","format":"int64","description":"Total requests today"}}},"ToggleDeploymentMetricsRequest":{"type":"object","description":"Request body to toggle OTLP metric ingestion for a deployment.","required":["enabled"],"properties":{"enabled":{"type":"boolean","description":"Whether to enable (`true`) or disable (`false`) metric ingestion."},"path":{"type":["string","null"],"description":"Prometheus scrape path (optional, defaults to `/metrics`)."},"port":{"type":["integer","null"],"format":"int32","description":"Prometheus scrape port (optional).","minimum":0}}},"ToggleServiceMetricsRequest":{"type":"object","description":"Request body to toggle metric collection for an external service.","required":["enabled"],"properties":{"enabled":{"type":"boolean","description":"Whether to enable (`true`) or disable (`false`) metric collection."}}},"TokenRenewalRequest":{"type":"object","required":["refresh_token"],"properties":{"refresh_token":{"type":"string"}}},"ToolCallEvent":{"type":"object","description":"Payload for the `tool_call` SSE event: the model is about to run a tool.\nSerialized as compact single-line JSON onto one `data:` line.","required":["id","name","arguments"],"properties":{"arguments":{"type":"string","description":"The raw JSON-args string the model emitted."},"id":{"type":"string"},"name":{"type":"string"}}},"ToolInfo":{"type":"object","description":"One persisted tool invocation + its result, attached to an assistant message.","required":["id","name","arguments"],"properties":{"arguments":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"},"result":{"type":["string","null"]}}},"ToolResultEvent":{"type":"object","description":"Payload for the `tool_result` SSE event: a tool finished running. Serialized\nas compact single-line JSON; `content` is JSON-string-escaped so it stays on\none `data:` line even when long.","required":["id","name","content"],"properties":{"content":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"}}},"TopModelsQueryParams":{"type":"object","properties":{"from":{"type":["string","null"],"description":"ISO 8601 start time (defaults to 24h ago)"},"limit":{"type":["integer","null"],"format":"int64","description":"Max results (defaults to 10)","minimum":0},"tags":{"type":["string","null"],"description":"Filter by tags (comma-separated, AND logic)"},"to":{"type":["string","null"],"description":"ISO 8601 end time (defaults to now)"},"user_id":{"type":["integer","null"],"format":"int32","description":"Filter by user ID"}}},"TraceProjectRef":{"type":"object","description":"All projects that contributed spans to a trace, including their sharing flag.\n\nReturned by `CrossProjectTraceService::find_trace_projects`.","required":["project_id","project_name","project_slug","first_seen","sharing"],"properties":{"first_seen":{"type":"string","format":"date-time"},"project_id":{"type":"integer","format":"int32"},"project_name":{"type":"string"},"project_slug":{"type":"string","description":"URL slug used to link into the project's single-project trace view."},"sharing":{"type":"boolean","description":"Whether this project has `cross_project_trace_sharing = true`."}}},"TraceSummariesResponse":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/TraceSummary"}},"total":{"type":["integer","null"],"format":"int64","description":"Total traces matching the filters, ignoring pagination. Omitted when\nthe request passed `include_total=false`, in which case the caller\nasked not to pay for the count — treat its absence as \"unknown\", not\nas zero.","minimum":0}}},"TraceSummary":{"type":"object","description":"A trace summary for the list view — one row per trace, aggregated from spans.","required":["trace_id","root_span_name","service_name","kind","status_code","start_time","duration_ms","span_count","error_count"],"properties":{"deployment_environment":{"type":["string","null"],"description":"The deployment environment from the root span's resource attributes (e.g. \"production\")."},"duration_ms":{"type":"number","format":"double"},"error_count":{"type":"integer","format":"int64"},"kind":{"$ref":"#/components/schemas/SpanKind"},"root_span_name":{"type":"string"},"service_name":{"type":"string"},"span_count":{"type":"integer","format":"int64"},"start_time":{"type":"string","format":"date-time"},"status_code":{"$ref":"#/components/schemas/SpanStatusCode"},"trace_id":{"type":"string"}}},"TracesResponse":{"type":"object","required":["data","count"],"properties":{"count":{"type":"integer","minimum":0},"data":{"type":"array","items":{"$ref":"#/components/schemas/SpanRecord"}}}},"TrackedLinkResponse":{"type":"object","description":"Tracked link with click count","required":["link_index","original_url","click_count"],"properties":{"click_count":{"type":"integer","format":"int32"},"link_index":{"type":"integer","format":"int32"},"original_url":{"type":"string"}}},"TrackingEventResponse":{"type":"object","description":"Email tracking event","required":["id","email_id","event_type","created_at"],"properties":{"created_at":{"type":"string"},"email_id":{"type":"string"},"event_type":{"type":"string"},"id":{"type":"integer","format":"int64"},"ip_address":{"type":["string","null"]},"link_index":{"type":["integer","null"],"format":"int32"},"link_url":{"type":["string","null"]},"user_agent":{"type":["string","null"]}}},"TriggerAgentRequest":{"type":"object","properties":{"trigger_source_id":{"type":["integer","null"],"format":"int32"},"trigger_source_type":{"type":["string","null"]},"user_context":{"type":["string","null"],"description":"Optional context from the user (e.g. a research topic, bug description, or instructions)."}}},"TriggerDigestResponse":{"type":"object","required":["success","message"],"properties":{"message":{"type":"string"},"success":{"type":"boolean"}}},"TriggerPipelinePayload":{"type":"object","properties":{"branch":{"type":["string","null"]},"commit":{"type":["string","null"]},"environment_id":{"type":["integer","null"],"format":"int32","description":"Optional environment ID - if not provided, will use the project's preview environment"},"tag":{"type":["string","null"]}}},"TriggerPipelineResponse":{"type":"object","required":["message","project_id","environment_id"],"properties":{"branch":{"type":["string","null"]},"commit":{"type":["string","null"]},"environment_id":{"type":"integer","format":"int32"},"message":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"tag":{"type":["string","null"]}}},"TriggerScanRequest":{"type":"object","required":["environment_id"],"properties":{"environment_id":{"type":"integer","format":"int32","description":"Environment ID to scan (uses the current deployment for this environment)","example":1}}},"TriggerScanResponse":{"type":"object","required":["scan_id","status","message"],"properties":{"message":{"type":"string"},"scan_id":{"type":"integer","format":"int32"},"status":{"type":"string"}}},"TtlRequest":{"type":"object","description":"Request to get TTL for a key","required":["key"],"properties":{"key":{"type":"string","description":"The key to check TTL for","example":"session:abc"},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1}}},"TtlResponse":{"type":"object","description":"Response for TTL operation","required":["ttl"],"properties":{"ttl":{"type":"integer","format":"int64","description":"TTL in seconds, -1 if no expiration, -2 if key doesn't exist","example":3600}}},"TxtRecord":{"type":"object","required":["name","value"],"properties":{"name":{"type":"string"},"value":{"type":"string"}}},"UiManifest":{"type":"object","description":"Describes the plugin's embedded UI bundle.","required":["entry_js"],"properties":{"css":{"type":"array","items":{"type":"string"},"description":"CSS files to load"},"entry_js":{"type":"string","description":"JavaScript entry point filename relative to the bundle root"},"routes":{"type":"array","items":{"$ref":"#/components/schemas/UiRoute"},"description":"Client-side routes the plugin handles"}}},"UiRoute":{"type":"object","description":"A client-side route provided by the plugin UI.","required":["path","title"],"properties":{"path":{"type":"string","description":"Route path pattern (e.g., \"/my-plugin\", \"/my-plugin/:id\")"},"title":{"type":"string","description":"Page title for breadcrumbs"}}},"UndrainNodeResponse":{"type":"object","description":"Response after undraining (reactivating) a node.","required":["id","name","status","message"],"properties":{"id":{"type":"integer","format":"int32"},"message":{"type":"string"},"name":{"type":"string"},"status":{"type":"string"}}},"UnifiedTrace":{"type":"object","description":"Merged cross-project trace result (Phase 2 unified waterfall).\n\nSpans are sorted by `start_time ASC`. At most 20 projects and 10,000\nspans total are included; `truncated` / `truncated_projects` signal when\nthe caps were hit.","required":["trace_id","projects","spans","start_time","end_time","total_duration_ms","span_count","error_count","has_redacted_spans","truncated","truncated_projects"],"properties":{"end_time":{"type":"string","format":"date-time"},"error_count":{"type":"integer","minimum":0},"has_redacted_spans":{"type":"boolean","description":"`true` when at least one project has `cross_project_trace_sharing = false`\nand its spans were therefore excluded from the result set."},"projects":{"type":"array","items":{"$ref":"#/components/schemas/ProjectRef"},"description":"Projects that contributed spans to this result set."},"span_count":{"type":"integer","minimum":0},"spans":{"type":"array","items":{"$ref":"#/components/schemas/AnnotatedSpan"},"description":"Annotated, merged span list sorted by `start_time ASC`."},"start_time":{"type":"string","format":"date-time"},"total_duration_ms":{"type":"number","format":"double","description":"Trace wall-clock duration in milliseconds (`end_time – start_time`)."},"trace_id":{"type":"string"},"truncated":{"type":"boolean","description":"`true` when the 20-project or 10,000-span cap was hit."},"truncated_projects":{"type":"array","items":{"type":"integer","format":"int32"},"description":"project_ids excluded due to truncation (most-recent first_seen dropped first)."}}},"UniqueCountsQuery":{"type":"object","description":"Query parameters for unique counts over time frame","required":["start_date","end_date"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32","description":"Optional deployment filter"},"end_date":{"type":"string","format":"date-time","description":"End date for the query range"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Optional environment filter"},"metric":{"type":"string","description":"Metric to count: \"sessions\" (unique sessions), \"visitors\" (unique visitors),\n\"returning_visitors\" (visitors seen before the range), or \"page_views\"\n(total page views) (default: \"sessions\")"},"start_date":{"type":"string","format":"date-time","description":"Start date for the query range"}}},"UniqueCountsResponse":{"type":"object","required":["count"],"properties":{"count":{"type":"integer","format":"int64"}}},"UnsupportedFeature":{"type":"object","description":"A feature from the source platform that cannot be migrated","required":["feature","reason"],"properties":{"alternative":{"type":["string","null"],"description":"Suggested alternative in Temps (if any)"},"feature":{"type":"string","description":"Feature name (e.g., \"Edge Middleware\", \"Serverless Functions\", \"Cron Jobs\")"},"reason":{"type":"string","description":"Why it can't be migrated"}}},"UpdateAdminGateRequest":{"type":"object","required":["allowed_ips","allowed_hosts","trust_forwarded_for"],"properties":{"allowed_hosts":{"type":"array","items":{"type":"string"}},"allowed_ips":{"type":"array","items":{"type":"string"}},"trust_forwarded_for":{"type":"boolean"}}},"UpdateAiProviderRequest":{"type":"object","description":"Body for `PATCH /settings/ai-providers/{provider_id}` — updates\nprovider-scoped settings (just the default model for now) without\ntouching the credential. Keeping credentials out of this shape means\nthe UI can auto-save model changes on select, without forcing the user\nto re-paste their token or config file.\nName-spaced schema name avoids an OpenAPI collision with\n`temps-notifications::UpdateProviderRequest`, which has different fields.\nBoth are exposed as `utoipa::ToSchema`; without the override the merged\nOpenAPI doc would silently shadow one struct with the other and break\ngenerated CLI/web clients.","properties":{"default_model":{"type":["string","null"],"description":"New default model id. `None` or an empty string clears the stored\nvalue so the CLI falls back to its own default."},"max_turns_analysis":{"type":["integer","null"],"format":"int32","description":"Default max turns for the autofixer analysis phase (1–200). `0`\nclears the stored value (built-in default applies); omitted/`None`\nleaves the current value unchanged — so a PATCH that only updates\n`default_model` doesn't wipe the turn settings."},"max_turns_feedback":{"type":["integer","null"],"format":"int32","description":"Default max turns for autofixer feedback rounds (1–200). `0` clears;\nomitted leaves unchanged."},"max_turns_fix":{"type":["integer","null"],"format":"int32","description":"Default max turns for the autofixer fix phase (1–200). `0` clears;\nomitted leaves unchanged."}}},"UpdateAiProviderResponse":{"type":"object","required":["provider_id"],"properties":{"default_model":{"type":["string","null"]},"max_turns_analysis":{"type":["integer","null"],"format":"int32"},"max_turns_feedback":{"type":["integer","null"],"format":"int32"},"max_turns_fix":{"type":["integer","null"],"format":"int32"},"provider_id":{"type":"string"}}},"UpdateAlertRuleRequest":{"type":"object","properties":{"cooldown_minutes":{"type":["integer","null"],"format":"int32"},"enabled":{"type":["boolean","null"]},"environment_filter":{"type":["integer","null"],"format":"int32"},"error_level_filter":{"type":["string","null"]},"name":{"type":["string","null"]},"notification_priority":{"type":["string","null"]},"trigger_config":{},"trigger_type":{"type":["string","null"]}}},"UpdateApiKeyRequest":{"type":"object","properties":{"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"is_active":{"type":["boolean","null"]},"name":{"type":["string","null"]},"permissions":{"type":["array","null"],"items":{"type":"string"},"example":["projects:read","deployments:read"]}}},"UpdateAutomaticDeployRequest":{"type":"object","required":["automatic_deploy"],"properties":{"automatic_deploy":{"type":"boolean"}}},"UpdateBackupScheduleRequest":{"type":"object","description":"Request body for updating an existing backup schedule via `PATCH /api/backups/schedules/{id}`.\n\nAll fields are optional; only present fields are updated. Absent fields\nleave the corresponding column unchanged.","properties":{"description":{"type":["string","null"],"description":"New human-readable description. Pass an empty string `\"\"` to clear."},"enabled":{"type":["boolean","null"],"description":"Enable or disable the schedule. Skipped when `None`."},"include_control_plane":{"type":["boolean","null"],"description":"Toggle whether the control-plane backup is produced on every run."},"max_runtime_secs":{"type":["integer","null"],"format":"int64","description":"Per-schedule wall-clock timeout override (seconds).\n\n- `None` (field absent) — leave current value unchanged\n- `Some(None)` (field present, JSON `null`) — clear override; fall back to engine default\n- `Some(Some(n))` — set to `n` seconds (must be >= 60)"},"name":{"type":["string","null"],"description":"New schedule name. Skipped when `None`. Must not be empty if provided."},"retention_period":{"type":["integer","null"],"format":"int32","description":"Days to retain backups produced by this schedule. Must be >= 1."},"schedule_expression":{"type":["string","null"],"description":"New cron expression. When changed, `next_run` is recomputed."},"tags":{"type":["array","null"],"items":{"type":"string"},"description":"Replace the full tag list. Skipped when `None`."},"target_all_services":{"type":["boolean","null"],"description":"Toggle between \"back up every database\" (`true`) and \"back up only\nthe explicit list\" (`false`). When set to `true`, the server clears\nthe explicit membership rows for this schedule."}}},"UpdateBlobRequest":{"type":"object","description":"Request to update Blob service configuration","properties":{"docker_image":{"type":["string","null"],"description":"Docker image to use (e.g., \"rustfs/rustfs:1.0.0-alpha.98\")","example":"rustfs/rustfs:1.0.0-alpha.98"}}},"UpdateBlobResponse":{"type":"object","description":"Response after updating Blob service","required":["success","message","status"],"properties":{"message":{"type":"string","description":"Human-readable message","example":"Blob service updated successfully"},"status":{"$ref":"#/components/schemas/BlobStatusResponse","description":"Current status"},"success":{"type":"boolean","description":"Whether the operation succeeded","example":true}}},"UpdateCapabilityResponse":{"type":"object","description":"Whether this install can apply a release update on request, and how the last\nattempt went.\n\nDeliberately answerable even when the answer is \"no\": an operator who cannot\nuse the button still needs to know *why* and what to run instead, so this\nnever 404s or returns an empty body when the feature is unavailable.","required":["can_apply","allowed","manual_command","supervisor","binary_path","phase"],"properties":{"allowed":{"type":"boolean","description":"Whether the *caller* holds `platform:update`. Distinct from `can_apply`,\nwhich describes the server: the console shows the action only when both\nare true, so a reader is never offered a button that would 403."},"binary_path":{"type":"string","description":"Binary that would be replaced."},"blocker":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SelfUpdateBlocker","description":"Machine-readable reason `can_apply` is false (`disabled_by_flag`,\n`disabled_by_setting`, `container`, `no_supervisor`, `binary_not_writable`,\n`unsupported_platform`, `in_progress`)."}]},"can_apply":{"type":"boolean","description":"True only when a request would actually download, install and restart."},"caveat":{"type":["string","null"],"description":"Non-blocking warning to show with the confirmation (split topology)."},"last_attempt":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SelfUpdateAttempt","description":"Most recent attempt, including one resolved during this boot — this is\nhow the console reports the outcome of an update that restarted it."}]},"manual_command":{"type":"string","description":"The equivalent command to run by hand. Always present."},"phase":{"$ref":"#/components/schemas/SelfUpdatePhase","description":"Phase of an in-flight attempt: `idle` when none is running."},"phase_error":{"type":["string","null"],"description":"Failure detail while `phase` is `failed`."},"reason":{"type":["string","null"],"description":"Operator-facing explanation of `blocker`."},"supervisor":{"$ref":"#/components/schemas/SupervisorKind","description":"What would restart the process: `systemd`, `launchd`, `container`, `none`."}}},"UpdateCloudflareProviderRequest":{"type":"object","required":["config"],"properties":{"config":{"$ref":"#/components/schemas/CloudflareConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":["string","null"]}}},"UpdateConfigBody":{"type":"object","properties":{"config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ProviderConfig","description":"Typed provider configuration. Setting `config` to `null` clears\nthe stored config back to the accept-everything default. The\nconfig's `provider` tag must match the integration's provider."}]}}},"UpdateCustomDomainRequest":{"type":"object","properties":{"branch":{"type":["string","null"]},"domain":{"type":["string","null"]},"environment_id":{"type":["integer","null"],"format":"int32"},"redirect_to":{"type":["string","null"]},"service_name":{"type":["string","null"],"description":"Docker Compose service name this domain routes to (empty string clears it)"},"status_code":{"type":["integer","null"],"format":"int32"}}},"UpdateDashboardRequest":{"type":"object","properties":{"layout":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DashboardLayout"}]},"name":{"type":["string","null"]}}},"UpdateDeploymentConfigRequest":{"type":"object","properties":{"automaticDeploy":{"type":["boolean","null"]},"cpuLimit":{"type":["integer","null"],"format":"int32"},"cpuRequest":{"type":["integer","null"],"format":"int32"},"crossArchitectureBuilds":{"type":["boolean","null"],"description":"Build one image per architecture the eligible nodes run. Off by\ndefault; environments inherit this and may override it. Cross-builds\nare emulated on the control plane and substantially slower, so they are\nopted into rather than triggered by cluster topology."},"exposedPort":{"type":["integer","null"],"format":"int32"},"memoryLimit":{"type":["integer","null"],"format":"int32"},"memoryRequest":{"type":["integer","null"],"format":"int32"},"performanceMetricsEnabled":{"type":["boolean","null"]},"replicas":{"type":["integer","null"],"format":"int32"},"security":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SecurityConfig"}]},"sessionRecordingEnabled":{"type":["boolean","null"]}}},"UpdateDeploymentTokenRequest":{"type":"object","properties":{"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"is_active":{"type":["boolean","null"]},"name":{"type":["string","null"]},"permissions":{"type":["array","null"],"items":{"type":"string"},"example":["visitors:enrich","emails:send"]}}},"UpdateDnsProviderRequest":{"type":"object","description":"Request to update a DNS provider","properties":{"credentials":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DnsProviderCredentials","description":"New credentials"}]},"description":{"type":["string","null"],"description":"New description"},"is_active":{"type":["boolean","null"],"description":"Active status"},"name":{"type":["string","null"],"description":"New name"}}},"UpdateEmailProviderRequest":{"type":"object","description":"Request body for `PATCH /email-providers/{id}`.\n\nAll fields are optional. Omit any field to leave it unchanged. The\n`provider_type` is immutable — to switch providers, delete the row and\ncreate a new one. For credentials, supplying any credential variant\nre-encrypts the stored blob; omitting them preserves the existing secret\n(so operators can rename without re-typing passwords).","properties":{"is_active":{"type":["boolean","null"]},"name":{"type":["string","null"],"example":"My AWS SES"},"region":{"type":["string","null"],"example":"us-east-1"},"scaleway_credentials":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ScalewayCredentialsRequest"}]},"ses_credentials":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SesCredentialsRequest"}]},"smtp_credentials":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SmtpCredentialsRequest"}]},"sns_topic_arn":{"type":["string","null"],"description":"Rotate or clear the exact SNS topic allowed for this SES provider.\nOmit to preserve it, send `null` to clear it, or send a string to set it."}}},"UpdateEnvironmentSettingsRequest":{"type":"object","properties":{"anti_affinity":{"type":["boolean","null"],"description":"Anti-affinity: spread replicas across different nodes.\nWhen enabled, the scheduler avoids placing two replicas of the same\nenvironment on the same node. Defaults to `true`."},"attack_mode":{"type":["boolean","null"],"description":"Per-environment CAPTCHA attack-mode override (tri-state):\n- absent → leave the current override unchanged\n- JSON `null` → clear the override (inherit the project-level setting)\n- `true`/`false` → override the project setting for this environment"},"automatic_deploy":{"type":["boolean","null"],"description":"Enable/disable automatic deployments for this environment"},"branch":{"type":["string","null"]},"cpu_limit":{"type":["integer","null"],"format":"int32","description":"Maximum (limit) CPU in microcores. Send JSON `null` to clear → \"no limit\".\nAbsent leaves the current value unchanged."},"cpu_request":{"type":["integer","null"],"format":"int32","description":"Minimum (request) CPU in microcores. Send JSON `null` to clear (no request).\nAbsent leaves the current value unchanged."},"cross_architecture_builds":{"type":["boolean","null"],"description":"Build one image per architecture the eligible nodes run (overrides the\nproject-level setting). Off by default: cross-architecture builds are\nemulated on the control plane and substantially slower, so they are\nopted into per environment rather than triggered by cluster topology."},"exposed_port":{"type":["integer","null"],"format":"int32","description":"Port exposed by the container (overrides project-level port for this environment)\n\nPriority order for port resolution:\n1. Image EXPOSE directive (auto-detected from built image)\n2. This environment-level exposed_port (overrides project setting)\n3. Project-level exposed_port (fallback)\n4. Default: 3000","example":8080},"force_https":{"type":["boolean","null"],"description":"Per-environment HTTP→HTTPS redirect override (tri-state):\n- absent → leave the current override unchanged\n- JSON `null` → clear the override (inherit the proxy default, which\n redirects only when the host has an active TLS certificate)\n- `true` → always redirect plain HTTP to HTTPS for this environment,\n even when no local certificate exists (TLS terminated upstream)\n- `false` → never redirect this environment, even when a certificate does\n exist\n\nRequests under `/.well-known/acme-challenge/` are never redirected\nregardless of this setting, so ACME HTTP-01 validation always completes."},"idle_timeout_seconds":{"type":["integer","null"],"format":"int32","description":"Seconds of inactivity before stopping containers (60-86400). Default: 300."},"memory_limit":{"type":["integer","null"],"format":"int32","description":"Maximum (limit) memory in MB. Send JSON `null` to clear → \"no limit\".\nAbsent leaves the current value unchanged."},"memory_request":{"type":["integer","null"],"format":"int32","description":"Minimum (request) memory in MB. Send JSON `null` to clear (no request).\nAbsent leaves the current value unchanged."},"on_demand":{"type":["boolean","null"],"description":"Enable on-demand mode (scale-to-zero). Containers are stopped after\nidle_timeout_seconds of no traffic and started on the next request."},"password":{"type":["string","null"],"description":"Set a password to protect this environment. The proxy will show an HTML\npassword form before allowing access. The password is bcrypt-hashed\nserver-side and never stored in plaintext.\nSend an empty string to remove password protection."},"performance_metrics_enabled":{"type":["boolean","null"],"description":"Enable/disable performance metrics collection"},"protected":{"type":["boolean","null"],"description":"When true, git pushes do NOT auto-deploy to this environment.\nDeployments must be promoted from another environment."},"replicas":{"type":["integer","null"],"format":"int32"},"security":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SecurityConfig","description":"Security configuration for this environment (overrides project-level settings)"}]},"session_recording_enabled":{"type":["boolean","null"],"description":"Enable/disable session recording"},"target_labels":{"description":"Label selector for node-based scheduling (overrides project-level setting).\nSame key with array value -> OR, different keys -> AND.\nExample: `{\"region\": [\"us\", \"asia\"], \"gpu\": \"true\"}`"},"target_nodes":{"type":["array","null"],"items":{"type":"integer","format":"int32"},"description":"Optional list of node IDs to deploy to (overrides project-level setting)"},"wake_timeout_seconds":{"type":["integer","null"],"format":"int32","description":"Max seconds to wait for containers to start on wake (5-120). Default: 30."}}},"UpdateEnvironmentSubdomainRequest":{"type":"object","description":"Request to rename an environment's auto-managed subdomain.\n\nThe subdomain is the host label inserted in front of the platform's\npreview domain (e.g. `myapp` in `myapp.preview.temps.sh`). Renaming\nreplaces the previous subdomain entirely — the old hostname stops\nresolving immediately after this request succeeds.","required":["subdomain"],"properties":{"subdomain":{"type":"string","description":"New subdomain label. Must be a DNS-safe slug (lowercase letters,\ndigits, and hyphens, 1-63 characters). The value is slugified\nserver-side, so casing and disallowed characters are normalized.","example":"myapp"}}},"UpdateEnvironmentVariableRequest":{"type":"object","required":["key","environment_ids"],"properties":{"environment_ids":{"type":"array","items":{"type":"integer","format":"int32"}},"include_in_preview":{"type":"boolean"},"is_secret":{"type":["boolean","null"],"description":"Optional secret-flag transition.\n- `Some(true)` promotes a regular var to a secret.\n- `Some(false)` is rejected if the row is already secret (one-way flag).\n- `None` (omitted) leaves the flag unchanged."},"key":{"type":"string"},"value":{"type":["string","null"],"description":"New plaintext value. `None` (omitted) keeps the existing ciphertext,\nwhich is the only way to edit a secret env var without re-typing its\nvalue (e.g. changing which environments it applies to)."}}},"UpdateErrorGroupRequest":{"type":"object","required":["status"],"properties":{"assigned_to":{"type":["string","null"]},"status":{"type":"string"}}},"UpdateExternalServiceRequest":{"type":"object","required":["parameters"],"properties":{"docker_image":{"type":["string","null"],"description":"Docker image to use for the service (e.g., \"gotempsh/postgres-walg:18-bookworm\", \"timescale/timescaledb-ha:pg18\")\nWhen provided, the service will be recreated with the new image while preserving data"},"parameters":{"type":"object","additionalProperties":{},"propertyNames":{"type":"string"}}}},"UpdateFlagRequest":{"type":"object","properties":{"client_visible":{"type":["boolean","null"]},"default_value":{"description":"Must match the flag's existing `value_type`."},"description":{"type":["string","null"],"description":"Tri-state: absent leaves it, `null` clears it, a string sets it."}}},"UpdateGitSettingsRequest":{"type":"object","required":["main_branch","repo_owner","repo_name","directory"],"properties":{"directory":{"type":"string"},"git_provider_connection_id":{"type":["integer","null"],"format":"int32"},"git_url":{"type":["string","null"],"description":"Git clone URL for public repositories"},"is_public_repo":{"type":["boolean","null"],"description":"Whether this is a public repository (no git provider connection needed)"},"main_branch":{"type":"string"},"preset":{"type":["string","null"]},"preset_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PresetConfigSchema","description":"Preset-specific configuration (e.g., Dockerfile path for Docker preset)\n\nExample for Dockerfile preset:\n```json\n{\n \"dockerfilePath\": \"docker/Dockerfile\",\n \"buildContext\": \"./api\"\n}\n```"}]},"repo_name":{"type":"string"},"repo_owner":{"type":"string"}}},"UpdateIncidentStatusRequest":{"type":"object","required":["status","message"],"properties":{"message":{"type":"string"},"status":{"type":"string"}}},"UpdateIpAccessControlRequest":{"type":"object","description":"Request to update an IP access control rule","properties":{"action":{"type":["string","null"],"description":"Optional new action"},"ip_address":{"type":["string","null"],"description":"Optional new IP address"},"reason":{"type":["string","null"],"description":"Optional new reason"}}},"UpdateKvRequest":{"type":"object","description":"Request to update KV service configuration","properties":{"docker_image":{"type":["string","null"],"description":"Docker image to use (e.g., \"gotempsh/redis-walg:8-bookworm\")","example":"gotempsh/redis-walg:8-bookworm"}}},"UpdateKvResponse":{"type":"object","description":"Response after updating KV service","required":["success","message","status"],"properties":{"message":{"type":"string","description":"Status message","example":"KV service updated successfully"},"status":{"$ref":"#/components/schemas/KvStatusResponse","description":"Current service status"},"success":{"type":"boolean","description":"Whether the operation succeeded"}}},"UpdateManagedDomainApiRequest":{"type":"object","description":"Request to update a managed domain's settings.","properties":{"auto_manage":{"type":["boolean","null"],"description":"Toggle automatic DNS management for this domain."},"generated_hostname_mode":{"type":["string","null"],"description":"`\"standard\"` or `\"flat\"`. Persisted as-is; switching to `\"flat\"` does not\nrecompute existing hostnames — use the apply endpoint for that."},"sync_generated_records":{"type":["boolean","null"],"description":"Toggle DNS record sync for this domain."}}},"UpdateMcpRequest":{"type":"object","required":["config"],"properties":{"config":{"type":"object"},"description":{"type":["string","null"]},"name":{"type":["string","null"]}}},"UpdateMemberRoleRequest":{"type":"object","description":"The new fixed role for an existing membership.","required":["role"],"properties":{"role":{"$ref":"#/components/schemas/TeamRole"}}},"UpdateMetricAlertRequest":{"type":"object","properties":{"aggregation":{"type":["string","null"]},"detection_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DetectionConfig","description":"Replaces the detector wholesale when present (absent = leave unchanged)."}]},"dynamic_alerts":{"type":["boolean","null"],"description":"Toggles per-series (\"dynamic\") alerting (absent = leave unchanged)."},"enabled":{"type":["boolean","null"]},"for_duration_secs":{"type":["integer","null"],"format":"int32"},"group_by":{"type":["array","null"],"items":{"type":"string"},"description":"Replaces the group_by keys wholesale when present (absent = leave unchanged)."},"grouped_notification_threshold":{"type":["integer","null"],"format":"int32","description":"Updates the notification-grouping threshold (absent = leave unchanged)."},"label_filters":{"type":["array","null"],"items":{"type":"array","items":false,"prefixItems":[{"type":"string"},{"type":"string"}]},"description":"Replaces the label filters wholesale when present (absent = leave unchanged)."},"max_series":{"type":["integer","null"],"format":"int32","description":"Updates the dynamic-alerting cardinality cap (absent = leave unchanged)."},"metric_name":{"type":["string","null"]},"name":{"type":["string","null"]},"severity":{"type":["string","null"]},"window_secs":{"type":["integer","null"],"format":"int32"}}},"UpdateNotificationEmailProviderRequest":{"type":"object","required":["config"],"properties":{"config":{"$ref":"#/components/schemas/EmailConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":["string","null"]}}},"UpdateOidcProviderRequest":{"type":"object","properties":{"client_id":{"type":["string","null"]},"client_secret":{"type":["string","null"]},"default_role":{"type":["string","null"]},"enabled":{"type":["boolean","null"]},"group_claim":{"type":["string","null"]},"issuer_url":{"type":["string","null"]},"jit_provisioning":{"type":["boolean","null"]},"name":{"type":["string","null"]},"role_claim":{"type":["string","null"]},"scopes":{"type":["string","null"]},"template":{"type":["string","null"]},"trust_idp_email":{"type":["boolean","null"]}}},"UpdatePreferencesRequest":{"type":"object","required":["preferences"],"properties":{"preferences":{"$ref":"#/components/schemas/NotificationPreferencesResponse"}}},"UpdateProjectSecretRequest":{"type":"object","description":"Request to update a project secret. The `value` field is optional — omit it\nto rotate only the environment scoping / preview flag without touching the\nciphertext.","properties":{"environment_ids":{"type":"array","items":{"type":"integer","format":"int32"}},"include_in_preview":{"type":"boolean"},"value":{"type":["string","null"],"description":"New plaintext value, <= 1 MiB. Omit to keep the existing value."}}},"UpdateProjectSettingsRequest":{"type":"object","properties":{"ai_alert_summaries_enabled":{"type":["boolean","null"],"description":"Opt in to AI summarization of metric alert notifications (ADR-021)."},"ai_debug_chat_enabled":{"type":["boolean","null"],"description":"Opt in to AI debugging chat, e.g. on deployment failures (ADR-023)."},"ai_write_actions_enabled":{"type":["boolean","null"],"description":"Opt in to AI propose-then-confirm write capability."},"attack_mode":{"type":["boolean","null"],"description":"Enable/disable attack mode (CAPTCHA protection) for all project environments"},"cross_project_trace_sharing":{"type":["boolean","null"],"description":"ADR-027 Phase 3 opt-out: set to false to suppress this project's traces\nfrom appearing in cross-project discovery results. Default true (consistent\nwith the OSS global-observability model). Omit to leave unchanged."},"directory":{"type":["string","null"]},"enable_preview_environments":{"type":["boolean","null"],"description":"Enable automatic preview environment creation for each branch"},"error_source_context_enabled":{"type":["boolean","null"],"description":"Opt in to native error-tracking source context (source-file upload +\nsource code shown in stack traces)."},"error_source_root":{"type":["string","null"],"description":"Set the auto-capture source root (relative to the checkout). Send an\nempty string to clear it back to the build-context default. Omit to\nleave unchanged."},"git_provider_connection_id":{"type":["integer","null"],"format":"int32"},"main_branch":{"type":["string","null"]},"preset":{"type":["string","null"]},"preset_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PresetConfigSchema","description":"Preset-specific configuration (e.g., Dockerfile path for Docker preset)\n\nExample for Dockerfile preset:\n```json\n{\n \"dockerfilePath\": \"docker/Dockerfile\",\n \"buildContext\": \"./api\"\n}\n```"}]},"preview_envs_idle_timeout_seconds":{"type":["integer","null"],"format":"int32","description":"Idle timeout (seconds, 60..=86400) for on-demand preview environments."},"preview_envs_on_demand":{"type":["boolean","null"],"description":"When true, newly-created preview environments default to on-demand mode."},"preview_envs_wake_timeout_seconds":{"type":["integer","null"],"format":"int32","description":"Wake timeout (seconds, 5..=120) for on-demand preview environments."},"repo_name":{"type":["string","null"]},"repo_owner":{"type":["string","null"]},"slug":{"type":["string","null"]}}},"UpdateProviderCredentialsRequest":{"type":"object","description":"Partial-update payload for provider credentials. Every field is optional;\nonly the fields the user re-enters are applied. The server validates that\nthe fields supplied make sense for the provider's current auth_method\n(e.g. `app_id` + `private_key` only apply to GitHub Apps).","properties":{"app_id":{"type":["string","null"],"description":"Application ID (GitHub App integer as string; GitLab App string)."},"app_secret":{"type":["string","null"],"description":"GitLab App secret (not used by GitHub App — use `client_secret`)."},"client_id":{"type":["string","null"],"description":"OAuth client ID (GitLab OAuth, GitHub App)."},"client_secret":{"type":["string","null"],"description":"OAuth client secret (GitLab OAuth, GitHub App)."},"private_key":{"type":["string","null"],"description":"GitHub App private key (PEM)."},"redirect_uri":{"type":["string","null"],"description":"OAuth redirect URI (GitLab OAuth / GitLab App)."},"token":{"type":["string","null"],"description":"PAT for PAT-type providers."},"webhook_secret":{"type":["string","null"],"description":"GitHub App webhook secret."}}},"UpdateProviderKeyRequest":{"type":"object","properties":{"api_key":{"type":["string","null"]},"base_url":{"type":["string","null"],"description":"Double-Option: absent = leave unchanged, present-null = clear (revert to\nthe provider's default endpoint), present-value = set."},"default_model":{"type":["string","null"],"description":"Double-Option: absent = leave unchanged, present-null = clear the pinned\nmodel (revert to the per-provider default), present-value = set."},"display_name":{"type":["string","null"]},"is_active":{"type":["boolean","null"]}}},"UpdateProviderRequest":{"type":"object","properties":{"config":{},"enabled":{"type":["boolean","null"]},"name":{"type":["string","null"]}}},"UpdateRouteRequest":{"type":"object","required":["host","port","enabled"],"properties":{"enabled":{"type":"boolean"},"host":{"type":"string"},"port":{"type":"integer","format":"int32"},"route_type":{"type":["string","null"],"description":"Route type: \"http\" (default) matches on HTTP Host header,\n\"tls\" matches on TLS SNI hostname for TCP passthrough"}}},"UpdateS3SourceRequest":{"type":"object","properties":{"access_key_id":{"type":["string","null"],"description":"Optional new access key ID","example":"AKIAXXXXXXXXXXXXXXXX"},"bucket_name":{"type":["string","null"],"description":"Optional new bucket name"},"bucket_path":{"type":["string","null"],"description":"Optional new bucket path"},"endpoint":{"type":["string","null"],"description":"Optional new endpoint URL for S3-compatible services","example":"http://minio.example.com:9000"},"force_path_style":{"type":["boolean","null"],"description":"Optional new path-style addressing setting","example":true},"name":{"type":["string","null"],"description":"Optional new name for the source"},"region":{"type":["string","null"],"description":"Optional new region"},"secret_key":{"type":["string","null"],"description":"Optional new secret key"}}},"UpdateSecretBody":{"type":"object","required":["signing_secret"],"properties":{"signing_secret":{"type":"string","description":"New signing secret from the provider's dashboard. Encrypted at\nrest; never returned in any API response."}}},"UpdateSelfRequest":{"type":"object","properties":{"email":{"type":["string","null"],"example":"john.doe@example.com"},"name":{"type":["string","null"],"example":"John Doe"}}},"UpdateSessionDurationRequest":{"type":"object","required":["duration"],"properties":{"duration":{"type":"integer","format":"int32"}}},"UpdateSessionDurationResponse":{"type":"object","required":["message"],"properties":{"message":{"type":"string"}}},"UpdateSkillRequest":{"type":"object","properties":{"content":{"type":["string","null"]},"description":{"type":["string","null"]},"name":{"type":["string","null"]}}},"UpdateSlackProviderRequest":{"type":"object","required":["config"],"properties":{"config":{"$ref":"#/components/schemas/SlackConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":["string","null"]}}},"UpdateSpeedMetricsPayload":{"type":"object","description":"Update speed metrics payload for late-loading metrics","properties":{"cls":{"type":["number","null"],"format":"float","description":"Cumulative Layout Shift (score)"},"inp":{"type":["number","null"],"format":"float","description":"Interaction to Next Paint (milliseconds)"}}},"UpdateStatusResponse":{"type":"object","description":"Result of the background release-update check, driving the web console's\nupgrade banner. All optional fields are set together iff\n`update_available` is true.","required":["update_available","docs_url"],"properties":{"channel":{"type":["string","null"],"description":"Channel the install tracks: `stable` or `beta`."},"checked_at":{"type":["string","null"],"description":"When the check that found the update ran (ISO 8601, UTC)."},"current_version":{"type":["string","null"],"description":"Version tag of the running binary, e.g. `v0.1.0-beta.45`."},"docs_url":{"type":"string","description":"Docs page with upgrade instructions. Always present so the UI links\nthe same page regardless of update state."},"latest_version":{"type":["string","null"],"description":"Newest published tag on this install's channel."},"release_url":{"type":["string","null"],"description":"Release-notes page (GitHub release) for the newer version."},"update_available":{"type":"boolean","description":"True when a newer release than the running binary has been published\non this install's channel."}}},"UpdateTeamRequest":{"type":"object","properties":{"description":{"type":["string","null"]},"name":{"type":["string","null"]}}},"UpdateTokenRequest":{"type":"object","required":["access_token"],"properties":{"access_token":{"type":"string"},"refresh_token":{"type":["string","null"]}}},"UpdateTokenResponse":{"type":"object","required":["connection_id","message","is_active"],"properties":{"connection_id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"message":{"type":"string"}}},"UpdateUserRequest":{"type":"object","properties":{"email":{"type":["string","null"],"example":"john.doe@example.com"},"name":{"type":["string","null"],"example":"John Doe"}}},"UpdateWebhookProviderRequest":{"type":"object","required":["config"],"properties":{"config":{"$ref":"#/components/schemas/WebhookConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":["string","null"]}}},"UpdateWebhookRequestBody":{"type":"object","properties":{"enabled":{"type":["boolean","null"],"description":"Whether the webhook is enabled"},"events":{"type":["array","null"],"items":{"type":"string"},"description":"Event types to subscribe to"},"secret":{"type":["string","null"],"description":"Secret for HMAC signature verification"},"url":{"type":["string","null"],"description":"Target URL for webhook delivery"}}},"UpgradeExternalServiceRequest":{"type":"object","required":["docker_image"],"properties":{"docker_image":{"type":"string","description":"Docker image to upgrade to (e.g., \"gotempsh/postgres-walg:18-bookworm\")\nThis will trigger pg_upgrade for PostgreSQL or equivalent upgrade procedures for other services","example":"gotempsh/postgres-walg:18-bookworm"}}},"UpgradeRequest":{"type":"object","required":["image"],"properties":{"image":{"type":"string","description":"Image reference to pull and run (e.g.\n`ghcr.io/gotempsh/temps-preview-gateway:latest`). Empty resets to default."}}},"UpsertAgentRequest":{"type":"object","properties":{"ai_model":{"type":["string","null"],"description":"Preferred model identifier for the CLI. `Some(\"\")` clears the stored value."},"ai_provider":{"type":["string","null"]},"ai_provider_key_id":{"type":["integer","null"],"format":"int32"},"api_key":{"type":["string","null"],"description":"Plain-text API key — will be encrypted before storage"},"branch_prefix":{"type":["string","null"]},"config_repo_branch":{"type":["string","null"],"description":"Branch of the config repo to use (default: \"main\")."},"config_repo_url":{"type":["string","null"],"description":"Private config repo containing .claude/ directory (skills, MCP, plugins)."},"cooldown_minutes":{"type":["integer","null"],"format":"int32"},"daily_budget_cents":{"type":["integer","null"],"format":"int32"},"deliverable":{"type":["string","null"]},"description":{"type":["string","null"]},"enabled":{"type":["boolean","null"]},"max_turns":{"type":["integer","null"],"format":"int32"},"mcp_servers_config":{"description":"MCP servers config (Claude Code settings.json mcpServers format).\nCredential-bearing legacy inline objects are write-only: normal reads\nmask them, and updates must omit this field to preserve existing values."},"name":{"type":["string","null"]},"prompt":{"type":["string","null"]},"sandbox_enabled":{"type":["boolean","null"]},"skills_config":{"description":"Skills config as JSON array."},"slug":{"type":["string","null"]},"timeout_seconds":{"type":["integer","null"],"format":"int32"},"tools_config":{"description":"Tools config as JSON array. Custom-tool webhook URLs and headers are\nwrite-only; omit this field on update to preserve them."},"trigger_config":{"description":"Trigger configuration JSON: { \"error\": { \"new_issue\": true, \"regression\": true }, \"manual\": true }"}}},"UpsertSecretRequest":{"type":"object","required":["name","value"],"properties":{"description":{"type":["string","null"]},"mount_path":{"type":["string","null"],"description":"Required for \"file\" type secrets — absolute path inside the sandbox"},"name":{"type":"string"},"secret_type":{"type":"string","description":"\"env\" (environment variable) or \"file\" (written to mount_path)"},"value":{"type":"string"}}},"UptimeDataPoint":{"type":"object","required":["timestamp","status"],"properties":{"error_message":{"type":["string","null"]},"response_time_ms":{"type":["integer","null"],"format":"int32"},"status":{"type":"string"},"timestamp":{"type":"string","format":"date-time"}}},"UptimeHistoryResponse":{"type":"object","required":["monitor_id","uptime_data"],"properties":{"monitor_id":{"type":"integer","format":"int32"},"uptime_data":{"type":"array","items":{"$ref":"#/components/schemas/UptimeDataPoint"}}}},"UsageFilter":{"type":"object","description":"Filters for querying AI usage data.\n\nCost bounds are expressed in microcents (the unit stored in\n`estimated_cost_microcents`). At most one of `gte`/`gt` and one of\n`lte`/`lt` is meaningful per query; if both are set the stricter wins\nnaturally because they are ANDead together.","properties":{"conversation_id":{"type":["string","null"]},"cost_gt":{"type":["integer","null"],"format":"int64","description":"Cost strictly greater-than, in microcents."},"cost_gte":{"type":["integer","null"],"format":"int64","description":"Cost greater-than-or-equal, in microcents."},"cost_lt":{"type":["integer","null"],"format":"int64","description":"Cost strictly less-than, in microcents."},"cost_lte":{"type":["integer","null"],"format":"int64","description":"Cost less-than-or-equal, in microcents."},"model":{"type":["string","null"]},"provider":{"type":["string","null"]},"status":{"type":["integer","null"],"format":"int32","description":"Filter by HTTP status code (exact match)."},"tags":{"type":["string","null"],"description":"Comma-separated tags to filter by (AND logic)."},"tokens_gt":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) strictly greater-than."},"tokens_gte":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) greater-than-or-equal."},"tokens_lt":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) strictly less-than."},"tokens_lte":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) less-than-or-equal."},"user_id":{"type":["integer","null"],"format":"int32"}}},"UsageInfo":{"type":"object","required":["prompt_tokens","completion_tokens","total_tokens"],"properties":{"completion_tokens":{"type":"integer","format":"int64"},"prompt_tokens":{"type":"integer","format":"int64"},"total_tokens":{"type":"integer","format":"int64"}}},"UsageLogEntry":{"type":"object","required":["id","timestamp","provider","model","input_tokens","output_tokens","latency_ms","estimated_cost_microcents","status","is_streaming","is_byok","tags"],"properties":{"conversation_id":{"type":["string","null"]},"estimated_cost_microcents":{"type":"integer","format":"int64"},"id":{"type":"integer","format":"int64"},"input_tokens":{"type":"integer","format":"int64"},"is_byok":{"type":"boolean"},"is_streaming":{"type":"boolean"},"latency_ms":{"type":"integer","format":"int32"},"model":{"type":"string"},"output_tokens":{"type":"integer","format":"int64"},"provider":{"type":"string"},"request_id":{"type":["string","null"]},"status":{"type":"integer","format":"int32"},"tags":{"type":"array","items":{"type":"string"}},"timestamp":{"type":"string"},"trace_id":{"type":["string","null"]}}},"UsageLogPage":{"type":"object","description":"A page of recent usage log entries plus the total count for pagination.","required":["entries","total"],"properties":{"entries":{"type":"array","items":{"$ref":"#/components/schemas/UsageLogEntry"},"description":"The usage log entries for the requested page."},"total":{"type":"integer","format":"int64","description":"Total number of entries matching the filter (across all pages)."}}},"UsageQueryParams":{"type":"object","properties":{"conversation_id":{"type":["string","null"],"description":"Filter by conversation ID"},"from":{"type":["string","null"],"description":"ISO 8601 start time (defaults to 24h ago)"},"model":{"type":["string","null"],"description":"Filter by model name"},"provider":{"type":["string","null"],"description":"Filter by provider name"},"tags":{"type":["string","null"],"description":"Filter by tags (comma-separated, AND logic)"},"to":{"type":["string","null"],"description":"ISO 8601 end time (defaults to now)"},"user_id":{"type":["integer","null"],"format":"int32","description":"Filter by user ID"}}},"UsageSource":{"type":"string","description":"How the \"actual usage\" numbers were obtained","enum":["metrics-api","requests-only","unavailable"]},"UsageSummary":{"type":"object","required":["total_requests","total_input_tokens","total_output_tokens","total_tokens","avg_latency_ms","total_cost_microcents","error_count","streaming_count","byok_count"],"properties":{"avg_latency_ms":{"type":"number","format":"double"},"byok_count":{"type":"integer","format":"int64"},"error_count":{"type":"integer","format":"int64"},"streaming_count":{"type":"integer","format":"int64"},"total_cost_microcents":{"type":"integer","format":"int64"},"total_input_tokens":{"type":"integer","format":"int64"},"total_output_tokens":{"type":"integer","format":"int64"},"total_requests":{"type":"integer","format":"int64"},"total_tokens":{"type":"integer","format":"int64"}}},"UserResponse":{"type":"object","required":["id","username","name","avatar_url","mfa_enabled","role"],"properties":{"avatar_url":{"type":"string"},"email":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"mfa_enabled":{"type":"boolean"},"name":{"type":"string"},"role":{"type":"string","description":"User's role (e.g., \"admin\", \"user\", \"demo\")"},"username":{"type":"string"}}},"ValidateEmailRequest":{"type":"object","description":"Request body for validating an email address","required":["email"],"properties":{"email":{"type":"string","description":"Email address to validate","example":"someone@gmail.com"}},"additionalProperties":false},"ValidateEmailResponse":{"type":"object","description":"Complete email validation response","required":["email","is_reachable","syntax","mx","misc","smtp"],"properties":{"email":{"type":"string","description":"The email address that was validated","example":"someone@gmail.com"},"is_reachable":{"$ref":"#/components/schemas/ReachabilityStatus","description":"Overall reachability status: safe, risky, invalid, or unknown"},"misc":{"$ref":"#/components/schemas/MiscResult","description":"Miscellaneous validation result"},"mx":{"$ref":"#/components/schemas/MxResult","description":"MX record validation result"},"smtp":{"$ref":"#/components/schemas/SmtpResult","description":"SMTP validation result"},"syntax":{"$ref":"#/components/schemas/SyntaxResult","description":"Syntax validation result"}}},"ValidationLevel":{"type":"string","description":"Validation severity level","enum":["info","warning","error","critical"]},"ValidationReport":{"type":"object","description":"Complete validation report","required":["results","overall_status","summary"],"properties":{"overall_status":{"$ref":"#/components/schemas/ValidationStatus","description":"Overall status"},"results":{"type":"array","items":{"$ref":"#/components/schemas/ValidationResult"},"description":"All validation results"},"summary":{"$ref":"#/components/schemas/ValidationSummary","description":"Summary statistics"}}},"ValidationResponse":{"type":"object","required":["connection_id","is_valid","message"],"properties":{"connection_id":{"type":"integer","format":"int32"},"is_valid":{"type":"boolean"},"message":{"type":"string"}}},"ValidationResult":{"type":"object","description":"Result of a validation check","required":["rule_id","rule_name","level","passed","message","affected_resources"],"properties":{"affected_resources":{"type":"array","items":{"type":"string"},"description":"Affected resources/fields"},"level":{"$ref":"#/components/schemas/ValidationLevel","description":"Validation level"},"message":{"type":"string","description":"Message describing the result"},"passed":{"type":"boolean","description":"Whether the validation passed"},"remediation":{"type":["string","null"],"description":"Suggested remediation (if failed)"},"rule_id":{"type":"string","description":"Rule that was checked"},"rule_name":{"type":"string","description":"Human-readable rule name"}}},"ValidationStatus":{"type":"string","description":"Overall validation status","enum":["passed","passed-with-warnings","failed-with-warnings","failed"]},"ValidationSummary":{"type":"object","description":"Validation summary statistics","required":["total_count","passed_count","failed_count","info_count","warning_count","error_count","critical_count"],"properties":{"critical_count":{"type":"integer","description":"Critical-level results","minimum":0},"error_count":{"type":"integer","description":"Error-level results","minimum":0},"failed_count":{"type":"integer","description":"Validations that failed","minimum":0},"info_count":{"type":"integer","description":"Info-level results","minimum":0},"passed_count":{"type":"integer","description":"Validations that passed","minimum":0},"total_count":{"type":"integer","description":"Total validations run","minimum":0},"warning_count":{"type":"integer","description":"Warning-level results","minimum":0}}},"VerifyMfaRequest":{"type":"object","required":["code"],"properties":{"code":{"type":"string"}}},"VerifyStepUpRequest":{"type":"object","required":["code"],"properties":{"code":{"type":"string","description":"Current TOTP value or an unused recovery code."}}},"ViewItem":{"type":"object","required":["label","value"],"properties":{"label":{"type":"string","format":"date-time"},"value":{"type":"integer","format":"int64"}}},"ViewsOverTime":{"type":"object","required":["items","metric","present_index"],"properties":{"comparison_labels":{"type":["array","null"],"items":{"type":"string"}},"comparison_plot":{"type":["array","null"],"items":{"type":"integer","format":"int64"}},"full_intervals":{"type":["array","null"],"items":{"type":"string"}},"items":{"type":"array","items":{"$ref":"#/components/schemas/ViewItem"}},"metric":{"type":"string"},"present_index":{"type":"integer","minimum":0}}},"ViewsOverTimeQuery":{"type":"object","required":["start_date","end_date","project_id"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"VisitorDetails":{"type":"object","required":["id","visitor_id","project_id","environment_id","first_seen","last_seen","is_crawler"],"properties":{"city":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"crawler_name":{"type":["string","null"]},"custom_data":{},"environment_id":{"type":"integer","format":"int32"},"first_channel":{"type":["string","null"],"description":"Marketing channel from the first visit (e.g. \"Organic Search\", \"Direct\")"},"first_referrer":{"type":["string","null"],"description":"Full referrer URL from the visitor's first session"},"first_referrer_hostname":{"type":["string","null"],"description":"Hostname extracted from first_referrer"},"first_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"id":{"type":"integer","format":"int32"},"ip_address":{"type":["string","null"]},"ip_address_id":{"type":["integer","null"],"format":"int32"},"is_crawler":{"type":"boolean"},"is_eu":{"type":["boolean","null"]},"last_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"latitude":{"type":["number","null"],"format":"double"},"longitude":{"type":["number","null"],"format":"double"},"project_id":{"type":"integer","format":"int32"},"region":{"type":["string","null"]},"timezone":{"type":["string","null"]},"user_agent":{"type":["string","null"]},"visitor_id":{"type":"string"}}},"VisitorFacetValue":{"type":"object","description":"A single facet value with its visitor count. Used to populate filter\ndropdowns on the visitors page (e.g. \"Germany — 1,234 visitors\").","required":["value","count"],"properties":{"code":{"type":["string","null"],"description":"Optional secondary code for the value. Currently only populated for\nthe `country` facet, where it carries the 2-letter ISO country code\nso the UI can render a flag without re-mapping."},"count":{"type":"integer","format":"int64","description":"Distinct visitor count matching this value in the current segment."},"value":{"type":"string","description":"The dimension value (e.g. \"United States\", \"Chrome\", \"google.com\").\n`None` is encoded as the literal string \"Direct\" for referrer and as\nthe empty string for the rest."}}},"VisitorFacets":{"type":"object","description":"All filter dropdown contents in one response. Each list is the top N\nvalues for that dimension within the current date range and segment\n(excluding the dimension being queried so the dropdown still shows\nalternatives when a value is already selected).","required":["country","region","city","channel","referrer"],"properties":{"channel":{"type":"array","items":{"$ref":"#/components/schemas/VisitorFacetValue"}},"city":{"type":"array","items":{"$ref":"#/components/schemas/VisitorFacetValue"}},"country":{"type":"array","items":{"$ref":"#/components/schemas/VisitorFacetValue"}},"referrer":{"type":"array","items":{"$ref":"#/components/schemas/VisitorFacetValue"}},"region":{"type":"array","items":{"$ref":"#/components/schemas/VisitorFacetValue"}}}},"VisitorFacetsQuery":{"allOf":[{"$ref":"#/components/schemas/VisitorSegmentFilters"},{"type":"object","required":["start_date","end_date","project_id"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"has_activity_only":{"type":["boolean","null"]},"include_crawlers":{"type":["boolean","null"]},"per_facet_limit":{"type":["integer","null"],"format":"int32","description":"Maximum number of values returned per dimension (default: 50, max: 200)."},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}}],"description":"Query parameters for the visitor-facets endpoint. Mirrors the shape of\n`VisitorsListQuery` so the same segment filters apply — facet counts are\nalways computed against the *currently filtered* visitor pool, minus the\ndimension being aggregated."},"VisitorInfo":{"type":"object","required":["id","visitor_id","project_id","environment_id","first_seen","last_seen","is_crawler"],"properties":{"city":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"crawler_name":{"type":["string","null"]},"current_page":{"type":["string","null"],"description":"Most recent page path visited by this visitor"},"custom_data":{},"environment_id":{"type":"integer","format":"int32"},"first_channel":{"type":["string","null"],"description":"Marketing channel from the first visit (e.g. \"Organic Search\", \"Direct\")"},"first_referrer":{"type":["string","null"],"description":"Full referrer URL from the visitor's first session"},"first_referrer_hostname":{"type":["string","null"],"description":"Hostname extracted from first_referrer"},"first_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"id":{"type":"integer","format":"int32"},"ip_address":{"type":["string","null"]},"ip_address_id":{"type":["integer","null"],"format":"int32"},"is_crawler":{"type":"boolean"},"is_eu":{"type":["boolean","null"]},"last_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"latitude":{"type":["number","null"],"format":"double"},"longitude":{"type":["number","null"],"format":"double"},"project_id":{"type":"integer","format":"int32"},"region":{"type":["string","null"]},"timezone":{"type":["string","null"]},"user_agent":{"type":["string","null"]},"visitor_id":{"type":"string"}}},"VisitorJourneyQuery":{"type":"object","required":["project_id"],"properties":{"limit_sessions":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"}}},"VisitorJourneyResponse":{"type":"object","description":"Complete visitor journey response","required":["visitor_id","total_sessions","total_events","sessions"],"properties":{"sessions":{"type":"array","items":{"$ref":"#/components/schemas/JourneySession"},"description":"Sessions with their events, ordered newest first"},"total_events":{"type":"integer","format":"int64","description":"Total number of events across all sessions"},"total_sessions":{"type":"integer","format":"int64","description":"Total number of sessions"},"visitor_id":{"type":"integer","format":"int32","description":"Visitor internal ID"}}},"VisitorLocationsQuery":{"type":"object","required":["start_date","end_date","project_id"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"granularity":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/LocationGranularity"}]},"limit":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"VisitorRecord":{"type":"object","required":["id","visitor_id","project_id","created_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"custom_data":{},"id":{"type":"integer","format":"int32"},"project_id":{"type":"integer","format":"int32"},"visitor_id":{"type":"string"}}},"VisitorSegmentFilters":{"type":"object","description":"Optional segment filters for [`VisitorsListQuery`]. Each filter narrows the\nresult set to visitors who match the given dimension value within the date\nrange. All filters resolve against `visitor` / `ip_geolocations` — by\ndesign we never touch the events hypertable here so filtering stays fast\nregardless of event volume.","properties":{"filter_channel":{"type":["string","null"],"description":"First-touch marketing channel (matches `visitor.first_channel`)"},"filter_city":{"type":["string","null"],"description":"Geolocation city (matches `ip_geolocations.city`)"},"filter_country":{"type":["string","null"],"description":"Geolocation country (matches `ip_geolocations.country`)"},"filter_referrer":{"type":["string","null"],"description":"First-touch referrer hostname (matches `visitor.first_referrer_hostname`)"},"filter_region":{"type":["string","null"],"description":"Geolocation region (matches `ip_geolocations.region`)"}}},"VisitorSessionsQuery":{"type":"object","required":["project_id"],"properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"}}},"VisitorSessionsResponse":{"type":"object","required":["visitor_id","sessions","total_sessions"],"properties":{"sessions":{"type":"array","items":{"$ref":"#/components/schemas/SessionSummary"}},"total_sessions":{"type":"integer","format":"int64"},"visitor_id":{"type":"string"}}},"VisitorStats":{"type":"object","required":["visitor_id","first_seen","last_seen","total_sessions","total_page_views","total_events","average_session_duration","bounce_rate","engagement_rate","top_pages","top_referrers","devices_used","locations"],"properties":{"average_session_duration":{"type":"number","format":"double"},"bounce_rate":{"type":"number","format":"double"},"devices_used":{"type":"array","items":{"type":"string"}},"engagement_rate":{"type":"number","format":"double"},"first_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"last_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"locations":{"type":"array","items":{"$ref":"#/components/schemas/LocationInfo"}},"top_pages":{"type":"array","items":{"$ref":"#/components/schemas/PageVisit"}},"top_referrers":{"type":"array","items":{"type":"string"}},"total_events":{"type":"integer","format":"int64"},"total_page_views":{"type":"integer","format":"int64"},"total_sessions":{"type":"integer","format":"int64"},"visitor_id":{"type":"integer","format":"int32"}}},"VisitorWithGeolocation":{"type":"object","required":["id","visitor_id","project_id","environment_id","first_seen","last_seen","is_crawler"],"properties":{"city":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"crawler_name":{"type":["string","null"]},"custom_data":{},"environment_id":{"type":"integer","format":"int32"},"first_channel":{"type":["string","null"],"description":"Marketing channel from the first visit (e.g. \"Organic Search\", \"Direct\")"},"first_referrer":{"type":["string","null"],"description":"Full referrer URL from the visitor's first session"},"first_referrer_hostname":{"type":["string","null"],"description":"Hostname extracted from first_referrer"},"first_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"id":{"type":"integer","format":"int32"},"ip_address":{"type":["string","null"]},"is_crawler":{"type":"boolean"},"is_eu":{"type":["boolean","null"]},"last_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"latitude":{"type":["number","null"],"format":"double"},"longitude":{"type":["number","null"],"format":"double"},"project_id":{"type":"integer","format":"int32"},"region":{"type":["string","null"]},"timezone":{"type":["string","null"]},"user_agent":{"type":["string","null"]},"visitor_id":{"type":"string"}}},"VisitorsListQuery":{"allOf":[{"$ref":"#/components/schemas/VisitorSegmentFilters"},{"type":"object","required":["start_date","end_date","project_id"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"has_activity_only":{"type":["boolean","null"],"description":"Filter to only include visitors with recorded activity (events/sessions).\nWhen true, excludes \"ghost\" visitors that have no events."},"include_crawlers":{"type":["boolean","null"]},"limit":{"type":["integer","null"],"format":"int32"},"offset":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}}]},"VisitorsResponse":{"type":"object","required":["visitors","total_count","filtered_count"],"properties":{"filtered_count":{"type":"integer","format":"int64"},"total_count":{"type":"integer","format":"int64"},"visitors":{"type":"array","items":{"$ref":"#/components/schemas/VisitorInfo"}}}},"VolumeMount":{"type":"object","description":"Volume mount in deployment","required":["source","destination","read_only","type"],"properties":{"destination":{"type":"string","description":"Destination path in container"},"read_only":{"type":"boolean","description":"Read-only flag"},"source":{"type":"string","description":"Source (volume name or path)"},"type":{"$ref":"#/components/schemas/VolumeType","description":"Volume type"}}},"VolumeType":{"type":"string","description":"Volume type","enum":["bind","volume","tmpfs"]},"VulnerabilityResponse":{"type":"object","required":["id","scan_id","vulnerability_id","package_name","installed_version","severity","title","created_at"],"properties":{"class":{"type":["string","null"],"example":"os-pkgs"},"created_at":{"type":"string","example":"2025-12-08T12:15:47.609192Z"},"cvss_score":{"type":["number","null"],"format":"float"},"description":{"type":["string","null"]},"fixed_version":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"installed_version":{"type":"string"},"last_modified_date":{"type":["string","null"],"example":"2025-12-08T12:15:47.609192Z"},"package_name":{"type":"string"},"primary_url":{"type":["string","null"]},"published_date":{"type":["string","null"],"example":"2025-12-08T12:15:47.609192Z"},"references":{},"scan_id":{"type":"integer","format":"int32"},"severity":{"type":"string"},"target":{"type":["string","null"],"example":"alpine:3.18 (alpine 3.18.0)"},"title":{"type":"string"},"type":{"type":["string","null"],"example":"alpine"},"vulnerability_id":{"type":"string"}}},"WalWarning":{"oneOf":[{"type":"object","description":"`pg_wal` is significantly larger than `max_wal_size`.","required":["pg_wal_bytes","max_wal_size_bytes","ratio","kind"],"properties":{"kind":{"type":"string","enum":["wal_bloat"]},"max_wal_size_bytes":{"type":"integer","format":"int64"},"pg_wal_bytes":{"type":"integer","format":"int64"},"ratio":{"type":"number","format":"double"}}},{"type":"object","description":"A replication slot is holding WAL it's not consuming.","required":["slot_name","retained_bytes","active","kind"],"properties":{"active":{"type":"boolean"},"kind":{"type":"string","enum":["stale_slot"]},"retained_bytes":{"type":"integer","format":"int64"},"slot_name":{"type":"string"}}},{"type":"object","description":"`archive_status/*.ready` count exceeds threshold — `archive_command`\nis either failing or running slower than WAL generation.","required":["ready_count","kind"],"properties":{"kind":{"type":"string","enum":["archive_backlog"]},"ready_count":{"type":"integer","format":"int64"}}},{"type":"object","description":"`archive_mode = on` but `archive_command` is empty / `/bin/true`.\nWAL accumulates forever waiting for a destination that never accepts.","required":["kind"],"properties":{"kind":{"type":"string","enum":["archive_mode_without_command"]}}},{"type":"object","description":"Oldest WAL segment is older than `WAL_NOT_RECYCLED_AGE_SECS`.\nIndependent signal: something is blocking recycling even if total\nsize hasn't exploded yet.","required":["oldest_age_secs","kind"],"properties":{"kind":{"type":"string","enum":["wal_not_recycled"]},"oldest_age_secs":{"type":"integer","format":"int64"}}}],"description":"One actionable warning surfaced to the UI.\n\nEach variant carries the data needed to render a remediation hint without\nthe frontend re-querying anything."},"WalWarningSeverity":{"type":"string","enum":["warning","critical"]},"WebhookConfig":{"type":"object","description":"Configuration for a generic webhook notification provider","required":["url"],"properties":{"headers":{"type":"object","description":"Custom headers to include in the request (e.g., for authentication tokens)","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"},"example":{"Authorization":"Bearer your-token","X-Custom-Header":"custom-value"}},"method":{"type":"string","description":"HTTP method to use (POST, PUT, PATCH). Defaults to POST.","example":"POST"},"timeout_secs":{"type":"integer","format":"int64","description":"Request timeout in seconds. Defaults to 30.","example":30,"minimum":0},"url":{"type":"string","description":"The URL to send webhook requests to","example":"https://api.example.com/notifications"}}},"WebhookDeliveryResponse":{"type":"object","required":["id","webhook_id","event_type","event_id","payload","success","attempt_number","created_at"],"properties":{"attempt_number":{"type":"integer","format":"int32"},"created_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"delivered_at":{"type":["string","null"],"format":"date-time"},"error_message":{"type":["string","null"]},"event_id":{"type":"string"},"event_type":{"type":"string"},"id":{"type":"integer","format":"int32"},"payload":{"type":"string","description":"JSON payload that was sent to the webhook endpoint","example":{"event_type":"deployment.succeeded","data":{"deployment_id":123}}},"status_code":{"type":["integer","null"],"format":"int32"},"success":{"type":"boolean"},"webhook_id":{"type":"integer","format":"int32"}}},"WebhookResponse":{"type":"object","required":["id","project_id","url","events","enabled","has_secret","created_at","updated_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"enabled":{"type":"boolean"},"events":{"type":"array","items":{"type":"string"}},"has_secret":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"project_id":{"type":"integer","format":"int32"},"updated_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"url":{"type":"string"}}},"WebhookTriggerRequest":{"allOf":[{"description":"Arbitrary JSON payload from the caller. Passed to the agent as user_context."}]},"WebhookTriggerResponse":{"type":"object","required":["run_id","status"],"properties":{"run_id":{"type":"integer","format":"int32"},"status":{"type":"string"}}},"WorkflowDryRunRequest":{"type":"object","required":["yaml"],"properties":{"cpu_limit":{"type":["number","null"],"format":"double","description":"Optional CPU override applied after parsing YAML (clamped server-side).\nWhen `Some`, this takes precedence over `cpu_limit` inside the YAML —\nlets the CLI pass `--cpu` without rewriting the YAML text."},"error_group_id":{"type":["integer","null"],"format":"int32","description":"Optional error group to link this dry-run to. When set, the executor's\n`load_error_context` path injects `{{error_type}}` / `{{error_message}}`\n/ `{{stack_trace}}` into the prompt — same behaviour as a committed\nworkflow triggered with `trigger_source_type = \"error_group\"`. Must\nbelong to `project_id` (handler enforces)."},"memory_limit_mb":{"type":["integer","null"],"format":"int64","description":"Optional memory override in MB (clamped server-side). Same precedence\nrule as `cpu_limit`.","minimum":0},"user_context":{"type":["string","null"],"description":"Optional context appended to the prompt (e.g. \"test against staging\nonly\"). Mirrors `TriggerAgentRequest.user_context`."},"yaml":{"type":"string","description":"Full WorkflowYamlConfig as YAML text. Server validates and re-serializes\nbefore storing on the run row."}}},"WorkloadDescriptor":{"type":"object","description":"Brief descriptor for discovered workloads (used in listing)","required":["id","workload_type","status","labels"],"properties":{"created_at":{"type":["string","null"],"format":"date-time","description":"Creation timestamp"},"id":{"$ref":"#/components/schemas/WorkloadId","description":"Unique ID in source system"},"image":{"type":["string","null"],"description":"Image/build reference (for containers)"},"labels":{"type":"object","description":"Labels/tags from source system","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"name":{"type":["string","null"],"description":"Workload name (if any)"},"status":{"$ref":"#/components/schemas/WorkloadStatus","description":"Current status"},"workload_type":{"$ref":"#/components/schemas/WorkloadType","description":"Workload type (container, function, static-site, etc.)"}}},"WorkloadId":{"type":"string","description":"Unique identifier for a workload in the source system"},"WorkloadStatus":{"type":"string","description":"Workload status in source system","enum":["running","paused","stopped","exited","failed","deployed","building","unknown"]},"WorkloadType":{"type":"string","description":"Workload type","enum":["container","function","static-site","server-side-app","worker","database","message-queue","cache","cron-job","other"]},"WriteFileBody":{"type":"object","required":["path","contents_b64"],"properties":{"contents_b64":{"type":"string","description":"File contents, base64-encoded. Required — lets callers ship binary\ndata over JSON without charset games."},"mode":{"type":["integer","null"],"format":"int32","description":"Unix permission mask (e.g. 0o644). Defaults to 0o644 when absent.","minimum":0},"path":{"type":"string","description":"Absolute path inside the sandbox. Must start with `/`."}},"additionalProperties":false},"WriteFilesBody":{"type":"object","required":["files"],"properties":{"files":{"type":"array","items":{"$ref":"#/components/schemas/WriteFileBody"},"description":"List of files to write. Each entry must include an absolute\n`path` and base64-encoded `contents_b64`. Empty list is a no-op."}},"additionalProperties":false},"WriteFilesResponse":{"type":"object","required":["written"],"properties":{"written":{"type":"integer","description":"Number of files successfully written before the first failure\n(if any). On full success this equals `files.len()`.","minimum":0}}},"ZoneListResponse":{"type":"object","description":"Zone list response","required":["zones"],"properties":{"zones":{"type":"array","items":{"$ref":"#/components/schemas/DnsZone"}}}}},"securitySchemes":{"bearer_auth":{"type":"http","scheme":"bearer","description":"Bearer token authentication. Use format: `Bearer `. Supports API keys (starting with `tk_`), CLI tokens, and session tokens."}}},"tags":[{"name":"Events","description":"Analytics events tracking endpoints"},{"name":"Metrics","description":"Analytics metrics collection endpoints including performance web vitals"},{"name":"Funnels","description":"Funnel management endpoints"},{"name":"Analytics","description":"Analytics and session replay management"},{"name":"Performance","description":"Performance metrics management"},{"name":"geo","description":"Geolocation API endpoints"},{"name":"Platform","description":"Platform information and compatibility"},{"name":"Teams","description":"Teams and project-scoped access"},{"name":"Git Providers","description":"Git provider management endpoints"},{"name":"Repositories","description":"Repository management endpoints"},{"name":"Public Repositories","description":"Endpoints for accessing public repositories without authentication. Supports GitHub and GitLab."},{"name":"Notification Providers","description":"Notification provider management endpoints"},{"name":"Notification Preferences","description":"User notification preferences and settings"},{"name":"DNS Providers","description":"DNS provider management endpoints"},{"name":"Internal DNS","description":"Per-node DNS resolver sync (ADR-011)"},{"name":"Domains","description":"Domain management endpoints"},{"name":"Email Providers","description":"Email provider management endpoints"},{"name":"Email Domains","description":"Email domain management and verification"},{"name":"Emails","description":"Email sending and retrieval"},{"name":"Email Tracking","description":"Email open and click tracking"},{"name":"Email Validation","description":"Email address validation and verification"},{"name":"Webhooks","description":"Webhook management endpoints"},{"name":"Webhook Deliveries","description":"Webhook delivery history and retry endpoints"},{"name":"External Services","description":"External service integration endpoints"},{"name":"External Services - Query","description":"Data querying and exploration endpoints"},{"name":"Metrics","description":"Time-series metrics and alert rule endpoints"},{"name":"KV Store","description":"Key-Value storage operations"},{"name":"KV Management","description":"KV service management operations"},{"name":"Blob","description":"Blob storage operations"},{"name":"Blob Management","description":"Blob service management operations"},{"name":"Feature Flags","description":"Runtime configuration that changes without a redeploy"},{"name":"Environments","description":"Environment management operations"},{"name":"Secrets","description":"File-mounted secrets (/run/secrets/)"},{"name":"Projects","description":"Project management endpoints"},{"name":"Presets","description":"Available deployment presets"},{"name":"Templates","description":"Project template endpoints"},{"name":"Custom Domains","description":"Custom domain management for projects"},{"name":"error-tracking","description":"Error tracking data fetching endpoints"},{"name":"Vulnerability Scans","description":"Vulnerability scan management endpoints"},{"name":"Agents","description":"Autonomous AI agents, autofixer (interactive AI debugging), skills/MCP definitions, and preview gateway management."},{"name":"Crons","description":"Cron jobs management API"},{"name":"Sandboxes","description":"Standalone sandbox API (`/v1/sandboxes/*`) for running isolated containers."},{"name":"Logs","description":"Log search, context, live tail, and retention management"},{"name":"Imports","description":"Import workloads from external sources"},{"name":"Status Page","description":"Status page and monitoring endpoints"},{"name":"OTel Ingest","description":"OTLP/HTTP ingest endpoints (protobuf)"},{"name":"OTel","description":"Query endpoints for the monitoring UI"},{"name":"GenAI","description":"GenAI agent activity tracing endpoints"},{"name":"Alarms","description":"Unified alarm history — list, summarise, acknowledge, resolve"},{"name":"Authentication","description":"Authentication and authorization endpoints"},{"name":"Users","description":"User management endpoints"},{"name":"Backups","description":"Backup management endpoints"},{"name":"Restore","description":"External service restore operations"},{"name":"Revenue","description":"Per-project revenue tracking integrations and analytics"},{"name":"Observability","description":"Unified observability event stream — runtime logs, requests, spans, errors, revenue"},{"name":"AI Gateway","description":"OpenAI-compatible chat, embeddings, and model endpoints"},{"name":"AI Gateway Admin","description":"Provider key management endpoints"},{"name":"AI Gateway Usage","description":"Usage analytics and reporting endpoints"},{"name":"AI Gateway Pricing","description":"Model pricing endpoints"},{"name":"API Keys","description":"API key management endpoints"},{"name":"Load Balancer","description":"Load balancer management endpoints"},{"name":"IP Access Control","description":"IP access control management endpoints"},{"name":"Files","description":"Static file serving endpoints"},{"name":"External Plugins","description":"External plugin management and discovery"}]} +{"openapi":"3.1.0","info":{"title":"Temps","description":"An API for managing projects, deployments, and infrastructure resources","contact":{"name":"Temps Support","url":"https://temps.sh"},"version":"1.0.0"},"servers":[{"url":"/api","description":"Base path for all API endpoints"}],"paths":{"/.well-known/temps.json":{"get":{"tags":["Platform"],"summary":"Get platform information","operationId":"get_platform_info","responses":{"200":{"description":"Successfully retrieved platform information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlatformInfo"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/0/organizations/{org_slug}/chunk-upload/":{"get":{"tags":["sentry-compat"],"summary":"Chunk upload options (stub for sentry-cli compatibility).","description":"sentry-cli checks this endpoint to determine if chunk-based upload is supported.\nWe return a response indicating that chunk upload is NOT supported, which forces\nsentry-cli to fall back to the standard file-by-file upload.","operationId":"chunk_upload_options","parameters":[{"name":"org_slug","in":"path","description":"Organization slug (ignored)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Chunk upload options","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryChunkUploadResponse"}}}}}}},"/0/organizations/{org_slug}/releases/":{"post":{"tags":["sentry-compat"],"summary":"Create a release (stub for sentry-cli compatibility).","description":"sentry-cli calls this before uploading files. Since Temps implicitly creates\nreleases when source maps are uploaded, this is a no-op that returns the\nexpected response format.","operationId":"create_release","parameters":[{"name":"org_slug","in":"path","description":"Organization slug (ignored in single-tenant mode)","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryCreateReleaseRequest"}}},"required":true},"responses":{"201":{"description":"Release created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryReleaseResponse"}}}},"401":{"description":"Unauthorized"}}}},"/0/projects/{org_slug}/{project_slug}/releases/":{"post":{"tags":["sentry-compat"],"summary":"Create a release for a specific project (stub for sentry-cli compatibility).","description":"sentry-cli calls this endpoint (instead of /organizations/.../releases/) when\nboth SENTRY_ORG and SENTRY_PROJECT env vars are set. Behaves identically to\nthe organizations endpoint but validates the project slug.","operationId":"create_project_release","parameters":[{"name":"org_slug","in":"path","description":"Organization slug (ignored in single-tenant mode)","required":true,"schema":{"type":"string"}},{"name":"project_slug","in":"path","description":"Project slug or numeric ID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryCreateReleaseRequest"}}},"required":true},"responses":{"201":{"description":"Release created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryReleaseResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Project not found"}}}},"/0/projects/{org_slug}/{project_slug}/releases/{version}/":{"put":{"tags":["sentry-compat"],"summary":"Finalize a release (stub for sentry-cli compatibility).","description":"sentry-cli calls `releases finalize` after uploading source maps. This sets\nthe dateReleased on the release. Since Temps stores source maps independently\nof releases, this is a no-op that returns the expected response.","operationId":"finalize_project_release","parameters":[{"name":"org_slug","in":"path","description":"Organization slug (ignored)","required":true,"schema":{"type":"string"}},{"name":"project_slug","in":"path","description":"Project slug or numeric ID","required":true,"schema":{"type":"string"}},{"name":"version","in":"path","description":"Release version to finalize","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Release finalized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryReleaseResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Project not found"}}}},"/0/projects/{org_slug}/{project_slug}/releases/{version}/files/":{"get":{"tags":["sentry-compat"],"summary":"List files for a release.","description":"Returns all source maps stored for a specific release in sentry-cli compatible format.","operationId":"list_release_files","parameters":[{"name":"org_slug","in":"path","description":"Organization slug (ignored)","required":true,"schema":{"type":"string"}},{"name":"project_slug","in":"path","description":"Project slug or numeric ID","required":true,"schema":{"type":"string"}},{"name":"version","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of release files","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SentryReleaseFileResponse"}}}}},"401":{"description":"Unauthorized"},"404":{"description":"Project not found"}}},"post":{"tags":["sentry-compat"],"summary":"Upload a source map file for a release.","description":"Accepts the same multipart format as the Sentry release files API.\nThe `name` field should be the URL path of the file (e.g., `~/dist/bundle.js.map`).\n\nThe route has a 50 MiB body limit applied at the router level (Fix #4).\nA per-field size check provides an additional defense-in-depth layer.","operationId":"upload_release_file","parameters":[{"name":"org_slug","in":"path","description":"Organization slug (ignored)","required":true,"schema":{"type":"string"}},{"name":"project_slug","in":"path","description":"Project slug or numeric ID","required":true,"schema":{"type":"string"}},{"name":"version","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"201":{"description":"File uploaded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryReleaseFileResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"404":{"description":"Project not found"},"413":{"description":"Source map file exceeds the 50 MiB per-field limit"}}}},"/_temps/event":{"post":{"tags":["Metrics"],"summary":"Record analytics event","operationId":"record_event_metrics","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventMetricsPayload"}}},"required":true},"responses":{"204":{"description":"Event recorded successfully"},"400":{"description":"Bad request"},"500":{"description":"Internal server error"}}}},"/_temps/session-replay/events":{"post":{"tags":["Analytics"],"summary":"Add events to existing session replay","operationId":"add_session_replay_events","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionReplayEventsRequest"}}},"required":true},"responses":{"200":{"description":"Events added successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddEventsResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Session not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/_temps/session-replay/init":{"post":{"tags":["Analytics"],"summary":"Initialize session replay with metadata","operationId":"init_session_replay","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionReplayInitRequest"}}},"required":true},"responses":{"201":{"description":"Session initialized successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionReplayInitResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/_temps/speed":{"post":{"tags":["Performance"],"summary":"Record performance metrics from client","operationId":"record_speed_metrics","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpeedMetricsPayload"}}},"required":true},"responses":{"204":{"description":"Metrics recorded successfully"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Host not found in route table","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/_temps/speed/update":{"post":{"tags":["Performance"],"summary":"Update late performance metrics","operationId":"update_speed_metrics","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSpeedMetricsPayload"}}},"required":true},"responses":{"204":{"description":"Metrics updated successfully"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Host not found or metrics not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/admin/gate-settings":{"get":{"tags":["AdminGate"],"operationId":"get_admin_gate","responses":{"200":{"description":"Current admin gate config","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminGateResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["AdminGate"],"operationId":"patch_admin_gate","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAdminGateRequest"}}},"required":true},"responses":{"200":{"description":"Updated admin gate config","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminGateResponse"}}}},"400":{"description":"Invalid IP/CIDR/host"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"409":{"description":"Env-overridden or would lock out caller"}},"security":[{"bearer_auth":[]}]}},"/admin/oidc/providers":{"get":{"tags":["Authentication"],"operationId":"list_oidc_providers","responses":{"200":{"description":"OIDC providers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/OidcProviderResponse"}}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Authentication"],"operationId":"create_oidc_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateOidcProviderRequest"}}},"required":true},"responses":{"201":{"description":"OIDC provider created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OidcProviderResponse"}}}},"409":{"description":"Another OIDC provider already uses that name"}},"security":[{"bearer_auth":[]}]}},"/admin/oidc/providers/{provider_id}":{"delete":{"tags":["Authentication"],"operationId":"delete_oidc_provider","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"OIDC provider deleted"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Authentication"],"operationId":"update_oidc_provider","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateOidcProviderRequest"}}},"required":true},"responses":{"200":{"description":"OIDC provider updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OidcProviderResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/admin/oidc/providers/{provider_id}/role-mappings":{"get":{"tags":["Authentication"],"operationId":"list_oidc_role_mappings","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"OIDC role mappings","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/OidcRoleMappingResponse"}}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Authentication"],"operationId":"create_oidc_role_mapping","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateOidcRoleMappingRequest"}}},"required":true},"responses":{"201":{"description":"Role mapping created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OidcRoleMappingResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/admin/oidc/providers/{provider_id}/test":{"post":{"tags":["Authentication"],"operationId":"test_oidc_provider","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Connection test result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OidcTestConnectionResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/admin/oidc/providers/{provider_id}/users":{"get":{"tags":["Authentication"],"operationId":"list_oidc_provider_users","parameters":[{"name":"provider_id","in":"path","description":"OIDC provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Users authenticated via this OIDC provider","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/OidcProviderUserResponse"}}}}},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]}},"/admin/oidc/role-mappings/{mapping_id}":{"delete":{"tags":["Authentication"],"operationId":"delete_oidc_role_mapping","parameters":[{"name":"mapping_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Role mapping deleted"}},"security":[{"bearer_auth":[]}]}},"/agents/webhook/{webhook_id}":{"post":{"tags":["Agents"],"summary":"Public webhook endpoint. Authenticated via `X-Webhook-Token` header.","description":"`POST /api/agents/webhook/{webhook_id}`\nHeader: `X-Webhook-Token: `\n\nThe `webhook_id` in the URL is a short non-secret identifier (safe to log).\nThe actual credential is the secret token in the header.\n\nAccepts any JSON body, which is passed as `user_context` to the agent run.","operationId":"webhook_trigger","parameters":[{"name":"webhook_id","in":"path","description":"Webhook ID (non-secret)","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookTriggerRequest"}}},"required":true},"responses":{"202":{"description":"Agent run created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookTriggerResponse"}}}},"401":{"description":"Missing or invalid X-Webhook-Token header"},"404":{"description":"Invalid webhook ID"},"422":{"description":"Agent disabled"}}}},"/ai/conversations":{"get":{"tags":["AI Chat"],"summary":"List every active conversation across all projects, most-recently-active\nfirst, annotated with project name/slug. Powers the unified \"all chats\"\nswitcher in the AI assistant dock.","operationId":"list_all_conversations","responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GlobalConversationResponse"}}}}},"401":{"description":""},"403":{"description":""}},"security":[{"bearer_auth":[]}]}},"/ai/pricing":{"get":{"tags":["AI Gateway Pricing"],"operationId":"get_pricing","responses":{"200":{"description":"Model pricing information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PricingResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/providers":{"get":{"tags":["AI Gateway Admin"],"operationId":"list_provider_keys","responses":{"200":{"description":"List of provider keys","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProviderKeyResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["AI Gateway Admin"],"operationId":"create_provider_key","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProviderKeyRequest"}}},"required":true},"responses":{"201":{"description":"Provider key created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderKeyResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/providers/test":{"post":{"tags":["AI Gateway Admin"],"operationId":"test_provider_key_inline","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestProviderKeyRequest"}}},"required":true},"responses":{"200":{"description":"Test result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestProviderKeyResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/providers/{id}":{"delete":{"tags":["AI Gateway Admin"],"operationId":"delete_provider_key","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Provider key deleted"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["AI Gateway Admin"],"operationId":"update_provider_key","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProviderKeyRequest"}}},"required":true},"responses":{"200":{"description":"Provider key updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderKeyResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/providers/{id}/test":{"post":{"tags":["AI Gateway Admin"],"operationId":"test_provider_key_by_id","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Test result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestProviderKeyResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Provider key not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/usage/by-provider":{"get":{"tags":["AI Gateway Usage"],"operationId":"get_usage_by_provider","parameters":[{"name":"from","in":"query","description":"ISO 8601 start time (defaults to 24h ago)","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","description":"ISO 8601 end time (defaults to now)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Usage broken down by provider","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProviderUsage"}}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/usage/conversations":{"get":{"tags":["AI Gateway Usage"],"operationId":"get_conversations","parameters":[{"name":"from","in":"query","description":"ISO 8601 start time (defaults to 24h ago)","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","description":"ISO 8601 end time (defaults to now)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max results (defaults to 50, max 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"user_id","in":"query","description":"Filter by user ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"tags","in":"query","description":"Filter by tags (comma-separated)","required":false,"schema":{"type":"string"}},{"name":"model","in":"query","description":"Filter by model name","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Conversation summaries","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ConversationSummary"}}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/usage/conversations/{conversation_id}":{"get":{"tags":["AI Gateway Usage"],"operationId":"get_conversation_detail","parameters":[{"name":"conversation_id","in":"path","description":"Conversation ID","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max results (defaults to 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Invocations within a conversation","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/UsageLogEntry"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/usage/recent":{"get":{"tags":["AI Gateway Usage"],"operationId":"get_usage_recent","parameters":[{"name":"limit","in":"query","description":"Page size (defaults to 20, max 50)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"offset","in":"query","description":"Number of results to skip for pagination (defaults to 0)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"provider","in":"query","description":"Filter by provider name","required":false,"schema":{"type":"string"}},{"name":"model","in":"query","description":"Filter by model name","required":false,"schema":{"type":"string"}},{"name":"status","in":"query","description":"Filter by HTTP status code (exact match)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"cost_gte","in":"query","description":"Cost greater-than-or-equal, in microcents","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"cost_gt","in":"query","description":"Cost strictly greater-than, in microcents","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"cost_lte","in":"query","description":"Cost less-than-or-equal, in microcents","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"cost_lt","in":"query","description":"Cost strictly less-than, in microcents","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"tokens_gte","in":"query","description":"Total tokens greater-than-or-equal","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"tokens_gt","in":"query","description":"Total tokens strictly greater-than","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"tokens_lte","in":"query","description":"Total tokens less-than-or-equal","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"tokens_lt","in":"query","description":"Total tokens strictly less-than","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Page of recent usage log entries","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsageLogPage"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/usage/summary":{"get":{"tags":["AI Gateway Usage"],"operationId":"get_usage_summary","parameters":[{"name":"from","in":"query","description":"ISO 8601 start time (defaults to 24h ago)","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","description":"ISO 8601 end time (defaults to now)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Usage summary for the time range","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsageSummary"}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/usage/timeseries":{"get":{"tags":["AI Gateway Usage"],"operationId":"get_usage_timeseries","parameters":[{"name":"from","in":"query","description":"ISO 8601 start time (defaults to 24h ago)","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","description":"ISO 8601 end time (defaults to now)","required":false,"schema":{"type":"string"}},{"name":"bucket","in":"query","description":"Bucket size: hour, day, week (defaults to day)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Time-series usage data","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TimeseriesBucket"}}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/usage/top-models":{"get":{"tags":["AI Gateway Usage"],"operationId":"get_usage_top_models","parameters":[{"name":"from","in":"query","description":"ISO 8601 start time (defaults to 24h ago)","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","description":"ISO 8601 end time (defaults to now)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max results (defaults to 10)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Top models by request count","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ModelUsage"}}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/v1/chat/completions":{"post":{"tags":["AI Gateway"],"operationId":"chat_completions","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatCompletionRequest"}}},"required":true},"responses":{"200":{"description":"Chat completion response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatCompletionResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}},"404":{"description":"Model not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/v1/embeddings":{"post":{"tags":["AI Gateway"],"operationId":"embeddings","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmbeddingRequest"}}},"required":true},"responses":{"200":{"description":"Embedding response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmbeddingResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}},"404":{"description":"Model not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/v1/models":{"get":{"tags":["AI Gateway"],"operationId":"list_models","responses":{"200":{"description":"List of available models","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelListResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/analytics/active-visitors":{"get":{"tags":["Analytics"],"summary":"Get detailed active visitors","operationId":"get_analytics_active_visitors","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Deployment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"window_minutes","in":"query","description":"Time window in minutes for active visitors (default: 5)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved active visitors","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActiveVisitorsResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/event-detail":{"get":{"tags":["Analytics"],"summary":"Get detailed analytics for a specific event","operationId":"get_event_detail","parameters":[{"name":"event_name","in":"query","description":"Event name to get details for","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date (ISO 8601)","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date (ISO 8601)","required":true,"schema":{"type":"string"}},{"name":"bucket_interval","in":"query","description":"Bucket interval: hour, day, week, month (default: auto)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved event details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventDetailResponse"}}}},"400":{"description":"Invalid parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/event-entries":{"get":{"tags":["Analytics"],"summary":"Get paginated list of raw occurrences of a specific event, including custom JSON properties","operationId":"get_event_entries","parameters":[{"name":"event_name","in":"query","description":"Event name to list occurrences for","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date (ISO 8601)","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date (ISO 8601)","required":true,"schema":{"type":"string"}},{"name":"page","in":"query","description":"Page number (1-based, default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Items per page (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Successfully retrieved event entries","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventEntriesResponse"}}}},"400":{"description":"Invalid parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/event-visitors":{"get":{"tags":["Analytics"],"summary":"Get paginated list of visitors who triggered a specific event","operationId":"get_event_visitors","parameters":[{"name":"event_name","in":"query","description":"Event name to list visitors for","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date (ISO 8601)","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date (ISO 8601)","required":true,"schema":{"type":"string"}},{"name":"page","in":"query","description":"Page number (1-based, default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Items per page (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Successfully retrieved event visitors","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventVisitorsResponse"}}}},"400":{"description":"Invalid parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/events":{"get":{"tags":["Analytics"],"operationId":"get_analytics_events_count","parameters":[{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"limit","in":"query","description":"Maximum number of results to return","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"custom_events_only","in":"query","description":"Only return custom events, excluding system events like page_view, page_leave, heartbeat (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"breakdown","in":"query","description":"Breakdown by geography: 'country', 'region', or 'city' (optional)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved event counts","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EventCount"}}}}},"400":{"description":"Invalid date format, missing required parameters, or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/general-stats":{"get":{"tags":["Analytics"],"summary":"Get general statistics across all projects for a time frame","operationId":"get_general_stats","parameters":[{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"project_ids","in":"query","description":"Optional: Filter by specific project IDs (comma-separated)","required":false,"schema":{"type":"array","items":{"type":"integer","format":"int32"}}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"include_project_breakdown","in":"query","description":"Whether to include per-project breakdown (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Successfully retrieved general statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GeneralStatsResponse"}}}},"400":{"description":"Invalid date format or parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/has-events":{"get":{"tags":["Analytics"],"operationId":"check_analytics_has_events","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Analytics events existence check","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HasAnalyticsEventsResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/live-visitors":{"get":{"tags":["Analytics"],"summary":"Get list of currently live visitors from visitor table","operationId":"get_live_visitors_list","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"window_minutes","in":"query","description":"Time window in minutes for live visitors (default: 5)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved live visitors list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LiveVisitorsListResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/page-flow":{"get":{"tags":["Analytics"],"summary":"Get page flow analytics: entry pages, exit pages, drop-off points, and page transitions","operationId":"get_page_flow","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max entry/exit pages to return (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"transitions_limit","in":"query","description":"Max page transitions to return (default: 50, max: 200)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"min_views_for_dropoff","in":"query","description":"Minimum views for drop-off analysis (default: 5)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved page flow analytics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PageFlowResponse"}}}},"400":{"description":"Invalid parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/page-hourly-sessions":{"get":{"tags":["Analytics"],"operationId":"get_page_hourly_sessions","parameters":[{"name":"page_path","in":"query","description":"The page path to get sessions for","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_time","in":"query","description":"Start time in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"bucket_interval","in":"query","description":"Bucket interval: 'hour', 'day', 'week', or 'month' (default: auto-determined based on range)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved page sessions with time buckets","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PageHourlySessionsResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/page-path-detail":{"get":{"tags":["Analytics"],"summary":"Get detailed analytics for a specific page path\nReturns visitors, page views, activity over time, geographic distribution, and referrers","operationId":"get_page_path_detail","parameters":[{"name":"page_path","in":"query","description":"The page path to get details for (URL-encoded)","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"bucket_interval","in":"query","description":"Bucket interval for time series: 'hour', 'day', 'week', 'month' (default: auto based on date range)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved page path detail analytics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PagePathDetailResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/page-path-visitors":{"get":{"tags":["Analytics"],"summary":"Get individual visitor sessions for a specific page path","operationId":"get_page_path_visitors","parameters":[{"name":"page_path","in":"query","description":"The page path to get visitors for (URL-encoded)","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"page","in":"query","description":"Page number (1-based, default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Items per page (default: 50, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Successfully retrieved page path visitors","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PagePathVisitorsResponse"}}}},"400":{"description":"Invalid parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/page-paths":{"get":{"tags":["Analytics"],"operationId":"get_page_paths","parameters":[{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS (optional)","required":false,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS (optional)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Maximum number of page paths to return (default: 100, max: 1000)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved page paths","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PagePathsResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/page-paths-sparklines":{"get":{"tags":["Analytics"],"operationId":"get_page_paths_sparklines","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_time","in":"query","description":"Start time in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"page_paths","in":"query","description":"Comma-separated list of page paths","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sparkline data for all requested page paths","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PagePathsSparklineResponse"}}}},"400":{"description":"Invalid parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/recent-activity":{"get":{"tags":["Analytics"],"summary":"Get recent activity events for real-time activity feed","operationId":"get_recent_activity","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"since_id","in":"query","description":"Return events with ID greater than this (cursor-based polling)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"limit","in":"query","description":"Max events to return (default: 50, max: 100)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved recent activity events","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecentActivityResponse"}}}},"400":{"description":"Invalid parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/sessions/{session_id}":{"get":{"tags":["Analytics"],"summary":"Get detailed information about a specific session including events and request logs","operationId":"get_session_details","parameters":[{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved session details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionDetails"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Session not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/sessions/{session_id}/events":{"get":{"tags":["Analytics"],"operationId":"get_analytics_session_events","parameters":[{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS","required":false,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Number of results to return (default: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"offset","in":"query","description":"Number of results to skip (default: 0)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved session events","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionEventsResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Session not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/sessions/{session_id}/logs":{"get":{"tags":["Analytics"],"operationId":"get_session_logs","parameters":[{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS","required":false,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Number of results to return (default: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"offset","in":"query","description":"Number of results to skip (default: 0)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved session logs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionLogsResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Session not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitor-facets":{"get":{"tags":["Analytics"],"summary":"Get filter dropdown contents for the visitors page. Returns the top\nvalues per dimension with distinct visitor counts so the UI can render\n\"Country — 1,234 visitors\" rows. Each dimension is computed against the\nsegment minus its own filter, so a selected value never collapses its\nown dropdown.","operationId":"get_visitor_facets","parameters":[{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"include_crawlers","in":"query","description":"Include crawlers (default: false)","required":false,"schema":{"type":"boolean"}},{"name":"has_activity_only","in":"query","description":"Hide ghost visitors (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"per_facet_limit","in":"query","description":"Top N values per dimension (default: 50, max: 200)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"filter_country","in":"query","description":"Geolocation country","required":false,"schema":{"type":"string"}},{"name":"filter_region","in":"query","description":"Geolocation region","required":false,"schema":{"type":"string"}},{"name":"filter_city","in":"query","description":"Geolocation city","required":false,"schema":{"type":"string"}},{"name":"filter_channel","in":"query","description":"First-touch channel","required":false,"schema":{"type":"string"}},{"name":"filter_referrer","in":"query","description":"First-touch referrer hostname (use 'Direct' for null)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Top values per dimension","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorFacets"}}}},"400":{"description":"Invalid date format or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors":{"get":{"tags":["Analytics"],"summary":"Get list of visitors with summary information","operationId":"get_visitors","parameters":[{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"include_crawlers","in":"query","description":"Include crawlers (default: false)","required":false,"schema":{"type":"boolean"}},{"name":"limit","in":"query","description":"Maximum number of visitors to return (default: 50)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"offset","in":"query","description":"Number of visitors to skip (default: 0)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"has_activity_only","in":"query","description":"Filter to only include visitors with recorded activity (events/sessions). When true, excludes ghost visitors (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"filter_country","in":"query","description":"Geolocation country","required":false,"schema":{"type":"string"}},{"name":"filter_region","in":"query","description":"Geolocation region","required":false,"schema":{"type":"string"}},{"name":"filter_city","in":"query","description":"Geolocation city","required":false,"schema":{"type":"string"}},{"name":"filter_channel","in":"query","description":"First-touch channel","required":false,"schema":{"type":"string"}},{"name":"filter_referrer","in":"query","description":"First-touch referrer hostname (use 'Direct' for null)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved visitors","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorsResponse"}}}},"400":{"description":"Invalid date format, missing required parameters, or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/guid/{visitor_id}":{"get":{"tags":["Analytics"],"summary":"Get visitor by GUID with geolocation data","operationId":"get_visitor_by_guid","parameters":[{"name":"visitor_id","in":"path","description":"Visitor GUID (supports enc_ prefix for encrypted IDs)","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved visitor with geolocation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorWithGeolocation"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/id/{id}":{"get":{"tags":["Analytics"],"summary":"Get visitor by numeric ID with geolocation data","operationId":"get_visitor_by_id","parameters":[{"name":"id","in":"path","description":"Visitor numeric ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved visitor with geolocation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorWithGeolocation"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/{visitor_id}":{"get":{"tags":["Analytics"],"summary":"Get detailed information about a specific visitor by numeric ID","operationId":"get_visitor_details","parameters":[{"name":"visitor_id","in":"path","description":"Visitor numeric ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved visitor details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorDetails"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/{visitor_id}/enrich":{"put":{"tags":["Analytics"],"operationId":"enrich_visitor","parameters":[{"name":"visitor_id","in":"path","description":"Visitor ID - can be numeric ID, GUID, or encrypted GUID (enc_xxx)","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnrichVisitorRequest"}}},"required":true},"responses":{"200":{"description":"Successfully enriched visitor data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnrichVisitorResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/{visitor_id}/info":{"get":{"tags":["Analytics"],"summary":"Get visitor record from database","operationId":"get_visitor_info","parameters":[{"name":"visitor_id","in":"path","description":"Visitor numeric ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved visitor info","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorRecord"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/{visitor_id}/journey":{"get":{"tags":["Analytics"],"summary":"Get the complete visitor journey: all events across all sessions, grouped by session","operationId":"get_visitor_journey","parameters":[{"name":"visitor_id","in":"path","description":"Visitor numeric ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"limit_sessions","in":"query","description":"Maximum number of sessions to return (default: 50)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved visitor journey","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorJourneyResponse"}}}},"400":{"description":"Invalid parameters"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/{visitor_id}/sessions":{"get":{"tags":["Analytics"],"summary":"Get all sessions for a specific visitor by numeric ID","operationId":"get_analytics_visitor_sessions","parameters":[{"name":"visitor_id","in":"path","description":"Visitor numeric ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"limit","in":"query","description":"Maximum number of sessions to return (default: 100)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved visitor sessions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorSessionsResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/{visitor_id}/stats":{"get":{"tags":["Analytics"],"summary":"Get visitor statistics","operationId":"get_visitor_stats","parameters":[{"name":"visitor_id","in":"path","description":"Visitor numeric ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved visitor statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorStats"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/api-keys":{"get":{"tags":["API Keys"],"operationId":"list_api_keys","parameters":[{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page (default: 20)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"API keys retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["API Keys"],"operationId":"create_api_key","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateApiKeyRequest"}}},"required":true},"responses":{"201":{"description":"API key created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateApiKeyResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"409":{"description":"Conflict - API key name already exists"},"428":{"description":"Recent MFA verification required"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/api-keys/permissions":{"get":{"tags":["API Keys"],"operationId":"get_api_key_permissions","responses":{"200":{"description":"Available permissions and roles retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AvailablePermissions"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/api-keys/{id}":{"get":{"tags":["API Keys"],"operationId":"get_api_key","parameters":[{"name":"id","in":"path","description":"API key ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"API key retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["API Keys"],"operationId":"update_api_key","parameters":[{"name":"id","in":"path","description":"API key ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateApiKeyRequest"}}},"required":true},"responses":{"200":{"description":"API key updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"409":{"description":"Conflict - API key name already exists"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["API Keys"],"operationId":"delete_api_key","parameters":[{"name":"id","in":"path","description":"API key ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"API key deleted successfully"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/api-keys/{id}/activate":{"post":{"tags":["API Keys"],"operationId":"activate_api_key","parameters":[{"name":"id","in":"path","description":"API key ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"API key activated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/api-keys/{id}/deactivate":{"post":{"tags":["API Keys"],"operationId":"deactivate_api_key","parameters":[{"name":"id","in":"path","description":"API key ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"API key deactivated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/api-keys/{id}/rotate":{"post":{"tags":["API Keys"],"operationId":"rotate_api_key","parameters":[{"name":"id","in":"path","description":"API key ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"API key rotated successfully; the response contains the new plaintext secret, shown only once","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateApiKeyResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"428":{"description":"Recent MFA verification required"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/auth/cli/device/approve":{"post":{"tags":["Authentication"],"operationId":"cli_device_approve","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDeviceApproveRequest"}}},"required":true},"responses":{"200":{"description":"Session approved; CLI can now claim the API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDeviceApproveResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Browser session required"},"404":{"description":"Unknown user_code"},"409":{"description":"Already resolved"},"410":{"description":"Session expired"},"428":{"description":"Recent MFA verification required"},"500":{"description":"Internal server error"}},"security":[{"session_token":[]}]}},"/auth/cli/device/deny":{"post":{"tags":["Authentication"],"operationId":"cli_device_deny","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDeviceApproveRequest"}}},"required":true},"responses":{"200":{"description":"Session denied","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDeviceApproveResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Unknown user_code"},"409":{"description":"Already resolved"},"410":{"description":"Session expired"},"500":{"description":"Internal server error"}},"security":[{"session_token":[]}]}},"/auth/cli/device/lookup":{"get":{"tags":["Authentication"],"operationId":"cli_device_lookup","parameters":[{"name":"user_code","in":"query","description":"`user_code` as displayed in the CLI / pasted into the URL.","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Device session metadata","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDeviceLookupResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Unknown user_code"},"410":{"description":"Device session expired"},"500":{"description":"Internal server error"}},"security":[{"session_token":[]}]}},"/auth/cli/device/poll":{"post":{"tags":["Authentication"],"operationId":"cli_device_poll","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDevicePollRequest"}}},"required":true},"responses":{"200":{"description":"Poll result; check `status` field","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDevicePollResponse"}}}},"404":{"description":"Unknown device_code"},"500":{"description":"Internal server error"}}}},"/auth/cli/device/start":{"post":{"tags":["Authentication"],"operationId":"cli_device_start","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDeviceStartRequest"}}},"required":true},"responses":{"200":{"description":"Device session created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDeviceStartResponse"}}}},"500":{"description":"Internal server error"}}}},"/auth/cli/logout":{"post":{"tags":["Authentication"],"operationId":"cli_logout","responses":{"204":{"description":"API key revoked"},"401":{"description":"Not authenticated"},"403":{"description":"Endpoint requires API key authentication"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/auth/email-status":{"get":{"tags":["Authentication"],"operationId":"email_status","responses":{"200":{"description":"Email configuration status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailStatusResponse"}}}},"500":{"description":"Internal server error"}}}},"/auth/login":{"post":{"tags":["Authentication"],"operationId":"login","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginRequest"}}},"required":true},"responses":{"200":{"description":"Login successful, session cookie set","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthResponse"}}}},"401":{"description":"Invalid credentials, or the account's role requires MFA enrollment that has not been completed"},"500":{"description":"Internal server error"}}}},"/auth/oidc/callback":{"get":{"tags":["Authentication"],"operationId":"oidc_callback","parameters":[{"name":"code","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"state","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"error","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"error_description","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"302":{"description":"Redirect to app with session cookie or login error"}}}},"/auth/oidc/login/{slug}":{"get":{"tags":["Authentication"],"operationId":"start_oidc_login_by_slug","parameters":[{"name":"slug","in":"path","description":"OIDC provider slug (from /email-status or /auth/oidc/providers)","required":true,"schema":{"type":"string"}},{"name":"return_to","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"302":{"description":"Redirect to IdP authorize URL"},"404":{"description":"Provider not found"},"503":{"description":"OIDC provider unreachable"}}}},"/auth/oidc/providers":{"get":{"tags":["Authentication"],"operationId":"list_public_providers","responses":{"200":{"description":"Enabled OIDC providers for login page","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OidcProvidersListResponse"}}}}}}},"/auth/password-change-required":{"post":{"tags":["Authentication"],"operationId":"change_required_password","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RequiredPasswordChangeRequest"}}},"required":true},"responses":{"200":{"description":"Required password change completed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RequiredPasswordChangeResponse"}}}},"400":{"description":"Password does not meet requirements"},"401":{"description":"Password-change session is missing or expired"},"500":{"description":"Internal server error"}}}},"/auth/password-reset/request":{"post":{"tags":["Authentication"],"operationId":"request_password_reset","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailRequest"}}},"required":true},"responses":{"200":{"description":"Reset email sent if account exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthResponse"}}}},"503":{"description":"Email service not configured"}}}},"/auth/password-reset/verify":{"post":{"tags":["Authentication"],"operationId":"reset_password","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResetPasswordRequest"}}},"required":true},"responses":{"200":{"description":"Password reset successful","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthResponse"}}}},"400":{"description":"Invalid or expired token"},"500":{"description":"Internal server error"}}}},"/auth/step-up":{"post":{"tags":["Authentication"],"operationId":"verify_step_up","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyStepUpRequest"}}},"required":true},"responses":{"200":{"description":"Session elevated for sensitive actions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StepUpResponse"}}}},"400":{"description":"Verification code is empty"},"401":{"description":"Invalid code or expired session"},"403":{"description":"Browser session required"},"428":{"description":"MFA setup required"},"429":{"description":"Too many verification attempts"},"500":{"description":"Verification infrastructure failed"}},"security":[{"session_token":[]}]}},"/auth/verify-email":{"get":{"tags":["Authentication"],"operationId":"verify_email","parameters":[{"name":"token","in":"query","description":"Email verification token","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Email verified successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthResponse"}}}},"400":{"description":"Invalid or expired token"},"500":{"description":"Internal server error"}}}},"/auth/verify-mfa":{"post":{"tags":["Authentication"],"operationId":"verify_mfa_challenge","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MfaVerificationRequest"}}},"required":true},"responses":{"204":{"description":"MFA verification successful"},"400":{"description":"Invalid request"},"401":{"description":"Invalid MFA code"},"500":{"description":"Internal server error"}}}},"/backups/alerts":{"get":{"tags":["Backups"],"summary":"List open backup alerts.","description":"Returns all alerts that have not yet been resolved, ordered by `opened_at`\ndescending (newest first). The UI renders these as a banner above the\nBackups page content. Alerts are auto-opened by the watcher and\nauto-resolved when the triggering condition clears.\n\n**Schedule overdue** — the backup scheduler did not enqueue a job within\nthe expected window (1 hour past `next_run`). Usually means the scheduler\ntask is dead or wedged.\n\n**Job stalled** — a `backup_jobs` row has been in `state='pending'` for\nmore than 1 hour. The runner never claimed the job. Usually means the\nrunner task is dead or the runner concurrency cap is too low.","operationId":"list_backup_alerts","responses":{"200":{"description":"List of open backup alerts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupAlertListResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/cleanup":{"post":{"tags":["Backups"],"summary":"Preview or run retention using each selected schedule's configured retention days.","operationId":"cleanup_expired_backups","parameters":[{"name":"dry_run","in":"query","description":"Return the backups selected by retention without deleting anything.","required":false,"schema":{"type":"boolean"}},{"name":"schedule_id","in":"query","description":"Limit cleanup to one backup schedule.","required":false,"schema":{"type":["integer","null"],"format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CleanupExpiredBackupsRequest"}}},"required":true},"responses":{"200":{"description":"Retention cleanup completed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RetentionCleanupReport"}}}},"400":{"description":"Missing or invalid preview candidate list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Schedule or backup not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"409":{"description":"Cleanup preview is stale","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Cleanup could not be started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/external-services/{id}/run":{"post":{"tags":["Backups"],"summary":"Run a backup for an external service manually.","description":"Enqueues the backup for asynchronous execution via the `BackupRunner`\n(ADR-014). Returns `202 Accepted` immediately: pending parent and child\nrows are inserted, and a `backup_jobs` row is enqueued for the resolved\nengine. Poll `GET /backups/{id}` to observe `pending → running → completed`.","operationId":"run_external_service_backup","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RunExternalServiceBackupRequest"}}},"required":true},"responses":{"202":{"description":"Backup enqueued for async execution","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceBackupResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"External service or S3 source not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/external-services/{service_id}/backups":{"get":{"tags":["Backups"],"summary":"List all backups for a specific external service (DB-only, no S3 scan).","description":"Returns a paginated list of backups that belong to this service.\nCompletes in <100 ms regardless of S3 endpoint latency because it\nnever touches S3.","operationId":"list_external_service_backups","parameters":[{"name":"service_id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-based). Defaults to 1.","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"page_size","in":"query","description":"Items per page. Defaults to 20, max 100.","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Paginated list of backups for this service","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceBackupListResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/external-services/{service_id}/schedules":{"get":{"tags":["Backups"],"summary":"List the schedules that target a specific external service. Useful for\nthe service detail page (\"which schedules back this DB up?\").","operationId":"list_service_schedules","parameters":[{"name":"service_id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Schedules backing up this service","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BackupScheduleResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Service not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/s3-sources":{"get":{"tags":["Backups"],"summary":"List all S3 sources","operationId":"list_s3_sources","responses":{"200":{"description":"List of S3 sources","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/S3SourceResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Backups"],"summary":"Create a new S3 source","operationId":"create_s3_source","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateS3SourceRequest"}}},"required":true},"responses":{"201":{"description":"S3 source created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/S3SourceResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/s3-sources/test":{"post":{"tags":["Backups"],"summary":"Test S3 connectivity against a prospective source configuration (before creating it).\nThe credentials are NOT persisted. Useful for validating the form in the UI.","operationId":"test_s3_connection_preview","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateS3SourceRequest"}}},"required":true},"responses":{"200":{"description":"Connection test result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/S3ConnectionTestResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/s3-sources/{id}":{"get":{"tags":["Backups"],"summary":"Get an S3 source by ID","operationId":"get_s3_source","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"S3 source details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/S3SourceResponse"}}}},"404":{"description":"S3 source not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Backups"],"summary":"Delete an S3 source","operationId":"delete_s3_source","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"S3 source deleted"},"404":{"description":"S3 source not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Backups"],"summary":"Update an S3 source","operationId":"update_s3_source","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateS3SourceRequest"}}},"required":true},"responses":{"200":{"description":"S3 source updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/S3SourceResponse"}}}},"404":{"description":"S3 source not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/s3-sources/{id}/backups":{"get":{"tags":["Backups"],"summary":"List all backups in an S3 source","operationId":"list_source_backups","parameters":[{"name":"include_s3_scan","in":"query","description":"When `true`, scan the S3 bucket for backups not tracked in the\nlocal database (useful after disaster-recovery from another Temps\ninstance). Defaults to `false` — the fast DB-only path.","required":false,"schema":{"type":"boolean"}},{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of all backups in the source","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceBackupIndexResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"S3 source not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/backups/s3-sources/{id}/run":{"post":{"tags":["Backups"],"summary":"Run a backup immediately for an S3 source.","description":"Enqueues the backup for asynchronous execution via the `BackupRunner`\n(ADR-014). Returns `202 Accepted` immediately: a `backups` row is inserted\nwith `state='pending'` and a `backup_jobs` row is enqueued for the\n`ControlPlaneEngine`. Poll `GET /backups/{id}` to observe\n`pending → running → completed`.","operationId":"run_backup_for_source","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RunBackupRequest"}}},"required":true},"responses":{"202":{"description":"Backup enqueued for async execution","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"S3 source not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/s3-sources/{id}/set-default":{"post":{"tags":["Backups"],"summary":"Mark an S3 source as the default. All new backups/schedules/services that do not\nexplicitly reference a source will use the default. Returns the updated source.","operationId":"set_default_s3_source","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"S3 source marked as default","content":{"application/json":{"schema":{"$ref":"#/components/schemas/S3SourceResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"S3 source not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/s3-sources/{id}/test":{"post":{"tags":["Backups"],"summary":"Test connectivity to an existing S3 source using its stored credentials.","operationId":"test_s3_source_connection","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Connection test result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/S3ConnectionTestResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"S3 source not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedule-runs/{id}/cancel":{"post":{"tags":["Backups"],"summary":"Cancel every non-terminal child backup belonging to a schedule run.","description":"Loops over `state IN ('pending','running')` children and flips each via\nthe same path as the per-backup cancel endpoint. The parent\n`schedule_runs.finished_at` is stamped automatically once no live\nchildren remain. Idempotent: cancelling a run with no live children is\na 200 with `cancelled = 0`.","operationId":"cancel_schedule_run","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Cancel processed (idempotent)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CancelBackupResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Schedule run not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedule-runs/{id}/jobs":{"get":{"tags":["Backups"],"summary":"List the individual backup jobs for a single scheduler run.","description":"Returns each child `backups` row joined with its external service name and\nthe most-recent `backup_jobs` engine key. Used by the schedule detail\naccordion to show per-job detail on row expand.\n\n`page_size` defaults to 50 and is capped at 200.","operationId":"list_schedule_run_jobs","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Jobs for this scheduler run","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ScheduleRunJobEntry"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedules":{"get":{"tags":["Backups"],"summary":"List all backup schedules","operationId":"list_backup_schedules","responses":{"200":{"description":"List of backup schedules","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BackupScheduleResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Backups"],"summary":"Create a new backup schedule","operationId":"create_backup_schedule","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateBackupScheduleRequest"}}},"required":true},"responses":{"201":{"description":"Backup schedule created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupScheduleResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}":{"get":{"tags":["Backups"],"summary":"Get a backup schedule by ID","operationId":"get_backup_schedule","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Backup schedule details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupScheduleResponse"}}}},"404":{"description":"Backup schedule not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Backups"],"summary":"Delete a backup schedule","operationId":"delete_backup_schedule","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Backup schedule deleted"},"404":{"description":"Backup schedule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Backups"],"summary":"Update a backup schedule (partial update).","description":"All request fields are optional; only fields that are present in the\nJSON body are updated. Absent fields leave the corresponding column\nunchanged. If `schedule_expression` is changed, `next_run` is\nrecomputed automatically.","operationId":"update_backup_schedule","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateBackupScheduleRequest"}}},"required":true},"responses":{"200":{"description":"Schedule updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupScheduleResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Schedule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}/backups":{"get":{"tags":["Backups"],"summary":"List backups for a schedule","operationId":"list_backups_for_schedule","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of backups for the schedule","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BackupResponse"}}}}},"404":{"description":"Backup schedule not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}/disable":{"patch":{"tags":["Backups"],"summary":"Disable a backup schedule","operationId":"disable_backup_schedule","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Backup schedule disabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupScheduleResponse"}}}},"404":{"description":"Backup schedule not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}/enable":{"patch":{"tags":["Backups"],"summary":"Enable a backup schedule","operationId":"enable_backup_schedule","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Backup schedule enabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupScheduleResponse"}}}},"404":{"description":"Backup schedule not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}/run":{"post":{"tags":["Backups"],"summary":"Immediately fan-out a run for the given schedule (Run Now).","description":"Creates one `schedule_runs` row, one control-plane backup job, and one\nbackup job per supported external service — all in a single transaction.\nReturns `202 Accepted` with a [`ScheduleRunResponse`] containing the new\n`schedule_run_id` and the list of enqueued jobs. Returns `409 Conflict` if\na run for this schedule is already in flight or if the schedule is disabled.","operationId":"run_schedule_now","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"202":{"description":"Fan-out run enqueued for async execution","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScheduleRunResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Schedule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"409":{"description":"Run already in flight or schedule disabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}/runs":{"get":{"tags":["Backups"],"summary":"Paginated run history for a backup schedule (one row per scheduler tick).","description":"Returns one [`ScheduleRunSummary`] per scheduler tick, with child backup\ncounts aggregated in a single SQL round-trip. Legacy `backups` rows (pre-\nfan-out) are surfaced as synthetic single-job runs so history does not\ndisappear. Ordered by `started_at DESC` (newest first).\n\nUse `GET /backups/schedule-runs/{run_id}/jobs` to drill into a single run.","operationId":"list_schedule_runs","parameters":[{"name":"page","in":"query","description":"Page number (1-based, defaults to 1, clamped to 1 if < 1).","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"page_size","in":"query","description":"Items per page (defaults to 20, clamped to 100 if > 100).","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Paginated run history for the schedule","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScheduleRunSummaryList"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Schedule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}/services":{"get":{"tags":["Backups"],"summary":"List the external services attached to a backup schedule.","operationId":"list_schedule_services","parameters":[{"name":"id","in":"path","description":"Schedule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Services attached to this schedule","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ExternalServiceSummary"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Schedule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Backups"],"summary":"Attach one or more external services to a backup schedule. Idempotent —\nservices that are already attached are silently skipped (`ON CONFLICT\nDO NOTHING`). Returns the count of newly inserted rows + the total\nmembership after the operation.","operationId":"attach_schedule_services","parameters":[{"name":"id","in":"path","description":"Schedule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttachScheduleServicesRequest"}}},"required":true},"responses":{"200":{"description":"Services attached","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttachScheduleServicesResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Schedule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}/services/{service_id}":{"delete":{"tags":["Backups"],"summary":"Detach a single external service from a backup schedule. Idempotent —\nreturns `204` whether or not a row was actually removed.","operationId":"detach_schedule_service","parameters":[{"name":"id","in":"path","description":"Schedule ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"service_id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Service detached (or was not attached)"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/{id}":{"get":{"tags":["Backups"],"summary":"Get a backup by ID","operationId":"get_backup","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Backup details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Backup not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Backups"],"summary":"Permanently delete one terminal backup from object storage and the database.","operationId":"delete_backup","parameters":[{"name":"id","in":"path","description":"Backup UUID","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Backup deleted"},"400":{"description":"Backup artifact cannot be safely attributed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Backup not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"409":{"description":"Backup is running, referenced, or lacks safe artifact identity","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Object storage or database error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/{id}/cancel":{"post":{"tags":["Backups"],"summary":"Cancel a single in-flight backup.","description":"Flips the parent `backups` row + its latest `backup_jobs` row to\n`failed` with reason `\"cancelled by user \"`. The in-process\n`CancellationToken` is observed on the next heartbeat tick (≤5s), so the\nengine exits cleanly and rollback reaps the sidecar. Idempotent: cancelling\nan already-terminal backup is a 200 with `cancelled = 0`.","operationId":"cancel_backup","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Cancel processed (idempotent)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CancelBackupResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Backup not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/{id}/children":{"get":{"tags":["Backups"],"summary":"List the external-service child backups that belong to a parent backup.","description":"Each entry in `children` corresponds to one `external_service_backups` row,\njoined with `external_services` so the caller receives the service name and\ntype without a second request.\n\nReturns an empty `{ \"children\": [] }` — **not 404** — when the parent\nbackup exists but has no children (e.g. control-plane backups).\nReturns 404 when the parent backup itself does not exist.","operationId":"list_backup_children","parameters":[{"name":"id","in":"path","description":"Integer row id of the parent backup","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Child backup list (may be empty)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChildBackupListResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Parent backup not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/blob":{"get":{"tags":["Blob"],"summary":"List blobs","operationId":"blob_list","parameters":[{"name":"limit","in":"query","description":"Maximum number of items to return","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"prefix","in":"query","description":"Prefix to filter by","required":false,"schema":{"type":"string"}},{"name":"cursor","in":"query","description":"Continuation token for pagination","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of blobs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListBlobsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Blob"],"summary":"Upload a blob","operationId":"blob_put","requestBody":{"description":"Binary blob data","content":{"application/octet-stream":{"schema":{"type":"string"}}},"required":true},"responses":{"201":{"description":"Blob uploaded successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlobResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Blob"],"summary":"Delete blobs","operationId":"blob_delete","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteBlobRequest"}}},"required":true},"responses":{"200":{"description":"Blobs deleted successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteBlobResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/blob/copy":{"post":{"tags":["Blob"],"summary":"Copy a blob to a new location","operationId":"blob_copy","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CopyBlobRequest"}}},"required":true},"responses":{"200":{"description":"Blob copied successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlobResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Source blob not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/blob/disable":{"delete":{"tags":["Blob Management"],"summary":"Disable Blob service","operationId":"blob_disable","responses":{"200":{"description":"Blob service disabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DisableBlobResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Blob service not enabled"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/blob/enable":{"post":{"tags":["Blob Management"],"summary":"Enable Blob service","operationId":"blob_enable","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnableBlobRequest"}}},"required":true},"responses":{"200":{"description":"Blob service enabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnableBlobResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/blob/status":{"get":{"tags":["Blob Management"],"summary":"Get Blob service status","operationId":"blob_status","responses":{"200":{"description":"Blob service status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlobStatusResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/blob/update":{"patch":{"tags":["Blob Management"],"summary":"Update Blob service configuration","operationId":"blob_update","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateBlobRequest"}}},"required":true},"responses":{"200":{"description":"Blob service updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateBlobResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Blob service not enabled"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/blob/{project_id}/{path}":{"get":{"tags":["Blob"],"summary":"Download a blob","operationId":"blob_download","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","description":"Blob path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Blob content"},"404":{"description":"Blob not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"head":{"tags":["Blob"],"summary":"Get blob metadata","operationId":"blob_head","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","description":"Blob path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Blob metadata in headers"},"404":{"description":"Blob not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/dashboard/projects-analytics":{"get":{"tags":["Events"],"summary":"Get dashboard analytics for multiple projects in a single batch request","description":"Returns unique visitor counts and hourly sparkline data for all requested projects\nusing only 2 SQL queries instead of 2×N per-project queries.","operationId":"get_dashboard_projects_analytics","parameters":[{"name":"project_ids","in":"query","description":"Comma-separated list of project IDs","required":true,"schema":{"type":"string"}},{"name":"start_date","in":"query","description":"Start date for filtering","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date for filtering","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved batch analytics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DashboardProjectsAnalyticsResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/deployments/activity-graph":{"get":{"tags":["Deployments"],"summary":"Get deployment activity graph showing daily deployment counts\nSimilar to GitHub's contribution graph","operationId":"get_activity_graph","parameters":[{"name":"project_id","in":"query","description":"Filter by project ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"days","in":"query","description":"Number of days to include (default: 365)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved activity graph","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivityGraphResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/deployments/{deployment_id}/vulnerability-scan":{"get":{"tags":["Vulnerability Scans"],"operationId":"get_scan_by_deployment","parameters":[{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Scan for the specified deployment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScanResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"No scan found for deployment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/deployments/{id}/metrics":{"get":{"tags":["Metrics"],"summary":"Fetch a time-series range for a single metric on a deployment.","operationId":"DeploymentMetricsGetRange","parameters":[{"name":"id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"metric","in":"query","description":"Metric name, e.g. `\"pg.connections_active\"`.","required":true,"schema":{"type":"string"}},{"name":"range","in":"query","description":"Time window: `\"1h\"` | `\"6h\"` | `\"24h\"` | `\"7d\"`.","required":false,"schema":{"type":"string"}},{"name":"percentile","in":"query","description":"Optional histogram percentile (0–100). When provided, the endpoint\nfetches histogram buckets and computes the requested quantile.","required":false,"schema":{"type":["number","null"],"format":"double"}}],"responses":{"200":{"description":"Metric time series data points","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MetricDataPoint"}}}}},"400":{"description":"Invalid query parameters"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"},"503":{"description":"Metrics store not available"}},"security":[{"bearer_auth":[]}]}},"/deployments/{id}/metrics/enable":{"patch":{"tags":["Metrics"],"summary":"Enable or disable OTLP metric ingestion for a deployment.","description":"When `enabled=true`, seeds the default container alert rules for the\ndeployment via [`temps_monitoring::seed_default_container_rules`] (idempotent).","operationId":"DeploymentMetricsToggle","parameters":[{"name":"id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToggleDeploymentMetricsRequest"}}},"required":true},"responses":{"200":{"description":"Metrics toggle applied"},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/deployments/{id}/metrics/latest":{"get":{"tags":["Metrics"],"summary":"Fetch the most-recent metric values for a deployment.","operationId":"DeploymentMetricsGetLatest","parameters":[{"name":"id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Map of metric name to latest value","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"number","format":"double"},"propertyNames":{"type":"string"}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"},"503":{"description":"Metrics store not available"}},"security":[{"bearer_auth":[]}]}},"/dns-providers":{"get":{"tags":["DNS Providers"],"summary":"List all DNS providers","operationId":"list_dns_providers","responses":{"200":{"description":"List of DNS providers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/DnsProviderResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["DNS Providers"],"summary":"Create a new DNS provider","description":"The provider's credentials will be tested before creation.\nIf the connection test fails, the provider will not be created.","operationId":"create_dns_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDnsProviderRequest"}}},"required":true},"responses":{"201":{"description":"DNS provider created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsProviderResponse"}}}},"400":{"description":"Invalid request or connection test failed"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{id}":{"get":{"tags":["DNS Providers"],"summary":"Get a DNS provider by ID","operationId":"get_dns_provider","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"DNS provider details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsProviderResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["DNS Providers"],"summary":"Update a DNS provider","description":"If new credentials are supplied, they are tested before the update is\npersisted (same as creation) -- otherwise a provider's credentials (and,\nfor Pebble, its target URL) could be swapped for something invalid or\nunsafe without ever going through validation.","operationId":"update_provider","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDnsProviderRequest"}}},"required":true},"responses":{"200":{"description":"DNS provider updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsProviderResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["DNS Providers"],"summary":"Delete a DNS provider","operationId":"delete_dns_provider","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"DNS provider deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{id}/domains":{"get":{"tags":["DNS Providers"],"summary":"List managed domains for a provider","operationId":"list_managed_domains","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of managed domains","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ManagedDomainResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["DNS Providers"],"summary":"Add a managed domain to a provider","operationId":"add_managed_domain","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddManagedDomainApiRequest"}}},"required":true},"responses":{"201":{"description":"Managed domain added","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagedDomainResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{id}/test":{"post":{"tags":["DNS Providers"],"summary":"Test provider connection","operationId":"test_provider_connection","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Connection test result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectionTestResult"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{id}/zones":{"get":{"tags":["DNS Providers"],"summary":"List zones available in a provider","operationId":"list_provider_zones","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of zones","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ZoneListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{provider_id}/domains/{domain}":{"delete":{"tags":["DNS Providers"],"summary":"Remove a managed domain","operationId":"remove_managed_domain","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Managed domain removed"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["DNS Providers"],"summary":"Update a managed domain's settings (hostname mode, sync opt-in, auto-manage).","operationId":"update_managed_domain","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateManagedDomainApiRequest"}}},"required":true},"responses":{"200":{"description":"Managed domain updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagedDomainResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{provider_id}/domains/{domain}/apply-hostname-mode":{"post":{"tags":["DNS Providers"],"summary":"Apply a hostname mode to a managed domain (persist + optional DNS sync +\nroute reload).","operationId":"apply_hostname_mode","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApplyHostnameModeRequest"}}},"required":true},"responses":{"200":{"description":"Hostname mode applied","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HostnamePreviewResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions or token lacks zone access"},"404":{"description":"Domain not found"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{provider_id}/domains/{domain}/hostname-preview":{"get":{"tags":["DNS Providers"],"summary":"Preview the impact of switching a managed domain's hostname mode.","operationId":"preview_hostname_mode","parameters":[{"name":"mode","in":"query","description":"Target mode: standard|flat","required":true,"schema":{"type":"string"}},{"name":"sync","in":"query","description":"Include DNS record changes","required":false,"schema":{"type":"boolean"}},{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Hostname mode preview","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HostnamePreviewResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{provider_id}/domains/{domain}/verify":{"post":{"tags":["DNS Providers"],"summary":"Verify a managed domain","operationId":"verify_managed_domain","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Domain verification result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagedDomainResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"}},"security":[{"bearer_auth":[]}]}},"/dns/lookup":{"get":{"tags":["DNS"],"summary":"Lookup DNS A records for a domain","operationId":"lookup_dns_a_records","parameters":[{"name":"domain","in":"query","description":"Domain name to lookup","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved DNS A records","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsLookupResponse"}}}},"400":{"description":"Invalid domain name or lookup failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsLookupError"}}}}}}},"/domains":{"get":{"tags":["Domains"],"summary":"List all domains","operationId":"list_domains","parameters":[{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20},{"name":"search","in":"query","description":"Search domains by name (substring match)","required":false,"schema":{"type":["string","null"]},"example":"example.com"}],"responses":{"200":{"description":"Domains retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListDomainsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Domains"],"summary":"Create a new domain","description":"Creates a new domain and automatically requests a Let's Encrypt challenge.\nYou can specify the challenge type (HTTP-01 or DNS-01) in the request.\n\n- **HTTP-01**: Validates domain ownership by placing a file on your web server at `/.well-known/acme-challenge/`\n- **DNS-01**: Validates domain ownership by adding a TXT record to your DNS (required for wildcard domains)","operationId":"create_domain","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDomainRequest"}}},"required":true},"responses":{"201":{"description":"Domain created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainResponse"}}}},"400":{"description":"Invalid input"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/by-host/{hostname}":{"get":{"tags":["Domains"],"summary":"Get domain details by hostname","operationId":"get_domain_by_host","parameters":[{"name":"hostname","in":"path","description":"Domain hostname","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Domain details retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/by-host/{hostname}/cert-status":{"get":{"tags":["Domains"],"summary":"Get on-demand TLS certificate status for a hostname","description":"Returns the current cert lifecycle state for a single hostname (from the\n`domains` row) plus the most recent on-demand issuance attempt (from the\n`on_demand_cert_attempts` audit log). This is the operator's first-line\ndiagnostic, surfaced by `temps domain cert-status` (ADR-018 §5). Returns the\nhostname with `None` fields when no on-demand activity exists for it (never a\n404, so the CLI can render \"no attempts recorded\").","operationId":"get_on_demand_cert_status","parameters":[{"name":"hostname","in":"path","description":"Domain hostname","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"On-demand cert status retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CertStatusResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/on-demand-certs":{"get":{"tags":["Domains"],"summary":"List on-demand TLS certificate attempts","description":"Returns rows from the append-only `on_demand_cert_attempts` audit log\n(ADR-018 §5), newest first, each joined with the current authoritative cert\nstate (`status`, `expiration_time`, `backoff_until`) from the `domains` row.\nThis backs the console \"Certificates\" surface. No certificate or private-key\nmaterial is returned — only audit metadata.","operationId":"list_on_demand_certs","parameters":[{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20}],"responses":{"200":{"description":"On-demand cert attempts retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListOnDemandCertsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain_id}/order":{"get":{"tags":["Domains"],"summary":"Get ACME order for a domain","operationId":"get_domain_order","parameters":[{"name":"domain_id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Order retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AcmeOrderResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Order not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Domains"],"summary":"Create or recreate ACME order for a domain","description":"Creates a new ACME order with Let's Encrypt for the specified domain.\nIf an order already exists, you should cancel it first using the cancel-order endpoint.\nReturns the challenge details that need to be fulfilled (DNS record or HTTP token).","operationId":"create_or_recreate_order","parameters":[{"name":"domain_id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Order created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainChallengeResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Domains"],"summary":"Cancel ACME order for a domain","description":"Cancels the current ACME order for a domain and clears all challenge data.\nThis allows you to start over with a new order if the previous one failed or got stuck.","operationId":"cancel_domain_order","parameters":[{"name":"domain_id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Order cancelled successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain_id}/order/finalize":{"post":{"tags":["Domains"],"summary":"Finalize ACME order for a domain","description":"Finalizes the ACME order by completing the challenge validation and requesting the certificate.\nThis should be called after the challenge has been set up (DNS record added or HTTP token served).","operationId":"finalize_order","parameters":[{"name":"domain_id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Order finalized successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain or order not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain_id}/setup-dns":{"post":{"tags":["Domains"],"summary":"Setup DNS challenge records automatically using a DNS provider","description":"This endpoint automatically creates the required DNS TXT records for ACME DNS-01 challenge\nvalidation using a configured DNS provider. The domain must have an active DNS challenge\npending (created via POST /domains/{id}/order with dns-01 challenge type).\n\nThis is similar to how email domain DNS records are auto-provisioned.","operationId":"setup_dns_challenge","parameters":[{"name":"domain_id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetupDnsChallengeRequest"}}},"required":true},"responses":{"200":{"description":"DNS records created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetupDnsChallengeResponse"}}}},"400":{"description":"Bad request - DNS provider not configured or no challenge pending"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain or DNS provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain}":{"get":{"tags":["Domains"],"summary":"Get domain by ID","operationId":"get_domain_by_id","parameters":[{"name":"domain","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Domain retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Domains"],"summary":"Delete a domain","operationId":"delete_domain","parameters":[{"name":"domain","in":"path","description":"Domain name","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Domain deleted successfully"},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain}/challenge-token":{"get":{"tags":["Domains"],"summary":"Get challenge token for a domain (returns plain text token)","operationId":"get_challenge_token","parameters":[{"name":"domain","in":"path","description":"Domain name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Challenge token retrieved successfully","content":{"text/plain":{"schema":{"type":"string"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Challenge not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain}/http-challenge-debug":{"get":{"tags":["Domains"],"summary":"Get HTTP challenge debug information","description":"Returns detailed debug information for HTTP-01 challenge including:\n- Whether a challenge exists for the domain\n- The challenge token and URL that Let's Encrypt will access\n- DNS resolution information showing where the domain currently points\n\nThis is useful for debugging why HTTP-01 challenges fail.","operationId":"get_http_challenge_debug","parameters":[{"name":"domain","in":"path","description":"Domain name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Debug information retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpChallengeDebugResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain}/provision":{"post":{"tags":["Domains"],"summary":"Provision a domain certificate","operationId":"provision_domain","parameters":[{"name":"domain","in":"path","description":"Domain name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Certificate provisioning initiated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProvisionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain}/renew":{"post":{"tags":["Domains"],"summary":"Renew domain certificate","description":"For HTTP-01 domains: Automatically renews the certificate\nFor DNS-01 domains (wildcards): Creates a new ACME order and returns challenge data","operationId":"renew_domain","parameters":[{"name":"domain","in":"path","description":"Domain name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Certificate renewal initiated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProvisionResponse"}}}},"202":{"description":"DNS challenge created - manual action required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainChallengeResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain}/status":{"get":{"tags":["Domains"],"summary":"Check domain status","operationId":"check_domain_status","parameters":[{"name":"domain","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Domain status retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/drop/inspect":{"post":{"tags":["Projects"],"summary":"Inspect a source ZIP without creating a project or retaining the upload.","operationId":"inspect_drop_archive","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/DropArchiveUpload"}}},"required":true},"responses":{"200":{"description":"Detected deployable project roots","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DropInspectionResponse"}}}},"400":{"description":"Invalid or unsupported archive"}},"security":[{"bearer_auth":[]}]}},"/email-domains":{"get":{"tags":["Email Domains"],"summary":"List all email domains","operationId":"list_email_domains","parameters":[{"name":"provider_id","in":"query","description":"Only return domains belonging to this provider","required":false,"schema":{"type":["integer","null"],"format":"int32"}}],"responses":{"200":{"description":"List of email domains","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EmailDomainResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Email Domains"],"summary":"Create a new email domain","operationId":"create_email_domain","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEmailDomainRequest"}}},"required":true},"responses":{"201":{"description":"Domain created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailDomainWithDnsResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-domains/by-domain/{domain}":{"get":{"tags":["Email Domains"],"summary":"Get an email domain by domain name with DNS records","operationId":"get_domain_by_name","parameters":[{"name":"domain","in":"path","description":"Domain name (e.g., 'mail.example.com')","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Email domain details with DNS records","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailDomainWithDnsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-domains/{id}":{"get":{"tags":["Email Domains"],"summary":"Get an email domain by ID with DNS records","operationId":"get_domain","parameters":[{"name":"id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Email domain details with DNS records","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailDomainWithDnsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Email Domains"],"summary":"Delete an email domain","operationId":"delete_email_domain","parameters":[{"name":"id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Domain deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-domains/{id}/dns-records":{"get":{"tags":["Email Domains"],"summary":"Get DNS records for an email domain","operationId":"get_domain_dns_records","parameters":[{"name":"id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"DNS records for the domain","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/DnsRecordResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-domains/{id}/setup-dns":{"post":{"tags":["Email Domains"],"summary":"Setup DNS records for an email domain using a configured DNS provider","operationId":"setup_dns","parameters":[{"name":"id","in":"path","description":"Email Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetupDnsRequest"}}},"required":true},"responses":{"200":{"description":"DNS records setup result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetupDnsResponse"}}}},"400":{"description":"Invalid request or DNS provider not configured"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-domains/{id}/verify":{"post":{"tags":["Email Domains"],"summary":"Verify an email domain's DNS configuration","operationId":"verify_domain","parameters":[{"name":"id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Domain verification result with DNS records","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailDomainWithDnsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-providers":{"get":{"tags":["Email Providers"],"summary":"List all email providers","operationId":"list_email_providers","responses":{"200":{"description":"List of email providers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EmailProviderResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Email Providers"],"summary":"Create a new email provider","operationId":"create_email_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEmailProviderRequest"}}},"required":true},"responses":{"201":{"description":"Provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailProviderResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-providers/{id}":{"get":{"tags":["Email Providers"],"summary":"Get an email provider by ID","operationId":"get_email_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Email provider details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailProviderResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Email Providers"],"summary":"Delete an email provider","operationId":"delete_email_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Provider deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Email Providers"],"summary":"Update an email provider","description":"Partial update — any field left out keeps its current value. Most importantly,\nomitting the credential block (`ses_credentials`/`scaleway_credentials`/`smtp_credentials`)\npreserves the stored secret, so operators can rename a provider without re-typing\npasswords. `provider_type` is immutable; to switch providers, delete and recreate.","operationId":"update_email_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEmailProviderRequest"}}},"required":true},"responses":{"200":{"description":"Provider updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailProviderResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"},"409":{"description":"Provider type mismatch"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-providers/{id}/test":{"post":{"tags":["Email Providers"],"summary":"Test an email provider by sending a test email to the logged-in user","operationId":"test_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestEmailRequest"}}},"required":true},"responses":{"200":{"description":"Test email result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestEmailResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-providers/{id}/tracking/setup":{"post":{"tags":["Email Providers"],"summary":"One-click AWS-side setup of SES event tracking (SNS topic + webhook\nsubscription + SESv2 event destination), using the provider's stored\ncredentials.","operationId":"setup_email_tracking","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Setup completed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailTrackingSetupResponse"}}}},"400":{"description":"Provider does not support event tracking"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"},"502":{"description":"An AWS call failed — the response detail names the failed step"}},"security":[{"bearer_auth":[]}]}},"/email-providers/{id}/tracking/status":{"get":{"tags":["Email Providers"],"summary":"Live status of SES event tracking for a provider","operationId":"get_email_tracking_status","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Event tracking status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailTrackingStatusResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]}},"/emails":{"get":{"tags":["Emails"],"summary":"List emails with optional filtering","operationId":"list_emails","parameters":[{"name":"domain_id","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"project_id","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"status","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"from_address","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"page","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"page_size","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}}],"responses":{"200":{"description":"List of emails","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedEmailsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Emails"],"summary":"Send an email","operationId":"send_email","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendEmailRequestBody"}}},"required":true},"responses":{"201":{"description":"Email sent successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendEmailResponseBody"}}}},"400":{"description":"Invalid request or domain not verified"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/emails/events":{"get":{"tags":["Email Tracking"],"summary":"GET /emails/events","operationId":"get_global_events","parameters":[{"name":"event_type","in":"query","description":"Filter by event type (open, click)","required":false,"schema":{"type":"string"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Paginated tracking events","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedEventsResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/emails/events/stats":{"get":{"tags":["Email Tracking"],"summary":"GET /emails/events/stats","operationId":"get_global_event_stats","responses":{"200":{"description":"Global tracking statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GlobalEventStatsResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/emails/stats":{"get":{"tags":["Emails"],"summary":"Get email statistics","operationId":"get_email_stats","parameters":[{"name":"domain_id","in":"query","description":"Optional domain ID to filter stats","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Email statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailStatsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/emails/validate":{"post":{"tags":["Email Validation"],"summary":"Validate an email address","operationId":"validate_email","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateEmailRequest"}}},"required":true},"responses":{"200":{"description":"Email validation result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateEmailResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/emails/{email_id}/track/click/{link_index}":{"get":{"tags":["Email Tracking"],"summary":"Track email link click - redirects to original URL","description":"This endpoint replaces original links in tracked emails.\nNo authentication required - it's called when the recipient clicks a link.","operationId":"track_click","parameters":[{"name":"email_id","in":"path","description":"Email ID (UUID)","required":true,"schema":{"type":"string"}},{"name":"link_index","in":"path","description":"Link index","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"302":{"description":"Redirect to original URL"},"404":{"description":"Link not found"}}}},"/emails/{email_id}/track/open":{"get":{"tags":["Email Tracking"],"summary":"Track email open - returns a 1x1 transparent GIF","description":"This endpoint is embedded as an tag in emails.\nNo authentication required - it's called by the email client.","operationId":"track_open","parameters":[{"name":"email_id","in":"path","description":"Email ID (UUID)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"1x1 transparent tracking pixel"},"404":{"description":"Email not found"}}}},"/emails/{id}":{"get":{"tags":["Emails"],"summary":"Get an email by ID","operationId":"get_email","parameters":[{"name":"id","in":"path","description":"Email ID (UUID)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Email details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Email not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/emails/{id}/tracking":{"get":{"tags":["Email Tracking"],"summary":"Get email tracking summary","operationId":"get_email_tracking","parameters":[{"name":"id","in":"path","description":"Email ID (UUID)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Tracking summary","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailTrackingResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Email not found"}},"security":[{"bearer_auth":[]}]}},"/emails/{id}/tracking/events":{"get":{"tags":["Email Tracking"],"summary":"Get email tracking events","operationId":"get_email_events","parameters":[{"name":"id","in":"path","description":"Email ID (UUID)","required":true,"schema":{"type":"string"}},{"name":"event_type","in":"query","description":"Filter by event type (open, click)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Tracking events","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TrackingEventResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Email not found"}},"security":[{"bearer_auth":[]}]}},"/emails/{id}/tracking/links":{"get":{"tags":["Email Tracking"],"summary":"Get tracked links for an email","operationId":"get_email_links","parameters":[{"name":"id","in":"path","description":"Email ID (UUID)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Tracked links","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TrackedLinkResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Email not found"}},"security":[{"bearer_auth":[]}]}},"/external-services":{"get":{"tags":["External Services"],"summary":"Get all external services","operationId":"list_services","parameters":[{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20},{"name":"sort_by","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"List of external services","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}}},"500":{"description":"Internal server error"}}},"post":{"tags":["External Services"],"summary":"Create new external service","operationId":"create_service","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateExternalServiceRequest"}}},"required":true},"responses":{"201":{"description":"Service created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}},"400":{"description":"Invalid request"},"500":{"description":"Internal server error"}}}},"/external-services/available-containers":{"get":{"tags":["External Services"],"summary":"List available Docker containers that can be imported as services","operationId":"list_available_containers","responses":{"200":{"description":"List of available containers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AvailableContainerInfo"}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/by-slug/{slug}":{"get":{"tags":["External Services"],"summary":"Get external service details by slug","operationId":"get_service_by_slug","parameters":[{"name":"slug","in":"path","description":"External service slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"External service details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceDetails"}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/health-status-batch":{"get":{"tags":["External Services"],"summary":"Current health status for many services at once","description":"Powers the status dot on the Storage list page. Pass a comma-separated\nlist of service IDs via `?ids=1,2,3`. Omit to get every service.","operationId":"list_service_health_statuses","parameters":[{"name":"ids","in":"query","description":"Comma-separated service IDs. Omit for all services.","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Batch of current health statuses","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceHealthStatusBatchResponse"}}}},"500":{"description":"Internal server error"}}}},"/external-services/import":{"post":{"tags":["External Services"],"summary":"Import an existing Docker container as a managed external service","operationId":"import_external_service","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportExternalServiceRequest"}}},"required":true},"responses":{"201":{"description":"Service imported successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/projects/{project_id}":{"get":{"tags":["External Services"],"summary":"List services linked to a project","operationId":"list_project_services","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20},{"name":"sort_by","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"List of services linked to project","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProjectServiceInfo"}}}}},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}}},"/external-services/projects/{project_id}/environment":{"get":{"tags":["External Services"],"summary":"Get all environment variables for all services linked to a project","operationId":"get_project_service_environment_variables","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Map of service IDs to their environment variables","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"object","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"propertyNames":{"type":"integer","format":"int32"}}}}},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}}},"/external-services/providers/metadata":{"get":{"tags":["External Services"],"summary":"Get provider metadata (display names, icons, descriptions)","operationId":"get_providers_metadata","responses":{"200":{"description":"List of provider metadata","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProviderMetadata"}}}}},"500":{"description":"Internal server error"}}}},"/external-services/providers/metadata/{service_type}":{"get":{"tags":["External Services"],"summary":"Get metadata for a specific provider","operationId":"get_provider_metadata","parameters":[{"name":"service_type","in":"path","description":"Service type (mongodb, postgres, redis, s3)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Provider metadata","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderMetadata"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}}}},"/external-services/types":{"get":{"tags":["External Services"],"summary":"Get available service types","operationId":"get_service_types","responses":{"200":{"description":"List of available service types","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ServiceTypeRoute"}}}}},"500":{"description":"Internal server error"}}}},"/external-services/types/{service_type}/parameters":{"get":{"tags":["External Services"],"summary":"Get parameter schema for a specific service type","operationId":"get_service_type_parameters","parameters":[{"name":"service_type","in":"path","description":"Service type","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Service type parameter schema"},"404":{"description":"Service type not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}":{"get":{"tags":["External Services"],"summary":"Get external service details","operationId":"get_service","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"External service details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceDetails"}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}},"put":{"tags":["External Services"],"summary":"Update external service","operationId":"update_service","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateExternalServiceRequest"}}},"required":true},"responses":{"200":{"description":"Service updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}},"400":{"description":"Invalid request"},"404":{"description":"Service not found"},"409":{"description":"A major upgrade is in progress for this service"},"500":{"description":"Internal server error"}}},"delete":{"tags":["External Services"],"summary":"Delete external service","operationId":"delete_service","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Service deleted successfully"},"400":{"description":"Cannot delete: service is still linked to projects"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/cluster-health":{"get":{"tags":["External Services"],"summary":"Per-member health for a Postgres HA cluster.","description":"Reads pg_auto_failover's `pgautofailover.node` table from the cluster's\nmonitor (TLS, autoctl_node) and joins each member with its\n`pg_stat_replication` row from the current primary. Returns one row per\ndata member with role/state, sync state, and replay lag.\n\nReturns `200` with `monitor_error` set when the monitor is briefly\nunreachable (UI surfaces it as a banner above the table); the table\nitself is empty in that case. Returns `400` for non-cluster services.","operationId":"get_cluster_health","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Per-member cluster health report","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClusterHealthReportResponse"}}}},"400":{"description":"Service is not a cluster"},"401":{"description":"Unauthorized"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/health-check":{"post":{"tags":["External Services"],"summary":"Run a health check for one service right now","description":"Triggers the same engine-specific probe as the background monitor, writes\na history row, updates the denormalized fields on `external_services`, and\nfires alerts on the Nth consecutive failure (so consecutive-failure state\nstays honest). Returns the fresh snapshot the UI can display immediately.","operationId":"trigger_service_health_check","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Fresh health snapshot after probing","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceHealthResponse"}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"},"503":{"description":"Health monitor not running on this node"}}}},"/external-services/{id}/health-status":{"get":{"tags":["External Services"],"summary":"Persisted health status for an external service","description":"Returns the latest health probe result recorded by\n`ExternalServiceHealthMonitor`, plus recent check history for sparklines\nand a 24-hour uptime percentage. Safe to poll from the UI every 30s.","operationId":"get_service_health_status","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"limit","in":"query","description":"Max number of recent checks (default 50, max 200)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Current health + recent history","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceHealthResponse"}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/members":{"post":{"tags":["External Services"],"summary":"Begin adding a single new member to a running cluster.","description":"Currently only `replica` members can be added at runtime. The\nresponse is **202 Accepted** as soon as the validation passes and\nthe placeholder `service_members` row is inserted. The actual\ncontainer provisioning + DNS registration runs in the background;\npoll `GET /external-services/{id}/members/{member_id}` to watch\n`provisioning_step` advance through the phases.","operationId":"add_cluster_member","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddClusterMemberRequest"}}},"required":true},"responses":{"202":{"description":"Cluster member provisioning started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceMemberInfo"}}}},"400":{"description":"Validation failed (wrong topology, status, or role)"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/members/{member_id}":{"get":{"tags":["External Services"],"summary":"Get a single cluster member's current state.","description":"Used by the add-member page to poll the row every second while the\nbackground provisioning task walks through its phases. The\n`provisioning_step` field advances through `inserting_row` →\n`provisioning_container` → `registering_dns` → `done` (or `failed`\nwith `provisioning_error` set).","operationId":"get_cluster_member","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"member_id","in":"path","description":"Cluster member ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Cluster member details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceMemberInfo"}}}},"404":{"description":"Service or member not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["External Services"],"summary":"Remove a single member from a running cluster.","description":"Refuses to remove the monitor (singleton), the current primary\n(failover first), or any member if the cluster would drop below the\n2-data-member quorum required for HA. Stops + removes the container,\ndeletes the row, and drops the Tier-2 DNS record.","operationId":"remove_cluster_member","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"member_id","in":"path","description":"Cluster member ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Cluster member removed"},"400":{"description":"Validation failed (monitor, primary, or quorum violation)"},"404":{"description":"Service or member not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/members/{member_id}/promote":{"post":{"tags":["External Services"],"summary":"Promote a replica to primary by triggering a pg_auto_failover\nfailover. The monitor demotes the current primary and the chosen\nreplica transitions to primary; the role reconciler then refreshes\nthe role-aliased VIPs (≤30s).","operationId":"promote_cluster_member","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"member_id","in":"path","description":"Cluster member ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"202":{"description":"Promotion initiated"},"400":{"description":"Validation failed (monitor, already primary, not running, etc.)"},"404":{"description":"Service or member not found"},"500":{"description":"pg_autoctl perform promotion failed"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/metrics":{"get":{"tags":["Metrics"],"summary":"Fetch a time-series range for a single metric on an external service.","description":"Pass `percentile` to compute a histogram quantile instead of a plain\ngauge/counter average.","operationId":"ExternalServiceMetricsGetRange","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"metric","in":"query","description":"Metric name, e.g. `\"pg.connections_active\"`.","required":true,"schema":{"type":"string"}},{"name":"range","in":"query","description":"Time window: `\"1h\"` | `\"6h\"` | `\"24h\"` | `\"7d\"`.","required":false,"schema":{"type":"string"}},{"name":"percentile","in":"query","description":"Optional histogram percentile (0–100). When provided, the endpoint\nfetches histogram buckets and computes the requested quantile.","required":false,"schema":{"type":["number","null"],"format":"double"}}],"responses":{"200":{"description":"Metric time series data points","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MetricDataPoint"}}}}},"400":{"description":"Invalid query parameters"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"},"503":{"description":"Metrics store not available"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/metrics/alert-rules":{"get":{"tags":["Metrics"],"summary":"List all monitoring alert rules for an external service.","operationId":"ExternalServiceMetricsGetAlertRules","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of alert rules","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ServiceAlertRuleResponse"}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Metrics"],"summary":"Create a monitoring alert rule for an external service.","description":"If metric collection is enabled and the service engine has default rules,\nseeding is idempotent (ON CONFLICT DO NOTHING).","operationId":"ExternalServiceMetricsCreateAlertRule","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceCreateAlertRuleRequest"}}},"required":true},"responses":{"201":{"description":"Alert rule created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceAlertRuleResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/metrics/alert-rules/{rule_id}":{"put":{"tags":["Metrics"],"summary":"Update an existing monitoring alert rule for an external service.","operationId":"ExternalServiceMetricsUpdateAlertRule","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"rule_id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceUpdateAlertRuleRequest"}}},"required":true},"responses":{"200":{"description":"Updated alert rule","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceAlertRuleResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Alert rule not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Metrics"],"summary":"Delete a monitoring alert rule for an external service.","operationId":"ExternalServiceMetricsDeleteAlertRule","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"rule_id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Alert rule deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Alert rule not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/metrics/by-database":{"get":{"tags":["Metrics"],"summary":"Return the latest per-database metric values for a Postgres service.","description":"Groups `pg_stat_database` / size metrics by `datname` so the UI can show a\nbreakdown table (each database with its own size, cache-hit ratio, etc.)\nrather than collapsing every database into one value.","operationId":"ExternalServiceMetricsByDatabase","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Per-database metric breakdown","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DatabaseMetricsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"},"503":{"description":"Metrics not available"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/metrics/enable":{"patch":{"tags":["Metrics"],"summary":"Enable or disable metric collection for an external service.","description":"When `enabled=true`, seeds the default alert rules for the service's engine\nvia [`temps_monitoring::seed_default_rules`] (idempotent).","operationId":"ExternalServiceMetricsToggle","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToggleServiceMetricsRequest"}}},"required":true},"responses":{"200":{"description":"Metrics toggle applied"},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/metrics/latest":{"get":{"tags":["Metrics"],"summary":"Fetch the most-recent value for every tracked metric on an external service.","operationId":"ExternalServiceMetricsGetLatest","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Map of metric name to latest value","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"number","format":"double"},"propertyNames":{"type":"string"}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"},"503":{"description":"Metrics store not available"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/metrics/status":{"get":{"tags":["Metrics"],"summary":"Return the freshness status (last-received timestamp) for a service.","description":"Cheap O(1) lookup against `service_metrics_status` — used by the UI to show\n\"last received at …\" without scanning the metrics hypertable.","operationId":"ExternalServiceMetricsStatus","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Metrics freshness status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MetricsStatusResponse"}}}},"503":{"description":"Metrics not available"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/parameters/{param_name}":{"get":{"tags":["External Services"],"summary":"Reveal one sensitive service parameter. Service detail responses never\ncontain plaintext values; every successful reveal is recorded separately.","operationId":"reveal_service_parameter","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"param_name","in":"path","description":"Sensitive parameter name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sensitive parameter value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SensitiveValueResponse"}}}},"400":{"description":"Parameter is not sensitive"},"403":{"description":"Caller cannot access a project linked to this service"},"404":{"description":"Service or parameter not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/preview-environment-masked":{"get":{"tags":["External Services"],"summary":"Get environment variables preview with masked sensitive values","operationId":"get_service_preview_environment_variables_masked","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Preview of environment variables with sensitive values masked as ***","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/preview-environment-names":{"get":{"tags":["External Services"],"summary":"Get environment variable names preview (safe - no sensitive values)","operationId":"get_service_preview_environment_variable_names","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of environment variable names that would be provided","content":{"application/json":{"schema":{"type":"array","items":{"type":"string"}}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/projects":{"get":{"tags":["External Services"],"summary":"List projects linked to service","operationId":"list_service_projects","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20},{"name":"sort_by","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"List of linked projects","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProjectServiceInfo"}}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}},"post":{"tags":["External Services"],"summary":"Link service to project","operationId":"link_service_to_project","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LinkServiceRequest"}}},"required":true},"responses":{"201":{"description":"Service linked to project successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectServiceInfo"}}}},"404":{"description":"Service or project not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/projects/{project_id}":{"delete":{"tags":["External Services"],"summary":"Unlink service from project","operationId":"unlink_service_from_project","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Service unlinked from project successfully"},"404":{"description":"Service link not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/projects/{project_id}/environment":{"get":{"tags":["External Services"],"summary":"Get all environment variables for a service-project pair","operationId":"get_service_environment_variables","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of environment variables","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EnvironmentVariableInfo"}}}}},"404":{"description":"Service or project not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/projects/{project_id}/environment/{var_name}":{"get":{"tags":["External Services"],"summary":"Get specific environment variable for a service-project pair","operationId":"get_service_environment_variable","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"var_name","in":"path","description":"Environment variable name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Environment variable value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentVariableInfo"}}}},"403":{"description":"Plaintext secret access is not permitted"},"404":{"description":"Service, project, or variable not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/resources":{"patch":{"tags":["External Services"],"summary":"Update a service's resource limits (memory, CPU caps).","description":"Persists the new caps to the encrypted config AND live-applies them\nvia Docker's update API. Memory and CPU can be hot-changed without a\nrestart on running containers; stopped containers also accept the\nupdate and pick up the new caps on next start.\n\nPass `null` (or omit) any field to leave it unlimited. A request where\nevery field is `null` removes any existing limits.\n\nThe response includes a per-container `applied[]` list so the caller\ncan tell which members got the update and which were skipped (e.g.,\ncontainer not yet created, or `docker update` rejected because the\nnew memory cap is below current usage).","operationId":"update_service_resources","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceResourceLimits"}}},"required":true},"responses":{"200":{"description":"Updated resource limits","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResourceLimitsUpdateResponse"}}}},"400":{"description":"Invalid resource limits"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/restore":{"post":{"tags":["Restore"],"operationId":"start_restore","parameters":[{"name":"id","in":"path","description":"External service id (source for the restore)","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartRestoreRequest"}}},"required":true},"responses":{"202":{"description":"Restore run started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RestoreRunView"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Backup or service not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/restore-capabilities":{"get":{"tags":["Restore"],"operationId":"get_restore_capabilities","parameters":[{"name":"id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Capabilities declared by the service","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RestoreCapabilitiesResponse"}}}},"404":{"description":"Service not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/restore-plan":{"post":{"tags":["Restore"],"operationId":"plan_restore","parameters":[{"name":"id","in":"path","description":"Target service id","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartRestoreRequest"}}},"required":true},"responses":{"200":{"description":"Preview of what the restore will do","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RestorePlan"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Backup or service not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/restore-runs":{"get":{"tags":["Restore"],"operationId":"list_restore_runs_for_service","parameters":[{"name":"id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Recent restore runs for the service","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RestoreRunView"}}}}}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/retry":{"post":{"tags":["External Services"],"summary":"Retry a failed cluster service initialization.","description":"Cleans up any leftover containers from the previous attempt and\nre-runs cluster initialization with the provided member specifications.","operationId":"retry_cluster","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RetryClusterRequest"}}},"required":true},"responses":{"200":{"description":"Cluster retry initiated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}},"400":{"description":"Service is not a failed cluster"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/runtime":{"get":{"tags":["External Services"],"summary":"Inspect a service's container(s): status, restart count, OOM-killed flag,\nexit code, and the cgroup limits actually applied.","operationId":"get_service_runtime","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Container runtime snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceRuntimeReport"}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/start":{"post":{"tags":["External Services"],"summary":"Start an external service","operationId":"start_service","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Service started successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}},"404":{"description":"Service not found"},"409":{"description":"A Postgres major upgrade is in progress for this service"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/stats":{"get":{"tags":["External Services"],"summary":"Sample current CPU/memory usage from each of a service's containers.\nOne-shot sample, no streaming. Cheap to call (single Docker round-trip\nper member) so the UI can poll on a 5–10s interval.","operationId":"get_service_stats","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Container stats snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceStatsReport"}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/stop":{"post":{"tags":["External Services"],"summary":"Stop an external service","operationId":"stop_service","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Service stopped successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/upgrade":{"post":{"tags":["External Services"],"summary":"Upgrade external service to new Docker image with data migration\nThis endpoint uses service-specific upgrade procedures (e.g., pg_upgrade for PostgreSQL)","operationId":"upgrade_service","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpgradeExternalServiceRequest"}}},"required":true},"responses":{"200":{"description":"Service upgraded successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}},"400":{"description":"Invalid request or upgrade not supported"},"404":{"description":"Service not found"},"409":{"description":"A major upgrade is already in progress for this service"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/wal-health":{"get":{"tags":["External Services"],"summary":"Postgres WAL & archive health snapshot","description":"Returns the latest WAL/archive health snapshot recorded by the background\nhealth monitor for a Postgres external service. Powers the warning banner\non the service detail page when the disk is filling up due to stale\nreplication slots, archive backlog, or misconfigured `archive_command`.\n\nReturns 404 when no snapshot exists yet (probe hasn't run, or the service\nisn't Postgres).","operationId":"getPostgresWalHealth","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Latest WAL health snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PostgresWalHealth"}}}},"404":{"description":"Service not found, or no WAL snapshot available"},"500":{"description":"Internal server error"}}}},"/external-services/{service_id}/pg-stat-statements/enable":{"post":{"tags":["External Services"],"summary":"Enable `pg_stat_statements` on a standalone Postgres service.","description":"Stops the container and restarts it so that the\n`shared_preload_libraries=pg_stat_statements` CMD flag (baked into every\nnew standalone Postgres container) takes effect. The named data volume is\nreused unchanged — no data is lost.\n\n**Clustered (HA) services are rejected** with 422 — a blind single-container\nrestart bypasses controlled failover. For clustered services the response\nbody describes the manual rolling-restart steps.\n\nConfirmation is the caller's responsibility (UI dialog / CLI `--yes` flag)\nbefore invoking this endpoint.","operationId":"ExternalServiceEnablePgStatStatements","parameters":[{"name":"service_id","in":"path","description":"ID of the provisioned standalone Postgres service","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Container restarted; pg_stat_statements now active","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnablePgStatStatementsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions (requires external_services:write)"},"404":{"description":"Service not found"},"422":{"description":"Service is not standalone Postgres (cluster or wrong type)"},"500":{"description":"Restart failed"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/pg-stat-statements/reset":{"post":{"tags":["External Services"],"summary":"Reset all statistics accumulated by `pg_stat_statements` for a Postgres\nservice. This affects every user, database, and normalized query tracked by\nthe target Postgres instance and cannot be undone.","operationId":"ExternalServiceResetPgStatStatements","parameters":[{"name":"service_id","in":"path","description":"ID of the provisioned Postgres service","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"Explicit confirmation of the global, irreversible reset","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResetPgStatStatementsRequest"}}},"required":true},"responses":{"200":{"description":"All accumulated pg_stat_statements statistics cleared","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResetPgStatStatementsResponse"}}}},"400":{"description":"Missing or invalid reset confirmation"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions (requires external_services:write)"},"404":{"description":"Service not found"},"422":{"description":"Service is not Postgres"},"502":{"description":"Target Postgres rejected or failed the reset operation"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/pg-stat-statements/slow-queries":{"get":{"tags":["External Services"],"operationId":"get_slow_queries","parameters":[{"name":"service_id","in":"path","description":"ID of the provisioned Postgres service","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-based). Defaults to 1.","required":false,"schema":{"type":["integer","null"],"format":"int32","minimum":0}},{"name":"page_size","in":"query","description":"Number of rows per page (1–100). Defaults to 20.","required":false,"schema":{"type":["integer","null"],"format":"int32","minimum":0}},{"name":"sort_by","in":"query","description":"Column to sort by: one of `calls`, `total_exec_time_ms`,\n`mean_exec_time_ms`, `rows`, `cache_hit_ratio`. Defaults to\n`mean_exec_time_ms`. Applied server-side so ordering stays\nconsistent across pages.","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","description":"Sort direction: `asc` or `desc`. Defaults to `desc`.","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"Paginated slow queries from pg_stat_statements","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SlowQueriesResponse"}}}},"400":{"description":"Invalid pagination or sort parameters"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions (requires external_services:read)"},"404":{"description":"Service not found"},"422":{"description":"Service is not a Postgres service"},"503":{"description":"pg_stat_statements extension not available (container restart required)"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/containers":{"get":{"tags":["External Services - Query"],"summary":"List containers at the root level (databases, keyspaces, etc.)","operationId":"list_root_containers","parameters":[{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of root containers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ContainerResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/containers/{path}":{"get":{"tags":["External Services - Query"],"summary":"List containers at a specific path\nPath segments are separated by forward slashes\nExample: /external-services/1/query/containers/mydb lists schemas in database \"mydb\"","operationId":"list_containers_at_path","parameters":[{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of containers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ContainerResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service or container not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/containers/{path}/entities":{"get":{"tags":["External Services - Query"],"summary":"List entities (tables, collections, etc.) in a container\nExample: /external-services/1/query/containers/mydb/public/entities lists tables in the public schema","operationId":"list_entities","parameters":[{"name":"limit","in":"query","description":"Maximum number of entities to return (default: 100, max: 1000)","required":false,"schema":{"type":"integer","minimum":0}},{"name":"token","in":"query","description":"Continuation token for pagination","required":false,"schema":{"type":"string"}},{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Paginated list of entities","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedEntitiesResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service or container not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/containers/{path}/entities/{entity}":{"get":{"tags":["External Services - Query"],"summary":"Get detailed information about an entity (table schema)","operationId":"get_entity_info","parameters":[{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","required":true,"schema":{"type":"string"}},{"name":"entity","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Entity details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EntityInfoResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service, container, or entity not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/containers/{path}/entities/{entity}/data":{"post":{"tags":["External Services - Query"],"summary":"Query data from an entity with optional filters, pagination, and sorting","operationId":"query_data","parameters":[{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","required":true,"schema":{"type":"string"}},{"name":"entity","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QueryDataRequest"}}},"required":true},"responses":{"200":{"description":"Query results","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QueryDataResponse"}}}},"400":{"description":"Invalid query"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service, container, or entity not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/containers/{path}/entities/{entity}/download":{"get":{"tags":["External Services - Query"],"summary":"Download an object (S3 only) as a streaming response","operationId":"download_object","parameters":[{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","required":true,"schema":{"type":"string"}},{"name":"entity","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Object data stream","content":{"application/octet-stream":{}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Object not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/containers/{path}/info":{"get":{"tags":["External Services - Query"],"summary":"Get information about a specific container","operationId":"get_container_info","parameters":[{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Container information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service or container not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/explorer-support":{"get":{"tags":["External Services - Query"],"summary":"Check if a service supports query explorer functionality","operationId":"check_explorer_support","parameters":[{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Explorer support information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExplorerSupportResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/upgrades":{"get":{"tags":["Postgres Upgrades"],"summary":"List recent upgrades for a single service (newest first, page size 50).","operationId":"list_pg_upgrades","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Recent upgrades","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PgUpgradeResponse"}}}}},"500":{"description":"Internal error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Postgres Upgrades"],"summary":"Start a new PostgreSQL major-version upgrade for a service.","operationId":"start_pg_upgrade","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartPgUpgradeRequest"}}},"required":true},"responses":{"201":{"description":"Upgrade started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PgUpgradeResponse"}}}},"400":{"description":"Invalid request"},"409":{"description":"An upgrade is already running for this service"},"412":{"description":"No default S3 source configured"},"500":{"description":"Internal error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/upgrades/{id}":{"get":{"tags":["Postgres Upgrades"],"summary":"Get a single upgrade by id, scoped to a service.","operationId":"get_pg_upgrade","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"id","in":"path","description":"Upgrade id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Upgrade","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PgUpgradeResponse"}}}},"404":{"description":"Not found"},"500":{"description":"Internal error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/upgrades/{id}/cancel":{"post":{"tags":["Postgres Upgrades"],"summary":"Cancel an in-flight upgrade. The orchestrator stops at its next phase\nboundary; already-terminal upgrades return 409.","operationId":"cancel_pg_upgrade","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"id","in":"path","description":"Upgrade id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Cancellation requested","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PgUpgradeResponse"}}}},"404":{"description":"Not found"},"409":{"description":"Upgrade already terminal"},"500":{"description":"Internal error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/upgrades/{id}/logs":{"get":{"tags":["Postgres Upgrades"],"summary":"Get the accumulated JSONL log content for an upgrade (for dashboard display).","operationId":"get_pg_upgrade_logs","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"id","in":"path","description":"Upgrade id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Log content","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PgUpgradeLogResponse"}}}},"404":{"description":"Not found"},"500":{"description":"Internal error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/upgrades/{id}/retry":{"post":{"tags":["Postgres Upgrades"],"summary":"Retry a failed upgrade. The phase is preserved, so the state machine\nresumes from where it failed.","operationId":"retry_pg_upgrade","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"id","in":"path","description":"Upgrade id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Retry scheduled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PgUpgradeResponse"}}}},"400":{"description":"Upgrade is not in a retriable state"},"404":{"description":"Not found"},"500":{"description":"Internal error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/upgrades/{id}/rollback":{"post":{"tags":["Postgres Upgrades"],"summary":"Roll a completed upgrade back to its pre-upgrade PGDATA volume and old image.\nOnly valid while the rollback retention window is still open (see\n`ROLLBACK_RETENTION_DAYS`) and the rollback volume has not been swept.","operationId":"rollback_pg_upgrade","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"id","in":"path","description":"Upgrade id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Rollback complete","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PgUpgradeResponse"}}}},"404":{"description":"Not found"},"409":{"description":"Upgrade is not in a rollbackable state (not completed, volume swept, or retention expired)"},"500":{"description":"Internal error"}},"security":[{"bearer_auth":[]}]}},"/files/{file_path}":{"get":{"tags":["Files"],"operationId":"get_file","parameters":[{"name":"file_path","in":"path","description":"Relative path to the file from static directory","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"File content retrieved successfully","content":{"application/octet-stream":{}}},"401":{"description":"Authentication required"},"403":{"description":"Access denied - path outside static directory or insufficient permissions"},"404":{"description":"File not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/flags/exposure":{"post":{"tags":["Feature Flags"],"summary":"Record which flags a running app actually evaluated.","description":"This is what makes `last_evaluated_at` mean something. The snapshot\nendpoint hands the SDK every flag in the environment and evaluation then\nhappens locally, so the control plane cannot otherwise tell a flag that is\nreferenced by live code from one nothing has called in a year. Stamping on\nsnapshot fetch would mark every flag as freshly used and defeat the point.\n\nScope comes from the deployment token, never the body. The endpoint writes\nonly `last_evaluated_at` — never a flag's value — so \"a deployment token\ncannot change what a flag serves\" still holds despite this being a write.","operationId":"record_flag_exposure","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecordExposureRequest"}}},"required":true},"responses":{"200":{"description":"Exposure recorded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecordExposureResponse"}}}},"400":{"description":"Deployment token required"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/flags/snapshot":{"get":{"tags":["Feature Flags"],"summary":"Every flag for the caller's environment, collapsed to what the evaluator\nneeds.","description":"Scope comes from the deployment token, never from the URL: a container's\nbaked-in `TEMPS_API_TOKEN` identifies exactly one project (and usually one\nenvironment), so a compromised app cannot read another tenant's flags by\nchanging a path parameter.\n\nSupports `If-None-Match`, so the SDK's background poll is a 304 in the\ncommon case.","operationId":"get_flag_snapshot","parameters":[{"name":"environment_id","in":"query","description":"Required only when the calling token is project-wide rather than scoped\nto a single environment.","required":false,"schema":{"type":["integer","null"],"format":"int32"}}],"responses":{"200":{"description":"Snapshot for the environment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagSnapshotResponse"}}}},"304":{"description":"Snapshot unchanged"},"400":{"description":"Environment could not be determined"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/geo/{ip}":{"get":{"tags":["geo"],"summary":"Get geolocation information for an IP address","operationId":"get_ip_geolocation","parameters":[{"name":"ip","in":"path","description":"IP address to geolocate (IPv4 or IPv6)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Geolocation information retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GeoLocationResponse"}}}},"400":{"description":"Invalid IP address","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"IP address not found in database","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/git-connections":{"get":{"tags":["Git Providers"],"summary":"List user's git provider connections","operationId":"list_connections","parameters":[{"name":"page","in":"query","description":"Page number for pagination (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Number of items per page (default: 30, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"sort","in":"query","description":"Sort field (created_at, updated_at, account_name)","required":false,"schema":{"type":"string"}},{"name":"direction","in":"query","description":"Sort direction (asc, desc), default: desc","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of connections","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectionListResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}":{"delete":{"tags":["Git Providers"],"summary":"Permanently delete a git provider connection","operationId":"delete_connection","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Connection deleted successfully"},"400":{"description":"Connection is in use by projects and cannot be deleted"},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}/activate":{"post":{"tags":["Git Providers"],"summary":"Activate a git provider connection","operationId":"activate_connection","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Connection activated successfully"},"400":{"description":"Provider is deactivated and connection cannot be activated"},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}/deactivate":{"post":{"tags":["Git Providers"],"summary":"Deactivate a git provider connection","operationId":"deactivate_connection","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Connection deactivated successfully"},"400":{"description":"Connection is in use by projects and cannot be deactivated"},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}/health-check":{"post":{"tags":["Git Provider Connections"],"summary":"Run an on-demand health check for a git connection.","description":"Probes the upstream (GitHub App, PAT, or OAuth token), persists the result,\nand fires admin notifications on status transitions. Returns the updated\nconnection.","operationId":"run_connection_health_check","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Health check completed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}/repositories":{"get":{"tags":["Git Providers"],"summary":"List repositories for a specific connection","description":"Fetches repositories from the connected git provider with support for pagination, search, and filtering.\nThis endpoint calls the provider's API directly to get the most up-to-date repository list.","operationId":"list_repositories_by_connection","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"sort","in":"query","description":"Sort field (name, created_at, updated_at, stars, etc.)","required":false,"schema":{"type":"string"}},{"name":"direction","in":"query","description":"Sort direction (asc, desc)","required":false,"schema":{"type":"string"}},{"name":"search","in":"query","description":"Search term to filter repositories","required":false,"schema":{"type":"string"}},{"name":"owner","in":"query","description":"Filter by repository owner","required":false,"schema":{"type":"string"}},{"name":"language","in":"query","description":"Filter by programming language","required":false,"schema":{"type":"string"}},{"name":"private","in":"query","description":"Filter by private status (true/false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of repositories","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositoryListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}/sync":{"post":{"tags":["Git Providers"],"summary":"Start a repository sync for a connection","description":"Kicks off a background sync of the connection's repositories from the\nprovider. Returns `202 Accepted` immediately — the caller should poll\nthe connection endpoint for `syncing` / `synced_repository_count`\nupdates rather than waiting on this response. The sync is guarded by\na hard deadline and always releases the `syncing` flag on exit, so a\nclient that disconnects mid-sync will not leave the connection stuck.","operationId":"sync_repositories","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"202":{"description":"Repository sync started in background","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositorySyncStartedResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"409":{"description":"Sync already in progress"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}/update-token":{"post":{"tags":["Git Provider Connections"],"summary":"Update access token for a connection (when tokens expire or are rotated)","operationId":"update_connection_token","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTokenRequest"}}},"required":true},"responses":{"200":{"description":"Token updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTokenResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}/validate":{"get":{"tags":["Git Provider Connections"],"summary":"Validate a connection by testing the access token","operationId":"validate_connection","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Connection validation result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers":{"get":{"tags":["Git Providers"],"summary":"List all git providers","operationId":"list_git_providers","responses":{"200":{"description":"List of providers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProviderResponse"}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Git Providers"],"summary":"Create a new git provider configuration","operationId":"create_git_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProviderRequest"}}},"required":true},"responses":{"201":{"description":"Provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/bitbucket":{"post":{"tags":["Git Providers"],"summary":"Create a Bitbucket Cloud provider with access token or app password authentication","operationId":"create_bitbucket_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateBitbucketRequest"}}},"required":true},"responses":{"201":{"description":"Bitbucket provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request — missing or invalid auth fields"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/generic":{"post":{"tags":["Git Providers"],"summary":"Create a Generic git provider for self-hosted or arbitrary HTTPS git hosts.\nSupports public repositories (no token) and private repositories (token-based).","operationId":"create_generic_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGenericRequest"}}},"required":true},"responses":{"201":{"description":"Generic git provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request — invalid clone URL or missing fields"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/gitea/pat":{"post":{"tags":["Git Providers"],"summary":"Create a Gitea Personal Access Token provider","operationId":"create_gitea_pat_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGiteaPATRequest"}}},"required":true},"responses":{"201":{"description":"Gitea PAT provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request — invalid URL or missing fields"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/github/pat":{"post":{"tags":["Git Providers"],"summary":"Create a GitHub Personal Access Token provider","operationId":"create_github_pat_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGitHubPATRequest"}}},"required":true},"responses":{"201":{"description":"GitHub PAT provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/gitlab/oauth":{"post":{"tags":["Git Providers"],"summary":"Create a GitLab OAuth provider","operationId":"create_gitlab_oauth_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGitLabOAuthRequest"}}},"required":true},"responses":{"201":{"description":"GitLab OAuth provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/gitlab/pat":{"post":{"tags":["Git Providers"],"summary":"Create a GitLab PAT provider","operationId":"create_gitlab_pat_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGitLabPATRequest"}}},"required":true},"responses":{"201":{"description":"GitLab PAT provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}":{"get":{"tags":["Git Providers"],"summary":"Get a specific git provider","operationId":"get_git_provider","parameters":[{"name":"provider_id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Provider details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Git Providers"],"summary":"Permanently delete a git provider","operationId":"delete_git_provider","parameters":[{"name":"provider_id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Provider deleted successfully"},"400":{"description":"Provider has connections and cannot be deleted"},"401":{"description":"Unauthorized"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/activate":{"post":{"tags":["Git Providers"],"summary":"Activate a git provider","operationId":"activate_provider","parameters":[{"name":"provider_id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Provider activated successfully"},"401":{"description":"Unauthorized"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/callback":{"get":{"tags":["Git Providers"],"summary":"Handle OAuth callback for a git provider","operationId":"handle_git_provider_oauth_callback","parameters":[{"name":"provider_id","in":"path","description":"Git provider ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"code","in":"query","description":"OAuth authorization code","required":true,"schema":{"type":"string"}},{"name":"state","in":"query","description":"CSRF state token","required":true,"schema":{"type":"string"}}],"responses":{"302":{"description":"Redirect to success page"},"400":{"description":"Bad request"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}}}},"/git-providers/{provider_id}/connections":{"get":{"tags":["Git Providers"],"summary":"Get connections for a specific git provider","operationId":"get_provider_connections","parameters":[{"name":"provider_id","in":"path","description":"Provider ID to get connections for","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of connections for the provider","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ConnectionResponse"}}}}},"401":{"description":"Unauthorized"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/credentials":{"patch":{"tags":["Git Providers"],"summary":"Partially update credentials for an existing git provider. Only the fields\nyou send are replaced; omitted fields keep their stored values. Fields that\ndon't apply to the provider's auth method are ignored on the service side.","operationId":"update_git_provider_credentials","parameters":[{"name":"provider_id","in":"path","description":"Git provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProviderCredentialsRequest"}}},"required":true},"responses":{"200":{"description":"Credentials updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/deactivate":{"post":{"tags":["Git Providers"],"summary":"Deactivate a git provider","operationId":"deactivate_provider","parameters":[{"name":"provider_id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Provider deactivated successfully"},"401":{"description":"Unauthorized"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/deletion-check":{"get":{"tags":["Git Providers"],"summary":"Check if a git provider can be safely deleted","operationId":"check_provider_deletion_safety","parameters":[{"name":"provider_id","in":"path","description":"Git provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deletion check result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderDeletionCheckResponse"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/oauth/authorize":{"get":{"tags":["Git Providers"],"summary":"Start OAuth flow for a git provider","operationId":"start_git_provider_oauth","parameters":[{"name":"provider_id","in":"path","description":"Git provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"302":{"description":"Redirect to OAuth provider"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/repositories":{"get":{"tags":["Git Providers"],"summary":"List all repositories for a specific provider","description":"Lists repositories synced to the database across every connection under\nthis provider, with the same pagination/filtering as `/repositories`.","operationId":"list_repositories_by_provider","parameters":[{"name":"provider_id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"sort","in":"query","description":"Sort field (name, created_at, updated_at, stars, watchers, size, issues)","required":false,"schema":{"type":"string"}},{"name":"direction","in":"query","description":"Sort direction (asc, desc)","required":false,"schema":{"type":"string"}},{"name":"search","in":"query","description":"Search term to filter repositories","required":false,"schema":{"type":"string"}},{"name":"owner","in":"query","description":"Filter by repository owner","required":false,"schema":{"type":"string"}},{"name":"language","in":"query","description":"Filter by programming language","required":false,"schema":{"type":"string"}},{"name":"private","in":"query","description":"Filter by private status (true/false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of repositories","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositoryListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/safe-delete":{"delete":{"tags":["Git Providers"],"summary":"Safely delete a git provider (only if no projects are using it)","operationId":"delete_provider_safely","parameters":[{"name":"provider_id","in":"path","description":"Git provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Provider successfully deleted"},"400":{"description":"Cannot delete provider because it's in use"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git/public/{provider}/{owner}/{repo}":{"get":{"tags":["Public Repositories"],"summary":"Get information about a public repository (supports GitHub and GitLab)","operationId":"get_public_repository","parameters":[{"name":"provider","in":"path","description":"Git provider (github or gitlab)","required":true,"schema":{"type":"string"}},{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"repo","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Repository information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicRepositoryInfo"}}}},"400":{"description":"Provider not supported"},"404":{"description":"Repository not found"},"429":{"description":"API rate limit exceeded"},"500":{"description":"Internal server error"}}}},"/git/public/{provider}/{owner}/{repo}/branches":{"get":{"tags":["Public Repositories"],"summary":"Get branches for a public repository (supports GitHub and GitLab)","operationId":"get_public_branches","parameters":[{"name":"provider","in":"path","description":"Git provider (github or gitlab)","required":true,"schema":{"type":"string"}},{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"repo","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}},{"name":"fresh","in":"query","description":"Force fetch fresh data, bypassing cache (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of branches","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BranchListResponse"}}}},"400":{"description":"Provider not supported"},"404":{"description":"Repository not found"},"429":{"description":"API rate limit exceeded"},"500":{"description":"Internal server error"}}}},"/git/public/{provider}/{owner}/{repo}/presets":{"get":{"tags":["Public Repositories"],"summary":"Detect presets for a public repository (supports GitHub and GitLab)","operationId":"detect_public_presets","parameters":[{"name":"provider","in":"path","description":"Git provider (github or gitlab)","required":true,"schema":{"type":"string"}},{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"repo","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}},{"name":"branch","in":"query","description":"Branch name to detect presets for (default: repository's default branch)","required":false,"schema":{"type":["string","null"]}},{"name":"fresh","in":"query","description":"Force fetch fresh data, bypassing cache (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Detected presets","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicPresetResponse"}}}},"400":{"description":"Provider not supported"},"404":{"description":"Repository or branch not found"},"429":{"description":"API rate limit exceeded"},"500":{"description":"Internal server error"}}}},"/imports/discover":{"post":{"tags":["Imports"],"summary":"Discover workloads from a source","operationId":"discover_workloads","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiscoverRequest"}}},"required":true},"responses":{"200":{"description":"List of discovered workloads","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiscoverResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/imports/execute":{"post":{"tags":["Imports"],"summary":"Execute an import","operationId":"execute_import","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecuteImportRequest"}}},"required":true},"responses":{"202":{"description":"Import execution started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecuteImportResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/imports/plan":{"post":{"tags":["Imports"],"summary":"Create an import plan","operationId":"create_plan","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePlanRequest"}}},"required":true},"responses":{"200":{"description":"Import plan created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePlanResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/imports/sources":{"get":{"tags":["Imports"],"summary":"List available import sources","operationId":"list_sources","responses":{"200":{"description":"List of available import sources","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ImportSourceInfo"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/imports/{session_id}":{"get":{"tags":["Imports"],"summary":"Get import status","operationId":"get_import_status","parameters":[{"name":"session_id","in":"path","description":"Import session ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Import status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportStatusResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Import session not found"}},"security":[{"bearer_auth":[]}]}},"/incidents/{incident_id}":{"get":{"tags":["Status Page"],"summary":"Get an incident by ID","operationId":"get_incident","parameters":[{"name":"incident_id","in":"path","description":"Incident ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved incident","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncidentResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Incident not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/incidents/{incident_id}/status":{"patch":{"tags":["Status Page"],"summary":"Update incident status","operationId":"update_incident_status","parameters":[{"name":"incident_id","in":"path","description":"Incident ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateIncidentStatusRequest"}}},"required":true},"responses":{"200":{"description":"Incident status updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncidentResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Incident not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/incidents/{incident_id}/updates":{"get":{"tags":["Status Page"],"summary":"Get incident updates","operationId":"get_incident_updates","parameters":[{"name":"incident_id","in":"path","description":"Incident ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved incident updates","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/IncidentUpdateResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Incident not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/internal/nodes":{"get":{"tags":["Nodes"],"summary":"List all registered nodes (admin — session auth via RequireAuth)","operationId":"admin_list_nodes","responses":{"200":{"description":"List of nodes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NodeListResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/internal/nodes/register":{"post":{"tags":["Nodes"],"summary":"Register a new worker node or reconnect an existing one","operationId":"register_node","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterNodeApiRequest"}}},"required":true},"responses":{"200":{"description":"Node reconnected successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterNodeResponse"}}}},"201":{"description":"Node registered successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterNodeResponse"}}}},"400":{"description":"Validation error"},"500":{"description":"Internal server error"}}}},"/internal/nodes/{node_id}":{"get":{"tags":["Nodes"],"summary":"Get a specific node by ID (admin — session auth via RequireAuth)","operationId":"admin_get_node","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Node details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NodeInfoResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Nodes"],"summary":"Remove a node from the cluster entirely. The node should be drained first\nto ensure containers have been rescheduled. If the node still has active\ncontainers, it will be drained automatically before removal.","operationId":"admin_remove_node","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Node removed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RemoveNodeResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Node not found"},"409":{"description":"Node still has active containers"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/internal/nodes/{node_id}/containers":{"get":{"tags":["Nodes"],"summary":"List all containers running on a specific node","operationId":"admin_list_node_containers","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Containers on this node","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NodeContainerListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/internal/nodes/{node_id}/dns/ack":{"post":{"tags":["Internal DNS"],"summary":"`POST /internal/nodes/{node_id}/dns/ack`","operationId":"post_dns_ack","parameters":[{"name":"node_id","in":"path","description":"Node id, must match the bearer token's node","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsAckRequest"}}},"required":true},"responses":{"200":{"description":"ACK accepted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsAckResponse"}}}},"400":{"description":"ACK higher than server generation"},"401":{"description":"Missing or invalid bearer token"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}}}},"/internal/nodes/{node_id}/dns/changes":{"get":{"tags":["Internal DNS"],"summary":"`GET /internal/nodes/{node_id}/dns/changes?since=N`","operationId":"get_dns_changes","parameters":[{"name":"node_id","in":"path","description":"Node id, must match the bearer token's node","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"since","in":"query","description":"Highest generation the agent has already applied. Pass `0` to\nrequest a full zone snapshot. Defaults to `0` if omitted.","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Diff or full snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsChangesResponse"}}}},"401":{"description":"Missing or invalid bearer token"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}}}},"/internal/nodes/{node_id}/drain":{"get":{"tags":["Nodes"],"summary":"Get the drain status for a node, including migration progress.","description":"Returns container counts and whether the drain is complete.\nCan be polled to track drain progress.","operationId":"admin_drain_status","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Drain status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DrainStatusResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Nodes"],"summary":"Drain a node: mark it as \"draining\" so no new replicas are scheduled on it,\nand trigger redeployment of all affected environments so their containers\nare rescheduled to healthy nodes.","operationId":"admin_drain_node","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Node drain initiated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DrainNodeResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Nodes"],"summary":"Undrain (reactivate) a node so it can accept new deployments again.\nOnly works for nodes in \"draining\" or \"drained\" status.","operationId":"admin_undrain_node","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Node reactivated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UndrainNodeResponse"}}}},"400":{"description":"Node not in drainable state"},"401":{"description":"Unauthorized"},"404":{"description":"Node not found"}},"security":[{"bearer_auth":[]}]}},"/internal/nodes/{node_id}/heartbeat":{"post":{"tags":["Nodes"],"summary":"Receive a heartbeat from a worker node","operationId":"node_heartbeat","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HeartbeatApiRequest"}}},"required":true},"responses":{"200":{"description":"Heartbeat received","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HeartbeatResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}}}},"/internal/nodes/{node_id}/network/peers":{"get":{"tags":["Nodes"],"summary":"`GET /internal/nodes/{node_id}/network/peers`","operationId":"list_peers","parameters":[{"name":"node_id","in":"path","description":"Node id, must match the bearer token's node","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Peer list and self-allocation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PeerListResponse"}}}},"401":{"description":"Missing or invalid bearer token"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}}}},"/internal/nodes/{node_id}/s3-credentials/{s3_source_id}":{"get":{"tags":["Nodes"],"summary":"Get decrypted S3 credentials for a backup/restore operation.","description":"Agents call this endpoint to receive the S3 credentials they need to upload\nor download backups. The credentials are decrypted from the stored S3 source\nand returned over the authenticated TLS/WireGuard channel.","operationId":"get_s3_credentials","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"s3_source_id","in":"path","description":"S3 source ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"S3 credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/S3CredentialsResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"S3 source not found"},"500":{"description":"Internal server error"}}}},"/ip-access-control":{"get":{"tags":["IP Access Control"],"summary":"List all IP access control rules","operationId":"list_ip_access_control","parameters":[{"name":"action","in":"query","description":"Filter by action (\"block\" or \"allow\")","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"List of IP access control rules","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/IpAccessControlResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["IP Access Control"],"summary":"Create a new IP access control rule","operationId":"create_ip_access_control","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateIpAccessControlRequest"}}},"required":true},"responses":{"201":{"description":"IP access control rule created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IpAccessControlResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"409":{"description":"Duplicate IP address","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ip-access-control/check/{ip}":{"get":{"tags":["IP Access Control"],"summary":"Check if an IP address is blocked","operationId":"check_ip_blocked","parameters":[{"name":"ip","in":"path","description":"IP address to check","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"IP block status"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ip-access-control/{id}":{"get":{"tags":["IP Access Control"],"summary":"Get a single IP access control rule by ID","operationId":"get_ip_access_control","parameters":[{"name":"id","in":"path","description":"IP access control rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"IP access control rule details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IpAccessControlResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"IP access control rule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["IP Access Control"],"summary":"Delete an IP access control rule","operationId":"delete_ip_access_control","parameters":[{"name":"id","in":"path","description":"IP access control rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"IP access control rule deleted"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"IP access control rule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["IP Access Control"],"summary":"Update an IP access control rule","operationId":"update_ip_access_control","parameters":[{"name":"id","in":"path","description":"IP access control rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateIpAccessControlRequest"}}},"required":true},"responses":{"200":{"description":"IP access control rule updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IpAccessControlResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"IP access control rule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/kv/del":{"post":{"tags":["KV Store"],"summary":"Delete one or more keys","operationId":"kv_del","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DelRequest"}}},"required":true},"responses":{"200":{"description":"Keys deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DelResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/disable":{"delete":{"tags":["KV Management"],"summary":"Disable KV service","operationId":"kv_disable","responses":{"200":{"description":"KV service disabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DisableKvResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"KV service not enabled"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/enable":{"post":{"tags":["KV Management"],"summary":"Enable KV service","operationId":"kv_enable","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnableKvRequest"}}},"required":true},"responses":{"200":{"description":"KV service enabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnableKvResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/expire":{"post":{"tags":["KV Store"],"summary":"Set expiration on a key","operationId":"kv_expire","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExpireRequest"}}},"required":true},"responses":{"200":{"description":"Expiration set","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExpireResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/get":{"post":{"tags":["KV Store"],"summary":"Get a value by key","operationId":"kv_get","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetRequest"}}},"required":true},"responses":{"200":{"description":"Value retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/incr":{"post":{"tags":["KV Store"],"summary":"Increment a numeric value","operationId":"kv_incr","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncrRequest"}}},"required":true},"responses":{"200":{"description":"Value incremented","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncrResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/keys":{"post":{"tags":["KV Store"],"summary":"Get keys matching a pattern","operationId":"kv_keys","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KeysRequest"}}},"required":true},"responses":{"200":{"description":"Keys retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KeysResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/set":{"post":{"tags":["KV Store"],"summary":"Set a value with optional expiration","operationId":"kv_set","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetRequest"}}},"required":true},"responses":{"200":{"description":"Value set","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/status":{"get":{"tags":["KV Management"],"summary":"Get KV service status","operationId":"kv_status","responses":{"200":{"description":"KV service status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KvStatusResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/ttl":{"post":{"tags":["KV Store"],"summary":"Get time-to-live for a key","operationId":"kv_ttl","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TtlRequest"}}},"required":true},"responses":{"200":{"description":"TTL retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TtlResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/update":{"patch":{"tags":["KV Management"],"summary":"Update KV service configuration","operationId":"kv_update","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateKvRequest"}}},"required":true},"responses":{"200":{"description":"KV service updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateKvResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"KV service not enabled"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/lb/routes":{"get":{"tags":["Load Balancer"],"operationId":"list_routes","responses":{"200":{"description":"List of routes","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RouteResponse"}}}}},"500":{"description":"Internal server error"}}},"post":{"tags":["Load Balancer"],"operationId":"create_route","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRouteRequest"}}},"required":true},"responses":{"201":{"description":"Route created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteResponse"}}}},"400":{"description":"Invalid request"}}}},"/lb/routes/{domain}":{"get":{"tags":["Load Balancer"],"operationId":"get_route","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Route found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteResponse"}}}},"404":{"description":"Route not found"}}},"put":{"tags":["Load Balancer"],"operationId":"update_route","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateRouteRequest"}}},"required":true},"responses":{"200":{"description":"Route updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteResponse"}}}},"404":{"description":"Route not found"}}},"delete":{"tags":["Load Balancer"],"operationId":"delete_route","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Route deleted successfully"},"404":{"description":"Route not found"}}}},"/logout":{"post":{"tags":["Authentication"],"operationId":"logout","responses":{"200":{"description":"Successfully logged out"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"session_token":[]}]}},"/logs/context":{"get":{"tags":["Logs"],"summary":"Get context lines surrounding a specific log line","operationId":"get_log_context","parameters":[{"name":"chunk_id","in":"query","description":"Chunk ID","required":true,"schema":{"type":"string"}},{"name":"line_offset","in":"query","description":"Line offset within the chunk","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"lines","in":"query","description":"Context lines before and after (default: 25)","required":false,"schema":{"type":"integer","format":"int32","minimum":0}}],"responses":{"200":{"description":"Context lines","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContextLogsResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Chunk not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/logs/search":{"post":{"tags":["Logs"],"summary":"Search logs with structured filters and full text search","operationId":"search_logs","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchLogsRequest"}}},"required":true},"responses":{"200":{"description":"Search results","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchLogsResponse"}}}},"400":{"description":"Invalid search parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/logs/tail":{"get":{"tags":["Logs"],"summary":"Live tail logs via Server-Sent Events","operationId":"tail_logs","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"string"}},{"name":"service","in":"query","description":"Service name","required":true,"schema":{"type":"string"}},{"name":"env","in":"query","description":"Environment","required":true,"schema":{"type":"string"}},{"name":"levels","in":"query","description":"Optional level filters","required":true,"schema":{"type":"array","items":{"type":"string"}}},{"name":"text","in":"query","description":"Optional text filter","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"SSE stream of log lines"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/monitors-health/projects":{"get":{"tags":["Status Page"],"summary":"Get monitor-based health summaries for multiple projects in a single query","operationId":"get_projects_monitor_health","parameters":[{"name":"project_ids","in":"query","description":"Comma-separated list of project IDs","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Health summaries per project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectsMonitorHealthResponse"}}}},"400":{"description":"Invalid parameters"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/monitors/{monitor_id}":{"get":{"tags":["Status Page"],"summary":"Get a monitor by ID","operationId":"get_monitor","parameters":[{"name":"monitor_id","in":"path","description":"Monitor ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved monitor","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MonitorResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Monitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Status Page"],"summary":"Delete a monitor","operationId":"delete_monitor","parameters":[{"name":"monitor_id","in":"path","description":"Monitor ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Monitor deleted successfully"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Monitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/monitors/{monitor_id}/bucketed":{"get":{"tags":["Status Page"],"summary":"Get bucketed status data for a monitor using TimescaleDB","operationId":"get_bucketed_status","parameters":[{"name":"monitor_id","in":"path","description":"Monitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"interval","in":"query","description":"Bucket interval: '5min', 'hourly', or 'daily' (default: hourly)","required":false,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601) (default: 24 hours ago)","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (ISO 8601) (default: now)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved bucketed status data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatusBucketedResponse"}}}},"400":{"description":"Invalid parameters"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Monitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/monitors/{monitor_id}/current-status":{"get":{"tags":["Status Page"],"summary":"Get current status and uptime metrics for a monitor","operationId":"get_current_monitor_status","parameters":[{"name":"monitor_id","in":"path","description":"Monitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_time","in":"query","description":"Custom start time (ISO 8601) - overrides timeframe","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"Custom end time (ISO 8601)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved current status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CurrentStatusResponse"}}}},"400":{"description":"Invalid time parameters"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Monitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/monitors/{monitor_id}/uptime":{"get":{"tags":["Status Page"],"summary":"Get uptime history for a monitor","operationId":"get_uptime_history","parameters":[{"name":"monitor_id","in":"path","description":"Monitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"days","in":"query","description":"Number of days of history (default: 60) - ignored if start_time/end_time provided","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601) - overrides days parameter","required":true,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (ISO 8601) - defaults to now","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved uptime history","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UptimeHistoryResponse"}}}},"400":{"description":"Invalid time parameters"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Monitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/nodes/{id}/metrics":{"get":{"tags":["Metrics"],"summary":"Fetch a time-series range for a single metric on a node.","operationId":"NodeMetricsGetRange","parameters":[{"name":"id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"metric","in":"query","description":"Metric name, e.g. `\"pg.connections_active\"`.","required":true,"schema":{"type":"string"}},{"name":"range","in":"query","description":"Time window: `\"1h\"` | `\"6h\"` | `\"24h\"` | `\"7d\"`.","required":false,"schema":{"type":"string"}},{"name":"percentile","in":"query","description":"Optional histogram percentile (0–100). When provided, the endpoint\nfetches histogram buckets and computes the requested quantile.","required":false,"schema":{"type":["number","null"],"format":"double"}}],"responses":{"200":{"description":"Metric time series data points","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MetricDataPoint"}}}}},"400":{"description":"Invalid query parameters"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"},"503":{"description":"Metrics store not available"}},"security":[{"bearer_auth":[]}]}},"/notification-preferences":{"get":{"tags":["Notification Preferences"],"summary":"Get notification preferences","operationId":"get_preferences","responses":{"200":{"description":"Successfully retrieved preferences","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationPreferencesResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Notification Preferences"],"summary":"Update notification preferences","operationId":"update_preferences","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePreferencesRequest"}}},"required":true},"responses":{"200":{"description":"Successfully updated preferences","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationPreferencesResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Notification Preferences"],"summary":"Delete notification preferences","operationId":"delete_preferences","responses":{"204":{"description":"Successfully deleted preferences"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers":{"get":{"tags":["Notification Providers"],"summary":"List all notification providers","operationId":"list_notification_providers","parameters":[{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20},{"name":"sort_by","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"Successfully retrieved providers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}}},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Notification Providers"],"summary":"Create a new notification provider","operationId":"create_notification_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProviderRequest"}}},"required":true},"responses":{"201":{"description":"Successfully created provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"400":{"description":"Invalid request"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/cloudflare":{"post":{"tags":["Notification Providers"],"summary":"Create a new Cloudflare Email Sending notification provider","operationId":"create_cloudflare_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCloudflareProviderRequest"}}},"required":true},"responses":{"201":{"description":"Successfully created Cloudflare provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"400":{"description":"Invalid request"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/cloudflare/{id}":{"put":{"tags":["Notification Providers"],"summary":"Update a Cloudflare Email Sending notification provider","operationId":"update_cloudflare_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCloudflareProviderRequest"}}},"required":true},"responses":{"200":{"description":"Successfully updated Cloudflare provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/email":{"post":{"tags":["Notification Providers"],"summary":"Create a new Email notification provider","operationId":"create_notification_email_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateNotificationEmailProviderRequest"}}},"required":true},"responses":{"201":{"description":"Successfully created Email provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"400":{"description":"Invalid request"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/email/{id}":{"put":{"tags":["Notification Providers"],"summary":"Update an Email notification provider","operationId":"update_notification_email_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateNotificationEmailProviderRequest"}}},"required":true},"responses":{"200":{"description":"Successfully updated Email provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/slack":{"post":{"tags":["Notification Providers"],"summary":"Create a new Slack notification provider","operationId":"create_slack_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSlackProviderRequest"}}},"required":true},"responses":{"201":{"description":"Successfully created Slack provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"400":{"description":"Invalid request"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/slack/{id}":{"put":{"tags":["Notification Providers"],"summary":"Update a Slack notification provider","operationId":"update_slack_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSlackProviderRequest"}}},"required":true},"responses":{"200":{"description":"Successfully updated Slack provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/webhook":{"post":{"tags":["Notification Providers"],"summary":"Create a new Webhook notification provider","description":"Webhook providers send notifications as JSON payloads to any HTTP endpoint.\nYou can configure custom headers for authentication (Bearer tokens, API keys, etc.).\nThe webhook will receive a JSON payload with notification details including:\nid, title, message, type, priority, severity, timestamp, and metadata.","operationId":"create_webhook_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWebhookProviderRequest"}}},"required":true},"responses":{"201":{"description":"Successfully created Webhook provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"400":{"description":"Invalid request"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/webhook/{id}":{"put":{"tags":["Notification Providers"],"summary":"Update a Webhook notification provider","operationId":"update_webhook_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWebhookProviderRequest"}}},"required":true},"responses":{"200":{"description":"Successfully updated Webhook provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/{id}":{"get":{"tags":["Notification Providers"],"summary":"Get a single notification provider","operationId":"get_notification_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Notification Providers"],"summary":"Update a notification provider","operationId":"update_notification_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProviderRequest"}}},"required":true},"responses":{"200":{"description":"Successfully updated provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"400":{"description":"Invalid masked provider configuration"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Notification Providers"],"summary":"Delete a notification provider","operationId":"delete_notification_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Successfully deleted provider"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/{id}/config/{field}":{"get":{"tags":["Notification Providers"],"operationId":"reveal_notification_provider_config","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"field","in":"path","description":"Sensitive field, such as password or headers.Authorization","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sensitive provider configuration value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SensitiveConfigValueResponse"}}}},"400":{"description":"Field is not revealable"},"403":{"description":"Missing secrets:read permission"},"404":{"description":"Provider or field not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/{id}/test":{"post":{"tags":["Notification Providers"],"summary":"Test a notification provider","operationId":"test_notification_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Test result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestProviderResponse"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/orders":{"get":{"tags":["Domains"],"summary":"List all ACME orders","operationId":"list_orders","parameters":[{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20},{"name":"sort_by","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"Orders retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListOrdersResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/otel/alerts":{"get":{"tags":["Alerts"],"summary":"List alert rules for a project (newest first, paginated).","operationId":"list_alerts","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Alert rules for the project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricAlertsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Alerts"],"summary":"Create a new alert rule for a project.","operationId":"create_alert","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMetricAlertRequest"}}},"required":true},"responses":{"201":{"description":"Alert rule created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricAlertRuleResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/alerts/preview":{"post":{"tags":["Alerts"],"summary":"Backtest an anomaly detector over a time range without saving a rule.","description":"Replays the metric against the same band the evaluator would use, returning\nthe per-bucket band + which points would have fired. Powers the form's\n\"would this have fired?\" preview and the explorer band overlay. Read-only.","operationId":"preview_alert","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnomalyPreviewRequest"}}},"required":true},"responses":{"200":{"description":"Per-bucket band + breach points","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnomalyPreviewResponse"}}}},"400":{"description":"Not an anomaly detector / bad input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/alerts/{id}":{"get":{"tags":["Alerts"],"summary":"Fetch a single alert rule by id.","operationId":"get_alert","parameters":[{"name":"id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Owning project ID (scopes the lookup)","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Alert rule","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricAlertRuleResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Alert rule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Alerts"],"summary":"Delete an alert rule.","operationId":"delete_alert","parameters":[{"name":"id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Owning project ID (scopes the delete)","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Alert rule deleted"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Alert rule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Alerts"],"summary":"Update an alert rule's fields.","operationId":"update_alert","parameters":[{"name":"id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Owning project ID (scopes the update)","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMetricAlertRequest"}}},"required":true},"responses":{"200":{"description":"Alert rule updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricAlertRuleResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Alert rule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/dashboards":{"get":{"tags":["Dashboards"],"summary":"List dashboards for a project (newest first, paginated).","operationId":"list_dashboards","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Dashboards for the project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelDashboardsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Dashboards"],"summary":"Create a new dashboard for a project.","operationId":"create_dashboard","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDashboardRequest"}}},"required":true},"responses":{"201":{"description":"Dashboard created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelDashboardResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/dashboards/{id}":{"get":{"tags":["Dashboards"],"summary":"Fetch a single dashboard by id.","operationId":"get_dashboard","parameters":[{"name":"id","in":"path","description":"Dashboard ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Owning project ID (scopes the lookup)","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Dashboard","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelDashboardResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Dashboard not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Dashboards"],"summary":"Delete a dashboard.","operationId":"delete_dashboard","parameters":[{"name":"id","in":"path","description":"Dashboard ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Owning project ID (scopes the delete)","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Dashboard deleted"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Dashboard not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Dashboards"],"summary":"Update a dashboard's name and/or layout.","operationId":"update_dashboard","parameters":[{"name":"id","in":"path","description":"Dashboard ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Owning project ID (scopes the update)","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDashboardRequest"}}},"required":true},"responses":{"200":{"description":"Dashboard updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelDashboardResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Dashboard not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/genai/traces":{"get":{"tags":["GenAI"],"summary":"Query GenAI trace summaries — traces containing spans with `gen_ai.*` attributes.","description":"`duration_ms` is the only field guaranteed to be milliseconds. `gen_ai.*`\nspan attributes (e.g. time-to-first-token, token latency) often follow the\nOTel GenAI semantic conventions, which use **seconds** (a fractional\ndouble), not milliseconds — do not read them as ms without converting.","operationId":"query_genai_traces","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"service_name","in":"query","description":"Filter by service name","required":false,"schema":{"type":"string"}},{"name":"gen_ai_system","in":"query","description":"Filter by AI system (openai, anthropic, etc.)","required":false,"schema":{"type":"string"}},{"name":"gen_ai_model","in":"query","description":"Filter by model (gpt-4, claude-sonnet-4-20250514, etc.)","required":false,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Start time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max traces to return (default: 50, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"offset","in":"query","description":"Offset for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"GenAI trace summaries","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenAiTraceSummariesResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/genai/traces/{project_id}/{trace_id}":{"get":{"tags":["GenAI"],"summary":"Get GenAI span details for a specific trace.","description":"`duration_ms` is the only field guaranteed to be milliseconds. `gen_ai.*`\nspan attributes (e.g. time-to-first-token, token latency) often follow the\nOTel GenAI semantic conventions, which use **seconds** (a fractional\ndouble), not milliseconds — do not read them as ms without converting.","operationId":"get_genai_trace","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"trace_id","in":"path","description":"Trace ID (hex)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"GenAI trace span details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenAiTraceDetailResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/global/traces/{trace_id}":{"get":{"tags":["Traces"],"summary":"Assemble a unified cross-project span waterfall (Phase 2).","description":"Fans out to every project that holds spans for `trace_id` (up to 20\nprojects, 10,000 total spans). Spans are annotated with\n`project_id`/`project_name` and sorted by `start_time ASC`.\n`truncated: true` signals a hit on either cap; `truncated_projects`\nlists the dropped project IDs. See ADR-027 §4 for the full design.","operationId":"getUnifiedTrace","parameters":[{"name":"trace_id","in":"path","description":"Trace ID (32 lowercase hex characters)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Unified cross-project trace waterfall","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnifiedTrace"}}}},"400":{"description":"trace_id is not 32 lowercase hex characters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions or deployment token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/health/{project_id}":{"get":{"tags":["OTel"],"summary":"Get health summaries for a project.","operationId":"get_health","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Health summaries","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/insights/{project_id}":{"get":{"tags":["Insights"],"summary":"List anomaly insights for a project.","operationId":"list_insights","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"status","in":"query","description":"Filter by status (active, resolved)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max insights to return (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"offset","in":"query","description":"Offset for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Insights list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InsightsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/logs":{"get":{"tags":["Telemetry Logs"],"summary":"Query log records with optional filters.","operationId":"query_logs","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"severity","in":"query","description":"Filter by severity (TRACE, DEBUG, INFO, WARN, ERROR, FATAL)","required":false,"schema":{"type":"string"}},{"name":"service_name","in":"query","description":"Filter by service name","required":false,"schema":{"type":"string"}},{"name":"search","in":"query","description":"Full-text search in log body (ILIKE)","required":false,"schema":{"type":"string"}},{"name":"trace_id","in":"query","description":"Filter by correlated trace ID","required":false,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Start time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max logs to return (default: 100, max: 1000)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"offset","in":"query","description":"Offset for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Log records","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LogsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/metric-label-keys":{"get":{"tags":["Telemetry Metrics"],"summary":"List the attribute (label) keys observed on a metric — powers the\nlabel-filter key autocomplete.","operationId":"list_metric_label_keys","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"metric_name","in":"query","description":"Metric to inspect","required":true,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Window start (RFC 3339); defaults to 24h before end","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"Window end (RFC 3339); defaults to now","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Distinct label keys","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricLabelKeysResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/metric-label-values":{"get":{"tags":["Telemetry Metrics"],"summary":"List the distinct values seen for a label key on a metric — powers value\nautocomplete once a key is chosen.","operationId":"list_metric_label_values","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"metric_name","in":"query","description":"Metric to inspect","required":true,"schema":{"type":"string"}},{"name":"label_key","in":"query","description":"Label key whose values to list (must match [a-zA-Z0-9_.:-])","required":true,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Window start (RFC 3339); defaults to 24h before end","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"Window end (RFC 3339); defaults to now","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Distinct label values","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricLabelValuesResponse"}}}},"400":{"description":"Invalid label key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/metric-names/{project_id}":{"get":{"tags":["Telemetry Metrics"],"summary":"List distinct metric names for a project.","operationId":"list_metric_names","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of metric names","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricNamesResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/metrics":{"get":{"tags":["Telemetry Metrics"],"summary":"Query metrics with time bucketing.","operationId":"query_metrics","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"metric_name","in":"query","description":"Filter by metric name","required":false,"schema":{"type":"string"}},{"name":"service_name","in":"query","description":"Filter by service name","required":false,"schema":{"type":"string"}},{"name":"environment","in":"query","description":"Filter by deployment environment","required":false,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Start time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"bucket_interval","in":"query","description":"Bucket interval (e.g. '1 hour', '5 minutes')","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max buckets to return (default: 1000)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"metric_type","in":"query","description":"Filter by metric type (gauge, sum, histogram, exponential_histogram, summary)","required":false,"schema":{"type":"string"}},{"name":"aggregation","in":"query","description":"Per-bucket aggregation: avg (default), sum, min, max, count, rate, p50/p95/p99, quantile:0.95","required":false,"schema":{"type":"string"}},{"name":"label_filters","in":"query","description":"Comma-separated key=value data-point label filters (keys must match [a-zA-Z0-9_.:-])","required":false,"schema":{"type":"string"}},{"name":"group_by","in":"query","description":"Comma-separated label keys to group series by","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Metrics data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricsResponse"}}}},"400":{"description":"Invalid label key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/pipeline-stats":{"get":{"tags":["OTel"],"summary":"Get OTel pipeline statistics (admin/system view).","operationId":"get_pipeline_stats","responses":{"200":{"description":"Pipeline statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PipelineStatsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/quota/{project_id}":{"get":{"tags":["OTel"],"summary":"Get storage quota for a project.","operationId":"get_quota","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Storage quota","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuotaResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/trace-summaries":{"get":{"tags":["Traces"],"summary":"Query trace summaries — one row per trace with span count, error count,\nroot span info, and proper trace-level pagination.","operationId":"query_trace_summaries","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"trace_id","in":"query","description":"Filter by trace ID","required":false,"schema":{"type":"string"}},{"name":"service_name","in":"query","description":"Filter by service name","required":false,"schema":{"type":"string"}},{"name":"status","in":"query","description":"Filter by status (OK, ERROR)","required":false,"schema":{"type":"string"}},{"name":"min_duration_ms","in":"query","description":"Minimum trace duration in ms","required":false,"schema":{"type":"number","format":"double"}},{"name":"start_time","in":"query","description":"Start time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"name_pattern","in":"query","description":"Filter by span name pattern (ILIKE)","required":false,"schema":{"type":"string"}},{"name":"sort_by","in":"query","description":"Sort field: 'start_time' (default) or 'duration'","required":false,"schema":{"type":"string"}},{"name":"sort_order","in":"query","description":"Sort direction: 'asc' or 'desc' (default)","required":false,"schema":{"type":"string"}},{"name":"include_total","in":"query","description":"Compute the `total` count (default: true). Set false to skip the second aggregation when only the page is needed","required":false,"schema":{"type":"boolean"}},{"name":"limit","in":"query","description":"Max traces to return (default: 50, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"offset","in":"query","description":"Offset for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Trace summaries","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TraceSummariesResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/traces":{"get":{"tags":["Traces"],"summary":"Query trace spans with optional filters.","description":"Each returned span has a `duration_ms` field (float, milliseconds) — this is\nthe ONLY field guaranteed to be in milliseconds. Spans also carry an\n`attributes` map of raw key/value pairs exactly as reported by the\ninstrumenting library: numeric attribute values may be seconds, milliseconds,\nmicroseconds, or nanoseconds depending on that library's convention, and\nnothing in this response labels the unit. Never assume an attribute's\nnumeric value shares `duration_ms`'s unit, and never state a duration in\nmilliseconds unless it came from a `duration_ms` field.","operationId":"query_traces","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"trace_id","in":"query","description":"Filter by trace ID","required":false,"schema":{"type":"string"}},{"name":"service_name","in":"query","description":"Filter by service name","required":false,"schema":{"type":"string"}},{"name":"status","in":"query","description":"Filter by status (OK, ERROR, UNSET)","required":false,"schema":{"type":"string"}},{"name":"min_duration_ms","in":"query","description":"Minimum span duration in ms","required":false,"schema":{"type":"number","format":"double"}},{"name":"start_time","in":"query","description":"Start time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"limit","in":"query","description":"Max spans to return (default: 100, max: 1000)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"offset","in":"query","description":"Offset for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Trace spans","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TracesResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/traces/cross-project/{trace_id}":{"get":{"tags":["Traces"],"summary":"Discover sibling projects that share the same `trace_id` (Phase 1 banner).","description":"Returns an empty `siblings` list when the trace is single-project — never\n404. Project names are included so the UI can render navigation links\nwithout a second round-trip. See ADR-027 §3 for the full auth model and\ntopology-disclosure trade-offs.","operationId":"getCrossProjectTraceSiblings","parameters":[{"name":"trace_id","in":"path","description":"Trace ID (32 lowercase hex characters)","required":true,"schema":{"type":"string"}},{"name":"exclude_project_id","in":"query","description":"Project ID to exclude (the caller's own project) so the UI does not render a self-link","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Sibling projects sharing this trace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CrossProjectTraceResponse"}}}},"400":{"description":"trace_id is not 32 lowercase hex characters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions or deployment token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/traces/{project_id}/{trace_id}":{"get":{"tags":["Traces"],"summary":"Get all spans for a specific trace.","description":"Each span has a `duration_ms` field (float, milliseconds) — the ONLY field\nguaranteed to be in milliseconds — plus an `attributes` map of raw\nkey/value pairs exactly as the instrumenting library reported them.\nNumeric attribute values (e.g. connection-pool wait times, queue delays)\nmay be in seconds, milliseconds, microseconds, or nanoseconds depending on\nthat library's own convention; this response never labels the unit. When\nexplaining what a span spent time on, only quote milliseconds from\n`duration_ms` (or from `start_time`/`end_time` deltas) — never assume a raw\nattribute number is already in milliseconds.","operationId":"get_trace","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"trace_id","in":"path","description":"Trace ID (hex)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Trace spans tree","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TracesResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/v1/logs":{"post":{"tags":["OTel Ingest"],"summary":"Ingest log records via OTLP/HTTP protobuf.","description":"Authenticates via API key in header, decompresses, decodes protobuf,\nchecks rate limit and storage quota, routes high-severity logs\nto DB and all logs to S3.","operationId":"ingest_logs","requestBody":{"description":"OTLP ExportLogsServiceRequest (protobuf, optionally gzip/zstd compressed)","content":{"application/x-protobuf":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"Logs accepted (OTLP protobuf response)"},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"413":{"description":"Storage quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"api_key":[]}]}},"/otel/v1/metrics":{"post":{"tags":["OTel Ingest"],"summary":"Ingest metrics via OTLP/HTTP protobuf.","description":"Authenticates via API key in header, decompresses, decodes protobuf,\nchecks rate limit and storage quota, then stores.","operationId":"ingest_metrics","requestBody":{"description":"OTLP ExportMetricsServiceRequest (protobuf, optionally gzip/zstd compressed)","content":{"application/x-protobuf":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"Metrics accepted (OTLP protobuf response)"},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"413":{"description":"Storage quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"api_key":[]}]}},"/otel/v1/traces":{"post":{"tags":["OTel Ingest"],"summary":"Ingest trace spans via OTLP/HTTP protobuf.","description":"Authenticates via API key in header, decompresses, decodes protobuf,\nchecks rate limit and storage quota, then stores spans.","operationId":"ingest_traces","requestBody":{"description":"OTLP ExportTraceServiceRequest (protobuf, optionally gzip/zstd compressed)","content":{"application/x-protobuf":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"Traces accepted (OTLP protobuf response)"},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"413":{"description":"Storage quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"api_key":[]}]}},"/otel/v1/{project_id}/{environment_id}/{deployment_id}/logs":{"post":{"tags":["OTel Ingest"],"summary":"Ingest log records with project/environment/deployment in the URL path.","operationId":"ingest_logs_by_path","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"OTLP ExportLogsServiceRequest (protobuf, optionally gzip/zstd compressed)","content":{"application/x-protobuf":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"Logs accepted (OTLP protobuf response)"},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"413":{"description":"Storage quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"api_key":[]}]}},"/otel/v1/{project_id}/{environment_id}/{deployment_id}/metrics":{"post":{"tags":["OTel Ingest"],"summary":"Ingest metrics with project/environment/deployment in the URL path.","operationId":"ingest_metrics_by_path","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"OTLP ExportMetricsServiceRequest (protobuf, optionally gzip/zstd compressed)","content":{"application/x-protobuf":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"Metrics accepted (OTLP protobuf response)"},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"413":{"description":"Storage quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"api_key":[]}]}},"/otel/v1/{project_id}/{environment_id}/{deployment_id}/traces":{"post":{"tags":["OTel Ingest"],"summary":"Ingest trace spans with project/environment/deployment in the URL path.","operationId":"ingest_traces_by_path","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"OTLP ExportTraceServiceRequest (protobuf, optionally gzip/zstd compressed)","content":{"application/x-protobuf":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"Traces accepted (OTLP protobuf response)"},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"413":{"description":"Storage quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"api_key":[]}]}},"/performance/has-metrics":{"get":{"tags":["Performance"],"summary":"Check if performance metrics exist for a project","operationId":"has_performance_metrics","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully checked performance metrics availability","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HasMetricsResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/performance/metrics":{"get":{"tags":["Performance"],"summary":"Get performance metrics","operationId":"get_performance_metrics","parameters":[{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Deployment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"device_type","in":"query","description":"Device type filter: desktop or mobile (optional)","required":false,"schema":{"type":"string"}},{"name":"include_bots","in":"query","description":"Include crawler/datacenter bot samples (default false)","required":false,"schema":{"type":"boolean"}},{"name":"filter_path","in":"query","description":"Filter to one page pathname (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_country","in":"query","description":"Filter to one country (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_region","in":"query","description":"Filter to one region (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_city","in":"query","description":"Filter to one city (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_browser","in":"query","description":"Filter to one browser (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_operating_system","in":"query","description":"Filter to one operating system (optional)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved performance metrics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PerformanceMetricsResponse"}}}},"400":{"description":"Invalid date format or missing parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/performance/metrics-over-time":{"get":{"tags":["Performance"],"summary":"Get metrics over time","operationId":"get_metrics_over_time","parameters":[{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DDTHH:MM:SSZ","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DDTHH:MM:SSZ","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Deployment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"device_type","in":"query","description":"Device type filter: desktop or mobile (optional)","required":false,"schema":{"type":"string"}},{"name":"include_bots","in":"query","description":"Include crawler/datacenter bot samples (default false)","required":false,"schema":{"type":"boolean"}},{"name":"filter_path","in":"query","description":"Filter to one page pathname (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_country","in":"query","description":"Filter to one country (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_region","in":"query","description":"Filter to one region (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_city","in":"query","description":"Filter to one city (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_browser","in":"query","description":"Filter to one browser (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_operating_system","in":"query","description":"Filter to one operating system (optional)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved metrics over time","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MetricsOverTimeResponse"}}}},"400":{"description":"Invalid date format or missing parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/performance/page-metrics":{"get":{"tags":["Performance"],"summary":"Get grouped page metrics","operationId":"get_grouped_page_metrics","parameters":[{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DDTHH:MM:SSZ","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DDTHH:MM:SSZ","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Deployment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"group_by","in":"query","description":"Group by: path, country, region, city, device_type, browser, operating_system","required":true,"schema":{"type":"string"}},{"name":"device_type","in":"query","description":"Device type filter: desktop or mobile (optional)","required":false,"schema":{"type":"string"}},{"name":"include_bots","in":"query","description":"Include crawler/datacenter bot samples (default false)","required":false,"schema":{"type":"boolean"}},{"name":"filter_path","in":"query","description":"Filter to one page pathname (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_country","in":"query","description":"Filter to one country (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_region","in":"query","description":"Filter to one region (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_city","in":"query","description":"Filter to one city (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_browser","in":"query","description":"Filter to one browser (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_operating_system","in":"query","description":"Filter to one operating system (optional)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved grouped page metrics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GroupedPageMetricsResponse"}}}},"400":{"description":"Invalid date format, missing parameters, or invalid group_by value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/platform/access-info":{"get":{"tags":["Platform"],"summary":"Get information about how the service is being accessed","description":"Returns details about the server's access mode, public IP address, private IP address,\nand domain creation capabilities. Both IP addresses are always included when available.","operationId":"get_access_info","responses":{"200":{"description":"Service access information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceAccessInfo"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/platform/private-ip":{"get":{"tags":["Platform"],"summary":"Get private/local IP address of the server","operationId":"get_private_ip","responses":{"200":{"description":"Successfully retrieved private IP address"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/platform/public-ip":{"get":{"tags":["Platform"],"summary":"Get public IP address of the server","operationId":"get_public_ip","responses":{"200":{"description":"Successfully retrieved public IP address"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/presets":{"get":{"tags":["Presets"],"summary":"List all available presets","operationId":"list_presets","responses":{"200":{"description":"List of available presets","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListPresetsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/presets/{slug}/dockerfile":{"post":{"tags":["Presets"],"summary":"Generate a Dockerfile from a preset","description":"Returns the Dockerfile content and build arguments for a given preset slug.\nThe CLI can use this to build Docker images locally without needing a Dockerfile\nin the project directory, enabling zero-config deployments.","operationId":"generate_preset_dockerfile","parameters":[{"name":"slug","in":"path","description":"Preset slug (e.g., nextjs, vite, python)","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateDockerfileRequest"}}},"required":true},"responses":{"200":{"description":"Generated Dockerfile","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateDockerfileResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Preset not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/preview-gateway/logs":{"get":{"tags":["Preview Gateway"],"operationId":"get_preview_gateway_logs","parameters":[{"name":"tail","in":"query","description":"Lines to tail (default 200, max 2000)","required":false,"schema":{"type":"integer","minimum":0}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LogsResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/preview-gateway/restart":{"post":{"tags":["Preview Gateway"],"operationId":"restart_preview_gateway","responses":{"204":{"description":"Gateway restarted"}},"security":[{"bearer_auth":[]}]}},"/preview-gateway/settings":{"get":{"tags":["Preview Gateway"],"operationId":"get_preview_gateway_settings","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreviewGatewaySettingsResponse"}}}}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Preview Gateway"],"operationId":"patch_preview_gateway_settings","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PatchSettingsRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreviewGatewaySettingsResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/preview-gateway/status":{"get":{"tags":["Preview Gateway"],"operationId":"get_preview_gateway_status","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayStatus"}}}}},"security":[{"bearer_auth":[]}]}},"/preview-gateway/upgrade":{"post":{"tags":["Preview Gateway"],"operationId":"upgrade_preview_gateway","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpgradeRequest"}}},"required":true},"responses":{"204":{"description":"Gateway upgraded"}},"security":[{"bearer_auth":[]}]}},"/projects":{"get":{"tags":["Projects"],"summary":"Get a list of all projects","operationId":"get_projects","parameters":[{"name":"page","in":"query","description":"Page number (1-based)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"per_page","in":"query","description":"Number of items per page","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"List of projects","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedProjectList"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Projects"],"summary":"Create a new project","operationId":"create_project","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectRequest"}}},"required":true},"responses":{"200":{"description":"Project created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"400":{"description":"Invalid input"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/by-slug/{slug}":{"get":{"tags":["Projects"],"summary":"Get details of a specific project by slug","operationId":"get_project_by_slug","parameters":[{"name":"slug","in":"path","description":"Project slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Project details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"404":{"description":"Project not found"}},"security":[{"bearer_auth":[]}]}},"/projects/from-template":{"post":{"tags":["Projects"],"summary":"Create a new project from a template","description":"Creates a new repository from a template and sets up the project with the\nspecified configuration. The template is cloned to a new repository under\nthe authenticated user's account or specified organization.","operationId":"create_project_from_template","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectFromTemplateRequest"}}},"required":true},"responses":{"201":{"description":"Project created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectFromTemplateResponse"}}}},"400":{"description":"Invalid input"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Template not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/statistics":{"get":{"tags":["Projects"],"summary":"Get project statistics","operationId":"get_project_statistics","responses":{"200":{"description":"Project statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectStatisticsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{id}":{"get":{"tags":["Projects"],"summary":"Get details of a specific project","operationId":"get_project","parameters":[{"name":"id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Project details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"404":{"description":"Project not found"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Projects"],"operationId":"update_project","parameters":[{"name":"id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectRequest"}}},"required":true},"responses":{"200":{"description":"Project updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Projects"],"operationId":"delete_project","parameters":[{"name":"id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Project deleted successfully"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{id}/deployments":{"get":{"tags":["Projects"],"operationId":"get_project_deployments","parameters":[{"name":"id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"per_page","in":"query","description":"Items per page","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"environment_id","in":"query","description":"Environment ID filter","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of deployments","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentListResponse"}}}},"404":{"description":"Project not found"}}}},"/projects/{id}/last-deployment":{"get":{"tags":["Deployments"],"summary":"Get the last deployment for a specific project","operationId":"get_last_deployment","parameters":[{"name":"id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Last deployment details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentResponse"}}}},"404":{"description":"Project not found or no deployments"},"500":{"description":"Internal server error"}}}},"/projects/{id}/source":{"patch":{"tags":["Projects"],"summary":"Change a project's source type to a Git-less type (docker_image /\nstatic_files / manual). Switching TO Git is done via the Git settings\nendpoint (`POST /projects/{id}/git`), which also supplies the repository and\nprovider connection.","operationId":"change_project_source","parameters":[{"name":"id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeProjectSourceRequest"}}},"required":true},"responses":{"200":{"description":"Source type changed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"400":{"description":"Invalid source type change (e.g. switching to Git here)"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{id}/trigger-pipeline":{"post":{"tags":["Projects"],"summary":"Trigger pipeline for a specific project","operationId":"trigger_project_pipeline","parameters":[{"name":"id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerPipelinePayload"}}},"required":true},"responses":{"200":{"description":"Pipeline triggered successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerPipelineResponse"}}}},"400":{"description":"Invalid request"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/access":{"get":{"tags":["Teams"],"operationId":"list_project_access","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Access grants","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProjectAccessResponse"}}}}},"403":{"description":"Insufficient permissions or no access to this project"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Teams"],"operationId":"grant_project_access","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectAccessRequest"}}},"required":true},"responses":{"201":{"description":"Access granted (idempotent upsert)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectAccessResponse"}}}},"403":{"description":"Insufficient permissions or no access to this project"},"404":{"description":"Team not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/access/{team_id}":{"delete":{"tags":["Teams"],"operationId":"revoke_project_access","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"team_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Access revoked"},"403":{"description":"Insufficient permissions or no access to this project"},"404":{"description":"Grant not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/active-visitors":{"get":{"tags":["Events"],"summary":"Get active visitors count","operationId":"get_active_visitors","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved active visitors count","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActiveVisitorsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents":{"get":{"tags":["Agents"],"operationId":"list_agents","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of agents for project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListAgentsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Agents"],"operationId":"create_agent","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertAgentRequest"}}},"required":true},"responses":{"201":{"description":"Agent created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentConfigResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/cli-status":{"get":{"tags":["Agents"],"operationId":"get_cli_status","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"provider","in":"query","description":"AI provider: claude_cli or codex_cli","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"CLI status"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/runs":{"get":{"tags":["Agents"],"operationId":"list_all_runs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-based)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (max 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List of all agent runs for a project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListRunsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/runs/latest-for-source":{"get":{"tags":["Agents"],"operationId":"latest_run_for_source","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"trigger_source_type","in":"query","description":"Trigger source type, e.g. 'error_group'","required":true,"schema":{"type":"string"}},{"name":"trigger_source_id","in":"query","description":"Trigger source ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Latest matching run, or null if none","content":{"application/json":{"schema":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AgentRunResponse"}]}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/runs/{run_id}":{"get":{"tags":["Agents"],"operationId":"get_run_with_logs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Run with logs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRunWithLogsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/runs/{run_id}/cancel":{"post":{"tags":["Agents"],"operationId":"cancel_run","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Agent run ID to cancel","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Run cancelled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRunResponse"}}}},"400":{"description":"Run is already in a terminal state"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/runs/{run_id}/retry":{"post":{"tags":["Agents"],"summary":"Retry a completed, failed, cancelled, or no_fix run with the same trigger context.\nCreates a new run record and spawns the executor.","operationId":"retry_run","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID to retry","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"202":{"description":"New run created from retry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRunResponse"}}}},"400":{"description":"Run is still active"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/runs/{run_id}/stream":{"get":{"tags":["Agents"],"summary":"SSE endpoint for real-time streaming of run events.\nPolls the agent_run_logs table every 500ms for new entries and streams them.\nCloses when the run reaches a terminal status.","operationId":"stream_run_events","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Agent run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Server-Sent Events stream of run log events and terminal status","content":{"text/event-stream":{}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/sandbox-status":{"get":{"tags":["Agents"],"operationId":"get_sandbox_status","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Project-scoped sandbox readiness (Docker + agent image)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxStatusResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/smoke-test":{"post":{"tags":["Agents"],"summary":"Run a smoke test to verify the selected AI CLI works in the environment\nwhere agents will actually execute (host or sandbox container). If no\n`provider_id` is supplied the globally active provider is tested.","operationId":"smoke_test_agent","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"provider_id","in":"query","description":"Provider id to test; defaults to the globally active provider","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Smoke test result for the AI CLI in the agent's execution environment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SmokeTestResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/{slug}":{"get":{"tags":["Agents"],"operationId":"get_agent","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Agent slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Agent config","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentConfigResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Agent not found"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Agents"],"operationId":"update_agent","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Agent slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertAgentRequest"}}},"required":true},"responses":{"200":{"description":"Agent updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentConfigResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Agent not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Agents"],"operationId":"delete_agent","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Agent slug","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Agent deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Agent not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/{slug}/runs":{"get":{"tags":["Agents"],"operationId":"list_agent_runs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Agent slug","required":true,"schema":{"type":"string"}},{"name":"page","in":"query","description":"Page number (1-based)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (max 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List of runs for a specific agent","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListRunsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Agent not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/{slug}/trigger":{"post":{"tags":["Agents"],"operationId":"trigger_agent","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Agent slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerAgentRequest"}}},"required":true},"responses":{"202":{"description":"Agent run created and queued","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRunResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"402":{"description":"Daily budget exceeded"},"403":{"description":"Insufficient permissions"},"404":{"description":"Agent not found"},"422":{"description":"AI CLI not installed"},"429":{"description":"Cooldown active"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/aggregated-buckets":{"get":{"tags":["Events"],"summary":"Get aggregated metrics by time bucket","operationId":"get_aggregated_buckets","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date for the query range","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date for the query range","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Optional environment filter","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Optional deployment filter","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"aggregation_level","in":"query","description":"Aggregation level: events, sessions, or visitors (default: events)","required":false,"schema":{"type":"string"}},{"name":"bucket_size","in":"query","description":"Time bucket size: '1 hour', '1 day', '1 week', etc. (default: '1 hour')","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved aggregated buckets","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AggregatedBucketsResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/conversations":{"get":{"tags":["AI Chat"],"summary":"Find the existing chat for a context (returns `null` if none yet). Requires\nthe per-project `ai_debug_chat_enabled` toggle to be on; returns 403 when the\nfeature is disabled so revoking it consistently hides existing chat content.","operationId":"find_conversation","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"context_type","in":"query","required":true,"schema":{"type":"string"}},{"name":"context_id","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ConversationResponse"}]}}}},"401":{"description":""},"403":{"description":""}},"security":[{"bearer_auth":[]}]},"post":{"tags":["AI Chat"],"summary":"Get-or-create the chat for a context (seeds it on first open).","operationId":"create_conversation","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateConversationRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversationResponse"}}}},"401":{"description":""},"403":{"description":""},"404":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/conversations/list":{"get":{"tags":["AI Chat"],"summary":"List all active conversations for a project, most-recently-active first.\nPowers the conversation switcher in the AI assistant sidebar.","operationId":"list_conversations","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ConversationResponse"}}}}},"401":{"description":""},"403":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/conversations/{public_id}":{"get":{"tags":["AI Chat"],"summary":"Full conversation history (excluding the internal system seed).","operationId":"get_conversation","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"public_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversationDetailResponse"}}}},"401":{"description":""},"403":{"description":""},"404":{"description":""}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["AI Chat"],"summary":"Rename a conversation (set its human-facing title).","operationId":"rename_conversation","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"public_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RenameConversationRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversationResponse"}}}},"400":{"description":""},"401":{"description":""},"403":{"description":""},"404":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/conversations/{public_id}/archive":{"post":{"tags":["AI Chat"],"summary":"Archive (soft-delete) a conversation.","operationId":"archive_conversation","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"public_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":""},"401":{"description":""},"403":{"description":""},"404":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/conversations/{public_id}/messages":{"post":{"tags":["AI Chat"],"summary":"Send a user message; stream the assistant reply as Server-Sent Events.","operationId":"send_message","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"public_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendMessageRequest"}}},"required":true},"responses":{"200":{"description":"SSE stream of assistant text deltas","content":{"text/event-stream":{}}},"401":{"description":""},"403":{"description":""},"404":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/conversations/{public_id}/pending-actions":{"get":{"tags":["AI Chat"],"summary":"List all pending actions for a conversation (most-recently-proposed first).","operationId":"list_pending_actions","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"public_id","in":"path","description":"Conversation public id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PendingActionResponse"}}}}},"401":{"description":""},"403":{"description":""},"404":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/pending-actions/{action_public_id}":{"get":{"tags":["AI Chat"],"summary":"Get a single pending action by its public id (scoped to the project).","operationId":"get_pending_action","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"action_public_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PendingActionResponse"}}}},"401":{"description":""},"403":{"description":""},"404":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/pending-actions/{action_public_id}/confirm":{"post":{"tags":["AI Chat"],"summary":"Confirm a proposed AI action: validate permission, atomically claim, execute,\npersist outcome. The execution uses the CONFIRMING user's auth — never the model's.","operationId":"confirm_pending_action","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"action_public_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PendingActionResponse"}}}},"401":{"description":""},"403":{"description":""},"404":{"description":""},"409":{"description":""},"503":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/pending-actions/{action_public_id}/reject":{"post":{"tags":["AI Chat"],"summary":"Reject a proposed AI action (no execution). Status transitions to \"rejected\".","operationId":"reject_pending_action","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"action_public_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PendingActionResponse"}}}},"401":{"description":""},"403":{"description":""},"404":{"description":""},"409":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/readiness":{"get":{"tags":["AI Chat"],"summary":"Report which AI prerequisites this project satisfies.","description":"Read-only and cheap, so the UI can decide up front whether to show a working\nentry point, an onboarding path, or nothing — instead of letting the user\nclick something that fails with a 409 they can't act on.","operationId":"get_chat_readiness","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Which AI prerequisites are met","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatReadinessResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/alarms":{"get":{"tags":["Alarms"],"summary":"List alarms for a project with optional filters.","operationId":"listProjectAlarms","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"alarm_type","in":"query","description":"Filter by alarm type (e.g. `container_restart`, `outage`).","required":false,"schema":{"type":["string","null"]}},{"name":"status","in":"query","description":"Filter by status: `firing`, `acknowledged`, or `resolved`.","required":false,"schema":{"type":["string","null"]}},{"name":"severity","in":"query","description":"Filter by severity: `info`, `warning`, or `critical`.","required":false,"schema":{"type":["string","null"]}},{"name":"environment_id","in":"query","description":"Filter by environment ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"service_id","in":"query","description":"Filter by external service ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"page","in":"query","description":"Page number (1-based, default 1).","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page (default 20, max 100).","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}}],"responses":{"200":{"description":"Paginated list of alarms","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlarmListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/alarms/summary":{"get":{"tags":["Alarms"],"summary":"Get alarm counts by status/severity/type for a project (dashboard summary widget).","operationId":"getProjectAlarmsSummary","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Alarm summary counts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlarmSummaryResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/alarms/{alarm_id}/acknowledge":{"post":{"tags":["Alarms"],"summary":"Acknowledge a firing alarm (marks it as seen but not resolved).","operationId":"acknowledgeAlarm","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"alarm_id","in":"path","description":"Alarm ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Alarm acknowledged"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Alarm not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/alarms/{alarm_id}/resolve":{"post":{"tags":["Alarms"],"summary":"Resolve an alarm.","operationId":"resolveAlarm","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"alarm_id","in":"path","description":"Alarm ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Alarm resolved"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Alarm not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/analyze":{"post":{"tags":["Autofixer"],"summary":"Start an autofixer analysis run for the given error group.\nCreates the run record immediately and spawns analysis in the background.","operationId":"start_analysis","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartAnalysisRequest"}}},"required":true},"responses":{"202":{"description":"Analysis started; returns run_id for streaming","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutofixerRunResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/runs/{run_id}":{"get":{"tags":["Autofixer"],"summary":"Get a single autofixer run with its logs.","operationId":"get_run","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Run with logs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutofixerRunWithLogsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/runs/{run_id}/add-context":{"post":{"tags":["Autofixer"],"summary":"Append a user message to the run's context field.","operationId":"add_context","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddContextRequest"}}},"required":true},"responses":{"200":{"description":"Context appended"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/runs/{run_id}/cancel":{"post":{"tags":["Autofixer"],"summary":"Cancel an autofixer run and clean up the work directory.","operationId":"cancel","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Run cancelled"},"400":{"description":"Run is already in a terminal state"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/runs/{run_id}/create-pr":{"post":{"tags":["Autofixer"],"summary":"Push the fix branch and create a pull request.\nRequires phase == \"fix_ready\".","operationId":"create_pr","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"201":{"description":"PR created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePrResponse"}}}},"400":{"description":"Run not in fix_ready phase"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/runs/{run_id}/fix":{"post":{"tags":["Autofixer"],"summary":"Transition from analysis to fix phase.\nRequires phase == \"analyzed\".","operationId":"start_fix","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"202":{"description":"Fix generation started"},"400":{"description":"Run not in analyzed phase"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/runs/{run_id}/re-analyze":{"post":{"tags":["Autofixer"],"summary":"Continue the conversation with user feedback.\nUses the same Claude session (--continue) in the existing work directory.\nRequires phase == \"analyzed\".","operationId":"re_analyze","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"202":{"description":"Conversation continued with feedback"},"400":{"description":"Run not in analyzed phase"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/runs/{run_id}/stream":{"get":{"tags":["Agents"],"summary":"SSE endpoint: streams run log events in real-time.\nPolls every 500 ms. Keeps the connection open through \"analyzed\" and \"fix_ready\"\nwaiting states; closes only on terminal statuses.","operationId":"stream_events","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Autofixer run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Server-Sent Events stream of autofixer run logs and status updates","content":{"text/event-stream":{}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/automatic-deploy":{"post":{"tags":["Projects"],"summary":"Update automatic deployment setting for a project","operationId":"update_automatic_deploy","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAutomaticDeployRequest"}}},"required":true},"responses":{"200":{"description":"Automatic deployment setting updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/custom-domains":{"get":{"tags":["Custom Domains"],"summary":"List all custom domains for a project","operationId":"list_custom_domains_for_project","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Custom domains retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListCustomDomainsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Custom Domains"],"summary":"Create a custom domain for a project","operationId":"create_custom_domain","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomDomainRequest"}}},"required":true},"responses":{"201":{"description":"Custom domain created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomDomainResponse"}}}},"400":{"description":"Invalid input"},"401":{"description":"Unauthorized"},"409":{"description":"Domain already exists"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/custom-domains/{domain_id}":{"get":{"tags":["Custom Domains"],"summary":"Get a custom domain by ID","operationId":"get_custom_domain","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain_id","in":"path","description":"Custom domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Custom domain retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomDomainResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Custom domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Custom Domains"],"summary":"Update a custom domain","operationId":"update_custom_domain","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain_id","in":"path","description":"Custom domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCustomDomainRequest"}}},"required":true},"responses":{"200":{"description":"Custom domain updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomDomainResponse"}}}},"400":{"description":"Invalid input"},"401":{"description":"Unauthorized"},"404":{"description":"Custom domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Custom Domains"],"summary":"Delete a custom domain","operationId":"delete_custom_domain","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain_id","in":"path","description":"Custom domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Custom domain deleted successfully"},"401":{"description":"Unauthorized"},"404":{"description":"Custom domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/custom-domains/{domain_id}/link-certificate/{certificate_id}":{"post":{"tags":["Custom Domains"],"summary":"Link a custom domain to a certificate","operationId":"link_custom_domain_to_certificate","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain_id","in":"path","description":"Custom domain ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"certificate_id","in":"path","description":"Certificate ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Custom domain linked to certificate successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomDomainResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Custom domain or certificate not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/deployment-config":{"patch":{"tags":["Projects"],"summary":"Update deployment configuration for a project","operationId":"update_project_deployment_config","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDeploymentConfigRequest"}}},"required":true},"responses":{"200":{"description":"Deployment configuration updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"400":{"description":"Invalid deployment configuration"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/deployment-tokens":{"get":{"tags":["Deployment Tokens"],"summary":"List all deployment tokens for a project","operationId":"list_deployment_tokens","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List of deployment tokens","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentTokenListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Deployment Tokens"],"summary":"Create a new deployment token for a project","operationId":"create_deployment_token","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDeploymentTokenRequest"}}},"required":true},"responses":{"201":{"description":"Deployment token created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDeploymentTokenResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"409":{"description":"Token with this name already exists"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/deployment-tokens/{token_id}":{"get":{"tags":["Deployment Tokens"],"summary":"Get a specific deployment token","operationId":"get_deployment_token","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"token_id","in":"path","description":"Deployment token ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deployment token details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentTokenResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Deployment token not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Deployment Tokens"],"summary":"Delete a deployment token","operationId":"delete_deployment_token","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"token_id","in":"path","description":"Deployment token ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Deployment token deleted successfully"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Deployment token not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Deployment Tokens"],"summary":"Update a deployment token","operationId":"update_deployment_token","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"token_id","in":"path","description":"Deployment token ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDeploymentTokenRequest"}}},"required":true},"responses":{"200":{"description":"Deployment token updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentTokenResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Deployment token not found"},"409":{"description":"Token with this name already exists"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/deployment-tokens/{token_id}/rotate":{"post":{"tags":["Deployment Tokens"],"summary":"Rotate a deployment token, invalidating its old secret and issuing a new one","operationId":"rotate_deployment_token","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"token_id","in":"path","description":"Deployment token ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deployment token rotated successfully; the response contains the new plaintext token, shown only once","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDeploymentTokenResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Deployment token not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/deployments/{deployment_id}":{"get":{"tags":["Deployments"],"summary":"Get a specific deployment by ID for a project (identified by ID or slug)","operationId":"get_deployment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deployment details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentResponse"}}}},"404":{"description":"Project or deployment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/deployments/{deployment_id}/cancel":{"post":{"tags":["Projects"],"summary":"Cancel a deployment","operationId":"cancel_deployment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deployment cancelled successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentStateResponse"}}}},"400":{"description":"Deployment cannot be cancelled (already completed, failed, or cancelled)"},"404":{"description":"Project or deployment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/deployments/{deployment_id}/container-logs":{"get":{"tags":["Deployments"],"summary":"List the captured (historical) container-log dumps for a deployment.","description":"Container runtime logs are normally only available live from the running\ncontainer. When a deployment is superseded its containers are torn down and\nthose logs would be lost — so just before teardown we capture each\ncontainer's logs to durable storage. This endpoint lists what was captured\nfor a given (often older) deployment, so a user can read the logs of a\ncontainer that no longer exists.","operationId":"list_deployment_container_logs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Captured container logs for the deployment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentContainerLogsListResponse"}}}},"404":{"description":"Deployment not found in this project"},"500":{"description":"Internal server error"}},"security":[{"bearer_token":[]}]}},"/projects/{project_id}/deployments/{deployment_id}/container-logs/{log_id}":{"get":{"tags":["Deployments"],"summary":"Get the captured text content of a single historical container-log dump.","operationId":"get_deployment_container_log_content","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"log_id","in":"path","description":"Captured log ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Captured container log content","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentContainerLogContentResponse"}}}},"404":{"description":"Captured log not found in this project"},"500":{"description":"Internal server error"}},"security":[{"bearer_token":[]}]}},"/projects/{project_id}/deployments/{deployment_id}/jobs":{"get":{"tags":["Deployments"],"summary":"Get jobs for a specific deployment","description":"Returns all jobs (workflow tasks) for a deployment, ordered by execution order.\nThis replaces the old deployment stages endpoint.","operationId":"get_deployment_jobs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Jobs retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentJobsResponse"}}}},"404":{"description":"Deployment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/deployments/{deployment_id}/jobs/{job_id}/logs":{"get":{"tags":["Deployments"],"summary":"Get logs for a specific deployment job","operationId":"get_deployment_job_logs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"job_id","in":"path","description":"Job ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Job logs retrieved successfully","content":{"text/plain":{"schema":{"type":"string"}}}},"404":{"description":"Job or logs not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_token":[]}]}},"/projects/{project_id}/deployments/{deployment_id}/jobs/{job_id}/logs/tail":{"get":{"tags":["Deployments"],"summary":"Tail logs for a specific deployment job in real-time via WebSocket","description":"**WebSocket Streaming**: Logs are sent as raw text, one line per WebSocket message.\n\n**Authentication**: Requires authentication via session cookie (browser clients)\nor API key (API clients). For browser-based WebSocket connections, ensure the user\nis logged in - the browser automatically includes session cookies in the WebSocket\nupgrade request.\n\n**API Client Authentication**: Include API key in Authorization header:\n```text\nAuthorization: Bearer tk_your_api_key_here\n```","operationId":"tail_deployment_job_logs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"job_id","in":"path","description":"Job ID","required":true,"schema":{"type":"string"}}],"responses":{"101":{"description":"WebSocket connection established for streaming deployment job logs"},"404":{"description":"Job or logs not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_token":[]}]}},"/projects/{project_id}/deployments/{deployment_id}/operations":{"get":{"tags":["Deployments"],"summary":"Get all operations for a deployment","operationId":"get_deployment_operations","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of operations","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperationResultsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Deployment not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Deployments"],"summary":"Execute a deployment operation (deploy, mark_complete, take_screenshot)","operationId":"execute_deployment_operation","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecuteOperationRequest"}}},"required":true},"responses":{"202":{"description":"Operation executed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperationResultResponse"}}}},"400":{"description":"Invalid operation"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Deployment not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/deployments/{deployment_id}/operations/{operation_type}":{"get":{"tags":["Deployments"],"summary":"Get the status of a specific operation type","operationId":"get_deployment_operation_status","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","required":true,"schema":{"type":"string"}},{"name":"operation_type","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Operation status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperationResultResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Operation not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/deployments/{deployment_id}/pause":{"post":{"tags":["Projects"],"summary":"Pause a deployment","operationId":"pause_deployment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deployment paused successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentStateResponse"}}}},"404":{"description":"Project or deployment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/deployments/{deployment_id}/promote":{"post":{"tags":["Deployments"],"summary":"Promote a deployment to another environment","description":"Creates a new deployment in the target environment using the source deployment's\nDocker image. Useful for promoting a validated preview/staging deployment to production.","operationId":"promote_deployment","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Source deployment ID to promote","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PromoteDeploymentRequest"}}},"required":true},"responses":{"200":{"description":"Promotion initiated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentResponse"}}}},"400":{"description":"Invalid deployment state for promotion"},"404":{"description":"Project, deployment, or target environment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/deployments/{deployment_id}/resume":{"post":{"tags":["Projects"],"summary":"Resume a deployment","operationId":"resume_deployment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deployment resumed successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentStateResponse"}}}},"404":{"description":"Project or deployment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/deployments/{deployment_id}/rollback":{"post":{"tags":["Projects"],"operationId":"rollback_to_deployment","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID to rollback to","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Rollback initiated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentResponse"}}}},"404":{"description":"Project or deployment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/deployments/{deployment_id}/teardown":{"delete":{"tags":["Projects"],"summary":"Teardown a specific deployment","operationId":"teardown_deployment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Deployment torn down successfully"},"404":{"description":"Project or deployment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/dsns":{"get":{"tags":[],"summary":"List all DSNs for a project","operationId":"list_dsns","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of DSNs","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProjectDSNResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"post":{"tags":[],"summary":"Create a new DSN for a project","operationId":"create_dsn","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDSNRequest"}}},"required":true},"responses":{"201":{"description":"DSN created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectDSNResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/dsns/get-or-create":{"post":{"tags":[],"summary":"Get or create DSN for a project/environment/deployment combination","operationId":"get_or_create_dsn","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetOrCreateDSNRequest"}}},"required":true},"responses":{"200":{"description":"DSN retrieved or created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectDSNResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/dsns/{dsn_id}/regenerate":{"post":{"tags":[],"summary":"Regenerate DSN keys (rotate keys)","operationId":"regenerate_dsn","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"dsn_id","in":"path","description":"DSN ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegenerateDSNRequest"}}},"required":true},"responses":{"200":{"description":"DSN keys regenerated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectDSNResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"DSN not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/dsns/{dsn_id}/revoke":{"post":{"tags":[],"summary":"Revoke (deactivate) a DSN","operationId":"revoke_dsn","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"dsn_id","in":"path","description":"DSN ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"DSN revoked"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"DSN not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/env-vars":{"get":{"tags":["Projects"],"summary":"Get environment variables for a project, optionally filtered by environment","operationId":"get_environment_variables","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Optional environment ID to filter by","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of environment variables","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EnvironmentVariableResponse"}}}}},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}},"post":{"tags":["Projects"],"summary":"Create a new environment variable","operationId":"create_environment_variable","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEnvironmentVariableRequest"}}},"required":true},"responses":{"201":{"description":"Environment variables created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentVariableResponse"}}}},"400":{"description":"Invalid input"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/env-vars/resolved":{"get":{"tags":["Projects"],"summary":"Resolved env vars for a project (manual + integration-sourced, merged).","description":"Returns the effective set of environment variables a deployment would see,\ncombining manually-defined vars with those contributed by linked external\nservices (Postgres, Redis, S3, etc.). Each entry is tagged with its source\nso the UI can render an integration icon, and manual entries that shadow an\nintegration key carry a reference to the integration they override.\n\nValues are always returned as a masked preview. Use the per-key reveal\nendpoint for plaintext (audit-logged).","operationId":"get_resolved_environment_variables","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Optional environment ID to filter manual vars by","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Resolved environment variables","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ResolvedEnvVarResponse"}}}}},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/env-vars/resolved/{key}/value":{"get":{"tags":["Projects"],"summary":"Reveal the plaintext value of a resolved environment variable.","description":"Mirrors `GET /projects/{id}/env-vars/{key}/value` but handles keys sourced\nfrom linked integrations (which are not stored in the `env_vars` table).\nResolution order mirrors the merged view:\n\n1. Manual env var with this key — this endpoint reads the manual store when\n the key exists there, then writes its own reveal audit event so callers\n can safely use one endpoint regardless of source.\n2. Integration env var supplied by a linked external service.\n\nReturns 404 when neither a manual var nor an integration produces the key.","operationId":"get_resolved_environment_variable_value","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"key","in":"path","description":"Environment variable key","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Optional environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"var_id","in":"query","description":"Exact manual environment-variable row ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"service_id","in":"query","description":"Integration service ID shown by the resolved list","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Resolved environment variable value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentVariableValueResponse"}}}},"403":{"description":"Plaintext secret access is not permitted"},"404":{"description":"Project, key, or integration not found"},"409":{"description":"Environment variable key is ambiguous"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/env-vars/{key}/value":{"get":{"tags":["Projects"],"summary":"Get environment variable value by key","operationId":"get_environment_variable_value","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"key","in":"path","description":"Environment variable key","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Optional environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"var_id","in":"query","description":"Exact environment-variable row ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Environment variable value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentVariableValueResponse"}}}},"403":{"description":"Plaintext secret access is not permitted"},"404":{"description":"Project or variable not found"},"409":{"description":"Environment variable key is ambiguous"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/env-vars/{var_id}":{"put":{"tags":["Projects"],"summary":"Update an environment variable","operationId":"update_environment_variable","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"var_id","in":"path","description":"Environment variable ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEnvironmentVariableRequest"}}},"required":true},"responses":{"200":{"description":"Environment variables updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentVariableResponse"}}}},"400":{"description":"Invalid input"},"404":{"description":"Project or variable not found"},"500":{"description":"Internal server error"}}},"delete":{"tags":["Projects"],"summary":"Delete an environment variable","operationId":"delete_environment_variable","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"var_id","in":"path","description":"Environment variable ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Environment variable deleted successfully"},"404":{"description":"Project or variable not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments":{"get":{"tags":["Projects"],"summary":"Get all environments for a project","operationId":"get_environments","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of environments","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EnvironmentResponse"}}}}},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}},"post":{"tags":["Projects"],"summary":"Create a new environment for a project","operationId":"create_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEnvironmentRequest"}}},"required":true},"responses":{"201":{"description":"Environment created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentResponse"}}}},"400":{"description":"Invalid input"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}":{"get":{"tags":["Projects"],"summary":"Get a specific environment by ID or slug","operationId":"get_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Environment details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentResponse"}}}},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}}},"delete":{"tags":["Projects"],"summary":"Delete an environment permanently","description":"Permanently deletes an environment and all related data. Cannot delete:\n- Production environments (name = \"Production\")\n\nWarning: This action is permanent and cannot be undone.\nActive deployments are automatically cancelled before deletion.","operationId":"delete_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Environment permanently deleted"},"400":{"description":"Cannot delete production environment"},"404":{"description":"Project or environment not found"},"428":{"description":"Recent MFA verification required"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/crons":{"get":{"tags":["Crons"],"operationId":"get_environment_crons","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of cron jobs","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CronInfo"}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/crons/{cron_id}":{"get":{"tags":["Crons"],"operationId":"get_cron_by_id","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"cron_id","in":"path","description":"Cron Job ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Cron job details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CronInfo"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Cron job not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/crons/{cron_id}/executions":{"get":{"tags":["Crons"],"operationId":"get_cron_executions","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"cron_id","in":"path","description":"Cron Job ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"per_page","in":"query","description":"Items per page (default: 20)","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"List of cron job executions","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CronExecutionInfo"}}}}},"401":{"description":"Unauthorized"},"404":{"description":"Cron job not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/domains":{"get":{"tags":["Projects"],"summary":"Get all environment domains for a specific environment","operationId":"get_environment_domains","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of environment domains","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EnvironmentDomainResponse"}}}}},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}}},"post":{"tags":["Projects"],"summary":"Add a new environment domain","operationId":"add_environment_domain","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddEnvironmentDomainRequest"}}},"required":true},"responses":{"201":{"description":"Domain added successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentDomainResponse"}}}},"400":{"description":"Invalid input"},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/domains/{domain_id}":{"delete":{"tags":["Projects"],"summary":"Delete an environment domain","operationId":"delete_environment_domain","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain_id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Domain deleted successfully"},"404":{"description":"Project, environment, or domain not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/settings":{"put":{"tags":["Projects"],"summary":"Update environment settings","operationId":"update_environment_settings","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEnvironmentSettingsRequest"}}},"required":true},"responses":{"200":{"description":"Environment settings updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentResponse"}}}},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/sleep":{"post":{"tags":["Environments"],"summary":"Sleep an on-demand environment","description":"Manually put an on-demand environment to sleep. Stops containers and sets\n`sleeping = true`. If no OnDemandWaker is available, falls back to DB flag only.","operationId":"sleep_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Environment put to sleep","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentResponse"}}}},"400":{"description":"On-demand not enabled for this environment"},"404":{"description":"Environment not found"},"429":{"description":"Too many state transitions, retry after cooldown"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/subdomain":{"patch":{"tags":["Projects"],"summary":"Rename the auto-managed subdomain for an environment.","description":"Replaces the environment's previous subdomain entirely — the old\nhostname stops resolving once the proxy reloads its route table.\nCustom domains attached to the environment are unaffected.","operationId":"update_environment_subdomain","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEnvironmentSubdomainRequest"}}},"required":true},"responses":{"200":{"description":"Subdomain updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentResponse"}}}},"400":{"description":"Invalid subdomain or conflict with another environment"},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/teardown":{"delete":{"tags":["Projects"],"summary":"Teardown an environment and all its active deployments","operationId":"teardown_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Environment torn down successfully"},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/wake":{"post":{"tags":["Environments"],"summary":"Wake a sleeping on-demand environment","description":"Manually wake an environment that has been put to sleep by the on-demand\nidle timeout. Starts containers, waits for health checks, then sets\n`sleeping = false`. If no OnDemandWaker is available (proxy not running\nin same process), falls back to setting the DB flag only.","operationId":"wake_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Environment woken up","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentResponse"}}}},"400":{"description":"On-demand not enabled for this environment"},"404":{"description":"Environment not found"},"429":{"description":"Too many state transitions, retry after cooldown"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{environment_id}/container-logs":{"get":{"tags":["Deployments"],"summary":"Get logs for a container in an environment via WebSocket","operationId":"get_container_logs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date for logs","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"end_date","in":"query","description":"End date for logs","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"tail","in":"query","description":"Number of lines to tail (or 'all')","required":false,"schema":{"type":"string"}},{"name":"container_name","in":"query","description":"Optional container name (defaults to first/primary container)","required":false,"schema":{"type":"string"}},{"name":"timestamps","in":"query","description":"Include timestamps in log output (default: false)","required":false,"schema":{"type":"boolean"}},{"name":"follow","in":"query","description":"Follow log output in real-time (default: true)","required":false,"schema":{"type":"boolean"}}],"responses":{"101":{"description":"WebSocket connection established for streaming container logs"},"400":{"description":"Not a server-type project"},"404":{"description":"Project, deployment, or container not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/containers":{"get":{"tags":["Deployments"],"summary":"List all containers for an environment","operationId":"list_containers","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of containers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerListResponse"}}}},"400":{"description":"Not a server-type project"},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}":{"get":{"tags":["Containers"],"summary":"Get detailed information about a specific container","operationId":"get_container_detail","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Container details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerDetailResponse"}}}},"404":{"description":"Container not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/environment/{variable_name}":{"get":{"tags":["Containers"],"operationId":"get_container_environment_variable","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}},{"name":"variable_name","in":"path","description":"Environment variable name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Environment variable value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerEnvironmentVariableValueResponse"}}}},"403":{"description":"Plaintext secret access is not permitted"},"404":{"description":"Container or environment variable not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/logs":{"get":{"tags":["Deployments"],"summary":"Get logs for a specific container by container ID via WebSocket","operationId":"get_container_logs_by_id","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}},{"name":"start_date","in":"query","description":"Start date for logs","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"end_date","in":"query","description":"End date for logs","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"tail","in":"query","description":"Number of lines to tail (or 'all')","required":false,"schema":{"type":"string"}},{"name":"timestamps","in":"query","description":"Include timestamps in log output (default: false)","required":false,"schema":{"type":"boolean"}},{"name":"follow","in":"query","description":"Follow log output in real-time (default: true)","required":false,"schema":{"type":"boolean"}}],"responses":{"101":{"description":"WebSocket connection established for streaming container logs"},"400":{"description":"Not a server-type project"},"404":{"description":"Project, environment, or container not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/metrics":{"get":{"tags":["Containers"],"summary":"Get metrics/stats for a specific container","operationId":"get_container_metrics","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Container metrics retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerMetricsResponse"}}}},"404":{"description":"Container not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/metrics/history":{"get":{"tags":["Containers"],"summary":"Fetch a time-series range for a single container resource metric\n(recorded by the container health monitor every ~30s).","description":"Useful metric names: `container.cpu_percent`,\n`container.cpu_utilization_percent`, `container.memory_used_bytes`,\n`container.memory_percent`, `container.network_rx_bytes_delta`,\n`container.network_tx_bytes_delta`.","operationId":"ContainerMetricsGetHistory","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}},{"name":"metric","in":"query","description":"Dotted metric name, e.g. `container.cpu_percent` or\n`container.memory_used_bytes`.","required":true,"schema":{"type":"string"}},{"name":"range","in":"query","description":"Time window: `1h`, `6h`, `24h`, or `7d` (defaults to `1h`).","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Metric time series data points","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ContainerMetricHistoryPoint"}}}}},"401":{"description":"Unauthorized"},"404":{"description":"Container not found"},"500":{"description":"Internal server error"},"503":{"description":"Metrics store not available"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/metrics/stream":{"get":{"tags":["Containers"],"summary":"Stream container metrics via Server-Sent Events (SSE)","operationId":"stream_container_metrics","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}},{"name":"interval","in":"query","description":"Update interval in milliseconds (default: 1000)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Metrics stream established (Server-Sent Events)"},"404":{"description":"Container not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/restart":{"post":{"tags":["Containers"],"summary":"Restart a container","operationId":"restart_container","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Container restarted successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerActionResponse"}}}},"404":{"description":"Container not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/start":{"post":{"tags":["Containers"],"summary":"Start a container","operationId":"start_container","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Container started successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerActionResponse"}}}},"404":{"description":"Container not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/stop":{"post":{"tags":["Containers"],"summary":"Stop a specific container","operationId":"stop_container","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Container stopped successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerActionResponse"}}}},"404":{"description":"Container not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{environment_id}/deploy/image":{"post":{"tags":["Deployments"],"summary":"Deploy from an external Docker image","description":"Triggers a deployment using a pre-built Docker image from an external registry.\nThe image will be pulled and deployed to the specified environment.","operationId":"deploy_from_image","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeployFromImageRequest"}}},"required":true},"responses":{"202":{"description":"Deployment started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RemoteDeploymentResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/deploy/image-upload":{"post":{"tags":["Deployments"],"summary":"Deploy from an uploaded Docker image tarball","description":"Uploads a Docker image tarball (from `docker save`) and deploys it directly.\nThe image is imported using `docker load` and then deployed to the specified environment.\nThis is useful when you want to deploy an image without pushing to a registry first.\n\nThe uploaded file should be a tarball created by `docker save myimage:tag > image.tar`\nor `docker save myimage:tag | gzip > image.tar.gz` (gzip compressed tarballs are also supported).","operationId":"deploy_from_image_upload","parameters":[{"name":"tag","in":"query","description":"Tag to apply to the imported image (e.g., \"myapp:v1.0\")\nIf not provided, a unique tag will be generated","required":false,"schema":{"type":["string","null"]}},{"name":"health_check_path","in":"query","description":"Optional HTTP health-check path override (e.g. \"/api/healthz\").\nMust start with '/'. When omitted, defaults to \"/\".","required":false,"schema":{"type":["string","null"]}},{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"202":{"description":"Image imported and deployment started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RemoteDeploymentResponse"}}}},"400":{"description":"Invalid request or unsupported format"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project or environment not found"},"413":{"description":"Image tarball too large"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/deploy/source":{"post":{"tags":["Deployments"],"summary":"Upload source code and immediately start a preset-based deployment.","operationId":"deploy_from_uploaded_source","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/SourceArchiveUpload"}}},"required":true},"responses":{"202":{"description":"Source deployment started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RemoteDeploymentResponse"}}}},"400":{"description":"Invalid source archive"},"404":{"description":"Project or environment not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/deploy/static":{"post":{"tags":["Deployments"],"summary":"Deploy from an uploaded static bundle","description":"Triggers a deployment using a previously uploaded static file bundle.","operationId":"deploy_from_static","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeployFromStaticRequest"}}},"required":true},"responses":{"202":{"description":"Deployment started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RemoteDeploymentResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project, environment, or bundle not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/error-alert-rules":{"get":{"tags":["error-alert-rules"],"summary":"List all alert rules for a project","operationId":"list_alert_rules","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of alert rules","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AlertRuleResponse"}}}}},"500":{"description":"Internal server error"}}},"post":{"tags":["error-alert-rules"],"summary":"Create a new alert rule","operationId":"create_alert_rule","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAlertRuleRequest"}}},"required":true},"responses":{"201":{"description":"Alert rule created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlertRuleResponse"}}}},"400":{"description":"Validation error"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-alert-rules/{rule_id}":{"get":{"tags":["error-alert-rules"],"summary":"Get a specific alert rule","operationId":"get_alert_rule","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"rule_id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Alert rule details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlertRuleResponse"}}}},"404":{"description":"Alert rule not found"},"500":{"description":"Internal server error"}}},"put":{"tags":["error-alert-rules"],"summary":"Update an existing alert rule","operationId":"update_alert_rule","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"rule_id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAlertRuleRequest"}}},"required":true},"responses":{"200":{"description":"Alert rule updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlertRuleResponse"}}}},"400":{"description":"Validation error"},"404":{"description":"Alert rule not found"},"500":{"description":"Internal server error"}}},"delete":{"tags":["error-alert-rules"],"summary":"Delete an alert rule","operationId":"delete_alert_rule","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"rule_id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Alert rule deleted"},"404":{"description":"Alert rule not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-dashboard-stats":{"get":{"tags":["error-tracking"],"summary":"Get error dashboard statistics","operationId":"get_error_dashboard_stats","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_time","in":"query","required":true,"schema":{"type":"string","format":"date-time"}},{"name":"end_time","in":"query","required":true,"schema":{"type":"string","format":"date-time"}},{"name":"environment_id","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"compare_to_previous","in":"query","required":false,"schema":{"type":["boolean","null"]}}],"responses":{"200":{"description":"Error dashboard statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDashboardStatsResponse"}}}},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-groups":{"get":{"tags":["error-tracking"],"summary":"List error groups for a project","operationId":"list_error_groups","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"status","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"environment_id","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"start_date","in":"query","required":false,"schema":{"type":["string","null"],"format":"date-time"}},{"name":"end_date","in":"query","required":false,"schema":{"type":["string","null"],"format":"date-time"}},{"name":"sort_by","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Paginated list of error groups","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedErrorGroupsResponse"}}}},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-groups/{group_id}":{"get":{"tags":["error-tracking"],"summary":"Get a specific error group","operationId":"get_error_group","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"group_id","in":"path","description":"Error group ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Error group details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorGroupResponse"}}}},"404":{"description":"Error group not found"},"500":{"description":"Internal server error"}}},"put":{"tags":["error-tracking"],"summary":"Update error group status","operationId":"update_error_group","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"group_id","in":"path","description":"Error group ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateErrorGroupRequest"}}},"required":true},"responses":{"200":{"description":"Error group updated successfully"},"404":{"description":"Error group not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-groups/{group_id}/events":{"get":{"tags":["error-tracking"],"summary":"List error events for a specific group","operationId":"list_error_events","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"group_id","in":"path","description":"Error group ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Paginated list of error events","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedErrorEventsResponse"}}}},"404":{"description":"Error group not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-groups/{group_id}/events/{event_id}":{"get":{"tags":["error-tracking"],"summary":"Get a specific error event","operationId":"get_error_event","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"group_id","in":"path","description":"Error group ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"event_id","in":"path","description":"Error event ID","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Error event details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEventResponse"}}}},"404":{"description":"Event not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-stats":{"get":{"tags":["error-tracking"],"summary":"Get error statistics for a project","operationId":"get_error_stats","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Error statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorGroupStatsResponse"}}}},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-time-series":{"get":{"tags":["error-tracking"],"summary":"Get error time series data for charts","operationId":"get_error_time_series","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_time","in":"query","required":true,"schema":{"type":"string","format":"date-time"}},{"name":"end_time","in":"query","required":true,"schema":{"type":"string","format":"date-time"}},{"name":"bucket","in":"query","description":"Time bucket size (e.g., \"1h\", \"15m\", \"1d\", \"1 hour\", \"30 minutes\")","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Error time series data","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ErrorTimeSeriesDataResponse"}}}}},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/events":{"get":{"tags":["Events"],"summary":"Get event counts with filtering","operationId":"get_events_count","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date for filtering events","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date for filtering events","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"limit","in":"query","description":"Maximum number of events to return (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"custom_events_only","in":"query","description":"Only return custom events, excluding system events like page_view, page_leave, heartbeat (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"aggregation_level","in":"query","description":"Aggregation level: events, sessions, or visitors (default: events)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved event counts","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EventCount"}}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/events/breakdown":{"get":{"tags":["Events"],"summary":"Get event type breakdown","operationId":"get_event_type_breakdown","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date for filtering events","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date for filtering events","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"aggregation_level","in":"query","description":"Aggregation level: events, sessions, or visitors (default: events)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved event type breakdown","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EventTypeBreakdown"}}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/events/ingest":{"post":{"tags":["Events"],"summary":"Record an analytics event via the console API with explicit project ID.","description":"The app backend forwards the user's encrypted Temps cookies, so visitor/session\nidentity is resolved automatically by middleware. No geolocation or user-agent\nenrichment is performed — this is a lightweight server-side ingestion path.","operationId":"record_console_event","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConsoleEventPayload"}}},"required":true},"responses":{"200":{"description":"Event recorded successfully"},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/events/properties/breakdown":{"get":{"tags":["Events"],"summary":"Get property breakdown by grouping events by a column","operationId":"get_property_breakdown","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in '%Y-%m-%d %H:%M:%S' format","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in '%Y-%m-%d %H:%M:%S' format","required":true,"schema":{"type":"string"}},{"name":"group_by","in":"query","description":"Column to group by (channel, device_type, browser, etc.)","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"event_name","in":"query","description":"Filter by event name","required":false,"schema":{"type":"string"}},{"name":"aggregation_level","in":"query","description":"Aggregation level: events, sessions, or visitors - default: events","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Maximum number of results (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"include_crawlers","in":"query","description":"Include crawler/bot traffic (default: false)","required":false,"schema":{"type":"boolean"}},{"name":"filter_country","in":"query","description":"Filter by country (for region/city drill-downs)","required":false,"schema":{"type":"string"}},{"name":"filter_region","in":"query","description":"Filter by region (for city drill-downs)","required":false,"schema":{"type":"string"}},{"name":"filter_browser","in":"query","description":"Filter by browser name (for version drill-downs)","required":false,"schema":{"type":"string"}},{"name":"filter_os","in":"query","description":"Filter by OS name (for version drill-downs)","required":false,"schema":{"type":"string"}},{"name":"filter_channel","in":"query","description":"Filter by channel name (for channel drill-downs)","required":false,"schema":{"type":"string"}},{"name":"filter_referrer","in":"query","description":"Filter by referrer hostname (for referrer drill-downs)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved property breakdown","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PropertyBreakdownResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/events/properties/timeline":{"get":{"tags":["Events"],"summary":"Get property timeline by grouping events by a column over time","operationId":"get_property_timeline","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in '%Y-%m-%d %H:%M:%S' format","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in '%Y-%m-%d %H:%M:%S' format","required":true,"schema":{"type":"string"}},{"name":"group_by","in":"query","description":"Column to group by (channel, device_type, browser, etc.)","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"event_name","in":"query","description":"Filter by event name","required":false,"schema":{"type":"string"}},{"name":"aggregation_level","in":"query","description":"Aggregation level: events, sessions, or visitors - default: events","required":false,"schema":{"type":"string"}},{"name":"bucket_size","in":"query","description":"Time bucket: hour, day, week, month (default: auto-detect)","required":false,"schema":{"type":"string"}},{"name":"include_crawlers","in":"query","description":"Include crawler/bot traffic (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Successfully retrieved property timeline","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PropertyTimelineResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/events/timeline":{"get":{"tags":["Events"],"summary":"Get events timeline","operationId":"get_events_timeline","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date for filtering events","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date for filtering events","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"event_name","in":"query","description":"Filter by specific event name","required":false,"schema":{"type":"string"}},{"name":"bucket_size","in":"query","description":"Bucket size: hour, day, or week (auto-detected if not specified)","required":false,"schema":{"type":"string"}},{"name":"aggregation_level","in":"query","description":"Aggregation level: events, sessions, or visitors (default: events)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved events timeline","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EventTimeline"}}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/events/unique":{"get":{"tags":["Funnels"],"summary":"Get all unique/distinct event types for a project (paginated)","operationId":"get_unique_events","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page (default: 50, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Unique event types retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventTypesResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/external-images":{"get":{"tags":["External Images"],"summary":"List external images for a project","operationId":"list_remote_external_images","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page (default: 20)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List of external images","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedExternalImagesResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["External Images"],"summary":"Register an external Docker image","description":"Registers an external Docker image reference without triggering a deployment.\nThe image can be deployed later using the deploy/image endpoint.","operationId":"register_external_image","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterImageRequest"}}},"required":true},"responses":{"201":{"description":"Image registered successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalImageResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/external-images/{image_id}":{"get":{"tags":["External Images"],"summary":"Get details of a specific external image","operationId":"get_remote_external_image","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"image_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Image details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalImageResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Image not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["External Images"],"summary":"Delete an external image","operationId":"delete_external_image","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"image_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Image deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Image not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/flags":{"get":{"tags":["Feature Flags"],"operationId":"list_flags","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"include_archived","in":"query","description":"Include archived flags. Defaults to false.","required":false,"schema":{"type":"boolean"}},{"name":"page","in":"query","description":"1-indexed page number. Defaults to 1.","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page. Defaults to 20, capped at 100.","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}}],"responses":{"200":{"description":"Flags listed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Feature Flags"],"operationId":"create_flag","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFlagRequest"}}},"required":true},"responses":{"201":{"description":"Flag created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"409":{"description":"Flag key already exists"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/flags/{key}":{"get":{"tags":["Feature Flags"],"operationId":"get_flag","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"key","in":"path","description":"Flag key","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Flag retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Flag not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Feature Flags"],"operationId":"archive_flag","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"key","in":"path","description":"Flag key","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Flag archived","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArchiveFlagResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Flag not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Feature Flags"],"operationId":"update_flag","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"key","in":"path","description":"Flag key","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateFlagRequest"}}},"required":true},"responses":{"200":{"description":"Flag updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Flag not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/flags/{key}/environments/{environment_id}":{"put":{"tags":["Feature Flags"],"summary":"Set a flag's value in one environment, and/or flip its kill switch.","operationId":"set_flag_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"key","in":"path","description":"Flag key","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetFlagEnvironmentRequest"}}},"required":true},"responses":{"200":{"description":"Environment value set","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagEnvironmentResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Flag or environment not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/flags/{key}/restore":{"post":{"tags":["Feature Flags"],"summary":"Bring an archived flag back.","description":"Archiving is otherwise one-way: the key stays reserved so the flag cannot\neven be re-created under the same name, which makes an accidental archive\nunrecoverable through the API.","operationId":"restore_flag","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"key","in":"path","description":"Flag key","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Flag restored","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Flag not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/funnels":{"get":{"tags":["Funnels"],"summary":"List all funnels for a project","operationId":"list_funnels","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Funnels retrieved successfully","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/FunnelResponse"}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Funnels"],"summary":"Create a new funnel","operationId":"create_funnel","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFunnelRequest"}}},"required":true},"responses":{"201":{"description":"Funnel created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFunnelResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/funnels/preview":{"post":{"tags":["Funnels"],"summary":"Preview funnel metrics without creating the funnel","operationId":"preview_funnel_metrics","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFunnelRequest"}}},"required":true},"responses":{"200":{"description":"Funnel metrics preview","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FunnelMetricsResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/funnels/{funnel_id}":{"put":{"tags":["Funnels"],"summary":"Update a funnel","operationId":"update_funnel","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"funnel_id","in":"path","description":"Funnel ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFunnelRequest"}}},"required":true},"responses":{"200":{"description":"Funnel updated successfully"},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"404":{"description":"Funnel not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Funnels"],"summary":"Delete a funnel","operationId":"delete_funnel","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"funnel_id","in":"path","description":"Funnel ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Funnel deleted successfully"},"401":{"description":"Unauthorized"},"404":{"description":"Funnel not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/funnels/{funnel_id}/metrics":{"get":{"tags":["Funnels"],"summary":"Get funnel metrics","operationId":"get_funnel_metrics","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"funnel_id","in":"path","description":"Funnel ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID filter","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"country_code","in":"query","description":"Country code filter","required":false,"schema":{"type":"string"}},{"name":"start_date","in":"query","description":"Start date filter (ISO 8601)","required":false,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date filter (ISO 8601)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Funnel metrics retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FunnelMetricsResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"404":{"description":"Funnel not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/git":{"post":{"tags":["Projects"],"summary":"Update git settings for a project","operationId":"update_git_settings","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateGitSettingsRequest"}}},"required":true},"responses":{"200":{"description":"Git settings updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"400":{"description":"Invalid git configuration or branch does not exist"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/gitlab/reinstall-webhook":{"post":{"tags":["Projects"],"summary":"Reinstall the GitLab webhook for a project","description":"Removes the existing webhook (if any) and installs a fresh one.\nUse this when a webhook has been manually deleted on the GitLab side\nand automatic deployments have stopped working.","operationId":"reinstall_gitlab_webhook","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Webhook reinstalled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReinstallWebhookResponse"}}}},"400":{"description":"Project is not connected to a GitLab repository"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/has-error-groups":{"get":{"tags":["error-tracking"],"summary":"Check if project has any error groups","operationId":"has_error_groups","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Error groups existence check","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HasErrorGroupsResponse"}}}},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/has-events":{"get":{"tags":["Events"],"summary":"Check if project has any analytics events","operationId":"has_analytics_events","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully checked for events","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HasEventsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/hourly-visits":{"get":{"tags":["Events"],"summary":"Get hourly visits","operationId":"get_hourly_visits","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date for filtering visits","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date for filtering visits","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"aggregation_level","in":"query","description":"Aggregation level: events (page views), sessions (unique sessions), or visitors (unique visitors) - default: events","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved hourly visits","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EventTimeline"}}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/images":{"get":{"tags":["External Images"],"summary":"List all external images for a project","operationId":"list_external_images","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of external images","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PushedExternalImageResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/images/push":{"post":{"tags":["External Images"],"summary":"Push an external Docker image","operationId":"push_external_image","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PushImageRequest"}}},"required":true},"responses":{"201":{"description":"Image pushed successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PushedExternalImageResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/images/{image_id}":{"get":{"tags":["External Images"],"summary":"Get details of a specific external image","operationId":"get_external_image","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"image_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Image details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PushedExternalImageResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Image not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/incidents":{"get":{"tags":["Status Page"],"summary":"List incidents for a project","operationId":"list_incidents","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"status","in":"query","description":"Filter by status","required":false,"schema":{"type":"string"}},{"name":"page","in":"query","description":"Page number","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Successfully retrieved incidents"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Status Page"],"summary":"Create a new incident","operationId":"create_incident","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateIncidentRequest"}}},"required":true},"responses":{"201":{"description":"Incident created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncidentResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/incidents/bucketed":{"get":{"tags":["Status Page"],"summary":"Get bucketed incident data for a project","operationId":"get_bucketed_incidents","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"interval","in":"query","description":"Bucket interval: '5min', 'hourly', or 'daily' (default: hourly)","required":false,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601) (default: 7 days ago)","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (ISO 8601) (default: now)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved bucketed incident data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncidentBucketedResponse"}}}},"400":{"description":"Invalid parameters"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/logs":{"delete":{"tags":["Logs"],"summary":"Purge all logs for a project before a given timestamp","operationId":"purge_project_logs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PurgeLogsRequest"}}},"required":true},"responses":{"200":{"description":"Purge completed"},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/mcp-servers":{"get":{"tags":["Agents"],"operationId":"list_mcps","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListMcpsResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Agents"],"operationId":"create_mcp","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMcpRequest"}}},"required":true},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpDefinitionResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/mcp-servers/{slug}":{"get":{"tags":["Agents"],"operationId":"get_mcp","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"MCP server not found"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Agents"],"operationId":"update_mcp","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMcpRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"MCP server not found"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Agents"],"operationId":"delete_mcp","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"MCP server deleted"},"401":{"description":"Unauthorized"},"404":{"description":"MCP server not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/mcp-servers/{slug}/config/{field}":{"get":{"tags":["Agents"],"operationId":"reveal_mcp_config","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}},{"name":"field","in":"path","description":"Sensitive field path, such as url or env.API_TOKEN","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SensitiveMcpConfigValueResponse"}}}},"400":{"description":"Field is not revealable"},"401":{"description":"Unauthorized"},"403":{"description":"Missing secrets:read permission"},"404":{"description":"MCP server or field not found"},"500":{"description":"Configuration read or audit failed"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/monitors":{"get":{"tags":["Status Page"],"summary":"List monitors for a project","operationId":"list_monitors","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved monitors","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MonitorResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Status Page"],"summary":"Create a new monitor","operationId":"create_monitor","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMonitorRequest"}}},"required":true},"responses":{"201":{"description":"Monitor created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MonitorResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/observe/events":{"get":{"tags":["Observability"],"summary":"List a merged page of observability events for a project.","description":"Each row carries everything the side panel needs to render — no\nfollow-up fetch is required for the common case. Heavy fields\n(stacktraces, headers, span attributes) are truncated server-side and\nexpose a `*_truncated` flag; clients fetch the full row from the\n`/full` endpoint only when the user explicitly clicks \"Show full\".","operationId":"observability_list_events","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"kinds","in":"query","description":"Comma-separated kinds: `log,request,span,error,revenue`. Empty or\nmissing returns every kind.","required":false,"schema":{"type":"string"}},{"name":"from","in":"query","description":"Inclusive lower bound on event timestamp (ISO 8601, `Z` suffix).","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","description":"Inclusive upper bound on event timestamp.","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"deployment_id","in":"query","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"search","in":"query","description":"Free-text substring matched against per-kind summary fields\n(request path / error class / revenue event_type).","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Page size (default 50, max 200).","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"hide_bots","in":"query","description":"When `true`, exclude bot/crawler request rows. When `false`, only\ninclude bot rows. Omitted means \"include everything\" (default).\nOnly affects the `Request` kind.","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Merged event page","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventsResponse"}}}},"400":{"description":"Invalid filter (kinds, time range, …)","content":{"text/plain":{"schema":{"type":"string"}}}},"401":{"description":"Unauthorized","content":{"text/plain":{"schema":{"type":"string"}}}},"403":{"description":"Insufficient permissions","content":{"text/plain":{"schema":{"type":"string"}}}},"500":{"description":"Internal server error","content":{"text/plain":{"schema":{"type":"string"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/observe/events/{kind}/{event_id}/full":{"get":{"tags":["Observability"],"summary":"Fetch the un-truncated form of one event by `(kind, id)`. Side panel\n\"Show full\" action calls this — the list response carries truncated\npreviews + a `*_truncated` flag to let the UI decide whether to fetch.","operationId":"observability_full_event","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"kind","in":"path","description":"Event kind discriminator","required":true,"schema":{"$ref":"#/components/schemas/EventKind"}},{"name":"event_id","in":"path","description":"Per-kind identity: request_id for requests, `{trace_id}:{span_id}` for spans, serial id for errors/revenue","required":true,"schema":{"type":"string"}},{"name":"ts","in":"query","description":"The row's event timestamp as returned by the list endpoint. Optional,\nbut strongly recommended: it bounds the lookup to the storage\npartitions/chunks around that instant instead of scanning the whole\nretention window.","required":false,"schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"Full row","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FullEvent"}}}},"401":{"description":"Unauthorized","content":{"text/plain":{"schema":{"type":"string"}}}},"403":{"description":"Insufficient permissions","content":{"text/plain":{"schema":{"type":"string"}}}},"404":{"description":"Event not found in project","content":{"text/plain":{"schema":{"type":"string"}}}},"500":{"description":"Internal server error","content":{"text/plain":{"schema":{"type":"string"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/releases/{release}/source-files":{"get":{"tags":["source-maps"],"summary":"List uploaded source files for a release (metadata only).","operationId":"list_source_files","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"release","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of source files","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceFileListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["source-maps"],"summary":"Upload a raw source file for a release (native symbolication).","description":"Accepts a multipart form with:\n- `file`: the source file bytes (required)\n- `file_path`: the path of the file as it appears in stack frames (required;\n derived from the uploaded filename if omitted). Normalized with the `~`\n prefix convention, matching source-map storage.\n\nRequires the project's `error_source_context_enabled` toggle to be on.\nUpserts on (project, release, file_path).","operationId":"upload_source_file","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"release","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"201":{"description":"Source file uploaded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceFileResponse"}}}},"400":{"description":"Missing fields"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"409":{"description":"Source context disabled for project"},"413":{"description":"Source file too large"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["source-maps"],"summary":"Delete all uploaded source files for a release.","operationId":"delete_release_source_files","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"release","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Source files deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/releases/{release}/source-maps":{"get":{"tags":["source-maps"],"summary":"List all source maps for a specific release","operationId":"list_source_maps","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"release","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of source maps","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceMapListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["source-maps"],"summary":"Upload a source map for a release.","description":"Accepts a multipart form with:\n- `file`: The .map file (required)\n- `file_path`: The URL path of the minified file as it appears in stack traces (required).\n Uses the ~ prefix convention (e.g., \"~/assets/main.js\").\n If a full URL is provided, it will be normalized automatically.\n- `dist`: Optional distribution identifier\n\nIf a source map already exists for the same (project, release, file_path), it is replaced.","operationId":"upload_source_map","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"release","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"201":{"description":"Source map uploaded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceMapResponse"}}}},"400":{"description":"Invalid source map or missing fields"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"413":{"description":"Source map too large"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["source-maps"],"summary":"Delete all source maps for a specific release","operationId":"delete_release_source_maps","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"release","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Source maps deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/events":{"get":{"tags":["Revenue"],"summary":"Recent ingested events for the activity feed.","operationId":"revenue_recent_events","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RecentEventResponse"}}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/integrations":{"get":{"tags":["Revenue"],"summary":"List revenue integrations for a project.","operationId":"revenue_list_integrations","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/IntegrationResponse"}}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Revenue"],"summary":"Create a new revenue integration. Response contains the generated\nwebhook path that the user must paste into their provider's dashboard.","operationId":"revenue_create_integration","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateIntegrationBody"}}},"required":true},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntegrationResponse"}}}},"400":{"description":"Validation error"},"409":{"description":"Already connected"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/integrations/{integration_id}":{"delete":{"tags":["Revenue"],"summary":"Delete a revenue integration (permanent — use rotate_token to refresh\ncredentials without breaking history).","operationId":"revenue_delete_integration","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"integration_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/integrations/{integration_id}/config":{"post":{"tags":["Revenue"],"summary":"Replace the typed provider config on an integration. Passing `null`\nclears the config back to the accept-everything default. The config's\nprovider tag must match the integration's provider.","operationId":"revenue_update_config","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"integration_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateConfigBody"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntegrationResponse"}}}},"400":{"description":"Validation error"},"404":{"description":"Integration not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/integrations/{integration_id}/import/invoices":{"post":{"tags":["Revenue"],"summary":"Import a Stripe invoices CSV export. Each paid invoice becomes an\n`invoice.paid` event so historical MRR/charge totals populate the\ntimeseries. Ingestion is idempotent: re-uploading the same file is a\nno-op.","operationId":"revenue_import_invoices_csv","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"integration_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportOutcomeResponse"}}}},"400":{"description":"Malformed CSV or wrong provider"},"404":{"description":"Integration not found"},"413":{"description":"CSV too large"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/integrations/{integration_id}/import/subscriptions":{"post":{"tags":["Revenue"],"summary":"Import a Stripe subscriptions CSV export. Use this to backfill MRR /\nactive subscriptions when migrating from Stripe without providing\nAPI keys. Webhooks remain the source of truth for live updates —\nCSV rows never overwrite newer webhook state.","operationId":"revenue_import_subscriptions_csv","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"integration_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportOutcomeResponse"}}}},"400":{"description":"Malformed CSV or wrong provider"},"404":{"description":"Integration not found"},"413":{"description":"CSV too large"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/integrations/{integration_id}/rotate-token":{"post":{"tags":["Revenue"],"summary":"Rotate the webhook path token. Returns the new integration state —\nthe user must paste the new URL into their provider's dashboard.","operationId":"revenue_rotate_token","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"integration_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntegrationResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/integrations/{integration_id}/update-secret":{"post":{"tags":["Revenue"],"summary":"Replace the stored signing secret without rotating the webhook URL.\nUse this after rotating the secret in the provider's dashboard.","operationId":"revenue_update_secret","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"integration_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSecretBody"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntegrationResponse"}}}},"400":{"description":"Validation error"},"404":{"description":"Integration not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/metrics/customers":{"get":{"tags":["Revenue"],"summary":"New + churned customers per bucket.","operationId":"revenue_metrics_customers","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CustomerMovementResponse"}}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/metrics/mrr":{"get":{"tags":["Revenue"],"summary":"Bucketed MRR timeseries for the revenue chart.","operationId":"revenue_metrics_mrr","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MrrBucketResponse"}}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/metrics/summary":{"get":{"tags":["Revenue"],"summary":"Current MRR / ARR / churn / ARPU for a project, in one currency.","operationId":"revenue_metrics_summary","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MetricsSummaryResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/secrets":{"get":{"tags":["Secrets"],"summary":"List project secrets (metadata only — values never returned).","operationId":"listProjectSecrets","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Optional environment filter","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of secrets (metadata only, no values)","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProjectSecretResponse"}}}}},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}},"post":{"tags":["Secrets"],"summary":"Create a new secret. The value is encrypted before storage and will be\nmounted as a file at `/run/secrets/` on the next deployment.\nThe plaintext value is NOT returned — the response carries only metadata.","operationId":"createProjectSecret","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectSecretRequest"}}},"required":true},"responses":{"201":{"description":"Secret created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectSecretResponse"}}}},"400":{"description":"Invalid key or value too large"},"409":{"description":"Key already exists in project"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/secrets/{secret_id}":{"put":{"tags":["Secrets"],"summary":"Update a project secret. Value rotation requires a redeploy to take effect —\nrunning containers keep their currently-mounted values until the next\ndeployment.","operationId":"updateProjectSecret","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"secret_id","in":"path","description":"Secret ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProjectSecretRequest"}}},"required":true},"responses":{"200":{"description":"Secret updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectSecretResponse"}}}},"400":{"description":"Value too large"},"404":{"description":"Secret not found"},"500":{"description":"Internal server error"}}},"delete":{"tags":["Secrets"],"summary":"Delete a project secret. Running containers keep their mounted secret files\nuntil they are redeployed.","operationId":"deleteProjectSecret","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"secret_id","in":"path","description":"Secret ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Secret deleted"},"404":{"description":"Secret not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/settings":{"post":{"tags":["Projects"],"summary":"Update project settings","operationId":"update_project_settings","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProjectSettingsRequest"}}},"required":true},"responses":{"200":{"description":"Project settings updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/skills":{"get":{"tags":["Agents"],"operationId":"list_skills","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListSkillsResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Agents"],"operationId":"create_skill","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSkillRequest"}}},"required":true},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/skills/upload":{"post":{"tags":["Agents"],"summary":"Upload a skill with an archive (tar.gz) — project-scoped.","operationId":"upload_skill","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"type":"string"}}},"required":true},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/skills/{slug}":{"get":{"tags":["Agents"],"operationId":"get_skill","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Agents"],"operationId":"update_skill","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSkillRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Agents"],"operationId":"delete_skill","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Skill deleted"},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/skills/{slug}/archive":{"get":{"tags":["Agents"],"summary":"Download a skill's archive (tar.gz) — project-scoped.","operationId":"download_skill_archive","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Skill archive tar.gz","content":{"application/gzip":{}}},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found or has no archive"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/source-map-releases":{"get":{"tags":["source-maps"],"summary":"List all releases that have source maps for a project","operationId":"list_releases","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of releases","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReleaseListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/source-maps/{source_map_id}":{"delete":{"tags":["source-maps"],"summary":"Delete a specific source map by ID","operationId":"delete_source_map","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"source_map_id","in":"path","description":"Source map ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Source map deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Source map not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/static-bundles":{"get":{"tags":["Static Bundles"],"summary":"List static bundles for a project","operationId":"list_static_bundles","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page (default: 20)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List of static bundles","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedStaticBundlesResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/static-bundles/{bundle_id}":{"get":{"tags":["Static Bundles"],"summary":"Get details of a specific static bundle","operationId":"get_static_bundle","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"bundle_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Bundle details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StaticBundleResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Bundle not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Static Bundles"],"summary":"Delete a static bundle","operationId":"delete_static_bundle","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"bundle_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Bundle deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Bundle not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/status":{"get":{"tags":["Status Page"],"summary":"Get status page overview","operationId":"get_status_overview","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved status overview","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatusPageOverview"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/unique-counts":{"get":{"tags":["Events"],"summary":"Get unique counts over time frame","operationId":"get_unique_counts","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in '%Y-%m-%d %H:%M:%S' format","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in '%Y-%m-%d %H:%M:%S' format","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"metric","in":"query","description":"Metric to count: 'sessions' (unique sessions), 'visitors' (unique visitors), 'returning_visitors' (visitors seen before the range), or 'page_views' (total page views) (default: 'sessions')","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved count","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UniqueCountsResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/upload/static":{"post":{"tags":["Static Bundles"],"summary":"Upload a static bundle for later deployment","description":"Uploads a tar.gz or zip file containing static assets. The bundle can be\ndeployed later using the deploy/static endpoint.","operationId":"upload_static_bundle","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/SourceArchiveUpload"}}},"required":true},"responses":{"201":{"description":"Bundle uploaded successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StaticBundleResponse"}}}},"400":{"description":"Invalid request or unsupported format"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project not found"},"413":{"description":"Bundle too large"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/vulnerability-scans":{"get":{"tags":["Vulnerability Scans"],"operationId":"list_project_scans","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List of vulnerability scans","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ScanResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Vulnerability Scans"],"operationId":"trigger_scan","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerScanRequest"}}},"required":true},"responses":{"202":{"description":"Scan triggered successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerScanResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/vulnerability-scans/environments":{"get":{"tags":["Vulnerability Scans"],"operationId":"get_latest_scans_per_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Latest scans per environment for current deployments","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ScanResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/vulnerability-scans/latest":{"get":{"tags":["Vulnerability Scans"],"operationId":"get_latest_scan","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Latest scan for project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScanResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"No scans found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/webhooks":{"get":{"tags":["Webhooks"],"summary":"List all webhooks for a project","operationId":"list_webhooks","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20},{"name":"sort_by","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"List of webhooks","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/WebhookResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Webhooks"],"summary":"Create a new webhook","operationId":"create_webhook","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWebhookRequestBody"}}},"required":true},"responses":{"201":{"description":"Webhook created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/webhooks/{webhook_id}":{"get":{"tags":["Webhooks"],"summary":"Get a specific webhook","operationId":"get_webhook","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"webhook_id","in":"path","description":"Webhook ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Webhook details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Webhook not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Webhooks"],"summary":"Update a webhook","operationId":"update_webhook","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"webhook_id","in":"path","description":"Webhook ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWebhookRequestBody"}}},"required":true},"responses":{"200":{"description":"Webhook updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Webhook not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Webhooks"],"summary":"Delete a webhook","operationId":"delete_webhook","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"webhook_id","in":"path","description":"Webhook ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Webhook deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Webhook not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/webhooks/{webhook_id}/deliveries":{"get":{"tags":["Webhook Deliveries"],"summary":"List webhook deliveries","operationId":"list_deliveries","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"webhook_id","in":"path","description":"Webhook ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"limit","in":"query","description":"Number of deliveries to return (default: 50)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List of deliveries","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/WebhookDeliveryResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/webhooks/{webhook_id}/deliveries/{delivery_id}":{"get":{"tags":["Webhook Deliveries"],"summary":"Get a specific webhook delivery by ID","operationId":"get_delivery","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"webhook_id","in":"path","description":"Webhook ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"delivery_id","in":"path","description":"Delivery ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Delivery details including full payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDeliveryResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Delivery not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/webhooks/{webhook_id}/deliveries/{delivery_id}/retry":{"post":{"tags":["Webhook Deliveries"],"summary":"Retry a failed delivery","operationId":"retry_delivery","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"webhook_id","in":"path","description":"Webhook ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"delivery_id","in":"path","description":"Delivery ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Delivery retried","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDeliveryResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Delivery not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/workflows/dry-run":{"post":{"tags":["Workflows"],"operationId":"workflow_dry_run","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkflowDryRunRequest"}}},"required":true},"responses":{"202":{"description":"Ephemeral run created and queued","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRunResponse"}}}},"400":{"description":"Validation error (bad YAML, oversized payload, capped limits exceeded)"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/proxy-logs":{"get":{"tags":["Proxy Logs"],"summary":"Get proxy logs with optional filters and pagination","operationId":"get_proxy_logs","parameters":[{"name":"project_id","in":"query","description":"Filter by project ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"session_id","in":"query","description":"Filter by session ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"visitor_id","in":"query","description":"Filter by visitor ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"start_date","in":"query","description":"Start date for filtering (ISO 8601 format).\n\n**Defaults to 1 hour before `end_date` (or before now) when omitted.**\nThe listing is always time-bounded: an unbounded query would have to\nconsider the entire retention window — 100M+ rows on a busy deployment —\nto return a single page. Pass an explicit `start_date` to widen the\nwindow, up to the configured retention horizon.\n\nThe maximum span between `start_date` and `end_date` is 7 days when\n`project_id` is omitted, or 30 days when a single `project_id` is set —\na project-scoped query is bounded by that project's own row count\nrather than the whole deployment's. A wider request is rejected with a\n400 naming the applicable cap.","required":false,"schema":{"type":["string","null"],"format":"date-time"}},{"name":"end_date","in":"query","description":"End date for filtering (ISO 8601 format). Defaults to now.","required":false,"schema":{"type":["string","null"],"format":"date-time"}},{"name":"method","in":"query","description":"Filter by HTTP method (GET, POST, etc.)","required":false,"schema":{"type":["string","null"]}},{"name":"host","in":"query","description":"Filter by host header","required":false,"schema":{"type":["string","null"]}},{"name":"path","in":"query","description":"Filter by path (supports partial match)","required":false,"schema":{"type":["string","null"]}},{"name":"client_ip","in":"query","description":"Filter by client IP address","required":false,"schema":{"type":["string","null"]}},{"name":"status_code","in":"query","description":"Filter by HTTP status code","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"response_time_min","in":"query","description":"Filter by minimum response time in ms","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"response_time_max","in":"query","description":"Filter by maximum response time in ms","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"routing_status","in":"query","description":"Filter by routing status (routed, no_project, error, pending)","required":false,"schema":{"type":["string","null"]}},{"name":"request_source","in":"query","description":"Filter by request source (proxy, api, console, cli)","required":false,"schema":{"type":["string","null"]}},{"name":"is_system_request","in":"query","description":"Filter by system request flag","required":false,"schema":{"type":["boolean","null"]}},{"name":"user_agent","in":"query","description":"Filter by user agent string (partial match)","required":false,"schema":{"type":["string","null"]}},{"name":"browser","in":"query","description":"Filter by browser name","required":false,"schema":{"type":["string","null"]}},{"name":"operating_system","in":"query","description":"Filter by operating system","required":false,"schema":{"type":["string","null"]}},{"name":"device_type","in":"query","description":"Filter by device type (mobile, desktop, tablet)","required":false,"schema":{"type":["string","null"]}},{"name":"is_bot","in":"query","description":"Filter by bot detection","required":false,"schema":{"type":["boolean","null"]}},{"name":"exclude_bots","in":"query","description":"When `true`, exclude rows flagged as bots while KEEPING rows whose\n`is_bot` is NULL (older rows without detection metadata). This is the\ntri-state complement of `is_bot=false`, which matches only rows\nexplicitly detected as non-bots. `false`/omitted is a no-op.","required":false,"schema":{"type":["boolean","null"]}},{"name":"bot_name","in":"query","description":"Filter by bot name","required":false,"schema":{"type":["string","null"]}},{"name":"ai_provider","in":"query","description":"Filter by AI provider (e.g. `OpenAI`, `Anthropic`, `Perplexity`). Matches\nthe canonical provider returned by the AI agent detector.","required":false,"schema":{"type":["string","null"]}},{"name":"ai_agent","in":"query","description":"Filter by AI agent name (e.g. `GPTBot`, `ChatGPT-User`). Equivalent to\nfiltering `bot_name` against a known AI taxonomy.","required":false,"schema":{"type":["string","null"]}},{"name":"is_ai_agent","in":"query","description":"When `true`, only return requests classified as known AI agents\n(regardless of provider/agent). Mutually compatible with the above.","required":false,"schema":{"type":["boolean","null"]}},{"name":"request_size_min","in":"query","description":"Filter by minimum request size in bytes","required":false,"schema":{"type":["integer","null"],"format":"int64"}},{"name":"request_size_max","in":"query","description":"Filter by maximum request size in bytes","required":false,"schema":{"type":["integer","null"],"format":"int64"}},{"name":"response_size_min","in":"query","description":"Filter by minimum response size in bytes","required":false,"schema":{"type":["integer","null"],"format":"int64"}},{"name":"response_size_max","in":"query","description":"Filter by maximum response size in bytes","required":false,"schema":{"type":["integer","null"],"format":"int64"}},{"name":"cache_status","in":"query","description":"Filter by cache status","required":false,"schema":{"type":["string","null"]}},{"name":"container_id","in":"query","description":"Filter by container ID","required":false,"schema":{"type":["string","null"]}},{"name":"upstream_host","in":"query","description":"Filter by upstream host","required":false,"schema":{"type":["string","null"]}},{"name":"has_error","in":"query","description":"Filter by presence of error message","required":false,"schema":{"type":["boolean","null"]}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (default: 20, max: 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"sort_by","in":"query","description":"Sort by field (default: timestamp)","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","description":"Sort order (asc or desc, default: desc)","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"List of proxy logs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProxyLogsPaginatedResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/ai-agents/known":{"get":{"tags":["Proxy Logs"],"summary":"List every AI agent the detector knows how to classify.","description":"Returned in the same order as the internal taxonomy so the UI can use it as\na stable dropdown.","operationId":"list_known_ai_agents","responses":{"200":{"description":"Known AI agents","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KnownAiAgentsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/request/{request_id}":{"get":{"tags":["Proxy Logs"],"summary":"Get a proxy log by request ID (for tracing)","operationId":"get_proxy_log_by_request_id","parameters":[{"name":"request_id","in":"path","description":"Request ID from pingora","required":true,"schema":{"type":"string"}},{"name":"timestamp","in":"query","description":"Event time of the log row (ISO 8601). When provided, the lookup is\nbounded to the hypertable chunks around this instant instead of\nscanning (and decompressing) the whole retention window. The list\nendpoint already returns this value per row — always pass it when\nnavigating from a list.","required":false,"schema":{"type":["string","null"],"format":"date-time"}}],"responses":{"200":{"description":"Proxy log found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProxyLogResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Proxy log not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/ai-agent-pages":{"get":{"tags":["Proxy Logs"],"summary":"Get the top pages accessed by a specific AI agent over a time window.","description":"Returns page paths ranked by request count, scoped to a single canonical\nagent name (e.g. `ChatGPT-User`). Use `GET /proxy-logs/ai-agents/known` to\nlist all valid agent names. Unknown agent names return an empty items array.","operationId":"get_ai_agent_pages","parameters":[{"name":"agent","in":"query","description":"Canonical agent name to filter by (e.g. `ChatGPT-User`, `ClaudeBot`).\nMust be a name returned by `GET /proxy-logs/ai-agents/known`.","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Filter by project ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601). Defaults to `end_time - 7d`.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-22T00:00:00Z"},{"name":"end_time","in":"query","description":"End time (ISO 8601). Defaults to now.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-29T00:00:00Z"},{"name":"limit","in":"query","description":"Maximum rows to return. Capped at 100 server-side.","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}}],"responses":{"200":{"description":"Pages breakdown for the requested agent","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiAgentPagesResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/ai-agents":{"get":{"tags":["Proxy Logs"],"summary":"Get the per-AI-agent breakdown for a project over a time window.","operationId":"get_ai_agent_breakdown","parameters":[{"name":"project_id","in":"query","description":"Filter by project ID (recommended for per-project analytics).","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601). Defaults to `end_time - 7d`.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-22T00:00:00Z"},{"name":"end_time","in":"query","description":"End time (ISO 8601). Defaults to now.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-29T00:00:00Z"},{"name":"limit","in":"query","description":"Maximum rows to return. Capped at 100 server-side.","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"path","in":"query","description":"Optional exact path filter. Only used by the AI pages breakdown — when\nset, returns the single matching page so callers can ask \"how many AI\nagents hit this page?\".","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"AI agent breakdown","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiAgentBreakdownResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/ai-agents/timeline":{"get":{"tags":["Proxy Logs"],"summary":"Time-bucketed AI-agent request volume, split by provider or agent.","description":"Powers the \"AI agents over time\" stacked chart. Same data source as the AI\nagent breakdown (request logs), just bucketed.","operationId":"get_ai_agent_timeline","parameters":[{"name":"project_id","in":"query","description":"Filter by project ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601). Defaults to `end_time - 7d`.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-22T00:00:00Z"},{"name":"end_time","in":"query","description":"End time (ISO 8601). Defaults to now.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-29T00:00:00Z"},{"name":"group_by","in":"query","description":"Grouping dimension: `provider` (default) or `agent`.","required":false,"schema":{"type":["string","null"]},"example":"provider"},{"name":"bucket","in":"query","description":"Bucket interval override (e.g. `1 hour`, `1 day`). Auto-selected from the\nwindow width when omitted.","required":false,"schema":{"type":["string","null"]},"example":"1 hour"}],"responses":{"200":{"description":"AI agent timeline","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiAgentTimelineResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/ai-pages":{"get":{"tags":["Proxy Logs"],"summary":"Get the top pages crawled by AI agents over a time window.","operationId":"get_ai_page_breakdown","parameters":[{"name":"project_id","in":"query","description":"Filter by project ID (recommended for per-project analytics).","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601). Defaults to `end_time - 7d`.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-22T00:00:00Z"},{"name":"end_time","in":"query","description":"End time (ISO 8601). Defaults to now.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-29T00:00:00Z"},{"name":"limit","in":"query","description":"Maximum rows to return. Capped at 100 server-side.","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"path","in":"query","description":"Optional exact path filter. Only used by the AI pages breakdown — when\nset, returns the single matching page so callers can ask \"how many AI\nagents hit this page?\".","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"AI page breakdown","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiPageBreakdownResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/ai-status":{"get":{"tags":["Proxy Logs"],"summary":"HTTP status-class breakdown for AI-agent traffic — are bots being served\n(2xx) or hitting broken/blocked pages (4xx/5xx)?","operationId":"get_ai_status_breakdown","parameters":[{"name":"project_id","in":"query","description":"Filter by project ID (recommended for per-project analytics).","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601). Defaults to `end_time - 7d`.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-22T00:00:00Z"},{"name":"end_time","in":"query","description":"End time (ISO 8601). Defaults to now.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-29T00:00:00Z"},{"name":"limit","in":"query","description":"Maximum rows to return. Capped at 100 server-side.","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"path","in":"query","description":"Optional exact path filter. Only used by the AI pages breakdown — when\nset, returns the single matching page so callers can ask \"how many AI\nagents hit this page?\".","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"AI status breakdown","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiStatusBreakdownResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/projects-health":{"get":{"tags":["Proxy Logs"],"summary":"Get health summaries for multiple projects (last 1 hour)","operationId":"get_projects_health","parameters":[{"name":"project_ids","in":"query","description":"Comma-separated list of project IDs","required":true,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Optional start time (ISO 8601). Defaults to `end_time - 1h`.","required":false,"schema":{"type":["string","null"]},"example":"2025-10-23T00:00:00Z"},{"name":"end_time","in":"query","description":"Optional end time (ISO 8601). Defaults to now.","required":false,"schema":{"type":["string","null"]},"example":"2025-10-23T23:59:59Z"},{"name":"is_bot","in":"query","description":"Filter by bot detection. Pass `false` to exclude bots, `true` for bots only.","required":false,"schema":{"type":["boolean","null"]}}],"responses":{"200":{"description":"Health summaries per project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectsHealthResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/time-buckets":{"get":{"tags":["Proxy Logs"],"summary":"Get time-bucketed statistics with optional filters","operationId":"get_time_bucket_stats","parameters":[{"name":"start_time","in":"query","description":"Start time (ISO 8601 format)","required":true,"schema":{"type":"string"},"example":"2025-10-23T00:00:00Z"},{"name":"end_time","in":"query","description":"End time (ISO 8601 format)","required":true,"schema":{"type":"string"},"example":"2025-10-23T23:59:59Z"},{"name":"bucket_interval","in":"query","description":"Bucket interval (e.g., \"1 hour\", \"1 day\", \"5 minutes\")","required":false,"schema":{"type":"string"}},{"name":"method","in":"query","description":"Filter by HTTP method","required":false,"schema":{"type":"string"}},{"name":"client_ip","in":"query","description":"Filter by client IP","required":false,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Filter by project ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"host","in":"query","description":"Filter by host","required":false,"schema":{"type":"string"}},{"name":"status_code","in":"query","description":"Filter by status code","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"status_code_class","in":"query","description":"Filter by status code class (e.g. \"2xx\", \"3xx\", \"4xx\", \"5xx\")","required":false,"schema":{"type":"string"}},{"name":"routing_status","in":"query","description":"Filter by routing status","required":false,"schema":{"type":"string"}},{"name":"request_source","in":"query","description":"Filter by request source","required":false,"schema":{"type":"string"}},{"name":"is_bot","in":"query","description":"Filter by bot detection","required":false,"schema":{"type":"boolean"}},{"name":"device_type","in":"query","description":"Filter by device type","required":false,"schema":{"type":"string"}},{"name":"has_project","in":"query","description":"When true, only count requests that matched a project\n(project_id IS NOT NULL). Makes chart totals line up with the\nper-project health cards.","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Time-bucketed statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TimeBucketStatsResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/today":{"get":{"tags":["Proxy Logs"],"summary":"Get today's request count with optional filters","operationId":"get_today_stats","parameters":[{"name":"method","in":"query","description":"Filter by HTTP method","required":false,"schema":{"type":["string","null"]}},{"name":"client_ip","in":"query","description":"Filter by client IP","required":false,"schema":{"type":["string","null"]}},{"name":"project_id","in":"query","description":"Filter by project ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"host","in":"query","description":"Filter by host","required":false,"schema":{"type":["string","null"]}},{"name":"status_code","in":"query","description":"Filter by status code","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"status_code_class","in":"query","description":"Filter by status code class (e.g. \"2xx\", \"3xx\", \"4xx\", \"5xx\")","required":false,"schema":{"type":["string","null"]}},{"name":"routing_status","in":"query","description":"Filter by routing status","required":false,"schema":{"type":["string","null"]}},{"name":"request_source","in":"query","description":"Filter by request source","required":false,"schema":{"type":["string","null"]}},{"name":"is_bot","in":"query","description":"Filter by bot detection","required":false,"schema":{"type":["boolean","null"]}},{"name":"device_type","in":"query","description":"Filter by device type","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"Today's request count","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TodayStatsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/{id}":{"get":{"tags":["Proxy Logs"],"summary":"Get a single proxy log by ID","operationId":"get_proxy_log_by_id","parameters":[{"name":"id","in":"path","description":"Proxy log ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"timestamp","in":"query","description":"Event time of the log row (ISO 8601). When provided, the lookup is\nbounded to the hypertable chunks around this instant instead of\nscanning (and decompressing) the whole retention window. The list\nendpoint already returns this value per row — always pass it when\nnavigating from a list.","required":false,"schema":{"type":["string","null"],"format":"date-time"}}],"responses":{"200":{"description":"Proxy log found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProxyLogResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Proxy log not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/repositories":{"get":{"tags":["Git Providers"],"summary":"List synced repositories with advanced filtering","description":"Lists repositories that have been synced to the database with filtering options.\nThis provides fast access to repository metadata with filtering by connection, search, and other criteria.","operationId":"list_synced_repositories","parameters":[{"name":"page","in":"query","description":"Page number for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"sort","in":"query","description":"Sort field (name, created_at, updated_at, stars, watchers, size, issues)","required":false,"schema":{"type":"string"}},{"name":"direction","in":"query","description":"Sort direction (asc, desc)","required":false,"schema":{"type":"string"}},{"name":"search","in":"query","description":"Search term to filter repositories","required":false,"schema":{"type":"string"}},{"name":"owner","in":"query","description":"Filter by repository owner","required":false,"schema":{"type":"string"}},{"name":"language","in":"query","description":"Filter by programming language","required":false,"schema":{"type":"string"}},{"name":"private","in":"query","description":"Filter by private status (true/false)","required":false,"schema":{"type":"boolean"}},{"name":"git_provider_connection_id","in":"query","description":"Filter by git provider connection ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of synced repositories","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositoryListResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repositories/{owner}/{name}":{"get":{"tags":["Git Providers"],"summary":"Get repository by owner and name from any connection","operationId":"get_repository_by_name","parameters":[{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}},{"name":"connection_id","in":"query","description":"Optional specific connection ID to search","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Repository found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositoryResponse"}}}},"404":{"description":"Repository not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repositories/{owner}/{name}/all":{"get":{"tags":["Git Providers"],"summary":"Get all repositories with same owner/name from all git providers","operationId":"get_all_repositories_by_name","parameters":[{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Repositories found from all providers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RepositoryResponse"}}}}},"404":{"description":"No repositories found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repositories/{owner}/{name}/preset":{"get":{"tags":["Git Providers"],"summary":"Get repository preset by owner and name","operationId":"get_repository_preset_by_name","parameters":[{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}},{"name":"branch","in":"query","description":"Git branch to check (defaults to repository's default branch)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Repository preset calculated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositoryPresetResponse"}}}},"404":{"description":"Repository not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repositories/{owner}/{repo}/branches":{"get":{"tags":["Repositories"],"summary":"Get repository branches","operationId":"get_repository_branches","parameters":[{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"repo","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}},{"name":"connection_id","in":"query","description":"Git provider connection ID (required when multiple connections have the same repo)","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"fresh","in":"query","description":"Force fetch fresh data, bypassing cache (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of branches","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BranchListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Repository not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repositories/{owner}/{repo}/tags":{"get":{"tags":["Repositories"],"summary":"Get repository tags","operationId":"get_repository_tags","parameters":[{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"repo","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}},{"name":"connection_id","in":"query","description":"Git provider connection ID (required when multiple connections have the same repo)","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"fresh","in":"query","description":"Force fetch fresh data, bypassing cache (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of tags","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TagListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Repository not found"},"429":{"description":"Fresh tag lookup rate limit exceeded"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repositories/{repository_id}/preset/live":{"get":{"tags":["Git Providers"],"operationId":"get_repository_preset_live","parameters":[{"name":"repository_id","in":"path","description":"Repository ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"branch","in":"query","description":"Git branch to check (defaults to repository's default branch)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Repository presets calculated successfully - includes root preset and projects in subdirectories","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositoryPresetResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"The git provider rejected the stored credential - the connection must be re-authorized"},"404":{"description":"Repository not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repository/{repository_id}":{"get":{"tags":["Git Providers"],"summary":"Get repository by ID","operationId":"get_repository_by_id","parameters":[{"name":"repository_id","in":"path","description":"Repository ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Repository found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositoryResponse"}}}},"404":{"description":"Repository not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repository/{repository_id}/branches":{"get":{"tags":["Repositories"],"summary":"Get repository branches by repository ID","operationId":"get_branches_by_repository_id","parameters":[{"name":"repository_id","in":"path","description":"Repository ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"fresh","in":"query","description":"Force fetch fresh data, bypassing cache (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of branches","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BranchListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Repository not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repository/{repository_id}/commits":{"get":{"tags":["Repositories"],"summary":"List recent commits for a repository branch","operationId":"list_commits_by_repository_id","parameters":[{"name":"repository_id","in":"path","description":"Repository ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"branch","in":"query","description":"Branch name to list commits for","required":true,"schema":{"type":"string"}},{"name":"per_page","in":"query","description":"Number of commits to return (default: 20, max: 100)","required":false,"schema":{"type":["integer","null"],"format":"int32","minimum":0}}],"responses":{"200":{"description":"List of commits","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommitListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Repository not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repository/{repository_id}/commits/{commit_sha}":{"get":{"tags":["Repositories"],"summary":"Check if a commit exists in a repository","operationId":"check_commit_exists","parameters":[{"name":"repository_id","in":"path","description":"Repository ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"commit_sha","in":"path","description":"Commit SHA to check","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Commit existence check result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommitExistsResponse"}}}},"400":{"description":"Invalid commit SHA"},"401":{"description":"Unauthorized"},"404":{"description":"Repository not found"},"429":{"description":"Commit lookup rate limit exceeded"},"500":{"description":"Internal server error"},"502":{"description":"Git provider request failed"}},"security":[{"bearer_auth":[]}]}},"/repository/{repository_id}/tags":{"get":{"tags":["Repositories"],"summary":"Get repository tags by repository ID","operationId":"get_tags_by_repository_id","parameters":[{"name":"repository_id","in":"path","description":"Repository ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"fresh","in":"query","description":"Force fetch fresh data, bypassing cache (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of tags","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TagListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Repository not found"},"429":{"description":"Fresh tag lookup rate limit exceeded"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/restore-runs/{id}":{"get":{"tags":["Restore"],"operationId":"get_restore_run","parameters":[{"name":"id","in":"path","description":"Restore run id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Restore run progress","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RestoreRunView"}}}},"404":{"description":"Restore run not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/revenue/events":{"get":{"tags":["Revenue"],"summary":"Org-wide revenue events across every project. Powers the revenue\ntransactions page. Supports filtering by project, date range, and\nevent type.","operationId":"revenue_global_events","parameters":[{"name":"project_id","in":"query","description":"Filter to a single project","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"from","in":"query","description":"Lower bound (inclusive), ISO-8601","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","description":"Upper bound (inclusive), ISO-8601","required":false,"schema":{"type":"string"}},{"name":"event_types","in":"query","description":"Comma-separated event types (e.g. `invoice.paid,charge.succeeded`)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max rows, default 100, max 500","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GlobalRecentEventResponse"}}}}}},"security":[{"bearer_auth":[]}]}},"/revenue/metrics/global-mrr":{"get":{"tags":["Revenue"],"summary":"Org-wide MRR total, summed across every project in the install.\nPowers the single-number MRR card on the main dashboard.","operationId":"revenue_metrics_global_mrr","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GlobalMrrResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/revenue/metrics/global-summary":{"get":{"tags":["Revenue"],"summary":"Org-wide revenue summary: MRR, paid cash (30d + all-time), refunds,\nactive subscriptions/customers, and transaction count. Powers the\nheader on the Revenue transactions page.","operationId":"revenue_metrics_global_summary","parameters":[{"name":"currency","in":"query","description":"ISO-4217 currency code, default USD","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GlobalRevenueSummaryResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/revenue/providers":{"get":{"tags":["Revenue"],"summary":"List registered providers (what the UI needs to render the \"Connect\"\ndropdown + its wizard instructions).","operationId":"revenue_list_providers","responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProviderDescriptor"}}}}}},"security":[{"bearer_auth":[]}]}},"/session-replays":{"get":{"tags":["Analytics"],"summary":"Get session replays for a project","operationId":"get_project_session_replays","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-based)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Items per page","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Session replays retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetProjectSessionReplaysResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/sessions/{session_id}/events":{"get":{"tags":["Events"],"summary":"Get events for a specific session","operationId":"get_session_events","parameters":[{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved session events","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalyticsSessionEventsResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Session not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings":{"get":{"tags":["Settings"],"summary":"Get application settings","operationId":"get_settings","responses":{"200":{"description":"Application settings with masked sensitive fields","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppSettingsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Settings"],"summary":"Update application settings","operationId":"update_settings","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppSettings"}}},"required":true},"responses":{"200":{"description":"Settings updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SettingsUpdateResponse"}}}},"400":{"description":"Bad request - invalid settings"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/agent-token":{"post":{"tags":["Agents"],"summary":"Save an encrypted AI provider token for use in sandbox containers.","operationId":"save_agent_token","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveAgentTokenRequest"}}},"required":true},"responses":{"200":{"description":"Token encrypted and persisted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveAgentTokenResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Encryption or database error"}},"security":[{"bearer_auth":[]}]}},"/settings/ai-providers":{"get":{"tags":["Agents"],"summary":"List the AI provider catalog. Includes per-provider \"is a credential\nconfigured?\" so the settings UI can render configured/not-configured\nbadges without leaking the encrypted credential.","operationId":"list_ai_providers","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderCatalogResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/settings/ai-providers/{provider_id}":{"patch":{"tags":["Agents"],"summary":"Update provider-scoped settings without touching the saved credential.\nToday that means just `default_model`; future per-provider settings\n(base URL overrides, request headers, etc.) can land here too without\nchanging the shape of `save_credential`.","operationId":"update_ai_provider","parameters":[{"name":"provider_id","in":"path","description":"AI provider ID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAiProviderRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAiProviderResponse"}}}},"400":{"description":"Unknown provider"},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/settings/ai-providers/{provider_id}/activate":{"post":{"tags":["Agents"],"summary":"Activate a provider as the platform-wide default. Refuses to activate a\nprovider that doesn't have a credential saved yet — the UI enforces the\nsame rule on the button, but we re-check server-side so a stale tab\ncan't bypass it.","operationId":"activate_ai_provider","parameters":[{"name":"provider_id","in":"path","description":"AI provider ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivateProviderResponse"}}}},"400":{"description":"Provider not configured"},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/settings/ai-providers/{provider_id}/credential":{"post":{"tags":["Agents"],"summary":"Save (or replace) a provider's credential. The credential is encrypted\nwith `EncryptionService` and stored inside\n`agent_sandbox.providers[provider_id].credentials_encrypted`.","description":"The plaintext shape depends on the flavor's `credential_format`:\n - `ApiKey` / `OauthToken`: the key/token string.\n - `ConfigFile`: the full file body (e.g. OpenCode's `auth.json`).","operationId":"save_ai_provider_credential","parameters":[{"name":"provider_id","in":"path","description":"AI provider ID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveCredentialRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveCredentialResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/settings/disk-status":{"get":{"tags":["Settings"],"summary":"Get current disk usage for the control-plane server","description":"Returns live disk usage for the monitored path along with any disks that\nmeet or exceed the configured alert threshold. Read-only — does not send\nnotifications. Used by the dashboard to surface a low-disk-space warning.","operationId":"get_disk_status","responses":{"200":{"description":"Current disk usage and threshold alerts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiskSpaceCheckResult"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/enrollment-tokens":{"get":{"tags":["Settings"],"summary":"List currently-valid node enrollment tokens (hashes elided).","operationId":"list_enrollment_tokens","responses":{"200":{"description":"Active enrollment tokens","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnrollmentTokenListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Settings"],"summary":"Mint a short-lived, single-use node enrollment token.","operationId":"mint_enrollment_token","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MintEnrollmentTokenRequest"}}},"required":true},"responses":{"200":{"description":"Enrollment token minted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MintEnrollmentTokenResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/enrollment-tokens/{id}":{"delete":{"tags":["Settings"],"summary":"Revoke a node enrollment token by id.","operationId":"revoke_enrollment_token","parameters":[{"name":"id","in":"path","description":"Enrollment token id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Enrollment token revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SettingsUpdateResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Enrollment token not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/join-token":{"delete":{"tags":["Settings"],"summary":"Revoke the current join token","description":"Removes the stored join token hash, allowing any node to register\n(if no other authentication is in place).","operationId":"revoke_join_token","responses":{"200":{"description":"Join token revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SettingsUpdateResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/join-token/generate":{"post":{"tags":["Settings"],"summary":"Generate a new join token for multi-node cluster registration","description":"Creates a random 32-byte hex token, stores the SHA-256 hash in settings,\nand returns the plaintext exactly once. If a token already exists, it is replaced.","operationId":"generate_join_token","responses":{"200":{"description":"Join token generated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateJoinTokenResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/join-token/status":{"get":{"tags":["Settings"],"summary":"Check whether a join token is currently configured","operationId":"get_join_token_status","responses":{"200":{"description":"Join token status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JoinTokenStatusResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/mcp-servers":{"get":{"tags":["Agents"],"operationId":"list_global_mcps","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListMcpsResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Agents"],"operationId":"create_global_mcp","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMcpRequest"}}},"required":true},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpDefinitionResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/settings/mcp-servers/{slug}":{"get":{"tags":["Agents"],"operationId":"get_global_mcp","parameters":[{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"MCP server not found"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Agents"],"operationId":"update_global_mcp","parameters":[{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMcpRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"MCP server not found"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Agents"],"operationId":"delete_global_mcp","parameters":[{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"MCP server deleted"},"401":{"description":"Unauthorized"},"404":{"description":"MCP server not found"}},"security":[{"bearer_auth":[]}]}},"/settings/mcp-servers/{slug}/config/{field}":{"get":{"tags":["Agents"],"operationId":"reveal_global_mcp_config","parameters":[{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}},{"name":"field","in":"path","description":"Sensitive field path, such as url or env.API_TOKEN","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SensitiveMcpConfigValueResponse"}}}},"400":{"description":"Field is not revealable"},"401":{"description":"Unauthorized"},"403":{"description":"Missing secrets:read permission"},"404":{"description":"MCP server or field not found"},"500":{"description":"Configuration read or audit failed"}},"security":[{"bearer_auth":[]}]}},"/settings/routes/refresh":{"post":{"tags":["Settings"],"summary":"Manually refresh the proxy route table","description":"Reloads all routes from the database into the in-memory proxy cache.\nUseful as a workaround when routes are out of sync.","operationId":"refresh_route_table","responses":{"200":{"description":"Route table refreshed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteRefreshResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/sandbox-rebuild":{"post":{"tags":["Agents"],"operationId":"rebuild_sandbox_image","responses":{"200":{"description":"Server-Sent Events stream of rebuild progress; final event `{\"type\":\"done\",\"success\":bool,...}`","content":{"text/event-stream":{}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/settings/sandbox-status":{"get":{"tags":["Agents"],"operationId":"get_global_sandbox_status","responses":{"200":{"description":"Global sandbox readiness for the settings page","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxStatusResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/settings/secrets":{"get":{"tags":["Secrets"],"operationId":"list_secrets","responses":{"200":{"description":"List of global agent secrets","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListSecretsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Secrets"],"operationId":"upsert_secret","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertSecretRequest"}}},"required":true},"responses":{"201":{"description":"Secret created/updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SecretResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/settings/secrets/{name}":{"delete":{"tags":["Secrets"],"operationId":"delete_secret","parameters":[{"name":"name","in":"path","description":"Secret name","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Secret deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Secret not found"}},"security":[{"bearer_auth":[]}]}},"/settings/skills":{"get":{"tags":["Agents"],"operationId":"list_global_skills","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListSkillsResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Agents"],"operationId":"create_global_skill","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSkillRequest"}}},"required":true},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/settings/skills/upload":{"post":{"tags":["Agents"],"summary":"Upload a skill with an archive (tar.gz) — global.","operationId":"upload_global_skill","requestBody":{"content":{"multipart/form-data":{"schema":{"type":"string"}}},"required":true},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/settings/skills/{slug}":{"get":{"tags":["Agents"],"operationId":"get_global_skill","parameters":[{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Agents"],"operationId":"update_global_skill","parameters":[{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSkillRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Agents"],"operationId":"delete_global_skill","parameters":[{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Skill deleted"},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found"}},"security":[{"bearer_auth":[]}]}},"/settings/skills/{slug}/archive":{"get":{"tags":["Agents"],"summary":"Download a skill's archive (tar.gz) — global.","operationId":"download_global_skill_archive","parameters":[{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Skill archive tar.gz","content":{"application/gzip":{}}},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found or has no archive"}},"security":[{"bearer_auth":[]}]}},"/settings/update":{"get":{"tags":["Settings"],"summary":"Report whether a release update can be applied from the console.","operationId":"get_update_capability","responses":{"200":{"description":"Self-update capability for this install","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCapabilityResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Settings"],"summary":"Install a release and restart the server.","description":"Returns as soon as the attempt is accepted: the download and swap run in the\nbackground and the process then exits so its supervisor restarts it on the\nnew binary. Poll `GET /settings/update` for progress — after the restart,\n`last_attempt` carries the outcome.","operationId":"start_update","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartUpdateRequest"}}},"required":true},"responses":{"202":{"description":"Update accepted; the server will restart","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartUpdateResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"409":{"description":"Update unavailable or already running","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"501":{"description":"This process cannot apply updates","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/settings/update-status":{"get":{"tags":["Settings"],"summary":"Report whether a newer temps release is available for this install.","operationId":"get_update_status","responses":{"200":{"description":"Release update status for this install","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateStatusResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/settings/update/check":{"post":{"tags":["Settings"],"summary":"Ask the release API for the newest version on this install's channel, now,\ninstead of waiting for the background notifier's next pass.","operationId":"check_for_update","responses":{"200":{"description":"Result of the release check","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReleaseCheckResult"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"501":{"description":"This process cannot check for updates","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"502":{"description":"The release API could not be reached","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/teams":{"get":{"tags":["Teams"],"operationId":"list_teams","parameters":[{"name":"page","in":"query","description":"1-indexed page","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"default 20, max 100","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Paginated teams","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Teams"],"operationId":"create_team","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTeamRequest"}}},"required":true},"responses":{"201":{"description":"Team created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamResponse"}}}},"400":{"description":"Validation error"},"403":{"description":"Insufficient permissions"},"409":{"description":"Slug already taken"}},"security":[{"bearer_auth":[]}]}},"/teams/{team_id}":{"get":{"tags":["Teams"],"operationId":"get_team","parameters":[{"name":"team_id","in":"path","description":"Team id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Team","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamResponse"}}}},"403":{"description":"Insufficient permissions"},"404":{"description":"Team not found"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Teams"],"operationId":"delete_team","parameters":[{"name":"team_id","in":"path","description":"Team id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Team deleted"},"403":{"description":"Insufficient permissions"},"404":{"description":"Team not found"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Teams"],"operationId":"update_team","parameters":[{"name":"team_id","in":"path","description":"Team id","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTeamRequest"}}},"required":true},"responses":{"200":{"description":"Updated team","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamResponse"}}}},"400":{"description":"Validation error"},"403":{"description":"Insufficient permissions"},"404":{"description":"Team not found"}},"security":[{"bearer_auth":[]}]}},"/teams/{team_id}/members":{"get":{"tags":["Teams"],"operationId":"list_team_members","parameters":[{"name":"team_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Members","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TeamMemberResponse"}}}}},"403":{"description":"Insufficient permissions"},"404":{"description":"Team not found"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Teams"],"operationId":"add_team_member","parameters":[{"name":"team_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTeamMemberRequest"}}},"required":true},"responses":{"201":{"description":"Member added","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamMemberResponse"}}}},"403":{"description":"Insufficient permissions"},"404":{"description":"Team not found"},"409":{"description":"User already a member"}},"security":[{"bearer_auth":[]}]}},"/teams/{team_id}/members/{user_id}":{"delete":{"tags":["Teams"],"operationId":"remove_team_member","parameters":[{"name":"team_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"user_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Member removed"},"403":{"description":"Insufficient permissions"},"404":{"description":"Member not found"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Teams"],"operationId":"update_team_member_role","parameters":[{"name":"team_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"user_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMemberRoleRequest"}}},"required":true},"responses":{"200":{"description":"Updated membership","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamMemberResponse"}}}},"403":{"description":"Insufficient permissions"},"404":{"description":"Member not found"}},"security":[{"bearer_auth":[]}]}},"/teams/{team_id}/projects":{"get":{"tags":["Teams"],"operationId":"list_team_projects","parameters":[{"name":"team_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Projects this team has access to","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProjectAccessResponse"}}}}},"403":{"description":"Insufficient permissions"},"404":{"description":"Team not found"}},"security":[{"bearer_auth":[]}]}},"/templates":{"get":{"tags":["Templates"],"summary":"List all available templates","description":"Returns a list of all public templates, optionally filtered by tag or featured status.","operationId":"list_project_templates","parameters":[{"name":"tag","in":"query","description":"Filter templates by tag","required":false,"schema":{"type":"string"}},{"name":"featured","in":"query","description":"Only return featured templates","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of templates","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListTemplatesResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/templates/tags":{"get":{"tags":["Templates"],"summary":"List all available template tags","description":"Returns a list of all unique tags used by public templates.","operationId":"list_project_template_tags","responses":{"200":{"description":"List of tags","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListTagsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/templates/{slug}":{"get":{"tags":["Templates"],"summary":"Get a specific template by slug","description":"Returns detailed information about a single template.","operationId":"get_project_template","parameters":[{"name":"slug","in":"path","description":"Template slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Template details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TemplateResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Template not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/user/me":{"get":{"tags":["Authentication"],"operationId":"get_current_user","responses":{"200":{"description":"Successfully retrieved user information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"session_token":[]}]}},"/users":{"get":{"tags":["Users"],"operationId":"list_users","parameters":[{"name":"include_deleted","in":"query","description":"Include deleted users in the response","required":true,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List all users with their roles","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RouteUserWithRoles"}}}}},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Users"],"summary":"Create a new user with roles","operationId":"create_user","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUserRequest"}}},"required":true},"responses":{"201":{"description":"User created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteUserWithRoles"}}}},"400":{"description":"Invalid input"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/me":{"patch":{"tags":["Users"],"summary":"Update current user's information","operationId":"update_self","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSelfRequest"}}},"required":true},"responses":{"200":{"description":"User updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteUserWithRoles"}}}},"400":{"description":"Invalid input"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/me/mfa":{"delete":{"tags":["Users"],"operationId":"disable_mfa","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DisableMfaRequest"}}},"required":true},"responses":{"204":{"description":"MFA disabled"},"400":{"description":"Invalid verification code"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/me/mfa/setup":{"post":{"tags":["Users"],"operationId":"setup_mfa","responses":{"200":{"description":"MFA setup data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MfaSetupResponse"}}}},"401":{"description":"Unauthorized"},"409":{"description":"MFA is already enabled; verify and disable it before re-enrollment"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/me/mfa/verify":{"post":{"tags":["Users"],"operationId":"verify_and_enable_mfa","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyMfaRequest"}}},"required":true},"responses":{"204":{"description":"MFA verified and enabled"},"400":{"description":"Invalid code"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/me/password":{"post":{"tags":["Users"],"operationId":"change_password_self","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangePasswordRequest"}}},"required":true},"responses":{"204":{"description":"Password updated"},"400":{"description":"Validation error (weak password, same as current, MFA missing)"},"401":{"description":"Current password incorrect or MFA code invalid"},"403":{"description":"Account has no password set (SSO only)"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/{user_id}":{"delete":{"tags":["Users"],"summary":"Delete a user","operationId":"delete_user","parameters":[{"name":"user_id","in":"path","description":"User ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"User deleted successfully"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden - Cannot delete yourself or non-admin attempt"},"404":{"description":"User not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Users"],"summary":"Update user information (admin only)","operationId":"update_user","parameters":[{"name":"user_id","in":"path","description":"User ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUserRequest"}}},"required":true},"responses":{"200":{"description":"User updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteUserWithRoles"}}}},"400":{"description":"Invalid input"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden - Non-admin attempt"},"404":{"description":"User not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/{user_id}/restore":{"post":{"tags":["Users"],"operationId":"restore_user","parameters":[{"name":"user_id","in":"path","description":"User ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"User restored successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteUserWithRoles"}}}},"400":{"description":"User is not deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden - Non-admin attempt"},"404":{"description":"User not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/{user_id}/roles":{"post":{"tags":["Users"],"operationId":"assign_role","parameters":[{"name":"user_id","in":"path","description":"User ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssignRoleRequest"}}},"required":true},"responses":{"200":{"description":"Role assigned successfully"},"400":{"description":"Invalid role type"},"401":{"description":"Unauthorized"},"403":{"description":"Admin role required or self-modification forbidden"},"404":{"description":"User or role not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/{user_id}/roles/{role_type}":{"delete":{"tags":["Users"],"operationId":"remove_role","parameters":[{"name":"user_id","in":"path","description":"User ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"role_type","in":"path","description":"Role type to remove","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Role removed successfully"},"400":{"description":"Invalid role type"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden - Cannot modify own roles or non-admin attempt"},"404":{"description":"User or role not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes":{"get":{"tags":["Sandboxes"],"operationId":"list_sandboxes","parameters":[{"name":"page","in":"query","description":"Page (1-indexed)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page (default 20, max 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List sandboxes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListSandboxesResponse"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Sandboxes"],"operationId":"create_sandbox","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSandboxBody"}}},"required":true},"responses":{"201":{"description":"Sandbox created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/rootfs":{"get":{"tags":["Sandboxes"],"summary":"Inspect rootfs storage: the Firecracker digest-keyed cache (with which\nsandboxes reference each entry) and per-VM disks. Empty on Docker-only\nhosts. Admin/read scope — this exposes host storage layout.","operationId":"rootfs_report","responses":{"200":{"description":"Rootfs storage report"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/rootfs/gc":{"post":{"tags":["Sandboxes"],"summary":"Reclaim rootfs cache entries not backing any live sandbox. Idempotent;\nsafe to call any time (live VMs hold their own per-VM disks).","operationId":"rootfs_gc","responses":{"200":{"description":"Reclaimed cache entries"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}":{"get":{"tags":["Sandboxes"],"operationId":"get_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sandbox details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"404":{"description":"Not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/cmd":{"post":{"tags":["Sandboxes"],"summary":"Run a command inside the sandbox (`@vercel/sandbox`-compatible).","description":"`wait=false` (default) returns `{ command: {..., exitCode: null} }`\nimmediately once the background task is spawned.\n\n`wait=true` streams `application/x-ndjson`: the first line is the\nrunning envelope, the second is the finished envelope with `exitCode`.","operationId":"cmd","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CmdBody"}}},"required":true},"responses":{"200":{"description":"Command started (wait=false) or finished (wait=true)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CmdResponse"}}}},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/cmd/{cmd_id}":{"get":{"tags":["Sandboxes"],"operationId":"get_cmd","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"cmd_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Command snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CmdResponse"}}}},"404":{"description":"Sandbox or command not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/cmd/{cmd_id}/logs":{"get":{"tags":["Sandboxes"],"summary":"Stream a command's stdout/stderr as `application/x-ndjson`\n(`@vercel/sandbox`-compatible). Each line is either\n`{stream:\"stdout\"|\"stderr\", data:\"...\"}` or\n`{stream:\"error\", data:{code, message}}`.","operationId":"cmd_logs","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"cmd_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"NDJSON stream of log events"},"404":{"description":"Sandbox or command not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/destroy":{"post":{"tags":["Sandboxes"],"operationId":"destroy_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Sandbox destroyed (alias for `/stop` with an explicit verb)"},"404":{"description":"Not found"},"409":{"description":"Sandbox belongs to an active agent run — stop the run instead"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/domain":{"get":{"tags":["Sandboxes"],"operationId":"domain","parameters":[{"name":"port","in":"query","description":"Port inside the sandbox (1..=65535)","required":true,"schema":{"type":"integer","format":"int32","minimum":0}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Preview URL for the port","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxDomainResponse"}}}},"400":{"description":"Invalid port"},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/events":{"get":{"tags":["Sandboxes"],"summary":"The operations timeline for a sandbox (lifecycle events only — never\nshell/exec activity), newest first.","operationId":"list_events","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Operations timeline","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxEventsResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/exec":{"post":{"tags":["Sandboxes"],"operationId":"exec","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecBody"}}},"required":true},"responses":{"200":{"description":"Command finished (non-zero exit is NOT an error)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecResponse"}}}},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/exec-detached":{"post":{"tags":["Sandboxes"],"operationId":"exec_detached","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecBody"}}},"required":true},"responses":{"202":{"description":"Command accepted; poll /jobs/{job_id}","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecDetachedResponse"}}}},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/extend-timeout":{"post":{"tags":["Sandboxes"],"operationId":"extend_timeout","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExtendTimeoutBody"}}},"required":true},"responses":{"200":{"description":"Timeout extended","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"400":{"description":"Validation error"},"404":{"description":"Not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/fs/mkdir":{"post":{"tags":["Sandboxes"],"operationId":"mkdir","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MkdirBody"}}},"required":true},"responses":{"204":{"description":"Directory created (or already existed)"},"400":{"description":"Validation error"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/fs/read":{"get":{"tags":["Sandboxes"],"operationId":"read_file","parameters":[{"name":"path","in":"query","description":"Absolute file path inside the sandbox","required":true,"schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"File contents (base64)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReadFileResponse"}}}},"400":{"description":"Validation error"},"404":{"description":"Sandbox or file not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/fs/stat":{"get":{"tags":["Sandboxes"],"operationId":"stat_path","parameters":[{"name":"path","in":"query","description":"Absolute path inside the sandbox","required":true,"schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Stat info (exists=false when missing — not an error)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatResponse"}}}},"400":{"description":"Validation error"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/fs/write":{"post":{"tags":["Sandboxes"],"summary":"Write a file into the sandbox. Accepts two body shapes — the SDK\npicks one based on `Content-Type`:","description":"- **`application/json`** (temps-native): `{path, contents_b64, mode}`\n — one file, base64-encoded.\n- **`application/gzip`** (`@vercel/sandbox`): a gzipped tarball of\n one-or-more entries, with the target extract dir carried in the\n `x-cwd` header. The SDK's `writeFile` and `writeFiles` both post\n here; they differ only in how many entries the tarball contains.\n\nWhy merge them on one route: the SDK is hardcoded to\n`POST /fs/write`, so splitting tar uploads onto a separate path would\nforce us to break SDK compat. Instead we dispatch on Content-Type,\npreserve JSON for native callers, and add tar for SDK callers.","operationId":"write_file","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WriteFileBody"}}},"required":true},"responses":{"204":{"description":"File(s) written"},"400":{"description":"Validation error or invalid base64"},"404":{"description":"Sandbox not found"},"415":{"description":"Unsupported Content-Type (expected application/json or application/gzip)"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/fs/write-batch":{"post":{"tags":["Sandboxes"],"summary":"Batch-write multiple files in a single request. Mirrors\n`@vercel/sandbox` `writeFiles()`. Semantics are fail-fast: if any\nfile errors, previously-written entries are left in place and the\nerror describes which file broke.","operationId":"write_files","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WriteFilesBody"}}},"required":true},"responses":{"200":{"description":"All files written","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WriteFilesResponse"}}}},"400":{"description":"Validation error or invalid base64"},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/jobs":{"get":{"tags":["Sandboxes"],"operationId":"list_jobs","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Detached jobs for this sandbox","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListJobsResponse"}}}},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/jobs/{job_id}":{"get":{"tags":["Sandboxes"],"operationId":"job_status","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"job_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Job status snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobStatusResponse"}}}},"404":{"description":"Sandbox or job not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/jobs/{job_id}/kill":{"post":{"tags":["Sandboxes"],"summary":"Terminate a detached job. Aborts the server-side tracking task and\nsends SIGTERM (or SIGKILL if `force=true`) to any matching processes\ninside the sandbox container. Returns 204 on success; 404 if the\nsandbox or job is unknown.","operationId":"kill_job","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"job_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KillJobBody"}}},"required":true},"responses":{"204":{"description":"Job killed"},"404":{"description":"Sandbox or job not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/jobs/{job_id}/logs":{"get":{"tags":["Sandboxes"],"summary":"SSE endpoint streaming each stdout/stderr line from a detached job\nas it's produced. Mirrors the `Command.logs()` async iterator shape\non `@vercel/sandbox` — events carry `{ stream, data }`.","description":"Late subscribers only see events produced after they connect. The\nJobState snapshot (`GET /jobs/{job_id}`) covers the history.\n\nA \"done\" sentinel event fires when the broadcast channel closes\n(the exec task has exited and dropped the sender), signalling\ncallers they can stop reading.","operationId":"job_logs","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"job_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"SSE stream of log events"},"404":{"description":"Sandbox or job not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/pause":{"post":{"tags":["Sandboxes"],"operationId":"pause_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sandbox paused (container stopped, state preserved)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"404":{"description":"Not found"},"409":{"description":"Sandbox is in an incompatible state (e.g. already destroyed)"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/preview-link":{"post":{"tags":["Sandboxes"],"summary":"Mint a shareable link to a sandbox preview.","description":"`GET /domain` returns the bare preview URL, which is useless to anyone who\ndoes not already hold the sandbox's preview password — so sharing a\nprotected preview meant sharing that password, which is the same secret for\nevery recipient and can only be withdrawn by rotating it for all of them.\n\nThis returns the same URL carrying a short-lived, sandbox-scoped grant. The\nrecipient's browser exchanges it for the ordinary preview cookie and lands\non `path`. The grant never reaches the sandbox, so preview application code\ncannot read it and re-share it.\n\nAnyone holding the returned URL can view the preview until it expires;\nthere is no per-link revocation short of rotating the preview password.","operationId":"sandbox_create_preview_link","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreviewShareLinkBody"}}},"required":true},"responses":{"200":{"description":"Shareable preview link","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreviewShareLinkResponse"}}}},"400":{"description":"Invalid port"},"404":{"description":"Sandbox not found"},"409":{"description":"Sandbox has no preview password"},"500":{"description":"Preview grant minting failed"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/preview-password":{"put":{"tags":["Sandboxes"],"operationId":"set_preview_password","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetPreviewPasswordBody"}}},"required":true},"responses":{"200":{"description":"Preview password set or rotated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetPreviewPasswordResponse"}}}},"400":{"description":"Password too short or too long"},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Sandboxes"],"operationId":"clear_preview_password","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Preview password removed (sandbox is now URL-only protected)"},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/resize":{"post":{"tags":["Sandboxes"],"summary":"Grow a Firecracker sandbox's root disk. Offline resize — the VM reboots\n(filesystem/data persist) rather than resizing fully live.","operationId":"resize_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResizeSandboxBody"}}},"required":true},"responses":{"200":{"description":"Resized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"400":{"description":"Invalid size or unsupported backend"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/restart":{"post":{"tags":["Sandboxes"],"operationId":"restart_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sandbox container restarted in place","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"404":{"description":"Not found"},"409":{"description":"Sandbox is stopped (use /resume) or already destroyed"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/resume":{"post":{"tags":["Sandboxes"],"operationId":"resume_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sandbox resumed; expires_at refreshed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"404":{"description":"Not found"},"409":{"description":"Sandbox is not in a resumable state"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/source":{"post":{"tags":["Sandboxes"],"operationId":"source_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceBody"}}},"required":true},"responses":{"200":{"description":"Source content seeded into the sandbox work dir","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"400":{"description":"Validation error (embedded creds, conflicting fields, etc.)"},"404":{"description":"Sandbox not found"},"409":{"description":"Sandbox is not running"},"500":{"description":"Source seed failed inside sandbox"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/stop":{"post":{"tags":["Sandboxes"],"operationId":"stop_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Sandbox stopped and destroyed"},"404":{"description":"Not found"},"409":{"description":"Sandbox belongs to an active agent run — stop the run instead"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/{cmd_id}/kill":{"post":{"tags":["Sandboxes"],"summary":"Kill a running command (`@vercel/sandbox`-compatible). The SDK\ncalls `POST /v1/sandboxes/{id}/{cmdId}/kill` — note the path has the\ncommand ID directly under the sandbox, NOT under `/jobs/` or `/cmd/`.","operationId":"cmd_kill","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"cmd_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CmdKillBody"}}}},"responses":{"200":{"description":"Command killed; returns final snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CmdResponse"}}}},"404":{"description":"Sandbox or command not found"}},"security":[{"bearer_auth":[]}]}},"/visitors/{visitor_id}/session-replays":{"get":{"tags":["Analytics"],"summary":"Get session replays for a visitor","operationId":"get_visitor_sessions","parameters":[{"name":"visitor_id","in":"path","description":"Visitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-based)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Items per page","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Session replays retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetVisitorSessionsResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/visitors/{visitor_id}/session-replays/{session_id}":{"get":{"tags":["Analytics"],"summary":"Get session replay data with visitor info (without events)","operationId":"get_session_replay","parameters":[{"name":"visitor_id","in":"path","description":"Visitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Session replay retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetSessionReplayResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Session not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Analytics"],"summary":"Delete a session replay","operationId":"delete_session_replay","parameters":[{"name":"visitor_id","in":"path","description":"Visitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Session replay deleted successfully"},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Session not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/visitors/{visitor_id}/session-replays/{session_id}/duration":{"put":{"tags":["Analytics"],"summary":"Update session duration","operationId":"update_session_duration","parameters":[{"name":"visitor_id","in":"path","description":"Visitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSessionDurationRequest"}}},"required":true},"responses":{"200":{"description":"Session duration updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSessionDurationResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Session not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/visitors/{visitor_id}/session-replays/{session_id}/events":{"get":{"tags":["Analytics"],"summary":"Get session replay events (with session and visitor metadata)","operationId":"get_session_replay_events","parameters":[{"name":"visitor_id","in":"path","description":"Visitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Session replay with events retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionReplayWithEventsDto"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Session not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Analytics"],"summary":"Add events to an existing session","operationId":"add_events","parameters":[{"name":"visitor_id","in":"path","description":"Visitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddEventsRequest"}}},"required":true},"responses":{"200":{"description":"Events added successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddEventsResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Session not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/vulnerability-scans/{scan_id}":{"get":{"tags":["Vulnerability Scans"],"operationId":"get_scan","parameters":[{"name":"scan_id","in":"path","description":"Scan ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Scan details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScanResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Scan not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Vulnerability Scans"],"operationId":"delete_scan","parameters":[{"name":"scan_id","in":"path","description":"Scan ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Scan deleted"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Scan not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/vulnerability-scans/{scan_id}/vulnerabilities":{"get":{"tags":["Vulnerability Scans"],"operationId":"get_scan_vulnerabilities","parameters":[{"name":"scan_id","in":"path","description":"Scan ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"severity","in":"query","description":"Filter by severity (CRITICAL, HIGH, MEDIUM, LOW)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of vulnerabilities","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/VulnerabilityResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Scan not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/webhook-event-types":{"get":{"tags":["Webhooks"],"summary":"List available event types","operationId":"list_event_types","responses":{"200":{"description":"List of available event types","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EventTypeResponse"}}}}}}}},"/weekly-digest/trigger":{"post":{"tags":["Notification Preferences"],"summary":"Trigger weekly digest generation manually","operationId":"trigger_weekly_digest","responses":{"200":{"description":"Weekly digest triggered successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerDigestResponse"}}}},"500":{"description":"Failed to generate digest"}},"security":[{"bearer_auth":[]}]}},"/x/plugins":{"get":{"tags":["External Plugins"],"summary":"List all running external plugins and their manifests.","description":"Requires only a valid session/token (no specific permission) since the\nmanifest drives sidebar navigation rendering for every authenticated\nuser, not just admins.","operationId":"list_external_plugins","responses":{"200":{"description":"List of all running external plugins","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PluginManifest"}}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/x/plugins/reload":{"post":{"tags":["External Plugins"],"summary":"Reload all external plugins.","description":"Stops all running plugin processes, re-scans the plugins directory,\nstarts any discovered binaries, and hot-swaps the proxy router so new\nand removed plugins take effect immediately without a server restart.\n\nRequires `SystemAdmin` permission.","operationId":"reload_plugins","responses":{"200":{"description":"Plugins reloaded successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReloadResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/{project_id}/envelope/":{"post":{"tags":["sentry-ingestor"],"summary":"Ingest a Sentry envelope (binary payload)","operationId":"ingest_sentry_envelope","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"Sentry envelope as binary data","content":{"application/octet-stream":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"Envelope ingested"},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"413":{"description":"Request body too large (exceeds 2 MiB)"}}}},"/{project_id}/store/":{"post":{"tags":["sentry-ingestor"],"summary":"Ingest a Sentry event (JSON payload)","operationId":"ingest_sentry_event","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryEventRequest"}}},"required":true},"responses":{"200":{"description":"Event ingested","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryEventResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"413":{"description":"Request body too large (exceeds 2 MiB)"}}}},"audit/logs":{"get":{"tags":["Audit Logs"],"summary":"List audit logs with optional filtering","operationId":"list_audit_logs","parameters":[{"name":"operation_type","in":"query","description":"Filter logs by operation type (omit for all)","required":false,"schema":{"type":"string"},"example":"user.login"},{"name":"user_id","in":"query","description":"Filter logs by user ID (omit for all users)","required":false,"schema":{"type":"integer","format":"int32"},"example":1},{"name":"from","in":"query","description":"Start timestamp (milliseconds since epoch)","required":false,"schema":{"type":"string","format":"date-time"},"example":1},{"name":"to","in":"query","description":"End timestamp (milliseconds since epoch)","required":false,"schema":{"type":"string","format":"date-time"},"example":1},{"name":"limit","in":"query","description":"Maximum number of logs to return","required":false,"schema":{"type":"integer","format":"int32"},"example":100},{"name":"offset","in":"query","description":"Number of logs to skip","required":false,"schema":{"type":"integer","format":"int32"},"example":0}],"responses":{"200":{"description":"List of audit logs","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AuditLogResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"api_key":[]}]}},"audit/logs/{id}":{"get":{"tags":["Audit Logs"],"summary":"Get a specific audit log entry by ID","operationId":"get_audit_log","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Audit log details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuditLogResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Audit log not found"},"500":{"description":"Internal server error"}},"security":[{"api_key":[]}]}}},"components":{"schemas":{"AcmeOrderResponse":{"type":"object","required":["id","order_url","domain_id","email","status","identifiers","created_at","updated_at"],"properties":{"authorizations":{},"certificate_url":{"type":["string","null"]},"challenge_validation":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ChallengeValidationStatus","description":"Live challenge validation status fetched from Let's Encrypt"}]},"created_at":{"type":"integer","format":"int64"},"domain_id":{"type":"integer","format":"int32"},"email":{"type":"string"},"error":{"type":["string","null"]},"error_type":{"type":["string","null"]},"expires_at":{"type":["integer","null"],"format":"int64"},"finalize_url":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"identifiers":{},"order_url":{"type":"string"},"status":{"type":"string"},"updated_at":{"type":"integer","format":"int64"}}},"ActivateProviderResponse":{"type":"object","required":["default_provider"],"properties":{"default_provider":{"type":"string"}}},"ActiveVisitor":{"type":"object","required":["session_id","session_start","last_activity","page_count","event_count","duration_seconds","is_active"],"properties":{"current_page":{"type":["string","null"]},"duration_seconds":{"type":"integer","format":"int64"},"event_count":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"last_activity":{"type":"string"},"page_count":{"type":"integer","format":"int32"},"session_id":{"type":"string"},"session_start":{"type":"string"},"visitor_id":{"type":["string","null"]}}},"ActiveVisitorsQuery":{"type":"object","properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"}}},"ActiveVisitorsResponse":{"type":"object","required":["active_visitors","window_minutes"],"properties":{"active_visitors":{"type":"integer","format":"int64"},"window_minutes":{"type":"integer","format":"int32"}}},"ActivityDay":{"type":"object","description":"Daily activity count for a single day","required":["date","count","level"],"properties":{"count":{"type":"integer","format":"int64","description":"Number of deployments on this day"},"date":{"type":"string","description":"Date in YYYY-MM-DD format","example":"2024-06-15"},"level":{"type":"integer","format":"int32","description":"Intensity level (0-4) for visualization\n0: No activity, 1: Low (1-2), 2: Medium (3-5), 3: High (6-10), 4: Very High (11+)","example":2}}},"ActivityEvent":{"type":"object","description":"A single activity event for the real-time activity feed","required":["id","timestamp","event_type","page_path","is_crawler"],"properties":{"browser":{"type":["string","null"],"description":"Browser"},"city":{"type":["string","null"],"description":"Visitor's city (from ip_geolocations)"},"country":{"type":["string","null"],"description":"Visitor's country (from ip_geolocations)"},"country_code":{"type":["string","null"],"description":"Visitor's country code (from ip_geolocations)"},"device_type":{"type":["string","null"],"description":"Device type"},"event_name":{"type":["string","null"],"description":"Event name (for custom events)"},"event_type":{"type":"string","description":"Event type: \"page_view\", \"custom\", etc."},"id":{"type":"integer","format":"int64","description":"Event ID"},"is_crawler":{"type":"boolean","description":"Whether this event was from a crawler"},"latitude":{"type":["number","null"],"format":"double","description":"Latitude"},"longitude":{"type":["number","null"],"format":"double","description":"Longitude"},"operating_system":{"type":["string","null"],"description":"Operating system"},"page_path":{"type":"string","description":"Page path where the event happened"},"page_title":{"type":["string","null"],"description":"Page title"},"referrer":{"type":["string","null"],"description":"Referrer"},"timestamp":{"type":"string","format":"date-time","description":"When the event occurred"},"visitor_id":{"type":["integer","null"],"format":"int32","description":"Visitor numeric ID"}}},"ActivityGraphQuery":{"type":"object","description":"Query parameters for activity graph endpoint","properties":{"days":{"type":"integer","format":"int32","description":"Number of days to include (default: 365 for last year)"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Optional environment ID to filter activity"},"project_id":{"type":["integer","null"],"format":"int32","description":"Optional project ID to filter activity"}}},"ActivityGraphResponse":{"type":"object","description":"Response for activity graph showing daily deployment activity","required":["days","total_count","start_date","end_date"],"properties":{"days":{"type":"array","items":{"$ref":"#/components/schemas/ActivityDay"},"description":"Array of daily activity counts"},"end_date":{"type":"string","description":"Date range end (YYYY-MM-DD)","example":"2024-12-31"},"start_date":{"type":"string","description":"Date range start (YYYY-MM-DD)","example":"2024-01-01"},"total_count":{"type":"integer","format":"int64","description":"Total count of activities across all days"}}},"AddClusterMemberRequest":{"type":"object","description":"Request body for adding a single member to a running cluster.","required":["role"],"properties":{"node_id":{"type":["integer","null"],"format":"int32","description":"Target worker node ID. Omit or null to run on the control plane."},"role":{"type":"string","description":"Member role. Currently only `replica` is accepted at runtime —\nmonitor is a singleton, primary is elected by pg_auto_failover.","example":"replica"}}},"AddContextRequest":{"type":"object","required":["message"],"properties":{"message":{"type":"string"}}},"AddEnvironmentDomainRequest":{"type":"object","required":["domain","is_primary"],"properties":{"domain":{"type":"string"},"is_primary":{"type":"boolean"}}},"AddEventsRequest":{"type":"object","required":["events"],"properties":{"events":{"type":"string"}}},"AddEventsResponse":{"type":"object","required":["event_count","message"],"properties":{"event_count":{"type":"integer","minimum":0},"message":{"type":"string"}}},"AddManagedDomainApiRequest":{"type":"object","description":"Request to add a managed domain","required":["domain"],"properties":{"auto_manage":{"type":"boolean"},"domain":{"type":"string","example":"example.com"},"generated_hostname_mode":{"type":["string","null"],"description":"Generated hostname layout: `\"standard\"` (default) or `\"flat\"`."},"sync_generated_records":{"type":"boolean","description":"Opt in to reconciling generated hostnames into this domain's DNS zone."}}},"AdminGateResponse":{"type":"object","required":["allowed_ips","allowed_hosts","trust_forwarded_for","source","editable"],"properties":{"allowed_hosts":{"type":"array","items":{"type":"string"},"description":"`Host` header values allowed. Empty = any host."},"allowed_ips":{"type":"array","items":{"type":"string"},"description":"IPs / CIDRs allowed to reach the admin listener. Empty = any source."},"editable":{"type":"boolean","description":"True when the config is writable through this API. False when env\nvars are dictating the active config."},"source":{"$ref":"#/components/schemas/AdminGateSource","description":"Where the active config came from."},"trust_forwarded_for":{"type":"boolean","description":"When true, the gate trusts `X-Forwarded-For` from loopback peers."}}},"AdminGateSource":{"type":"string","description":"Where the active gate configuration came from. Env-supplied configs are\nfrozen at the process level — the UI shows them read-only and refuses to\npersist DB writes. DB-supplied configs are editable at runtime.","enum":["default","db","env"]},"AgentConfigResponse":{"type":"object","description":"Response DTO for a single agent — masks the encrypted API key.","required":["id","project_id","slug","name","source","enabled","trigger_config","ai_provider","api_key_set","max_turns","timeout_seconds","daily_budget_cents","cooldown_minutes","branch_prefix","deliverable","created_at","updated_at"],"properties":{"ai_model":{"type":["string","null"],"description":"Preferred model for the CLI (e.g. \"sonnet\", \"gpt-5-codex\"). `None` means default."},"ai_provider":{"type":"string"},"ai_provider_key_id":{"type":["integer","null"],"format":"int32"},"api_key_set":{"type":"boolean","description":"`true` if an API key is set; `false` otherwise."},"branch_prefix":{"type":"string"},"config_repo_branch":{"type":["string","null"],"description":"Branch of the config repo to use."},"config_repo_url":{"type":["string","null"],"description":"Private config repo containing .claude/ directory (skills, MCP, plugins)."},"cooldown_minutes":{"type":"integer","format":"int32"},"created_at":{"type":"string"},"daily_budget_cents":{"type":"integer","format":"int32"},"deliverable":{"type":"string"},"description":{"type":["string","null"]},"enabled":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"max_turns":{"type":"integer","format":"int32"},"mcp_servers_config":{"description":"MCP servers config (Claude Code settings.json mcpServers format).\nCredential-bearing legacy inline values are write-only and appear as\n`***`. Omit this field on update to preserve their stored values."},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"prompt":{"type":["string","null"]},"sandbox_enabled":{"type":["boolean","null"],"description":"None = use global sandbox setting, true = force on, false = force off"},"skills_config":{"description":"Skills config as JSON array."},"slug":{"type":"string"},"source":{"type":"string"},"timeout_seconds":{"type":"integer","format":"int32"},"tools_config":{"description":"Tools config as JSON array. Legacy custom-tool webhook URLs and headers\nare write-only and appear as `***`. Omit this field on update to\npreserve their stored values."},"trigger_config":{},"updated_at":{"type":"string"},"webhook_token":{"type":["string","null"],"description":"Secret token for the `X-Webhook-Token` header. Shown once when created,\nmasked with `***` prefix in subsequent reads."},"webhook_url":{"type":["string","null"],"description":"Public webhook URL for triggering this agent externally.\nOnly set when `on: { webhook: true }` is configured.\nUsage: `POST {webhook_url}` with header `X-Webhook-Token: {webhook_token}`"}}},"AgentRunLogResponse":{"type":"object","required":["id","run_id","level","message","created_at"],"properties":{"created_at":{"type":"string"},"id":{"type":"integer","format":"int64"},"level":{"type":"string"},"message":{"type":"string"},"metadata":{},"run_id":{"type":"integer","format":"int32"}}},"AgentRunResponse":{"type":"object","required":["id","project_id","source","trigger_type","status","tokens_input","tokens_output","estimated_cost_cents","files_changed","created_at","sandbox_enabled"],"properties":{"agent_name":{"type":["string","null"],"description":"Name of the agent that created this run, if available."},"agent_slug":{"type":["string","null"],"description":"Slug of the agent that created this run, if available."},"ai_model":{"type":["string","null"]},"ai_output":{"type":["string","null"]},"ai_provider":{"type":["string","null"],"description":"AI provider slug that executed this run (e.g. claude_cli, codex_cli, opencode)."},"ai_reasoning":{"type":["string","null"]},"ai_session_id":{"type":["string","null"],"description":"Claude CLI session UUID for resuming conversations via `--resume`."},"analysis":{"type":["string","null"],"description":"Report / analysis text produced by the agent (used for report/notification deliverables)."},"branch_name":{"type":["string","null"]},"commit_sha":{"type":["string","null"]},"completed_at":{"type":["string","null"]},"config_id":{"type":["integer","null"],"format":"int32","description":"Optional. NULL for ephemeral CLI runs (`source = \"cli_ephemeral\"`) and\nhistorical autofixer runs that pre-date the agent_id column."},"created_at":{"type":"string"},"ephemeral_yaml":{"type":["string","null"],"description":"Full WorkflowYamlConfig as YAML text. Populated only when\n`source = \"cli_ephemeral\"`. Used by the web UI to show a \"View YAML\"\nmodal so the user can see exactly what the executor ran."},"error_message":{"type":["string","null"]},"estimated_cost_cents":{"type":"integer","format":"int32"},"files_changed":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"phase":{"type":["string","null"],"description":"Autofixer phase: \"analyzing\", \"analyzed\", \"fixing\", \"fix_ready\", \"no_fix\",\n\"pr_created\", or NULL for non-autofixer runs."},"pr_number":{"type":["integer","null"],"format":"int32"},"pr_url":{"type":["string","null"]},"preview_url":{"type":["string","null"]},"project_id":{"type":"integer","format":"int32"},"prompt_text":{"type":["string","null"],"description":"Final assembled prompt the AI CLI actually saw (trigger context block +\nYAML prompt, with error-group fields interpolated). Captured once per\nrun. `None` for pre-migration rows."},"run_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AutofixRunConfig","description":"Per-run AI options the user chose when starting an autofixer run\n(provider, model, max_turns, branch). NULL for generic agent runs\nand historical rows. Used to prefill the retry dialog."}]},"sandbox_enabled":{"type":"boolean","description":"Legacy field — all runs now execute in a sandbox. Kept for\nbackwards-compatible JSON shape; always `true`."},"source":{"type":"string","description":"`committed` (the run's config lives in `project_agents`) or\n`cli_ephemeral` (the config was uploaded via the CLI for a one-off\ndry run; see `ephemeral_yaml`)."},"started_at":{"type":["string","null"]},"status":{"type":"string"},"tokens_input":{"type":"integer","format":"int32"},"tokens_output":{"type":"integer","format":"int32"},"trigger_source_id":{"type":["integer","null"],"format":"int32"},"trigger_source_type":{"type":["string","null"]},"trigger_type":{"type":"string"},"user_context":{"type":["string","null"],"description":"User-provided context for this run (e.g. webhook payload, manual instructions)."}}},"AgentRunWithLogsResponse":{"type":"object","required":["run","logs"],"properties":{"logs":{"type":"array","items":{"$ref":"#/components/schemas/AgentRunLogResponse"}},"run":{"$ref":"#/components/schemas/AgentRunResponse"}}},"AgentSandboxSettings":{"type":"object","description":"Global agent sandbox settings. Controls whether agent runs are isolated\ninside Docker containers by default. Individual agents can override this.","properties":{"api_key_encrypted":{"type":["string","null"],"description":"DEPRECATED: use `providers[default_provider].credentials_encrypted` instead.","default":null},"auth_type":{"type":"string","description":"DEPRECATED: use `providers[default_provider].auth_type` instead.","default":"subscription"},"cpu_limit":{"type":"number","format":"double","description":"CPU limit in cores for sandbox containers","default":4.0,"example":4.0},"custom_image":{"type":"string","description":"Custom Docker image (only used when runtime is \"custom\").\nMust have git and claude CLI installed.","default":"","example":""},"default_provider":{"type":"string","description":"Default AI provider for agents: \"claude_cli\", \"opencode\", or \"codex_cli\".\nWorkspaces always use this provider — no per-session override.","default":"claude_cli","example":"claude_cli"},"enabled":{"type":"boolean","description":"Sandbox is always enabled — the executor refuses to run any agent\noutside a sandboxed container. Field is retained so existing settings\nrows still deserialize, but it is ignored at runtime.","default":true},"memory_limit_mb":{"type":"integer","format":"int64","description":"Memory limit in MB for sandbox containers","default":8192,"example":8192,"minimum":0},"network_mode":{"type":"string","description":"Network access level: \"full\" (unrestricted), \"restricted\" (Temps network only), \"none\" (no network)","default":"full","example":"full"},"providers":{"type":"object","description":"Per-provider auth + config. Keyed by provider id (e.g. `claude_cli`,\n`codex_cli`, `opencode`). Adding a new provider only requires a new\ncatalog entry on the Rust side — the JSON column stays migration-free.","default":{},"additionalProperties":{"$ref":"#/components/schemas/ProviderConfig"},"propertyNames":{"type":"string"}},"runtime":{"type":"string","description":"Runtime preset: \"node\", \"bun\", \"python\", \"rust\", \"go\", \"full\", or \"custom\"","default":"node","example":"node"},"sandbox_backend":{"type":["string","null"],"description":"Default isolation backend for sandboxes: \"docker\" (default) or\n\"firecracker\" (ADR-029; requires `temps firecracker setup`). Only\nconsulted when the Firecracker backend probes available — otherwise\nDocker is used regardless.","default":null,"example":"docker"}}},"AgentSandboxSettingsMasked":{"type":"object","description":"Agent sandbox settings with masked per-provider credentials.\nEach provider entry reports only whether a credential is saved, not\nthe encrypted blob itself. Non-sensitive fields (auth_type, default_model,\nextra) are passed through so the UI can render provider-specific state.","required":["default_provider","providers","api_key_saved","auth_type","enabled","runtime","custom_image","cpu_limit","memory_limit_mb","network_mode","sandbox_backend"],"properties":{"api_key_saved":{"type":"boolean"},"auth_type":{"type":"string"},"cpu_limit":{"type":"number","format":"double"},"custom_image":{"type":"string"},"default_provider":{"type":"string"},"enabled":{"type":"boolean"},"memory_limit_mb":{"type":"integer","format":"int64","minimum":0},"network_mode":{"type":"string"},"providers":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/ProviderConfigMasked"},"propertyNames":{"type":"string"}},"runtime":{"type":"string"},"sandbox_backend":{"type":"string"}}},"AggregatedBucketItem":{"type":"object","required":["timestamp","count"],"properties":{"count":{"type":"integer","format":"int64"},"timestamp":{"type":"string"}}},"AggregatedBucketsQuery":{"type":"object","description":"Query parameters for aggregated metrics by time bucket","required":["start_date","end_date"],"properties":{"aggregation_level":{"$ref":"#/components/schemas/AggregationLevel","description":"Aggregation level: events, sessions, or visitors"},"bucket_size":{"type":"string","description":"Time bucket size: \"1 hour\", \"1 day\", \"1 week\", etc. (default: \"1 hour\")"},"deployment_id":{"type":["integer","null"],"format":"int32","description":"Optional deployment filter"},"end_date":{"type":"string","format":"date-time","description":"End date for the query range"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Optional environment filter"},"start_date":{"type":"string","format":"date-time","description":"Start date for the query range"}}},"AggregatedBucketsResponse":{"type":"object","required":["bucket_size","aggregation_level","items","total"],"properties":{"aggregation_level":{"type":"string"},"bucket_size":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/AggregatedBucketItem"}},"total":{"type":"integer","format":"int64"}}},"AggregationLevel":{"type":"string","enum":["events","sessions","visitors"]},"AggregationTemporality":{"type":"string","description":"The aggregation temporality of a Sum/Histogram/ExponentialHistogram metric.\n\nMirrors OTel's `AggregationTemporality` proto enum: whether reported values\nare cumulative since the start of the series (Cumulative) or only the delta\nsince the previous report (Delta).","enum":["unspecified","delta","cumulative"]},"AiAgentBreakdownResponse":{"type":"object","description":"Response wrapping the AI agent breakdown rows.","required":["items","start_time","end_time"],"properties":{"end_time":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/AiAgentBreakdownRow"}},"start_time":{"type":"string"}}},"AiAgentBreakdownRow":{"type":"object","description":"One row in the AI-agent analytics breakdown. `agent` is the canonical\ncrawler name (e.g. `GPTBot`, `Claude-User`), `provider` is the vendor used\nfor grouping + logos. The UI mirrors the browsers card and ranks by\n`request_count`.","required":["provider","agent","purpose","request_count","unique_ips"],"properties":{"agent":{"type":"string"},"last_seen":{"type":["string","null"],"description":"Last-seen timestamp in RFC3339 format, or `None` if no rows matched.","example":"2026-05-29T12:00:00Z"},"provider":{"type":"string"},"purpose":{"type":"string"},"request_count":{"type":"integer","format":"int64"},"unique_ips":{"type":"integer","format":"int64"}}},"AiAgentDescriptor":{"type":"object","description":"Static descriptor for one entry in the known-AI-agents taxonomy.","required":["provider","agent","purpose"],"properties":{"agent":{"type":"string"},"provider":{"type":"string"},"purpose":{"type":"string"}}},"AiAgentPageRow":{"type":"object","description":"One row in the pages-by-agent breakdown. Returned by\n[`ProxyLogService::get_ai_agent_pages`] for a single named agent.\n`unique_ips` counts distinct client IPs that hit this path via that agent\n(same definition as the per-agent unique-IPs in [`AiAgentBreakdownRow`]).","required":["path","request_count","unique_ips"],"properties":{"last_seen":{"type":["string","null"],"description":"Last-seen timestamp in RFC3339 format, or `None` if no rows matched.","example":"2026-05-29T12:00:00Z"},"path":{"type":"string"},"request_count":{"type":"integer","format":"int64"},"unique_ips":{"type":"integer","format":"int64"}}},"AiAgentPagesResponse":{"type":"object","description":"Response wrapping the per-agent pages breakdown rows.","required":["agent","items","start_time","end_time"],"properties":{"agent":{"type":"string","description":"The agent name this breakdown is scoped to."},"end_time":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/AiAgentPageRow"}},"start_time":{"type":"string"}}},"AiAgentTimelineResponse":{"type":"object","description":"Response wrapping the AI agent timeline rows.","required":["items","start_time","end_time","bucket","group_by"],"properties":{"bucket":{"type":"string","description":"Bucket interval used for the buckets (so the UI can label the x-axis).","example":"1 hour"},"end_time":{"type":"string"},"group_by":{"type":"string","description":"Echoes the grouping dimension actually applied.","example":"provider"},"items":{"type":"array","items":{"$ref":"#/components/schemas/AiAgentTimelineRow"}},"start_time":{"type":"string"}}},"AiAgentTimelineRow":{"type":"object","description":"One point in the AI-agent timeline: the request count for a single\n(`bucket`, `key`) pair, where `key` is a provider or agent name depending on\nthe requested grouping. The UI pivots these into one stacked series per\n`key` across the shared bucket x-axis.","required":["bucket","key","request_count"],"properties":{"bucket":{"type":"string","description":"Bucket start in RFC3339 format.","example":"2026-05-29T12:00:00Z"},"key":{"type":"string","description":"Provider or agent name this count belongs to.","example":"OpenAI"},"request_count":{"type":"integer","format":"int64"}}},"AiChatLimitsSettings":{"type":"object","description":"Bounds on one AI chat turn.\n\nA turn is bounded by TIME rather than by a number of steps. A step count\nsays nothing about cost or about how long someone has been watching a\nspinner, and it cuts short exactly the long, productive turns the chat\nexists for. The user can already see each tool call and press Stop; the\ndeadline is what guarantees an *unattended* turn still ends.\n\nThe right value is a property of the model, which is why it is configurable\nrather than compiled in: a full alert-suggestion turn takes ~10 minutes\nagainst a slow local model and seconds against a hosted one.","properties":{"turn_timeout_secs":{"type":"integer","format":"int32","description":"How long one turn may run before it is stopped and the partial answer\nreturned, in seconds. The user is told the turn was cut short.\n\nChecked between steps, not mid-call: a model round already in flight\nfinishes, so a turn can overrun by up to one round. Against a slow\nself-hosted model that is a minute or two. Aborting mid-stream would cut\nthe answer off in the middle of a sentence and throw away work already\npaid for, which is worse than a late stop.","default":900,"example":900,"maximum":3600,"minimum":30}}},"AiConfigSettings":{"type":"object","description":"Global AI configuration settings. Controls the default config repo\ncontaining `.claude/` directory (skills, MCP servers, plugins) that\ngets overlaid into every agent sandbox.","properties":{"config_repo":{"type":"string","description":"Global config repo URL in \"owner/repo\" format (e.g. \"myorg/claude-config\").\nCloned at agent run time and overlaid into the sandbox's `.claude/` directory.","default":"","example":""},"config_repo_branch":{"type":"string","description":"Branch of the config repo to use.","default":"main","example":"main"}}},"AiPageBreakdownResponse":{"type":"object","description":"Response wrapping the AI page breakdown rows.","required":["items","start_time","end_time"],"properties":{"end_time":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/AiPageBreakdownRow"}},"start_time":{"type":"string"}}},"AiPageBreakdownRow":{"type":"object","description":"One row in the AI-crawled-pages breakdown. `agent_count` is the number of\n*distinct* AI agents that hit this path, so the UI can show both how heavily\nand how broadly a page is being crawled.","required":["path","request_count","agent_count"],"properties":{"agent_count":{"type":"integer","format":"int64"},"last_seen":{"type":["string","null"],"description":"Last-seen timestamp in RFC3339 format, or `None` if no rows matched.","example":"2026-05-29T12:00:00Z"},"path":{"type":"string"},"request_count":{"type":"integer","format":"int64"}}},"AiStatusBreakdownResponse":{"type":"object","description":"Response wrapping the AI status breakdown rows.","required":["items","start_time","end_time"],"properties":{"end_time":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/AiStatusBreakdownRow"}},"start_time":{"type":"string"}}},"AiStatusBreakdownRow":{"type":"object","description":"One row in the AI-agent HTTP status breakdown: the request count for a\nstatus class (`2xx`/`3xx`/`4xx`/`5xx`/`other`) across crawler traffic.","required":["status_class","request_count"],"properties":{"request_count":{"type":"integer","format":"int64"},"status_class":{"type":"string","description":"Status class label.","example":"2xx"}}},"AlarmListResponse":{"type":"object","description":"Paginated list of alarms.","required":["items","total","page","page_size"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AlarmResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"AlarmResponse":{"type":"object","description":"Full alarm representation returned by list/summary endpoints.","required":["id","project_id","alarm_type","severity","status","title","fired_at","created_at","updated_at"],"properties":{"acknowledged_at":{"type":["string","null"],"description":"ISO-8601 UTC timestamp when the alarm was acknowledged, if any."},"acknowledged_by":{"type":["integer","null"],"format":"int32","description":"User ID who acknowledged the alarm, if any."},"alarm_type":{"type":"string"},"container_id":{"type":["integer","null"],"format":"int32"},"created_at":{"type":"string","description":"ISO-8601 UTC timestamp when the row was created."},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"fired_at":{"type":"string","description":"ISO-8601 UTC timestamp when the alarm fired."},"id":{"type":"integer","format":"int32"},"message":{"type":["string","null"]},"metadata":{"description":"Arbitrary JSON metadata attached by the alarm source."},"project_id":{"type":"integer","format":"int32"},"resolved_at":{"type":["string","null"],"description":"ISO-8601 UTC timestamp when the alarm was resolved, if any."},"service_id":{"type":["integer","null"],"format":"int32"},"severity":{"type":"string"},"status":{"type":"string"},"title":{"type":"string"},"updated_at":{"type":"string","description":"ISO-8601 UTC timestamp when the row was last updated."}}},"AlarmSummaryResponse":{"type":"object","description":"Re-export AlarmSummary for the OpenAPI schema.","required":["total_active","firing","acknowledged","critical","warning","by_type"],"properties":{"acknowledged":{"type":"integer","format":"int32","minimum":0},"by_type":{"type":"object","additionalProperties":{"type":"integer","format":"int32","minimum":0},"propertyNames":{"type":"string"}},"critical":{"type":"integer","format":"int32","minimum":0},"firing":{"type":"integer","format":"int32","minimum":0},"total_active":{"type":"integer","format":"int32","minimum":0},"warning":{"type":"integer","format":"int32","minimum":0}}},"AlertRuleResponse":{"type":"object","required":["id","project_id","name","trigger_type","trigger_config","notification_priority","cooldown_minutes","enabled","created_at","updated_at"],"properties":{"cooldown_minutes":{"type":"integer","format":"int32"},"created_at":{"type":"string"},"enabled":{"type":"boolean"},"environment_filter":{"type":["integer","null"],"format":"int32"},"error_level_filter":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"notification_priority":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"trigger_config":{},"trigger_type":{"type":"string"},"updated_at":{"type":"string"}}},"AllocEntry":{"type":"object","description":"Wire-format allocation. `null` in the JSON when the node hasn't been\nallocated yet — workers should treat that as \"single-host mode, do\nnot bring up the overlay\".","required":["node_id","compute_cidr","bridge_address","underlay_address"],"properties":{"bridge_address":{"type":"string"},"compute_cidr":{"type":"string"},"node_id":{"type":"string","description":"Stable v5 UUID derived from the database node id."},"underlay_address":{"type":"string"}}},"AnalyticsSessionEventsResponse":{"type":"object","required":["session_id","events","total_events"],"properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/SessionEvent"}},"session_id":{"type":"string"},"total_events":{"type":"integer","minimum":0}}},"AnnotatedSpan":{"type":"object","description":"A single span annotated with the project that originally stored it.\nUsed in `UnifiedTrace` to let the UI colour-code spans by project.","required":["project_id","project_name","span"],"properties":{"project_id":{"type":"integer","format":"int32","description":"The project that stored this span (same as `span.project_id`)."},"project_name":{"type":"string","description":"Human-readable project name for waterfall colour-coding and legend."},"span":{"$ref":"#/components/schemas/SpanRecord","description":"Original span data verbatim from storage."}}},"AnomalyAlgorithm":{"type":"string","description":"Anomaly baseline algorithm. Adding one (e.g. a new robust variant) is a\ncode-only enum addition — no migration, since it lives inside the blob.","enum":["robust","basic","agile","ewma"]},"AnomalyParams":{"type":"object","description":"Seasonal anomaly-band detector parameters (stub — not yet evaluated).","properties":{"algorithm":{"$ref":"#/components/schemas/AnomalyAlgorithm","description":"Baseline model. `robust` is the default (seasonal, stable, flags level\nshifts); `ewma`/`agile` adopt level shifts; `basic` is non-seasonal."},"baseline_lookback_days":{"type":["integer","null"],"format":"int32","description":"How far back to build the baseline. `None` = an evaluator default."},"deviations":{"type":"number","format":"double","description":"Band width in robust standard deviations (Datadog's `bounds`)."},"direction":{"$ref":"#/components/schemas/Direction","description":"Which side(s) of the band a deviation must be on to count."},"pct_anomalous":{"type":"number","format":"double","description":"Fraction (0..=1) of points in the window that must be anomalous to fire."},"seasonality":{"$ref":"#/components/schemas/Seasonality","description":"Seasonality model for the baseline."}}},"AnomalyPreviewPointResponse":{"type":"object","required":["bucket","value","lower","upper","breaching"],"properties":{"breaching":{"type":"boolean"},"bucket":{"type":"string","example":"2025-10-12T12:15:47Z"},"lower":{"type":"number","format":"double","description":"Lower edge of the expected band at this point."},"upper":{"type":"number","format":"double","description":"Upper edge of the expected band at this point."},"value":{"type":"number","format":"double"}}},"AnomalyPreviewRequest":{"type":"object","required":["project_id","metric_name","aggregation","window_secs","detection_config"],"properties":{"aggregation":{"type":"string","description":"One of `avg|sum|min|max|count|rate|p50|p90|p95|p99`."},"detection_config":{"$ref":"#/components/schemas/DetectionConfig","description":"The detector to backtest. `static` and `anomaly` are supported — the\nkinds the evaluator actually runs."},"end_time":{"type":["string","null"],"description":"RFC 3339; defaults to now.","example":"2025-10-12T12:15:47Z"},"metric_name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"start_time":{"type":["string","null"],"description":"RFC 3339; defaults to 7 days before `end_time`.","example":"2025-10-12T12:15:47Z"},"window_secs":{"type":"integer","format":"int32"}}},"AnomalyPreviewResponse":{"type":"object","required":["points","breach_count","baseline_samples","sufficient"],"properties":{"baseline_samples":{"type":"integer","format":"int64","description":"Baseline sample count (drives the `sufficient` flag)."},"breach_count":{"type":"integer","format":"int64","description":"How many points in the range would have fired."},"points":{"type":"array","items":{"$ref":"#/components/schemas/AnomalyPreviewPointResponse"}},"sufficient":{"type":"boolean","description":"Whether the baseline had enough history for a trustworthy band."}}},"ApiKeyListResponse":{"type":"object","required":["api_keys","total"],"properties":{"api_keys":{"type":"array","items":{"$ref":"#/components/schemas/ApiKeyResponse"}},"total":{"type":"integer","format":"int64","minimum":0}}},"ApiKeyResponse":{"type":"object","required":["id","name","key_prefix","role_type","is_active","created_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00Z"},"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"key_prefix":{"type":"string"},"last_used_at":{"type":["string","null"],"format":"date-time","example":"2024-01-01T00:00:00Z"},"name":{"type":"string"},"permissions":{"type":["array","null"],"items":{"type":"string"}},"role_type":{"type":"string"}}},"AppSettings":{"type":"object","description":"Application settings stored in the database\nAll fields have sensible defaults for easy onboarding","properties":{"agent_sandbox":{"oneOf":[{"$ref":"#/components/schemas/AgentSandboxSettings"}],"default":{"default_provider":"claude_cli","providers":{},"auth_type":"subscription","api_key_encrypted":null,"enabled":true,"runtime":"node","custom_image":"","cpu_limit":4.0,"memory_limit_mb":8192,"network_mode":"full","sandbox_backend":null}},"ai_chat_limits":{"oneOf":[{"$ref":"#/components/schemas/AiChatLimitsSettings","description":"Limits on a single AI chat turn. Operator-tunable because the right\nvalue depends on the model: a turn against a slow self-hosted model can\nlegitimately take ten minutes, while a hosted one finishes in seconds\nand a shorter ceiling keeps costs predictable."}],"default":{"turn_timeout_secs":900}},"ai_config":{"oneOf":[{"$ref":"#/components/schemas/AiConfigSettings"}],"default":{"config_repo":"","config_repo_branch":"main"}},"build_limits":{"oneOf":[{"$ref":"#/components/schemas/BuildLimitsSettings","description":"Build-time resource limits applied on the control plane to prevent\n`docker build` from saturating host CPU/RAM. Worker nodes are\nintentionally NOT subject to these limits (each worker is dedicated\nhardware that already has its own per-host headroom)."}],"default":{"max_concurrent":2,"cpu_limit_cores":0.0,"memory_limit_mb":0}},"cluster_dns":{"oneOf":[{"$ref":"#/components/schemas/ClusterDnsSettings","description":"Cluster-DNS resolver settings (ADR-024, experimental beta). Off by\ndefault — see `ClusterDnsSettings` for the incident background and\ntrade-offs. Must be explicitly enabled by operators who need\n`*.temps.local` service-to-service resolution inside containers."}],"default":{"enabled":false}},"console_version":{"type":["string","null"],"description":"Binary version tag (e.g. \"v0.1.0\") of the *console* process\n(`temps serve`, role=all or role=console) that last started. Written\non console startup; read by the standalone `temps proxy` to detect\nversion skew during a rolling upgrade (ADR-017 Phase 3). `None` on\ninstalls that never ran a console build carrying this field.\n\nThis is informational state written by the binary itself — NOT an\noperator-tunable setting. It is intentionally absent from\n`AppSettingsResponse` and the PATCH path so an operator cannot\naccidentally overwrite the self-recorded value.","default":null},"container_logs":{"oneOf":[{"$ref":"#/components/schemas/ContainerLogSettings"}],"default":{"max_size":"50m","max_file":3,"service_max_size":"20m","service_max_file":3}},"disk_space_alert":{"oneOf":[{"$ref":"#/components/schemas/DiskSpaceAlertSettings"}],"default":{"enabled":true,"threshold_percent":80,"check_interval_seconds":300,"monitor_path":null}},"dns_provider":{"oneOf":[{"$ref":"#/components/schemas/DnsProviderSettings"}],"default":{"provider":"manual","cloudflare_api_key":null}},"docker_registry":{"oneOf":[{"$ref":"#/components/schemas/DockerRegistrySettings"}],"default":{"enabled":false,"registry_url":null,"username":null,"password":null,"tls_verify":true,"ca_certificate":null}},"edge_target":{"type":["string","null"],"description":"Public edge target that generated DNS records point at when a managed\ndomain opts into automatic record sync. An IPv4/IPv6 address produces an\n`A`/`AAAA` record; anything else is treated as a `CNAME` target. `None`\ndisables DNS record sync regardless of per-domain opt-in.","default":null},"external_url":{"type":["string","null"],"default":null},"insecure_tls":{"type":"boolean","description":"Skip TLS certificate verification on outbound HTTP clients built by the\nserver (deployer, agent, remote service client). Strictly opt-in for\noperators running self-signed control plane / worker certs on a trusted\ninternal network. Worker→control-plane traffic that traverses the public\ninternet must keep this `false` — otherwise a MitM steals the join token.","default":false},"internal_url":{"type":["string","null"],"description":"URL that service containers use to reach the Temps API from *inside*\nthe Docker network (OTLP metrics ingest, agent callbacks, etc.). On\nDocker Desktop this defaults to `http://host.docker.internal:`;\non Linux it requires the `host.docker.internal:host-gateway` host\nmapping (which Temps adds to provisioned containers). Distinct from\n`external_url`, which is the public-facing address.","default":null},"letsencrypt":{"oneOf":[{"$ref":"#/components/schemas/LetsEncryptSettings"}],"default":{"email":null,"environment":"production"}},"monitoring":{"oneOf":[{"$ref":"#/components/schemas/MonitoringSettings","description":"Metrics observability settings. Controls the MetricsStore backend,\nscrape interval, and tiered retention windows."}],"default":{"enabled":false,"store":"timescale_db","scrape_interval_secs":30,"retention_raw_days":7,"retention_hourly_days":90,"retention_daily_years":2,"clickhouse_url":null}},"multi_node":{"oneOf":[{"$ref":"#/components/schemas/MultiNodeSettings"}],"default":{"join_token_hash":null,"private_address":null,"legacy_shared_token_enabled":true,"cluster_ca_cert_pem":null,"cluster_ca_key_encrypted":null,"require_mtls":false,"node_cpu_alert_percent":90.0,"node_memory_alert_percent":90.0,"node_disk_alert_percent":90.0}},"observability_compression":{"oneOf":[{"$ref":"#/components/schemas/ObservabilityCompressionSettings","description":"TimescaleDB compression delays for immutable observability data.\nChanges are applied at runtime by the Settings API."}],"default":{"proxy_logs_after_hours":24,"otel_spans_after_hours":24}},"observability_retention":{"oneOf":[{"$ref":"#/components/schemas/ObservabilityRetentionSettings","description":"Retention windows for raw proxy and OpenTelemetry telemetry.\nTimescaleDB policies are updated at runtime by the Settings API."}],"default":{"proxy_logs_days":30,"otel_spans_days":90,"otel_logs_days":90,"otel_metrics_days":90}},"on_demand_tls":{"oneOf":[{"$ref":"#/components/schemas/OnDemandTlsSettings"}],"default":{"enabled":false,"zone":null,"max_concurrent":3,"hourly_cap":10,"deployment_url_mode":"http"}},"preview_domain":{"type":"string","default":"localho.st"},"preview_gateway":{"oneOf":[{"$ref":"#/components/schemas/PreviewGatewaySettings"}],"default":{"image":"ghcr.io/gotempsh/temps-preview-gateway:latest","host_port":8090,"auto_upgrade":true}},"rate_limiting":{"oneOf":[{"$ref":"#/components/schemas/RateLimitSettings"}],"default":{"enabled":false,"max_requests_per_minute":60,"max_requests_per_hour":1000,"whitelist_ips":[],"blacklist_ips":[]}},"require_mfa_for_admins":{"type":"boolean","description":"When `true`, any user holding the `Admin` role must have MFA enrolled\n(`users.mfa_enabled = true`) to complete a **password** login. Users\nwithout MFA enrolled are rejected with a typed error instructing them\nto enroll before retrying. This only gates the password-login path\n(`AuthService::login`) -- SSO/OIDC logins are handled by a separate\ncode path (`OidcService::resolve_user` + `oidc_handler`) and are\nintentionally unaffected, since federating identity to a\nproperly-hardened IdP is itself an acceptable alternative to local\nTOTP MFA. Modeled as a settings row (not an env var) per CLAUDE.md so\nan operator can flip it at runtime via the Settings API without\nrestarting the binary.","default":false},"screenshots":{"oneOf":[{"$ref":"#/components/schemas/ScreenshotSettings"}],"default":{"enabled":false,"provider":"local","url":""}},"security_headers":{"oneOf":[{"$ref":"#/components/schemas/SecurityHeadersSettings"}],"default":{"enabled":false,"preset":"moderate","content_security_policy":"default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self'; frame-ancestors 'self'","x_frame_options":"SAMEORIGIN","x_content_type_options":"nosniff","x_xss_protection":"1; mode=block","strict_transport_security":"max-age=31536000; includeSubDomains","referrer_policy":"strict-origin-when-cross-origin","permissions_policy":"geolocation=(), microphone=(), camera=()"}},"self_update":{"oneOf":[{"$ref":"#/components/schemas/SelfUpdateSettings","description":"One-click \"Update now\" from the console. Enabled by default; an admin\ncan turn it off here to keep upgrades on the CLI/config-management path.\n\nThis is the *soft* switch — it is stored in the database, so whoever can\nwrite settings can also turn it back on. Operators who need an upgrade\npath that no console session can re-open should start the server with\n`--disable-self-update`, which wins over this field unconditionally."}],"default":{"enabled":true,"channel":null}},"setup_complete":{"type":"boolean","description":"Set to `true` by `temps setup` (all modes) once initial configuration\nhas been applied. The web onboarding wizard reads this from the server\nand skips itself when true, preventing the \"Configure Base Domain\" wall\nfrom appearing on installs that were already configured via the CLI.","default":false}}},"AppSettingsResponse":{"type":"object","description":"Safe response for application settings that masks sensitive fields","required":["preview_domain","screenshots","letsencrypt","dns_provider","security_headers","rate_limiting","docker_registry","disk_space_alert","container_logs","agent_sandbox","ai_config","preview_gateway","multi_node","monitoring","observability_compression","observability_retention","effective_metrics_store","effective_observability_store","insecure_tls","setup_complete","require_mfa_for_admins","cluster_dns","build_limits","ai_chat_limits","self_update"],"properties":{"agent_sandbox":{"$ref":"#/components/schemas/AgentSandboxSettingsMasked"},"ai_chat_limits":{"$ref":"#/components/schemas/AiChatLimitsSettings","description":"Per-turn limits for the AI chat. No sensitive content."},"ai_config":{"$ref":"#/components/schemas/AiConfigSettings"},"build_limits":{"$ref":"#/components/schemas/BuildLimitsSettings","description":"Build-time resource limits (control-plane only). No sensitive content,\npassed through as-is."},"cluster_dns":{"$ref":"#/components/schemas/ClusterDnsSettings","description":"Cluster-DNS resolver settings (ADR-024, experimental beta). No masking\nneeded — `enabled` is a plain bool with no sensitive content. Passed\nthrough as-is so the settings UI can read and toggle the flag."},"container_logs":{"$ref":"#/components/schemas/ContainerLogSettings"},"disk_space_alert":{"$ref":"#/components/schemas/DiskSpaceAlertSettings"},"dns_provider":{"$ref":"#/components/schemas/DnsProviderSettingsMasked"},"docker_registry":{"$ref":"#/components/schemas/DockerRegistrySettingsMasked"},"edge_target":{"type":["string","null"],"description":"Public edge target that synced DNS records point at (IP → A/AAAA, else CNAME)."},"effective_metrics_store":{"$ref":"#/components/schemas/MetricsStoreKind","description":"The storage backend the runtime is **actually** using for metrics,\nafter reconciling the `monitoring.store` toggle with the server's\n`TEMPS_CLICKHOUSE_*` configuration. When `monitoring.store` is\n`click_house` but those env vars are not fully set, the runtime falls\nback to TimescaleDB — in that case this reports `timescale_db` even\nthough `monitoring.store` says `click_house`. The UI shows this as the\neffective backend and warns when it diverges from the configured store."},"effective_observability_store":{"$ref":"#/components/schemas/MetricsStoreKind","description":"Storage backend actually used for proxy logs, OTel spans, and OTel\nmetrics. OTel logs remain TimescaleDB-backed. Unlike resource metrics,\nthese domains switch to ClickHouse whenever the server-level ClickHouse\nconnection is configured; they do not use the monitoring store toggle."},"external_url":{"type":["string","null"]},"insecure_tls":{"type":"boolean"},"internal_url":{"type":["string","null"]},"letsencrypt":{"$ref":"#/components/schemas/LetsEncryptSettings"},"monitored_services_count":{"type":["integer","null"],"format":"int64","description":"Number of enabled, running services the MetricsScraper currently\nincludes. Used for the lightweight storage estimate in the UI.","minimum":0},"monitoring":{"$ref":"#/components/schemas/MonitoringSettingsMasked"},"multi_node":{"$ref":"#/components/schemas/MultiNodeSettingsMasked"},"observability_compression":{"$ref":"#/components/schemas/ObservabilityCompressionSettings","description":"TimescaleDB compression delays for immutable proxy logs and OTel spans."},"observability_retention":{"$ref":"#/components/schemas/ObservabilityRetentionSettings","description":"Retention windows for raw proxy logs and OpenTelemetry data."},"preview_domain":{"type":"string"},"preview_gateway":{"$ref":"#/components/schemas/PreviewGatewaySettingsMasked"},"rate_limiting":{"$ref":"#/components/schemas/RateLimitSettings"},"require_mfa_for_admins":{"type":"boolean","description":"When enabled, Admin-role accounts without MFA enrolled are rejected\nat password login (bherila/temps#32). SSO/OIDC logins are unaffected."},"screenshots":{"$ref":"#/components/schemas/ScreenshotSettings"},"security_headers":{"$ref":"#/components/schemas/SecurityHeadersSettings"},"self_update":{"$ref":"#/components/schemas/SelfUpdateSettings","description":"Whether admins may apply a release from the console. This is the\ndatabase-backed toggle only — a server started with\n`--disable-self-update` refuses regardless of what this says, which\n`GET /settings/update` reports as the authoritative answer."},"setup_complete":{"type":"boolean","description":"Whether `temps setup` has been run at least once. The web onboarding\nwizard checks this field on load and skips itself when true."}}},"ApplyHostnameModeRequest":{"type":"object","description":"Request to apply a hostname mode (recompute + optional DNS sync).","required":["mode"],"properties":{"mode":{"type":"string","description":"Target mode to apply: `\"standard\"` or `\"flat\"`."},"sync_dns":{"type":"boolean","description":"Also reconcile the provider's DNS zone for the affected hostnames."}}},"ArchiveFlagResponse":{"type":"object","required":["key"],"properties":{"archived_at":{"type":["string","null"]},"key":{"type":"string"}}},"ArchiveMode":{"type":"string","enum":["off","on","always","unknown"]},"AssignRoleRequest":{"type":"object","required":["user_id","role_type"],"properties":{"role_type":{"type":"string"},"user_id":{"type":"integer","format":"int32"}}},"AttachScheduleServicesRequest":{"type":"object","description":"Body for `POST /api/backups/schedules/{id}/services` — attach external\nservices to a backup schedule. Idempotent.","required":["service_ids"],"properties":{"service_ids":{"type":"array","items":{"type":"integer","format":"int32"},"description":"External service ids to attach. Duplicates are de-duplicated server-side."}}},"AttachScheduleServicesResponse":{"type":"object","description":"Response for `POST /api/backups/schedules/{id}/services`.","required":["inserted","total_attached"],"properties":{"inserted":{"type":"integer","format":"int64","description":"Number of rows actually inserted (excludes rows skipped by\n`ON CONFLICT DO NOTHING`).","minimum":0},"total_attached":{"type":"integer","description":"Total number of services now attached to the schedule.","minimum":0}}},"AuditLogIpInfo":{"type":"object","description":"IP address information in audit log","required":["ip"],"properties":{"city":{"type":["string","null"],"description":"City name","example":"San Francisco"},"country":{"type":["string","null"],"description":"Country code","example":"US"},"ip":{"type":"string","description":"IP address","example":"192.168.1.1"},"latitude":{"type":["number","null"],"format":"double","description":"Latitude","example":37.7749},"longitude":{"type":["number","null"],"format":"double","description":"Longitude","example":122.4194}}},"AuditLogResponse":{"type":"object","description":"Response type for audit log entries","required":["id","operation_type","audit_date"],"properties":{"audit_date":{"type":"integer","format":"int64","description":"When the action occurred","example":11932193},"data":{"description":"Additional context about the action"},"id":{"type":"integer","format":"int32","description":"Unique identifier for the audit log entry"},"ip_address":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AuditLogIpInfo","description":"IP address details"}]},"operation_type":{"type":"string","description":"The type of action that was performed","example":"USER_LOGIN"},"user":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AuditLogUserInfo","description":"User details who performed the action"}]},"user_id":{"type":["integer","null"],"format":"int32","description":"The user who performed the action (`null` when that account has\nsince been deleted; `data` retains the original actor context)"}}},"AuditLogUserInfo":{"type":"object","description":"User information in audit log","required":["id","name","email"],"properties":{"email":{"type":"string","description":"User's email","example":"john.doe@example.com"},"id":{"type":"integer","format":"int32","description":"User ID"},"name":{"type":"string","description":"User's name","example":"John Doe"}}},"AuthFlavorDto":{"type":"object","description":"One auth flavor surfaced to the UI. Mirrors `AuthFlavor` in the catalog\nbut without the seed-path / env-var fields the frontend doesn't need\n(those are server-side only — exposing them just bloats the response).","required":["id","label","description","format"],"properties":{"description":{"type":"string"},"env_var":{"type":["string","null"],"description":"For `api_key` format: the env var name that will be set inside the\nsandbox. Useful for showing the user \"we'll set OPENAI_API_KEY\" so\nthey know what their key controls."},"format":{"type":"string","description":"`api_key`, `oauth_token`, or `config_file` — drives which input UI\nthe settings page renders (single-line vs. multi-line textarea)."},"id":{"type":"string"},"label":{"type":"string"}}},"AuthResponse":{"type":"object","required":["success","message","mfa_required","mfa_enrollment_required","password_change_required"],"properties":{"message":{"type":"string"},"mfa_enrollment_required":{"type":"boolean"},"mfa_required":{"type":"boolean"},"mfa_setup":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/MfaSetupResponse"}]},"password_change_required":{"type":"boolean"},"success":{"type":"boolean"},"user_id":{"type":["integer","null"],"format":"int32"}}},"AuthStatusResponse":{"type":"object","required":["status"],"properties":{"cli_token":{"type":["string","null"]},"status":{"type":"string"}}},"AuthTokenResponse":{"type":"object","required":["access_token","refresh_token","expires_at"],"properties":{"access_token":{"type":"string"},"expires_at":{"type":"integer","format":"int64"},"refresh_token":{"type":"string"}}},"AutoWatchParams":{"type":"object","description":"Auto-watch (Watchdog-style) detector parameters (stub — not evaluated).","properties":{"direction":{"$ref":"#/components/schemas/Direction","description":"The engine self-tunes the band; the user supplies only the direction."}}},"AutofixRunConfig":{"type":"object","description":"User-chosen per-run options, persisted as JSON in `agent_runs.run_config`.\nEvery field is optional — unset fields fall back to the provider defaults\nin settings, then to built-in defaults.","properties":{"branch":{"type":["string","null"],"description":"Branch to clone instead of the project's main branch.","default":null},"max_turns":{"type":["integer","null"],"format":"int32","description":"Per-run turn cap applied to every phase of this run. Only enforced\nfor CLIs with a turn flag (Claude Code); Codex/OpenCode run to\ncompletion. `None` uses the provider's per-phase defaults.","default":null},"model":{"type":["string","null"],"description":"Model id for the chosen provider. `None` uses the provider's saved\ndefault model, or the CLI's own default.","default":null},"provider":{"type":["string","null"],"description":"AI provider id (\"claude_cli\", \"codex_cli\", \"opencode\"). `None` uses\nthe platform default provider from agent sandbox settings.","default":null}}},"AutofixerRunResponse":{"type":"object","required":["id","project_id","status","tokens_input","tokens_output","files_changed","created_at"],"properties":{"ai_model":{"type":["string","null"]},"ai_output":{"type":["string","null"]},"ai_provider":{"type":["string","null"],"description":"AI provider slug this run executes with (e.g. claude_cli, codex_cli)."},"analysis":{"type":["string","null"]},"branch_name":{"type":["string","null"]},"completed_at":{"type":["string","null"]},"created_at":{"type":"string"},"error_message":{"type":["string","null"]},"files_changed":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"phase":{"type":["string","null"]},"pr_number":{"type":["integer","null"],"format":"int32"},"pr_url":{"type":["string","null"]},"project_id":{"type":"integer","format":"int32"},"run_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AutofixRunConfig","description":"Per-run options the run was started with; used to prefill the\nretry / start-over dialog."}]},"started_at":{"type":["string","null"]},"status":{"type":"string"},"tokens_input":{"type":"integer","format":"int32"},"tokens_output":{"type":"integer","format":"int32"},"trigger_source_id":{"type":["integer","null"],"format":"int32"},"user_context":{"type":["string","null"]}}},"AutofixerRunWithLogsResponse":{"type":"object","required":["run","logs"],"properties":{"logs":{"type":"array","items":{"$ref":"#/components/schemas/AgentRunLogResponse"}},"run":{"$ref":"#/components/schemas/AutofixerRunResponse"}}},"AvailableContainerInfo":{"type":"object","description":"Available Docker container that can be imported as a service","required":["container_id","container_name","image","version","service_type","is_running"],"properties":{"container_id":{"type":"string","description":"Container ID or name","example":"abc123def456"},"container_name":{"type":"string","description":"Container display name","example":"my-postgres"},"exposed_ports":{"type":"array","items":{"type":"integer","format":"int32","minimum":0},"description":"Exposed ports (e.g., [5432] for PostgreSQL, [6379] for Redis)"},"image":{"type":"string","description":"Docker image name (e.g., \"gotempsh/postgres-walg:18-bookworm\")","example":"gotempsh/postgres-walg:18-bookworm"},"is_running":{"type":"boolean","description":"Whether the container is currently running","example":true},"service_type":{"$ref":"#/components/schemas/ServiceTypeRoute","description":"Service type this container represents"},"version":{"type":"string","description":"Extracted version from image","example":"18"}}},"AvailablePermissions":{"type":"object","description":"Response containing all available permissions for frontend validation","required":["permissions","roles"],"properties":{"permissions":{"type":"array","items":{"$ref":"#/components/schemas/PermissionInfo"},"description":"All available permissions in the system"},"roles":{"type":"array","items":{"$ref":"#/components/schemas/RoleInfo"},"description":"All available roles"}}},"BackupAlertListResponse":{"type":"object","description":"Response body for the list-backup-alerts endpoint.","required":["alerts"],"properties":{"alerts":{"type":"array","items":{"$ref":"#/components/schemas/BackupAlertResponse"},"description":"All currently open (unresolved) alerts, newest first."}}},"BackupAlertResponse":{"type":"object","description":"A single open backup alert surfaced in the UI banner.\n\nAlerts are auto-opened by the watcher and auto-resolved when the triggering\ncondition clears. No manual dismiss is required or supported.\n\nThe optional `schedule_s3_source_id` field is included so the UI can\ndeep-link an `overdue_schedule` alert to the S3 source detail page that\nhosts the schedule. `stalled_job` alerts no longer carry a deep-link\ntarget — the alert message text contains the backup id for display.","required":["id","kind","severity","message","opened_at"],"properties":{"id":{"type":"integer","format":"int64","description":"Database id of the alert row."},"kind":{"type":"string","description":"`\"overdue_schedule\"` or `\"stalled_job\"`."},"message":{"type":"string","description":"Human-readable description of the alert condition."},"opened_at":{"type":"string","description":"RFC 3339 timestamp when the alert was opened.","example":"2026-05-15T10:00:00Z"},"schedule_id":{"type":["integer","null"],"format":"int32","description":"FK to `backup_schedules.id`. Set for `overdue_schedule` alerts."},"schedule_name":{"type":["string","null"],"description":"Human-readable name of the linked schedule, if applicable."},"schedule_s3_source_id":{"type":["integer","null"],"format":"int32","description":"FK to `backup_schedules.s3_source_id`. The UI uses this to deep-link\nthe alert to the S3 source detail page that hosts the schedule.\nSet for `overdue_schedule` alerts."},"severity":{"type":"string","description":"`\"warning\"` or `\"critical\"`."}}},"BackupResponse":{"type":"object","description":"Response type for backup","required":["id","name","backup_id","backup_type","state","started_at","s3_source_id","s3_location","metadata","compression_type","created_by","tags"],"properties":{"attempts":{"type":["integer","null"],"format":"int32","description":"How many times this job has been claimed and run. `null` for legacy\nbackups with no `backup_jobs` row."},"backup_id":{"type":"string"},"backup_type":{"type":"string"},"checksum":{"type":["string","null"]},"completed_at":{"type":["integer","null"],"format":"int64"},"compression_type":{"type":"string"},"created_by":{"type":"integer","format":"int32"},"current_step":{"type":["string","null"],"description":"Name of the engine step currently executing (e.g., `\"walg_push\"`).\n`null` when no `backup_jobs` row exists for this backup (legacy rows\npre-dating ADR-014), or when the job has not yet completed its first step."},"error_message":{"type":["string","null"]},"expires_at":{"type":["integer","null"],"format":"int64"},"external_service":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ExternalServiceSummary","description":"External service that owns this backup (Redis, Postgres, etc.).\n`null` for control-plane backups (the Temps server's own database)."}]},"file_count":{"type":["integer","null"],"format":"int32"},"id":{"type":"integer","format":"int32"},"live_size_bytes":{"type":["integer","null"],"format":"int64","description":"Best-effort partial size while a backup is still running, computed\nby listing the S3 prefix. Null when the backup is finished\n(`size_bytes` is authoritative in that case)."},"max_attempts":{"type":["integer","null"],"format":"int32","description":"Maximum attempts before the job is permanently failed. `null` for\nlegacy backups."},"max_runtime_secs":{"type":["integer","null"],"format":"int64","description":"Resolved wall-clock timeout for this backup job (seconds). `null` for\nlegacy backups. Derived from the three-tier resolution order:\ncaller override → schedule override → engine default."},"metadata":{},"name":{"type":"string"},"s3_location":{"type":"string"},"s3_source_id":{"type":"integer","format":"int32"},"schedule_id":{"type":["integer","null"],"format":"int32"},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Final size of the backup once completed. Null while running."},"started_at":{"type":"integer","format":"int64"},"state":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}}}},"BackupScheduleResponse":{"type":"object","description":"Response type for backup schedule","required":["id","name","backup_type","retention_period","s3_source_id","schedule_expression","enabled","created_at","updated_at","tags","target_all_services","include_control_plane"],"properties":{"backup_type":{"type":"string"},"created_at":{"type":"integer","format":"int64"},"description":{"type":["string","null"]},"enabled":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"include_control_plane":{"type":"boolean","description":"When `true`, every run also produces a `control_plane` backup\n(Temps's own Postgres). When `false`, only the external service\nfan-out happens."},"last_run":{"type":["integer","null"],"format":"int64"},"max_runtime_secs":{"type":["integer","null"],"format":"int64","description":"Per-schedule wall-clock timeout override for backup jobs (seconds).\n`null` means the engine-family default is used. See\n`temps_backup_core::timeouts::default_max_runtime_secs`."},"name":{"type":"string"},"next_run":{"type":["integer","null"],"format":"int64"},"retention_period":{"type":"integer","format":"int32"},"s3_source_id":{"type":"integer","format":"int32"},"schedule_expression":{"type":"string","example":"0 0 * * *"},"tags":{"type":"array","items":{"type":"string"}},"target_all_services":{"type":"boolean","description":"When `true`, the schedule auto-includes every external service on\nthe host (and any future ones). When `false`, the schedule only\ntargets services attached via `backup_schedule_services`."},"updated_at":{"type":"integer","format":"int64"}}},"BitbucketAuthInput":{"oneOf":[{"type":"object","description":"Personal / Workspace / Repository Access Token.","required":["token","type"],"properties":{"token":{"type":"string","description":"The Bitbucket access token value."},"type":{"type":"string","enum":["access_token"]}}},{"type":"object","description":"HTTP Basic / App Password authentication.","required":["username","password","type"],"properties":{"password":{"type":"string","description":"App password generated in Bitbucket security settings."},"type":{"type":"string","enum":["app_password"]},"username":{"type":"string","description":"Bitbucket account username."}}}],"description":"Authentication input for a Bitbucket Cloud provider. Use `access_token` for\na Repository or Workspace Access Token (PAT), or `username` + `app_password`\nfor App Password (HTTP Basic) authentication."},"BlobResponse":{"type":"object","description":"Response after uploading a blob","required":["url","pathname","contentType","size","uploadedAt"],"properties":{"contentType":{"type":"string","description":"Content type of the blob","example":"image/png"},"pathname":{"type":"string","description":"Original pathname","example":"images/avatar-abc123.png"},"size":{"type":"integer","format":"int64","description":"Size in bytes","example":12345},"uploadedAt":{"type":"string","format":"date-time","description":"Upload timestamp","example":"2025-01-03T12:00:00Z"},"url":{"type":"string","description":"URL path to access the blob","example":"/api/blob/123/images/avatar-abc123.png"}}},"BlobStatusResponse":{"type":"object","description":"Response for Blob service status","required":["enabled","healthy"],"properties":{"docker_image":{"type":["string","null"],"description":"Docker image being used","example":"ghcr.io/rustfs/rustfs:0.5.0"},"enabled":{"type":"boolean","description":"Whether the Blob service is enabled","example":true},"healthy":{"type":"boolean","description":"Whether the service is healthy","example":true},"version":{"type":["string","null"],"description":"Current version (if running)","example":"0.5.0"}}},"BranchInfo":{"type":"object","required":["name","commit_sha","protected"],"properties":{"commit_sha":{"type":"string"},"name":{"type":"string"},"protected":{"type":"boolean"}}},"BranchListResponse":{"type":"object","required":["branches"],"properties":{"branches":{"type":"array","items":{"$ref":"#/components/schemas/BranchInfo"}}}},"BrowserCount":{"type":"object","required":["browser","count","percentage"],"properties":{"browser":{"type":"string"},"count":{"type":"integer","format":"int64"},"percentage":{"type":"number","format":"double"}}},"BrowsersQuery":{"type":"object","required":["start_date","end_date","project_id"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"BuildConfiguration":{"type":"object","description":"Build configuration (for building images from source)","required":["context","args"],"properties":{"args":{"type":"object","description":"Build arguments","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"context":{"type":"string","description":"Build context (Dockerfile path or buildpack)"},"dockerfile":{"type":["string","null"],"description":"Dockerfile path (relative to context)"},"target":{"type":["string","null"],"description":"Target stage (for multi-stage builds)"}}},"BuildLimitsSettings":{"type":"object","description":"Control-plane build resource limits.\n\nCaps how many builds run concurrently AND how much CPU/memory each build\nis allowed to consume. A single global semaphore in the deployer crate\ngates every `DockerRuntime::build_image` call to `max_concurrent`. When\nthe semaphore is full, additional builds queue and wait — they do not\nfail. Per-build CPU/memory caps are forwarded to Docker via\n`BuildImageOptions { memory, cpuquota, cpuperiod }`.\n\n`cpu_limit_cores = 0.0` or `memory_limit_mb = 0` means \"no explicit cap\"\n— fall back to the legacy 50%-of-host heuristic for backwards\ncompatibility with operators who never visit the settings page.","properties":{"cpu_limit_cores":{"type":"number","format":"float","description":"CPU cores allowed per build (float, e.g. 2.0 = 2 cores, 0.5 = half\na core). 0 means \"use the legacy 50%-of-host default\".","default":0.0,"example":2.0,"minimum":0},"max_concurrent":{"type":"integer","format":"int32","description":"Maximum number of `docker build` operations allowed to run at the\nsame time on the control plane. Additional builds queue. Min 1.","default":2,"example":2,"minimum":1},"memory_limit_mb":{"type":"integer","format":"int32","description":"Memory allowed per build, in megabytes. 0 means \"use the legacy\n50%-of-host default\". Docker enforces this as a hard cap — builds\nthat exceed it OOM-kill.","default":0,"example":2048,"minimum":0}}},"CancelBackupResponse":{"type":"object","description":"Response body for cancel endpoints.","required":["cancelled"],"properties":{"cancelled":{"type":"integer","format":"int64","description":"Number of rows that were actually flipped to `failed`. `0` is a valid\nsuccess and means the backup was already terminal — the call is\nidempotent.","minimum":0}}},"CertStatusResponse":{"type":"object","description":"Current on-demand cert status for a single hostname (ADR-018 §5). Backs\n`GET /domains/by-host/{hostname}/cert-status`.","required":["hostname"],"properties":{"backoff_until":{"type":["integer","null"],"format":"int64","description":"On-demand negative-cache deadline (epoch millis), when in backoff."},"hostname":{"type":"string","description":"SNI hostname."},"last_attempt":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/OnDemandCertAttemptResponse","description":"The most recent on-demand issuance attempt for this hostname, if any."}]},"status":{"type":["string","null"],"description":"Current cert lifecycle status from the `domains` row, when one exists."}}},"ChallengeConfig":{"type":"object","description":"Challenge configuration (future feature)\nFor CAPTCHA, JS challenges, proof-of-work, etc.","required":["challengeType","difficulty"],"properties":{"challengeType":{"type":"string","description":"Challenge type: \"captcha\", \"js_challenge\", \"proof_of_work\""},"difficulty":{"type":"integer","format":"int32","description":"Challenge difficulty level (1-10)","minimum":0},"protectedPaths":{"type":"array","items":{"type":"string"},"description":"Paths that require challenges"}}},"ChallengeError":{"type":"object","required":["type","detail","status"],"properties":{"detail":{"type":"string","description":"Human-readable error description"},"status":{"type":"integer","format":"int32","description":"HTTP status code"},"type":{"type":"string","description":"Error type (e.g., \"urn:ietf:params:acme:error:unauthorized\")"}}},"ChallengeValidationStatus":{"type":"object","required":["type","url","status","token"],"properties":{"error":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ChallengeError","description":"Error details if validation failed"}]},"status":{"type":"string","description":"Challenge status (e.g., \"pending\", \"valid\", \"invalid\")"},"token":{"type":"string","description":"Challenge token"},"type":{"type":"string","description":"Challenge type (e.g., \"dns-01\", \"http-01\")"},"url":{"type":"string","description":"Challenge validation URL"},"validated":{"type":["string","null"],"description":"When the challenge was validated (if successful)"}}},"ChangePasswordRequest":{"type":"object","required":["current_password","new_password"],"properties":{"current_password":{"type":"string","example":"current_password_value"},"mfa_code":{"type":["string","null"],"description":"TOTP code (or recovery code). Required iff the user has MFA enabled.","example":"123456"},"new_password":{"type":"string","example":"new_password_value"},"revoke_other_sessions":{"type":"boolean","description":"When true, every session OTHER than the one making this request is\nrevoked. Defaults to false; the UI surfaces this as a checkbox."}}},"ChangeProjectSourceRequest":{"type":"object","description":"Change a project's source type to a Git-less type (docker_image /\nstatic_files / manual). Switching TO `git` is done via the Git settings\nendpoint (which also supplies the repository + provider connection).","required":["source_type"],"properties":{"source_type":{"$ref":"#/components/schemas/SourceType"}}},"ChatCompletionChoice":{"type":"object","required":["index","message"],"properties":{"finish_reason":{"type":["string","null"]},"index":{"type":"integer","format":"int32"},"message":{"$ref":"#/components/schemas/ChatMessage"}}},"ChatCompletionRequest":{"allOf":[{"type":["object","null"],"description":"Tolerates extra SDK fields (stream_options, logprobs, etc.)","additionalProperties":{},"propertyNames":{"type":"string"}},{"type":"object","required":["model","messages"],"properties":{"frequency_penalty":{"type":["number","null"],"format":"double"},"max_tokens":{"type":["integer","null"],"format":"int64"},"messages":{"type":"array","items":{"$ref":"#/components/schemas/ChatMessage"}},"model":{"type":"string"},"n":{"type":["integer","null"],"format":"int32"},"presence_penalty":{"type":["number","null"],"format":"double"},"response_format":{},"seed":{"type":["integer","null"],"format":"int64"},"stop":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/StopSequence"}]},"stream":{"type":"boolean"},"temperature":{"type":["number","null"],"format":"double"},"tool_choice":{},"tools":{"type":["array","null"],"items":{}},"top_p":{"type":["number","null"],"format":"double"},"user":{"type":["string","null"]}}}],"description":"OpenAI-compatible chat completion request.\nUses `deny_unknown_fields = false` (serde default) so that SDK-specific\nfields like `stream_options`, `logprobs`, `top_logprobs`, `logit_bias`,\n`parallel_tool_calls`, etc. are silently accepted without breaking."},"ChatCompletionResponse":{"type":"object","required":["id","object","created","model","choices"],"properties":{"choices":{"type":"array","items":{"$ref":"#/components/schemas/ChatCompletionChoice"}},"created":{"type":"integer","format":"int64"},"id":{"type":"string"},"model":{"type":"string"},"object":{"type":"string"},"usage":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/UsageInfo"}]}}},"ChatMessage":{"type":"object","required":["role"],"properties":{"content":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/MessageContent"}]},"name":{"type":["string","null"]},"role":{"type":"string"},"tool_call_id":{"type":["string","null"]},"tool_calls":{"type":["array","null"],"items":{}}}},"ChatReadinessResponse":{"type":"object","description":"What still has to be true before an AI chat can run a turn in this project.\n\nThe three gates are independent and fail for different reasons with different\nfixes, so they are reported separately rather than collapsed into one boolean:\nan instance admin configures a provider (instance-wide), while the two toggles\nare per-project. Collapsing them would leave the user with \"AI unavailable\"\nand no idea which of three places to go.","required":["ai_configured","chat_enabled","write_actions_enabled"],"properties":{"ai_configured":{"type":"boolean","description":"An AI provider is configured on this instance. Fixed in\nSettings → AI Providers; instance-wide, not per project."},"chat_enabled":{"type":"boolean","description":"The per-project read-only chat toggle is on (the default)."},"write_actions_enabled":{"type":"boolean","description":"The per-project write-actions opt-in is on. Required for any flow where\nthe assistant *proposes* changes; irrelevant for read-only questions."}}},"ChildBackupEntryResponse":{"type":"object","description":"A single child backup entry in the `GET /backups/{id}/children` response.\n\nEach entry corresponds to one `external_service_backups` row joined with\n`external_services`, providing service metadata without a second request.","required":["id","service_id","service_name","service_type","state","backup_type","started_at","s3_location","compression_type"],"properties":{"backup_type":{"type":"string","description":"Backup variant (e.g. \"full\", \"incremental\")."},"compression_type":{"type":"string","description":"Compression algorithm used (e.g. \"gzip\", \"lz4\")."},"error_message":{"type":["string","null"],"description":"Engine-reported error message when `state = \"failed\"`."},"finished_at":{"type":["string","null"],"description":"When the child backup finished, if known.","example":"2025-01-15T14:35:00.456Z"},"id":{"type":"integer","format":"int32","description":"Row ID from `external_service_backups`."},"s3_location":{"type":"string","description":"Object key or `s3://` URL where the backup data lives."},"service_id":{"type":"integer","format":"int32","description":"FK to `external_services.id`."},"service_name":{"type":"string","description":"Human-readable name of the external service (e.g. \"redis-prod\")."},"service_type":{"type":"string","description":"Service type string (e.g. \"postgres\", \"redis\", \"mongodb\", \"s3\").","example":"postgres"},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Size of the child backup in bytes, if available."},"started_at":{"type":"string","description":"When the child backup started (RFC 3339).","example":"2025-01-15T14:30:00.123Z"},"state":{"type":"string","description":"Current state: \"pending\" | \"running\" | \"completed\" | \"failed\"."}}},"ChildBackupListResponse":{"type":"object","description":"Response body for `GET /backups/{id}/children`.\n\nReturns an empty `children` list (not 404) when the parent backup has no\nchild records (e.g. control-plane backups).","required":["children"],"properties":{"children":{"type":"array","items":{"$ref":"#/components/schemas/ChildBackupEntryResponse"},"description":"Zero or more child backup entries ordered by `external_service_backups.id` ASC."}}},"CleanupExpiredBackupsRequest":{"type":"object","properties":{"expected_backup_ids":{"type":["array","null"],"items":{"type":"string"},"description":"Exact candidates returned by the dry run. Execution fails if the\nretention selection has changed since preview."}}},"CliDeviceApproveRequest":{"type":"object","required":["user_code"],"properties":{"user_code":{"type":"string"}}},"CliDeviceApproveResponse":{"type":"object","required":["user_code","status"],"properties":{"status":{"type":"string"},"user_code":{"type":"string"}}},"CliDeviceLookupResponse":{"type":"object","required":["user_code","status","expires_at"],"properties":{"client_name":{"type":["string","null"]},"expires_at":{"type":"string","format":"date-time"},"requested_ip":{"type":["string","null"]},"status":{"type":"string","description":"`pending` | `approved` | `denied` | `expired`."},"user_code":{"type":"string"}}},"CliDevicePollRequest":{"type":"object","required":["device_code"],"properties":{"device_code":{"type":"string"}}},"CliDevicePollResponse":{"oneOf":[{"type":"object","description":"Still waiting on the user to approve in the browser.","required":["status"],"properties":{"status":{"type":"string","enum":["authorization_pending"]}}},{"type":"object","description":"CLI is polling faster than the server-suggested interval.","required":["status"],"properties":{"status":{"type":"string","enum":["slow_down"]}}},{"type":"object","description":"User denied the request in the browser.","required":["status"],"properties":{"status":{"type":"string","enum":["access_denied"]}}},{"type":"object","description":"The session has expired without approval.","required":["status"],"properties":{"status":{"type":"string","enum":["expired_token"]}}},{"type":"object","description":"The session was approved; this is the only response that carries\nthe API key. The key is returned exactly once and then cleared\nfrom the session row.","required":["user_id","email","role","api_key","key_prefix","status"],"properties":{"api_key":{"type":"string"},"email":{"type":"string"},"expires_at":{"type":["string","null"],"format":"date-time"},"key_prefix":{"type":"string"},"role":{"type":"string"},"status":{"type":"string","enum":["approved"]},"user_id":{"type":"integer","format":"int32"}}}]},"CliDeviceStartRequest":{"type":"object","properties":{"client_name":{"type":["string","null"],"description":"Friendly hostname / client identifier shown in the browser approval\nscreen. Sanitized before display.","example":"dviejo-mac.local"}}},"CliDeviceStartResponse":{"type":"object","required":["device_code","user_code","verification_uri","verification_uri_complete","expires_in","interval"],"properties":{"device_code":{"type":"string","description":"Opaque secret the CLI polls with. Never display to a human."},"expires_in":{"type":"integer","format":"int64","description":"Seconds until the device_code expires."},"interval":{"type":"integer","format":"int64","description":"Suggested polling interval, in seconds."},"user_code":{"type":"string","description":"Short human-readable code the user types into the browser.","example":"ABCD-1234"},"verification_uri":{"type":"string","description":"Base verification URL — the CLI may display this when the\npre-filled URL is too long to be useful.","example":"https://temps.example.com/cli-login"},"verification_uri_complete":{"type":"string","description":"`verification_uri` with `user_code` pre-filled. Open this directly.","example":"https://temps.example.com/cli-login/ABCD-1234"}}},"CliLoginRequest":{"type":"object","required":["username","password"],"properties":{"password":{"type":"string"},"username":{"type":"string"}}},"CloudProvider":{"type":"string","description":"Cloud provider detected from node metadata","enum":["aws","gcp","azure","hetzner","digitalocean","other"]},"CloudflareConfig":{"type":"object","description":"Configuration for a Cloudflare Email Sending notification provider.\n\nNotifications are delivered through Cloudflare's transactional Email Sending\nAPI. Only the account, token, sender and recipients are configured here —\nsubject and body are derived from each notification.","required":["account_id","api_token","from_address","to_addresses"],"properties":{"account_id":{"type":"string","description":"Cloudflare account id that owns the Email Sending configuration.","example":"023e105f4ecef8ad9ca31a8372d0c353"},"api_token":{"type":"string","description":"Cloudflare API token with the Email Sending permission. Encrypted at\nrest and masked in normal API responses."},"from_address":{"type":"string","description":"Verified sender address (must belong to a domain enabled for Cloudflare\nEmail Sending).","example":"welcome@infracf.example.com"},"from_name":{"type":["string","null"],"description":"Optional human-friendly sender name shown in the recipient's inbox."},"to_addresses":{"type":"array","items":{"type":"string"},"description":"Recipients that should receive the notification."}}},"ClusterCapacity":{"type":"object","description":"Total cluster capacity (sum of node allocatable resources)","required":["node_count","cpu_millis","memory_mb"],"properties":{"cpu_millis":{"type":"integer","format":"int64","description":"Total allocatable CPU in millicores"},"memory_mb":{"type":"integer","format":"int64","description":"Total allocatable memory in MB"},"node_count":{"type":"integer","description":"Number of nodes","minimum":0}}},"ClusterDnsSettings":{"type":"object","description":"Cluster-DNS resolver settings (ADR-024, experimental beta).\n\nWhen `enabled`, the Temps control plane starts a Hickory DNS resolver and\ninjects it as the first nameserver into every deployed container via\n`HostConfig.Dns` — giving containers the ability to resolve `*.temps.local`\nFQDNs for service-to-service communication. Worker nodes pick this flag up\nfrom the `/api/internal/nodes/{id}/network/peers` wire response and gate\ntheir own per-node resolver the same way.\n\n**Default: `false` (disabled).**\n\nWhy disabled by default: a production incident showed that when the injected\nHickory resolver was slow or transiently unresponsive for a non-`*.temps.local`\n(external) hostname, glibc's resolver cycled through all three nameservers\n(`172.20.0.1`, `1.1.1.1`, `8.8.8.8`) at ~5 s timeout × 2 attempts each,\ncausing 22–27 s delays for outbound TCP connections. Disabling the injection\nrestores Docker's embedded DNS as the sole resolver, eliminating that failure\nmode. Operators running single/multi-node installs that depend on\n`*.temps.local` resolution must explicitly opt in by setting `enabled: true`.\n\n`bool` defaults to `false` in Rust and JSON (`#[serde(default)]`), so the\nsafe-off behaviour is automatic for new installs and legacy settings rows.","properties":{"enabled":{"type":"boolean","description":"Master switch. When `false` (default), no custom DNS is injected into\ncontainers — they use Docker's embedded DNS which forwards to the host's\nown `resolv.conf`. When `true`, the control-plane Hickory resolver is\nstarted and its bridge IP is injected as the first nameserver so\n`*.temps.local` FQDNs resolve inside containers.","default":false,"example":false}}},"ClusterHealthReportResponse":{"type":"object","description":"Response body for `GET /external-services/{id}/cluster-health`.","required":["checked_at","monitor_response_ms","members"],"properties":{"checked_at":{"type":"string","description":"ISO-8601 wall-clock when the report was generated.","example":"2025-10-12T12:15:47.609192Z"},"members":{"type":"array","items":{"$ref":"#/components/schemas/ClusterMemberHealthResponse"}},"monitor_error":{"type":["string","null"],"description":"Set when the monitor itself was unreachable. UI shows a banner."},"monitor_response_ms":{"type":"integer","format":"int64","description":"Round-trip to query the monitor (ms)."}}},"ClusterMemberHealthResponse":{"type":"object","description":"One row in the cluster Members table — see `GET /external-services/{id}/cluster-health`.","required":["nodename","nodehost","nodeport","reported_state","goal_state","health","seconds_since_report","candidate_priority","replication_quorum"],"properties":{"candidate_priority":{"type":"integer","format":"int32"},"goal_state":{"type":"string","description":"What the monitor *wants* the node to be. Differs from\n`reported_state` mid-transition (failover, demotion, etc.)."},"health":{"type":"integer","format":"int32","description":"pg_auto_failover liveness signal: `1` healthy, `0` unknown\n(no recent report), `-1` unhealthy."},"nodehost":{"type":"string"},"nodename":{"type":"string"},"nodeport":{"type":"integer","format":"int32"},"replay_lag_ms":{"type":["integer","null"],"format":"int64","description":"`replay_lag` from `pg_stat_replication`, in milliseconds."},"replication_quorum":{"type":"boolean"},"reported_state":{"type":"string","description":"What the node *last told the monitor* it was. Stale during outages."},"seconds_since_report":{"type":"integer","format":"int64","description":"Wall-clock seconds since the node last reported in."},"sync_state":{"type":["string","null"],"description":"`sync` / `quorum` / `async` for secondaries; `null` for the primary."}}},"ClusterMemberRequest":{"type":"object","description":"Request spec for a single cluster member.","required":["role"],"properties":{"node_id":{"type":["integer","null"],"format":"int32","description":"Target worker node ID. Omit or null to run on the control plane."},"role":{"type":"string","description":"Service-type-specific role (e.g., \"monitor\", \"primary\", \"replica\")","example":"primary"}}},"CmdBody":{"type":"object","required":["command"],"properties":{"args":{"type":"array","items":{"type":"string"},"description":"Arguments to pass to the binary. Defaults to empty."},"command":{"type":"string","description":"Binary name (argv[0]) — e.g. `\"ls\"`, `\"node\"`. The SDK sends this\nseparately from `args`."},"cwd":{"type":["string","null"],"description":"Working directory override."},"env":{"type":"object","description":"Extra env vars.","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"sudo":{"type":"boolean","description":"When true, the SDK runs the command privileged. We ignore it today\n— the underlying provider always runs as the sandbox's own user."},"wait":{"type":"boolean","description":"When true, the response is an `application/x-ndjson` stream where\nthe first line is the running-command envelope and the second line\nis the finished-command envelope with `exitCode`."}}},"CmdInner":{"type":"object","description":"Inner `command` object — matches the SDK's zod validator exactly.\n`exitCode` is `null` until the command terminates; `startedAt` is Unix\nepoch milliseconds.","required":["id","name","args","cwd","sandboxId","startedAt"],"properties":{"args":{"type":"array","items":{"type":"string"}},"cwd":{"type":"string"},"exitCode":{"type":["integer","null"],"format":"int32"},"id":{"type":"string"},"name":{"type":"string"},"sandboxId":{"type":"string"},"startedAt":{"type":"integer","format":"int64"}}},"CmdKillBody":{"type":"object","description":"SDK-shaped kill body. The SDK sends `{signal: AbortSignal}` but only\nuses the signal for HTTP request abortion client-side; there's no\nsignal name on the wire.","properties":{"force":{"type":"boolean","description":"Optional: when true, SIGKILL instead of SIGTERM."}}},"CmdResponse":{"type":"object","description":"`@vercel/sandbox` envelope: `{ command: {...} }`.","required":["command"],"properties":{"command":{"$ref":"#/components/schemas/CmdInner"}}},"CommitExistsResponse":{"type":"object","required":["exists"],"properties":{"commit":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/CommitInfo","description":"Commit metadata when the requested SHA exists."}]},"commit_sha":{"type":["string","null"]},"exists":{"type":"boolean"}}},"CommitInfo":{"type":"object","required":["sha","message","author","author_email","date"],"properties":{"author":{"type":"string","description":"Author name"},"author_email":{"type":"string","description":"Author email"},"date":{"type":"string","format":"date-time","description":"Commit date in ISO 8601 format","example":"2025-10-12T12:15:47.609192Z"},"message":{"type":"string","description":"Commit message"},"sha":{"type":"string","description":"Commit SHA hash"}}},"CommitListResponse":{"type":"object","required":["commits"],"properties":{"commits":{"type":"array","items":{"$ref":"#/components/schemas/CommitInfo"}}}},"Comparator":{"type":"string","description":"Comparator for static/forecast threshold detectors. Serializes to the\nkeyword forms `gt|gte|lt|lte` (NOT the SQL operators used by\n`temps-monitoring::compare`).","enum":["gt","gte","lt","lte"]},"ComposePublicPort":{"type":"object","description":"A port that should be exposed publicly through the proxy for a compose service.","required":["service","port"],"properties":{"port":{"type":"integer","format":"int32","description":"Container port to expose (e.g. 8123)","minimum":0},"service":{"type":"string","description":"Compose service name (e.g. \"web\", \"clickhouse\")"}}},"ConnectionListQuery":{"type":"object","properties":{"direction":{"type":["string","null"]},"page":{"type":["integer","null"],"format":"int64","minimum":0},"per_page":{"type":["integer","null"],"format":"int64","minimum":0},"sort":{"type":["string","null"]}}},"ConnectionListResponse":{"type":"object","required":["connections","total_count","page","per_page"],"properties":{"connections":{"type":"array","items":{"$ref":"#/components/schemas/ConnectionResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"per_page":{"type":"integer","format":"int64","minimum":0},"total_count":{"type":"integer","minimum":0}}},"ConnectionResponse":{"type":"object","required":["id","provider_id","account_name","account_type","is_active","is_expired","syncing","synced_repository_count","health_status","consecutive_health_failures","created_at","updated_at"],"properties":{"account_name":{"type":"string"},"account_type":{"type":"string"},"consecutive_health_failures":{"type":"integer","format":"int32"},"created_at":{"type":"string","format":"date-time"},"health_message":{"type":["string","null"],"description":"Human-readable reason when health_status is \"unhealthy\"; null otherwise."},"health_status":{"type":"string","description":"Current health status: \"healthy\", \"unhealthy\", or \"unknown\"."},"id":{"type":"integer","format":"int32"},"installation_id":{"type":["string","null"]},"is_active":{"type":"boolean"},"is_expired":{"type":"boolean"},"last_health_check_at":{"type":["string","null"],"format":"date-time"},"last_synced_at":{"type":["string","null"],"format":"date-time"},"provider_id":{"type":"integer","format":"int32"},"synced_repository_count":{"type":"integer","format":"int32","description":"Running count of repositories persisted by the current (or most\nrecent) sync. Resets to 0 when a new sync begins; useful for showing\nlive progress on large syncs."},"syncing":{"type":"boolean"},"updated_at":{"type":"string","format":"date-time"},"user_id":{"type":["integer","null"],"format":"int32"}}},"ConnectionTestResult":{"type":"object","description":"Connection test result","required":["success","message"],"properties":{"message":{"type":"string"},"success":{"type":"boolean"}}},"ConsoleEventPayload":{"type":"object","description":"Payload for server-side event ingestion via the console API.\n\nThe app backend reads the encrypted `_temps_visitor_id` and `_temps_sid`\ncookie values from the user's request and forwards them here.\nTemps decrypts them server-side to resolve visitor/session identity.","required":["event_name","environment_id","deployment_id"],"properties":{"deployment_id":{"type":"integer","format":"int32","description":"Deployment ID to attribute the event to"},"environment_id":{"type":"integer","format":"int32","description":"Environment ID to attribute the event to"},"event_data":{"description":"Arbitrary JSON event data"},"event_name":{"type":"string","description":"Event name (e.g. \"purchase\", \"signup\", custom event names)"},"request_path":{"type":"string","description":"Page path context (defaults to \"/\")"},"request_query":{"type":"string","description":"Query string context"},"session_id":{"type":["string","null"],"description":"Encrypted `_temps_sid` cookie value from the user's browser"},"visitor_id":{"type":["string","null"],"description":"Encrypted `_temps_visitor_id` cookie value from the user's browser"}}},"ContainerActionResponse":{"type":"object","description":"Response indicating success of container state change","required":["container_id","container_name","action","status","message"],"properties":{"action":{"type":"string"},"container_id":{"type":"string"},"container_name":{"type":"string"},"message":{"type":"string"},"status":{"type":"string"}}},"ContainerDetailResponse":{"type":"object","description":"Detailed container information with environment variables and metrics","required":["id","container_id","container_name","image_name","status","deployment_id","created_at","deployed_at","container_port","environment_variables"],"properties":{"container_id":{"type":"string"},"container_name":{"type":"string"},"container_port":{"type":"integer","format":"int32","description":"Port inside the container"},"cpu_limit_cores":{"type":["number","null"],"format":"double","description":"CPU limit in whole cores (e.g. 1.0). None when no limit is configured."},"created_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"deployed_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"deployment_id":{"type":"integer","format":"int32"},"environment_variables":{"type":"array","items":{"$ref":"#/components/schemas/EnvVarResponse"},"description":"Environment variables (sensitive values masked)"},"error_message":{"type":["string","null"],"description":"Free-form error string from Docker's container state on exit."},"exit_code":{"type":["integer","null"],"format":"int32","description":"Process exit code reported by Docker. None while still running."},"exit_reason":{"type":["string","null"],"description":"Human-readable reason the container exited."},"finished_at":{"type":["string","null"],"description":"When the container exited (Docker's FinishedAt). None while running.","example":"2025-10-12T12:16:47.609192Z"},"host_port":{"type":["integer","null"],"format":"int32","description":"Port on the host machine"},"id":{"type":"integer","format":"int32"},"image_name":{"type":"string"},"oom_killed":{"type":["boolean","null"],"description":"True when Docker's OOM killer terminated the container."},"ready_at":{"type":["string","null"],"example":"2025-10-12T12:16:47.609192Z"},"resource_limits":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ResourceLimitsResponse","description":"Resource limits"}]},"restart_count":{"type":["integer","null"],"format":"int64","description":"Container restart count from Docker"},"service_name":{"type":["string","null"],"description":"Compose service name (e.g. \"web\", \"redis\"). None for single-container deployments."},"service_url":{"type":["string","null"],"description":"Per-service URL for compose deployments"},"started_at":{"type":["string","null"],"description":"When the container's main process most recently started.","example":"2025-10-12T12:15:50.000000Z"},"status":{"type":"string"}}},"ContainerEnvironmentVariableValueResponse":{"type":"object","required":["value"],"properties":{"value":{"type":"string"}}},"ContainerInfoResponse":{"type":"object","required":["container_id","container_name","image_name","status","created_at"],"properties":{"container_id":{"type":"string"},"container_name":{"type":"string"},"cpu_limit_cores":{"type":["number","null"],"format":"double","description":"CPU limit in whole cores (e.g. 1.0). None when no limit is configured."},"created_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"error_message":{"type":["string","null"],"description":"Free-form error string from Docker's container state on exit."},"exit_code":{"type":["integer","null"],"format":"int32","description":"Process exit code reported by Docker. None while still running."},"exit_reason":{"type":["string","null"],"description":"Human-readable reason the container exited (e.g. \"OOMKilled\",\n\"Killed by SIGKILL (exit code 137)\", \"Exit code 1\"). None while running."},"finished_at":{"type":["string","null"],"description":"When the container exited (Docker's FinishedAt). None while running.","example":"2025-10-12T12:16:47.609192Z"},"image_name":{"type":"string"},"node_name":{"type":["string","null"],"description":"Node name where this container is running. None for local (single-node) deployments."},"oom_killed":{"type":["boolean","null"],"description":"True when Docker's OOM killer terminated the container."},"restart_count":{"type":["integer","null"],"format":"int64","description":"Container restart count from Docker. The UI shows a chip when this is\n> 0 so a crash loop is visible without opening detail."},"service_name":{"type":["string","null"],"description":"Compose service name (e.g. \"web\", \"redis\"). None for single-container deployments."},"service_url":{"type":["string","null"],"description":"Per-service URL for compose deployments (e.g. \"https://web-myapp.localho.st\")"},"started_at":{"type":["string","null"],"description":"When the container's main process most recently started. The UI uses\nthis for the uptime label so the count resets when a container is\nrestarted in place. None for containers that never started.","example":"2025-10-12T12:15:50.000000Z"},"status":{"type":"string"}}},"ContainerInventoryItem":{"type":"object","description":"A container reported by the agent during heartbeat reconciliation.","required":["container_id","container_name"],"properties":{"container_id":{"type":"string","description":"Docker container ID"},"container_name":{"type":"string","description":"Docker container name"}}},"ContainerListResponse":{"type":"object","required":["containers","total"],"properties":{"containers":{"type":"array","items":{"$ref":"#/components/schemas/ContainerInfoResponse"}},"total":{"type":"integer","minimum":0}}},"ContainerLogSettings":{"type":"object","description":"Docker container log rotation settings\nControls the `--log-opt max-size` and `--log-opt max-file` for containers","properties":{"max_file":{"type":"integer","format":"int32","description":"Maximum number of rotated log files to keep (e.g., 3 means up to 3 x max_size total)","default":3,"example":3,"minimum":0},"max_size":{"type":"string","description":"Maximum size of each log file (e.g., \"50m\", \"100m\", \"1g\")\nDocker default is unlimited; we default to \"50m\" to prevent disk exhaustion","default":"50m","example":"50m"},"service_max_file":{"type":"integer","format":"int32","description":"Maximum rotated log files for external service containers","default":3,"example":3,"minimum":0},"service_max_size":{"type":"string","description":"Maximum size for external service container logs (postgres, redis, etc.)\nDefaults to \"20m\" since services are typically less verbose than app containers","default":"20m","example":"20m"}}},"ContainerLogsQuery":{"type":"object","properties":{"container_name":{"type":["string","null"],"description":"Optional container name to get logs from (if deployment has multiple containers)"},"end_date":{"type":["integer","null"],"format":"int64"},"follow":{"type":"boolean","description":"Follow log output in real-time (default: true for backward compatibility)"},"start_date":{"type":["integer","null"],"format":"int64"},"tail":{"type":["string","null"]},"timestamps":{"type":"boolean","description":"Include timestamps in log output (default: false)"}}},"ContainerMetricHistoryPoint":{"type":"object","description":"One bucketed data point of a container resource metric time series.","required":["time","value"],"properties":{"time":{"type":"string","description":"Bucket timestamp (ISO 8601 with `Z` suffix).","example":"2025-10-12T12:15:00+00:00"},"value":{"type":"number","format":"double","description":"Averaged metric value for the bucket."}}},"ContainerMetricsHistoryQuery":{"type":"object","description":"Query parameters for the container metrics history endpoint.","required":["metric"],"properties":{"metric":{"type":"string","description":"Dotted metric name, e.g. `container.cpu_percent` or\n`container.memory_used_bytes`."},"range":{"type":"string","description":"Time window: `1h`, `6h`, `24h`, or `7d` (defaults to `1h`)."}}},"ContainerMetricsResponse":{"type":"object","description":"Container resource metrics (CPU, memory usage)","required":["container_id","container_name","cpu_percent","memory_bytes","network_rx_bytes","network_tx_bytes","timestamp"],"properties":{"container_id":{"type":"string"},"container_name":{"type":"string"},"cpu_limit_cores":{"type":["number","null"],"format":"double","description":"CPU limit in whole cores (e.g. 1.0). None = no limit."},"cpu_percent":{"type":"number","format":"double","description":"CPU usage as a multi-core percentage (Docker convention: 200 = 2 cores\nfully pinned). Divide by 100 to get cores used."},"memory_bytes":{"type":"integer","format":"int64","description":"Memory usage in bytes","minimum":0},"memory_limit_bytes":{"type":["integer","null"],"format":"int64","description":"Memory limit in bytes (if set)","minimum":0},"memory_percent":{"type":["number","null"],"format":"double","description":"Memory usage percentage (0-100) if limit is set"},"network_rx_bytes":{"type":"integer","format":"int64","description":"Network bytes received","minimum":0},"network_tx_bytes":{"type":"integer","format":"int64","description":"Network bytes transmitted","minimum":0},"timestamp":{"type":"string","description":"Timestamp of metrics collection","example":"2025-10-12T12:15:47.609192Z"}}},"ContainerResponse":{"type":"object","required":["name","container_type","can_contain_containers","can_contain_entities","metadata"],"properties":{"can_contain_containers":{"type":"boolean","description":"Can this container hold other containers?","example":true},"can_contain_entities":{"type":"boolean","description":"Can this container hold entities (tables, collections, etc.)?","example":false},"child_container_type":{"type":["string","null"],"description":"Type of child containers (if can_contain_containers is true)","example":"schema"},"container_type":{"type":"string","description":"Container type (database, schema, keyspace, bucket, etc.)","example":"database"},"entity_count_hint":{"type":["string","null"],"description":"Hint for UI on expected entity count (small = sidebar, large = pagination)","example":"large"},"entity_type_label":{"type":["string","null"],"description":"Label for entity type (if can_contain_entities is true)","example":"table"},"metadata":{"description":"Additional metadata"},"name":{"type":"string","description":"Container name","example":"mydb"}}},"ContainerRuntimeInfo":{"type":"object","description":"Snapshot of a container's lifecycle state from `docker inspect`.\n`restart_count` and `oom_killed` are the load-bearing fields when\ndiagnosing crash loops — the kernel OOM killer never reaches the\napplication's logs, so seeing `oom_killed=true` is the only signal\nthat a memory limit was the cause.","required":["role","container_name","resource_limits"],"properties":{"container_id":{"type":["string","null"],"description":"Container Docker id, when present. None = container does not exist\n(was never created or was removed externally)."},"container_name":{"type":"string","description":"Stable name of the Docker container (e.g. `postgres-mydb`)."},"exit_code":{"type":["integer","null"],"format":"int64","description":"Last container exit code, when known. Non-zero = unclean stop."},"finished_at":{"type":["string","null"],"description":"ISO-8601 timestamp of the most recent termination, when known."},"image":{"type":["string","null"],"description":"Currently-effective Docker image (e.g. `gotempsh/postgres-walg:18-bookworm`)."},"oom_killed":{"type":["boolean","null"],"description":"True when the container's last termination was caused by the\nkernel OOM killer. Set if the user enabled hard memory limits\nand the working set exceeded them."},"resource_limits":{"$ref":"#/components/schemas/ServiceResourceLimits","description":"Currently-applied resource limits read off the container's\n`HostConfig`. Compare this against the user-configured limits to\ndetect drift (an old container that never picked up new caps)."},"restart_count":{"type":["integer","null"],"format":"int64","description":"Total restarts since the container was created. Useful for\ndetecting crash loops — a steady stream means something is killing\nthe container repeatedly (frequently OOM)."},"role":{"type":"string","description":"`service_members.role` for cluster members; \"standalone\" otherwise."},"started_at":{"type":["string","null"],"description":"ISO-8601 timestamp of when the container last started. None when\nit has never started (i.e. created but never run)."},"status":{"type":["string","null"],"description":"Bollard container state (\"running\", \"exited\", \"dead\", etc.). None\nwhen the container does not exist."}}},"ContainerStatsSample":{"type":"object","description":"Live resource usage sample for a single container.\n\n`cpu_percent` is computed by Docker's standard formula:\n ((cpu_delta / system_delta) * online_cpus) * 100\n`memory_percent` is `(memory_usage / memory_limit) * 100` — when no\nmemory limit is set the limit reported by Docker is the host's total\nRAM, so a 5% reading means \"5% of host RAM\", not \"5% of allocated\".","required":["role","container_name"],"properties":{"container_name":{"type":"string"},"cpu_percent":{"type":["number","null"],"format":"double","description":"CPU usage as a percentage. `None` when the container is not running\n(Docker returns no usable counters)."},"memory_limit_bytes":{"type":["integer","null"],"format":"int64","description":"Memory limit in bytes (host RAM if no limit set).","minimum":0},"memory_percent":{"type":["number","null"],"format":"double","description":"Memory usage as a percentage of `memory_limit_bytes`."},"memory_usage_bytes":{"type":["integer","null"],"format":"int64","description":"Resident memory usage in bytes.","minimum":0},"online_cpus":{"type":["integer","null"],"format":"int32","description":"Number of cores Docker observed at sample time. Used by the UI\nto label \"x/y cores\" instead of just a percent.","minimum":0},"role":{"type":"string"}}},"ContentPart":{"type":"object","required":["type"],"properties":{"image_url":{},"text":{"type":["string","null"]},"type":{"type":"string"}}},"ContextLine":{"type":"object","description":"A line in context response","required":["timestamp","level","message","line_offset","is_match"],"properties":{"fields":{},"is_match":{"type":"boolean","description":"Whether this line matched the original search"},"level":{"$ref":"#/components/schemas/LogLevel"},"line_offset":{"type":"integer","format":"int32"},"message":{"type":"string"},"timestamp":{"type":"string"}}},"ContextLogsRequest":{"type":"object","required":["chunk_id","line_offset"],"properties":{"chunk_id":{"type":"string"},"line_offset":{"type":"integer","format":"int32"},"lines":{"type":["integer","null"],"format":"int32","description":"Number of context lines before and after (default: 25)","minimum":0}}},"ContextLogsResponse":{"type":"object","required":["lines","target_index"],"properties":{"lines":{"type":"array","items":{"$ref":"#/components/schemas/ContextLine"}},"target_index":{"type":"integer","minimum":0}}},"ConversationDetailResponse":{"allOf":[{"$ref":"#/components/schemas/ConversationResponse"},{"type":"object","required":["messages"],"properties":{"messages":{"type":"array","items":{"$ref":"#/components/schemas/MessageResponse"},"description":"Turns oldest-first. The `system` seed message is omitted (internal)."}}}]},"ConversationResponse":{"type":"object","required":["public_id","context_type","context_id","status","created_at","last_activity_at"],"properties":{"context_id":{"type":"string"},"context_type":{"type":"string"},"created_at":{"type":"string"},"last_activity_at":{"type":"string"},"public_id":{"type":"string"},"status":{"type":"string"},"title":{"type":["string","null"]}}},"ConversationSummary":{"type":"object","description":"A conversation summary grouping related AI invocations.","required":["conversation_id","message_count","total_input_tokens","total_output_tokens","total_tokens","total_cost_microcents","avg_latency_ms","models_used","first_at","last_at"],"properties":{"avg_latency_ms":{"type":"number","format":"double"},"conversation_id":{"type":"string"},"first_at":{"type":"string"},"last_at":{"type":"string"},"message_count":{"type":"integer","format":"int64"},"models_used":{"type":"array","items":{"type":"string"}},"total_cost_microcents":{"type":"integer","format":"int64"},"total_input_tokens":{"type":"integer","format":"int64"},"total_output_tokens":{"type":"integer","format":"int64"},"total_tokens":{"type":"integer","format":"int64"}}},"ConversationsQueryParams":{"type":"object","properties":{"from":{"type":["string","null"],"description":"ISO 8601 start time (defaults to 24h ago)"},"limit":{"type":["integer","null"],"format":"int64","description":"Max results (defaults to 50, max 100)","minimum":0},"model":{"type":["string","null"],"description":"Filter by model name"},"tags":{"type":["string","null"],"description":"Filter by tags (comma-separated, AND logic)"},"to":{"type":["string","null"],"description":"ISO 8601 end time (defaults to now)"},"user_id":{"type":["integer","null"],"format":"int32","description":"Filter by user ID"}}},"CopyBlobRequest":{"type":"object","description":"Request to copy a blob","required":["fromUrl","toPathname"],"properties":{"fromUrl":{"type":"string","description":"Source blob URL or pathname","example":"/api/blob/10/images/avatar.png"},"projectId":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1},"toPathname":{"type":"string","description":"Destination pathname","example":"images/avatar-copy.png"}}},"CostAnalysis":{"type":"object","description":"Full cluster cost + rightsizing analysis attached to an import plan.","required":["nodes","capacity","requested","usage_source","overprovisioning","recommendation","notes"],"properties":{"actual_usage":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ResourceFootprint","description":"Measured usage from the metrics API (`metrics.k8s.io`).\n`None` when metrics-server is not installed."}]},"capacity":{"$ref":"#/components/schemas/ClusterCapacity","description":"Total cluster capacity (sum of node allocatable resources)"},"control_plane_monthly_usd":{"type":["number","null"],"format":"double","description":"Managed control-plane fee included in `current_monthly_usd` (EKS/GKE\ncharge ~$73/mo per cluster). `None` when not applicable/unknown."},"current_monthly_usd":{"type":["number","null"],"format":"double","description":"Estimated total infrastructure cost per month in USD (compute nodes +\ncontrol-plane fee). `None` when no node could be priced."},"nodes":{"type":"array","items":{"$ref":"#/components/schemas/NodeCostInfo"},"description":"Per-node inventory with price estimates where the instance type is known"},"notes":{"type":"array","items":{"type":"string"},"description":"Honesty notes: what could not be measured, which numbers are\nestimates, and any assumptions made. Always shown to the user."},"overprovisioning":{"$ref":"#/components/schemas/OverprovisioningAssessment","description":"Requests-vs-capacity-vs-usage assessment"},"provider":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/CloudProvider","description":"Detected cloud provider (from node `providerID` prefixes)"}]},"recommendation":{"$ref":"#/components/schemas/TargetRecommendation","description":"The temps/Hetzner target sizing and savings estimate"},"requested":{"$ref":"#/components/schemas/ResourceFootprint","description":"Sum of pod resource *requests* across running pods — what the\nscheduler has reserved, i.e. what the cluster is sized for."},"usage_source":{"$ref":"#/components/schemas/UsageSource","description":"How the usage numbers were obtained (drives UI wording)"}}},"CreateAlertRuleRequest":{"type":"object","required":["name","trigger_type"],"properties":{"cooldown_minutes":{"type":"integer","format":"int32","description":"Minimum minutes between notifications for same rule+group"},"enabled":{"type":"boolean"},"environment_filter":{"type":["integer","null"],"format":"int32","description":"Optional environment ID to filter alerts"},"error_level_filter":{"type":["string","null"],"description":"Optional error type/level filter"},"name":{"type":"string"},"notification_priority":{"type":"string","description":"Notification priority: Low, Normal, High, Critical"},"trigger_config":{"description":"Trigger-specific configuration (e.g., {\"count\": 100, \"window_minutes\": 60} for frequency)"},"trigger_type":{"type":"string","description":"Trigger type: new_issue, regression, frequency, new_user, user_count, status_change"}}},"CreateApiKeyRequest":{"type":"object","required":["name","role_type"],"properties":{"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"name":{"type":"string"},"permissions":{"type":["array","null"],"items":{"type":"string"},"example":["projects:read","deployments:read"]},"role_type":{"type":"string","example":"admin"}}},"CreateApiKeyResponse":{"type":"object","required":["id","name","key_prefix","role_type","api_key","created_at"],"properties":{"api_key":{"type":"string"},"created_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00Z"},"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"id":{"type":"integer","format":"int32"},"key_prefix":{"type":"string"},"name":{"type":"string"},"permissions":{"type":["array","null"],"items":{"type":"string"}},"role_type":{"type":"string"}}},"CreateBackupScheduleRequest":{"type":"object","required":["name","backup_type","retention_period","schedule_expression","enabled","tags"],"properties":{"backup_type":{"type":"string"},"description":{"type":["string","null"]},"enabled":{"type":"boolean"},"include_control_plane":{"type":["boolean","null"],"description":"When `true` (default), every run also produces a `control_plane`\nbackup of Temps's own database. Operators who use Temps purely as\na backup orchestrator for external DBs can set this to `false` to\nkeep the run history focused on those services."},"max_runtime_secs":{"type":["integer","null"],"format":"int64","description":"Optional wall-clock timeout override for jobs created by this schedule\n(seconds). When set, overrides the engine-family default. `null` means\n\"use engine default.\" The per-job `max_runtime_secs` in\n`EnqueueJobParams` can still override this for ad-hoc triggers."},"name":{"type":"string"},"retention_period":{"type":"integer","format":"int32"},"s3_source_id":{"type":["integer","null"],"format":"int32","description":"Optional S3 source. If omitted, the current default S3 source is used."},"schedule_expression":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"target_all_services":{"type":["boolean","null"],"description":"When `true` (default), the schedule backs up every external service\non the host — including databases created in the future. When\n`false`, the schedule backs up only the services explicitly attached\nvia `POST /backups/schedules/{id}/services`. Omit to use the default."}}},"CreateBitbucketRequest":{"type":"object","required":["name","auth"],"properties":{"auth":{"$ref":"#/components/schemas/BitbucketAuthInput","description":"Authentication credentials — either an access token or an app password."},"name":{"type":"string","description":"Display name for this provider."}}},"CreateCloudflareProviderRequest":{"type":"object","required":["name","config"],"properties":{"config":{"$ref":"#/components/schemas/CloudflareConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":"string"}}},"CreateConversationRequest":{"type":"object","required":["context_type","context_id"],"properties":{"context_id":{"type":"string","description":"The entity id (ints stringified)."},"context_type":{"type":"string","description":"e.g. `\"deployment\"`."}}},"CreateDSNRequest":{"type":"object","properties":{"base_url":{"type":["string","null"]},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"name":{"type":["string","null"]}}},"CreateDashboardRequest":{"type":"object","required":["project_id","name","layout"],"properties":{"layout":{"$ref":"#/components/schemas/DashboardLayout"},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"}}},"CreateDeploymentTokenRequest":{"type":"object","required":["name"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32","description":"Optional deployment ID - if set, token is scoped to a specific deployment"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Optional environment ID - if not set, token applies to all environments"},"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"name":{"type":"string"},"permissions":{"type":["array","null"],"items":{"type":"string"},"description":"List of permissions (e.g., [\"visitors:enrich\", \"emails:send\"])\nIf not provided, defaults to full access","example":["visitors:enrich","emails:send"]}}},"CreateDeploymentTokenResponse":{"type":"object","required":["id","project_id","name","token_prefix","token","created_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00Z"},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"permissions":{"type":["array","null"],"items":{"type":"string"}},"project_id":{"type":"integer","format":"int32"},"token":{"type":"string","description":"The full token value - only returned on creation"},"token_prefix":{"type":"string"}}},"CreateDnsProviderRequest":{"type":"object","description":"Request to create a new DNS provider","required":["name","provider_type","credentials"],"properties":{"credentials":{"$ref":"#/components/schemas/DnsProviderCredentials","description":"Provider credentials"},"description":{"type":["string","null"],"description":"Optional description"},"name":{"type":"string","description":"User-friendly name","example":"My Cloudflare"},"provider_type":{"$ref":"#/components/schemas/DnsProviderType","description":"Provider type"}}},"CreateDomainRequest":{"type":"object","required":["domain"],"properties":{"challenge_type":{"type":"string","description":"Challenge type for Let's Encrypt validation. Options: \"http-01\" (default) or \"dns-01\""},"domain":{"type":"string"}}},"CreateEmailDomainRequest":{"type":"object","required":["provider_id","domain"],"properties":{"domain":{"type":"string","description":"Domain name (e.g., \"updates.example.com\")","example":"updates.example.com"},"provider_id":{"type":"integer","format":"int32","description":"Provider ID to use for this domain"}}},"CreateEmailProviderRequest":{"type":"object","required":["name","provider_type","region"],"properties":{"name":{"type":"string","description":"User-friendly name for the provider","example":"My AWS SES"},"provider_type":{"$ref":"#/components/schemas/EmailProviderTypeRoute","description":"Provider type"},"region":{"type":"string","description":"Cloud region. For SMTP this is informational only — the host/port carry the real routing.","example":"us-east-1"},"scaleway_credentials":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ScalewayCredentialsRequest","description":"Scaleway credentials (required if provider_type is scaleway)"}]},"ses_credentials":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SesCredentialsRequest","description":"AWS SES credentials (required if provider_type is ses)"}]},"smtp_credentials":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SmtpCredentialsRequest","description":"Generic SMTP credentials (required if provider_type is smtp). Use when\nyou only have SMTP creds and want to import an already-set-up domain."}]},"sns_topic_arn":{"type":["string","null"],"description":"Exact SNS topic allowed to deliver SES events for this provider."}}},"CreateEnvironmentRequest":{"type":"object","required":["name","branch"],"properties":{"branch":{"type":"string"},"name":{"type":"string"},"set_as_preview":{"type":"boolean","description":"If true, set this environment as the preview environment for the project"}}},"CreateEnvironmentVariableRequest":{"type":"object","required":["key","value","environment_ids"],"properties":{"environment_ids":{"type":"array","items":{"type":"integer","format":"int32"}},"include_in_preview":{"type":"boolean","description":"Include this environment variable in preview environments (default: true)"},"is_secret":{"type":"boolean","description":"When true the variable is treated as write-only: never returned in\nplaintext from the API, masked in the UI, and updates that omit the\nvalue preserve the existing ciphertext. The flag is one-way — secret\nvars cannot be demoted back to regular vars."},"key":{"type":"string"},"value":{"type":"string"}}},"CreateExternalServiceRequest":{"type":"object","required":["name","service_type","parameters"],"properties":{"members":{"type":"array","items":{"$ref":"#/components/schemas/ClusterMemberRequest"},"description":"Cluster member specifications. Required when topology is \"cluster\"."},"name":{"type":"string"},"node_id":{"type":["integer","null"],"format":"int32","description":"Target node ID for the service. Omit or null to run on the control plane."},"parameters":{"type":"object","additionalProperties":{},"propertyNames":{"type":"string"}},"service_type":{"$ref":"#/components/schemas/ServiceTypeRoute"},"topology":{"type":"string","description":"Service topology: \"standalone\" (default) or \"cluster\" (HA multi-member).","example":"standalone"},"version":{"type":["string","null"]}}},"CreateFlagRequest":{"type":"object","required":["key","value_type","default_value"],"properties":{"client_visible":{"type":"boolean","description":"Whether the flag may be exposed on the unauthenticated same-origin\nevaluation endpoint. Defaults to `false`: flags are server-only unless\nexplicitly opted in, because targeting rules can encode business logic."},"default_value":{"description":"Served whenever evaluation cannot do better. Must match `value_type`.\n\nLeft unannotated so utoipa emits a free-form schema: a bool flag's\ndefault is `false`, not an object, and `value_type = Object` would tell\nevery generated client otherwise."},"description":{"type":["string","null"]},"key":{"type":"string","description":"Stable key used in application code. Immutable after create.","example":"checkout.v2"},"value_type":{"$ref":"#/components/schemas/FlagValueType","description":"Fixed at create: retyping would invalidate every stored value and every\ncall site."}}},"CreateFunnelRequest":{"type":"object","required":["name","steps"],"properties":{"description":{"type":["string","null"]},"name":{"type":"string"},"steps":{"type":"array","items":{"$ref":"#/components/schemas/CreateFunnelStep"}}}},"CreateFunnelResponse":{"type":"object","required":["funnel_id","message"],"properties":{"funnel_id":{"type":"integer","format":"int32"},"message":{"type":"string"}}},"CreateFunnelStep":{"type":"object","required":["event_name"],"properties":{"event_filter":{"type":"array","items":{"$ref":"#/components/schemas/SmartFilter"}},"event_name":{"type":"string"}}},"CreateGenericRequest":{"type":"object","required":["name","clone_url"],"properties":{"base_url":{"type":["string","null"],"description":"Optional base URL of the git host for display purposes (no API is called)."},"clone_url":{"type":"string","description":"HTTPS clone URL for the repository, e.g. `https://git.example.com/org/repo.git`."},"name":{"type":"string","description":"Display name for this provider."},"token":{"type":["string","null"],"description":"Access token or password. Omit (or set to `null`) for public repositories."},"token_username":{"type":["string","null"],"description":"HTTP Basic username used with the token. Defaults to `x-access-token` when\nabsent or empty. Ignored for public (unauthenticated) repositories."}}},"CreateGitHubPATRequest":{"type":"object","required":["name","token"],"properties":{"name":{"type":"string"},"token":{"type":"string"}}},"CreateGitLabOAuthRequest":{"type":"object","required":["name","client_id","client_secret","redirect_uri"],"properties":{"base_url":{"type":["string","null"]},"client_id":{"type":"string"},"client_secret":{"type":"string"},"name":{"type":"string"},"redirect_uri":{"type":"string"}}},"CreateGitLabPATRequest":{"type":"object","required":["name","token"],"properties":{"base_url":{"type":["string","null"]},"name":{"type":"string"},"token":{"type":"string"}}},"CreateGiteaPATRequest":{"type":"object","required":["name","token","base_url"],"properties":{"base_url":{"type":"string","description":"HTTPS base URL of the Gitea instance, e.g. `https://git.example.com`."},"name":{"type":"string","description":"Display name for this provider."},"token":{"type":"string","description":"Personal access token issued by the Gitea instance."}}},"CreateIncidentRequest":{"type":"object","required":["title","severity"],"properties":{"description":{"type":["string","null"]},"environment_id":{"type":["integer","null"],"format":"int32"},"monitor_id":{"type":["integer","null"],"format":"int32"},"severity":{"type":"string"},"title":{"type":"string"}}},"CreateIntegrationBody":{"type":"object","required":["provider","signing_secret"],"properties":{"provider":{"type":"string","description":"Registered provider name, e.g. \"stripe\"."},"signing_secret":{"type":"string","description":"Signing secret from the provider's dashboard."}}},"CreateIpAccessControlRequest":{"type":"object","description":"Request to create an IP access control rule","required":["ip_address","action"],"properties":{"action":{"type":"string","description":"Action to take: \"block\" or \"allow\"","example":"block"},"ip_address":{"type":"string","description":"IP address in CIDR notation (e.g., \"192.168.1.1\" or \"10.0.0.0/24\")","example":"192.168.1.100"},"reason":{"type":["string","null"],"description":"Optional reason for the action","example":"Malicious activity detected"}}},"CreateMcpRequest":{"type":"object","required":["slug","name","config"],"properties":{"config":{"type":"object"},"description":{"type":["string","null"]},"name":{"type":"string"},"slug":{"type":"string"}}},"CreateMetricAlertRequest":{"type":"object","required":["project_id","name","metric_name","aggregation","detection_config","window_secs","for_duration_secs","severity","enabled"],"properties":{"aggregation":{"type":"string","description":"One of `avg|sum|min|max|count|rate|p50|p90|p95|p99`."},"detection_config":{"$ref":"#/components/schemas/DetectionConfig","description":"The detector: a discriminated union keyed by `kind`. Today only\n`{ \"kind\": \"static\", \"comparator\": \"gt\", \"threshold\": 500 }` is evaluable."},"dynamic_alerts":{"type":"boolean","description":"When true (and `group_by` is set) fire one independent alarm per breaching\nseries. Static detectors only. Default false."},"enabled":{"type":"boolean"},"for_duration_secs":{"type":"integer","format":"int32"},"group_by":{"type":"array","items":{"type":"string"},"description":"Label keys to break the metric down by, e.g. `[\"endpoint\",\"region\"]`. Empty\n(the default) = one aggregate stream. Max 2 keys; keys must match\n`[a-zA-Z0-9_.:-]`."},"grouped_notification_threshold":{"type":"integer","format":"int32","description":"When more than this many series transition to firing in the same tick, only\nthe first gets the expensive chart/AI enrichment. Range 1–1000, default 5."},"label_filters":{"type":"array","items":{"type":"array","items":false,"prefixItems":[{"type":"string"},{"type":"string"}]},"description":"AND-combined label equality filters: `[[\"key\",\"value\"],…]`. Empty = no\nfiltering (the default). Max 10 pairs; keys must match `[a-zA-Z0-9_.:-]`;\nvalues capped at 500 characters."},"max_series":{"type":"integer","format":"int32","description":"Cardinality cap for dynamic alerting: at most this many series (top by\n`|value|`). Range 1–100, default 20."},"metric_name":{"type":"string"},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"severity":{"type":"string","description":"One of `info|warning|critical`."},"window_secs":{"type":"integer","format":"int32"}}},"CreateMonitorRequest":{"type":"object","required":["name","monitor_type","environment_id"],"properties":{"check_interval_seconds":{"type":["integer","null"],"format":"int32"},"check_path":{"type":["string","null"]},"environment_id":{"type":"integer","format":"int32"},"monitor_type":{"type":"string"},"name":{"type":"string"}}},"CreateNotificationEmailProviderRequest":{"type":"object","required":["name","config"],"properties":{"config":{"$ref":"#/components/schemas/EmailConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":"string"}}},"CreateOidcProviderRequest":{"type":"object","required":["name","issuer_url","client_id","client_secret"],"properties":{"client_id":{"type":"string"},"client_secret":{"type":"string"},"default_role":{"type":"string"},"enabled":{"type":"boolean"},"group_claim":{"type":"string"},"issuer_url":{"type":"string"},"jit_provisioning":{"type":"boolean"},"name":{"type":"string"},"role_claim":{"type":"string"},"scopes":{"type":"string"},"template":{"type":"string"},"trust_idp_email":{"type":"boolean","description":"Defaults false. Set to true only for IdPs where an admin\ncontrols user provisioning (corporate Okta, Azure AD) and\nself-signup of arbitrary emails is not possible — see the\n`trust_idp_email` field on `oidc_providers::Model` for the\nsecurity tradeoff this enables."}}},"CreateOidcRoleMappingRequest":{"type":"object","required":["priority","idp_group","role"],"properties":{"idp_group":{"type":"string"},"priority":{"type":"integer","format":"int32"},"role":{"type":"string"}}},"CreatePlanRequest":{"type":"object","description":"Request to create an import plan","required":["source","workload_id"],"properties":{"credentials":{"$ref":"#/components/schemas/ImportCredentials","description":"Platform credentials (required for cloud platforms like Vercel, Railway)"},"repository_id":{"type":["integer","null"],"format":"int32","description":"Optional repository ID to associate with the import\nIf provided, preset will be detected from the repository"},"source":{"$ref":"#/components/schemas/ImportSource","description":"Source to import from"},"workload_id":{"$ref":"#/components/schemas/WorkloadId","description":"Workload ID to import"}}},"CreatePlanResponse":{"type":"object","description":"Response with created plan","required":["session_id","plan","validation","can_execute"],"properties":{"can_execute":{"type":"boolean","description":"Whether the plan can be executed"},"plan":{"$ref":"#/components/schemas/ImportPlan","description":"Generated import plan"},"session_id":{"type":"string","description":"Session ID for tracking"},"validation":{"$ref":"#/components/schemas/ValidationReport","description":"Validation report"}}},"CreatePrResponse":{"type":"object","required":["run","pr_url","pr_number","branch_name"],"properties":{"branch_name":{"type":"string"},"pr_number":{"type":"integer","format":"int32"},"pr_url":{"type":"string"},"run":{"$ref":"#/components/schemas/AutofixerRunResponse"}}},"CreateProjectAccessRequest":{"type":"object","required":["team_id","role"],"properties":{"role":{"$ref":"#/components/schemas/TeamRole"},"team_id":{"type":"integer","format":"int32"}}},"CreateProjectFromTemplateRequest":{"type":"object","description":"Request to create a project from a template\n\nSupports two deploy modes:\n * **Fork mode** — when `git_provider_connection_id` is set, the template\n repo is cloned into a new repository under the user's Git account and the\n project tracks that fork (git-push deploys, automatic deploy on push).\n * **One-click public-repo mode** — when `git_provider_connection_id` is\n omitted, the project deploys directly from the template's public source\n repository (no fork, no Git account required). This is the activation\n path: a brand-new user with no Git provider connected can still deploy a\n demo in one click. `repository_name` / `repository_owner` are ignored in\n this mode, and automatic-deploy-on-push is unavailable (there is no fork\n to receive webhooks).","required":["template_slug","project_name"],"properties":{"automatic_deploy":{"type":"boolean","description":"Enable automatic deployment on push (defaults to true). Only honoured in\nfork mode; public-repo deploys cannot receive push webhooks."},"environment_variables":{"type":"array","items":{"$ref":"#/components/schemas/EnvVarInput"},"description":"Environment variables to set (key-value pairs)"},"git_provider_connection_id":{"type":["integer","null"],"format":"int32","description":"Git provider connection ID. When omitted, the project deploys directly\nfrom the template's public source repository instead of forking it."},"private":{"type":"boolean","description":"Whether to make the repository private (defaults to true)"},"project_name":{"type":"string","description":"Name for the new project"},"repository_name":{"type":["string","null"],"description":"Name for the new repository to create. Required in fork mode; ignored in\none-click public-repo mode."},"repository_owner":{"type":["string","null"],"description":"Owner/organization for the new repository (defaults to authenticated user)"},"storage_service_ids":{"type":"array","items":{"type":"integer","format":"int32"},"description":"External storage service IDs to attach to the project"},"template_slug":{"type":"string","description":"Template slug to use as the base"}}},"CreateProjectFromTemplateResponse":{"type":"object","description":"Response after creating a project from template","required":["project_id","project_slug","project_name","repository_url","template_slug","message"],"properties":{"message":{"type":"string","description":"Message with additional info"},"project_id":{"type":"integer","format":"int32","description":"ID of the created project"},"project_name":{"type":"string","description":"Name of the created project"},"project_slug":{"type":"string","description":"Slug of the created project"},"repository_url":{"type":"string","description":"URL of the created repository"},"template_slug":{"type":"string","description":"Template that was used"}}},"CreateProjectRequest":{"type":"object","required":["name","directory","main_branch","preset","storage_service_ids"],"properties":{"automatic_deploy":{"type":["boolean","null"]},"build_command":{"type":["string","null"]},"custom_domain":{"type":["string","null"]},"directory":{"type":"string"},"environment_variables":{"type":["array","null"],"items":{"type":"array","items":false,"prefixItems":[{"type":"string"},{"type":"string"}]}},"exposed_port":{"type":["integer","null"],"format":"int32","description":"Port exposed by the container (fallback when image has no EXPOSE directive)\n\nPriority order for port resolution:\n1. Image EXPOSE directive (auto-detected from built image)\n2. Environment-level exposed_port (overrides this value per environment)\n3. This project-level exposed_port (fallback)\n4. Default: 3000\n\nOnly set this if your image doesn't use EXPOSE directive.","example":8080},"git_provider_connection_id":{"type":["integer","null"],"format":"int32"},"git_url":{"type":["string","null"]},"install_command":{"type":["string","null"]},"is_on_demand":{"type":["boolean","null"]},"is_public_repo":{"type":["boolean","null"]},"is_web_app":{"type":["boolean","null"]},"main_branch":{"type":"string"},"name":{"type":"string"},"output_dir":{"type":["string","null"]},"performance_metrics_enabled":{"type":"boolean"},"preset":{"type":"string"},"preset_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PresetConfigSchema","description":"Preset-specific configuration\n\nDifferent presets accept different configuration options:\n- **Dockerfile preset**: Accepts `DockerfilePresetConfig` with `dockerfile_path` and `build_context`\n- **Nixpacks preset**: Accepts ordered `providers` (for example `[\"...\", \"python\"]`)\n and optional inline `nixpacksConfig` TOML\n- **Static presets** (Vite, Next.js, etc.): Accept `StaticPresetConfig` with build commands and output dir\n\nExample for Dockerfile preset:\n```json\n{\n \"dockerfilePath\": \"docker/Dockerfile\",\n \"buildContext\": \"./api\"\n}\n```"}]},"project_type":{"type":["string","null"]},"repo_name":{"type":["string","null"]},"repo_owner":{"type":["string","null"]},"source_type":{"$ref":"#/components/schemas/SourceType","description":"Source type for deployments\n\nDetermines how the project is deployed:\n- **git** (default): Traditional Git-based deployments - source code is pulled, built, and deployed\n- **docker_image**: Deploy pre-built Docker images from external registries (DockerHub, GHCR, etc.)\n- **static_files**: Deploy pre-built static files uploaded as tar.gz or zip bundles\n\nFor `docker_image` and `static_files` source types, `repo_name` and `repo_owner` are optional."},"storage_service_ids":{"type":"array","items":{"type":"integer","format":"int32"}},"use_default_wildcard":{"type":["boolean","null"]}}},"CreateProjectSecretRequest":{"type":"object","description":"Request to create a new project secret.\n\nProject secrets are mounted into the container as files under\n`/run/secrets/` (mode 0400, tmpfs) instead of as environment variables.\nValues are always encrypted at rest and never returned in plaintext from\nthe API after create. Distinct from agent secrets (global `/settings/secrets`).","required":["key","value"],"properties":{"environment_ids":{"type":"array","items":{"type":"integer","format":"int32"}},"include_in_preview":{"type":"boolean","description":"Include this secret in preview environments."},"key":{"type":"string","description":"Identifier for the secret. Becomes the filename at `/run/secrets/`.\nMust start with a letter or underscore and contain only A-Z, a-z, 0-9, _."},"value":{"type":"string","description":"Plaintext value, <= 1 MiB."}}},"CreateProviderKeyRequest":{"type":"object","required":["provider","display_name","api_key"],"properties":{"api_key":{"type":"string"},"base_url":{"type":["string","null"]},"default_model":{"type":["string","null"],"description":"Optional model id to pin for this provider (e.g. \"gpt-4o-mini\")."},"display_name":{"type":"string"},"provider":{"type":"string"}}},"CreateProviderRequest":{"type":"object","required":["name","provider_type","config"],"properties":{"config":{},"enabled":{"type":["boolean","null"]},"name":{"type":"string"},"provider_type":{"type":"string"}}},"CreateRouteRequest":{"type":"object","required":["domain","host","port"],"properties":{"domain":{"type":"string"},"host":{"type":"string"},"port":{"type":"integer","format":"int32"},"route_type":{"type":["string","null"],"description":"Route type: \"http\" (default) matches on HTTP Host header,\n\"tls\" matches on TLS SNI hostname for TCP passthrough"}}},"CreateS3SourceRequest":{"type":"object","required":["name","bucket_name","bucket_path","access_key_id","secret_key","region"],"properties":{"access_key_id":{"type":"string"},"bucket_name":{"type":"string"},"bucket_path":{"type":"string"},"endpoint":{"type":["string","null"],"description":"Optional endpoint URL for S3-compatible services like MinIO","example":"http://minio.example.com:9000"},"force_path_style":{"type":["boolean","null"],"description":"Whether to use path-style addressing (default: true)","example":true},"is_default":{"type":["boolean","null"],"description":"When true, make this the default source (will swap out any existing default).\nThe very first S3 source is always created as default regardless of this flag.","example":false},"name":{"type":"string"},"region":{"type":"string"},"secret_key":{"type":"string"}}},"CreateSandboxBody":{"type":"object","properties":{"_runtime":{"type":["string","null"]},"backend":{"type":["string","null"],"description":"Isolation backend: `\"docker\"` (default) or `\"firecracker\"` (ADR-029,\nhardware-virtualized microVM — requires a host provisioned with\n`temps firecracker setup`). Omit for the platform default; existing\nclients are unaffected. Requesting an unavailable backend fails with\n400 rather than silently downgrading isolation."},"cpu_limit":{"type":["number","null"],"format":"double"},"disk_size_mb":{"type":["integer","null"],"format":"int64","description":"Root disk size in MB (Firecracker only; Docker ignores it). Omit for\nthe platform default (1 GiB).","minimum":0},"env":{"type":"object","description":"Extra env vars baked into the container on create.","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"image":{"type":["string","null"],"description":"Docker image override. `null` uses the platform default."},"memory_limit_mb":{"type":["integer","null"],"format":"int64","minimum":0},"name":{"type":["string","null"]},"networkPolicy":{},"pids_limit":{"type":["integer","null"],"format":"int64"},"ports":{"type":"array","items":{"type":"integer","format":"int32","minimum":0},"description":"Ports the sandbox will listen on. Each port becomes a `routes[]`\nentry in the create/get response so `@vercel/sandbox`'s\n`sandbox.domain(port)` can resolve it client-side without an\nextra round-trip."},"preview_password":{"type":["string","null"],"description":"Optional preview-URL password. When set, every preview URL served\nfor this sandbox is gated behind a login form. 8–256 characters.\nOmit to leave preview URLs open (the sandbox ID remains the only\ngate). The plaintext is never returned; only the last-4 hint is\nsurfaced in `SandboxResponse.preview_password_hint`."},"projectId":{"type":["string","null"]},"resources":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ResourcesBody","description":"`@vercel/sandbox`'s nested resources object. When present, its\n`memory` / `vcpus` populate `memory_limit_mb` / `cpu_limit` if those\nweren't sent directly."}]},"source":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SourceBody","description":"Optional initial content to seed into the work dir. Clones a\nrepo or extracts a tarball after the sandbox is created."}]},"timeout":{"type":["integer","null"],"format":"int64","description":"Idle timeout as sent by `@vercel/sandbox` (milliseconds). Converted\nto seconds when `timeout_secs` is absent.","minimum":0},"timeout_secs":{"type":["integer","null"],"format":"int64","description":"Idle timeout in seconds (temps-native). Clamped to `[60, 86400]`.","minimum":0}}},"CreateSkillRequest":{"type":"object","required":["slug","name","content"],"properties":{"content":{"type":"string"},"description":{"type":["string","null"]},"name":{"type":"string"},"slug":{"type":"string"}}},"CreateSlackProviderRequest":{"type":"object","required":["name","config"],"properties":{"config":{"$ref":"#/components/schemas/SlackConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":"string"}}},"CreateTeamMemberRequest":{"type":"object","required":["user_id","role"],"properties":{"role":{"$ref":"#/components/schemas/TeamRole"},"user_id":{"type":"integer","format":"int32"}}},"CreateTeamRequest":{"type":"object","required":["name","slug"],"properties":{"description":{"type":["string","null"]},"name":{"type":"string"},"slug":{"type":"string"}}},"CreateUserRequest":{"type":"object","required":["username","roles"],"properties":{"email":{"type":["string","null"]},"must_change_password":{"type":"boolean"},"password":{"type":["string","null"]},"roles":{"type":"array","items":{"type":"string"}},"username":{"type":"string"}}},"CreateWebhookProviderRequest":{"type":"object","required":["name","config"],"properties":{"config":{"$ref":"#/components/schemas/WebhookConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":"string"}}},"CreateWebhookRequestBody":{"type":"object","required":["url","events"],"properties":{"enabled":{"type":["boolean","null"],"description":"Whether the webhook is enabled","default":true},"events":{"type":"array","items":{"type":"string"},"description":"Event types to subscribe to","example":["deployment.created","deployment.succeeded"]},"secret":{"type":["string","null"],"description":"Secret for HMAC signature verification (optional)"},"url":{"type":"string","description":"Target URL for webhook delivery","example":"https://example.com/webhook"}}},"CreatedResource":{"type":"object","description":"Resource created during import (for rollback / audit)","required":["resource_type","resource_id","resource_name"],"properties":{"resource_id":{"type":"integer","format":"int32","description":"Resource ID"},"resource_name":{"type":"string","description":"Resource name"},"resource_type":{"type":"string","description":"Resource type (project, environment, deployment, service, domain, etc.)"}}},"CronExecutionInfo":{"type":"object","required":["id","cron_id","executed_at","url","status_code","headers","response_time_ms"],"properties":{"cron_id":{"type":"integer","format":"int32"},"error_message":{"type":["string","null"]},"executed_at":{"type":"string"},"headers":{"type":"string"},"id":{"type":"integer","format":"int32"},"response_time_ms":{"type":"integer","format":"int32"},"status_code":{"type":"integer","format":"int32"},"url":{"type":"string"}}},"CronInfo":{"type":"object","required":["id","project_id","environment_id","path","schedule","created_at","updated_at"],"properties":{"created_at":{"type":"string"},"deleted_at":{"type":["string","null"]},"environment_id":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"next_run":{"type":["string","null"]},"path":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"schedule":{"type":"string"},"updated_at":{"type":"string"}}},"CrossProjectSiblingRef":{"type":"object","description":"A sibling project that shares the same `trace_id`, returned by the\nPhase 1 cross-project banner endpoint.","required":["project_id","project_name","project_slug","first_seen"],"properties":{"first_seen":{"type":"string","format":"date-time","description":"ISO 8601 timestamp (UTC, `Z` suffix) of first span ingest for this\n`(trace_id, project_id)` pair."},"project_id":{"type":"integer","format":"int32"},"project_name":{"type":"string"},"project_slug":{"type":"string","description":"URL slug used to link into the sibling project's single-project trace view."}}},"CrossProjectTraceResponse":{"type":"object","description":"Response body for `GET /otel/traces/cross-project/{trace_id}`.\n\nAn empty `siblings` vec is the normal single-project case — never 404.","required":["trace_id","siblings"],"properties":{"siblings":{"type":"array","items":{"$ref":"#/components/schemas/CrossProjectSiblingRef"},"description":"Projects other than the caller's that hold spans for this trace,\nordered by `first_seen ASC`."},"trace_id":{"type":"string","description":"The trace_id that was queried (echoed back for client convenience)."}}},"CurrentStatusResponse":{"type":"object","required":["monitor_id","current_status","uptime_percentage"],"properties":{"avg_response_time_ms":{"type":["number","null"],"format":"double"},"current_status":{"type":"string"},"last_check_at":{"type":["string","null"],"format":"date-time"},"monitor_id":{"type":"integer","format":"int32"},"uptime_percentage":{"type":"number","format":"double"}}},"CustomDomainRequest":{"type":"object","required":["domain","environment_id"],"properties":{"branch":{"type":["string","null"]},"domain":{"type":"string"},"environment_id":{"type":"integer","format":"int32"},"redirect_to":{"type":["string","null"]},"service_name":{"type":["string","null"],"description":"Docker Compose service name this domain routes to (only for docker-compose projects)"},"status_code":{"type":["integer","null"],"format":"int32"}}},"CustomDomainResponse":{"type":"object","required":["id","project_id","domain","status","created_at","updated_at"],"properties":{"branch":{"type":["string","null"]},"created_at":{"type":"integer","format":"int64"},"domain":{"type":"string"},"domain_id":{"type":["integer","null"],"format":"int32"},"environment":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DomainEnvironmentResponse"}]},"expiration_time":{"type":["integer","null"],"format":"int64"},"id":{"type":"integer","format":"int32"},"last_renewed":{"type":["integer","null"],"format":"int64"},"message":{"type":["string","null"]},"project_id":{"type":"integer","format":"int32"},"redirect_to":{"type":["string","null"]},"service_name":{"type":["string","null"],"description":"Docker Compose service name this domain routes to"},"status":{"type":"string"},"status_code":{"type":["integer","null"],"format":"int32"},"updated_at":{"type":"integer","format":"int64"}}},"CustomerMovementResponse":{"type":"object","required":["bucket","new_customers","churned_customers"],"properties":{"bucket":{"type":"string","format":"date-time"},"churned_customers":{"type":"integer","format":"int64"},"new_customers":{"type":"integer","format":"int64"}}},"DashboardLayout":{"type":"object","description":"The typed layout persisted (as JSONB) in `metric_dashboards.layout`.","required":["sections"],"properties":{"sections":{"type":"array","items":{"$ref":"#/components/schemas/DashboardSection"},"description":"Ordered sections that make up the dashboard."}}},"DashboardProjectsAnalyticsQuery":{"type":"object","description":"Query parameters for batch dashboard analytics","required":["project_ids","start_date","end_date"],"properties":{"end_date":{"type":"string","format":"date-time","description":"End date for the query range"},"project_ids":{"type":"string","description":"Comma-separated list of project IDs"},"start_date":{"type":"string","format":"date-time","description":"Start date for the query range"}}},"DashboardProjectsAnalyticsResponse":{"type":"object","description":"Batch response for dashboard project analytics","required":["projects"],"properties":{"projects":{"type":"object","description":"Map of project_id -> analytics data","additionalProperties":{"$ref":"#/components/schemas/ProjectDashboardAnalytics"},"propertyNames":{"type":"string"}}}},"DashboardSection":{"type":"object","description":"A titled group of tiles within a dashboard.","required":["id","title","tiles"],"properties":{"id":{"type":"string","description":"Stable client-generated section id."},"tiles":{"type":"array","items":{"$ref":"#/components/schemas/DashboardTile"},"description":"Tiles rendered within this section."},"title":{"type":"string","description":"Section heading."}}},"DashboardTile":{"type":"object","description":"A single metric tile within a dashboard section.","required":["id","metric_name","aggregation"],"properties":{"aggregation":{"type":"string","description":"Aggregation applied per bucket: one of\n`avg|sum|min|max|count|rate|p50|p90|p95|p99`."},"group_by":{"type":"array","items":{"type":"string"},"description":"Label keys to break the metric down by (group-by / multi-series view).\nEmpty = single aggregated series (current behavior). Max 2 keys — more\ndimensions are unreadable in a chart (ADR-026 Phase 2). Each key must\nmatch `[a-zA-Z0-9_.:-]`. Wired directly to `MetricQuery.group_by` by\nthe tile query path (separate frontend task)."},"id":{"type":"string","description":"Stable client-generated tile id (used as a React key / for reordering)."},"label_filters":{"type":"array","items":{"type":"array","items":false,"prefixItems":[{"type":"string"},{"type":"string"}]},"description":"AND-combined label equality filters: `[[\"key\",\"value\"],…]`. Empty = no\nfiltering. Max 10 pairs; keys must match `[a-zA-Z0-9_.:-]`; values\ncapped at 500 characters. Not yet wired into the tile query path\n(Phase 1 ADR-026 — field round-trips and validates; query wiring is\na separate frontend task)."},"metric_name":{"type":"string","description":"The metric name to chart (e.g. `http.server.duration`)."},"title":{"type":["string","null"],"description":"Optional display title; falls back to the metric name in the UI."}}},"DataImplication":{"type":"object","description":"A specific data implication the user needs to understand","required":["severity","message"],"properties":{"message":{"type":"string","description":"Human-readable description of what could happen"},"recommended_action":{"type":["string","null"],"description":"What the user should do about it (if anything)"},"severity":{"$ref":"#/components/schemas/DataImplicationSeverity","description":"Severity of this implication"}}},"DataImplicationSeverity":{"type":"string","description":"Severity of a data implication","enum":["info","warning","data-not-migrated","potential-data-loss"]},"DatabaseMetricsResponse":{"type":"object","description":"Response for the per-database metrics breakdown.","required":["databases"],"properties":{"databases":{"type":"array","items":{"$ref":"#/components/schemas/DatabaseMetricsRow"},"description":"One entry per database, sorted by the first metric descending\n(largest first) so the biggest database leads the table."}}},"DatabaseMetricsRow":{"type":"object","description":"Per-database metric values for a Postgres service.\n\nA Postgres instance can host many databases (some unrelated to this\nservice). The collector records per-`datname` series; this groups the\nlatest value of each requested metric by database so the UI can render a\n\"Databases\" breakdown table instead of one collapsed number.","required":["database","metrics"],"properties":{"database":{"type":"string","description":"Database name (`datname`)."},"metrics":{"type":"object","description":"Latest value of each requested metric for this database\n(e.g. `{\"pg.database_size_bytes\": 7943871, \"pg.cache_hit_ratio\": 0.99}`).","additionalProperties":{"type":"number","format":"double"},"propertyNames":{"type":"string"}}}},"DelRequest":{"type":"object","description":"Request to delete keys","required":["keys"],"properties":{"keys":{"type":"array","items":{"type":"string"},"description":"The key(s) to delete","example":["user:123","user:456"]},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1}}},"DelResponse":{"type":"object","description":"Response for delete operation","required":["deleted"],"properties":{"deleted":{"type":"integer","format":"int64","description":"Number of keys deleted","example":2}}},"DeleteBlobRequest":{"type":"object","description":"Request to delete blobs","required":["pathnames"],"properties":{"pathnames":{"type":"array","items":{"type":"string"},"description":"Pathnames to delete (relative to project)","example":["images/avatar.png","documents/file.pdf"]},"projectId":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1}}},"DeleteBlobResponse":{"type":"object","description":"Response after deleting blobs","required":["deleted"],"properties":{"deleted":{"type":"integer","format":"int64","description":"Number of blobs deleted","example":2}}},"DeleteResponse":{"type":"object","required":["deleted"],"properties":{"deleted":{"type":"integer","format":"int64","minimum":0}}},"DeployFromImageRequest":{"type":"object","properties":{"external_image_id":{"type":["integer","null"],"format":"int32","description":"External image ID (if already registered). If provided without image_ref,\nthe image reference will be fetched from the registered external image."},"health_check_path":{"type":["string","null"],"description":"Optional HTTP health-check path override (e.g. \"/api/healthz\").\nImage deploys can't read `.temps.yaml`, so this sets the path the deployer\nprobes after the container starts and the path the environment's uptime\nmonitor checks. Must start with '/'. When omitted, defaults to \"/\".","example":"/api/healthz"},"image_ref":{"type":["string","null"],"description":"Docker image reference (e.g., \"ghcr.io/org/app:v1.0\")\nRequired if external_image_id is not provided","example":"ghcr.io/myorg/myapp:v1.0"},"metadata":{"description":"Optional deployment metadata"}}},"DeployFromImageUploadQuery":{"type":"object","description":"Query parameters for deploying from an uploaded image tarball","properties":{"health_check_path":{"type":["string","null"],"description":"Optional HTTP health-check path override (e.g. \"/api/healthz\").\nMust start with '/'. When omitted, defaults to \"/\".","example":"/api/healthz"},"tag":{"type":["string","null"],"description":"Tag to apply to the imported image (e.g., \"myapp:v1.0\")\nIf not provided, a unique tag will be generated","example":"myapp:v1.0"}}},"DeployFromStaticRequest":{"type":"object","required":["static_bundle_id"],"properties":{"health_check_path":{"type":["string","null"],"description":"Optional HTTP health-check path override (e.g. \"/api/healthz\").\nStatic deploys can't read `.temps.yaml`, so this sets the path the deployer\nprobes after the container starts and the path the environment's uptime\nmonitor checks. Must start with '/'. When omitted, defaults to \"/\".","example":"/api/healthz"},"metadata":{"description":"Optional deployment metadata"},"static_bundle_id":{"type":"integer","format":"int32","description":"Static bundle ID (required)"}}},"DeploymentConfig":{"type":"object","description":"Deployment configuration shared between projects and environments\n\nThis configuration can be set at the project level (as defaults) and\noverridden at the environment level for specific deployments.\n\nNote: Environment variables are managed separately and are not part of this config.","properties":{"antiAffinity":{"type":"boolean","description":"Anti-affinity: spread replicas across different nodes.\n\nWhen enabled, the scheduler avoids placing two replicas of the same\nenvironment on the same node. If there are fewer eligible nodes than\nreplicas, remaining replicas wrap around (best-effort spreading).\n\nDefaults to `true` — replicas spread by default."},"automaticDeploy":{"type":["boolean","null"],"description":"Enable automatic deployments on git push.\n`None` = inherit from project config; `Some(true/false)` = explicit override.\nStored as JSONB so absent key → `None` (inherit), never silently defaults to false."},"containerExecEnabled":{"type":"boolean","description":"Enable container exec/shell access (disabled by default for security)"},"cpuLimit":{"type":["integer","null"],"format":"int32","description":"CPU limit in microcores, where 1_000_000 = 1 full CPU core\n(e.g., 2_000_000 = 2 CPUs). NOT millicores. `None` = uncapped."},"cpuRequest":{"type":["integer","null"],"format":"int32","description":"CPU request in microcores, where 1_000_000 = 1 full CPU core\n(e.g., 100_000 = 0.1 CPU, 500_000 = 0.5 CPU, 2_000_000 = 2 CPUs).\nNOT millicores — the deployer formats this as `{n}u` and converts\n`n / 1_000_000` cores into Docker nano_cpus."},"crossArchitectureBuilds":{"type":["boolean","null"],"description":"Build one image per architecture the eligible nodes run.\n\n`None`/`false` (the default) builds exactly once, on the control\nplane's native platform — byte-for-byte the behaviour of a\nsingle-architecture cluster. When enabled and the nodes this\ndeployment could land on span more than one architecture, the build\njob produces one image per architecture; the non-native ones go\nthrough the daemon's `platform` option, which requires QEMU binfmt\nhandlers registered on the control plane.\n\n**Opt-in on purpose.** Cross-architecture builds are emulated and\nsubstantially slower, and deriving them from cluster topology would\nmean a single node joining silently changes build behaviour for every\ndeployment in the cluster. It also keeps the decision on operator\nconfig rather than on a value each node reports about itself.\n\n`Option` so an environment inherits the project's setting\n(`None`) or overrides it, matching `automatic_deploy`."},"exposedPort":{"type":["integer","null"],"format":"int32","description":"Port exposed by the container\nIf not specified, will be auto-detected from Docker image or default to 3000"},"idleTimeoutSeconds":{"type":"integer","format":"int32","description":"Seconds of inactivity before containers are stopped in on-demand mode.\nOnly used when `on_demand` is true. Min: 60, Max: 86400 (24h).\nDefault: 300 (5 minutes)."},"memoryLimit":{"type":["integer","null"],"format":"int32","description":"Memory limit in megabytes. Three-state semantics:\n- `None` → inherit the parent layer (env inherits project, project\n inherits the seeded default); used by the settings UI's \"Use default\".\n- `Some(0)` → explicit **uncapped**: stop inheriting and run with no\n memory limit. This is the deliberate escape hatch for dedicated\n workloads, distinct from `None`.\n- `Some(n)` → hard cap of `n` MB.\n\n`merge`/resolution keep `Some(0)` as a present value (it wins precedence\nover a parent cap), and the deployer collapses it to \"no limit\" before\ntalking to Docker."},"memoryRequest":{"type":["integer","null"],"format":"int32","description":"Memory request in megabytes (e.g., 128 = 128MB)"},"onDemand":{"type":"boolean","description":"Enable on-demand mode (scale-to-zero).\nWhen enabled, containers are stopped after `idle_timeout_seconds` of no traffic\nand automatically started when a new request arrives."},"performanceMetricsEnabled":{"type":"boolean","description":"Enable performance metrics collection (speed insights)"},"replicas":{"type":"integer","format":"int32","description":"Number of replicas/instances to run\nDefaults to 1 replica"},"security":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SecurityConfig","description":"Security configuration (headers, rate limiting, attack mode, etc.)\nThese settings inherit and override from parent level (Environment > Project > Global)"}]},"sessionRecordingEnabled":{"type":"boolean","description":"Enable session recording for analytics"},"targetLabels":{"description":"Label selector for node-based scheduling. Replicas are only deployed to\nnodes whose labels match the selector.\n\nMatching rules:\n- **Same key, array value** → OR: node must match any value\n- **Different keys** → AND: node must satisfy all keys\n\nExample: `{\"region\": [\"us\", \"asia\"], \"gpu\": \"true\"}`\n→ (region=us OR region=asia) AND gpu=true\n\nApplied after `target_nodes` filtering (they stack)."},"targetNodes":{"type":["array","null"],"items":{"type":"integer","format":"int32"},"description":"Optional list of node IDs to deploy to. When set, replicas are distributed\nonly across these nodes (round-robin). When None, the scheduler distributes\nacross all active nodes (or deploys locally if no nodes exist)."},"wakeTimeoutSeconds":{"type":"integer","format":"int32","description":"Max seconds to wait for containers to start when waking from on-demand sleep.\nRequests return 503 if exceeded. Default: 30."}}},"DeploymentConfigSnapshot":{"type":"object","description":"Deployment configuration snapshot for deployments\n\nThis extends DeploymentConfig with environment variables to capture\nthe complete state of a deployment at the time it was created.","properties":{"automaticDeploy":{"type":"boolean","description":"Enable automatic deployments on git push"},"containerExecEnabled":{"type":"boolean","description":"Enable container exec/shell access"},"cpuLimit":{"type":["integer","null"],"format":"int32","description":"CPU limit in millicores"},"cpuRequest":{"type":["integer","null"],"format":"int32","description":"CPU request in millicores"},"environmentVariables":{"type":"object","description":"Environment variables used for this deployment","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"exposedPort":{"type":["integer","null"],"format":"int32","description":"Port exposed by the container"},"memoryLimit":{"type":["integer","null"],"format":"int32","description":"Memory limit in megabytes"},"memoryRequest":{"type":["integer","null"],"format":"int32","description":"Memory request in megabytes"},"performanceMetricsEnabled":{"type":"boolean","description":"Enable performance metrics collection"},"replicas":{"type":"integer","format":"int32","description":"Number of replicas"},"sessionRecordingEnabled":{"type":"boolean","description":"Enable session recording"}}},"DeploymentConfiguration":{"type":"object","description":"Deployment-level configuration","required":["image","strategy","env_vars","ports","volumes","network","resources"],"properties":{"build":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/BuildConfiguration","description":"Build configuration (if building from source)"}]},"command":{"type":["array","null"],"items":{"type":"string"},"description":"Command override"},"entrypoint":{"type":["array","null"],"items":{"type":"string"},"description":"Entrypoint override"},"env_vars":{"type":"array","items":{"$ref":"#/components/schemas/EnvironmentVariable"},"description":"Environment variables"},"git":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/GitSourcePlan","description":"Where the application's source code lives, when the source platform\nbuilds from a git repository. Execution uses this to link the temps\nproject to the same repository so the real deployment pipeline can\nclone and build it."}]},"health_check":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/HealthCheckConfiguration","description":"Health check configuration"}]},"image":{"type":"string","description":"Image to deploy"},"network":{"$ref":"#/components/schemas/NetworkConfiguration","description":"Network configuration"},"ports":{"type":"array","items":{"$ref":"#/components/schemas/PortMapping"},"description":"Port mappings"},"resources":{"$ref":"#/components/schemas/ResourceLimits","description":"Resource limits"},"strategy":{"$ref":"#/components/schemas/DeploymentStrategy","description":"Deployment strategy"},"volumes":{"type":"array","items":{"$ref":"#/components/schemas/VolumeMount"},"description":"Volume mounts"},"working_dir":{"type":["string","null"],"description":"Working directory"}}},"DeploymentContainerLogContentResponse":{"type":"object","description":"A single captured container-log dump, including its full text content.","required":["id","container_name","size_bytes","truncated","captured_at","content"],"properties":{"captured_at":{"type":"integer","format":"int64"},"container_name":{"type":"string"},"content":{"type":"string","description":"The captured plain-text log content."},"id":{"type":"integer","format":"int32"},"service_name":{"type":["string","null"]},"size_bytes":{"type":"integer","format":"int64"},"truncated":{"type":"boolean"}}},"DeploymentContainerLogResponse":{"type":"object","description":"Metadata for one captured (historical) container-log dump. Listed on the\ndeployment detail page so a user can pick which past container's logs to read.","required":["id","deployment_id","container_id","container_name","size_bytes","truncated","captured_at"],"properties":{"captured_at":{"type":"integer","format":"int64","description":"Unix epoch milliseconds of when the logs were captured (just before\nteardown). Matches the timestamp convention used by `DeploymentResponse`."},"container_id":{"type":"string"},"container_name":{"type":"string"},"deployment_id":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"node_id":{"type":["integer","null"],"format":"int32"},"service_name":{"type":["string","null"]},"size_bytes":{"type":"integer","format":"int64"},"truncated":{"type":"boolean"}}},"DeploymentContainerLogsListResponse":{"type":"object","description":"The list of captured container-log dumps for a deployment.","required":["logs"],"properties":{"logs":{"type":"array","items":{"$ref":"#/components/schemas/DeploymentContainerLogResponse"}}}},"DeploymentEnvironmentResponse":{"type":"object","required":["id","name","slug","domains"],"properties":{"domains":{"type":"array","items":{"type":"string"}},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"slug":{"type":"string"}}},"DeploymentJobResponse":{"type":"object","required":["id","deployment_id","job_id","job_type","name","status","created_at","updated_at","log_id"],"properties":{"created_at":{"type":"integer","format":"int64"},"dependencies":{},"deployment_id":{"type":"integer","format":"int32"},"description":{"type":["string","null"]},"error_message":{"type":["string","null"]},"execution_order":{"type":["integer","null"],"format":"int32"},"finished_at":{"type":["integer","null"],"format":"int64"},"id":{"type":"integer","format":"int32"},"job_config":{"description":"Internal workflow configuration is intentionally redacted. It can\ncontain legacy plaintext secrets or encrypted secret envelopes."},"job_id":{"type":"string"},"job_type":{"type":"string"},"log_id":{"type":"string"},"name":{"type":"string"},"outputs":{},"started_at":{"type":["integer","null"],"format":"int64"},"status":{"type":"string"},"updated_at":{"type":"integer","format":"int64"}}},"DeploymentJobsResponse":{"type":"object","required":["jobs","total"],"properties":{"jobs":{"type":"array","items":{"$ref":"#/components/schemas/DeploymentJobResponse"}},"total":{"type":"integer","minimum":0}}},"DeploymentListResponse":{"type":"object","required":["deployments","total","page","per_page"],"properties":{"deployments":{"type":"array","items":{"$ref":"#/components/schemas/DeploymentResponse"}},"page":{"type":"integer","format":"int64"},"per_page":{"type":"integer","format":"int64"},"total":{"type":"integer","format":"int64"}}},"DeploymentMetadata":{"type":"object","description":"Deployment metadata - typed information about the deployment","properties":{"buildDurationMs":{"type":["integer","null"],"format":"int64","description":"Build duration in milliseconds"},"builder":{"type":["string","null"],"description":"Docker builder used (e.g., \"nixpacks\", \"dockerfile\")"},"deploymentDurationMs":{"type":["integer","null"],"format":"int64","description":"Deployment duration in milliseconds"},"deploymentSourceType":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SourceType","description":"Source type for THIS specific deployment (for Manual/flexible projects)\nThis allows Manual projects to have deployments via different methods\n(docker_image, static_files, or git) while keeping per-deployment tracking"}]},"dockerfilePath":{"type":["string","null"],"description":"Dockerfile path if using Dockerfile builder"},"externalImageId":{"type":["integer","null"],"format":"int32","description":"External image ID (reference to external_images table)"},"externalImageRef":{"type":["string","null"],"description":"External Docker image reference (for docker_image source type)\ne.g., \"ghcr.io/org/app:v1.0\" or \"docker.io/myapp:sha-abc123\""},"fileCount":{"type":["integer","null"],"format":"int32","description":"Number of files in the build output"},"gitPushEvent":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/GitPushEvent","description":"Git push event that triggered this deployment (if from webhook)"}]},"healthCheckPath":{"type":["string","null"],"description":"Explicit deploy-time HTTP health-check path override.\nImage/static deploys can't read `.temps.yaml`, so this lets the deploy\nrequest set a custom path (e.g. \"/api/healthz\"). When present it takes\npriority over any `.temps.yaml` `health.path` value. Always starts with '/'."},"imageSizeBytes":{"type":["integer","null"],"format":"int64","description":"Total size of the built image in bytes"},"imageUploadedLocally":{"type":"boolean","description":"Whether the image was uploaded directly (via docker save/load) rather than pulled from registry\nWhen true, the PullExternalImageJob is skipped since the image is already loaded locally"},"isRollback":{"type":"boolean","description":"Whether this is a rollback deployment"},"labels":{"type":"array","items":{"type":"string"},"description":"Custom labels/tags for the deployment"},"rolledBackFromId":{"type":["integer","null"],"format":"int32","description":"ID of the deployment this was rolled back from (if applicable)"},"sourceBundleContentType":{"type":["string","null"],"description":"Uploaded source archive content type."},"sourceBundleId":{"type":["integer","null"],"format":"int32","description":"Uploaded source archive ID. Source archives are extracted before the\nregular preset build pipeline and do not require Git metadata."},"sourceBundlePath":{"type":["string","null"],"description":"Uploaded source archive path in the Temps data directory."},"staticBundleContentType":{"type":["string","null"],"description":"Static bundle content type (for proper extraction: application/gzip or application/zip)"},"staticBundleId":{"type":["integer","null"],"format":"int32","description":"Static bundle ID (reference to static_bundles table, for static_files source type)"},"staticBundlePath":{"type":["string","null"],"description":"Static bundle path in blob storage (for static_files source type)"},"uploadedImageId":{"type":["string","null"],"description":"Docker image ID of the locally uploaded image (sha256:...)\nUsed to verify the image exists before deployment"}}},"DeploymentResponse":{"type":"object","required":["id","project_id","environment_id","environment","status","url","created_at","is_current"],"properties":{"branch":{"type":["string","null"]},"cancelled_reason":{"type":["string","null"]},"commit_author":{"type":["string","null"]},"commit_date":{"type":["integer","null"],"format":"int64"},"commit_hash":{"type":["string","null"]},"commit_message":{"type":["string","null"]},"created_at":{"type":"integer","format":"int64"},"deployment_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DeploymentConfigSnapshot","description":"Deployment configuration snapshot (CPU, memory, replicas, environment variables, etc.)"}]},"environment":{"$ref":"#/components/schemas/DeploymentEnvironmentResponse"},"environment_id":{"type":"integer","format":"int32"},"finished_at":{"type":["integer","null"],"format":"int64"},"id":{"type":"integer","format":"int32"},"is_current":{"type":"boolean"},"metadata":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DeploymentMetadata","description":"Deployment metadata (build info, git event, etc.)"}]},"project_id":{"type":"integer","format":"int32"},"screenshot_location":{"type":["string","null"]},"started_at":{"type":["integer","null"],"format":"int64"},"status":{"type":"string"},"tag":{"type":["string","null"]},"url":{"type":"string"}}},"DeploymentStateResponse":{"type":"object","required":["id","state","message"],"properties":{"id":{"type":"integer","format":"int32"},"message":{"type":"string"},"state":{"type":"string"}}},"DeploymentStrategy":{"type":"string","description":"Deployment strategy","enum":["replace","blue-green","rolling"]},"DeploymentTokenListResponse":{"type":"object","required":["tokens","total"],"properties":{"tokens":{"type":"array","items":{"$ref":"#/components/schemas/DeploymentTokenResponse"}},"total":{"type":"integer","format":"int64","minimum":0}}},"DeploymentTokenResponse":{"type":"object","required":["id","project_id","name","token_prefix","is_active","created_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00Z"},"created_by":{"type":["integer","null"],"format":"int32"},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"last_used_at":{"type":["string","null"],"format":"date-time","example":"2024-01-01T00:00:00Z"},"name":{"type":"string"},"permissions":{"type":["array","null"],"items":{"type":"string"}},"project_id":{"type":"integer","format":"int32"},"token_prefix":{"type":"string"}}},"DetectionConfig":{"oneOf":[{"allOf":[{"$ref":"#/components/schemas/StaticParams","description":"v0 (shipping): static threshold comparison of the aggregated value."},{"type":"object","required":["kind"],"properties":{"kind":{"type":"string","enum":["static"]}}}],"description":"v0 (shipping): static threshold comparison of the aggregated value."},{"allOf":[{"$ref":"#/components/schemas/AnomalyParams","description":"Seasonal anomaly band (basic/agile/robust/ewma share this variant — the\nalgorithm is a field, not a new kind). Creation rejected until evaluated."},{"type":"object","required":["kind"],"properties":{"kind":{"type":"string","enum":["anomaly"]}}}],"description":"Seasonal anomaly band (basic/agile/robust/ewma share this variant — the\nalgorithm is a field, not a new kind). Creation rejected until evaluated."},{"allOf":[{"$ref":"#/components/schemas/ForecastParams","description":"Predict a future threshold breach (capacity planning). Stub."},{"type":"object","required":["kind"],"properties":{"kind":{"type":"string","enum":["forecast"]}}}],"description":"Predict a future threshold breach (capacity planning). Stub."},{"allOf":[{"$ref":"#/components/schemas/OutlierParams","description":"Cross-series population outlier (one host misbehaving vs its peers). Stub."},{"type":"object","required":["kind"],"properties":{"kind":{"type":"string","enum":["outlier"]}}}],"description":"Cross-series population outlier (one host misbehaving vs its peers). Stub."},{"allOf":[{"$ref":"#/components/schemas/AutoWatchParams","description":"Watchdog-style self-tuning auto-watch (engine picks bounds). Stub."},{"type":"object","required":["kind"],"properties":{"kind":{"type":"string","enum":["auto_watch"]}}}],"description":"Watchdog-style self-tuning auto-watch (engine picks bounds). Stub."}],"description":"The typed detector definition stored (as jsonb) in\n`metric_alert_rules.detection_config`.\n\nToday only [`DetectionConfig::Static`] is evaluable; the other variants are\nschema-present (so the SDK/UI and storage are already future-shaped) but\nrejected by [`DetectionConfig::validate`] until their evaluator lands. Each is\nthen enabled code-only, with no schema migration."},"DeviceCount":{"type":"object","required":["device_type","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"device_type":{"type":"string"},"percentage":{"type":"number","format":"double"}}},"DigestSections":{"type":"object","description":"Sections that can be included in the weekly digest\nNote: `#[serde(default)]` allows backward compatibility when deserializing\nold data that may have `security` and `resources` fields instead of `projects`","properties":{"deployments":{"type":"boolean","default":true},"errors":{"type":"boolean","default":true},"funnels":{"type":"boolean","default":true},"performance":{"type":"boolean","default":true},"projects":{"type":"boolean","default":true}}},"Direction":{"type":"string","description":"Which side(s) of an anomaly band count as a deviation.","enum":["both","above","below"]},"DisableBlobResponse":{"type":"object","description":"Response after disabling Blob service","required":["success","message"],"properties":{"message":{"type":"string","description":"Human-readable message","example":"Blob service disabled successfully"},"success":{"type":"boolean","description":"Whether the operation succeeded","example":true}}},"DisableKvResponse":{"type":"object","description":"Response after disabling KV service","required":["success","message"],"properties":{"message":{"type":"string","description":"Status message","example":"KV service disabled successfully"},"success":{"type":"boolean","description":"Whether the service was successfully disabled"}}},"DisableMfaRequest":{"type":"object","required":["code"],"properties":{"code":{"type":"string"}}},"DiscoverRequest":{"type":"object","description":"Request to discover workloads","required":["source"],"properties":{"credentials":{"$ref":"#/components/schemas/ImportCredentials","description":"Platform credentials (required for cloud platforms like Vercel, Railway)"},"selector":{"$ref":"#/components/schemas/ImportSelector","description":"Optional selector to filter workloads"},"source":{"$ref":"#/components/schemas/ImportSource","description":"Source to discover from"}}},"DiscoverResponse":{"type":"object","description":"Response with discovered workloads","required":["workloads"],"properties":{"workloads":{"type":"array","items":{"$ref":"#/components/schemas/WorkloadDescriptor"},"description":"Discovered workloads"}}},"DiskInfo":{"type":"object","description":"Disk space information for a single disk/partition","required":["mount_point","total_bytes","used_bytes","available_bytes","usage_percent","file_system"],"properties":{"available_bytes":{"type":"integer","format":"int64","description":"Available space in bytes","minimum":0},"file_system":{"type":"string","description":"File system type (e.g., \"ext4\", \"apfs\")"},"mount_point":{"type":"string","description":"Mount point of the disk"},"total_bytes":{"type":"integer","format":"int64","description":"Total space in bytes","minimum":0},"usage_percent":{"type":"number","format":"double","description":"Usage percentage (0-100)"},"used_bytes":{"type":"integer","format":"int64","description":"Used space in bytes","minimum":0}}},"DiskSpaceAlert":{"type":"object","description":"Alert for a disk that exceeds the threshold","required":["mount_point","usage_percent","threshold_percent","available_bytes","available_human"],"properties":{"available_bytes":{"type":"integer","format":"int64","description":"Available space in bytes","minimum":0},"available_human":{"type":"string","description":"Human-readable available space"},"mount_point":{"type":"string","description":"Mount point of the disk"},"threshold_percent":{"type":"integer","format":"int32","description":"Configured threshold percentage","minimum":0},"usage_percent":{"type":"number","format":"double","description":"Current usage percentage"}}},"DiskSpaceAlertSettings":{"type":"object","description":"Disk space alert settings for monitoring disk usage","properties":{"check_interval_seconds":{"type":"integer","format":"int64","description":"Interval in seconds between disk space checks","default":300,"example":300,"minimum":60},"enabled":{"type":"boolean","description":"Whether disk space alerts are enabled","default":true},"monitor_path":{"type":["string","null"],"description":"Restrict monitoring to the disk backing this path. When unset (the\ndefault), every mounted writable volume is monitored — including\ndedicated volumes such as `/var/lib/docker`.","default":null},"threshold_percent":{"type":"integer","format":"int32","description":"Threshold percentage (0-100) at which to trigger alerts","default":80,"example":80,"maximum":100,"minimum":0}}},"DiskSpaceCheckResult":{"type":"object","description":"Result of a disk space check","required":["checked_at","enabled","threshold_percent","disks","alerts"],"properties":{"alerts":{"type":"array","items":{"$ref":"#/components/schemas/DiskSpaceAlert"},"description":"Disks that meet or exceed the threshold"},"checked_at":{"type":"string","format":"date-time","description":"Timestamp of the check (ISO 8601, UTC)","example":"2026-05-28T12:15:47.609192Z"},"disks":{"type":"array","items":{"$ref":"#/components/schemas/DiskInfo"},"description":"List of all monitored disks"},"enabled":{"type":"boolean","description":"Whether disk space monitoring is enabled in settings"},"threshold_percent":{"type":"integer","format":"int32","description":"Configured alert threshold percentage (0-100)","minimum":0}}},"DnsAckRequest":{"type":"object","required":["applied_generation"],"properties":{"applied_generation":{"type":"integer","format":"int64","description":"Highest generation the agent has actually applied locally."}}},"DnsAckResponse":{"type":"object","required":["node_id","applied_generation","server_generation"],"properties":{"applied_generation":{"type":"integer","format":"int64"},"node_id":{"type":"integer","format":"int32"},"server_generation":{"type":"integer","format":"int64"}}},"DnsChallengeRecordResult":{"type":"object","description":"Result of a single DNS TXT record creation for ACME challenge","required":["name","value","success","message"],"properties":{"message":{"type":"string","description":"Human-readable message about the operation"},"name":{"type":"string","description":"TXT record name (e.g., \"_acme-challenge.example.com\")","example":"_acme-challenge.example.com"},"success":{"type":"boolean","description":"Whether the record was created successfully"},"value":{"type":"string","description":"TXT record value (the ACME challenge token)","example":"abc123..."}}},"DnsChangesResponse":{"type":"object","required":["generation","full_snapshot","records","removed_ids"],"properties":{"full_snapshot":{"type":"boolean","description":"`true` ⇒ replace the local zone with `records`. `false` ⇒ merge\n`records` into the existing zone (and remove `removed_ids`)."},"generation":{"type":"integer","format":"int64","description":"Highest generation included in this response. Agent ACKs this back."},"records":{"type":"array","items":{"$ref":"#/components/schemas/EndpointDto"}},"removed_ids":{"type":"array","items":{"type":"integer","format":"int64"},"description":"IDs the agent should remove from its zone. Always empty in the v1\nprotocol — the resolver reconciles by name on snapshot mode. Kept\nin the wire format so a future tombstone-based protocol doesn't\nrequire a breaking change."}}},"DnsCompletionResponse":{"type":"object","required":["domain","status"],"properties":{"domain":{"type":"string"},"status":{"type":"string"}}},"DnsLookupError":{"type":"object","description":"Error response for DNS lookup failures","required":["error","domain"],"properties":{"domain":{"type":"string","description":"Domain name that failed","example":"nonexistent.com"},"error":{"type":"string","description":"Error message","example":"DNS lookup failed: domain not found"}}},"DnsLookupRequest":{"type":"object","description":"Request to lookup DNS A records for a domain","required":["domain"],"properties":{"domain":{"type":"string","description":"Domain name to lookup","example":"example.com"}}},"DnsLookupResponse":{"type":"object","description":"Response containing DNS A records","required":["domain","records","count","dns_servers"],"properties":{"count":{"type":"integer","description":"Number of records found","example":1,"minimum":0},"dns_servers":{"type":"array","items":{"type":"string"},"description":"DNS servers used for the lookup","example":["8.8.8.8","8.8.4.4"]},"domain":{"type":"string","description":"Domain name that was queried","example":"example.com"},"records":{"type":"array","items":{"type":"string"},"description":"List of A record IP addresses","example":["93.184.216.34"]}}},"DnsProviderCredentials":{"oneOf":[{"type":"object","required":["api_token","type"],"properties":{"account_id":{"type":["string","null"]},"api_token":{"type":"string","example":"your-api-token"},"type":{"type":"string","enum":["cloudflare"]}}},{"type":"object","required":["api_user","api_key","type"],"properties":{"api_key":{"type":"string","example":"your-api-key"},"api_user":{"type":"string","example":"your-username"},"client_ip":{"type":["string","null"]},"sandbox":{"type":"boolean"},"type":{"type":"string","enum":["namecheap"]}}},{"type":"object","required":["access_key_id","secret_access_key","type"],"properties":{"access_key_id":{"type":"string","example":"AKIAIOSFODNN7EXAMPLE"},"region":{"type":["string","null"],"example":"us-east-1"},"secret_access_key":{"type":"string","example":"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"},"session_token":{"type":["string","null"]},"type":{"type":"string","enum":["route53"]}}},{"type":"object","required":["api_token","type"],"properties":{"api_token":{"type":"string","example":"dop_v1_your-token"},"type":{"type":"string","enum":["digitalocean"]}}},{"type":"object","required":["service_account_email","private_key","project_id","type"],"properties":{"private_key":{"type":"string","example":"-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----"},"project_id":{"type":"string","example":"my-gcp-project"},"service_account_email":{"type":"string","example":"dns-admin@myproject.iam.gserviceaccount.com"},"type":{"type":"string","enum":["gcp"]}}},{"type":"object","required":["tenant_id","client_id","client_secret","subscription_id","resource_group","type"],"properties":{"client_id":{"type":"string","example":"00000000-0000-0000-0000-000000000000"},"client_secret":{"type":"string"},"resource_group":{"type":"string","example":"my-resource-group"},"subscription_id":{"type":"string","example":"00000000-0000-0000-0000-000000000000"},"tenant_id":{"type":"string","example":"00000000-0000-0000-0000-000000000000"},"type":{"type":"string","enum":["azure"]}}},{"type":"object","description":"Pebble challtestsrv mock DNS (LOCAL DEV/TEST ONLY)","required":["management_url","type"],"properties":{"management_url":{"type":"string","example":"http://localhost:8055"},"type":{"type":"string","enum":["pebble"]}}}],"description":"DNS provider credentials (API-facing)"},"DnsProviderResponse":{"type":"object","description":"DNS provider response","required":["id","name","provider_type","credentials","is_active","flat_hostnames_supported","created_at","updated_at"],"properties":{"created_at":{"type":"string"},"credentials":{"description":"Masked credentials for display"},"description":{"type":["string","null"]},"flat_hostnames_supported":{"type":"boolean","description":"Whether this provider benefits from the flat hostname mode (e.g. Cloudflare\nUniversal SSL). The UI surfaces/recommends the Flat toggle when true."},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"last_error":{"type":["string","null"]},"last_used_at":{"type":["string","null"]},"name":{"type":"string"},"provider_type":{"type":"string"},"updated_at":{"type":"string"}}},"DnsProviderSettings":{"type":"object","properties":{"cloudflare_api_key":{"type":["string","null"],"default":null},"provider":{"type":"string","default":"manual"}}},"DnsProviderSettingsMasked":{"type":"object","description":"DNS provider settings with masked sensitive fields","required":["provider"],"properties":{"cloudflare_api_key":{"type":["string","null"]},"provider":{"type":"string"}}},"DnsProviderType":{"type":"string","description":"Supported DNS provider types","enum":["cloudflare","namecheap","route53","digitalocean","gcp","azure","manual","pebble"]},"DnsRecord":{"type":"object","description":"A DNS record","required":["zone","name","fqdn","content","ttl"],"properties":{"content":{"$ref":"#/components/schemas/DnsRecordContent","description":"Record content"},"fqdn":{"type":"string","description":"Fully qualified domain name","example":"www.example.com"},"id":{"type":["string","null"],"description":"Provider-specific record ID (if exists)","example":"abc123"},"metadata":{"type":"object","description":"Provider-specific metadata","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"name":{"type":"string","description":"Record name (without zone, e.g., \"www\" or \"@\" for root)","example":"www"},"proxied":{"type":"boolean","description":"Whether this record is proxied (Cloudflare-specific)"},"ttl":{"type":"integer","format":"int32","description":"Time to live in seconds","example":300,"minimum":0},"zone":{"type":"string","description":"Zone/domain this record belongs to","example":"example.com"}}},"DnsRecordChange":{"type":"object","description":"A single DNS record change the Cloudflare sync would make.","required":["action","name","record_type","value"],"properties":{"action":{"type":"string","description":"`\"create\"`, `\"update\"`, or `\"delete\"`."},"name":{"type":"string"},"record_type":{"type":"string","description":"Record type, e.g. `\"A\"` or `\"CNAME\"`."},"value":{"type":"string"}}},"DnsRecordContent":{"oneOf":[{"type":"object","description":"A record - IPv4 address (as string, e.g., \"192.0.2.1\")","required":["value","type"],"properties":{"type":{"type":"string","enum":["A"]},"value":{"type":"object","description":"A record - IPv4 address (as string, e.g., \"192.0.2.1\")","required":["address"],"properties":{"address":{"type":"string","example":"192.0.2.1"}}}}},{"type":"object","description":"AAAA record - IPv6 address (as string, e.g., \"2001:db8::1\")","required":["value","type"],"properties":{"type":{"type":"string","enum":["AAAA"]},"value":{"type":"object","description":"AAAA record - IPv6 address (as string, e.g., \"2001:db8::1\")","required":["address"],"properties":{"address":{"type":"string","example":"2001:db8::1"}}}}},{"type":"object","description":"CNAME record - canonical name","required":["value","type"],"properties":{"type":{"type":"string","enum":["CNAME"]},"value":{"type":"object","description":"CNAME record - canonical name","required":["target"],"properties":{"target":{"type":"string"}}}}},{"type":"object","description":"TXT record - text content","required":["value","type"],"properties":{"type":{"type":"string","enum":["TXT"]},"value":{"type":"object","description":"TXT record - text content","required":["content"],"properties":{"content":{"type":"string"}}}}},{"type":"object","description":"MX record - mail exchange","required":["value","type"],"properties":{"type":{"type":"string","enum":["MX"]},"value":{"type":"object","description":"MX record - mail exchange","required":["priority","target"],"properties":{"priority":{"type":"integer","format":"int32","minimum":0},"target":{"type":"string"}}}}},{"type":"object","description":"NS record - nameserver","required":["value","type"],"properties":{"type":{"type":"string","enum":["NS"]},"value":{"type":"object","description":"NS record - nameserver","required":["nameserver"],"properties":{"nameserver":{"type":"string"}}}}},{"type":"object","description":"SRV record - service","required":["value","type"],"properties":{"type":{"type":"string","enum":["SRV"]},"value":{"type":"object","description":"SRV record - service","required":["priority","weight","port","target"],"properties":{"port":{"type":"integer","format":"int32","minimum":0},"priority":{"type":"integer","format":"int32","minimum":0},"target":{"type":"string"},"weight":{"type":"integer","format":"int32","minimum":0}}}}},{"type":"object","description":"CAA record - certification authority authorization","required":["value","type"],"properties":{"type":{"type":"string","enum":["CAA"]},"value":{"type":"object","description":"CAA record - certification authority authorization","required":["flags","tag","value"],"properties":{"flags":{"type":"integer","format":"int32","minimum":0},"tag":{"type":"string"},"value":{"type":"string"}}}}},{"type":"object","description":"PTR record - pointer","required":["value","type"],"properties":{"type":{"type":"string","enum":["PTR"]},"value":{"type":"object","description":"PTR record - pointer","required":["target"],"properties":{"target":{"type":"string"}}}}}],"description":"DNS record content - varies by record type"},"DnsRecordResponse":{"type":"object","required":["record_type","name","value","status"],"properties":{"name":{"type":"string","description":"DNS record name (host)","example":"temps._domainkey.example.com"},"priority":{"type":["integer","null"],"format":"int32","description":"Priority (for MX records)","example":"10","minimum":0},"record_type":{"type":"string","description":"Record type: TXT, CNAME, MX","example":"TXT"},"status":{"$ref":"#/components/schemas/DnsRecordStatusResponse","description":"Verification status: unknown, verified, pending, failed"},"value":{"type":"string","description":"DNS record value","example":"v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3..."}}},"DnsRecordSetupResult":{"type":"object","description":"Result of a single DNS record creation","required":["record_type","name","success","automatic","message"],"properties":{"automatic":{"type":"boolean","description":"Whether the operation was automatic or manual"},"message":{"type":"string","description":"Human-readable message"},"name":{"type":"string","description":"Record name"},"record_type":{"type":"string","description":"Record type (TXT, CNAME, MX)"},"success":{"type":"boolean","description":"Whether the record was created successfully"}}},"DnsRecordStatusResponse":{"type":"string","description":"DNS record verification status","enum":["unknown","verified","pending","failed"]},"DnsZone":{"type":"object","description":"A DNS zone (domain managed by the provider)","required":["id","name","status","nameservers"],"properties":{"id":{"type":"string","description":"Provider-specific zone ID","example":"zone123"},"metadata":{"type":"object","description":"Provider-specific metadata","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"name":{"type":"string","description":"Zone name (domain)","example":"example.com"},"nameservers":{"type":"array","items":{"type":"string"},"description":"Nameservers for this zone"},"status":{"type":"string","description":"Zone status","example":"active"}}},"DockerComposePresetConfig":{"type":"object","description":"Configuration for Docker Compose deployments.","properties":{"composeOverride":{"type":["string","null"],"description":"User-provided docker-compose.override.yml content."},"composePath":{"type":["string","null"],"description":"Path to the Compose file relative to the project directory."},"publicPorts":{"type":"array","items":{"$ref":"#/components/schemas/ComposePublicPort"},"description":"Compose service ports that should be publicly routed."}}},"DockerRegistrySettings":{"type":"object","properties":{"ca_certificate":{"type":["string","null"],"default":null},"enabled":{"type":"boolean","default":false},"password":{"type":["string","null"],"default":null},"registry_url":{"type":["string","null"],"default":null},"tls_verify":{"type":"boolean","default":true},"username":{"type":["string","null"],"default":null}}},"DockerRegistrySettingsMasked":{"type":"object","description":"Docker registry settings with masked sensitive fields","required":["enabled","tls_verify"],"properties":{"ca_certificate":{"type":["string","null"]},"enabled":{"type":"boolean"},"password":{"type":["string","null"]},"registry_url":{"type":["string","null"]},"tls_verify":{"type":"boolean"},"username":{"type":["string","null"]}}},"DockerfilePresetConfig":{"type":"object","description":"Configuration for Dockerfile preset\nAllows customizing the Dockerfile path and build context for Docker-based deployments","properties":{"buildContext":{"type":["string","null"],"description":"Custom build context path (relative to repository root)\nIf not specified, uses the project's directory setting","example":"./api"},"dockerfilePath":{"type":["string","null"],"description":"Custom Dockerfile path (relative to build context)\nIf not specified, defaults to \"Dockerfile\" in the build context","example":"docker/Dockerfile"},"variant":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DockerfileVariant","description":"Catalog variant. Normally omitted; `custom` selects the generated\nDockerfile compatibility preset."}]}}},"DockerfileVariant":{"type":"string","description":"Catalog variant persisted under the canonical Dockerfile preset.\n\nExisting rows predate this discriminator and therefore deserialize as\n[`DockerfileVariant::File`].","enum":["file","custom"]},"DomainAction":{"type":"string","description":"What to do with a domain during migration","enum":["import","skip"]},"DomainChallengeResponse":{"type":"object","required":["domain","txt_records","status"],"properties":{"domain":{"type":"string"},"status":{"type":"string"},"txt_records":{"type":"array","items":{"$ref":"#/components/schemas/TxtRecord"},"description":"Array of TXT records to add to DNS. For wildcards, multiple records are required."}}},"DomainEnvironmentResponse":{"type":"object","required":["id","name","slug"],"properties":{"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"slug":{"type":"string"}}},"DomainError":{"type":"object","required":["message","code"],"properties":{"code":{"type":"string"},"details":{"type":["string","null"]},"message":{"type":"string"}}},"DomainPlan":{"type":"object","description":"Plan for migrating a single custom domain","required":["domain","environment","action","action_description"],"properties":{"action":{"$ref":"#/components/schemas/DomainAction","description":"What to do with this domain"},"action_description":{"type":"string","description":"Human-readable explanation"},"domain":{"type":"string","description":"Full domain name"},"environment":{"type":"string","description":"Which environment to associate with (\"production\")"},"redirect_to":{"type":["string","null"],"description":"Redirect target (if this is a redirect domain)"},"replacement":{"type":["string","null"],"description":"The temps-side address that replaces this domain when it is skipped.\n\nSource-generated domains (sslip.io / traefik.me / platform subdomains)\nembed the source server's IP and would keep pointing at the old\nmachine — this tells the user where the app will be reachable on\ntemps instead."},"status_code":{"type":["integer","null"],"format":"int32","description":"Redirect status code"}}},"DomainResponse":{"type":"object","required":["id","domain","status","is_wildcard","verification_method","created_at","updated_at"],"properties":{"certificate":{"type":["string","null"],"description":"The PEM-encoded certificate chain (can be displayed in browser or downloaded)"},"created_at":{"type":"integer","format":"int64"},"dns_challenge_token":{"type":["string","null"]},"dns_challenge_value":{"type":["string","null"]},"domain":{"type":"string"},"expiration_time":{"type":["integer","null"],"format":"int64"},"id":{"type":"integer","format":"int32"},"is_wildcard":{"type":"boolean"},"last_error":{"type":["string","null"]},"last_error_type":{"type":["string","null"]},"last_renewed":{"type":["integer","null"],"format":"int64"},"on_demand_backoff_until":{"type":["integer","null"],"format":"int64","description":"On-demand TLS negative-cache deadline (epoch millis), when this hostname's\non-demand HTTP-01 issuance is in backoff after a failure (ADR-018 §4).\n`None` means no active backoff."},"status":{"type":"string"},"updated_at":{"type":"integer","format":"int64"},"verification_method":{"type":"string"}}},"DrainNodeResponse":{"type":"object","required":["id","name","status","affected_environments","message"],"properties":{"affected_environments":{"type":"integer","minimum":0},"id":{"type":"integer","format":"int32"},"message":{"type":"string"},"name":{"type":"string"},"status":{"type":"string"}}},"DrainStatusResponse":{"type":"object","description":"Progress of a node drain operation.","required":["node_id","node_name","status","remaining_containers","drain_complete","can_remove","message"],"properties":{"can_remove":{"type":"boolean","description":"Can the node be safely removed?"},"drain_complete":{"type":"boolean","description":"Whether the drain is complete (all containers migrated)"},"message":{"type":"string"},"node_id":{"type":"integer","format":"int32"},"node_name":{"type":"string"},"remaining_containers":{"type":"integer","description":"Number of containers still on this node","minimum":0},"status":{"type":"string"}}},"DropArchiveUpload":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary"}}},"DropInspectionResponse":{"type":"object","required":["suggestedName","candidates"],"properties":{"candidates":{"type":"array","items":{"$ref":"#/components/schemas/DropPresetCandidate"}},"suggestedName":{"type":"string"}}},"DropOffPoint":{"type":"object","description":"Drop-off point: pages where visitors leave the site","required":["page_path","exit_count","total_views","exit_rate"],"properties":{"exit_count":{"type":"integer","format":"int64","description":"Number of exits from this page"},"exit_rate":{"type":"number","format":"double","description":"Exit rate for this page (exit_count / total_views)"},"page_path":{"type":"string","description":"The page path where visitors drop off"},"total_views":{"type":"integer","format":"int64","description":"Total views of this page"}}},"DropPresetCandidate":{"type":"object","required":["directory","preset","label","confidence","reason","isStatic"],"properties":{"confidence":{"type":"string"},"directory":{"type":"string"},"isStatic":{"type":"boolean"},"label":{"type":"string"},"preset":{"type":"string"},"reason":{"type":"string"}}},"EmailConfig":{"type":"object","required":["smtp_host","smtp_port","username","password","from_address","to_addresses"],"properties":{"accept_invalid_certs":{"type":"boolean"},"from_address":{"type":"string"},"from_name":{"type":["string","null"]},"password":{"type":"string"},"smtp_host":{"type":"string"},"smtp_port":{"type":"integer","format":"int32","minimum":0},"starttls_required":{"type":"boolean"},"tls_mode":{"$ref":"#/components/schemas/TlsMode"},"to_addresses":{"type":"array","items":{"type":"string"}},"username":{"type":"string"}}},"EmailDomainResponse":{"type":"object","required":["id","provider_id","domain","status","created_at","updated_at"],"properties":{"created_at":{"type":"string","example":"2025-12-03T10:30:00Z"},"domain":{"type":"string","example":"updates.example.com"},"id":{"type":"integer","format":"int32"},"last_verified_at":{"type":["string","null"]},"provider_id":{"type":"integer","format":"int32"},"status":{"type":"string","example":"verified"},"updated_at":{"type":"string","example":"2025-12-03T10:30:00Z"},"verification_error":{"type":["string","null"]}}},"EmailDomainWithDnsResponse":{"type":"object","required":["domain","dns_records"],"properties":{"dns_records":{"type":"array","items":{"$ref":"#/components/schemas/DnsRecordResponse"}},"domain":{"$ref":"#/components/schemas/EmailDomainResponse"}}},"EmailProviderResponse":{"type":"object","required":["id","name","provider_type","region","is_active","credentials","created_at","updated_at"],"properties":{"created_at":{"type":"string","example":"2025-12-03T10:30:00Z"},"credentials":{"description":"Masked credentials for display"},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"name":{"type":"string","example":"My AWS SES"},"provider_type":{"$ref":"#/components/schemas/EmailProviderTypeRoute"},"region":{"type":"string","example":"us-east-1"},"sns_topic_arn":{"type":["string","null"]},"updated_at":{"type":"string","example":"2025-12-03T10:30:00Z"}}},"EmailProviderTypeRoute":{"type":"string","enum":["ses","scaleway","smtp"]},"EmailRequest":{"type":"object","description":"Request body carrying just an email address (password-reset request).","required":["email"],"properties":{"email":{"type":"string"}}},"EmailResponse":{"type":"object","required":["id","from_address","to_addresses","subject","status","created_at","track_opens","track_clicks","open_count","click_count"],"properties":{"bcc_addresses":{"type":["array","null"],"items":{"type":"string"}},"cc_addresses":{"type":["array","null"],"items":{"type":"string"}},"click_count":{"type":"integer","format":"int32","description":"Number of times links in the email were clicked"},"created_at":{"type":"string","example":"2025-12-03T10:30:00Z"},"domain_id":{"type":["integer","null"],"format":"int32"},"error_message":{"type":["string","null"]},"first_clicked_at":{"type":["string","null"],"description":"When a link was first clicked"},"first_opened_at":{"type":["string","null"],"description":"When the email was first opened"},"from_address":{"type":"string","example":"hello@updates.example.com"},"from_name":{"type":["string","null"]},"headers":{"type":["object","null"],"additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"html_body":{"type":["string","null"]},"id":{"type":"string","example":"550e8400-e29b-41d4-a716-446655440000"},"open_count":{"type":"integer","format":"int32","description":"Number of times the email was opened"},"project_id":{"type":["integer","null"],"format":"int32"},"provider_message_id":{"type":["string","null"]},"reply_to":{"type":["string","null"]},"sent_at":{"type":["string","null"]},"status":{"type":"string","example":"sent"},"subject":{"type":"string"},"tags":{"type":["array","null"],"items":{"type":"string"}},"text_body":{"type":["string","null"]},"to_addresses":{"type":"array","items":{"type":"string"}},"track_clicks":{"type":"boolean","description":"Whether click tracking is enabled"},"track_opens":{"type":"boolean","description":"Whether open tracking is enabled"},"tracked_html_body":{"type":["string","null"],"description":"The final HTML sent to the provider (with tracking pixel and rewritten links)"}}},"EmailStatsResponse":{"type":"object","required":["total","sent","failed","queued","captured"],"properties":{"captured":{"type":"integer","format":"int64","description":"Emails captured without sending (Mailhog mode - no provider configured)","minimum":0},"failed":{"type":"integer","format":"int64","minimum":0},"queued":{"type":"integer","format":"int64","minimum":0},"sent":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"EmailStatusResponse":{"type":"object","required":["email_configured","password_reset_available","oidc_providers"],"properties":{"email_configured":{"type":"boolean"},"oidc_providers":{"type":"array","items":{"$ref":"#/components/schemas/OidcProviderSummary"}},"password_reset_available":{"type":"boolean"}}},"EmailTrackingResponse":{"type":"object","description":"Email tracking summary","required":["email_id","track_opens","track_clicks","open_count","click_count","unique_opens","unique_clicks","links"],"properties":{"click_count":{"type":"integer","format":"int32"},"email_id":{"type":"string"},"first_clicked_at":{"type":["string","null"]},"first_opened_at":{"type":["string","null"]},"links":{"type":"array","items":{"$ref":"#/components/schemas/TrackedLinkResponse"}},"open_count":{"type":"integer","format":"int32"},"track_clicks":{"type":"boolean"},"track_opens":{"type":"boolean"},"unique_clicks":{"type":"integer","format":"int64","minimum":0},"unique_opens":{"type":"integer","format":"int64","minimum":0}}},"EmailTrackingSetupResponse":{"type":"object","description":"Result of the one-click AWS-side event-tracking setup.","required":["topic_arn","webhook_url","subscription_requested","event_destination_attached"],"properties":{"event_destination_attached":{"type":"boolean","description":"The SESv2 event destination (bounce/complaint/delivery) is attached\nto the `temps-tracking` configuration set."},"subscription_requested":{"type":"boolean","description":"The webhook subscription was requested; SNS confirms it\nasynchronously through the webhook itself."},"topic_arn":{"type":"string","example":"arn:aws:sns:us-east-1:123456789012:temps-email-events-1"},"webhook_url":{"type":"string"}}},"EmailTrackingStatusResponse":{"type":"object","description":"Live status of the SES event-tracking pipeline for one provider.","required":["webhook_url","supports_event_tracking"],"properties":{"last_event_at":{"type":["string","null"],"description":"Most recent delivered/bounced/complained event recorded for an email\nsent through this provider. `null` means no provider feedback has\narrived yet.","example":"2026-07-18T10:31:00Z"},"sns_topic_arn":{"type":["string","null"]},"subscription_confirmed_at":{"type":["string","null"],"description":"When the SNS subscription for the current topic was confirmed.\n`null` with a topic set usually means the subscription is still\npending — most often because the endpoint was subscribed before the\ntopic ARN was saved here.","example":"2026-07-18T10:30:00Z"},"supports_event_tracking":{"type":"boolean","description":"Only SES providers support SNS event tracking."},"webhook_url":{"type":"string","description":"Public webhook endpoint SNS must deliver events to.","example":"https://temps.example.com/api/t/webhook/ses"}}},"EmbeddingData":{"type":"object","required":["object","embedding","index"],"properties":{"embedding":{"type":"array","items":{"type":"number","format":"double"}},"index":{"type":"integer","format":"int32"},"object":{"type":"string"}}},"EmbeddingInput":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]},"EmbeddingRequest":{"type":"object","required":["model","input"],"properties":{"dimensions":{"type":["integer","null"],"format":"int32"},"encoding_format":{"type":["string","null"]},"input":{"$ref":"#/components/schemas/EmbeddingInput"},"model":{"type":"string"}}},"EmbeddingResponse":{"type":"object","required":["object","data","model","usage"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/EmbeddingData"}},"model":{"type":"string"},"object":{"type":"string"},"usage":{"$ref":"#/components/schemas/EmbeddingUsage"}}},"EmbeddingUsage":{"type":"object","required":["prompt_tokens","total_tokens"],"properties":{"prompt_tokens":{"type":"integer","format":"int64"},"total_tokens":{"type":"integer","format":"int64"}}},"EnableBlobRequest":{"type":"object","description":"Request to enable Blob service","properties":{"docker_image":{"type":["string","null"],"description":"Docker image to use (optional, defaults to RustFS)","example":"ghcr.io/rustfs/rustfs:0.5.0"},"root_password":{"type":["string","null"],"description":"Root password for S3 access"},"root_user":{"type":["string","null"],"description":"Root user for S3 access"}}},"EnableBlobResponse":{"type":"object","description":"Response after enabling Blob service","required":["success","message","status"],"properties":{"message":{"type":"string","description":"Human-readable message","example":"Blob service enabled successfully"},"status":{"$ref":"#/components/schemas/BlobStatusResponse","description":"Current status"},"success":{"type":"boolean","description":"Whether the operation succeeded","example":true}}},"EnableKvRequest":{"type":"object","description":"Request to enable the KV service","properties":{"docker_image":{"type":["string","null"],"description":"Docker image to use (optional, uses default if not provided)","example":"gotempsh/redis-walg:8-bookworm"},"max_memory":{"type":["string","null"],"description":"Maximum memory allocation (e.g., \"256mb\", \"1gb\")","example":"256mb"},"persistence":{"type":"boolean","description":"Enable data persistence"}}},"EnableKvResponse":{"type":"object","description":"Response after enabling KV service","required":["success","message","status"],"properties":{"message":{"type":"string","description":"Status message","example":"KV service enabled successfully"},"status":{"$ref":"#/components/schemas/KvStatusResponse","description":"Current service status"},"success":{"type":"boolean","description":"Whether the service was successfully enabled"}}},"EnablePgStatStatementsResponse":{"type":"object","description":"Response for the enable pg_stat_statements endpoint.","required":["message"],"properties":{"message":{"type":"string","description":"Human-readable message confirming the action."}}},"EndpointDto":{"type":"object","description":"One DNS record on the wire. Mirrors `service_endpoints::Model` but\nkeeps the API stable across entity evolution. `target_ip` is a string\n(v4 or v6 literal, or CNAME target hostname) parsed by the resolver.","required":["id","fqdn","record_type","ttl","owner_kind","owner_id","generation"],"properties":{"fqdn":{"type":"string"},"generation":{"type":"integer","format":"int64"},"id":{"type":"integer","format":"int64"},"node_id":{"type":["integer","null"],"format":"int32"},"owner_id":{"type":"integer","format":"int64"},"owner_kind":{"type":"string"},"record_type":{"type":"string"},"target_ip":{"type":["string","null"]},"target_port":{"type":["integer","null"],"format":"int32"},"ttl":{"type":"integer","format":"int32"}}},"EnqueuedJob":{"type":"object","description":"A single job that was successfully enqueued during a fan-out run.","required":["backup_id","job_id","engine"],"properties":{"backup_id":{"type":"integer","format":"int32","description":"FK to `backups.id` for this job."},"engine":{"type":"string","description":"Engine key (e.g. `\"control_plane\"`, `\"redis\"`, `\"postgres_pgdump\"`)."},"job_id":{"type":"integer","format":"int64","description":"FK to `backup_jobs.id` for this job."},"target_service_id":{"type":["integer","null"],"format":"int32","description":"FK to `external_services.id` when this is an external-service job.\n`None` for the control-plane job."}}},"EnrichVisitorRequest":{"type":"object","required":["custom_data"],"properties":{"custom_data":{"type":"object"}}},"EnrichVisitorResponse":{"type":"object","required":["success","visitor_id","message"],"properties":{"message":{"type":"string"},"success":{"type":"boolean"},"visitor_id":{"type":"string"}}},"EnrollmentTokenInfo":{"type":"object","required":["id","expires_at","used_count","max_uses","created_at"],"properties":{"bound_node_name":{"type":["string","null"]},"created_at":{"type":"string"},"expires_at":{"type":"string"},"id":{"type":"integer","format":"int32"},"max_uses":{"type":"integer","format":"int32"},"used_count":{"type":"integer","format":"int32"}}},"EnrollmentTokenListResponse":{"type":"object","required":["tokens"],"properties":{"tokens":{"type":"array","items":{"$ref":"#/components/schemas/EnrollmentTokenInfo"}}}},"EntityInfoResponse":{"type":"object","required":["container_path","entity","entity_type","fields"],"properties":{"container_path":{"type":"array","items":{"type":"string"},"description":"Full container path","example":["mydb","public"]},"entity":{"type":"string","description":"Entity name","example":"users"},"entity_type":{"type":"string","description":"Entity type","example":"table"},"fields":{"type":"array","items":{"$ref":"#/components/schemas/FieldResponse"},"description":"Field definitions"},"metadata":{"description":"Additional metadata (content_type, last_modified, etag, etc.)"},"row_count":{"type":["integer","null"],"description":"Approximate row count (for tables/collections)","example":1234,"minimum":0},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Size in bytes (for objects/files)","example":1048576,"minimum":0},"sort_schema":{"description":"JSON Schema for sort options (if supported)"}}},"EntityResponse":{"type":"object","required":["name","entity_type"],"properties":{"entity_type":{"type":"string","description":"Entity type (table, view, collection, etc.)","example":"table"},"name":{"type":"string","description":"Entity name (table/collection)","example":"users"},"row_count":{"type":["integer","null"],"description":"Approximate row count","example":1234,"minimum":0},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Size in bytes (for files/objects)","example":1048576,"minimum":0}}},"EnvVarInput":{"type":"object","description":"Input for environment variable","required":["name","value"],"properties":{"name":{"type":"string","description":"Variable name"},"value":{"type":"string","description":"Variable value"}}},"EnvVarIntegrationInfo":{"type":"object","required":["service_id","service_name","service_type","service_updated_at"],"properties":{"service_id":{"type":"integer","format":"int32"},"service_name":{"type":"string"},"service_slug":{"type":["string","null"]},"service_type":{"type":"string"},"service_updated_at":{"type":"string"}}},"EnvVarResponse":{"type":"object","description":"Environment variable with masked sensitive values","required":["key","value","is_masked"],"properties":{"is_masked":{"type":"boolean","description":"Whether this is a sensitive/masked value"},"key":{"type":"string"},"value":{"type":"string"}}},"EnvVarTemplateResponse":{"type":"object","description":"Environment variable template response","required":["name","required"],"properties":{"default":{"type":["string","null"],"description":"Default value if not provided by user"},"default_generator":{"type":["string","null"],"description":"Frontend-side generator hint for the default value\n(e.g. `app_url`, `random_secret`, `random_hex_32`)"},"description":{"type":["string","null"],"description":"Description of what this variable is used for"},"example":{"type":["string","null"],"description":"Example value for documentation"},"name":{"type":"string","description":"Name of the environment variable"},"required":{"type":"boolean","description":"Whether this variable is required"}}},"EnvironmentConfiguration":{"type":"object","description":"Environment-level configuration","required":["name","subdomain","resources"],"properties":{"name":{"type":"string","description":"Environment name"},"resources":{"$ref":"#/components/schemas/ResourceLimits","description":"Resource limits for environment"},"subdomain":{"type":"string","description":"Proposed subdomain"}}},"EnvironmentDomainResponse":{"type":"object","required":["id","environment_id","domain","created_at","url"],"properties":{"created_at":{"type":"integer","format":"int64"},"domain":{"type":"string"},"environment_id":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"url":{"type":"string","description":"Full URL for this domain (e.g., https://buildtolearndev-production.example.com)","example":"https://buildtolearndev-production.example.com"}}},"EnvironmentInfo":{"type":"object","required":["id","name","main_url"],"properties":{"current_deployment_id":{"type":["integer","null"],"format":"int32"},"id":{"type":"integer","format":"int32"},"main_url":{"type":"string"},"name":{"type":"string"}}},"EnvironmentResponse":{"type":"object","required":["id","project_id","name","slug","main_url","subdomain","created_at","updated_at","is_preview","protected","sleeping"],"properties":{"attack_mode":{"type":["boolean","null"],"description":"Per-environment CAPTCHA attack-mode override.\n`null` means inherit the project-level `attack_mode`; `true`/`false`\nexplicitly enable/disable the challenge for this environment. Always\nserialized (NOT skipped) so the UI can distinguish `null` from `false`."},"branch":{"type":["string","null"]},"created_at":{"type":"integer","format":"int64"},"current_deployment_id":{"type":["integer","null"],"format":"int32"},"deployment_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DeploymentConfig","description":"Deployment configuration for this environment (overrides project-level config)"}]},"estimated_sleep_at":{"type":["integer","null"],"format":"int64","description":"Estimated time (epoch millis) when the environment will go to sleep\nbased on last activity + idle timeout. NULL when sleeping or on-demand disabled."},"force_https":{"type":["boolean","null"],"description":"Per-environment HTTP→HTTPS redirect override.\n`null` means inherit the proxy default (redirect only when the host has\nan active TLS certificate); `true` always redirects plain HTTP for this\nenvironment, `false` never does. Always serialized (NOT skipped) so the\nUI can distinguish `null` from `false`."},"id":{"type":"integer","format":"int32"},"is_preview":{"type":"boolean","description":"Indicates if this is a preview environment (auto-created per branch)\nFor preview environments, 'branch' contains the feature branch name"},"last_activity_at":{"type":["integer","null"],"format":"int64","description":"Last proxied request timestamp (epoch millis) for on-demand environments.\nNULL when on-demand is disabled or no traffic has been received yet."},"main_url":{"type":"string"},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"protected":{"type":"boolean","description":"When true, git pushes do NOT auto-deploy to this environment.\nDeployments must be promoted from another environment."},"sleeping":{"type":"boolean","description":"When true, the environment's containers are currently stopped due to\ninactivity (on-demand mode) and will start on the next request."},"slug":{"type":"string"},"subdomain":{"type":"string","description":"The host label stored for this environment (e.g.\n`myproject-production`). This is the prefix that is combined with the\nplatform's preview domain at request time to produce `main_url`. Edit\nthis via the rename-subdomain endpoint, not the full URL."},"updated_at":{"type":"integer","format":"int64"}}},"EnvironmentVariable":{"type":"object","description":"Environment variable","required":["key","value","is_secret"],"properties":{"is_secret":{"type":"boolean","description":"Whether this is a secret (should be encrypted)"},"key":{"type":"string","description":"Variable name"},"source_description":{"type":["string","null"],"description":"Where this env var originates from (for traceability)"},"value":{"type":"string","description":"Variable value (may be redacted for secrets)"}}},"EnvironmentVariableInfo":{"type":"object","required":["name","value","sensitive"],"properties":{"name":{"type":"string"},"sensitive":{"type":"boolean","description":"Whether this variable contains sensitive data (passwords, keys, tokens)","example":false},"value":{"type":"string"}}},"EnvironmentVariableResponse":{"type":"object","required":["id","key","created_at","updated_at","environments","include_in_preview","is_secret"],"properties":{"created_at":{"type":"integer","format":"int64"},"environments":{"type":"array","items":{"$ref":"#/components/schemas/EnvironmentInfo"}},"id":{"type":"integer","format":"int32"},"include_in_preview":{"type":"boolean","description":"Include this environment variable in preview environments"},"is_secret":{"type":"boolean","description":"Whether the variable is a write-only secret. Secrets always have\n`value: None` in responses."},"key":{"type":"string"},"updated_at":{"type":"integer","format":"int64"},"value":{"type":["string","null"],"description":"Plaintext value for non-secret vars (or `\"***\"` mask for list responses).\n`None` for secret vars — secrets are write-only."}}},"EnvironmentVariableValueResponse":{"type":"object","required":["value"],"properties":{"value":{"type":"string"}}},"ErrorDashboardStatsQuery":{"type":"object","required":["start_time","end_time"],"properties":{"compare_to_previous":{"type":["boolean","null"]},"end_time":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"start_time":{"type":"string","format":"date-time"}}},"ErrorDashboardStatsResponse":{"type":"object","required":["total_errors","total_errors_previous_period","total_errors_change_percent","error_groups","error_groups_previous_period","start_time","end_time"],"properties":{"comparison_end_time":{"type":["string","null"],"format":"date-time"},"comparison_start_time":{"type":["string","null"],"format":"date-time"},"end_time":{"type":"string","format":"date-time"},"error_groups":{"type":"integer","format":"int64"},"error_groups_previous_period":{"type":"integer","format":"int64"},"start_time":{"type":"string","format":"date-time"},"total_errors":{"type":"integer","format":"int64"},"total_errors_change_percent":{"type":"number","format":"double"},"total_errors_previous_period":{"type":"integer","format":"int64"}}},"ErrorEventResponse":{"type":"object","required":["id","error_group_id","timestamp","created_at"],"properties":{"created_at":{"type":"string"},"data":{"description":"Full error event data (contains raw Sentry event or custom error data)"},"error_group_id":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int64"},"source":{"type":["string","null"],"description":"Source of the error event (e.g., \"sentry\", \"custom\", \"bugsnag\")"},"timestamp":{"type":"string"}}},"ErrorGroupResponse":{"type":"object","required":["id","title","error_type","first_seen","last_seen","total_count","status","project_id","created_at","updated_at"],"properties":{"assigned_to":{"type":["string","null"]},"created_at":{"type":"string"},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"error_type":{"type":"string"},"first_seen":{"type":"string"},"id":{"type":"integer","format":"int32"},"last_seen":{"type":"string"},"message_template":{"type":["string","null"]},"project_id":{"type":"integer","format":"int32"},"status":{"type":"string"},"title":{"type":"string"},"total_count":{"type":"integer","format":"int32"},"updated_at":{"type":"string"},"visitor_id":{"type":["integer","null"],"format":"int32"}}},"ErrorGroupStatsResponse":{"type":"object","required":["total_groups","unresolved_groups","resolved_groups","ignored_groups"],"properties":{"ignored_groups":{"type":"integer","format":"int64"},"resolved_groups":{"type":"integer","format":"int64"},"total_groups":{"type":"integer","format":"int64"},"unresolved_groups":{"type":"integer","format":"int64"}}},"ErrorResponse":{"type":"object","required":["error"],"properties":{"details":{"type":["string","null"]},"error":{"type":"string"}}},"ErrorRow":{"type":"object","required":["id","ts","error_group_id","fingerprint","error_class","stacktrace_preview","stacktrace_truncated"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"error_class":{"type":"string"},"error_group_id":{"type":"integer","format":"int32"},"fingerprint":{"type":"string"},"id":{"type":"integer","format":"int64"},"message":{"type":["string","null"]},"stacktrace_preview":{},"stacktrace_truncated":{"type":"boolean"},"trace_id":{"type":["string","null"]},"ts":{"type":"string","format":"date-time"}}},"ErrorTimeSeriesDataResponse":{"type":"object","required":["timestamp","count"],"properties":{"count":{"type":"integer","format":"int64"},"timestamp":{"type":"string"}}},"ErrorTimeSeriesQuery":{"type":"object","required":["start_time","end_time"],"properties":{"bucket":{"type":"string","description":"Time bucket size (e.g., \"1h\", \"15m\", \"1d\", \"1 hour\", \"30 minutes\")","example":"1h"},"end_time":{"type":"string","format":"date-time"},"start_time":{"type":"string","format":"date-time"}}},"EventActivityBucket":{"type":"object","description":"Time bucket data point for event activity graph","required":["timestamp","count","unique_visitors"],"properties":{"count":{"type":"integer","format":"int64","description":"Number of event occurrences in this bucket"},"timestamp":{"type":"string","description":"Timestamp for this bucket (ISO 8601)"},"unique_visitors":{"type":"integer","format":"int64","description":"Number of unique visitors in this bucket"}}},"EventBreakdown":{"type":"string","enum":["country","region","city"]},"EventBrowserStats":{"type":"object","description":"Browser stats for an event","required":["browser","count","percentage"],"properties":{"browser":{"type":"string","description":"Browser name"},"count":{"type":"integer","format":"int64","description":"Number of event occurrences from this browser"},"percentage":{"type":"number","format":"double","description":"Percentage of total events"}}},"EventCount":{"type":"object","required":["event_name","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"event_name":{"type":"string"},"percentage":{"type":"number","format":"double"}}},"EventCountryStats":{"type":"object","description":"Country stats for an event","required":["country","count","percentage"],"properties":{"count":{"type":"integer","format":"int64","description":"Number of event occurrences from this country"},"country":{"type":"string","description":"Country name"},"country_code":{"type":["string","null"],"description":"ISO country code (2-letter)"},"percentage":{"type":"number","format":"double","description":"Percentage of total events"}}},"EventDetailQuery":{"type":"object","description":"Query parameters for event detail analytics","required":["event_name","project_id","start_date","end_date"],"properties":{"bucket_interval":{"type":["string","null"],"description":"Bucket interval for time series: 'hour', 'day', 'week', 'month' (default: auto)"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"event_name":{"type":"string","description":"The specific event name to get details for"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"EventDetailResponse":{"type":"object","description":"Summary response for a specific event's analytics","required":["event_name","total_count","unique_visitors","unique_sessions","activity_over_time","referrers","countries","browsers","bucket_interval"],"properties":{"activity_over_time":{"type":"array","items":{"$ref":"#/components/schemas/EventActivityBucket"},"description":"Time series data for event activity graph"},"browsers":{"type":"array","items":{"$ref":"#/components/schemas/EventBrowserStats"},"description":"Browser distribution of visitors who triggered this event"},"bucket_interval":{"type":"string","description":"Bucket interval used for time series ('hour', 'day', etc.)"},"countries":{"type":"array","items":{"$ref":"#/components/schemas/EventCountryStats"},"description":"Geographic distribution of visitors who triggered this event"},"event_name":{"type":"string","description":"The event name being analyzed"},"referrers":{"type":"array","items":{"$ref":"#/components/schemas/EventReferrerStats"},"description":"Top referrer hostnames for visitors who triggered this event"},"total_count":{"type":"integer","format":"int64","description":"Total number of times this event was triggered in the date range"},"unique_sessions":{"type":"integer","format":"int64","description":"Number of unique sessions where this event occurred"},"unique_visitors":{"type":"integer","format":"int64","description":"Number of unique visitors who triggered this event"}}},"EventEntriesQuery":{"type":"object","description":"Query parameters for the raw event entries list","required":["event_name","project_id","start_date","end_date"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"event_name":{"type":"string","description":"The specific event name to list occurrences for"},"page":{"type":["integer","null"],"format":"int64","description":"Page number (1-based, default: 1)","minimum":0},"per_page":{"type":["integer","null"],"format":"int64","description":"Items per page (default: 20, max: 100)","minimum":0},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"EventEntriesResponse":{"type":"object","description":"Paginated response for raw event entries","required":["event_name","total_count","page","per_page","entries"],"properties":{"entries":{"type":"array","items":{"$ref":"#/components/schemas/EventEntryInfo"},"description":"Individual event occurrences, most recent first"},"event_name":{"type":"string","description":"The event name"},"page":{"type":"integer","format":"int64","description":"Current page number","minimum":0},"per_page":{"type":"integer","format":"int64","description":"Items per page","minimum":0},"total_count":{"type":"integer","format":"int64","description":"Total number of occurrences of this event in the date range"}}},"EventEntryInfo":{"type":"object","description":"A single raw occurrence of an event, including its custom JSON properties","required":["id","timestamp","page_path","href"],"properties":{"browser":{"type":["string","null"],"description":"Browser name"},"city":{"type":["string","null"],"description":"City of the visitor at the time of the event"},"country":{"type":["string","null"],"description":"Country of the visitor at the time of the event"},"country_code":{"type":["string","null"],"description":"ISO country code (2-letter)"},"device_type":{"type":["string","null"],"description":"Device type (Desktop, Mobile, Tablet)"},"href":{"type":"string","description":"Full URL where the event was triggered"},"id":{"type":"integer","format":"int64","description":"Event row ID"},"page_path":{"type":"string","description":"Page path where the event was triggered"},"props":{"type":["object","null"],"description":"Custom event properties as JSON (null when the event carried no data)"},"session_id":{"type":["string","null"],"description":"Session ID the event belongs to (if any)"},"timestamp":{"type":"string","format":"date-time","description":"When the event occurred"},"visitor_id":{"type":["integer","null"],"format":"int32","description":"Visitor numeric ID (if known)"},"visitor_uuid":{"type":["string","null"],"description":"Visitor UUID (if known)"}}},"EventKind":{"type":"string","description":"Tag enum for filter parameters and routing. Matches the variant\ndiscriminator used by `ObservabilityEvent`.","enum":["request","span","error","revenue"]},"EventMetricsPayload":{"type":"object","required":["event_name","event_data","request_path","request_query"],"properties":{"cls":{"type":["number","null"],"format":"float","description":"Cumulative Layout Shift (score)"},"event_data":{},"event_name":{"type":"string"},"fcp":{"type":["number","null"],"format":"float","description":"First Contentful Paint (milliseconds)"},"fid":{"type":["number","null"],"format":"float","description":"First Input Delay (milliseconds)"},"inp":{"type":["number","null"],"format":"float","description":"Interaction to Next Paint (milliseconds)"},"language":{"type":["string","null"]},"lcp":{"type":["number","null"],"format":"float","description":"Largest Contentful Paint (milliseconds)"},"page_title":{"type":["string","null"]},"referrer":{"type":["string","null"],"description":"Referrer URL (falls back to Referer header if not provided)"},"request_path":{"type":"string"},"request_query":{"type":"string"},"screen_height":{"type":["integer","null"],"format":"int32","minimum":0},"screen_width":{"type":["integer","null"],"format":"int32","minimum":0},"ttfb":{"type":["number","null"],"format":"float","description":"Time to First Byte (milliseconds)"},"viewport_height":{"type":["integer","null"],"format":"int32","minimum":0},"viewport_width":{"type":["integer","null"],"format":"int32","minimum":0}}},"EventReferrerStats":{"type":"object","description":"Referrer stats for an event","required":["referrer","count","percentage"],"properties":{"count":{"type":"integer","format":"int64","description":"Number of event occurrences from this referrer"},"percentage":{"type":"number","format":"double","description":"Percentage of total events"},"referrer":{"type":"string","description":"Referrer hostname or \"Direct\""}}},"EventTimeline":{"type":"object","required":["date","count"],"properties":{"count":{"type":"integer","format":"int64"},"date":{"type":"string","format":"date-time"}}},"EventTimelineQuery":{"type":"object","required":["start_date","end_date"],"properties":{"aggregation_level":{"$ref":"#/components/schemas/AggregationLevel","description":"Aggregation level: events (raw count), sessions (unique sessions), or visitors (unique visitors)"},"bucket_size":{"type":["string","null"],"description":"Bucket size: hour, day, or week (auto-detected if not specified)"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"event_name":{"type":["string","null"]},"start_date":{"type":"string","format":"date-time"}}},"EventType":{"type":"object","required":["name","count"],"properties":{"count":{"type":"integer","format":"int64"},"name":{"type":"string"}}},"EventTypeBreakdown":{"type":"object","required":["event_type","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"event_type":{"type":"string"},"percentage":{"type":"number","format":"double"}}},"EventTypeBreakdownQuery":{"type":"object","required":["start_date","end_date"],"properties":{"aggregation_level":{"$ref":"#/components/schemas/AggregationLevel","description":"Aggregation level: events (raw count), sessions (unique sessions), or visitors (unique visitors)"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"EventTypeResponse":{"type":"object","required":["event_type","description","category"],"properties":{"category":{"type":"string"},"description":{"type":"string"},"event_type":{"type":"string"}}},"EventTypesResponse":{"type":"object","required":["events","total","page","page_size"],"properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/EventType"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"EventVisitorInfo":{"type":"object","description":"A visitor who triggered a specific event","required":["visitor_id","visitor_uuid","event_count","first_triggered","last_triggered"],"properties":{"browser":{"type":["string","null"],"description":"Browser name"},"city":{"type":["string","null"],"description":"Visitor's city"},"country":{"type":["string","null"],"description":"Visitor's country"},"country_code":{"type":["string","null"],"description":"Visitor's country code"},"device_type":{"type":["string","null"],"description":"Device type (Desktop, Mobile, Tablet)"},"event_count":{"type":"integer","format":"int64","description":"Number of times this visitor triggered the event"},"first_triggered":{"type":"string","format":"date-time","description":"When the visitor first triggered the event in the date range"},"last_triggered":{"type":"string","format":"date-time","description":"When the visitor last triggered the event in the date range"},"referrer_hostname":{"type":["string","null"],"description":"Referrer hostname for the event"},"visitor_id":{"type":"integer","format":"int32","description":"Visitor numeric ID"},"visitor_uuid":{"type":"string","description":"Visitor UUID"}}},"EventVisitorsQuery":{"type":"object","description":"Query parameters for event visitors list","required":["event_name","project_id","start_date","end_date"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"event_name":{"type":"string","description":"The specific event name to list visitors for"},"page":{"type":["integer","null"],"format":"int64","description":"Page number (1-based, default: 1)","minimum":0},"per_page":{"type":["integer","null"],"format":"int64","description":"Items per page (default: 20, max: 100)","minimum":0},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"EventVisitorsResponse":{"type":"object","description":"Paginated response for event visitors","required":["event_name","total_count","page","per_page","visitors"],"properties":{"event_name":{"type":"string","description":"The event name"},"page":{"type":"integer","format":"int64","description":"Current page number","minimum":0},"per_page":{"type":"integer","format":"int64","description":"Items per page","minimum":0},"total_count":{"type":"integer","format":"int64","description":"Total number of unique visitors who triggered this event"},"visitors":{"type":"array","items":{"$ref":"#/components/schemas/EventVisitorInfo"},"description":"Individual visitors who triggered this event"}}},"EventsCountQuery":{"type":"object","required":["start_date","end_date"],"properties":{"aggregation_level":{"$ref":"#/components/schemas/AggregationLevel","description":"Aggregation level: events (raw count), sessions (unique sessions), or visitors (unique visitors)"},"custom_events_only":{"type":["boolean","null"],"description":"Only return custom events, excluding system events like page_view, page_leave, heartbeat (default: true)"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"EventsResponse":{"type":"object","required":["events","applied_kinds"],"properties":{"applied_kinds":{"type":"array","items":{"$ref":"#/components/schemas/EventKind"},"description":"Echo of the kinds filter actually applied (server-resolved). Useful\nfor clients that pass `kinds=` empty and want to know what they got."},"events":{"type":"array","items":{"$ref":"#/components/schemas/ObservabilityEvent"}}}},"ExecBody":{"type":"object","required":["cmd"],"properties":{"cmd":{"type":"array","items":{"type":"string"}},"cwd":{"type":["string","null"]},"env":{"type":"object","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}}},"additionalProperties":false},"ExecDetachedResponse":{"type":"object","required":["job_id"],"properties":{"job_id":{"type":"string"}}},"ExecResponse":{"type":"object","required":["exit_code","stdout","stderr"],"properties":{"exit_code":{"type":"integer","format":"int32"},"stderr":{"type":"string"},"stdout":{"type":"string"}}},"ExecuteImportRequest":{"type":"object","description":"Request to execute an import","required":["session_id","project_name","preset","directory","main_branch"],"properties":{"directory":{"type":"string","description":"Project directory","example":"."},"dry_run":{"type":["boolean","null"],"description":"Dry run mode (don't create resources)"},"main_branch":{"type":"string","description":"Main branch name","example":"main"},"preset":{"type":"string","description":"Preset to use for the project (e.g., \"nextjs\", \"express\", \"docker\")"},"project_name":{"type":"string","description":"Project name to use (overrides the name from the plan)","example":"my-app"},"session_id":{"type":"string","description":"Session ID from plan creation"}}},"ExecuteImportResponse":{"type":"object","description":"Response from import execution","required":["session_id","status","step_results"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32","description":"Created deployment ID (if completed)"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Created environment ID (if completed)"},"project_id":{"type":["integer","null"],"format":"int32","description":"Created project ID (if completed)"},"session_id":{"type":"string","description":"Session ID"},"status":{"$ref":"#/components/schemas/ImportExecutionStatus","description":"Execution status"},"step_results":{"type":"array","items":{"$ref":"#/components/schemas/StepResult"},"description":"Per-step results (in execution order)"}}},"ExecuteOperationRequest":{"type":"object","required":["operation"],"properties":{"operation":{"type":"string"}}},"ExpireRequest":{"type":"object","description":"Request to set expiration on a key","required":["key","seconds"],"properties":{"key":{"type":"string","description":"The key to set expiration on","example":"session:abc"},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1},"seconds":{"type":"integer","format":"int64","description":"Expiration time in seconds","example":3600}}},"ExpireResponse":{"type":"object","description":"Response for expire operation","required":["success"],"properties":{"success":{"type":"boolean","description":"True if expiration was set, false if key doesn't exist"}}},"ExplorerSupportResponse":{"type":"object","required":["supported","service_type","capabilities","hierarchy"],"properties":{"capabilities":{"type":"array","items":{"type":"string"},"description":"Capabilities supported by this service","example":["sql"]},"filter_schema":{"description":"JSON Schema for filter format with embedded UI hints (if supported)"},"hierarchy":{"type":"array","items":{"$ref":"#/components/schemas/HierarchyLevel"},"description":"Hierarchy levels (describes the navigation structure)"},"reason":{"type":["string","null"],"description":"Reason why explorer is not supported (if applicable)"},"service_type":{"type":"string","description":"Service type","example":"postgres"},"supported":{"type":"boolean","description":"Whether the service supports query explorer functionality","example":true}}},"ExtendTimeoutBody":{"type":"object","properties":{"duration":{"type":["integer","null"],"format":"int64","description":"`@vercel/sandbox`-compatible alternative — duration in milliseconds.\nUsed when `extra_secs` is absent.","minimum":0},"extra_secs":{"type":["integer","null"],"format":"int64","description":"Extra seconds to add to the existing `expires_at` (temps-native).","minimum":0}}},"ExternalImageResponse":{"type":"object","required":["id","project_id","image_ref","pushed_at","created_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"digest":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"image_ref":{"type":"string"},"metadata":{},"project_id":{"type":"integer","format":"int32"},"pushed_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"size_bytes":{"type":["integer","null"],"format":"int64"},"tag":{"type":["string","null"]}}},"ExternalServiceBackupResponse":{"type":"object","description":"Response type for external service backup","required":["id","service_id","backup_id","backup_type","state","started_at","s3_location","metadata","compression_type","created_by"],"properties":{"backup_id":{"type":"integer","format":"int32"},"backup_type":{"type":"string"},"checksum":{"type":["string","null"]},"compression_type":{"type":"string"},"created_by":{"type":"integer","format":"int32"},"error_message":{"type":["string","null"]},"expires_at":{"type":["string","null"],"example":"2025-02-15T14:30:00.123Z"},"finished_at":{"type":["string","null"],"example":"2025-01-15T14:35:00.456Z"},"id":{"type":"integer","format":"int32"},"metadata":{},"s3_location":{"type":"string"},"service_id":{"type":"integer","format":"int32"},"size_bytes":{"type":["integer","null"],"format":"int64"},"started_at":{"type":"string","example":"2025-01-15T14:30:00.123Z"},"state":{"type":"string"}}},"ExternalServiceDetails":{"type":"object","required":["service","sensitive_parameters"],"properties":{"current_parameters":{"type":["object","null"],"additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"parameter_schema":{},"sensitive_parameters":{"type":"array","items":{"type":"string"},"description":"Parameter names whose values are masked in `current_parameters` and\nmay be fetched only through the audited reveal endpoint."},"service":{"$ref":"#/components/schemas/ExternalServiceInfo"}}},"ExternalServiceInfo":{"type":"object","required":["id","name","service_type","status","created_at","updated_at","topology"],"properties":{"connection_info":{"type":["string","null"]},"created_at":{"type":"string"},"error_message":{"type":["string","null"],"description":"Error message from failed initialization."},"id":{"type":"integer","format":"int32"},"members":{"type":"array","items":{"$ref":"#/components/schemas/ServiceMemberInfo"},"description":"Cluster members (empty for standalone services)."},"metrics_enabled":{"type":"boolean","description":"Whether metric collection is enabled for this service. The UI uses this\nto decide whether to poll the monitoring endpoints."},"name":{"type":"string"},"node_id":{"type":["integer","null"],"format":"int32","description":"Node ID where the service runs. Null means control plane (local)."},"service_type":{"$ref":"#/components/schemas/ServiceTypeRoute"},"status":{"type":"string"},"topology":{"type":"string","description":"Service topology: \"standalone\" (single container) or \"cluster\" (HA multi-member).","example":"standalone"},"updated_at":{"type":"string"},"version":{"type":["string","null"]}}},"ExternalServiceSummary":{"type":"object","description":"Summary of the external service that owns a backup. Only populated for\nexternal-service backups (Redis, Postgres, etc.); absent for control-plane\nbackups.","required":["id","name","service_type"],"properties":{"id":{"type":"integer","format":"int32","description":"Database id of the external service."},"name":{"type":"string","description":"Human-readable service name (e.g. \"redis-prod\")."},"service_type":{"type":"string","description":"Service type string (e.g. \"postgres\", \"redis\", \"mongodb\").","example":"postgres"}}},"FieldResponse":{"type":"object","required":["name","field_type","nullable"],"properties":{"field_type":{"type":"string","description":"Field type (Int32, String, Timestamp, etc.)","example":"Int64"},"name":{"type":"string","description":"Field name","example":"id"},"nullable":{"type":"boolean","description":"Whether the field is nullable","example":false}}},"FiringSeriesEntry":{"type":"object","description":"A single currently-firing series for a dynamic alert rule, snapshotted from\nthe evaluator's in-memory per-series firing map at read time (ADR-026 Phase 3).","required":["series_key","series_label"],"properties":{"alarm_id":{"type":["integer","null"],"format":"int32","description":"The open alarm's id, when one was created (absent if suppressed)."},"series_key":{"type":"array","items":{"type":"array","items":false,"prefixItems":[{"type":"string"},{"type":"string"}]},"description":"The series' label pairs, e.g. `[[\"endpoint\",\"/checkout\"],[\"region\",\"eu-west\"]]`."},"series_label":{"type":"string","description":"The human-readable joined label, e.g. `endpoint=/checkout, region=eu-west`."}}},"FlagEnvironmentResponse":{"type":"object","required":["environment_id","enabled"],"properties":{"enabled":{"type":"boolean"},"environment_id":{"type":"integer","format":"int32"},"value":{}}},"FlagListResponse":{"type":"object","description":"Note the absence of `salt`: it is never exposed. Publishing the bucketing\nsalt would let a client predict, and self-select into, a rollout cohort.","required":["flags","total","page","page_size","total_pages"],"properties":{"flags":{"type":"array","items":{"$ref":"#/components/schemas/FlagResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","description":"Total flags matching the filter, across all pages.","minimum":0},"total_pages":{"type":"integer","format":"int64","minimum":0}}},"FlagResponse":{"type":"object","required":["id","key","value_type","default_value","client_visible","created_at","updated_at","environments"],"properties":{"archived_at":{"type":["string","null"]},"client_visible":{"type":"boolean"},"created_at":{"type":"string"},"default_value":{},"description":{"type":["string","null"]},"environments":{"type":"array","items":{"$ref":"#/components/schemas/FlagEnvironmentResponse"},"description":"Per-environment overrides. Empty means the flag inherits its default\neverywhere."},"id":{"type":"integer","format":"int32"},"key":{"type":"string"},"last_evaluated_at":{"type":["string","null"],"description":"When an app last actually evaluated this flag. `None` means never seen,\nwhich is a real answer rather than missing data."},"updated_at":{"type":"string"},"value_type":{"type":"string"}}},"FlagSnapshot":{"type":"object","description":"A single flag, already resolved down to one environment. This is what the\nevaluator sees and what the SDK caches in memory.","required":["key","value_type","default_value","enabled"],"properties":{"default_value":{"description":"Served whenever evaluation cannot do better. Genuinely polymorphic by\ndesign — the surrounding struct carries the type."},"enabled":{"type":"boolean","description":"False means the kill switch is engaged for this environment."},"environment_value":{"description":"`None` means \"inherit `default_value`\"."},"key":{"type":"string"},"value_type":{"$ref":"#/components/schemas/FlagValueType"}}},"FlagSnapshotResponse":{"type":"object","required":["environment_id","flags"],"properties":{"environment_id":{"type":"integer","format":"int32"},"flags":{"type":"array","items":{"$ref":"#/components/schemas/FlagSnapshot"},"description":"Flags collapsed to what the evaluator needs, sorted by key so the\nserialized form — and therefore the ETag — is stable."}}},"FlagValueType":{"type":"string","description":"The declared type of a flag's value. Fixed at create time.","enum":["bool","string","number","json"]},"ForecastAlgorithm":{"type":"string","description":"Forecast model family.","enum":["linear","seasonal"]},"ForecastParams":{"type":"object","description":"Forecast detector parameters (stub — not yet evaluated).","required":["forecast_horizon_secs","comparator","threshold"],"properties":{"algorithm":{"$ref":"#/components/schemas/ForecastAlgorithm"},"comparator":{"$ref":"#/components/schemas/Comparator","description":"Comparator + threshold the *forecast* is checked against."},"deviations":{"type":"number","format":"double"},"forecast_horizon_secs":{"type":"integer","format":"int32","description":"How far ahead to project before checking the breach condition."},"threshold":{"type":"number","format":"double"}}},"FullError":{"type":"object","required":["id","ts","error_group_id","fingerprint","error_class"],"properties":{"data":{"description":"Full JSONB blob from `error_events.data` — stack trace, breadcrumbs,\nrequest context, everything. Schema is documented per source SDK."},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"error_class":{"type":"string"},"error_group_id":{"type":"integer","format":"int32"},"fingerprint":{"type":"string"},"id":{"type":"integer","format":"int64"},"message":{"type":["string","null"]},"trace_id":{"type":["string","null"]},"ts":{"type":"string","format":"date-time"}}},"FullEvent":{"oneOf":[{"allOf":[{"$ref":"#/components/schemas/FullRequest"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["request"]}}}]},{"allOf":[{"$ref":"#/components/schemas/FullError"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["error"]}}}]},{"allOf":[{"$ref":"#/components/schemas/RevenueRow"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["revenue"]}}}]},{"allOf":[{"$ref":"#/components/schemas/SpanRow","description":"`SpanRow.attributes` is the truncated form; re-fetching returns\nthe same shape so the panel has a stable contract."},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["span"]}}}],"description":"`SpanRow.attributes` is the truncated form; re-fetching returns\nthe same shape so the panel has a stable contract."}],"description":"One un-truncated row, returned by the `/full/{type}/{id}` endpoint when\nthe user clicks \"Show full\". Same shape as the list rows, but with the\nraw heavy fields restored (no truncation flags) so the side panel can\nrender the long form."},"FullRequest":{"type":"object","required":["id","ts","method","host","path","status"],"properties":{"client_ip":{"type":["string","null"]},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"error_group_id":{"type":["integer","null"],"format":"int32"},"host":{"type":"string"},"id":{"type":"string","description":"The request's unique `request_id` — same identity the list rows carry\n(backend-agnostic; ClickHouse rows have no serial PK)."},"latency_ms":{"type":["integer","null"],"format":"int32"},"method":{"type":"string"},"path":{"type":"string"},"referrer":{"type":["string","null"]},"request_headers":{},"response_headers":{},"status":{"type":"integer","format":"int32"},"trace_id":{"type":["string","null"]},"ts":{"type":"string","format":"date-time"},"user_agent":{"type":["string","null"]}}},"FunnelMetricsResponse":{"type":"object","required":["funnel_id","funnel_name","total_entries","step_conversions","overall_conversion_rate","average_completion_time_seconds"],"properties":{"average_completion_time_seconds":{"type":"number","format":"double"},"funnel_id":{"type":"integer","format":"int32"},"funnel_name":{"type":"string"},"overall_conversion_rate":{"type":"number","format":"double"},"step_conversions":{"type":"array","items":{"$ref":"#/components/schemas/StepConversionResponse"}},"total_entries":{"type":"integer","format":"int64","minimum":0}}},"FunnelResponse":{"type":"object","required":["id","name","is_active","created_at","updated_at"],"properties":{"created_at":{"type":"string"},"description":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"name":{"type":"string"},"updated_at":{"type":"string"}}},"GatewayStatus":{"type":"object","description":"Detailed gateway container status surfaced to the settings UI.","required":["present","running","health","container_name","expected_image","drift","auto_upgrade"],"properties":{"auto_upgrade":{"type":"boolean","description":"True if `auto_upgrade` is enabled in settings."},"container_name":{"type":"string","description":"Container name."},"drift":{"type":"boolean","description":"True when `image != expected_image` and the container is present."},"expected_image":{"type":"string","description":"The image the supervisor *expects* (from settings/constant). If this\ndiffers from `image`, the UI shows a \"drift\" badge."},"health":{"type":"string","description":"Higher-level health label: \"running\" | \"restarting\" | \"crash_looping\"\n| \"stopped\" | \"missing\". UI should prefer this over `running`."},"host_port":{"type":["integer","null"],"format":"int32","description":"Host port that the container's :8080 is published on.","minimum":0},"image":{"type":["string","null"],"description":"Image reference the container was created with (e.g.\n`ghcr.io/gotempsh/temps-preview-gateway:latest`)."},"image_digest":{"type":["string","null"],"description":"Image digest if available (e.g. `sha256:…`)."},"last_error":{"type":["string","null"],"description":"Error string Docker recorded for the container (e.g. startup failure)."},"last_exit_code":{"type":["integer","null"],"format":"int64","description":"Exit code of the last run, if the container is not currently running."},"network":{"type":["string","null"],"description":"Network the container is attached to (should be `temps-sandbox-net`)."},"present":{"type":"boolean","description":"Whether the container exists at all."},"restart_count":{"type":["integer","null"],"format":"int64","description":"Number of times Docker has restarted the container."},"running":{"type":"boolean","description":"Whether the container is currently running."},"started_at":{"type":["string","null"],"description":"ISO 8601 timestamp the container was started at, if running."}}},"GenAiEvent":{"type":"object","description":"A GenAI-related event extracted from span events.\n\nCovers `gen_ai.client.inference.operation.details` and `gen_ai.evaluation.result`\nevents per the OTel GenAI semantic conventions.","required":["span_id","trace_id","event_name","timestamp","attributes"],"properties":{"attributes":{"type":"object","description":"All event attributes.","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"event_name":{"type":"string"},"span_id":{"type":"string"},"timestamp":{"type":"string","format":"date-time"},"trace_id":{"type":"string"}}},"GenAiSpanDetail":{"type":"object","description":"A single GenAI span with extracted semantic convention fields.\n\nFields are aligned with the OpenTelemetry GenAI Semantic Conventions spec:\n","required":["span_id","name","kind","start_time","duration_ms","status_code","attributes"],"properties":{"agent_description":{"type":["string","null"],"description":"Agent description from `gen_ai.agent.description`."},"agent_id":{"type":["string","null"],"description":"Agent identifier from `gen_ai.agent.id`."},"agent_name":{"type":["string","null"],"description":"Agent name from `gen_ai.agent.name`."},"agent_version":{"type":["string","null"],"description":"Agent version from `gen_ai.agent.version`."},"attributes":{"type":"object","description":"All span attributes for extensibility.","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"aws_bedrock_guardrail_id":{"type":["string","null"],"description":"AWS Bedrock guardrail ID from `aws.bedrock.guardrail.id`."},"aws_bedrock_knowledge_base_id":{"type":["string","null"],"description":"AWS Bedrock knowledge base ID from `aws.bedrock.knowledge_base.id`."},"azure_resource_provider_namespace":{"type":["string","null"],"description":"Azure resource provider namespace from `azure.resource_provider.namespace`."},"cache_creation_input_tokens":{"type":["integer","null"],"format":"int64","description":"Tokens written to provider cache from `gen_ai.usage.cache_creation.input_tokens`."},"cache_read_input_tokens":{"type":["integer","null"],"format":"int64","description":"Tokens served from provider cache from `gen_ai.usage.cache_read.input_tokens`."},"conversation_id":{"type":["string","null"],"description":"Unique conversation/session/thread ID from `gen_ai.conversation.id`."},"data_source_id":{"type":["string","null"],"description":"Data source identifier from `gen_ai.data_source.id`."},"duration_ms":{"type":"number","format":"double"},"embeddings_dimension_count":{"type":["integer","null"],"format":"int64","description":"Output embedding dimensions from `gen_ai.embeddings.dimension.count`."},"error_type":{"type":["string","null"],"description":"Error type from `error.type` when the span status is ERROR."},"gen_ai_model":{"type":["string","null"],"description":"The requested model from `gen_ai.request.model`."},"gen_ai_operation":{"type":["string","null"],"description":"The operation type from `gen_ai.operation.name` (e.g. \"chat\", \"embeddings\", \"execute_tool\")."},"gen_ai_response_model":{"type":["string","null"],"description":"The model that actually generated the response from `gen_ai.response.model`."},"gen_ai_system":{"type":["string","null"],"description":"The GenAI provider from `gen_ai.provider.name` (falls back to deprecated `gen_ai.system`)."},"input_messages":{"type":["string","null"],"description":"Chat history input from `gen_ai.input.messages` (opt-in, JSON string)."},"input_tokens":{"type":["integer","null"],"format":"int64"},"kind":{"$ref":"#/components/schemas/SpanKind"},"name":{"type":"string"},"openai_api_type":{"type":["string","null"],"description":"OpenAI API type from `openai.api.type` (chat_completions, responses)."},"openai_request_service_tier":{"type":["string","null"],"description":"Requested service tier from `openai.request.service_tier`."},"openai_response_service_tier":{"type":["string","null"],"description":"Actual service tier from `openai.response.service_tier`."},"openai_system_fingerprint":{"type":["string","null"],"description":"System fingerprint from `openai.response.system_fingerprint`."},"output_messages":{"type":["string","null"],"description":"Model output from `gen_ai.output.messages` (opt-in, JSON string)."},"output_tokens":{"type":["integer","null"],"format":"int64"},"output_type":{"type":["string","null"],"description":"Output content type from `gen_ai.output.type` (text, json, image, speech)."},"parent_span_id":{"type":["string","null"]},"request_choice_count":{"type":["integer","null"],"format":"int64","description":"Number of choices requested from `gen_ai.request.choice.count`."},"request_encoding_formats":{"type":["array","null"],"items":{"type":"string"},"description":"Requested encoding formats from `gen_ai.request.encoding_formats`."},"request_frequency_penalty":{"type":["number","null"],"format":"double","description":"Frequency penalty from `gen_ai.request.frequency_penalty`."},"request_max_tokens":{"type":["integer","null"],"format":"int64","description":"Max tokens from `gen_ai.request.max_tokens`."},"request_presence_penalty":{"type":["number","null"],"format":"double","description":"Presence penalty from `gen_ai.request.presence_penalty`."},"request_seed":{"type":["integer","null"],"format":"int64","description":"Seed for reproducibility from `gen_ai.request.seed`."},"request_stop_sequences":{"type":["array","null"],"items":{"type":"string"},"description":"Stop sequences from `gen_ai.request.stop_sequences`."},"request_temperature":{"type":["number","null"],"format":"double","description":"Temperature setting from `gen_ai.request.temperature`."},"request_top_k":{"type":["number","null"],"format":"double","description":"Top-k setting from `gen_ai.request.top_k`."},"request_top_p":{"type":["number","null"],"format":"double","description":"Top-p setting from `gen_ai.request.top_p`."},"response_finish_reasons":{"type":["array","null"],"items":{"type":"string"},"description":"Reasons the model stopped from `gen_ai.response.finish_reasons` (e.g. [\"stop\"])."},"response_id":{"type":["string","null"],"description":"Unique completion ID from `gen_ai.response.id` (e.g. \"chatcmpl-123\")."},"retrieval_documents":{"type":["string","null"],"description":"Retrieved documents from `gen_ai.retrieval.documents` (opt-in, JSON string)."},"retrieval_query_text":{"type":["string","null"],"description":"Retrieval query text from `gen_ai.retrieval.query.text` (opt-in)."},"server_address":{"type":["string","null"],"description":"GenAI server address from `server.address`."},"server_port":{"type":["integer","null"],"format":"int64","description":"GenAI server port from `server.port`."},"span_id":{"type":"string"},"start_time":{"type":"string","format":"date-time"},"status_code":{"$ref":"#/components/schemas/SpanStatusCode"},"system_instructions":{"type":["string","null"],"description":"System instructions from `gen_ai.system_instructions` (opt-in, JSON string)."},"tool_call_arguments":{"type":["string","null"],"description":"Tool call arguments from `gen_ai.tool.call.arguments` (opt-in, JSON string)."},"tool_call_id":{"type":["string","null"],"description":"Tool call ID from `gen_ai.tool.call.id`."},"tool_call_result":{"type":["string","null"],"description":"Tool call result from `gen_ai.tool.call.result` (opt-in, JSON string)."},"tool_definitions":{"type":["string","null"],"description":"Tool definitions from `gen_ai.tool.definitions` (opt-in, JSON string)."},"tool_description":{"type":["string","null"],"description":"Tool description from `gen_ai.tool.description`."},"tool_name":{"type":["string","null"],"description":"Tool name from `gen_ai.tool.name`."},"tool_type":{"type":["string","null"],"description":"Tool type from `gen_ai.tool.type` (function, extension, datastore)."}}},"GenAiTraceDetailResponse":{"type":"object","required":["trace_id","spans","span_count","events","event_count"],"properties":{"event_count":{"type":"integer","minimum":0},"events":{"type":"array","items":{"$ref":"#/components/schemas/GenAiEvent"}},"span_count":{"type":"integer","minimum":0},"spans":{"type":"array","items":{"$ref":"#/components/schemas/GenAiSpanDetail"}},"trace_id":{"type":"string"}}},"GenAiTraceSummariesResponse":{"type":"object","required":["data","total"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/GenAiTraceSummary"}},"total":{"type":"integer","format":"int64","minimum":0}}},"GenAiTraceSummary":{"type":"object","description":"Summary of a GenAI conversation — aggregated from OTel spans with `gen_ai.*` attributes.","required":["trace_id","root_span_name","service_name","start_time","duration_ms","span_count","error_count"],"properties":{"duration_ms":{"type":"number","format":"double"},"error_count":{"type":"integer","format":"int64"},"gen_ai_model":{"type":["string","null"],"description":"The requested model from `gen_ai.request.model`."},"gen_ai_operation":{"type":["string","null"],"description":"The operation type from `gen_ai.operation.name` (e.g. \"chat\", \"embeddings\")."},"gen_ai_system":{"type":["string","null"],"description":"The GenAI provider (e.g. \"openai\", \"anthropic\") from `gen_ai.provider.name`."},"root_span_name":{"type":"string"},"service_name":{"type":"string"},"span_count":{"type":"integer","format":"int64"},"start_time":{"type":"string","format":"date-time"},"total_cache_creation_input_tokens":{"type":["integer","null"],"format":"int64","description":"Total cache-creation input tokens across all spans."},"total_cache_read_input_tokens":{"type":["integer","null"],"format":"int64","description":"Total cache-read input tokens across all spans."},"total_input_tokens":{"type":["integer","null"],"format":"int64","description":"Total input tokens across all spans in this trace."},"total_output_tokens":{"type":["integer","null"],"format":"int64","description":"Total output tokens across all spans in this trace."},"trace_id":{"type":"string"}}},"GeneralStatsQuery":{"type":"object","required":["start_date","end_date"],"properties":{"end_date":{"type":"string","format":"date-time"},"start_date":{"type":"string","format":"date-time"}}},"GeneralStatsResponse":{"type":"object","required":["total_unique_visitors","total_visits","total_page_views","total_events","total_projects","avg_bounce_rate","avg_engagement_rate","project_breakdown"],"properties":{"avg_bounce_rate":{"type":"number","format":"double"},"avg_engagement_rate":{"type":"number","format":"double"},"page_views_trend_percentage":{"type":["number","null"],"format":"double","description":"Percentage change in page views vs previous period"},"previous_page_views":{"type":["integer","null"],"format":"int64","description":"Previous period page views"},"previous_unique_visitors":{"type":["integer","null"],"format":"int64","description":"Previous period unique visitors (same duration, shifted back)"},"project_breakdown":{"type":"array","items":{"$ref":"#/components/schemas/ProjectStatsBreakdown"}},"total_events":{"type":"integer","format":"int64"},"total_page_views":{"type":"integer","format":"int64"},"total_projects":{"type":"integer","format":"int64"},"total_unique_visitors":{"type":"integer","format":"int64"},"total_visits":{"type":"integer","format":"int64"},"visitors_trend_percentage":{"type":["number","null"],"format":"double","description":"Percentage change in unique visitors vs previous period"}}},"GenerateDockerfileRequest":{"type":"object","description":"Request body for generating a Dockerfile from a preset","properties":{"build_command":{"type":["string","null"],"description":"Custom build command (overrides preset default)","example":"npm run build"},"install_command":{"type":["string","null"],"description":"Custom install command (overrides preset default)","example":"npm ci"},"output_dir":{"type":["string","null"],"description":"Output directory for static builds","example":"dist"},"package_manager":{"type":["string","null"],"description":"Package manager used by the project (npm, yarn, pnpm, bun)\nIf not provided, defaults to npm","example":"npm"},"project_name":{"type":["string","null"],"description":"Project name/slug used for container naming","example":"my-app"},"use_buildkit":{"type":"boolean","description":"Whether to use BuildKit cache mounts for faster builds"}}},"GenerateDockerfileResponse":{"type":"object","description":"Response containing a generated Dockerfile and build arguments","required":["dockerfile","build_args","preset"],"properties":{"build_args":{"type":"object","description":"Build arguments to pass to `docker build --build-arg KEY=VALUE`","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"dockerfile":{"type":"string","description":"The generated Dockerfile content"},"preset":{"type":"string","description":"The preset slug used for generation"}}},"GenerateJoinTokenResponse":{"type":"object","description":"Response returned when a join token is generated (plaintext shown once)","required":["token","message"],"properties":{"message":{"type":"string"},"token":{"type":"string","description":"The plaintext join token — shown only once, save it now"}}},"GeoLocationResponse":{"type":"object","description":"Response containing geolocation information for an IP address","required":["ip","is_eu"],"properties":{"city":{"type":["string","null"],"description":"City name","example":"Mountain View"},"country":{"type":["string","null"],"description":"Country name","example":"United States"},"country_code":{"type":["string","null"],"description":"ISO country code (2 letters)","example":"US"},"ip":{"type":"string","description":"IP address that was geolocated","example":"8.8.8.8"},"is_eu":{"type":"boolean","description":"Whether the IP is in the European Union","example":false},"latitude":{"type":["number","null"],"format":"double","description":"Latitude coordinate","example":37.386},"longitude":{"type":["number","null"],"format":"double","description":"Longitude coordinate","example":-122.0838},"region":{"type":["string","null"],"description":"Region/state name","example":"California"},"timezone":{"type":["string","null"],"description":"Timezone identifier","example":"America/Los_Angeles"}}},"GeoRestrictionsConfig":{"type":"object","description":"Geographic restrictions configuration (future feature)","properties":{"allowedCountries":{"type":"array","items":{"type":"string"},"description":"Allow traffic only from specific countries"},"blockedCountries":{"type":"array","items":{"type":"string"},"description":"Block traffic from specific countries (ISO 3166-1 alpha-2 codes)"}}},"GetDeploymentsParams":{"type":"object","properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"page":{"type":["integer","null"],"format":"int64"},"per_page":{"type":["integer","null"],"format":"int64"}}},"GetEnvironmentVariablesQuery":{"type":"object","properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"service_id":{"type":["integer","null"],"format":"int32","description":"Required by integration-value reveals to bind the plaintext response to\nthe exact service displayed by the client."},"var_id":{"type":["integer","null"],"format":"int32","description":"Exact manual env-var row to reveal. Required by the dashboard so\nduplicate keys on disjoint environments cannot cross-reveal."}}},"GetFunnelMetricsQuery":{"type":"object","properties":{"country_code":{"type":["string","null"]},"end_date":{"type":["string","null"],"format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"start_date":{"type":["string","null"],"format":"date-time"}}},"GetOrCreateDSNRequest":{"type":"object","properties":{"base_url":{"type":["string","null"]},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"}}},"GetProjectSecretsQuery":{"type":"object","properties":{"environment_id":{"type":["integer","null"],"format":"int32"}}},"GetProjectSessionReplaysQuery":{"type":"object","required":["project_id"],"properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"page":{"type":["integer","null"],"format":"int64","minimum":0},"per_page":{"type":["integer","null"],"format":"int64","minimum":0},"project_id":{"type":"integer","format":"int32"}}},"GetProjectSessionReplaysResponse":{"type":"object","required":["sessions","page","per_page","total_count"],"properties":{"page":{"type":"integer","format":"int64","minimum":0},"per_page":{"type":"integer","format":"int64","minimum":0},"sessions":{"type":"array","items":{"$ref":"#/components/schemas/SessionReplayWithVisitorDto"}},"total_count":{"type":"integer","format":"int64","minimum":0}}},"GetRequest":{"type":"object","description":"Request to get a value by key","required":["key"],"properties":{"key":{"type":"string","description":"The key to retrieve","example":"user:123"},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1}}},"GetResponse":{"type":"object","description":"Response for get operation","properties":{"value":{"description":"The value, or null if not found"}}},"GetSessionReplayResponse":{"type":"object","required":["session"],"properties":{"session":{"$ref":"#/components/schemas/SessionReplayWithVisitorDto"}}},"GetUniqueEventsQuery":{"type":"object","properties":{"page":{"type":["integer","null"],"format":"int64","minimum":0},"page_size":{"type":["integer","null"],"format":"int64","minimum":0}}},"GetVisitorSessionsQuery":{"type":"object","properties":{"page":{"type":["integer","null"],"format":"int64","minimum":0},"per_page":{"type":["integer","null"],"format":"int64","minimum":0}}},"GetVisitorSessionsResponse":{"type":"object","required":["sessions","page","per_page","total_count"],"properties":{"page":{"type":"integer","format":"int64","minimum":0},"per_page":{"type":"integer","format":"int64","minimum":0},"sessions":{"type":"array","items":{"$ref":"#/components/schemas/SessionReplayWithVisitorDto"}},"total_count":{"type":"integer","minimum":0}}},"GitPushEvent":{"type":"object","description":"Git push event information that triggered the deployment","required":["repo","owner","branch","commit"],"properties":{"branch":{"type":"string","description":"Branch that was pushed"},"commit":{"type":"string","description":"Commit SHA"},"owner":{"type":"string","description":"Repository owner/organization"},"repo":{"type":"string","description":"Repository name"}}},"GitRefResponse":{"type":"object","description":"Git repository reference response","required":["url","ref"],"properties":{"path":{"type":["string","null"],"description":"Path within the repository (for monorepos)"},"ref":{"type":"string","description":"Git reference (branch, tag, or commit)"},"url":{"type":"string","description":"Git repository URL"}}},"GitSourcePlan":{"type":"object","description":"Git repository the source platform deploys from","required":["owner","repo","branch","is_public"],"properties":{"branch":{"type":"string","description":"Branch the source platform deploys"},"clone_url":{"type":["string","null"],"description":"Full clone URL, e.g. `https://github.com/owner/repo.git`"},"is_public":{"type":"boolean","description":"True when the repository is public (no credentials on the source\nplatform) — the project can then build without a git provider\nconnection."},"owner":{"type":"string","description":"Repository owner (organization or user)"},"repo":{"type":"string","description":"Repository name"}}},"GlobalConversationResponse":{"type":"object","description":"A conversation in the unified cross-project switcher: carries the project it\nbelongs to (name/slug) so the UI can show where the chat was started and\nlink back to the source.","required":["public_id","project_id","context_type","context_id","status","created_at","last_activity_at"],"properties":{"context_id":{"type":"string"},"context_type":{"type":"string"},"created_at":{"type":"string"},"last_activity_at":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"project_name":{"type":["string","null"]},"project_slug":{"type":["string","null"]},"public_id":{"type":"string"},"status":{"type":"string"},"title":{"type":["string","null"]}}},"GlobalEventStatsResponse":{"type":"object","required":["delivered","opened","clicked","bounced","complained"],"properties":{"bounce_rate":{"type":["number","null"],"format":"double"},"bounced":{"type":"integer","format":"int64","minimum":0},"click_rate":{"type":["number","null"],"format":"double"},"clicked":{"type":"integer","format":"int64","minimum":0},"complained":{"type":"integer","format":"int64","minimum":0},"delivered":{"type":"integer","format":"int64","minimum":0},"open_rate":{"type":["number","null"],"format":"double"},"opened":{"type":"integer","format":"int64","minimum":0}}},"GlobalMrrResponse":{"type":"object","required":["currency","current_mrr_minor","previous_mrr_minor"],"properties":{"change_percentage":{"type":["number","null"],"format":"double","description":"Percentage change vs 24h ago. Null when previous MRR is zero\n(no baseline to compare against)."},"currency":{"type":"string"},"current_mrr_minor":{"type":"integer","format":"int64"},"previous_mrr_minor":{"type":"integer","format":"int64","description":"MRR 24h before now, reconstructed from the event log."}}},"GlobalRecentEventResponse":{"type":"object","required":["id","project_id","project_name","occurred_at","event_type"],"properties":{"amount_minor":{"type":["integer","null"],"format":"int64"},"currency":{"type":["string","null"]},"customer_ref":{"type":["string","null"]},"event_type":{"type":"string"},"id":{"type":"integer","format":"int64"},"mrr_minor":{"type":["integer","null"],"format":"int64"},"occurred_at":{"type":"string","format":"date-time"},"project_id":{"type":"integer","format":"int32"},"project_name":{"type":"string"}}},"GlobalRevenueSummaryResponse":{"type":"object","required":["currency","current_mrr_minor","paid_last_30d_minor","refunded_last_30d_minor","paid_all_time_minor","refunded_all_time_minor","active_subscriptions","active_customers","transactions_last_30d"],"properties":{"active_customers":{"type":"integer","format":"int64"},"active_subscriptions":{"type":"integer","format":"int64"},"currency":{"type":"string"},"current_mrr_minor":{"type":"integer","format":"int64"},"paid_all_time_minor":{"type":"integer","format":"int64"},"paid_last_30d_minor":{"type":"integer","format":"int64"},"refunded_all_time_minor":{"type":"integer","format":"int64"},"refunded_last_30d_minor":{"type":"integer","format":"int64"},"transactions_last_30d":{"type":"integer","format":"int64"}}},"GroupedPageMetric":{"type":"object","required":["group_key","events"],"properties":{"cls":{"type":["number","null"],"format":"float"},"country_code":{"type":["string","null"],"description":"ISO 3166-1 alpha-2 code of the group's country. Populated for the\ngeographic dimensions (country/region/city) so clients can match map\ngeometries without name-based lookups; null otherwise."},"events":{"type":"integer","format":"int64"},"fcp":{"type":["number","null"],"format":"float"},"group_key":{"type":"string"},"inp":{"type":["number","null"],"format":"float"},"lcp":{"type":["number","null"],"format":"float"},"ttfb":{"type":["number","null"],"format":"float"}}},"GroupedPageMetricsQuery":{"allOf":[{"$ref":"#/components/schemas/SpeedSegmentFilters","description":"Segment filters — same shape as `PerformanceMetricsQuery`."},{"type":"object","required":["start_date","end_date","project_id","group_by"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"device_type":{"type":["string","null"],"description":"Device type filter: \"desktop\" or \"mobile\""},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"group_by":{"type":"string"},"include_bots":{"type":["boolean","null"],"description":"Include crawler/datacenter (bot) samples. Defaults to false."},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}}]},"GroupedPageMetricsResponse":{"type":"object","required":["groups","total_events","grouped_by"],"properties":{"grouped_by":{"type":"string"},"groups":{"type":"array","items":{"$ref":"#/components/schemas/GroupedPageMetric"}},"total_events":{"type":"integer","format":"int64"}}},"HasAnalyticsEventsResponse":{"type":"object","required":["has_events"],"properties":{"has_events":{"type":"boolean"}}},"HasErrorGroupsResponse":{"type":"object","required":["has_error_groups"],"properties":{"has_error_groups":{"type":"boolean"}}},"HasEventsQuery":{"type":"object","required":["project_id"],"properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"}}},"HasEventsResponse":{"type":"object","required":["has_events"],"properties":{"has_events":{"type":"boolean"}}},"HasMetricsQuery":{"type":"object","required":["project_id"],"properties":{"project_id":{"type":"integer","format":"int32"}}},"HasMetricsResponse":{"type":"object","required":["has_metrics"],"properties":{"has_metrics":{"type":"boolean"}}},"HealthCheckConfiguration":{"type":"object","description":"Health check configuration","required":["port","interval","timeout","retries"],"properties":{"http_path":{"type":["string","null"],"description":"HTTP path to check (if applicable)"},"interval":{"type":"integer","format":"int32","description":"Interval between checks (seconds)","minimum":0},"port":{"type":"integer","format":"int32","description":"Port to check","minimum":0},"retries":{"type":"integer","format":"int32","description":"Number of retries before marking unhealthy","minimum":0},"timeout":{"type":"integer","format":"int32","description":"Timeout for each check (seconds)","minimum":0}}},"HealthCheckEntryResponse":{"type":"object","required":["checked_at","status"],"properties":{"checked_at":{"type":"string","description":"ISO 8601 timestamp of when the probe ran.","example":"2026-04-22T11:30:00Z"},"error_message":{"type":["string","null"],"description":"Present only when the probe failed or was degraded."},"response_time_ms":{"type":["integer","null"],"format":"int32","description":"TCP connect latency in milliseconds."},"status":{"type":"string","description":"\"operational\" | \"degraded\" | \"down\"","example":"operational"}}},"HealthResponse":{"type":"object","required":["summaries"],"properties":{"summaries":{"type":"array","items":{"$ref":"#/components/schemas/HealthSummary"}}}},"HealthStatus":{"type":"string","description":"Overall health status.","enum":["healthy","degraded","down","unknown"]},"HealthSummary":{"type":"object","description":"Pre-computed health summary for a project environment.","required":["project_id","service_name","status","uptime_pct","error_rate","p95_latency_ms","cpu_usage_pct","memory_usage_pct","computed_at"],"properties":{"computed_at":{"type":"string","format":"date-time"},"cpu_usage_pct":{"type":"number","format":"double"},"environment_id":{"type":["integer","null"],"format":"int32"},"error_rate":{"type":"number","format":"double"},"last_deploy_at":{"type":["string","null"],"format":"date-time"},"last_deploy_id":{"type":["integer","null"],"format":"int32"},"memory_usage_pct":{"type":"number","format":"double"},"p95_latency_ms":{"type":"number","format":"double"},"project_id":{"type":"integer","format":"int32"},"service_name":{"type":"string"},"status":{"$ref":"#/components/schemas/HealthStatus"},"uptime_pct":{"type":"number","format":"double"}}},"HeartbeatApiRequest":{"type":"object","properties":{"architecture":{"type":["string","null"],"description":"Container platform of this node's Docker daemon (`linux/amd64`,\n`linux/arm64`), read from `docker info` by the agent. Absent from\npre-multi-arch agents; the stored value is then left untouched."},"capacity":{"description":"Resource capacity/usage info as JSON (cpu_usage, memory_usage, etc.)"},"containers":{"type":["array","null"],"items":{"$ref":"#/components/schemas/ContainerInventoryItem"},"description":"Container inventory for reconciliation (sent on first heartbeat after agent startup).\nEach entry has `container_id` and `container_name` of temps-managed containers."},"labels":{"description":"Updated node labels for scheduling (allows runtime label changes)."}}},"HeartbeatResponse":{"type":"object","required":["status","message"],"properties":{"message":{"type":"string"},"status":{"type":"string"}}},"HierarchyLevel":{"type":"object","description":"Describes a level in the data source hierarchy","required":["level","name","container_type","can_list_containers","can_list_entities"],"properties":{"can_list_containers":{"type":"boolean","description":"Can list containers at this level?","example":true},"can_list_entities":{"type":"boolean","description":"Can list entities at this level?","example":false},"container_type":{"type":"string","description":"Type of container at this level","example":"database"},"level":{"type":"integer","format":"int32","description":"Level number (0 = root)","example":0,"minimum":0},"name":{"type":"string","description":"Human-readable name for this level","example":"root"}}},"HistogramSummary":{"type":"object","description":"An explicit-bucket histogram aggregated over a time bucket.\n\nCarries the reduced scalars (count/sum/min/max) plus the explicit bucket\nlayout — `bounds` (the upper bounds) and `bucket_counts` (observation counts,\nsummed element-wise across the window; length is `bounds.len() + 1`, the last\nentry being the +Inf overflow bucket). With these, a caller can reconstruct\nany quantile (e.g. p95) via cumulative-count interpolation.","required":["count","sum","bounds","bucket_counts"],"properties":{"bounds":{"type":"array","items":{"type":"number","format":"double"},"description":"Explicit bucket upper bounds (OTLP `explicit_bounds`), ascending."},"bucket_counts":{"type":"array","items":{"type":"integer","format":"int64","minimum":0},"description":"Per-bucket observation counts summed element-wise across the window.\nLength is `bounds.len() + 1` (the trailing element is the +Inf bucket)."},"count":{"type":"integer","format":"int64","description":"Total observation count summed across the bucket window.","minimum":0},"max":{"type":["number","null"],"format":"double","description":"Maximum observed value, when reported by the producer."},"min":{"type":["number","null"],"format":"double","description":"Minimum observed value, when reported by the producer."},"sum":{"type":"number","format":"double","description":"Sum of observed values across the bucket window."}}},"HostnameChange":{"type":"object","description":"A single generated-hostname change in a flatten preview/apply.","required":["kind","id","old","new"],"properties":{"id":{"type":"integer","format":"int32","description":"Row id of the affected record."},"kind":{"type":"string","description":"`\"deployment\"` or `\"environment\"`."},"new":{"type":"string"},"old":{"type":"string"}}},"HostnamePreviewResponse":{"type":"object","description":"Combined preview of a hostname-mode change.","required":["hostname_changes","dns_changes","total"],"properties":{"dns_changes":{"type":"array","items":{"$ref":"#/components/schemas/DnsRecordChange"}},"hostname_changes":{"type":"array","items":{"$ref":"#/components/schemas/HostnameChange"}},"total":{"type":"integer","minimum":0},"zone_access_ok":{"type":["boolean","null"],"description":"Whether the provider token can manage this zone (None if not checked)."}}},"HourlyPageSessions":{"type":"object","required":["timestamp","session_count","event_count","avg_duration_seconds"],"properties":{"avg_duration_seconds":{"type":"number","format":"double"},"event_count":{"type":"integer","format":"int64"},"session_count":{"type":"integer","format":"int64"},"timestamp":{"type":"string"}}},"HourlyVisitsQuery":{"type":"object","required":["start_date","end_date"],"properties":{"aggregation_level":{"$ref":"#/components/schemas/AggregationLevel","description":"Aggregation level: events (page views), sessions (unique sessions), or visitors (unique visitors)"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"HttpChallengeDebugResponse":{"type":"object","required":["domain","challenge_exists","dns_a_records","dns_aaaa_records"],"properties":{"challenge_exists":{"type":"boolean"},"challenge_token":{"type":["string","null"]},"challenge_url":{"type":["string","null"],"description":"The full URL that Let's Encrypt will try to access to validate the challenge"},"dns_a_records":{"type":"array","items":{"type":"string"},"description":"IPv4 addresses the domain points to"},"dns_aaaa_records":{"type":"array","items":{"type":"string"},"description":"IPv6 addresses the domain points to"},"dns_error":{"type":["string","null"],"description":"Any DNS resolution errors"},"domain":{"type":"string"},"validation_url":{"type":["string","null"],"description":"The ACME validation URL (internal to ACME protocol)"}}},"ImportCredentials":{"type":"object","description":"Platform-specific credentials for accessing the source system.\n\nFor platforms like Vercel and Railway, this contains the API token.\nFor self-hosted platforms like Coolify and Dokploy, this also contains\nthe `base_url` of the instance.\n\nLocal importers (Docker) can use `ImportCredentials::none()`.","properties":{"base_url":{"type":["string","null"],"description":"Base URL override (for self-hosted platforms like Coolify, Dokploy)\n\nExample: `https://coolify.example.com`"},"extra":{"type":"object","description":"Additional platform-specific parameters","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"team_id":{"type":["string","null"],"description":"Team or organization ID (for platforms with team scoping like Vercel)"},"token":{"type":["string","null"],"description":"API token / bearer token for the source platform"}}},"ImportExecutionStatus":{"type":"string","description":"Import execution status","enum":["pending","inprogress","completed","failed"]},"ImportExternalServiceRequest":{"type":"object","description":"Request to import a Docker container as a managed service","required":["name","service_type","parameters","container_id"],"properties":{"container_id":{"type":"string","description":"Container ID or name to import","example":"abc123def456"},"name":{"type":"string","description":"Name to register the service as in Temps","example":"production-database"},"parameters":{"type":"object","description":"Service configuration parameters","additionalProperties":{},"propertyNames":{"type":"string"}},"service_type":{"$ref":"#/components/schemas/ServiceTypeRoute","description":"Service type"},"version":{"type":["string","null"],"description":"Optional version override"}}},"ImportOutcomeResponse":{"type":"object","required":["rows_read","inserted","updated","skipped_stale","skipped_invalid","errors"],"properties":{"errors":{"type":"array","items":{"$ref":"#/components/schemas/ImportRowErrorResponse"}},"inserted":{"type":"integer","minimum":0},"rows_read":{"type":"integer","minimum":0},"skipped_invalid":{"type":"integer","minimum":0},"skipped_stale":{"type":"integer","minimum":0},"updated":{"type":"integer","minimum":0}}},"ImportPlan":{"type":"object","description":"Complete import plan describing all operations to onboard a workload.\n\nThe plan is generated from a snapshot and presented to the user for review\nbefore any resources are created. Users can modify individual items\n(skip services, change actions) before approving execution.","required":["version","source","source_id","project","environment","deployment","summary","metadata"],"properties":{"additional_deployments":{"type":"array","items":{"$ref":"#/components/schemas/DeploymentConfiguration"},"description":"Additional deployments (workers, cron jobs, etc.)"},"cost_analysis":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/CostAnalysis","description":"Cost, overprovisioning, and savings analysis. Populated by importers\nthat can observe the whole source cluster (currently Kubernetes);\n`None` for container/platform imports."}]},"deployment":{"$ref":"#/components/schemas/DeploymentConfiguration","description":"Primary deployment configuration"},"domains":{"type":"array","items":{"$ref":"#/components/schemas/DomainPlan"},"description":"Custom domains to migrate"},"environment":{"$ref":"#/components/schemas/EnvironmentConfiguration","description":"Environment configuration"},"metadata":{"$ref":"#/components/schemas/PlanMetadata","description":"Plan metadata"},"project":{"$ref":"#/components/schemas/ProjectConfiguration","description":"Project configuration"},"services":{"type":"array","items":{"$ref":"#/components/schemas/ServicePlan"},"description":"Services to migrate (databases, caches, blob stores)\n\nEach service has an `action` field the user can change before execution."},"source":{"type":"string","description":"Source system this plan was generated from"},"source_id":{"type":"string","description":"Source workload / project ID in the source system"},"steps":{"type":"array","items":{"$ref":"#/components/schemas/MigrationStep"},"description":"Ordered list of migration steps that will be executed.\n\nThis is the human-readable execution plan. Each step describes what\nwill happen, what risks are involved, and what the user should verify.\nSteps are executed in order. If a step fails, execution stops and\nalready-created resources are reported for manual cleanup."},"summary":{"$ref":"#/components/schemas/MigrationSummary","description":"Human-readable summary of the entire migration"},"version":{"type":"string","description":"Plan version for compatibility tracking"}}},"ImportRowErrorResponse":{"type":"object","required":["row","reason"],"properties":{"reason":{"type":"string"},"row":{"type":"integer","minimum":0}}},"ImportSelector":{"type":"object","description":"Selector for discovering workloads","properties":{"label_filter":{"type":["object","null"],"description":"Filter by labels/tags","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"limit":{"type":["integer","null"],"description":"Limit number of results","minimum":0},"name_pattern":{"type":["string","null"],"description":"Filter by name pattern (glob/regex)"},"status_filter":{"type":["array","null"],"items":{"type":"string"},"description":"Filter by status (running, stopped, deployed, etc.)"},"workload_type_filter":{"type":["array","null"],"items":{"type":"string"},"description":"Filter by workload type (container, function, static-site, etc.)"}}},"ImportSource":{"type":"string","description":"Import source identifier","enum":["docker","coolify","dokploy","vercel","netlify","railway","render","fly","kubernetes","caprover","portainer","kamal","custom"]},"ImportSourceCapabilities":{"type":"object","description":"Source capabilities","required":["supports_volumes","supports_networks","supports_health_checks","supports_resource_limits","supports_build","supports_services","supports_domains","supports_project_snapshot","supports_cost_analysis","requires_credentials"],"properties":{"requires_credentials":{"type":"boolean","description":"Whether this source requires API credentials (token, base URL)"},"supports_build":{"type":"boolean"},"supports_cost_analysis":{"type":"boolean","description":"Supports cluster cost + overprovisioning analysis in the plan"},"supports_domains":{"type":"boolean","description":"Supports custom domain migration"},"supports_health_checks":{"type":"boolean"},"supports_networks":{"type":"boolean"},"supports_project_snapshot":{"type":"boolean","description":"Supports full project-level snapshots"},"supports_resource_limits":{"type":"boolean"},"supports_services":{"type":"boolean","description":"Supports service migration (databases, caches, etc.)"},"supports_volumes":{"type":"boolean"}}},"ImportSourceInfo":{"type":"object","description":"Information about an import source","required":["source","name","version","available","capabilities"],"properties":{"available":{"type":"boolean","description":"Whether the source is currently available"},"capabilities":{"$ref":"#/components/schemas/ImportSourceCapabilities","description":"Capabilities"},"name":{"type":"string","description":"Human-readable name"},"source":{"$ref":"#/components/schemas/ImportSource","description":"Source identifier"},"version":{"type":"string","description":"Source version"}}},"ImportStatusResponse":{"type":"object","description":"Response with import status","required":["session_id","status","errors","warnings","created_at","updated_at"],"properties":{"created_at":{"type":"string","format":"date-time","description":"Created at timestamp"},"deployment_id":{"type":["integer","null"],"format":"int32","description":"Created deployment ID"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Created environment ID"},"errors":{"type":"array","items":{"type":"string"},"description":"Errors (if any)"},"plan":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ImportPlan","description":"Import plan"}]},"project_id":{"type":["integer","null"],"format":"int32","description":"Created project ID"},"session_id":{"type":"string","description":"Session ID"},"status":{"$ref":"#/components/schemas/ImportExecutionStatus","description":"Current status"},"updated_at":{"type":"string","format":"date-time","description":"Updated at timestamp"},"validation":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ValidationReport","description":"Validation report"}]},"warnings":{"type":"array","items":{"type":"string"},"description":"Warnings (if any)"}}},"IncidentBucket":{"type":"object","required":["bucket_start","total_incidents","minor_incidents","major_incidents","critical_incidents","resolved_incidents","active_incidents"],"properties":{"active_incidents":{"type":"integer","format":"int64"},"avg_resolution_time_minutes":{"type":["number","null"],"format":"double"},"bucket_start":{"type":"string","format":"date-time"},"critical_incidents":{"type":"integer","format":"int64"},"major_incidents":{"type":"integer","format":"int64"},"minor_incidents":{"type":"integer","format":"int64"},"resolved_incidents":{"type":"integer","format":"int64"},"total_incidents":{"type":"integer","format":"int64"}}},"IncidentBucketedResponse":{"type":"object","required":["project_id","interval","buckets"],"properties":{"buckets":{"type":"array","items":{"$ref":"#/components/schemas/IncidentBucket"}},"environment_id":{"type":["integer","null"],"format":"int32"},"interval":{"type":"string"},"project_id":{"type":"integer","format":"int32"}}},"IncidentResponse":{"type":"object","required":["id","project_id","title","severity","status","started_at","created_at","updated_at"],"properties":{"created_at":{"type":"string","format":"date-time"},"description":{"type":["string","null"]},"environment_id":{"type":["integer","null"],"format":"int32"},"id":{"type":"integer","format":"int32"},"monitor_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"resolved_at":{"type":["string","null"],"format":"date-time"},"severity":{"type":"string"},"started_at":{"type":"string","format":"date-time"},"status":{"type":"string"},"title":{"type":"string"},"updated_at":{"type":"string","format":"date-time"}}},"IncidentUpdateResponse":{"type":"object","required":["id","incident_id","status","message","created_at"],"properties":{"created_at":{"type":"string","format":"date-time"},"id":{"type":"integer","format":"int32"},"incident_id":{"type":"integer","format":"int32"},"message":{"type":"string"},"status":{"type":"string"}}},"IncrRequest":{"type":"object","description":"Request to increment a value","required":["key"],"properties":{"amount":{"type":["integer","null"],"format":"int64","description":"Amount to increment by (default: 1)"},"key":{"type":"string","description":"The key to increment","example":"counter"},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1}}},"IncrResponse":{"type":"object","description":"Response for increment operation","required":["value"],"properties":{"value":{"type":"integer","format":"int64","description":"New value after increment","example":42}}},"InitAuthResponse":{"type":"object","required":["auth_url","session_token"],"properties":{"auth_url":{"type":"string"},"session_token":{"type":"string"}}},"Insight":{"type":"object","description":"An anomaly insight.","required":["id","project_id","service_name","severity","status","title","description","anomaly_ids","started_at","created_at","updated_at"],"properties":{"anomaly_ids":{"type":"array","items":{"type":"integer","format":"int64"}},"correlated_deploy_id":{"type":["integer","null"],"format":"int32"},"created_at":{"type":"string","format":"date-time"},"description":{"type":"string"},"environment":{"type":["string","null"]},"id":{"type":"integer","format":"int64"},"metric_name":{"type":["string","null"]},"project_id":{"type":"integer","format":"int32"},"resolved_at":{"type":["string","null"],"format":"date-time"},"service_name":{"type":"string"},"severity":{"$ref":"#/components/schemas/InsightSeverity"},"started_at":{"type":"string","format":"date-time"},"status":{"$ref":"#/components/schemas/InsightStatus"},"title":{"type":"string"},"updated_at":{"type":"string","format":"date-time"}}},"InsightSeverity":{"type":"string","description":"Severity of an anomaly insight.","enum":["low","medium","high","critical"]},"InsightStatus":{"type":"string","description":"Status of an insight.","enum":["active","resolved"]},"InsightsResponse":{"type":"object","required":["data","count"],"properties":{"count":{"type":"integer","minimum":0},"data":{"type":"array","items":{"$ref":"#/components/schemas/Insight"}}}},"IntegrationResponse":{"type":"object","required":["id","project_id","provider","webhook_path_token","webhook_path","status","has_secret","created_at"],"properties":{"config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ProviderConfig","description":"Typed provider config — allowlist and metered-billing mode. Null\nwhen the operator hasn't configured one yet (accept everything)."}]},"created_at":{"type":"string","format":"date-time"},"has_secret":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"last_event_at":{"type":["string","null"],"format":"date-time"},"project_id":{"type":"integer","format":"int32"},"provider":{"type":"string"},"status":{"type":"string"},"webhook_path":{"type":"string","description":"Relative path the UI can display and copy. The frontend builds\nthe full URL by prefixing its own origin."},"webhook_path_token":{"type":"string","description":"Unguessable token embedded in the public webhook URL. The full\nURL is `{api_origin}/webhooks/revenue/{provider}/{webhook_path_token}`."}}},"IpAccessControlQuery":{"type":"object","description":"Query parameters for listing IP access control rules","properties":{"action":{"type":["string","null"],"description":"Filter by action (\"block\" or \"allow\")"}}},"IpAccessControlResponse":{"type":"object","description":"Response model for IP access control rules","required":["id","ip_address","action","created_at","updated_at"],"properties":{"action":{"type":"string"},"created_at":{"type":"string","example":"2025-10-12T12:15:47.609Z"},"created_by":{"type":["integer","null"],"format":"int32"},"id":{"type":"integer","format":"int32"},"ip_address":{"type":"string"},"reason":{"type":["string","null"]},"updated_at":{"type":"string","example":"2025-10-12T12:15:47.609Z"}}},"JobStatusResponse":{"type":"object","description":"Snapshot of a background job. `status` is one of \"running\" | \"exited\"\n| \"failed\"; `exit_code` is populated only when `status == \"exited\"`.","required":["status","stdout","stderr"],"properties":{"exit_code":{"type":["integer","null"],"format":"int32"},"reason":{"type":["string","null"]},"status":{"type":"string"},"stderr":{"type":"string"},"stdout":{"type":"string"}}},"JobSummaryResponse":{"type":"object","description":"Row in the jobs list. Omits stdout/stderr so a noisy dev server doesn't\nbloat the list payload — callers drill into `GET /jobs/{id}` for the\nfull buffer.","required":["id","status","cmd","started_at"],"properties":{"cmd":{"type":"string"},"exit_code":{"type":["integer","null"],"format":"int32"},"id":{"type":"string"},"reason":{"type":["string","null"]},"started_at":{"type":"string"},"status":{"type":"string"}}},"JoinTokenStatusResponse":{"type":"object","description":"Response for join token status check","required":["has_token"],"properties":{"has_token":{"type":"boolean","description":"Whether a join token has been configured"}}},"JourneyEvent":{"type":"object","description":"A single event in the visitor journey timeline","required":["id","event_type","event_name","occurred_at","is_entry","is_exit","is_bounce"],"properties":{"event_data":{"description":"Custom event properties (for custom events)"},"event_name":{"type":"string","description":"Resolved event name (event_name for custom events, event_type for system events)"},"event_type":{"type":"string","description":"Event type: \"page_view\", \"page_leave\", \"custom\", \"web_vitals\""},"id":{"type":"integer","format":"int64","description":"Event ID"},"is_bounce":{"type":"boolean","description":"Whether this was a bounce"},"is_entry":{"type":"boolean","description":"Whether this is the entry page of the session"},"is_exit":{"type":"boolean","description":"Whether this is the exit page of the session"},"occurred_at":{"type":"string","format":"date-time","description":"When the event occurred"},"page_path":{"type":["string","null"],"description":"Page path where the event happened"},"page_title":{"type":["string","null"],"description":"Page title (if available)"},"referrer":{"type":["string","null"],"description":"Referrer URL for this event"},"scroll_depth":{"type":["integer","null"],"format":"int32","description":"Scroll depth percentage (0-100)"},"session_page_number":{"type":["integer","null"],"format":"int32","description":"Page number within the session (1-indexed)"},"time_on_page":{"type":["integer","null"],"format":"int32","description":"Time spent on page in seconds (computed, not from column)"}}},"JourneySession":{"type":"object","description":"A session within the visitor journey, grouping events","required":["session_id","started_at","duration_seconds","page_views","events_count","is_bounced","is_engaged","events"],"properties":{"channel":{"type":["string","null"],"description":"Traffic source: channel (e.g. \"organic\", \"direct\", \"social\")"},"duration_seconds":{"type":"integer","format":"int64","description":"Session duration in seconds"},"ended_at":{"type":["string","null"],"format":"date-time","description":"When the session ended"},"entry_path":{"type":["string","null"],"description":"Entry page path"},"events":{"type":"array","items":{"$ref":"#/components/schemas/JourneyEvent"},"description":"Events within this session, ordered chronologically"},"events_count":{"type":"integer","format":"int64","description":"Total events in this session"},"exit_path":{"type":["string","null"],"description":"Exit page path"},"is_bounced":{"type":"boolean","description":"Whether the session was a bounce"},"is_engaged":{"type":"boolean","description":"Whether the visitor was engaged (had non-pageview events)"},"page_views":{"type":"integer","format":"int64","description":"Number of page views in this session"},"referrer":{"type":["string","null"],"description":"Traffic source: referrer URL"},"referrer_hostname":{"type":["string","null"],"description":"Traffic source: referrer hostname"},"session_id":{"type":"integer","format":"int32","description":"Session internal ID"},"started_at":{"type":"string","format":"date-time","description":"When the session started"},"utm_campaign":{"type":["string","null"],"description":"UTM campaign parameter"},"utm_medium":{"type":["string","null"],"description":"UTM medium parameter"},"utm_source":{"type":["string","null"],"description":"UTM source parameter"}}},"KeysRequest":{"type":"object","description":"Request to get keys matching a pattern","required":["pattern"],"properties":{"pattern":{"type":"string","description":"Pattern to match (supports * and ? wildcards)","example":"user:*"},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1}}},"KeysResponse":{"type":"object","description":"Response for keys operation","required":["keys"],"properties":{"keys":{"type":"array","items":{"type":"string"},"description":"List of matching keys","example":["user:1","user:2","user:3"]}}},"KillJobBody":{"type":"object","properties":{"force":{"type":"boolean","description":"When true, sends SIGKILL immediately. Defaults to SIGTERM so the\nprocess gets a chance to flush (mirrors `Command.kill()` in\n`@vercel/sandbox`, which also accepts a signal override)."}},"additionalProperties":false},"KnownAiAgentsResponse":{"type":"object","description":"Response listing every AI agent the detector knows about.","required":["items"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AiAgentDescriptor"}}}},"KvStatusResponse":{"type":"object","description":"Response for KV service status","required":["enabled","healthy"],"properties":{"docker_image":{"type":["string","null"],"description":"Docker image being used","example":"gotempsh/redis-walg:8-bookworm"},"enabled":{"type":"boolean","description":"Whether the KV service is enabled"},"healthy":{"type":"boolean","description":"Whether the underlying Redis service is healthy"},"version":{"type":["string","null"],"description":"Service version","example":"7.2"}}},"LemonSqueezyConfig":{"type":"object","properties":{"product_allowlist":{"type":"array","items":{"type":"string"}},"variant_allowlist":{"type":"array","items":{"type":"string"}}}},"LetsEncryptSettings":{"type":"object","properties":{"email":{"type":["string","null"],"default":null},"environment":{"type":"string","default":"production"}}},"LineContext":{"type":"object","description":"Raw surrounding lines for a single match (grep -C style).","required":["before","after"],"properties":{"after":{"type":"array","items":{"$ref":"#/components/schemas/ContextLine"},"description":"Lines immediately after the match, oldest-first."},"before":{"type":"array","items":{"$ref":"#/components/schemas/ContextLine"},"description":"Lines immediately before the match, oldest-first."}}},"LinkServiceRequest":{"type":"object","required":["project_id"],"properties":{"project_id":{"type":"integer","format":"int32"}}},"ListAgentsResponse":{"type":"object","required":["items","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AgentConfigResponse"}},"total":{"type":"integer","minimum":0}}},"ListApiKeysQuery":{"type":"object","properties":{"page":{"type":["integer","null"],"format":"int64","minimum":0},"page_size":{"type":["integer","null"],"format":"int64","minimum":0}}},"ListAuditLogsQuery":{"type":"object","description":"Query parameters for listing audit logs.\n\nEvery field is optional — omitting one means \"don't filter on it\". Deriving\n`IntoParams` makes utoipa render them as optional query params with the\ncorrect types; the previous hand-written `params((\"operation_type\", Query,\n…))` tuples defaulted every param to `required: true, type: string`, which\nmisled both API clients and the AI `describe_api`/`call_api` tools into\nthinking all filters were mandatory.","properties":{"from":{"type":["string","null"],"format":"date-time","description":"Start timestamp (milliseconds since epoch)"},"limit":{"type":["integer","null"],"format":"int32","description":"Maximum number of logs to return"},"offset":{"type":["integer","null"],"format":"int32","description":"Number of logs to skip"},"operation_type":{"type":["string","null"],"description":"Filter logs by operation type (omit for all)"},"to":{"type":["string","null"],"format":"date-time","description":"End timestamp (milliseconds since epoch)"},"user_id":{"type":["integer","null"],"format":"int32","description":"Filter logs by user ID (omit for all users)"}}},"ListBlobsQuery":{"type":"object","description":"Query parameters for listing blobs","properties":{"cursor":{"type":["string","null"],"description":"Continuation token for pagination"},"limit":{"type":["integer","null"],"format":"int32","description":"Maximum number of items to return","example":100},"prefix":{"type":["string","null"],"description":"Prefix to filter by","example":"images/"},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1}}},"ListBlobsResponse":{"type":"object","description":"Response for listing blobs","required":["blobs","hasMore"],"properties":{"blobs":{"type":"array","items":{"$ref":"#/components/schemas/BlobResponse"},"description":"List of blobs"},"cursor":{"type":["string","null"],"description":"Continuation token for next page"},"hasMore":{"type":"boolean","description":"Whether there are more results","example":false}}},"ListCustomDomainsResponse":{"type":"object","required":["domains","total"],"properties":{"domains":{"type":"array","items":{"$ref":"#/components/schemas/CustomDomainResponse"}},"total":{"type":"integer","minimum":0}}},"ListDeploymentTokensQuery":{"type":"object","properties":{"page":{"type":["integer","null"],"format":"int64","example":1,"minimum":0},"page_size":{"type":["integer","null"],"format":"int64","example":20,"minimum":0}}},"ListDomainsResponse":{"type":"object","required":["domains","total","page","page_size"],"properties":{"domains":{"type":"array","items":{"$ref":"#/components/schemas/DomainResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"ListEntitiesQuery":{"type":"object","properties":{"limit":{"type":"integer","description":"Maximum number of entities to return","example":100,"minimum":0},"token":{"type":["string","null"],"description":"Continuation token for pagination (backend-specific)"}}},"ListErrorEventsQuery":{"type":"object","properties":{"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0}}},"ListErrorGroupsQuery":{"type":"object","properties":{"end_date":{"type":["string","null"],"format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"sort_by":{"type":["string","null"]},"sort_order":{"type":"string"},"start_date":{"type":["string","null"],"format":"date-time"},"status":{"type":["string","null"]}}},"ListJobsResponse":{"type":"object","required":["items"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/JobSummaryResponse"}}}},"ListMcpsResponse":{"type":"object","description":"Concrete list wrapper for MCP server definitions (utoipa requires non-generic types).","required":["items","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/McpDefinitionResponse"}},"total":{"type":"integer","minimum":0}}},"ListOnDemandCertsResponse":{"type":"object","description":"Paginated list of on-demand cert attempts (ADR-018 §5 console \"Certificates\"\nsurface). Joined with current `domains.status`, newest first.","required":["certs","total","page","page_size"],"properties":{"certs":{"type":"array","items":{"$ref":"#/components/schemas/OnDemandCertRow"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"ListOrdersResponse":{"type":"object","required":["orders"],"properties":{"orders":{"type":"array","items":{"$ref":"#/components/schemas/AcmeOrderResponse"}}}},"ListPresetsResponse":{"type":"object","required":["presets","total"],"properties":{"presets":{"type":"array","items":{"$ref":"#/components/schemas/PresetResponse"}},"total":{"type":"integer","minimum":0}}},"ListRunsResponse":{"type":"object","required":["items","total","page","page_size"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AgentRunResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"ListSandboxesResponse":{"type":"object","description":"SDK list response: `{ sandboxes: [...], pagination: {...} }`.","required":["sandboxes","pagination"],"properties":{"pagination":{"$ref":"#/components/schemas/Pagination"},"sandboxes":{"type":"array","items":{"$ref":"#/components/schemas/SandboxInner"}}}},"ListScansQuery":{"type":"object","properties":{"page":{"type":["integer","null"],"format":"int64","example":1,"minimum":0},"page_size":{"type":["integer","null"],"format":"int64","example":20,"minimum":0}}},"ListSecretsResponse":{"type":"object","required":["items","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/SecretResponse"}},"total":{"type":"integer","minimum":0}}},"ListSkillsResponse":{"type":"object","description":"Concrete list wrapper for skill definitions (utoipa requires non-generic types).","required":["items","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/SkillDefinitionResponse"}},"total":{"type":"integer","minimum":0}}},"ListTagsResponse":{"type":"object","description":"Response for listing tags","required":["tags","total"],"properties":{"tags":{"type":"array","items":{"type":"string"},"description":"List of available tags"},"total":{"type":"integer","description":"Total number of tags","minimum":0}}},"ListTemplatesQuery":{"type":"object","description":"Query parameters for listing templates","properties":{"featured":{"type":["boolean","null"],"description":"Only return featured templates"},"tag":{"type":["string","null"],"description":"Filter templates by tag"}}},"ListTemplatesResponse":{"type":"object","description":"Response for listing templates","required":["templates","total"],"properties":{"templates":{"type":"array","items":{"$ref":"#/components/schemas/TemplateResponse"},"description":"List of templates"},"total":{"type":"integer","description":"Total number of templates","minimum":0}}},"ListVulnerabilitiesQuery":{"type":"object","properties":{"page":{"type":["integer","null"],"format":"int64","example":1,"minimum":0},"page_size":{"type":["integer","null"],"format":"int64","example":20,"minimum":0},"severity":{"type":["string","null"],"example":"CRITICAL"}}},"LiveVisitorInfo":{"type":"object","required":["id","visitor_id","project_id","environment_id","first_seen","last_seen","is_crawler"],"properties":{"city":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"crawler_name":{"type":["string","null"]},"current_page":{"type":["string","null"],"description":"Most recent page path visited by this visitor"},"custom_data":{},"environment_id":{"type":"integer","format":"int32"},"first_channel":{"type":["string","null"],"description":"Marketing channel from the first visit (e.g. \"Organic Search\", \"Direct\")"},"first_referrer":{"type":["string","null"],"description":"Full referrer URL from the visitor's first session"},"first_referrer_hostname":{"type":["string","null"],"description":"Hostname extracted from first_referrer"},"first_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"id":{"type":"integer","format":"int32"},"ip_address":{"type":["string","null"]},"ip_address_id":{"type":["integer","null"],"format":"int32"},"is_crawler":{"type":"boolean"},"is_eu":{"type":["boolean","null"]},"last_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"latitude":{"type":["number","null"],"format":"double"},"longitude":{"type":["number","null"],"format":"double"},"project_id":{"type":"integer","format":"int32"},"region":{"type":["string","null"]},"timezone":{"type":["string","null"]},"user_agent":{"type":["string","null"]},"visitor_id":{"type":"string"}}},"LiveVisitorsListResponse":{"type":"object","required":["total_count","visitors","window_minutes"],"properties":{"total_count":{"type":"integer","format":"int64"},"visitors":{"type":"array","items":{"$ref":"#/components/schemas/LiveVisitorInfo"}},"window_minutes":{"type":"integer","format":"int32"}}},"LocationCount":{"type":"object","required":["location","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"location":{"type":"string"},"percentage":{"type":"number","format":"double"}}},"LocationGranularity":{"type":"string","enum":["country","region","city"]},"LocationInfo":{"type":"object","properties":{"city":{"type":["string","null"]},"country":{"type":["string","null"]},"region":{"type":["string","null"]}}},"LogLevel":{"type":"string","description":"Normalized log level","enum":["TRACE","DEBUG","INFO","WARN","ERROR"]},"LogRecord":{"type":"object","description":"A single log record ready for storage.","required":["project_id","resource","timestamp","observed_timestamp","severity","severity_text","body","attributes"],"properties":{"attributes":{"type":"object","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"body":{"type":"string"},"deployment_id":{"type":["integer","null"],"format":"int32"},"observed_timestamp":{"type":"string","format":"date-time"},"project_id":{"type":"integer","format":"int32"},"resource":{"$ref":"#/components/schemas/ResourceInfo"},"severity":{"$ref":"#/components/schemas/LogSeverity"},"severity_text":{"type":"string"},"span_id":{"type":["string","null"]},"timestamp":{"type":"string","format":"date-time"},"trace_id":{"type":["string","null"]}}},"LogSearchLine":{"type":"object","description":"A single line in search results","required":["timestamp","level","service","message","chunk_id","line_offset"],"properties":{"chunk_id":{"type":"string"},"container_id":{"type":"string","description":"Container this line came from — lets the UI tag/group lines by container\nin a combined (\"show all\") multi-container view."},"context":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/LineContext","description":"Raw surrounding lines (grep -C). `None` unless `context_lines > 0` was\nrequested. Overlapping windows between nearby matches are merged: the\nshared neighbors appear on the earlier match only, so the frontend can\nrender one continuous block without duplicated lines."}]},"deploy_id":{"type":["integer","null"],"format":"int32"},"fields":{},"level":{"$ref":"#/components/schemas/LogLevel"},"line_offset":{"type":"integer","format":"int32"},"message":{"type":"string"},"node_id":{"type":["integer","null"],"format":"int32","description":"Worker node the line came from (`None` = control-plane-local)."},"node_name":{"type":["string","null"],"description":"Human-readable node name for display."},"service":{"type":"string"},"timestamp":{"type":"string"}}},"LogSeverity":{"type":"string","description":"Log severity level (simplified from OTel's 24 levels).","enum":["TRACE","DEBUG","INFO","WARN","ERROR","FATAL"]},"LogSource":{"type":"object","description":"A distinct log source (container) seen in the queried scope. Used to populate\nthe history filter dropdowns with the *full* set of containers/nodes for the\nproject + env + deployment + time window — independent of the active\ncontainer/node/service filter, so the user can switch between them.","required":["container_id","service"],"properties":{"container_id":{"type":"string"},"node_id":{"type":["integer","null"],"format":"int32"},"node_name":{"type":["string","null"]},"service":{"type":"string"}}},"LogStream":{"type":"string","description":"Log output stream","enum":["stdout","stderr"]},"LoginRequest":{"type":"object","required":["email","password"],"properties":{"email":{"type":"string"},"password":{"type":"string"}}},"LogsQuery":{"type":"object","properties":{"tail":{"type":["integer","null"],"description":"Number of lines to return from the tail. Defaults to 200, capped at 2000.","minimum":0}}},"LogsResponse":{"type":"object","required":["data","count"],"properties":{"count":{"type":"integer","minimum":0},"data":{"type":"array","items":{"$ref":"#/components/schemas/LogRecord"}}}},"ManagedDomainResponse":{"type":"object","description":"Managed domain response","required":["id","provider_id","domain","auto_manage","verified","generated_hostname_mode","sync_generated_records","created_at","updated_at"],"properties":{"auto_manage":{"type":"boolean"},"created_at":{"type":"string"},"domain":{"type":"string"},"generated_hostname_mode":{"type":"string","description":"Generated hostname layout: `\"standard\"` or `\"flat\"`."},"id":{"type":"integer","format":"int32"},"provider_id":{"type":"integer","format":"int32"},"sync_generated_records":{"type":"boolean","description":"Whether generated hostnames are reconciled into the provider's DNS zone."},"updated_at":{"type":"string"},"verification_error":{"type":["string","null"]},"verified":{"type":"boolean"},"verified_at":{"type":["string","null"]},"zone_access_error":{"type":["string","null"],"description":"Detail for a failed zone-access check."},"zone_access_ok":{"type":["boolean","null"],"description":"Last token zone-access check: `Some(true)`/`Some(false)`/`None` (unchecked)."},"zone_id":{"type":["string","null"]}}},"ManualAction":{"type":"object","description":"A manual action the user must perform outside of the automated migration","required":["timing","description","reason"],"properties":{"description":{"type":"string","description":"Human-readable description"},"reason":{"type":"string","description":"Why this can't be automated"},"timing":{"$ref":"#/components/schemas/ManualActionTiming","description":"When this action needs to happen"}}},"ManualActionTiming":{"type":"string","description":"When a manual action needs to happen relative to migration","enum":["before-migration","after-migration","within-hours"]},"McpDefinitionResponse":{"type":"object","required":["id","slug","name","config","created_at","updated_at"],"properties":{"config":{"type":"object"},"created_at":{"type":"string"},"description":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"project_id":{"type":["integer","null"],"format":"int32"},"slug":{"type":"string"},"updated_at":{"type":"string"}}},"MessageContent":{"oneOf":[{"type":"string"},{"type":"array","items":{"$ref":"#/components/schemas/ContentPart"}}]},"MessagePart":{"oneOf":[{"type":"object","required":["text","type"],"properties":{"text":{"type":"string"},"type":{"type":"string","enum":["text"]}}},{"type":"object","required":["tool","type"],"properties":{"tool":{"$ref":"#/components/schemas/ToolInfo"},"type":{"type":"string","enum":["tool"]}}}],"description":"One ordered segment of an assistant turn: a chunk of prose, or a tool\ninvocation. Mirrors the `metadata.parts` persisted by the chat service."},"MessageResponse":{"type":"object","required":["role","content","created_at"],"properties":{"content":{"type":"string"},"created_at":{"type":"string"},"parts":{"type":["array","null"],"items":{"$ref":"#/components/schemas/MessagePart"},"description":"Ordered render segments (text / tool, in the order they occurred) so a\nreloaded chat shows the same interleaving as the live stream. Absent for\nolder messages persisted before parts were tracked; the client then falls\nback to `tools` (rendered first) + `content`."},"role":{"type":"string"},"tools":{"type":["array","null"],"items":{"$ref":"#/components/schemas/ToolInfo"},"description":"Tools the assistant ran on this turn (persisted in message metadata), so\nthe chat replays its tool work after a reload. Absent for plain turns."}}},"MeteredMode":{"type":"string","description":"How to treat metered-billing subscriptions when computing MRR.\n\n* `DeriveFromInvoices` (default): ignore the subscription row's\n `mrr_minor` for metered items and rely on the per-invoice\n [`NormalizedEventType::MrrRealized`] events instead. Correct for\n pure-metered, hybrid, tiered, and flat — recommended.\n* `UseSubscription`: trust whatever MRR the subscription parser\n returns (0 for metered). Legacy behavior.\n* `Ignore`: drop metered subscriptions from MRR entirely.","enum":["derive_from_invoices","use_subscription","ignore"]},"MetricAggregation":{"oneOf":[{"type":"string","description":"Arithmetic mean of the scalar value in each bucket. The default.","enum":["avg"]},{"type":"string","description":"Sum of the scalar value in each bucket.","enum":["sum"]},{"type":"string","description":"Minimum scalar value in each bucket.","enum":["min"]},{"type":"string","description":"Maximum scalar value in each bucket.","enum":["max"]},{"type":"string","description":"Number of points in each bucket.","enum":["count"]},{"type":"string","description":"Per-second rate of change of a cumulative monotonic counter, computed as\n`(max - min) / window_seconds` within each bucket. Non-monotonic series\nfall back to a simple delta.","enum":["rate_per_sec"]},{"type":"object","description":"A quantile of the scalar value in each bucket. The carried `f64` is the\nrequested quantile in `[0.0, 1.0]`.","required":["quantile"],"properties":{"quantile":{"type":"number","format":"double","description":"A quantile of the scalar value in each bucket. The carried `f64` is the\nrequested quantile in `[0.0, 1.0]`."}}}],"description":"The aggregation applied when reducing raw metric points into a time bucket.\n\nStore-neutral: every storage backend (ClickHouse today, TimescaleDB later)\nmust be able to satisfy this contract. `Quantile(q)` carries the requested\nquantile in `[0.0, 1.0]` (e.g. `0.95` for p95)."},"MetricBucket":{"type":"object","description":"A time-bucketed metric aggregate for chart display.\n\nStore-neutral response contract. The legacy scalar fields\n(`avg_value`/`min_value`/`max_value`/`count`) are always populated for chart\nback-compat. The richer fields describe the explicitly-requested\n[`MetricAggregation`] (`value`), optional `quantiles`, an optional\n`histogram_summary`, and a `series_key` identifying the label-set when the\nquery used `group_by`.","required":["bucket","avg_value","min_value","max_value","count"],"properties":{"avg_value":{"type":"number","format":"double"},"bucket":{"type":"string","format":"date-time"},"count":{"type":"integer","format":"int64"},"histogram_summary":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/HistogramSummary","description":"A reduced histogram summary when the bucketed metric is a histogram."}]},"max_value":{"type":"number","format":"double"},"min_value":{"type":"number","format":"double"},"quantiles":{"type":"array","items":{"type":"array","items":false,"prefixItems":[{"type":"number","format":"double"},{"type":"number","format":"double"}]},"description":"Computed quantile/value pairs `(quantile, value)` when the query asked for\nquantile aggregation; otherwise empty."},"series_key":{"type":["array","null"],"items":{"type":"array","items":false,"prefixItems":[{"type":"string"},{"type":"string"}]},"description":"The label-set this bucket belongs to, as ordered `(key, value)` pairs,\nwhen the query grouped by labels. Empty/`None` = the single ungrouped\naggregate stream."},"value":{"type":"number","format":"double","description":"The value of the requested [`MetricAggregation`] for this bucket. For the\ndefault `Avg` aggregation this equals `avg_value`. `#[serde(default)]` so\npre-existing payloads (which only carried avg/min/max/count) still parse."}}},"MetricDataPoint":{"type":"object","description":"A single `(timestamp, value)` data point in a metric series.","required":["time","value"],"properties":{"time":{"type":"string","description":"ISO 8601 timestamp with `Z` suffix."},"value":{"type":"number","format":"double","description":"Metric value at this bucket."}}},"MetricType":{"type":"string","description":"The type of an OTel metric.","enum":["gauge","sum","histogram","exponential_histogram","summary"]},"MetricsOverTimeResponse":{"type":"object","required":["timestamps","ttfb","lcp","fid","fcp","cls","inp"],"properties":{"cls":{"type":"array","items":{"type":["number","null"],"format":"float"}},"cls_p75":{"type":["number","null"],"format":"float"},"cls_p90":{"type":["number","null"],"format":"float"},"cls_p95":{"type":["number","null"],"format":"float"},"cls_p99":{"type":["number","null"],"format":"float"},"fcp":{"type":"array","items":{"type":["number","null"],"format":"float"}},"fcp_p75":{"type":["number","null"],"format":"float"},"fcp_p90":{"type":["number","null"],"format":"float"},"fcp_p95":{"type":["number","null"],"format":"float"},"fcp_p99":{"type":["number","null"],"format":"float"},"fid":{"type":"array","items":{"type":["number","null"],"format":"float"}},"fid_p75":{"type":["number","null"],"format":"float"},"fid_p90":{"type":["number","null"],"format":"float"},"fid_p95":{"type":["number","null"],"format":"float"},"fid_p99":{"type":["number","null"],"format":"float"},"inp":{"type":"array","items":{"type":["number","null"],"format":"float"}},"inp_p75":{"type":["number","null"],"format":"float"},"inp_p90":{"type":["number","null"],"format":"float"},"inp_p95":{"type":["number","null"],"format":"float"},"inp_p99":{"type":["number","null"],"format":"float"},"lcp":{"type":"array","items":{"type":["number","null"],"format":"float"}},"lcp_p75":{"type":["number","null"],"format":"float"},"lcp_p90":{"type":["number","null"],"format":"float"},"lcp_p95":{"type":["number","null"],"format":"float"},"lcp_p99":{"type":["number","null"],"format":"float"},"timestamps":{"type":"array","items":{"type":"string"}},"ttfb":{"type":"array","items":{"type":["number","null"],"format":"float"}},"ttfb_p75":{"type":["number","null"],"format":"float"},"ttfb_p90":{"type":["number","null"],"format":"float"},"ttfb_p95":{"type":["number","null"],"format":"float"},"ttfb_p99":{"type":["number","null"],"format":"float"}}},"MetricsQuery":{"type":"object","required":["start_date","end_date","project_id"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"MetricsRangeQuery":{"type":"object","description":"Query params for range metric queries.","required":["metric"],"properties":{"metric":{"type":"string","description":"Metric name, e.g. `\"pg.connections_active\"`."},"percentile":{"type":["number","null"],"format":"double","description":"Optional histogram percentile (0–100). When provided, the endpoint\nfetches histogram buckets and computes the requested quantile."},"range":{"type":"string","description":"Time window: `\"1h\"` | `\"6h\"` | `\"24h\"` | `\"7d\"`."}}},"MetricsStatusResponse":{"type":"object","description":"Freshness status: when metrics were last received for this service.","properties":{"last_received_at":{"type":["string","null"],"description":"ISO 8601 timestamp of the most recent metric row, or null if none yet."}}},"MetricsStoreKind":{"type":"string","description":"Which storage backend to use for the MetricsStore.","enum":["timescale_db","click_house"]},"MetricsSummaryResponse":{"type":"object","required":["currency","current_mrr_minor","current_arr_minor","active_subscriptions","active_customers","churned_last_30d","arpu_minor"],"properties":{"active_customers":{"type":"integer","format":"int64"},"active_subscriptions":{"type":"integer","format":"int64"},"arpu_minor":{"type":"integer","format":"int64"},"churned_last_30d":{"type":"integer","format":"int64"},"currency":{"type":"string"},"current_arr_minor":{"type":"integer","format":"int64"},"current_mrr_minor":{"type":"integer","format":"int64"}}},"MfaRequiredResponse":{"type":"object","required":["requires_mfa","session_token"],"properties":{"requires_mfa":{"type":"boolean"},"session_token":{"type":"string"}}},"MfaSetupResponse":{"type":"object","required":["secret_key","qr_code","recovery_codes"],"properties":{"qr_code":{"type":"string"},"recovery_codes":{"type":"array","items":{"type":"string"}},"secret_key":{"type":"string"}}},"MfaVerificationRequest":{"type":"object","required":["code"],"properties":{"code":{"type":"string"}}},"MigrationStep":{"type":"object","description":"A single step in the migration execution plan.\n\nSteps are presented to the user before execution so they know exactly\nwhat will happen. During execution, each step runs in order and reports\nits outcome before proceeding to the next.","required":["order","id","title","description","resource_type","risk","skippable","reversible"],"properties":{"data_implications":{"type":"array","items":{"$ref":"#/components/schemas/DataImplication"},"description":"Data implications — what could go wrong or what the user needs to know"},"description":{"type":"string","description":"Detailed description of what this step does"},"estimated_duration":{"type":["string","null"],"description":"Estimated duration hint (e.g., \"< 1 second\", \"10-30 seconds\")"},"id":{"type":"string","description":"Machine-readable step identifier (e.g., \"create-project\", \"create-service-postgres\")"},"order":{"type":"integer","description":"Step number (1-based, for display)","minimum":0},"post_conditions":{"type":"array","items":{"type":"string"},"description":"Things the user should verify AFTER this step completes"},"pre_conditions":{"type":"array","items":{"type":"string"},"description":"Things the user should verify BEFORE this step runs"},"resource_type":{"$ref":"#/components/schemas/StepResourceType","description":"What kind of resource this step creates/modifies"},"reversible":{"type":"boolean","description":"Whether this step is reversible (can be cleaned up on failure)"},"risk":{"$ref":"#/components/schemas/RiskLevel","description":"Risk level for this step"},"skippable":{"type":"boolean","description":"Whether this step can be skipped by the user"},"skipped":{"type":"boolean","description":"Whether the user has chosen to skip this step (set during review)"},"title":{"type":"string","description":"Human-readable title (e.g., \"Create project 'my-app'\")"}}},"MigrationSummary":{"type":"object","description":"Human-readable summary of the entire migration plan","required":["headline","overall_risk","resource_counts"],"properties":{"critical_warnings":{"type":"array","items":{"type":"string"},"description":"Critical warnings that must be acknowledged before proceeding.\nThese are the most important things the user needs to know."},"headline":{"type":"string","description":"One-line summary (e.g., \"Migrate 'my-app' from Vercel with 1 database, 2 domains\")"},"manual_actions_required":{"type":"array","items":{"$ref":"#/components/schemas/ManualAction"},"description":"Manual actions the user must perform (before or after migration)"},"overall_risk":{"$ref":"#/components/schemas/RiskLevel","description":"Overall risk assessment for the migration"},"resource_counts":{"$ref":"#/components/schemas/ResourceCounts","description":"Resource counts for quick overview"},"unsupported_features":{"type":"array","items":{"$ref":"#/components/schemas/UnsupportedFeature"},"description":"Features from the source platform that cannot be migrated"}}},"MintEnrollmentTokenRequest":{"type":"object","properties":{"bound_node_name":{"type":["string","null"],"description":"Optional: restrict the token to register one specific node name."},"max_uses":{"type":["integer","null"],"format":"int32","description":"Maximum registrations this token may authorize (default 1)."},"ttl_secs":{"type":["integer","null"],"format":"int64","description":"Time-to-live in seconds (default 3600 = 1h)."}}},"MintEnrollmentTokenResponse":{"type":"object","required":["id","token","expires_at","max_uses","message"],"properties":{"ca_fingerprint":{"type":["string","null"],"description":"SHA-256 fingerprint of the cluster CA (if mTLS is set up). Pass it to the\nworker as `temps join --ca-fingerprint ` to verify the CA on join."},"expires_at":{"type":"string"},"id":{"type":"integer","format":"int32"},"max_uses":{"type":"integer","format":"int32"},"message":{"type":"string"},"token":{"type":"string","description":"The plaintext enrollment token — shown only once, save it now."}}},"MiscResult":{"type":"object","description":"Miscellaneous validation result","required":["is_disposable","is_role_account","is_b2c"],"properties":{"gravatar_url":{"type":["string","null"],"description":"Gravatar URL if available"},"is_b2c":{"type":"boolean","description":"Whether the email provider is a B2C (consumer) email provider"},"is_disposable":{"type":"boolean","description":"Whether the email is from a disposable email provider"},"is_role_account":{"type":"boolean","description":"Whether the email is a role-based account (e.g., admin@, info@)"}}},"MkdirBody":{"type":"object","required":["path"],"properties":{"path":{"type":"string"}},"additionalProperties":false},"ModelInfo":{"type":"object","required":["id","object","owned_by"],"properties":{"id":{"type":"string"},"object":{"type":"string"},"owned_by":{"type":"string"}}},"ModelListResponse":{"type":"object","required":["object","data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ModelInfo"}},"object":{"type":"string"}}},"ModelPricing":{"type":"object","description":"Pricing for a single model, all values in USD per 1M tokens.\nFields are optional because not every provider supports every pricing tier.","required":["model","display_name","provider","input_per_million","output_per_million"],"properties":{"batch_input_per_million":{"type":["number","null"],"format":"double","description":"Batch API input cost per 1M tokens (if provider offers batch pricing)"},"batch_output_per_million":{"type":["number","null"],"format":"double","description":"Batch API output cost per 1M tokens"},"cache_hit_per_million":{"type":["number","null"],"format":"double","description":"Cache hit / refresh cost per 1M tokens"},"cache_write_1h_per_million":{"type":["number","null"],"format":"double","description":"1-hour cache write cost per 1M tokens"},"cache_write_5m_per_million":{"type":["number","null"],"format":"double","description":"5-minute cache write cost per 1M tokens (Anthropic-style prompt caching)"},"deprecated":{"type":"boolean","description":"Whether the model is deprecated"},"display_name":{"type":"string","description":"Human-readable model name (e.g. \"Claude Sonnet 4.6\")"},"input_per_million":{"type":"number","format":"double","description":"Base input token cost per 1M tokens"},"model":{"type":"string","description":"Model identifier (e.g. \"gpt-5.4\", \"claude-sonnet-4-6\")"},"output_per_million":{"type":"number","format":"double","description":"Output token cost per 1M tokens"},"provider":{"type":"string","description":"Provider ID (e.g. \"openai\", \"anthropic\")"}}},"ModelUsage":{"type":"object","required":["model","provider","request_count","input_tokens","output_tokens","total_tokens","avg_latency_ms"],"properties":{"avg_latency_ms":{"type":"number","format":"double"},"input_tokens":{"type":"integer","format":"int64"},"model":{"type":"string"},"output_tokens":{"type":"integer","format":"int64"},"provider":{"type":"string"},"request_count":{"type":"integer","format":"int64"},"total_tokens":{"type":"integer","format":"int64"}}},"MonitorResponse":{"type":"object","required":["id","project_id","name","monitor_type","monitor_url","check_interval_seconds","is_active","created_at","updated_at"],"properties":{"check_interval_seconds":{"type":"integer","format":"int32"},"check_path":{"type":["string","null"]},"created_at":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"monitor_type":{"type":"string"},"monitor_url":{"type":"string"},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"updated_at":{"type":"string","format":"date-time"}}},"MonitorStatus":{"type":"object","required":["monitor","current_status","uptime_percentage"],"properties":{"avg_response_time_ms":{"type":["integer","null"],"format":"int32"},"current_status":{"type":"string"},"monitor":{"$ref":"#/components/schemas/MonitorResponse"},"uptime_percentage":{"type":"number","format":"double"}}},"MonitoringSettings":{"type":"object","description":"Global metrics observability configuration.\n\nControls whether the MetricsScraper and AlertEvaluator background tasks\nare active, which storage backend they write to, and how long data is kept\nat each retention tier.","properties":{"clickhouse_url":{"type":["string","null"],"description":"ClickHouse DSN (legacy, optional). The runtime metrics store is built\nfrom the `TEMPS_CLICKHOUSE_*` env vars, never from this field; it is\nretained for compatibility and operator reference only.\nExample: `\"http://localhost:8123\"`.","default":null},"enabled":{"type":"boolean","description":"Enable or disable all metrics collection (scraping + alerting).\nDefaults to `false` so new installs don't write to TimescaleDB until\nan operator explicitly enables the feature.","default":false},"retention_daily_years":{"type":"integer","format":"int32","description":"How many years of daily-aggregate data to keep (converted to days internally).","default":2,"example":2,"maximum":10,"minimum":1},"retention_hourly_days":{"type":"integer","format":"int32","description":"How many days of hourly-aggregate data to keep.","default":90,"example":90,"minimum":1},"retention_raw_days":{"type":"integer","format":"int32","description":"How many days of raw (30 s resolution) metric data to keep.","default":7,"example":7,"minimum":1},"scrape_interval_secs":{"type":"integer","format":"int64","description":"How often the MetricsScraper collects data from all sources, in seconds.\nMinimum effective value is 10 s; values below that are clamped at runtime.","default":30,"example":30,"minimum":10},"store":{"oneOf":[{"$ref":"#/components/schemas/MetricsStoreKind","description":"Storage backend for metric data."}],"default":"timescale_db"}}},"MonitoringSettingsMasked":{"type":"object","description":"Monitoring settings with the ClickHouse DSN masked.\n\n`clickhouse_url` can embed credentials (`http://user:pass@host`), so it is\nreported only as a boolean (`clickhouse_url_set`) rather than echoed back —\nconsistent with how the DNS API key and Docker registry password are masked.","required":["enabled","store","scrape_interval_secs","retention_raw_days","retention_hourly_days","retention_daily_years","clickhouse_url_set"],"properties":{"clickhouse_url_set":{"type":"boolean","description":"True when a ClickHouse DSN is configured. The DSN itself is never\nreturned over HTTP because it may contain credentials."},"enabled":{"type":"boolean"},"retention_daily_years":{"type":"integer","format":"int32","minimum":0},"retention_hourly_days":{"type":"integer","format":"int32","minimum":0},"retention_raw_days":{"type":"integer","format":"int32","minimum":0},"scrape_interval_secs":{"type":"integer","format":"int64","minimum":0},"store":{"$ref":"#/components/schemas/MetricsStoreKind"}}},"MrrBucketResponse":{"type":"object","required":["bucket","mrr_minor","charge_total_minor","refund_total_minor","charge_count"],"properties":{"bucket":{"type":"string","format":"date-time"},"charge_count":{"type":"integer","format":"int64"},"charge_total_minor":{"type":"integer","format":"int64"},"mrr_minor":{"type":"integer","format":"int64"},"refund_total_minor":{"type":"integer","format":"int64"}}},"MultiNodeSettings":{"type":"object","description":"Multi-node cluster settings","properties":{"cluster_ca_cert_pem":{"type":["string","null"],"description":"Per-cluster CA certificate (PEM) for multi-node mTLS (ADR-020 WS-2.1).\nPublic — distributed to nodes as the trust root and used by the control\nplane as the root for verifying agent server certs. Minted lazily on the\nfirst CSR-bearing registration.","default":null},"cluster_ca_key_encrypted":{"type":["string","null"],"description":"Per-cluster CA private key, AES-256-GCM ciphertext (EncryptionService).\nSECRET — never returned over HTTP (elided in the masked response).","default":null},"join_token_hash":{"type":["string","null"],"description":"SHA-256 hash of the join token (never store plaintext)","default":null},"legacy_shared_token_enabled":{"type":"boolean","description":"Whether the legacy single shared join token is still accepted for node\nregistration (ADR-020 WS-1.1). Defaults to `true` so existing clusters\nkeep working on upgrade; fresh installs should set it `false` and rely on\nshort-lived, single-use enrollment tokens instead.","default":true},"node_cpu_alert_percent":{"type":["number","null"],"format":"double","description":"CPU-usage percent above which a worker node raises a resource alert\n(ADR-020 / monitoring). `None` disables CPU alerting. Default 90.","default":90.0},"node_disk_alert_percent":{"type":["number","null"],"format":"double","description":"Disk-usage percent above which a worker node raises a resource alert.\n`None` disables disk alerting. Default 90.","default":90.0},"node_memory_alert_percent":{"type":["number","null"],"format":"double","description":"Memory-usage percent above which a worker node raises a resource alert.\n`None` disables memory alerting. Default 90.","default":90.0},"private_address":{"type":["string","null"],"description":"Private/WireGuard IP address of the control plane node.\nUsed by remote worker nodes to reach services (databases, etc.) running on the control plane.\nSet via `--private-address` or `TEMPS_PRIVATE_ADDRESS`.","default":null},"require_mtls":{"type":"boolean","description":"Whether to enforce multi-node mTLS (ADR-020 WS-2.1). When `false`\n(default), the control plane ignores join-time CSRs and nodes keep\nserving plaintext HTTP — zero behavior change. When `true`, the CP signs\nnode CSRs, nodes serve mutual TLS, and every CP→agent call uses the\ncluster client cert. Observe-then-enforce: flip this on only once all\nworkers have re-enrolled with certs.","default":false}}},"MultiNodeSettingsMasked":{"type":"object","description":"Multi-node settings with `join_token_hash` elided.","required":["has_join_token","require_mtls","legacy_shared_token_enabled"],"properties":{"cluster_ca_fingerprint":{"type":["string","null"],"description":"SHA-256 fingerprint of the cluster CA certificate (public — operators can\nverify it out of band; the CA private key is never exposed)."},"has_join_token":{"type":"boolean"},"legacy_shared_token_enabled":{"type":"boolean","description":"Whether the deprecated shared join token is still accepted."},"node_cpu_alert_percent":{"type":["number","null"],"format":"double","description":"Node resource-alert thresholds (percent); `None` = that alert disabled."},"node_disk_alert_percent":{"type":["number","null"],"format":"double"},"node_memory_alert_percent":{"type":["number","null"],"format":"double"},"private_address":{"type":["string","null"]},"require_mtls":{"type":"boolean","description":"Whether control-plane↔agent mutual TLS is enforced."}}},"MxResult":{"type":"object","description":"MX (Mail Exchange) validation result","required":["accepts_mail","records"],"properties":{"accepts_mail":{"type":"boolean","description":"Whether the domain accepts mail"},"error":{"type":["string","null"],"description":"Error message if MX lookup failed"},"records":{"type":"array","items":{"type":"string"},"description":"List of MX records for the domain","example":["alt1.gmail-smtp-in.l.google.com.","gmail-smtp-in.l.google.com."]}}},"NavEntry":{"type":"object","description":"A navigation entry that the plugin contributes to the Temps UI.","required":["label","icon","section","path","order"],"properties":{"icon":{"type":"string","description":"Lucide icon name (e.g., \"puzzle\", \"database\", \"activity\")"},"label":{"type":"string","description":"Display label in the sidebar"},"order":{"type":"integer","format":"int32","description":"Sort order within the section (lower = higher in list)","minimum":0},"path":{"type":"string","description":"Client-side route path (e.g., \"/my-plugin\")"},"section":{"$ref":"#/components/schemas/NavSection","description":"Which sidebar section this entry belongs to"}}},"NavSection":{"type":"string","description":"Where the plugin's nav entry appears in the Temps UI sidebar.","enum":["platform","settings","project"]},"NetworkConfiguration":{"type":"object","description":"Network configuration","required":["mode","dns_servers"],"properties":{"dns_servers":{"type":"array","items":{"type":"string"},"description":"DNS servers"},"hostname":{"type":["string","null"],"description":"Hostname"},"mode":{"$ref":"#/components/schemas/NetworkMode","description":"Network mode"}}},"NetworkMode":{"oneOf":[{"type":"string","enum":["bridge"]},{"type":"string","enum":["host"]},{"type":"string","enum":["none"]},{"type":"object","required":["custom"],"properties":{"custom":{"type":"string"}}}],"description":"Network mode"},"NixpacksPresetConfig":{"type":"object","description":"Configuration for Nixpacks preset\nNixpacks provider and inline build-plan configuration.","properties":{"nixpacksConfig":{"type":["string","null"],"description":"Optional inline nixpacks.toml contents."},"providers":{"type":"array","items":{"$ref":"#/components/schemas/NixpacksProvider"},"description":"Ordered Nixpacks providers. Empty means repository config or auto-detect;\ninclude `...` to combine auto-detection with explicit providers."}}},"NixpacksProvider":{"type":"string","description":"A Nixpacks build provider.\n\n`Auto` serializes as the native Nixpacks `...` marker, which includes the\nprovider detected from the project alongside any explicitly listed\nproviders.","enum":["...","node","python","rust","go","java","php","ruby","deno","elixir","csharp","fsharp","dart","swift","zig","scala","haskell","clojure","crystal","cobol","gleam","lunatic","scheme","static"]},"NodeContainerListResponse":{"type":"object","required":["containers","total"],"properties":{"containers":{"type":"array","items":{"$ref":"#/components/schemas/NodeContainerResponse"}},"total":{"type":"integer","minimum":0}}},"NodeContainerResponse":{"type":"object","description":"A container running on a specific node, enriched with project/environment context.","required":["container_id","container_name","image_name","status","created_at","deployment_id","project_id","project_name","environment_id","environment_name"],"properties":{"container_id":{"type":"string"},"container_name":{"type":"string"},"created_at":{"type":"string"},"deployment_id":{"type":"integer","format":"int32"},"environment_id":{"type":"integer","format":"int32"},"environment_name":{"type":"string"},"image_name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"project_name":{"type":"string"},"status":{"type":"string"}}},"NodeCostInfo":{"type":"object","description":"One cluster node with capacity and (when priceable) a cost estimate","required":["name","cpu_millis","memory_mb"],"properties":{"cpu_millis":{"type":"integer","format":"int64","description":"CPU capacity in millicores"},"instance_type":{"type":["string","null"],"description":"Instance type from `node.kubernetes.io/instance-type` (e.g. \"m5.xlarge\")"},"memory_mb":{"type":"integer","format":"int64","description":"Memory capacity in MB"},"monthly_usd":{"type":["number","null"],"format":"double","description":"Estimated on-demand monthly price in USD. `None` when the instance\ntype is unknown or not in the price table."},"name":{"type":"string","description":"Node name"},"region":{"type":["string","null"],"description":"Region from `topology.kubernetes.io/region`"}}},"NodeInfoResponse":{"type":"object","required":["id","name","address","private_address","role","status","labels","capacity","created_at"],"properties":{"address":{"type":"string"},"architecture":{"type":["string","null"],"description":"Container platform this node runs (`linux/amd64`, `linux/arm64`).\n`None` until an agent that reports it has heartbeated."},"capacity":{"description":"Resource capacity/usage metrics from the latest heartbeat"},"created_at":{"type":"string"},"id":{"type":"integer","format":"int32"},"labels":{},"last_heartbeat":{"type":["string","null"]},"name":{"type":"string"},"private_address":{"type":"string"},"role":{"type":"string"},"status":{"type":"string"}}},"NodeListResponse":{"type":"object","required":["nodes","total"],"properties":{"nodes":{"type":"array","items":{"$ref":"#/components/schemas/NodeInfoResponse"}},"total":{"type":"integer","minimum":0}}},"NotificationPreferencesResponse":{"type":"object","required":["email_enabled","slack_enabled","batch_similar_notifications","minimum_severity","deployment_failures_enabled","build_errors_enabled","runtime_errors_enabled","error_threshold","error_time_window","ssl_expiration_enabled","ssl_days_before_expiration","domain_expiration_enabled","dns_changes_enabled","backup_failures_enabled","backup_successes_enabled","s3_connection_issues_enabled","retention_policy_violations_enabled","route_downtime_enabled","load_balancer_issues_enabled","weekly_digest_enabled","digest_send_day","digest_send_time","digest_sections"],"properties":{"backup_failures_enabled":{"type":"boolean"},"backup_successes_enabled":{"type":"boolean"},"batch_similar_notifications":{"type":"boolean"},"build_errors_enabled":{"type":"boolean"},"deployment_failures_enabled":{"type":"boolean"},"digest_sections":{"$ref":"#/components/schemas/DigestSections"},"digest_send_day":{"type":"string"},"digest_send_time":{"type":"string"},"dns_changes_enabled":{"type":"boolean"},"domain_expiration_enabled":{"type":"boolean"},"email_enabled":{"type":"boolean"},"error_threshold":{"type":"integer","format":"int32"},"error_time_window":{"type":"integer","format":"int32"},"load_balancer_issues_enabled":{"type":"boolean"},"minimum_severity":{"type":"string"},"retention_policy_violations_enabled":{"type":"boolean"},"route_downtime_enabled":{"type":"boolean"},"runtime_errors_enabled":{"type":"boolean"},"s3_connection_issues_enabled":{"type":"boolean"},"slack_enabled":{"type":"boolean"},"ssl_days_before_expiration":{"type":"integer","format":"int32"},"ssl_expiration_enabled":{"type":"boolean"},"weekly_digest_enabled":{"type":"boolean"}}},"NotificationProviderResponse":{"type":"object","required":["id","name","provider_type","config","enabled","created_at","updated_at"],"properties":{"config":{},"created_at":{"type":"integer","format":"int64"},"enabled":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"provider_type":{"type":"string"},"updated_at":{"type":"integer","format":"int64"}}},"ObservabilityCompressionSettings":{"type":"object","description":"TimescaleDB compression policy configuration for append-only observability\ntables. Values are expressed in hours so operators can choose sub-day\nwindows while keeping the API representation unambiguous.","properties":{"otel_spans_after_hours":{"type":"integer","format":"int32","description":"Compress OpenTelemetry span chunks after this many hours. Defaults to\n24 hours.","default":24,"example":24,"maximum":2160,"minimum":1},"proxy_logs_after_hours":{"type":"integer","format":"int32","description":"Compress proxy-log chunks after this many hours. Defaults to 24 hours.","default":24,"example":24,"maximum":720,"minimum":1}}},"ObservabilityEvent":{"oneOf":[{"allOf":[{"$ref":"#/components/schemas/RequestRow"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["request"]}}}]},{"allOf":[{"$ref":"#/components/schemas/SpanRow"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["span"]}}}]},{"allOf":[{"$ref":"#/components/schemas/ErrorRow"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["error"]}}}]},{"allOf":[{"$ref":"#/components/schemas/RevenueRow"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["revenue"]}}}]}],"description":"Discriminated union of every row that can appear in the Observe list.\n\nSerializes to `{ \"type\": \"request\" | \"span\" | ... , ...rest }` so the UI\ncan switch on `event.type` without ambiguity.\n\n**No `Log` variant**: runtime stdout/stderr lines live on a dedicated\nLogs page rather than Observe. Logs are too high-volume to interleave\nwith business signals (requests, errors, revenue) without dominating\nthe timeline, and they have their own retention/storage constraints\n(TimescaleDB hypertable + chunked file/S3 store) that don't compose\nwith the merge service's per-kind LIMIT strategy."},"ObservabilityRetentionSettings":{"type":"object","description":"Retention policy configuration for raw observability tables. Values are in\ndays. The Settings API applies them to TimescaleDB; ClickHouse-backed proxy\nlogs and spans retain their storage-level per-row TTL behavior.","properties":{"otel_logs_days":{"type":"integer","format":"int32","description":"Retain OpenTelemetry log events for this many days.","default":90,"example":90,"maximum":3650,"minimum":1},"otel_metrics_days":{"type":"integer","format":"int32","description":"Retain OpenTelemetry metric points for this many days.","default":90,"example":90,"maximum":3650,"minimum":1},"otel_spans_days":{"type":"integer","format":"int32","description":"Retain OpenTelemetry spans (traces) for this many days.","default":90,"example":90,"maximum":3650,"minimum":1},"proxy_logs_days":{"type":"integer","format":"int32","description":"Retain proxy request logs for this many days.","default":30,"example":30,"maximum":3650,"minimum":1}}},"OidcProviderResponse":{"type":"object","required":["id","name","issuer_url","client_id","client_secret","scopes","jit_provisioning","enabled","template","group_claim","role_claim","default_role","trust_idp_email"],"properties":{"client_id":{"type":"string"},"client_secret":{"type":"string","description":"Always masked — the secret is never returned after creation."},"default_role":{"type":"string"},"enabled":{"type":"boolean"},"group_claim":{"type":"string"},"id":{"type":"integer","format":"int32"},"issuer_url":{"type":"string"},"jit_provisioning":{"type":"boolean"},"name":{"type":"string"},"role_claim":{"type":"string"},"scopes":{"type":"string"},"template":{"type":"string"},"trust_idp_email":{"type":"boolean","description":"When true, the resolver skips the `email_verified` claim gate\nduring SSO login. Only safe for IdPs where an admin controls\nuser provisioning — see `oidc_providers::Model::trust_idp_email`."}}},"OidcProviderSummary":{"type":"object","required":["slug","name","template"],"properties":{"name":{"type":"string"},"slug":{"type":"string","description":"Stable opaque slug — use this as the path parameter when initiating\nOIDC login (`/auth/oidc/login/{slug}`). The integer database ID is\nintentionally omitted from this public endpoint to prevent provider\nenumeration."},"template":{"type":"string","description":"The template the provider was created from — e.g. `keycloak`,\n`okta`, `auth0`, `google`, `azure-ad`, or `generic`. Surfaced on\nthe public login endpoint so the unauthenticated login page can\nrender the right brand logo on the \"Sign in with X\" button.\nNever sensitive — the template name is part of the provider's\npublic identity, not configuration."}}},"OidcProviderUserResponse":{"type":"object","description":"A user that has logged in via a given OIDC provider. Used by the\nadmin \"Users for provider\" panel — the `oidc_subject` is the\nIdP-side identifier we matched on, useful when diagnosing why a\nuser can or can't log in.","required":["id","name","email","email_verified","mfa_enabled","created_at","updated_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2024-01-15T14:30:00Z"},"email":{"type":"string"},"email_verified":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"mfa_enabled":{"type":"boolean"},"name":{"type":"string"},"oidc_subject":{"type":["string","null"]},"updated_at":{"type":"string","format":"date-time","example":"2024-01-15T14:30:00Z"}}},"OidcProvidersListResponse":{"type":"object","required":["providers"],"properties":{"providers":{"type":"array","items":{"$ref":"#/components/schemas/OidcProviderSummary"}}}},"OidcRoleMappingResponse":{"type":"object","required":["id","provider_id","priority","idp_group","role"],"properties":{"id":{"type":"integer","format":"int32"},"idp_group":{"type":"string"},"priority":{"type":"integer","format":"int32"},"provider_id":{"type":"integer","format":"int32"},"role":{"type":"string"}}},"OidcTestConnectionResponse":{"type":"object","required":["success","message"],"properties":{"message":{"type":"string"},"success":{"type":"boolean"}}},"OnDemandCertAttemptResponse":{"type":"object","description":"A single on-demand HTTP-01 issuance attempt from the append-only\n`on_demand_cert_attempts` audit log. Carries the full forensic detail for one\nattempt; the current cert state lives on the enclosing row's domain fields.\n\nContains no private-key or certificate material — only audit metadata — so it\nis safe to return without masking.","required":["id","hostname","trigger","outcome","created_at"],"properties":{"acme_request_sent":{"type":["boolean","null"],"description":"Did we reach the Let's Encrypt API?"},"acme_response_status":{"type":["string","null"],"description":"HTTP status or ACME error type returned by Let's Encrypt, when known."},"challenge_served":{"type":["boolean","null"],"description":"Did the proxy serve the `/.well-known/acme-challenge/` request?"},"created_at":{"type":"integer","format":"int64","description":"When the attempt was recorded (epoch millis)."},"duration_ms":{"type":["integer","null"],"format":"int32","description":"End-to-end issuance duration in milliseconds (0/None for skipped)."},"error_category":{"type":["string","null"],"description":"Coarse error category for UI labelling: `\"rate_limited\"`, `\"dns_failure\"`,\n`\"acme_order_expired\"`, `\"challenge_mismatch\"`, `\"timeout\"`, `\"internal\"`."},"error_chain":{"type":["string","null"],"description":"Full `Display` chain of the error (all `source()` levels), when failed."},"hostname":{"type":"string","description":"SNI hostname that triggered the attempt."},"id":{"type":"integer","format":"int32"},"outcome":{"type":"string","description":"Final outcome: `\"issued\"`, `\"failed\"`, `\"skipped_duplicate\"`,\n`\"skipped_gate\"`, `\"skipped_rate_limit\"`, or `\"skipped_no_route\"`."},"trigger":{"type":"string","description":"What triggered the attempt (always `\"tls_callback\"` today)."}}},"OnDemandCertRow":{"type":"object","description":"One row of the on-demand certificates list: the most-recent attempt for a\nhostname plus the current authoritative cert state from its `domains` row.","required":["hostname","attempt"],"properties":{"attempt":{"$ref":"#/components/schemas/OnDemandCertAttemptResponse","description":"The audit record for the attempt this row represents (newest first in\nthe list)."},"backoff_until":{"type":["integer","null"],"format":"int64","description":"On-demand negative-cache deadline (epoch millis), when in backoff."},"expiration_time":{"type":["integer","null"],"format":"int64","description":"Certificate expiration (epoch millis), when an active cert exists."},"hostname":{"type":"string","description":"SNI hostname."},"status":{"type":["string","null"],"description":"Current cert lifecycle status from the `domains` row, when one exists:\n`on_demand_pending`, `on_demand_issuing`, `active`, `on_demand_failed`,\netc. `None` when no `domains` row exists yet for this hostname."}}},"OnDemandTlsSettings":{"type":"object","description":"On-demand (lazy) HTTP-01 TLS issuance settings (ADR-018).\n\nWhen `enabled`, the proxy's `certificate_callback` triggers ACME HTTP-01\nissuance for allowlisted, STABLE hostnames (per-environment aliases and the\nconsole host) that have no active cert, rather than silently failing the\nhandshake. Ephemeral per-deployment hostnames are NEVER certed (ADR §2).\n\nOff by default — operators opt in explicitly, except QuickStart (`sslip.io`)\ninstalls where `temps setup` auto-enables it and derives `zone`.","properties":{"deployment_url_mode":{"type":"string","description":"How ephemeral per-deployment hostnames behave when they have no cert\n(they are NEVER certed — see ADR §2). One of:\n - `\"http\"` (default): serve plain HTTP on :80.\n - `\"redirect_to_env\"`: 308-redirect to the stable per-environment URL,\n which IS certed.","default":"http","example":"http"},"enabled":{"type":"boolean","description":"Master switch. When `false` (default) the proxy's on-demand cert gate\nrejects every SNI and no issuance is ever triggered.","default":false,"example":false},"hourly_cap":{"type":"integer","format":"int32","description":"Global cap on total on-demand issuances per hour across all hostnames\n(ADR §4 Layer 3). The operator's self-imposed safety net, separate from\nthe Let's Encrypt rate limit.","default":10,"example":10,"minimum":1},"max_concurrent":{"type":"integer","format":"int32","description":"Maximum number of ACME issuance flows allowed to run simultaneously\n(the concurrent-issuance semaphore, ADR §4 Layer 1). Min 1.","default":3,"example":3,"minimum":1},"zone":{"type":["string","null"],"description":"Zone suffix for the allowlist gate. A hostname passes the gate only if\nit is a direct subdomain of this zone (e.g. zone `1.2.3.4.sslip.io`\nadmits `myapp.1.2.3.4.sslip.io` but not `deep.sub.1.2.3.4.sslip.io`).\n`None` (default) means \"auto-derive from `external_url`\"; if no zone can\nbe derived the gate rejects all SNI, disabling the feature.","default":null,"example":"1.2.3.4.sslip.io"}}},"OpenAiError":{"type":"object","required":["message","type"],"properties":{"code":{"type":["string","null"]},"message":{"type":"string"},"type":{"type":"string"}}},"OpenAiErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"$ref":"#/components/schemas/OpenAiError"}}},"OperatingSystemCount":{"type":"object","required":["operating_system","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"operating_system":{"type":"string"},"percentage":{"type":"number","format":"double"}}},"OperationResultResponse":{"type":"object","required":["operation","success","message","executed_at"],"properties":{"data":{},"executed_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"message":{"type":"string"},"operation":{"type":"string"},"success":{"type":"boolean"}}},"OperationResultsResponse":{"type":"object","required":["deployment_id","operations"],"properties":{"deployment_id":{"type":"string"},"operations":{"type":"array","items":{"$ref":"#/components/schemas/OperationResultResponse"}}}},"OtelDashboardResponse":{"type":"object","required":["id","project_id","name","layout","created_at","updated_at"],"properties":{"created_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"id":{"type":"integer","format":"int32"},"layout":{"$ref":"#/components/schemas/DashboardLayout"},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"updated_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"}}},"OtelDashboardsResponse":{"type":"object","required":["data","total"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/OtelDashboardResponse"}},"total":{"type":"integer","format":"int64","minimum":0}}},"OtelMetricAlertRuleResponse":{"type":"object","required":["id","project_id","name","metric_name","aggregation","detection_kind","detection_config","window_secs","for_duration_secs","severity","enabled","last_state","label_filters","group_by","dynamic_alerts","max_series","grouped_notification_threshold","last_dropped_series_count","series_states","created_at","updated_at"],"properties":{"aggregation":{"type":"string"},"created_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"detection_config":{"$ref":"#/components/schemas/DetectionConfig","description":"The typed detector definition (discriminated union keyed by `kind`)."},"detection_kind":{"type":"string","description":"Coarse detector discriminator: `static|anomaly|forecast|outlier|auto_watch`."},"dynamic_alerts":{"type":"boolean","description":"Whether per-series (\"dynamic\") alerting is enabled for this rule."},"enabled":{"type":"boolean"},"firing_series":{"type":"array","items":{"$ref":"#/components/schemas/FiringSeriesEntry"},"description":"Currently-firing series for a dynamic rule, snapshotted from the evaluator's\nin-memory firing map at read time. Empty for static/aggregate rules or when\nnothing is firing."},"for_duration_secs":{"type":"integer","format":"int32"},"group_by":{"type":"array","items":{"type":"string"},"description":"Label keys the rule breaks the metric down by. Empty = one aggregate stream."},"grouped_notification_threshold":{"type":"integer","format":"int32","description":"Notification-grouping threshold: when more than this many series fire in the\nsame tick, only the first gets chart/AI enrichment (1–1000)."},"id":{"type":"integer","format":"int32"},"label_filters":{"type":"array","items":{"type":"array","items":false,"prefixItems":[{"type":"string"},{"type":"string"}]},"description":"AND-combined label equality filters applied when evaluating this rule.\nEmpty = no filtering (matches all series)."},"last_dropped_series_count":{"type":"integer","format":"int32","description":"Number of series dropped by the cardinality cap on the latest dynamic tick\n(0 when nothing was dropped or for static/aggregate rules). Lets a UI warn\n\"N series were dropped this tick\" without reading server logs."},"last_evaluated_at":{"type":["string","null"],"example":"2025-10-12T12:15:47.609192Z"},"last_state":{"type":"string","description":"One of `ok|firing|unknown`."},"last_value":{"type":["number","null"],"format":"double"},"max_series":{"type":"integer","format":"int32","description":"Cardinality cap for dynamic alerting (1–100)."},"metric_name":{"type":"string"},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"series_states":{"type":"object","description":"Full per-series state snapshot persisted after the latest dynamic-rule tick,\nkeyed by the human-readable series label (`endpoint=/checkout`). Empty for\nstatic/aggregate rules. Unlike `firing_series` (a live in-memory snapshot),\nthis is decoded from the persisted `series_states` jsonb column, so an\nexternal consumer that only reads the rule row still sees per-series detail.","additionalProperties":{"$ref":"#/components/schemas/SeriesStateEntry"},"propertyNames":{"type":"string"}},"severity":{"type":"string"},"updated_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"window_secs":{"type":"integer","format":"int32"}}},"OtelMetricAlertsResponse":{"type":"object","required":["data","total"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/OtelMetricAlertRuleResponse"}},"total":{"type":"integer","format":"int64","minimum":0}}},"OtelMetricLabelKeysResponse":{"type":"object","required":["keys"],"properties":{"keys":{"type":"array","items":{"type":"string"}}}},"OtelMetricLabelValuesResponse":{"type":"object","required":["values"],"properties":{"values":{"type":"array","items":{"type":"string"}}}},"OtelMetricNamesResponse":{"type":"object","required":["names"],"properties":{"names":{"type":"array","items":{"type":"string"}}}},"OtelMetricsResponse":{"type":"object","required":["data","count"],"properties":{"count":{"type":"integer","minimum":0},"data":{"type":"array","items":{"$ref":"#/components/schemas/MetricBucket"}}}},"OutlierAlgorithm":{"type":"string","description":"Outlier detection algorithm.","enum":["dbscan","scaled_dbscan","mad","scaled_mad"]},"OutlierParams":{"type":"object","description":"Outlier (cross-series population) detector parameters (stub — not evaluated).","required":["peer_group_key"],"properties":{"algorithm":{"$ref":"#/components/schemas/OutlierAlgorithm"},"peer_group_key":{"type":"string","description":"Label key defining the peer population compared across series (e.g. `host`)."},"tolerance":{"type":"number","format":"double","description":"Sensitivity; higher tolerates larger spread before flagging."}}},"OverprovisioningAssessment":{"type":"object","description":"Requests-vs-capacity-vs-usage assessment","required":["verdict","explanation"],"properties":{"cpu_request_inflation_ratio":{"type":["number","null"],"format":"double","description":"Ratio of requested CPU to measured CPU usage (e.g. 40.0 = requests\nreserve 40× what the workloads actually use). `None` without metrics."},"cpu_requested_pct":{"type":["number","null"],"format":"double","description":"Requested CPU as % of cluster capacity"},"cpu_utilization_pct":{"type":["number","null"],"format":"double","description":"Measured CPU usage as % of cluster capacity (`None` without metrics)"},"explanation":{"type":"string","description":"Human-readable explanation of the verdict, e.g. \"Cluster capacity is\n8 vCPU but measured usage is 0.3 vCPU (3.7%) — severely overprovisioned\""},"memory_request_inflation_ratio":{"type":["number","null"],"format":"double","description":"Ratio of requested memory to measured memory usage"},"memory_requested_pct":{"type":["number","null"],"format":"double","description":"Requested memory as % of cluster capacity"},"memory_utilization_pct":{"type":["number","null"],"format":"double","description":"Measured memory usage as % of cluster capacity (`None` without metrics)"},"verdict":{"$ref":"#/components/schemas/OverprovisioningVerdict","description":"Overall verdict"}}},"OverprovisioningVerdict":{"type":"string","description":"Overall overprovisioning verdict","enum":["severe","moderate","reasonable","unknown"]},"PageActivityBucket":{"type":"object","description":"Time bucket data point for page activity graph","required":["timestamp","visitors","page_views","avg_time_seconds"],"properties":{"avg_time_seconds":{"type":"number","format":"double","description":"Average time on page in seconds"},"page_views":{"type":"integer","format":"int64","description":"Number of page views in this bucket"},"timestamp":{"type":"string","description":"Timestamp for this bucket (ISO 8601)"},"visitors":{"type":"integer","format":"int64","description":"Number of unique visitors in this bucket"}}},"PageCountryStats":{"type":"object","description":"Geographic distribution of visitors for a page","required":["country","visitors","page_views","percentage"],"properties":{"country":{"type":"string","description":"Country name"},"country_code":{"type":["string","null"],"description":"ISO country code (2-letter)"},"page_views":{"type":"integer","format":"int64","description":"Number of page views from this country"},"percentage":{"type":"number","format":"double","description":"Percentage of total visitors"},"visitors":{"type":"integer","format":"int64","description":"Number of unique visitors from this country"}}},"PageFlowEntry":{"type":"object","description":"A single page with its entry/exit/bounce statistics","required":["page_path","entry_count","exit_count","bounce_count","total_views","entry_rate","exit_rate","bounce_rate"],"properties":{"avg_time_on_page":{"type":["number","null"],"format":"double","description":"Average time spent on this page in seconds"},"bounce_count":{"type":"integer","format":"int64","description":"Number of times visitors bounced on this page"},"bounce_rate":{"type":"number","format":"double","description":"Bounce rate: bounce_count / entry_count (only meaningful for entry pages)"},"entry_count":{"type":"integer","format":"int64","description":"Number of times this page was the entry page of a session"},"entry_rate":{"type":"number","format":"double","description":"Entry rate: entry_count / total_views"},"exit_count":{"type":"integer","format":"int64","description":"Number of times this page was the exit page of a session"},"exit_rate":{"type":"number","format":"double","description":"Exit rate: exit_count / total_views"},"page_path":{"type":"string","description":"The page path (e.g. \"/pricing\", \"/docs/getting-started\")"},"total_views":{"type":"integer","format":"int64","description":"Total page views for this page"}}},"PageFlowQuery":{"type":"object","description":"Query parameters for page flow analytics","required":["project_id","start_date","end_date"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32","description":"Maximum number of entry/exit pages to return (default: 20)"},"min_views_for_dropoff":{"type":["integer","null"],"format":"int32","description":"Minimum views for drop-off analysis (default: 5)"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"},"transitions_limit":{"type":["integer","null"],"format":"int32","description":"Maximum number of transitions to return (default: 50)"}}},"PageFlowResponse":{"type":"object","description":"Complete page flow analytics response","required":["top_entry_pages","top_exit_pages","drop_off_points","transitions","total_pages","total_sessions"],"properties":{"drop_off_points":{"type":"array","items":{"$ref":"#/components/schemas/DropOffPoint"},"description":"Top drop-off points (highest exit rates with meaningful traffic)"},"top_entry_pages":{"type":"array","items":{"$ref":"#/components/schemas/PageFlowEntry"},"description":"Top entry pages (where visitors land), sorted by entry_count DESC"},"top_exit_pages":{"type":"array","items":{"$ref":"#/components/schemas/PageFlowEntry"},"description":"Top exit pages (where visitors leave), sorted by exit_count DESC"},"total_pages":{"type":"integer","format":"int64","description":"Total unique pages seen in the period"},"total_sessions":{"type":"integer","format":"int64","description":"Total sessions in the period"},"transitions":{"type":"array","items":{"$ref":"#/components/schemas/PageTransition"},"description":"Page-to-page transitions (most common navigation paths)"}}},"PageHourlySessionsQuery":{"type":"object","description":"Query parameters for page hourly sessions endpoint","required":["page_path","project_id","start_time","end_time"],"properties":{"bucket_interval":{"type":["string","null"]},"end_time":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"page_path":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"start_time":{"type":"string","format":"date-time"}}},"PageHourlySessionsResponse":{"type":"object","required":["page_path","hourly_data","total_sessions","hours"],"properties":{"hourly_data":{"type":"array","items":{"$ref":"#/components/schemas/HourlyPageSessions"}},"hours":{"type":"integer","format":"int32"},"page_path":{"type":"string"},"total_sessions":{"type":"integer","format":"int64"}}},"PagePathDetailQuery":{"type":"object","description":"Query parameters for page path detail analytics","required":["page_path","project_id","start_date","end_date"],"properties":{"bucket_interval":{"type":["string","null"],"description":"Bucket interval for time series: 'hour', 'day', 'week', 'month' (default: auto)"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"page_path":{"type":"string","description":"The specific page path to get details for (URL-encoded)"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"PagePathDetailResponse":{"type":"object","description":"Detailed analytics response for a specific page path","required":["page_path","unique_visitors","total_page_views","avg_time_on_page","bounce_rate","entry_rate","exit_rate","activity_over_time","countries","referrers","bucket_interval"],"properties":{"activity_over_time":{"type":"array","items":{"$ref":"#/components/schemas/PageActivityBucket"},"description":"Time series data for activity graph"},"avg_time_on_page":{"type":"number","format":"double","description":"Average time on page in seconds"},"bounce_rate":{"type":"number","format":"double","description":"Bounce rate percentage (0-100)"},"bucket_interval":{"type":"string","description":"Bucket interval used for time series ('hour', 'day', etc.)"},"countries":{"type":"array","items":{"$ref":"#/components/schemas/PageCountryStats"},"description":"Geographic distribution of visitors"},"entry_rate":{"type":"number","format":"double","description":"Entry rate - percentage of sessions that started on this page"},"exit_rate":{"type":"number","format":"double","description":"Exit rate - percentage of sessions that ended on this page"},"page_path":{"type":"string","description":"The page path being analyzed"},"referrers":{"type":"array","items":{"$ref":"#/components/schemas/PageReferrerStats"},"description":"Top referrers to this page"},"total_page_views":{"type":"integer","format":"int64","description":"Total page views in the date range"},"unique_visitors":{"type":"integer","format":"int64","description":"Total unique visitors to this page in the date range"}}},"PagePathInfo":{"type":"object","required":["page_path","session_count","page_view_count","first_seen","last_seen"],"properties":{"avg_time_seconds":{"type":["number","null"],"format":"double"},"first_seen":{"type":"string"},"last_seen":{"type":"string"},"page_path":{"type":"string"},"page_view_count":{"type":"integer","format":"int64"},"session_count":{"type":"integer","format":"int64"}}},"PagePathSparkline":{"type":"object","required":["page_path","points"],"properties":{"page_path":{"type":"string"},"points":{"type":"array","items":{"$ref":"#/components/schemas/PagePathSparklinePoint"}}}},"PagePathSparklinePoint":{"type":"object","required":["timestamp","session_count"],"properties":{"session_count":{"type":"integer","format":"int64"},"timestamp":{"type":"string"}}},"PagePathVisitorsQuery":{"type":"object","description":"Query parameters for page path visitors","required":["page_path","project_id","start_date","end_date"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"page":{"type":["integer","null"],"format":"int64","description":"Page number (1-based, default: 1)","minimum":0},"page_path":{"type":"string","description":"The specific page path to get visitors for"},"per_page":{"type":["integer","null"],"format":"int64","description":"Items per page (default: 50, max: 100)","minimum":0},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"PagePathVisitorsResponse":{"type":"object","description":"Response for page path visitors endpoint","required":["page_path","total_count","page","per_page","sessions"],"properties":{"page":{"type":"integer","format":"int64","description":"Current page number","minimum":0},"page_path":{"type":"string","description":"The page path"},"per_page":{"type":"integer","format":"int64","description":"Items per page","minimum":0},"sessions":{"type":"array","items":{"$ref":"#/components/schemas/PageVisitorSession"},"description":"Individual visitor sessions"},"total_count":{"type":"integer","format":"int64","description":"Total number of visitor sessions matching the query"}}},"PagePathsQuery":{"type":"object","required":["project_id"],"properties":{"end_date":{"type":["string","null"],"format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":["string","null"],"format":"date-time"}}},"PagePathsResponse":{"type":"object","required":["page_paths","total_count"],"properties":{"page_paths":{"type":"array","items":{"$ref":"#/components/schemas/PagePathInfo"}},"total_count":{"type":"integer","minimum":0}}},"PagePathsSparklineQuery":{"type":"object","description":"Query parameters for batch page paths sparkline endpoint","required":["project_id","start_time","end_time","page_paths"],"properties":{"end_time":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"page_paths":{"type":"string","description":"Comma-separated list of page paths"},"project_id":{"type":"integer","format":"int32"},"start_time":{"type":"string","format":"date-time"}}},"PagePathsSparklineResponse":{"type":"object","required":["sparklines"],"properties":{"sparklines":{"type":"array","items":{"$ref":"#/components/schemas/PagePathSparkline"}}}},"PageReferrerStats":{"type":"object","description":"Referrer source for the page","required":["referrer","visits","percentage"],"properties":{"percentage":{"type":"number","format":"double","description":"Percentage of total visits"},"referrer":{"type":"string","description":"Referrer URL or domain"},"visits":{"type":"integer","format":"int64","description":"Number of visits from this referrer"}}},"PageSessionComparison":{"type":"object","required":["page_path","date","session_count","event_count","avg_duration_seconds"],"properties":{"avg_duration_seconds":{"type":"number","format":"double"},"date":{"type":"string"},"event_count":{"type":"integer","format":"int64"},"page_path":{"type":"string"},"session_count":{"type":"integer","format":"int64"}}},"PageSessionStats":{"type":"object","required":["page_path","total_sessions","avg_time_seconds","min_time_seconds","max_time_seconds","total_page_views","avg_page_views_per_session"],"properties":{"avg_page_views_per_session":{"type":"number","format":"double"},"avg_time_seconds":{"type":"number","format":"double"},"max_time_seconds":{"type":"number","format":"double"},"min_time_seconds":{"type":"number","format":"double"},"page_path":{"type":"string"},"total_page_views":{"type":"integer","format":"int64"},"total_sessions":{"type":"integer","format":"int64"}}},"PageSessionStatsQuery":{"type":"object","required":["page_path","project_id","start_date","end_date"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"page_path":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"PageTransition":{"type":"object","description":"A page-to-page transition with count","required":["from_page","to_page","transition_count","percentage"],"properties":{"from_page":{"type":"string","description":"The source page path"},"percentage":{"type":"number","format":"double","description":"Percentage of transitions from the source page that go to this destination"},"to_page":{"type":"string","description":"The destination page path"},"transition_count":{"type":"integer","format":"int64","description":"Number of times this transition occurred"}}},"PageVisit":{"type":"object","required":["path","visits"],"properties":{"path":{"type":"string"},"visits":{"type":"integer","format":"int64"}}},"PageVisitorSession":{"type":"object","description":"Individual visitor session that viewed a specific page","required":["visitor_id","visitor_uuid","viewed_at","is_entry","is_exit","is_bounce"],"properties":{"browser":{"type":["string","null"],"description":"Browser name"},"city":{"type":["string","null"],"description":"Visitor's city"},"country":{"type":["string","null"],"description":"Visitor's country"},"country_code":{"type":["string","null"],"description":"Visitor's country code"},"device_type":{"type":["string","null"],"description":"Device type (Desktop, Mobile, Tablet)"},"is_bounce":{"type":"boolean","description":"Whether this was a bounce"},"is_entry":{"type":"boolean","description":"Whether this was the entry page for the session"},"is_exit":{"type":"boolean","description":"Whether this was the exit page for the session"},"operating_system":{"type":["string","null"],"description":"Operating system"},"referrer":{"type":["string","null"],"description":"Referrer URL"},"session_id":{"type":["string","null"],"description":"Session ID"},"session_page_number":{"type":["integer","null"],"format":"int32","description":"Page number in session flow"},"time_on_page":{"type":["integer","null"],"format":"int32","description":"Time spent on this page in seconds"},"viewed_at":{"type":"string","format":"date-time","description":"When the page was viewed"},"visitor_id":{"type":"integer","format":"int32","description":"Visitor numeric ID"},"visitor_uuid":{"type":"string","description":"Visitor UUID"}}},"PagesComparisonResponse":{"type":"object","required":["comparisons","page_paths"],"properties":{"comparisons":{"type":"array","items":{"$ref":"#/components/schemas/PageSessionComparison"}},"page_paths":{"type":"array","items":{"type":"string"}}}},"PaginatedEmailsResponse":{"type":"object","required":["data","total","page","page_size"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/EmailResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"PaginatedEntitiesResponse":{"type":"object","required":["entities","count","limit","has_more"],"properties":{"count":{"type":"integer","description":"Number of entities returned","minimum":0},"entities":{"type":"array","items":{"$ref":"#/components/schemas/EntityResponse"},"description":"List of entities"},"has_more":{"type":"boolean","description":"Whether there are more entities available"},"limit":{"type":"integer","description":"Limit used for this request","minimum":0},"next_token":{"type":["string","null"],"description":"Continuation token for next page (S3, etc.)"},"total":{"type":["integer","null"],"description":"Total number of entities (if available)","minimum":0}}},"PaginatedErrorEventsResponse":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ErrorEventResponse"}},"pagination":{"$ref":"#/components/schemas/PaginationMeta"}}},"PaginatedErrorGroupsResponse":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ErrorGroupResponse"}},"pagination":{"$ref":"#/components/schemas/PaginationMeta"}}},"PaginatedEventsResponse":{"type":"object","required":["events","total","page","page_size"],"properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/TrackingEventResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"PaginatedExternalImagesResponse":{"type":"object","required":["data","total","page","page_size"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ExternalImageResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"PaginatedProjectList":{"type":"object","required":["projects","total","page","per_page"],"properties":{"page":{"type":"integer","format":"int64"},"per_page":{"type":"integer","format":"int64"},"projects":{"type":"array","items":{"$ref":"#/components/schemas/ProjectResponse"}},"total":{"type":"integer","format":"int64"}}},"PaginatedStaticBundlesResponse":{"type":"object","required":["data","total","page","page_size"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/StaticBundleResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"Pagination":{"type":"object","description":"SDK pagination cursor. We use opaque page numbers internally but\nexpose `count`/`next`/`prev` the way `@vercel/sandbox` expects.","required":["count"],"properties":{"count":{"type":"integer","format":"int64","minimum":0},"next":{"type":["integer","null"],"format":"int64","minimum":0},"prev":{"type":["integer","null"],"format":"int64","minimum":0}}},"PaginationMeta":{"type":"object","required":["page","page_size","total_count","total_pages"],"properties":{"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total_count":{"type":"integer","format":"int64","minimum":0},"total_pages":{"type":"integer","format":"int64","minimum":0}}},"PaginationParams":{"type":"object","properties":{"page":{"type":"integer","format":"int64"},"per_page":{"type":"integer","format":"int64"}}},"PasswordProtectionConfig":{"type":"object","description":"Password protection configuration\n\nWhen enabled, the proxy shows an HTML password form before allowing access.\nAfter the user enters the correct password, an HMAC-signed cookie is set\nso subsequent requests pass through without re-entering the password.","required":["enabled","passwordHash"],"properties":{"enabled":{"type":"boolean","description":"Whether password protection is enabled"},"passwordHash":{"type":"string","description":"The bcrypt-hashed password (never stored or returned in plaintext)"}}},"PatchSettingsRequest":{"type":"object","properties":{"auto_upgrade":{"type":["boolean","null"]},"host_port":{"type":["integer","null"],"format":"int32","minimum":0},"image":{"type":["string","null"]}}},"PathVisitors":{"type":"object","required":["name","visitors","percentage"],"properties":{"name":{"type":"string"},"percentage":{"type":"number","format":"double"},"visitors":{"type":"integer","format":"int64"}}},"PathVisitorsAnalyticsQuery":{"type":"object","required":["start_date","end_date","project_id"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"PathVisitorsResponse":{"type":"object","required":["results"],"properties":{"results":{"type":"array","items":{"$ref":"#/components/schemas/PathVisitors"}}}},"PeerEntry":{"type":"object","description":"Wire-format peer entry. Matches `temps_network::config::Peer` but\nuses strings on the wire to keep the API stable across underlying\ntype evolution.","required":["node_id","compute_cidr","underlay_address"],"properties":{"compute_cidr":{"type":"string","description":"Per-node CIDR (e.g. `\"172.20.5.0/24\"`)."},"node_id":{"type":"string","description":"Stable v5 UUID derived from the database node id. Workers use\nthis as the kernel-layer identifier when calling\n`NetworkManager::reconcile_peers`."},"underlay_address":{"type":"string","description":"Address the local node should use to reach this peer over the\nunderlay (private VPC IP for same-DC, public IP for cross-DC)."}}},"PeerListResponse":{"type":"object","description":"Response body for `GET /internal/nodes/{node_id}/network/peers`.","required":["peers","cluster_dns_enabled"],"properties":{"alloc":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AllocEntry","description":"Caller's own allocation, or `null` if multi-host networking has\nnot been enabled for this node yet."}]},"cluster_dns_enabled":{"type":"boolean","description":"Whether the cluster-DNS resolver is enabled on this control plane\n(`AppSettings.cluster_dns.enabled`). Workers should start their\nper-node resolver and write `overlay_bridge_address` only when this\nis `true`. Always serialized (never `skip_serializing_if`) so older\nand newer version skew degrades to the safe default of `false`."},"peers":{"type":"array","items":{"$ref":"#/components/schemas/PeerEntry"},"description":"All other nodes with a `compute_cidr` set, excluding the caller."}}},"PendingActionResponse":{"type":"object","description":"A proposed AI write action awaiting human confirmation.","required":["public_id","operation_id","method","summary","status","step_index","params","created_at"],"properties":{"confirmed_at":{"type":["string","null"]},"created_at":{"type":"string"},"error":{"type":["string","null"]},"executed_at":{"type":["string","null"]},"method":{"type":"string"},"operation_id":{"type":"string"},"params":{"description":"The flat params to be replayed at execute time (shown pre-execution for review)."},"plan_public_id":{"type":["string","null"],"description":"Set when this action is one step of a multi-step plan (chained actions);\nall steps of the plan share this id. Absent for standalone single actions."},"public_id":{"type":"string"},"required_permission":{"type":["string","null"]},"result":{},"status":{"type":"string"},"step_index":{"type":"integer","format":"int32","description":"0-based order of this step within its plan (0 for standalone actions)."},"summary":{"type":"string"}}},"PerformanceMetricsQuery":{"allOf":[{"$ref":"#/components/schemas/SpeedSegmentFilters","description":"Segment filters (filter_path, filter_country, filter_region,\nfilter_city, filter_browser, filter_operating_system) — flattened so\neach remains a top-level query string param."},{"type":"object","required":["start_date","end_date","project_id"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"device_type":{"type":["string","null"],"description":"Device type filter: \"desktop\" or \"mobile\""},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"include_bots":{"type":["boolean","null"],"description":"Include crawler/datacenter (bot) samples. Defaults to false — bots\nare excluded from the read view but always stored at ingest."},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}}]},"PerformanceMetricsResponse":{"type":"object","properties":{"cls":{"type":["number","null"],"format":"float"},"cls_p75":{"type":["number","null"],"format":"float"},"cls_p90":{"type":["number","null"],"format":"float"},"cls_p95":{"type":["number","null"],"format":"float"},"cls_p99":{"type":["number","null"],"format":"float"},"fcp":{"type":["number","null"],"format":"float"},"fcp_p75":{"type":["number","null"],"format":"float"},"fcp_p90":{"type":["number","null"],"format":"float"},"fcp_p95":{"type":["number","null"],"format":"float"},"fcp_p99":{"type":["number","null"],"format":"float"},"fid":{"type":["number","null"],"format":"float"},"fid_p75":{"type":["number","null"],"format":"float"},"fid_p90":{"type":["number","null"],"format":"float"},"fid_p95":{"type":["number","null"],"format":"float"},"fid_p99":{"type":["number","null"],"format":"float"},"inp":{"type":["number","null"],"format":"float"},"inp_p75":{"type":["number","null"],"format":"float"},"inp_p90":{"type":["number","null"],"format":"float"},"inp_p95":{"type":["number","null"],"format":"float"},"inp_p99":{"type":["number","null"],"format":"float"},"lcp":{"type":["number","null"],"format":"float"},"lcp_p75":{"type":["number","null"],"format":"float"},"lcp_p90":{"type":["number","null"],"format":"float"},"lcp_p95":{"type":["number","null"],"format":"float"},"lcp_p99":{"type":["number","null"],"format":"float"},"ttfb":{"type":["number","null"],"format":"float"},"ttfb_p75":{"type":["number","null"],"format":"float"},"ttfb_p90":{"type":["number","null"],"format":"float"},"ttfb_p95":{"type":["number","null"],"format":"float"},"ttfb_p99":{"type":["number","null"],"format":"float"}}},"PermissionInfo":{"type":"object","description":"Information about a single permission","required":["name","description","category"],"properties":{"category":{"type":"string","description":"Category of the permission (e.g., \"Projects\", \"Deployments\")"},"description":{"type":"string","description":"Human-readable description of the permission"},"name":{"type":"string","description":"The permission identifier (e.g., \"projects:read\")"}}},"PgUpgradeLogResponse":{"type":"object","required":["log_id","content"],"properties":{"content":{"type":"string"},"log_id":{"type":"string"}}},"PgUpgradeResponse":{"type":"object","required":["id","service_id","from_version","to_version","from_image","to_image","status","phase","log_id","attempt","created_at"],"properties":{"attempt":{"type":"integer","format":"int32"},"created_at":{"type":"string"},"error_message":{"type":["string","null"]},"finished_at":{"type":["string","null"]},"from_image":{"type":"string"},"from_version":{"type":"string"},"id":{"type":"integer","format":"int32"},"log_id":{"type":"string"},"phase":{"type":"string"},"pre_upgrade_backup_id":{"type":["integer","null"],"format":"int32"},"rollback_volume_name":{"type":["string","null"]},"service_id":{"type":"integer","format":"int32"},"started_at":{"type":["string","null"]},"status":{"type":"string"},"to_image":{"type":"string"},"to_version":{"type":"string"}}},"PipelineStats":{"type":"object","description":"Internal pipeline statistics for self-observability.","required":["metrics_received","metrics_stored","metrics_dropped","spans_received","spans_stored","spans_dropped","logs_received","logs_stored_db","logs_stored_s3","logs_dropped","ingest_errors"],"properties":{"ingest_errors":{"type":"integer","format":"int64","minimum":0},"logs_dropped":{"type":"integer","format":"int64","minimum":0},"logs_received":{"type":"integer","format":"int64","minimum":0},"logs_stored_db":{"type":"integer","format":"int64","minimum":0},"logs_stored_s3":{"type":"integer","format":"int64","minimum":0},"metrics_dropped":{"type":"integer","format":"int64","minimum":0},"metrics_received":{"type":"integer","format":"int64","minimum":0},"metrics_stored":{"type":"integer","format":"int64","minimum":0},"spans_dropped":{"type":"integer","format":"int64","minimum":0},"spans_received":{"type":"integer","format":"int64","minimum":0},"spans_stored":{"type":"integer","format":"int64","minimum":0}}},"PipelineStatsResponse":{"type":"object","required":["stats"],"properties":{"stats":{"$ref":"#/components/schemas/PipelineStats"}}},"PlanComplexity":{"type":"string","description":"Plan complexity indicator","enum":["low","medium","high"]},"PlanMetadata":{"type":"object","description":"Plan metadata","required":["generated_at","generator_version","complexity","warnings"],"properties":{"complexity":{"$ref":"#/components/schemas/PlanComplexity","description":"Estimated complexity (low, medium, high)"},"generated_at":{"type":"string","format":"date-time","description":"When the plan was generated"},"generator_version":{"type":"string","description":"Generator (importer) version"},"warnings":{"type":"array","items":{"type":"string"},"description":"Warnings detected during planning"}}},"PlanSourceBackup":{"type":"object","required":["location","location_was_resolved","format"],"properties":{"created_at":{"type":["string","null"]},"format":{"type":"string","description":"\"walg\", \"pg_dump\", \"unknown\"."},"id":{"type":["integer","null"],"format":"int32","description":"DB id, absent for orphan (S3-scan) backups."},"location":{"type":"string","description":"Resolved S3 location the orchestrator will actually use."},"location_was_resolved":{"type":"boolean","description":"True when the original row's `s3_location` was empty and we resolved\na location by probing S3. The UI shows this as a warning."},"origin_service_name":{"type":["string","null"],"description":"Service that originally produced the backup, if known."},"size_bytes":{"type":["integer","null"],"format":"int64"}}},"PlanTarget":{"type":"object","required":["id","name","container"],"properties":{"container":{"type":"string","description":"Expected Docker container name."},"id":{"type":"integer","format":"int32"},"name":{"type":"string"}}},"PlatformInfo":{"type":"object","description":"Platform compatibility information","required":["os_type","architecture","platforms"],"properties":{"architecture":{"type":"string","description":"System architecture (e.g., \"x86_64\", \"aarch64\")"},"os_type":{"type":"string","description":"Operating system type (e.g., \"linux\", \"windows\", \"darwin\")"},"platforms":{"type":"array","items":{"type":"string"},"description":"List of supported platforms in \"os/arch\" format (e.g., [\"linux/amd64\"])"}}},"PluginManifest":{"type":"object","description":"The complete plugin manifest — the handshake contract.","required":["name","version"],"properties":{"description":{"type":["string","null"],"description":"Short description of what the plugin does"},"display_name":{"type":["string","null"],"description":"Human-readable display name"},"events":{"type":"array","items":{"type":"string"},"description":"Platform event types the plugin subscribes to.\n\nWhen specified, Temps will POST matching events to the plugin's\n`/_events` endpoint. Uses dot-notation event names matching the\nwebhook event types (e.g., \"deployment.succeeded\", \"project.created\").\n\nAvailable events:\n- `deployment.created`, `deployment.succeeded`, `deployment.failed`,\n `deployment.cancelled`, `deployment.ready`\n- `project.created`, `project.deleted`\n- `domain.created`, `domain.provisioned`"},"health_path":{"type":"string","description":"Health check endpoint path (relative to plugin root)"},"name":{"type":"string","description":"Unique plugin identifier (kebab-case, e.g., \"backup-manager\")"},"nav":{"type":"array","items":{"$ref":"#/components/schemas/NavEntry"},"description":"Navigation entries for the UI sidebar"},"requires_db":{"type":"boolean","description":"Whether the plugin needs database access"},"ui":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/UiManifest","description":"UI bundle manifest (if the plugin has a UI)"}]},"version":{"type":"string","description":"SemVer version string"}}},"PortMapping":{"type":"object","description":"Port mapping","required":["container_port","protocol","is_primary"],"properties":{"container_port":{"type":"integer","format":"int32","description":"Container port","minimum":0},"host_port":{"type":["integer","null"],"format":"int32","description":"Host port (optional - can be assigned dynamically)","minimum":0},"is_primary":{"type":"boolean","description":"Whether this is the primary HTTP port"},"protocol":{"$ref":"#/components/schemas/Protocol","description":"Protocol (tcp, udp)"}}},"PostgresWalHealth":{"type":"object","required":["probed_at","pg_wal_bytes","max_wal_size_bytes","archive_mode","archive_backlog","stale_slots","oldest_wal_age_secs","warnings"],"properties":{"archive_backlog":{"type":"integer","format":"int64","description":"Number of `archive_status/*.ready` files — un-shipped WAL segments."},"archive_command":{"type":["string","null"],"description":"The literal `archive_command` setting. May be empty or `/bin/true`\nwhen archiving is effectively disabled despite `archive_mode = on`."},"archive_mode":{"$ref":"#/components/schemas/ArchiveMode"},"archiver_failed_count":{"type":["integer","null"],"format":"int64"},"archiver_last_failed_at":{"type":["string","null"],"format":"date-time"},"max_wal_size_bytes":{"type":"integer","format":"int64","description":"`max_wal_size` setting in bytes (parsed from `pg_settings`)."},"oldest_wal_age_secs":{"type":"integer","format":"int64","description":"Age of the oldest WAL file in `pg_wal/` (seconds)."},"pg_wal_bytes":{"type":"integer","format":"int64","description":"Total size of files under `pg_wal/`, from `pg_ls_waldir()`."},"probed_at":{"type":"string","format":"date-time","description":"When the snapshot was taken."},"stale_slots":{"type":"array","items":{"$ref":"#/components/schemas/StaleSlot"}},"warnings":{"type":"array","items":{"$ref":"#/components/schemas/WalWarning"},"description":"Computed warnings, ordered by severity (critical first)."}}},"PresetConfigSchema":{"oneOf":[{"$ref":"#/components/schemas/DockerfilePresetConfig","description":"Configuration for Dockerfile preset"},{"$ref":"#/components/schemas/DockerComposePresetConfig","description":"Configuration for Docker Compose"},{"$ref":"#/components/schemas/NixpacksPresetConfig","description":"Configuration for Nixpacks provider selection and inline build plan"},{"$ref":"#/components/schemas/StaticPresetConfig","description":"Configuration for static site presets (Vite, Next.js, etc.)"}],"description":"Union type for preset configurations\nUse the appropriate configuration type based on your preset"},"PresetInfo":{"type":"object","description":"Detected preset information","required":["path","preset","preset_label","project_type"],"properties":{"compose_files":{"type":["array","null"],"items":{"type":"string"},"description":"Compose file paths found in the repository (only for docker-compose preset)"},"exposed_port":{"type":["integer","null"],"format":"int32","description":"Default exposed port for this preset"},"icon_url":{"type":["string","null"],"description":"Icon URL for this preset"},"path":{"type":"string","description":"Path where preset was detected (empty for root)"},"preset":{"type":"string","description":"Preset slug (e.g., \"nextjs\", \"fastapi\")"},"preset_label":{"type":"string","description":"Human-readable preset label"},"project_type":{"type":"string","description":"Project type (e.g., \"frontend\", \"backend\", \"fullstack\")"}}},"PresetResponse":{"type":"object","required":["slug","label","icon_url","project_type","description"],"properties":{"default_port":{"type":["integer","null"],"format":"int32","description":"Default port the application listens on (None for static sites)","example":3000,"minimum":0},"description":{"type":"string","description":"Description of what this preset does"},"icon_url":{"type":"string","description":"Icon URL for the preset"},"label":{"type":"string","description":"Display name/label for the preset"},"project_type":{"type":"string","description":"Project type (server or static)"},"slug":{"type":"string","description":"Unique identifier slug for the preset"}}},"PreviewGatewaySettings":{"type":"object","description":"Workspace preview gateway settings.\n\nThe preview gateway is a single shared Docker container that lives on the\n`temps-sandbox-net` network and routes requests to workspace sandbox dev\nservers based on the `Host` header (`ws--.`).\n`temps serve` reconciles this container on startup; these settings let an\noperator override the image, host port, and auto-upgrade behavior.","properties":{"auto_upgrade":{"type":"boolean","description":"When true (default), the supervisor will pull and apply the image\npinned in the Temps binary on every startup. When false, the\ncurrently-running image is left alone — operators upgrade manually\nfrom the settings UI.","default":true,"example":true},"host_port":{"type":"integer","format":"int32","description":"Host port to publish the gateway on (always bound to 127.0.0.1).\nPingora forwards `ws-*` traffic to this port after authenticating.","default":8090,"example":8090,"minimum":0},"image":{"type":"string","description":"Docker image reference for the gateway. Pinned per Temps release.\nOperators can override this to test a custom build.","default":"ghcr.io/gotempsh/temps-preview-gateway:latest","example":"ghcr.io/gotempsh/temps-preview-gateway:latest"},"shared_secret":{"type":"string","description":"Shared secret the host-side Pingora sends on every forwarded preview\nrequest via `X-Temps-Preview-Token`; the gateway rejects requests\nwithout it. Auto-generated on first boot, persisted in DB so the\nsecret is stable across `temps serve` restarts regardless of cwd,\n`TEMPS_DATA_DIR`, or data-dir changes. MUST be masked (`***`) in any\nAPI response — never expose it over HTTP.","default":"","example":""}}},"PreviewGatewaySettingsMasked":{"type":"object","description":"Preview gateway settings with `shared_secret` elided.","required":["image","host_port","auto_upgrade","shared_secret_set"],"properties":{"auto_upgrade":{"type":"boolean"},"host_port":{"type":"integer","format":"int32","minimum":0},"image":{"type":"string"},"shared_secret_set":{"type":"boolean"}}},"PreviewGatewaySettingsResponse":{"type":"object","required":["image","host_port","auto_upgrade","default_image","default_host_port"],"properties":{"auto_upgrade":{"type":"boolean"},"default_host_port":{"type":"integer","format":"int32","description":"The compile-time default host port.","minimum":0},"default_image":{"type":"string","description":"The compile-time default image — exposed so the UI can offer a\n\"Reset to default\" link without round-tripping."},"host_port":{"type":"integer","format":"int32","minimum":0},"image":{"type":"string"}}},"PreviewShareLinkBody":{"type":"object","description":"Request body for minting a preview share link.","required":["port"],"properties":{"path":{"type":["string","null"],"description":"Path the recipient lands on. Must be same-origin (start with a single\n`/`); anything else is replaced with `/` so a share link can never be\nturned into an open redirect."},"port":{"type":"integer","format":"int32","description":"Port inside the sandbox the preview serves on.","minimum":0},"ttl_seconds":{"type":["integer","null"],"format":"int64","description":"How long the link stays usable, in seconds. Clamped to 24 hours.\nDefaults to one hour — long enough to send to a reviewer, short enough\nthat a link pasted in a ticket does not stay live indefinitely.","minimum":0}}},"PreviewShareLinkResponse":{"type":"object","required":["url","expires_at"],"properties":{"expires_at":{"type":"integer","format":"int64","description":"Unix seconds after which the link stops working.","minimum":0},"url":{"type":"string","description":"The full link. Its fragment contains the grant and must be treated as a\ncredential; URL fragments are not sent to servers or in Referer headers."}}},"PricingResponse":{"type":"object","required":["models"],"properties":{"models":{"type":"array","items":{"$ref":"#/components/schemas/ModelPricing"}}}},"ProblemDetails":{"type":"object","description":"Representation of a Problem error to return to the client.\nFollows RFC 7807 - Problem Details for HTTP APIs","required":["title","extensions"],"properties":{"detail":{"type":["string","null"],"description":"A human-readable explanation specific to this occurrence of the problem","example":"The server encountered an unexpected condition"},"extensions":{"type":"object","description":"Additional properties of the problem","additionalProperties":true},"instance":{"type":["string","null"],"description":"A URI reference that identifies the specific occurrence of the problem","example":"/account/12345/msgs/abc"},"title":{"type":"string","description":"A short, human-readable summary of the problem type","example":"Internal Server Error"},"type":{"type":["string","null"],"description":"A URI reference that identifies the problem type","example":"https://example.com/probs/out-of-memory"}},"example":{"type":"https://example.com/probs/out-of-memory","title":"Internal Server Error","detail":"The server encountered an unexpected condition","instance":"/account/12345/msgs/abc","additional_info":"Custom field with additional details"}},"ProjectAccessResponse":{"type":"object","required":["id","project_id","team_id","role","granted_by","created_at","updated_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2026-07-30T12:15:47.609192Z"},"granted_by":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"project_id":{"type":"integer","format":"int32"},"role":{"$ref":"#/components/schemas/TeamRole"},"team_id":{"type":"integer","format":"int32"},"updated_at":{"type":"string","format":"date-time","example":"2026-07-30T12:15:47.609192Z"}}},"ProjectConfiguration":{"type":"object","description":"Project-level configuration","required":["name","slug","project_type","is_web_app"],"properties":{"is_web_app":{"type":"boolean","description":"Whether this is a web application"},"name":{"type":"string","description":"Proposed project name"},"project_type":{"$ref":"#/components/schemas/ProjectType","description":"Project type"},"slug":{"type":"string","description":"Proposed slug (URL-safe identifier)"}}},"ProjectDSNResponse":{"type":"object","required":["id","project_id","name","public_key","dsn","created_at","is_active","event_count"],"properties":{"created_at":{"type":"string"},"deployment_id":{"type":["integer","null"],"format":"int32"},"dsn":{"type":"string"},"environment_id":{"type":["integer","null"],"format":"int32"},"event_count":{"type":"integer","format":"int64"},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"public_key":{"type":"string"}}},"ProjectDashboardAnalytics":{"type":"object","description":"Analytics data for a single project in the dashboard batch response","required":["project_id","unique_visitors","previous_unique_visitors","hourly_visits"],"properties":{"hourly_visits":{"type":"array","items":{"$ref":"#/components/schemas/EventTimeline"},"description":"Hourly sparkline data points"},"previous_unique_visitors":{"type":"integer","format":"int64","description":"Unique visitor count in the previous period (same duration, shifted back)"},"project_id":{"type":"integer","format":"int32"},"trend_percentage":{"type":["number","null"],"format":"double","description":"Percentage change from previous period (positive = growth, negative = decline)\nNull when previous period had zero visitors (no baseline to compare)"},"unique_visitors":{"type":"integer","format":"int64","description":"Unique visitor count in the current time range"}}},"ProjectHealthSummary":{"type":"object","description":"Health summary for a single project (last 1 hour)","required":["project_id","total_requests","total_errors","avg_response_time_ms","error_rate","status"],"properties":{"avg_response_time_ms":{"type":"number","format":"double","description":"Average response time in ms"},"error_rate":{"type":"number","format":"double","description":"Error rate as a percentage (0-100)"},"project_id":{"type":"integer","format":"int32"},"status":{"type":"string","description":"Health status: \"healthy\", \"degraded\", \"down\", \"unknown\""},"total_errors":{"type":"integer","format":"int64","description":"Total server errors (status >= 500) in the period"},"total_requests":{"type":"integer","format":"int64","description":"Total requests in the period"}}},"ProjectInfo":{"type":"object","required":["id","slug","created_at"],"properties":{"created_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"id":{"type":"integer","format":"int32"},"slug":{"type":"string"}}},"ProjectMonitorHealth":{"type":"object","description":"Health summary for a single project based on its production monitors","required":["project_id","status"],"properties":{"project_id":{"type":"integer","format":"int32"},"status":{"type":"string","description":"Overall status: \"operational\", \"degraded\", \"down\", or \"no_monitors\""}}},"ProjectPresetResponse":{"type":"object","required":["path","preset","presetLabel","projectType"],"properties":{"composeFiles":{"type":["array","null"],"items":{"type":"string"},"description":"Compose file paths found in the repository (only for docker-compose preset)"},"exposedPort":{"type":["integer","null"],"format":"int32","description":"Default exposed port for this preset (e.g., 3000 for Next.js, 8000 for FastAPI)"},"iconUrl":{"type":["string","null"],"description":"Icon URL for the preset"},"path":{"type":"string"},"preset":{"type":"string"},"presetLabel":{"type":"string"},"projectType":{"type":"string","description":"Project type category (e.g., \"frontend\", \"backend\", \"fullstack\")"}}},"ProjectQuery":{"type":"object","required":["project_id"],"properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"}}},"ProjectRef":{"type":"object","description":"A lightweight project descriptor included in `UnifiedTrace`.","required":["project_id","project_name","project_slug"],"properties":{"project_id":{"type":"integer","format":"int32"},"project_name":{"type":"string"},"project_slug":{"type":"string","description":"URL slug used to link a span back into its owning project's trace view."}}},"ProjectResponse":{"type":"object","required":["id","slug","name","directory","main_branch","created_at","updated_at","deployment_config","attack_mode","ai_write_actions_enabled","error_source_context_enabled","enable_preview_environments","preview_envs_on_demand","preview_envs_idle_timeout_seconds","preview_envs_wake_timeout_seconds","source_type","cross_project_trace_sharing"],"properties":{"ai_alert_summaries_enabled":{"type":["boolean","null"],"description":"Opt-in to AI summarization of metric alert notifications (NULL/false = off)."},"ai_debug_chat_enabled":{"type":["boolean","null"],"description":"Opt-in to AI debugging chat, e.g. on deployment failures (NULL/false = off)."},"ai_write_actions_enabled":{"type":"boolean","description":"Opt-in to AI propose-then-confirm write capability (false = off)."},"attack_mode":{"type":"boolean","description":"Attack mode - when enabled, requires CAPTCHA verification for all project environments"},"created_at":{"type":"integer","format":"int64"},"cross_project_trace_sharing":{"type":"boolean","description":"ADR-027 Phase 3 opt-out: when false, this project's traces are suppressed\nfrom cross-project discovery results. Default true (consistent with the\nOSS global-observability model where any OtelRead holder can query any\nproject's telemetry)."},"deployment_config":{"$ref":"#/components/schemas/DeploymentConfig","description":"Deployment configuration (resources, autoscaling, features)"},"directory":{"type":"string"},"enable_preview_environments":{"type":"boolean","description":"Enable automatic preview environment creation for each branch"},"error_source_context_enabled":{"type":"boolean","description":"Opt-in to native error-tracking source context (false = off). When on,\nTemps stores uploaded source files and shows source code in stack traces."},"error_source_root":{"type":["string","null"],"description":"Where auto-capture reads source from (relative to the checkout). Null =\nthe deployment's Docker build context."},"git_provider_connection_id":{"type":["integer","null"],"format":"int32"},"git_url":{"type":["string","null"],"description":"Git clone URL for the repository (used for public repos without a provider connection)"},"gitlab_webhook_id":{"type":["integer","null"],"format":"int32","description":"GitLab webhook ID installed on the connected repository.\n`null` when no GitLab webhook is installed (not connected to GitLab,\nor webhook was removed / never created).","example":42},"id":{"type":"integer","format":"int32"},"last_deployment":{"type":["integer","null"],"format":"int64"},"main_branch":{"type":"string"},"name":{"type":"string"},"preset":{"type":["string","null"]},"preset_config":{"description":"Preset-specific configuration (Dockerfile path, build context, etc.)"},"preview_envs_idle_timeout_seconds":{"type":"integer","format":"int32","description":"Idle timeout (seconds) for on-demand preview environments."},"preview_envs_on_demand":{"type":"boolean","description":"When true, newly-created preview environments default to on-demand mode\n(containers stop after the configured idle timeout to save resources)."},"preview_envs_wake_timeout_seconds":{"type":"integer","format":"int32","description":"Wake timeout (seconds) for on-demand preview environments."},"repo_name":{"type":["string","null"]},"repo_owner":{"type":["string","null"]},"slug":{"type":"string"},"source_type":{"$ref":"#/components/schemas/SourceType","description":"Source type for deployments (git, docker_image, or static_files)"},"updated_at":{"type":"integer","format":"int64"}}},"ProjectSecretEnvironmentInfo":{"type":"object","required":["id","name","main_url"],"properties":{"id":{"type":"integer","format":"int32"},"main_url":{"type":"string"},"name":{"type":"string"}}},"ProjectSecretResponse":{"type":"object","description":"Project secret metadata. There is deliberately no `value` field — secret\nplaintext is never returned after creation. Callers that need the value\nmust read it from the mounted file inside the container.","required":["id","project_id","key","include_in_preview","created_at","updated_at","environments"],"properties":{"created_at":{"type":"integer","format":"int64"},"environments":{"type":"array","items":{"$ref":"#/components/schemas/ProjectSecretEnvironmentInfo"}},"id":{"type":"integer","format":"int32"},"include_in_preview":{"type":"boolean"},"key":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"updated_at":{"type":"integer","format":"int64"}}},"ProjectServiceInfo":{"type":"object","required":["id","project","service"],"properties":{"id":{"type":"integer","format":"int32"},"project":{"$ref":"#/components/schemas/ProjectInfo"},"service":{"$ref":"#/components/schemas/ExternalServiceInfo"}}},"ProjectStatisticsResponse":{"type":"object","required":["total_count"],"properties":{"total_count":{"type":"integer","format":"int64"}}},"ProjectStatsBreakdown":{"type":"object","required":["project_id","unique_visitors","total_visits","total_page_views","bounce_rate","engagement_rate"],"properties":{"bounce_rate":{"type":"number","format":"double"},"engagement_rate":{"type":"number","format":"double"},"project_id":{"type":"integer","format":"int32"},"project_name":{"type":["string","null"]},"total_page_views":{"type":"integer","format":"int64"},"total_visits":{"type":"integer","format":"int64"},"unique_visitors":{"type":"integer","format":"int64"}}},"ProjectType":{"type":"string","description":"Project type enumeration","enum":["static","docker","buildpack","git"]},"ProjectUsageInfoResponse":{"type":"object","required":["id","name","slug","connection_id","connection_name"],"properties":{"connection_id":{"type":"integer","format":"int32"},"connection_name":{"type":"string"},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"slug":{"type":"string"}}},"ProjectsHealthResponse":{"type":"object","description":"Batch health summary response","required":["projects"],"properties":{"projects":{"type":"object","description":"Health summaries keyed by project ID","additionalProperties":{"$ref":"#/components/schemas/ProjectHealthSummary"},"propertyNames":{"type":"string"}}}},"ProjectsMonitorHealthResponse":{"type":"object","description":"Batch response for projects health","required":["projects"],"properties":{"projects":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/ProjectMonitorHealth"},"propertyNames":{"type":"string"}}}},"PromoteDeploymentRequest":{"type":"object","required":["target_environment_id"],"properties":{"target_environment_id":{"type":"integer","format":"int32","description":"Target environment ID to promote the deployment to"}}},"PropertyBreakdownItem":{"type":"object","required":["value","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"percentage":{"type":"number","format":"double"},"value":{"type":"string"}}},"PropertyBreakdownQuery":{"type":"object","description":"Query parameters for property breakdown (group by column)","required":["start_date","end_date","group_by"],"properties":{"aggregation_level":{"$ref":"#/components/schemas/AggregationLevel","description":"Aggregation level"},"deployment_id":{"type":["integer","null"],"format":"int32","description":"Optional deployment filter"},"end_date":{"type":"string","format":"date-time","description":"End date for the query range"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Optional environment filter"},"event_name":{"type":["string","null"],"description":"Optional event name filter (e.g., \"page_view\", \"click\")"},"filter_browser":{"type":["string","null"],"description":"Filter by browser name (for browser version drill-downs)"},"filter_channel":{"type":["string","null"],"description":"Filter by channel name (for channel -> referrer drill-downs)"},"filter_country":{"type":["string","null"],"description":"Filter by country (for region/city drill-downs). Requires geolocation join."},"filter_os":{"type":["string","null"],"description":"Filter by operating system name (for OS version drill-downs)"},"filter_referrer":{"type":["string","null"],"description":"Filter by referrer hostname (for referrer -> pages drill-downs)"},"filter_region":{"type":["string","null"],"description":"Filter by region (for city drill-downs). Requires geolocation join."},"group_by":{"$ref":"#/components/schemas/PropertyColumn","description":"Property column to group by"},"include_crawlers":{"type":["boolean","null"],"description":"Include crawler/bot traffic (default: false). Off by default so the\nbreakdown percentages share a denominator with the headline counts,\nwhich always exclude crawlers."},"limit":{"type":["integer","null"],"format":"int32","description":"Maximum number of results to return (default: 20, max: 100)"},"start_date":{"type":"string","format":"date-time","description":"Start date for the query range"}}},"PropertyBreakdownResponse":{"type":"object","required":["property","items","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/PropertyBreakdownItem"}},"property":{"type":"string"},"total":{"type":"integer","format":"int64"}}},"PropertyColumn":{"type":"string","enum":["channel","device_type","browser","browser_version","operating_system","operating_system_version","utm_source","utm_medium","utm_campaign","utm_term","utm_content","referrer_hostname","language","event_type","event_name","page_path","pathname","country","region","city"]},"PropertyTimelineItem":{"type":"object","required":["timestamp","value","count"],"properties":{"count":{"type":"integer","format":"int64"},"timestamp":{"type":"string"},"value":{"type":"string"}}},"PropertyTimelineQuery":{"type":"object","description":"Query parameters for property timeline (group by column over time)","required":["start_date","end_date","group_by"],"properties":{"aggregation_level":{"$ref":"#/components/schemas/AggregationLevel","description":"Aggregation level"},"bucket_size":{"type":["string","null"],"description":"Time bucket size: \"hour\", \"day\", \"week\", \"month\" (default: auto-detect)"},"deployment_id":{"type":["integer","null"],"format":"int32","description":"Optional deployment filter"},"end_date":{"type":"string","format":"date-time","description":"End date for the query range"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Optional environment filter"},"event_name":{"type":["string","null"],"description":"Optional event name filter"},"group_by":{"$ref":"#/components/schemas/PropertyColumn","description":"Property column to group by"},"include_crawlers":{"type":["boolean","null"],"description":"Include crawler/bot traffic (default: false). See\n[`PropertyBreakdownQuery::include_crawlers`]."},"start_date":{"type":"string","format":"date-time","description":"Start date for the query range"}}},"PropertyTimelineResponse":{"type":"object","required":["property","bucket_size","items"],"properties":{"bucket_size":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/PropertyTimelineItem"}},"property":{"type":"string"}}},"Protocol":{"type":"string","description":"Network protocol","enum":["tcp","udp"]},"ProviderCatalogDto":{"type":"object","description":"One catalog entry rendered for the settings UI.","required":["id","name","install_command","auth_command","auth_flavors","models","credential_saved","supports_max_turns"],"properties":{"auth_command":{"type":"string"},"auth_flavors":{"type":"array","items":{"$ref":"#/components/schemas/AuthFlavorDto"}},"credential_saved":{"type":"boolean","description":"True when a credential is currently saved for this provider in the\nsettings JSON. Lets the UI render \"Configured\" badges without the\nfrontend having to inspect the encrypted blob."},"current_auth_type":{"type":["string","null"],"description":"Currently saved auth flavor id (when `credential_saved` is true).\n`None` when no credential is saved yet."},"default_model":{"type":["string","null"],"description":"Currently saved default model id for this provider, if one was\npicked. `None` means \"use the CLI's own default\" — the UI renders\nthat as \"Use provider default\"."},"id":{"type":"string"},"install_command":{"type":"string"},"max_turns_analysis":{"type":["integer","null"],"format":"int32","description":"Default max turns for the autofixer analysis phase. `None` = built-in\ndefault (10). Only enforced for CLIs with a turn flag (Claude Code)."},"max_turns_feedback":{"type":["integer","null"],"format":"int32","description":"Default max turns for autofixer feedback rounds. `None` = built-in\ndefault (10)."},"max_turns_fix":{"type":["integer","null"],"format":"int32","description":"Default max turns for the autofixer fix phase. `None` = built-in\ndefault (20)."},"models":{"type":"array","items":{"type":"string"},"description":"Model ids this provider accepts, in display order. The first entry is\nthe recommended default. Empty when the provider doesn't expose model\nselection (e.g. OpenCode), which the UI uses to hide the dropdown."},"name":{"type":"string"},"supports_max_turns":{"type":"boolean","description":"True when this provider's CLI supports enforcing a turn cap. False\nfor Codex/OpenCode, which run to completion — the UI labels their\nmax-turns inputs accordingly."}}},"ProviderCatalogResponse":{"type":"object","required":["default_provider","providers"],"properties":{"default_provider":{"type":"string","description":"Active provider id from `agent_sandbox.default_provider`. The settings\nUI uses this to highlight which card is the active one."},"providers":{"type":"array","items":{"$ref":"#/components/schemas/ProviderCatalogDto"}}}},"ProviderConfig":{"oneOf":[{"allOf":[{"$ref":"#/components/schemas/StripeConfig"},{"type":"object","required":["provider"],"properties":{"provider":{"type":"string","enum":["stripe"]}}}]},{"allOf":[{"$ref":"#/components/schemas/LemonSqueezyConfig"},{"type":"object","required":["provider"],"properties":{"provider":{"type":"string","enum":["lemon_squeezy"]}}}]}],"description":"Provider-specific integration settings persisted in\n`revenue_integrations.config`.\n\nThe tag is the lowercase provider name, so adding a new provider\nmeans adding a new variant and the existing rows are untouched.\nOld rows (pre-config) and rows with `NULL` config are treated as\n\"accept all events, no filtering\" via [`ProviderConfig::default_for`]."},"ProviderConfigMasked":{"type":"object","required":["auth_type","credential_saved","extra"],"properties":{"auth_type":{"type":"string"},"credential_saved":{"type":"boolean","description":"True if a credential is stored for this provider. The encrypted blob\nis never returned over HTTP."},"default_model":{"type":["string","null"]},"extra":{}}},"ProviderDeletionCheckResponse":{"type":"object","required":["can_delete","projects_in_use","message"],"properties":{"can_delete":{"type":"boolean"},"message":{"type":"string"},"projects_in_use":{"type":"array","items":{"$ref":"#/components/schemas/ProjectUsageInfoResponse"}}}},"ProviderDescriptor":{"type":"object","required":["name","display_name","recommended_events"],"properties":{"display_name":{"type":"string"},"name":{"type":"string"},"recommended_events":{"type":"array","items":{"type":"string"}}}},"ProviderKeyResponse":{"type":"object","required":["id","provider","display_name","api_key_masked","is_active","created_at","updated_at"],"properties":{"api_key_masked":{"type":"string","description":"Masked API key (only last 4 chars visible)"},"base_url":{"type":["string","null"]},"created_at":{"type":"string"},"default_model":{"type":["string","null"],"description":"Model id this provider serves (NULL → per-provider default)."},"display_name":{"type":"string"},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"provider":{"type":"string"},"updated_at":{"type":"string"}}},"ProviderMetadata":{"type":"object","required":["service_type","display_name","description","icon_url","color"],"properties":{"color":{"type":"string","example":"#336791"},"description":{"type":"string","example":"Relational database management system"},"display_name":{"type":"string","example":"PostgreSQL"},"icon_url":{"type":"string","example":"https://cdn.simpleicons.org/postgresql"},"service_type":{"$ref":"#/components/schemas/ServiceTypeRoute"}}},"ProviderResponse":{"type":"object","required":["id","name","provider_type","auth_method","is_active","is_default","created_at","updated_at"],"properties":{"auth_method":{"type":"string"},"base_url":{"type":["string","null"]},"created_at":{"type":"string","format":"date-time"},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"is_default":{"type":"boolean"},"name":{"type":"string"},"provider_type":{"type":"string"},"updated_at":{"type":"string","format":"date-time"}}},"ProviderUsage":{"type":"object","required":["provider","request_count","input_tokens","output_tokens","avg_latency_ms","error_count"],"properties":{"avg_latency_ms":{"type":"number","format":"double"},"error_count":{"type":"integer","format":"int64"},"input_tokens":{"type":"integer","format":"int64"},"output_tokens":{"type":"integer","format":"int64"},"provider":{"type":"string"},"request_count":{"type":"integer","format":"int64"}}},"ProvisionResponse":{"oneOf":[{"allOf":[{"$ref":"#/components/schemas/DomainError"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["error"]}}}]},{"allOf":[{"$ref":"#/components/schemas/DomainResponse"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["complete"]}}}]},{"allOf":[{"$ref":"#/components/schemas/DomainChallengeResponse"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["pending"]}}}]}]},"ProxyLogResponse":{"type":"object","description":"Response model for proxy logs","required":["id","timestamp","method","path","host","status_code","request_source","is_system_request","routing_status","request_id"],"properties":{"bot_name":{"type":["string","null"]},"browser":{"type":["string","null"]},"browser_version":{"type":["string","null"]},"cache_status":{"type":["string","null"]},"client_ip":{"type":["string","null"]},"container_id":{"type":["string","null"]},"deployment_id":{"type":["integer","null"],"format":"int32"},"device_type":{"type":["string","null"]},"environment_id":{"type":["integer","null"],"format":"int32"},"error_message":{"type":["string","null"]},"host":{"type":"string"},"id":{"type":"integer","format":"int32"},"ip_geolocation_id":{"type":["integer","null"],"format":"int32"},"is_bot":{"type":["boolean","null"]},"is_system_request":{"type":"boolean"},"method":{"type":"string"},"operating_system":{"type":["string","null"]},"path":{"type":"string"},"project_id":{"type":["integer","null"],"format":"int32"},"query_string":{"type":["string","null"]},"referrer":{"type":["string","null"]},"request_id":{"type":"string"},"request_size_bytes":{"type":["integer","null"],"format":"int64"},"request_source":{"type":"string"},"response_size_bytes":{"type":["integer","null"],"format":"int64"},"response_time_ms":{"type":["integer","null"],"format":"int32"},"routing_status":{"type":"string"},"session_id":{"type":["integer","null"],"format":"int32"},"status_code":{"type":"integer","format":"int32"},"timestamp":{"type":"string"},"upstream_host":{"type":["string","null"]},"user_agent":{"type":["string","null"]},"visitor_id":{"type":["integer","null"],"format":"int32"}}},"ProxyLogsPaginatedResponse":{"type":"object","description":"Paginated response for proxy logs","required":["logs","total","page","page_size","total_pages"],"properties":{"logs":{"type":"array","items":{"$ref":"#/components/schemas/ProxyLogResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0},"total_pages":{"type":"integer","format":"int64","minimum":0}}},"PublicHostnameStrategy":{"type":"string","description":"Public hostname generation mode for Temps-managed preview routes.\n\nThe mode is stored per managed domain (`dns_managed_domains.generated_hostname_mode`)\nrather than globally, so a provider such as Cloudflare can offer the flat layout\nrequired by its Universal SSL wildcard cert without changing every domain's behaviour.","enum":["standard","flat"]},"PublicPresetResponse":{"type":"object","description":"Response for preset detection","required":["branch","presets"],"properties":{"branch":{"type":"string","description":"Branch name where presets were detected"},"presets":{"type":"array","items":{"$ref":"#/components/schemas/PresetInfo"},"description":"List of detected presets"}}},"PublicRepositoryInfo":{"type":"object","description":"Public repository information","required":["owner","name","full_name","default_branch","stars","forks"],"properties":{"default_branch":{"type":"string","description":"Default branch name"},"description":{"type":["string","null"],"description":"Repository description"},"forks":{"type":"integer","format":"int32","description":"Fork count"},"full_name":{"type":"string","description":"Full repository name (owner/repo)"},"language":{"type":["string","null"],"description":"Primary programming language"},"name":{"type":"string","description":"Repository name"},"owner":{"type":"string","description":"Repository owner"},"stars":{"type":"integer","format":"int32","description":"Star count"}}},"PurgeLogsRequest":{"type":"object","required":["before"],"properties":{"before":{"type":"string","description":"Delete all logs before this timestamp (ISO 8601)"}}},"PushImageRequest":{"type":"object","description":"Request to push an external image","required":["image_ref"],"properties":{"image_ref":{"type":"string"},"metadata":{}}},"PushedExternalImageResponse":{"type":"object","description":"Response for in-memory external image operations (legacy push flow).\n\nRenamed to avoid shadowing the richer database-backed `ExternalImageResponse`\nin `handlers/remote_deployments.rs`. The two types serve different routes\n(`/images` ephemeral push vs `/external-images` registered images).","required":["id","image_ref","pushed_at"],"properties":{"digest":{"type":["string","null"]},"id":{"type":"string"},"image_ref":{"type":"string"},"pushed_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"size":{"type":["integer","null"],"format":"int64","minimum":0}}},"QueryDataRequest":{"type":"object","properties":{"filters":{"description":"JSON filters (backend-specific format)"},"limit":{"type":"integer","description":"Maximum number of rows to return","example":100,"minimum":0},"offset":{"type":"integer","description":"Number of rows to skip","example":0,"minimum":0},"sort_by":{"type":["string","null"],"description":"Sort by field name"},"sort_order":{"type":["string","null"],"description":"Sort order (asc/desc)"}}},"QueryDataResponse":{"type":"object","required":["fields","rows","total_count","returned_count","execution_time_ms"],"properties":{"execution_time_ms":{"type":"integer","format":"int64","description":"Query execution time in milliseconds","example":45,"minimum":0},"fields":{"type":"array","items":{"$ref":"#/components/schemas/FieldResponse"},"description":"Field definitions"},"returned_count":{"type":"integer","description":"Number of rows returned in this response","example":100,"minimum":0},"rows":{"type":"array","items":{},"description":"Data rows (array of JSON objects)"},"total_count":{"type":"integer","format":"int64","description":"Total number of rows matching the query (before limit/offset)","example":1234,"minimum":0}}},"QuotaResponse":{"type":"object","required":["quota"],"properties":{"quota":{"$ref":"#/components/schemas/StorageQuota"}}},"RateLimitConfig":{"type":"object","description":"Rate limiting configuration (subset of global RateLimitSettings)","properties":{"blacklistIps":{"type":"array","items":{"type":"string"},"description":"Blacklist specific IPs for this project/environment"},"maxRequestsPerHour":{"type":["integer","null"],"format":"int32","description":"Override rate limit per hour","minimum":0},"maxRequestsPerMinute":{"type":["integer","null"],"format":"int32","description":"Override rate limit per minute","minimum":0},"whitelistIps":{"type":"array","items":{"type":"string"},"description":"Whitelist specific IPs for this project/environment"}}},"RateLimitSettings":{"type":"object","properties":{"blacklist_ips":{"type":"array","items":{"type":"string"},"default":[]},"enabled":{"type":"boolean","default":false},"max_requests_per_hour":{"type":"integer","format":"int32","default":1000,"minimum":0},"max_requests_per_minute":{"type":"integer","format":"int32","default":60,"minimum":0},"whitelist_ips":{"type":"array","items":{"type":"string"},"default":[]}}},"ReachabilityStatus":{"type":"string","description":"Email reachability status","enum":["safe","risky","invalid","unknown"]},"ReadFileResponse":{"type":"object","required":["path","contents_b64","size"],"properties":{"contents_b64":{"type":"string","description":"File contents, base64-encoded. Symmetric with `WriteFileBody`."},"path":{"type":"string"},"size":{"type":"integer","format":"int64","minimum":0}}},"RecentActivityQuery":{"type":"object","description":"Query parameters for recent activity endpoint","required":["project_id"],"properties":{"environment_id":{"type":["integer","null"],"format":"int32","description":"Environment ID (optional)"},"limit":{"type":["integer","null"],"format":"int32","description":"Max number of events to return (default: 50, max: 100)"},"project_id":{"type":"integer","format":"int32","description":"Project ID"},"since_id":{"type":["integer","null"],"format":"int64","description":"Return events with ID greater than this (for cursor-based polling)"}}},"RecentActivityResponse":{"type":"object","description":"Response for recent activity events endpoint","required":["events","count"],"properties":{"count":{"type":"integer","description":"Total events returned","minimum":0},"events":{"type":"array","items":{"$ref":"#/components/schemas/ActivityEvent"},"description":"Recent events, newest first"}}},"RecentEventResponse":{"type":"object","required":["occurred_at","event_type"],"properties":{"amount_minor":{"type":["integer","null"],"format":"int64"},"currency":{"type":["string","null"]},"customer_ref":{"type":["string","null"]},"event_type":{"type":"string"},"mrr_minor":{"type":["integer","null"],"format":"int64"},"occurred_at":{"type":"string","format":"date-time"}}},"RecentQueryParams":{"type":"object","properties":{"conversation_id":{"type":["string","null"],"description":"Filter by conversation ID"},"cost_gt":{"type":["integer","null"],"format":"int64","description":"Cost strictly greater-than, in microcents"},"cost_gte":{"type":["integer","null"],"format":"int64","description":"Cost greater-than-or-equal, in microcents"},"cost_lt":{"type":["integer","null"],"format":"int64","description":"Cost strictly less-than, in microcents"},"cost_lte":{"type":["integer","null"],"format":"int64","description":"Cost less-than-or-equal, in microcents"},"limit":{"type":["integer","null"],"format":"int64","description":"Page size (defaults to 20, max 50)","minimum":0},"model":{"type":["string","null"],"description":"Filter by model name"},"offset":{"type":["integer","null"],"format":"int64","description":"Number of results to skip for pagination (defaults to 0)","minimum":0},"provider":{"type":["string","null"],"description":"Filter by provider name"},"status":{"type":["integer","null"],"format":"int32","description":"Filter by HTTP status code (exact match)"},"tags":{"type":["string","null"],"description":"Filter by tags (comma-separated, AND logic)"},"tokens_gt":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) strictly greater-than"},"tokens_gte":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) greater-than-or-equal"},"tokens_lt":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) strictly less-than"},"tokens_lte":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) less-than-or-equal"},"user_id":{"type":["integer","null"],"format":"int32","description":"Filter by user ID"}}},"RecordExposureRequest":{"type":"object","description":"Keys a running app actually evaluated since its last report.","required":["keys"],"properties":{"keys":{"type":"array","items":{"type":"string"},"description":"Flag keys evaluated since the last report. Unknown keys are ignored.","example":["checkout.v2","api.rate_limit"]}}},"RecordExposureResponse":{"type":"object","required":["recorded"],"properties":{"recorded":{"type":"integer","format":"int64","description":"How many keys were accepted for processing.\n\nDeliberately not the number of rows updated: echoing that back would\nlet a caller post a single candidate key and read the result as \"this\nflag exists\", turning the endpoint into an existence oracle.","minimum":0}}},"RecordListResponse":{"type":"object","description":"Record list response","required":["records"],"properties":{"records":{"type":"array","items":{"$ref":"#/components/schemas/DnsRecord"}}}},"RecoveryTarget":{"oneOf":[{"type":"object","description":"Recover to a specific timestamp.","required":["time","kind"],"properties":{"kind":{"type":"string","enum":["time"]},"time":{"type":"string","format":"date-time"}}},{"type":"object","description":"Recover to a specific transaction id (Postgres).","required":["xid","kind"],"properties":{"kind":{"type":"string","enum":["xid"]},"xid":{"type":"string"}}},{"type":"object","description":"Recover to a specific log sequence number (Postgres).","required":["lsn","kind"],"properties":{"kind":{"type":"string","enum":["lsn"]},"lsn":{"type":"string"}}},{"type":"object","description":"Recover to a named restore point created via `pg_create_restore_point` (Postgres).","required":["name","kind"],"properties":{"kind":{"type":"string","enum":["name"]},"name":{"type":"string"}}}],"description":"Engine-specific recovery target for PITR.\n\nPostgres honors all variants; Redis/Mongo/S3 will likely reject non-Time\nvariants or define their own semantics when they grow PITR support."},"ReferrerCount":{"type":"object","required":["referrer","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"percentage":{"type":"number","format":"double"},"referrer":{"type":"string"}}},"ReferrersAnalyticsQuery":{"type":"object","required":["start_date","end_date","project_id"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"RegenerateDSNRequest":{"type":"object","properties":{"base_url":{"type":["string","null"]}}},"RegisterImageRequest":{"type":"object","required":["image_ref"],"properties":{"digest":{"type":["string","null"],"description":"Image digest (sha256:...)","example":"sha256:abc123def456"},"image_ref":{"type":"string","description":"Docker image reference (e.g., \"ghcr.io/org/app:v1.0\")","example":"ghcr.io/myorg/myapp:v1.0"},"metadata":{"description":"Additional metadata"},"tag":{"type":["string","null"],"description":"Image tag","example":"v1.0"}}},"RegisterNodeApiRequest":{"type":"object","required":["name","token","address","private_address"],"properties":{"address":{"type":"string","description":"Node's reachable address (e.g., \"10.100.0.2\" or \"192.168.1.50\")"},"architecture":{"type":["string","null"],"description":"Container platform of this node's Docker daemon (`linux/amd64`,\n`linux/arm64`). Optional: agents older than multi-arch support omit it\nand the value is learned from the first heartbeat instead."},"csr_pem":{"type":["string","null"],"description":"Node-generated certificate signing request (PEM) for multi-node mTLS\n(ADR-020 WS-2.1). When present, the control plane signs it with the\ncluster CA and returns the leaf + CA cert. Optional — token-only nodes\n(legacy / edge) still register without one."},"edge_public_key":{"type":["string","null"],"description":"X25519 public key for ECIES certificate encryption (base64-encoded, edge nodes only)"},"join_token":{"type":["string","null"],"description":"Join token to authorize this registration (must match the token generated in Settings)"},"labels":{"description":"Labels for scheduling (e.g., {\"region\": \"us-east\", \"gpu\": \"true\"})"},"name":{"type":"string","description":"Unique name for this node"},"prior_token":{"type":["string","null"],"description":"The node's *current* token, supplied to prove possession when\nre-registering (changing the identity of) a node that already exists.\nOptional; only needed to rebind a still-live node. (ADR-020 WS-1.2.)"},"private_address":{"type":"string","description":"Private/WireGuard address for inter-node communication"},"public_endpoint":{"type":["string","null"],"description":"Public endpoint for WireGuard (e.g., \"203.0.113.1:51820\")"},"role":{"type":["string","null"],"description":"Node role (default: \"worker\")"},"token":{"type":"string","description":"Registration token (plaintext, will be hashed before storage)"},"wg_public_key":{"type":["string","null"],"description":"WireGuard public key"}}},"RegisterNodeResponse":{"type":"object","required":["id","name","status","message"],"properties":{"ca_cert_pem":{"type":["string","null"],"description":"The cluster CA certificate (PEM) the node pins as its trust root.\nPresent only when a `csr_pem` was supplied. (ADR-020 WS-2.1.)"},"cert_pem":{"type":["string","null"],"description":"The signed per-node leaf certificate (PEM) the agent serves as its TLS\nserver cert. Present only when a `csr_pem` was supplied. (ADR-020 WS-2.1.)"},"id":{"type":"integer","format":"int32"},"message":{"type":"string"},"name":{"type":"string"},"status":{"type":"string"}}},"RegisterRequest":{"type":"object","required":["email","password","name"],"properties":{"email":{"type":"string"},"name":{"type":"string"},"password":{"type":"string"}}},"ReinstallWebhookResponse":{"type":"object","description":"Response for `POST /projects/{project_id}/gitlab/reinstall-webhook`","required":["hook_id","message"],"properties":{"hook_id":{"type":"integer","format":"int32","description":"The new GitLab hook ID that was installed."},"message":{"type":"string","description":"Human-readable status message."}}},"ReleaseCheckResult":{"type":"object","description":"Outcome of an operator-triggered release check.","required":["channel","current_version","update_available"],"properties":{"channel":{"type":"string","description":"Channel that was queried."},"current_version":{"type":"string","description":"Version tag of the running binary."},"latest_version":{"type":["string","null"],"description":"Newest release published on that channel, if any could be resolved."},"release_url":{"type":["string","null"],"description":"Release-notes page for `latest_version`."},"update_available":{"type":"boolean","description":"True when `latest_version` is strictly newer than what is running.\nFalse on a channel whose newest release is older — which is normal and\nexpected right after switching a nightly box onto stable."}}},"ReleaseListResponse":{"type":"object","required":["releases"],"properties":{"releases":{"type":"array","items":{"type":"string"}}}},"ReloadResponse":{"type":"object","description":"Response from the reload endpoint.","required":["loaded","plugins","message"],"properties":{"loaded":{"type":"integer","description":"Number of plugins successfully loaded after reload","minimum":0},"message":{"type":"string","description":"Human-readable status message"},"plugins":{"type":"array","items":{"type":"string"},"description":"Names of loaded plugins"}}},"RemoteDeploymentResponse":{"type":"object","required":["id","project_id","environment_id","slug","state","source_type","created_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"environment_id":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"project_id":{"type":"integer","format":"int32"},"slug":{"type":"string"},"source_type":{"type":"string"},"state":{"type":"string"}}},"RemoveNodeResponse":{"type":"object","required":["id","message"],"properties":{"id":{"type":"integer","format":"int32"},"message":{"type":"string"}}},"RenameConversationRequest":{"type":"object","required":["title"],"properties":{"title":{"type":"string","description":"New human-facing title. Trimmed; must be non-empty after trimming."}}},"RepositoryListQuery":{"type":"object","properties":{"direction":{"type":["string","null"]},"language":{"type":["string","null"]},"owner":{"type":["string","null"]},"page":{"type":["integer","null"],"format":"int64","minimum":0},"per_page":{"type":["integer","null"],"format":"int64","minimum":0},"private":{"type":["boolean","null"]},"search":{"type":["string","null"]},"sort":{"type":["string","null"]}}},"RepositoryListResponse":{"type":"object","required":["repositories","total_count"],"properties":{"repositories":{"type":"array","items":{"$ref":"#/components/schemas/RepositoryResponse"}},"total_count":{"type":"integer","minimum":0}}},"RepositoryPresetResponse":{"type":"object","required":["repository_id","owner","name","presets","calculated_at"],"properties":{"calculated_at":{"type":"string","format":"date-time"},"name":{"type":"string"},"owner":{"type":"string"},"presets":{"type":"array","items":{"$ref":"#/components/schemas/ProjectPresetResponse"}},"repository_id":{"type":"integer","format":"int32"}}},"RepositoryResponse":{"type":"object","required":["id","owner","name","full_name","private","default_branch","created_at","updated_at","pushed_at","git_provider_connection_id"],"properties":{"clone_url":{"type":["string","null"],"description":"HTTPS clone URL (e.g., https://github.com/owner/repo.git)"},"created_at":{"type":"string","format":"date-time"},"default_branch":{"type":"string"},"description":{"type":["string","null"]},"full_name":{"type":"string"},"git_provider_connection_id":{"type":"integer","format":"int32","description":"ID of the git provider connection this repository was synced from."},"id":{"type":"integer","format":"int32"},"language":{"type":["string","null"]},"name":{"type":"string"},"owner":{"type":"string"},"preset":{"type":["array","null"],"items":{"$ref":"#/components/schemas/ProjectPresetResponse"}},"private":{"type":"boolean"},"pushed_at":{"type":"string","format":"date-time"},"ssh_url":{"type":["string","null"],"description":"SSH clone URL (e.g., git@github.com:owner/repo.git)"},"updated_at":{"type":"string","format":"date-time"}}},"RepositorySyncStartedResponse":{"type":"object","description":"Returned by `POST /git-connections/{id}/sync` to acknowledge that a\nsync has been kicked off in the background. Clients should poll the\nconnection's `syncing` and `synced_repository_count` fields to track\nprogress rather than waiting on this response.","required":["connection_id","syncing","started_at"],"properties":{"connection_id":{"type":"integer","format":"int32"},"started_at":{"type":"string","format":"date-time"},"syncing":{"type":"boolean"}}},"RequestRow":{"type":"object","required":["id","ts","method","host","path","status","request_headers","response_headers","headers_truncated"],"properties":{"client_ip":{"type":["string","null"]},"country":{"type":["string","null"]},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"error_group_id":{"type":["integer","null"],"format":"int32"},"headers_truncated":{"type":"boolean"},"host":{"type":"string"},"id":{"type":"string","description":"The request's unique `request_id` (assigned by the proxy). Used as the\nrow identity instead of the storage PK because the ClickHouse backend\nhas no serial id (rows come back with `id = 0`) while `request_id` is\nunique and present on both backends."},"latency_ms":{"type":["integer","null"],"format":"int32"},"method":{"type":"string"},"path":{"type":"string"},"query_string":{"type":["string","null"]},"referrer":{"type":["string","null"]},"request_headers":{},"response_headers":{},"status":{"type":"integer","format":"int32"},"trace_id":{"type":["string","null"]},"ts":{"type":"string","format":"date-time"},"user_agent":{"type":["string","null"]}}},"RequiredPasswordChangeRequest":{"type":"object","required":["new_password"],"properties":{"new_password":{"type":"string"}}},"RequiredPasswordChangeResponse":{"type":"object","required":["success","message","user_id","mfa_enrollment_required"],"properties":{"message":{"type":"string"},"mfa_enrollment_required":{"type":"boolean"},"mfa_setup":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/MfaSetupResponse"}]},"success":{"type":"boolean"},"user_id":{"type":"integer","format":"int32"}}},"ResetPasswordRequest":{"type":"object","required":["token","new_password"],"properties":{"new_password":{"type":"string"},"token":{"type":"string"}}},"ResetPgStatStatementsRequest":{"type":"object","description":"Explicit confirmation required for the destructive statistics reset.\n\nRequiring JSON makes the endpoint non-simple for browsers, preventing a\ndeployed same-site application from triggering it with a plain HTML form.","required":["confirm"],"properties":{"confirm":{"type":"boolean","description":"Must be `true` to acknowledge the global, irreversible reset."}}},"ResetPgStatStatementsResponse":{"type":"object","description":"Response for the pg_stat_statements reset endpoint.","required":["message"],"properties":{"message":{"type":"string","description":"Human-readable message confirming the destructive action."}}},"ResizeSandboxBody":{"type":"object","required":["disk_size_mb"],"properties":{"disk_size_mb":{"type":"integer","format":"int64","description":"New root disk size in MB. Grow-only; must exceed the current size.","minimum":0}},"additionalProperties":false},"ResolvedEnvVarResponse":{"type":"object","description":"One entry in the computed env-var view that merges manual and integration\nsources and tags each result with its origin. `value_preview` is always\nmasked — plaintext must be fetched per-key via the existing reveal endpoint,\nwhich is audit-logged.","required":["key","value_preview","source","environments","include_in_preview"],"properties":{"environments":{"type":"array","items":{"$ref":"#/components/schemas/EnvironmentInfo"},"description":"Environments this var applies to. For integration-sourced vars this\nreflects every environment of the project (integrations are global)."},"include_in_preview":{"type":"boolean","description":"Whether the var would be auto-applied to preview environments.\nIntegration vars always surface in preview; manual vars follow the flag."},"key":{"type":"string"},"source":{"$ref":"#/components/schemas/ResolvedEnvVarSource"},"value_preview":{"type":"string","description":"Masked or truncated preview. Never the raw value."}}},"ResolvedEnvVarSource":{"oneOf":[{"type":"object","description":"Manually-defined env var. If `overrides_service` is set, this key would\notherwise have been supplied by an integration — the UI should show the\nintegration icon plus an \"overridden\" indicator.","required":["var_id","type"],"properties":{"overrides_service":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/EnvVarIntegrationInfo"}]},"type":{"type":"string","enum":["manual"]},"var_id":{"type":"integer","format":"int32"}}},{"type":"object","description":"Supplied by a linked external service (Postgres, Redis, S3, etc.).","required":["service","type"],"properties":{"service":{"$ref":"#/components/schemas/EnvVarIntegrationInfo"},"type":{"type":"string","enum":["integration"]}}}],"description":"Where a resolved env var comes from. Integration-sourced vars may be\n\"shadowed\" by a manual entry with the same key, in which case the response\ncarries `Manual` with `overrides_service` populated so the UI can still show\nthe integration icon."},"ResourceCounts":{"type":"object","description":"Quick count of resources involved in the migration","required":["projects","environments","deployments","environment_variables","services","domains"],"properties":{"deployments":{"type":"integer","minimum":0},"domains":{"type":"integer","minimum":0},"environment_variables":{"type":"integer","minimum":0},"environments":{"type":"integer","minimum":0},"projects":{"type":"integer","minimum":0},"services":{"type":"integer","minimum":0}}},"ResourceFootprint":{"type":"object","description":"A CPU + memory footprint (requests or measured usage)","required":["cpu_millis","memory_mb"],"properties":{"cpu_millis":{"type":"integer","format":"int64","description":"CPU in millicores"},"memory_mb":{"type":"integer","format":"int64","description":"Memory in MB"}}},"ResourceInfo":{"type":"object","description":"Resource attributes extracted from OTel resource descriptors.","required":["service_name","attributes"],"properties":{"attributes":{"type":"object"},"deployment_environment":{"type":["string","null"]},"service_name":{"type":"string"},"service_version":{"type":["string","null"]}}},"ResourceLimitApplyResult":{"type":"object","description":"Per-container outcome of a live `docker update` call. Surfaced from the\nPATCH /resources endpoint so the UI can tell the operator whether the\nnew caps are already in effect or whether they only apply on next\nrecreate (e.g., container was missing).","required":["role","container_name","outcome"],"properties":{"container_name":{"type":"string"},"error":{"type":["string","null"],"description":"Populated only when `outcome == \"failed\"`."},"outcome":{"type":"string","description":"One of:\n- \"applied\" — Docker accepted the update; caps are live now.\n- \"missing\" — container does not exist; caps stored, will apply on next start.\n- \"stopped\" — container exists but isn't running; Docker still\n accepts the update (the new caps apply on next start).\n- \"failed\" — `docker update` returned an error (see `error`)."},"role":{"type":"string","description":"`service_members.role` for cluster members; \"standalone\" otherwise."}}},"ResourceLimits":{"type":"object","description":"Resource limits and requests","properties":{"cpu_limit":{"type":["integer","null"],"format":"int32","description":"CPU limit (millicores)"},"cpu_request":{"type":["integer","null"],"format":"int32","description":"CPU request (millicores)"},"memory_limit":{"type":["integer","null"],"format":"int32","description":"Memory limit (MB)"},"memory_request":{"type":["integer","null"],"format":"int32","description":"Memory request (MB)"}}},"ResourceLimitsResponse":{"type":"object","description":"Container resource limits","properties":{"cpu_limit":{"type":["integer","null"],"format":"int32"},"cpu_request":{"type":["integer","null"],"format":"int32"},"memory_limit":{"type":["integer","null"],"format":"int32"},"memory_request":{"type":["integer","null"],"format":"int32"}}},"ResourceLimitsUpdateResponse":{"type":"object","description":"Response from PATCH /external-services/{id}/resources.","required":["limits","applied"],"properties":{"applied":{"type":"array","items":{"$ref":"#/components/schemas/ResourceLimitApplyResult"},"description":"Per-container result of trying to apply the limits live."},"limits":{"$ref":"#/components/schemas/ServiceResourceLimits","description":"The limits that were persisted to the encrypted config."}}},"ResourcesBody":{"type":"object","description":"Nested `resources: { memory, vcpus }` as sent by `@vercel/sandbox`.\n`memory` is in MB, `vcpus` is fractional CPU count.","properties":{"memory":{"type":["integer","null"],"format":"int64","minimum":0},"vcpus":{"type":["number","null"],"format":"double"}}},"RestoreCapabilities":{"type":"object","description":"Capabilities a service exposes for the generic restore framework.\n\nEach engine overrides `ExternalService::restore_capabilities` to declare\nwhat it supports. The handler layer uses this to validate requests and\nthe UI uses it to conditionally show options (e.g., PITR picker).","required":["restore_in_place","restore_to_new_service","pitr"],"properties":{"earliest_pitr_time":{"type":["string","null"],"format":"date-time","description":"Earliest recoverable timestamp, if `pitr` is true. Derived from\nengine-specific archive metadata (e.g., `pg_stat_archiver`)."},"latest_pitr_time":{"type":["string","null"],"format":"date-time","description":"Latest recoverable timestamp, if `pitr` is true."},"pitr":{"type":"boolean","description":"Point-in-time recovery using engine-specific continuous archives\n(WAL for Postgres, AOF for Redis, oplog for MongoDB, object versions for S3)."},"restore_in_place":{"type":"boolean","description":"Restore a backup onto the same running service (destructive)."},"restore_to_new_service":{"type":"boolean","description":"Restore a backup into a freshly provisioned service."}}},"RestoreCapabilitiesResponse":{"allOf":[{"$ref":"#/components/schemas/RestoreCapabilities","description":"Trait-declared capabilities."},{"type":"object","required":["suggested_new_service_name"],"properties":{"suggested_new_service_name":{"type":"string","description":"Suggested name for the new service when creating a clone. Safe to\npre-fill into the UI dialog; the user can edit before submitting."}}}]},"RestorePlan":{"type":"object","description":"Preview of a restore operation. Answers \"what will happen if I click\nstart?\" with engine-level specificity so the user can confirm before\ncommitting to a destructive action.","required":["engine","target_service","source_backup","strategy","steps","warnings","errors","destructive","mode"],"properties":{"destructive":{"type":"boolean","description":"Whether any step overwrites existing data on the target service."},"engine":{"type":"string","description":"Target engine (\"postgres\", etc.)."},"errors":{"type":"array","items":{"type":"string"},"description":"Blocking problems. The UI disables the Start button when non-empty."},"mode":{"type":"string","description":"Echo of the requested mode for the UI."},"source_backup":{"$ref":"#/components/schemas/PlanSourceBackup","description":"Backup we'll read from."},"steps":{"type":"array","items":{"type":"string"},"description":"Ordered list of human-readable actions the orchestrator will take."},"strategy":{"type":"string","description":"How the restore will be performed: \"walg_restore\", \"pg_dump_restore\",\nor \"unsupported\"."},"target_service":{"$ref":"#/components/schemas/PlanTarget","description":"Service we'll operate on (or provision a sibling of)."},"warnings":{"type":"array","items":{"type":"string"},"description":"Non-blocking caveats the user should see (cross-service, empty\nlocation that will be auto-resolved, missing engine metadata, ...)."}}},"RestoreRequestMode":{"oneOf":[{"type":"object","description":"Restore the backup onto the existing service (destructive).","required":["mode"],"properties":{"mode":{"type":"string","enum":["in_place"]}}},{"type":"object","description":"Provision a new service and restore into it.","required":["name","mode"],"properties":{"mode":{"type":"string","enum":["new_service"]},"name":{"type":"string","description":"Name for the new service. Orchestrator auto-suggests\n`{source}-restore-{yyyymmdd-hhmm}` if caller omits, but we require\nan explicit value at the API boundary."},"parameter_overrides":{"description":"Optional parameter overrides (port, docker_image, database)."}}},{"type":"object","description":"Point-in-time recovery. Only valid on WAL-G backups (Postgres).","required":["to_new_service","target","mode"],"properties":{"mode":{"type":"string","enum":["pitr"]},"new_service_name":{"type":["string","null"],"description":"Required when `to_new_service` is true."},"target":{"$ref":"#/components/schemas/RecoveryTarget","description":"Recovery target kind + value."},"to_new_service":{"type":"boolean","description":"Whether PITR restores in place or creates a new service."}}}],"description":"What the caller wants to do. Mirrors `externalsvc::RestoreMode` but\nflattened for JSON over the wire."},"RestoreRunView":{"type":"object","required":["id","source_backup_id","source_service_id","mode","status","phase","created_at"],"properties":{"created_at":{"type":"string"},"error_message":{"type":["string","null"]},"finished_at":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"mode":{"type":"string"},"phase":{"type":"string"},"recovery_target":{},"source_backup_id":{"type":"integer","format":"int32"},"source_service_id":{"type":"integer","format":"int32"},"started_at":{"type":["string","null"]},"status":{"type":"string"},"target_service_id":{"type":["integer","null"],"format":"int32"},"target_service_name":{"type":["string","null"]}}},"RetentionCleanupFailure":{"type":"object","required":["backup_id","reason","partial","deleted_objects"],"properties":{"backup_id":{"type":"string"},"deleted_objects":{"type":"integer","format":"int64","minimum":0},"partial":{"type":"boolean"},"reason":{"type":"string"}}},"RetentionCleanupReport":{"type":"object","required":["dry_run","expired","deleted","failed","failures","deleted_backup_ids","deleted_backup_ids_truncated","partially_deleted_backup_ids","partially_deleted_backup_ids_truncated","candidate_backup_ids","candidate_backup_ids_truncated"],"properties":{"candidate_backup_ids":{"type":"array","items":{"type":"string"},"description":"Capped sample of backups selected by the retention policy."},"candidate_backup_ids_truncated":{"type":"boolean"},"deleted":{"type":"integer","format":"int64","minimum":0},"deleted_backup_ids":{"type":"array","items":{"type":"string"},"description":"Capped sample of deleted backup UUIDs for audit attribution."},"deleted_backup_ids_truncated":{"type":"boolean"},"dry_run":{"type":"boolean","description":"True when this report is a non-destructive preview."},"expired":{"type":"integer","format":"int64","minimum":0},"failed":{"type":"integer","format":"int64","minimum":0},"failures":{"type":"array","items":{"$ref":"#/components/schemas/RetentionCleanupFailure"},"description":"Capped diagnostic sample; `failed` remains the authoritative total."},"partially_deleted_backup_ids":{"type":"array","items":{"type":"string"}},"partially_deleted_backup_ids_truncated":{"type":"boolean"},"schedule_id":{"type":["integer","null"],"format":"int32","description":"Schedule scope, or `None` when every schedule was considered."}}},"RetryClusterRequest":{"type":"object","description":"Request body for retrying a failed cluster initialization.","properties":{"members":{"type":"array","items":{"$ref":"#/components/schemas/ClusterMemberRequest"},"description":"Cluster member specifications (same format as create).\nIf omitted, the original member configuration is reconstructed from\nthe preserved service_members records."}}},"RevenueRow":{"type":"object","required":["id","ts","provider","event_type"],"properties":{"amount_minor":{"type":["integer","null"],"format":"int64"},"currency":{"type":["string","null"]},"customer_ref":{"type":["string","null"]},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"event_type":{"type":"string"},"id":{"type":"integer","format":"int64"},"provider":{"type":"string"},"trace_id":{"type":["string","null"]},"ts":{"type":"string","format":"date-time"}}},"RiskLevel":{"type":"string","description":"Risk level for a migration step","enum":["none","low","medium","high","critical"]},"RoleInfo":{"type":"object","description":"Information about a role","required":["name","description","permissions"],"properties":{"description":{"type":"string","description":"Human-readable description of the role"},"name":{"type":"string","description":"The role identifier (e.g., \"admin\")"},"permissions":{"type":"array","items":{"type":"string"},"description":"Permissions included in this role"}}},"RootfsCacheEntry":{"type":"object","description":"A cached rootfs image (Firecracker backend). Digest-keyed build artifact\nshared by all VMs created from the same image.","required":["digest","bytes","referenced_by"],"properties":{"bytes":{"type":"integer","format":"int64","description":"Actual on-disk size in bytes (sparse-aware).","minimum":0},"digest":{"type":"string","description":"Image digest this rootfs was built from (the cache key)."},"referenced_by":{"type":"array","items":{"type":"string"},"description":"IDs of live sandboxes whose per-VM disk was cloned from this entry.\nEmpty means the entry is reclaimable — no sandbox needs it."}}},"RootfsGcReport":{"type":"object","description":"Outcome of a rootfs garbage-collection pass.","required":["removed_digests","freed_bytes"],"properties":{"freed_bytes":{"type":"integer","format":"int64","minimum":0},"removed_digests":{"type":"array","items":{"type":"string"},"description":"Digests of cache entries removed because no sandbox referenced them."}}},"RootfsReport":{"type":"object","description":"Snapshot of a backend's rootfs storage for the management API. Backends\nwithout a rootfs concept (Docker, local) return an empty report.","required":["cache_bytes","cache","vm_bytes","vms"],"properties":{"cache":{"type":"array","items":{"$ref":"#/components/schemas/RootfsCacheEntry"}},"cache_bytes":{"type":"integer","format":"int64","minimum":0},"vm_bytes":{"type":"integer","format":"int64","minimum":0},"vms":{"type":"array","items":{"$ref":"#/components/schemas/RootfsVmEntry"}}}},"RootfsVmEntry":{"type":"object","description":"A per-sandbox rootfs disk (Firecracker backend). One per non-destroyed\nsandbox — the authoritative storage, independent of the cache.","required":["sandbox_name","bytes","running"],"properties":{"bytes":{"type":"integer","format":"int64","minimum":0},"running":{"type":"boolean"},"sandbox_name":{"type":"string"}}},"RouteRefreshResponse":{"type":"object","required":["route_count","message"],"properties":{"message":{"type":"string","description":"Human-readable message"},"route_count":{"type":"integer","description":"Number of routes loaded","minimum":0}}},"RouteResponse":{"type":"object","required":["id","domain","host","port","enabled","route_type","created_at","updated_at"],"properties":{"created_at":{"type":"integer","format":"int64"},"domain":{"type":"string"},"enabled":{"type":"boolean"},"host":{"type":"string"},"id":{"type":"integer","format":"int32"},"port":{"type":"integer","format":"int32"},"route_type":{"type":"string","description":"Route type: \"http\" or \"tls\""},"updated_at":{"type":"integer","format":"int64"}}},"RouteRole":{"type":"object","required":["id","name","created_at","updated_at"],"properties":{"created_at":{"type":"integer","format":"int64","example":"1683900000000"},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"updated_at":{"type":"integer","format":"int64","example":"1683900000000"}}},"RouteUser":{"type":"object","required":["id","name","username","email","image","mfa_enabled","email_verified","must_change_password","created_at","updated_at"],"properties":{"created_at":{"type":"integer","format":"int64","example":"1683900000000"},"deleted_at":{"type":["integer","null"],"format":"int64"},"email":{"type":"string"},"email_verified":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"image":{"type":"string"},"mfa_enabled":{"type":"boolean"},"must_change_password":{"type":"boolean"},"name":{"type":"string"},"updated_at":{"type":"integer","format":"int64","example":"1683900000000"},"username":{"type":"string"}}},"RouteUserWithRoles":{"type":"object","required":["user","roles"],"properties":{"roles":{"type":"array","items":{"$ref":"#/components/schemas/RouteRole"}},"user":{"$ref":"#/components/schemas/RouteUser"}}},"RunBackupRequest":{"type":"object","required":["backup_type"],"properties":{"backup_type":{"type":"string","description":"Type of backup to perform","example":"full"}}},"RunExternalServiceBackupRequest":{"type":"object","properties":{"backup_type":{"type":["string","null"],"description":"Type of backup to perform (e.g., \"full\", \"incremental\")","example":"full"},"s3_source_id":{"type":["integer","null"],"format":"int32","description":"ID of the S3 source to store the backup. If omitted, the current default S3 source is used.","example":1}}},"S3ConnectionTestResponse":{"type":"object","description":"Response body for an S3 connection test.","required":["ok","message"],"properties":{"message":{"type":"string","description":"Human-readable message (success confirmation or error detail)."},"ok":{"type":"boolean","description":"Whether the connection and credentials worked."}}},"S3CredentialsResponse":{"type":"object","description":"S3 credentials distributed to agents for backup/restore operations.","required":["access_key_id","secret_key","region","bucket_name","force_path_style"],"properties":{"access_key_id":{"type":"string"},"bucket_name":{"type":"string"},"endpoint":{"type":["string","null"]},"force_path_style":{"type":"boolean"},"region":{"type":"string"},"secret_key":{"type":"string"}}},"S3SourceResponse":{"type":"object","description":"Response type for S3 source","required":["id","name","bucket_name","bucket_path","access_key_id","secret_key","region","is_default","created_at","updated_at"],"properties":{"access_key_id":{"type":"string","example":"AKIAXXXXXXXXXXXXXXXX"},"bucket_name":{"type":"string"},"bucket_path":{"type":"string"},"created_at":{"type":"integer","format":"int64"},"endpoint":{"type":["string","null"],"example":"http://minio.example.com:9000"},"force_path_style":{"type":["boolean","null"]},"id":{"type":"integer","format":"int32"},"is_default":{"type":"boolean"},"name":{"type":"string"},"region":{"type":"string"},"secret_key":{"type":"string","writeOnly":true},"updated_at":{"type":"integer","format":"int64"}}},"SandboxDomainResponse":{"type":"object","required":["url"],"properties":{"url":{"type":"string"}}},"SandboxEvent":{"type":"object","description":"One entry in a sandbox's operations timeline.","required":["event_type","at"],"properties":{"at":{"type":"integer","format":"int64","description":"Unix epoch milliseconds."},"detail":{"description":"Optional structured context (shape depends on `event_type`)."},"event_type":{"type":"string","description":"Machine-readable operation (`created`, `stopped`, `resumed`,\n`restarted`, `timeout_extended`, `resized`, `preview_password_set`,\n`preview_password_cleared`, `preview_share_link_created`, `source_seeded`,\n`destroyed`)."}}},"SandboxEventsResponse":{"type":"object","required":["events"],"properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/SandboxEvent"}}}},"SandboxInner":{"type":"object","description":"Inner `sandbox` object in `@vercel/sandbox` responses. Strict shape —\nthe SDK's zod validator rejects missing required fields.","required":["id","memory","vcpus","region","runtime","timeout","status","requestedAt","createdAt","updatedAt","cwd","name","preview_url_template"],"properties":{"agent_run_id":{"type":["integer","null"],"format":"int32","description":"Agent run this sandbox executes (autofixer / workflow agent).\n`None` for sandboxes created via this API."},"backend":{"type":["string","null"],"description":"Isolation backend: \"docker\" | \"firecracker\". `None` on legacy rows\ncreated before the backend was recorded."},"createdAt":{"type":"integer","format":"int64"},"cwd":{"type":"string"},"disk_size_mb":{"type":["integer","null"],"format":"int64","description":"Configured root disk size in MB (Firecracker). `None` when unknown or\nthe default.","minimum":0},"id":{"type":"string"},"image":{"type":["string","null"]},"memory":{"type":"integer","format":"int64","minimum":0},"name":{"type":"string"},"preview_password_hint":{"type":["string","null"]},"preview_url_template":{"type":"string"},"region":{"type":"string"},"requestedAt":{"type":"integer","format":"int64","description":"Creation time as Unix epoch milliseconds."},"runtime":{"type":"string"},"status":{"type":"string"},"timeout":{"type":"integer","format":"int64","description":"Idle timeout in milliseconds (SDK convention).","minimum":0},"updatedAt":{"type":"integer","format":"int64"},"vcpus":{"type":"number","format":"double"}}},"SandboxResponse":{"type":"object","description":"`@vercel/sandbox` wraps every single-sandbox response as\n`{ sandbox: {...}, routes: [...] }`. The SDK reads both.","required":["sandbox","routes"],"properties":{"routes":{"type":"array","items":{"$ref":"#/components/schemas/SandboxRoute"}},"sandbox":{"$ref":"#/components/schemas/SandboxInner"}}},"SandboxRoute":{"type":"object","description":"A single preview route, one per declared port. We don't know ports\nupfront, so we surface an empty array by default — SDK clients use\ntheir own port when calling `sandbox.domain(port)`.","required":["url","subdomain","port"],"properties":{"port":{"type":"integer","format":"int32","minimum":0},"subdomain":{"type":"string"},"url":{"type":"string"}}},"SandboxStatusResponse":{"type":"object","required":["docker_available","image_ready","image_name","firecracker_available"],"properties":{"docker_available":{"type":"boolean"},"error":{"type":["string","null"]},"firecracker_available":{"type":"boolean"},"image_name":{"type":"string"},"image_ready":{"type":"boolean"}}},"SaveAgentTokenRequest":{"type":"object","required":["token"],"properties":{"token":{"type":"string","description":"The OAuth token from `claude setup-token` or an API key.\nWill be encrypted before storage."}}},"SaveAgentTokenResponse":{"type":"object","required":["saved"],"properties":{"saved":{"type":"boolean"}}},"SaveCredentialRequest":{"type":"object","required":["auth_type","credential"],"properties":{"auth_type":{"type":"string","description":"Auth flavor id (must match one of the provider's catalog entries)."},"credential":{"type":"string","description":"Plaintext credential body (API key, OAuth token, or full config file\ncontents). Encrypted with `EncryptionService` before being persisted\ninside the `agent_sandbox.providers` JSON map."}}},"SaveCredentialResponse":{"type":"object","required":["saved","provider_id","auth_type"],"properties":{"auth_type":{"type":"string"},"provider_id":{"type":"string"},"saved":{"type":"boolean"}}},"ScalewayCredentialsRequest":{"type":"object","required":["api_key","project_id"],"properties":{"api_key":{"type":"string","example":"scw-secret-key-12345"},"project_id":{"type":"string","example":"12345678-1234-1234-1234-123456789012"}}},"ScanResponse":{"type":"object","required":["id","project_id","scanner_type","status","total_count","critical_count","high_count","medium_count","low_count","unknown_count","started_at","created_at","updated_at"],"properties":{"branch":{"type":["string","null"]},"commit_hash":{"type":["string","null"]},"completed_at":{"type":["string","null"],"example":"2025-12-08T12:15:47.609192Z"},"created_at":{"type":"string","example":"2025-12-08T12:15:47.609192Z"},"critical_count":{"type":"integer","format":"int32"},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"error_message":{"type":["string","null"]},"high_count":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"low_count":{"type":"integer","format":"int32"},"medium_count":{"type":"integer","format":"int32"},"project_id":{"type":"integer","format":"int32"},"scanner_type":{"type":"string"},"scanner_version":{"type":["string","null"]},"started_at":{"type":"string","example":"2025-12-08T12:15:47.609192Z"},"status":{"type":"string"},"total_count":{"type":"integer","format":"int32"},"unknown_count":{"type":"integer","format":"int32"},"updated_at":{"type":"string","example":"2025-12-08T12:15:47.609192Z"}}},"ScheduleRunEntry":{"type":"object","description":"A single run-history entry for the schedule detail page (deliverable 1).\n\nCombines one `backups` row with the most-recent `backup_jobs` row for that\nbackup via a lateral JOIN. Fields from `backup_jobs` are `None` for legacy\nbackup rows that pre-date ADR-014.","required":["backup_id","backup_uuid","state","started_at","s3_location"],"properties":{"attempts":{"type":["integer","null"],"format":"int32","description":"Number of claim-and-run attempts so far. `None` for legacy rows."},"backup_id":{"type":"integer","format":"int32","description":"DB id of the `backups` row."},"backup_uuid":{"type":"string","description":"UUID string (`backups.backup_id`)."},"current_step":{"type":["string","null"],"description":"Last completed step reported by the engine (e.g. `\"upload\"`).\n`None` when no step has been persisted yet."},"error_message":{"type":["string","null"],"description":"Engine-reported error message when `state = \"failed\"`."},"finished_at":{"type":["string","null"],"description":"When the backup finished, if known."},"job_id":{"type":["integer","null"],"format":"int64","description":"Most recent `backup_jobs.id` for this backup. `None` for legacy rows."},"s3_location":{"type":"string","description":"S3 object key or URL where the backup data lives."},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Final size in bytes once completed. `None` while running."},"started_at":{"type":"string","description":"When the backup was started (ISO 8601 / RFC 3339)."},"state":{"type":"string","description":"Current state: `\"pending\"`, `\"running\"`, `\"completed\"`, `\"failed\"`."}}},"ScheduleRunJobEntry":{"type":"object","description":"A single job entry inside an expanded schedule run, returned by\n[`BackupService::list_schedule_run_jobs`].","required":["backup_id","backup_uuid","engine","service_name","state","started_at","s3_source_id"],"properties":{"backup_id":{"type":"integer","format":"int32","description":"`backups.id` for this job."},"backup_uuid":{"type":"string","description":"`backups.backup_id` UUID string."},"engine":{"type":"string","description":"Engine key (e.g. `\"control_plane\"`, `\"redis\"`)."},"error_message":{"type":["string","null"],"description":"Engine-reported error message when `state = \"failed\"`."},"finished_at":{"type":["string","null"],"description":"When this child backup finished, if known."},"s3_source_id":{"type":"integer","format":"int32","description":"FK to `s3_sources.id` — needed for the backup detail link."},"service_id":{"type":["integer","null"],"format":"int32","description":"`external_services.id` — `NULL` for the control-plane job."},"service_name":{"type":"string","description":"Name of the external service, or `\"control plane\"` for the\ncontrol-plane job."},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Size in bytes once completed; `None` while running."},"started_at":{"type":"string","description":"When this child backup started (ISO 8601 / RFC 3339)."},"state":{"type":"string","description":"Current state of this child backup."}}},"ScheduleRunListResponse":{"type":"object","description":"Paginated run-history response for a backup schedule (deliverable 1).","required":["runs","total","page","page_size"],"properties":{"page":{"type":"integer","format":"int64","description":"Current page (1-based)."},"page_size":{"type":"integer","format":"int64","description":"Number of items per page (clamped to 1–100)."},"runs":{"type":"array","items":{"$ref":"#/components/schemas/ScheduleRunEntry"},"description":"Run entries, newest first."},"total":{"type":"integer","format":"int64","description":"Total number of runs across all pages."}}},"ScheduleRunResponse":{"type":"object","description":"HTTP response body for `POST /api/backups/schedules/{id}/run` (fan-out).","required":["schedule_run_id","jobs"],"properties":{"jobs":{"type":"array","items":{"$ref":"#/components/schemas/EnqueuedJob"},"description":"All jobs that were enqueued in this fan-out."},"schedule_run_id":{"type":"integer","format":"int64","description":"The `schedule_runs.id` of the newly created run."}}},"ScheduleRunSummary":{"type":"object","description":"Summary of one scheduler tick (or one \"Run now\" click), returned by\n[`BackupService::list_schedule_runs`].\n\nThe `aggregate_state` is computed at read time from child backup counts:\n- `\"running\"` — at least one child is `\"pending\"` or `\"running\"`.\n- `\"failed\"` — at least one child is `\"failed\"` and none are running.\n- `\"completed\"` — all children are `\"completed\"`.","required":["run_id","schedule_id","triggered_by","started_at","aggregate_state","total_jobs","completed_jobs","failed_jobs","running_jobs","pending_jobs"],"properties":{"aggregate_state":{"type":"string","description":"Aggregate state computed from child counts (see struct docs)."},"completed_jobs":{"type":"integer","format":"int64","description":"Number of children in `state = \"completed\"`."},"failed_jobs":{"type":"integer","format":"int64","description":"Number of children in `state = \"failed\"`."},"finished_at":{"type":["string","null"],"description":"When all children reached a terminal state. `None` while any child is\nstill `\"pending\"` or `\"running\"`."},"pending_jobs":{"type":"integer","format":"int64","description":"Number of children in `state = \"pending\"`."},"run_id":{"type":"integer","format":"int64","description":"`schedule_runs.id` for this tick."},"running_jobs":{"type":"integer","format":"int64","description":"Number of children in `state = \"running\"`."},"schedule_id":{"type":"integer","format":"int32","description":"FK to `backup_schedules.id`."},"started_at":{"type":"string","description":"When the fan-out started (ISO 8601 / RFC 3339)."},"total_jobs":{"type":"integer","format":"int64","description":"Total number of child backup jobs in this run."},"triggered_by":{"type":"string","description":"How the run was triggered: `\"cron\"` or `\"manual\"`."}}},"ScheduleRunSummaryList":{"type":"object","description":"Paginated list of schedule run summaries returned by the new\n[`BackupService::list_schedule_runs`].","required":["runs","total","page","page_size"],"properties":{"page":{"type":"integer","format":"int64","description":"Current page (1-based)."},"page_size":{"type":"integer","format":"int64","description":"Number of items per page."},"runs":{"type":"array","items":{"$ref":"#/components/schemas/ScheduleRunSummary"},"description":"Run summaries, newest first. Includes synthetic single-job rows for\nlegacy `backups` rows that have `schedule_id` set but no\n`schedule_run_id` (pre-fan-out history)."},"total":{"type":"integer","format":"int64","description":"Total number of run entries across all pages."}}},"ScreenshotSettings":{"type":"object","properties":{"enabled":{"type":"boolean","default":false},"provider":{"type":"string","default":"local"},"url":{"type":"string","default":""}}},"SearchLogsRequest":{"type":"object","required":["project_id"],"properties":{"container_ids":{"type":"array","items":{"type":"string"},"description":"Filter to specific containers (Docker container IDs). Empty = all\ncontainers. Drives \"filter by container / show all\" in a project's\nhistory, which spans multiple deployments and containers."},"context_lines":{"type":["integer","null"],"format":"int32","description":"grep -C: number of raw context lines to include before and after each\nmatch (0 = none, default). Clamped to 50 server-side. The surrounding\nlines ignore the level/text filters — they are the actual adjacent log\nlines, merged across overlapping matches.","minimum":0},"cursor":{"type":["string","null"],"description":"Pagination cursor"},"deploy_id":{"type":["integer","null"],"format":"int32","description":"Filter by deployment ID (deployments.id)"},"end_time":{"type":["string","null"],"description":"End of time range (ISO 8601). Defaults to now."},"envs":{"type":"array","items":{"type":"string"},"description":"Filter by environments"},"external_service_id":{"type":["integer","null"],"format":"int32","description":"When set, search an imported/managed external service's logs instead\nof a project's. `project_id` is ignored in this mode."},"levels":{"type":"array","items":{"type":"string"},"description":"Filter by log levels"},"node_ids":{"type":"array","items":{"type":"integer","format":"int32"},"description":"Filter to specific worker nodes (node_id). Empty = all nodes, including\ncontrol-plane-local logs."},"page_size":{"type":["integer","null"],"format":"int32","description":"Page size (default: 100, max: 500)","minimum":0},"project_id":{"type":"integer","format":"int32","description":"Project ID (integer, as used by the rest of the platform)"},"services":{"type":"array","items":{"type":"string"},"description":"Filter by services"},"start_time":{"type":["string","null"],"description":"Start of time range (ISO 8601). Defaults to 1 hour ago."},"text":{"type":["string","null"],"description":"Full text search query"}}},"SearchLogsResponse":{"type":"object","required":["lines","search_mode","total_scanned"],"properties":{"available_sources":{"type":"array","items":{"$ref":"#/components/schemas/LogSource"},"description":"Distinct containers/nodes/services available in the queried scope, for\nthe filter dropdowns. Populated on the first page (no cursor)."},"lines":{"type":"array","items":{"$ref":"#/components/schemas/LogSearchLine"}},"next_cursor":{"type":["string","null"]},"search_mode":{"$ref":"#/components/schemas/SearchMode"},"total_scanned":{"type":"integer","format":"int64","minimum":0}}},"SearchMode":{"type":"string","description":"Search execution mode","enum":["index","archive"]},"Seasonality":{"type":"string","description":"Seasonality model for an anomaly baseline.","enum":["none","hourly","daily","weekly"]},"SecretResponse":{"type":"object","required":["id","name","secret_type","value","created_at","updated_at"],"properties":{"created_at":{"type":"string"},"description":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"mount_path":{"type":["string","null"]},"name":{"type":"string"},"secret_type":{"type":"string"},"updated_at":{"type":"string"},"value":{"type":"string","description":"Always masked in responses"}}},"SecurityConfig":{"type":"object","description":"Security configuration for projects and environments\n\nThis configuration can be set at three levels:\n1. Global (in settings table) - applies to all projects\n2. Project level - overrides global settings for specific project\n3. Environment level - overrides project settings for specific environment\n\nThe inheritance chain: Environment > Project > Global","properties":{"attackMode":{"type":["string","null"],"description":"Attack mode configuration (future: \"off\", \"challenge\", \"block\")\nPlaceholder for DDoS protection, bot detection, etc."},"challengeConfig":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ChallengeConfig","description":"Challenge configuration (future: CAPTCHA, JS challenge, etc.)"}]},"enabled":{"type":["boolean","null"],"description":"Enable/disable security features at this level\nIf None, inherits from parent level"},"geoRestrictions":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/GeoRestrictionsConfig","description":"Geographic restrictions (future: country blocking, etc.)"}]},"headers":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SecurityHeadersConfig","description":"Security headers configuration"}]},"passwordProtection":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PasswordProtectionConfig","description":"Password protection: shows an HTML password form before allowing access"}]},"rateLimiting":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/RateLimitConfig","description":"Rate limiting configuration"}]}}},"SecurityHeadersConfig":{"type":"object","description":"Security headers configuration (subset of global SecurityHeadersSettings)","properties":{"contentSecurityPolicy":{"type":["string","null"],"description":"Custom CSP (only used if preset is \"custom\")"},"preset":{"type":["string","null"],"description":"Use a preset: \"strict\", \"moderate\", \"permissive\", \"disabled\", \"custom\""},"referrerPolicy":{"type":["string","null"],"description":"Referrer-Policy override"},"strictTransportSecurity":{"type":["string","null"],"description":"HSTS override"},"xFrameOptions":{"type":["string","null"],"description":"X-Frame-Options override"}}},"SecurityHeadersSettings":{"type":"object","properties":{"content_security_policy":{"type":["string","null"],"default":"default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self'; frame-ancestors 'self'"},"enabled":{"type":"boolean","default":false},"permissions_policy":{"type":["string","null"],"default":"geolocation=(), microphone=(), camera=()"},"preset":{"type":"string","default":"moderate"},"referrer_policy":{"type":"string","default":"strict-origin-when-cross-origin"},"strict_transport_security":{"type":"string","default":"max-age=31536000; includeSubDomains"},"x_content_type_options":{"type":"string","default":"nosniff"},"x_frame_options":{"type":"string","default":"SAMEORIGIN"},"x_xss_protection":{"type":"string","default":"1; mode=block"}}},"SelfUpdateAttempt":{"type":"object","description":"A single update attempt. Persisted to `/self-update.json` so the\nresult survives the restart it causes.","required":["from_version","status","started_at"],"properties":{"error":{"type":["string","null"],"description":"Operator-facing failure reason. Always set when `status` is `Failed`."},"finished_at":{"type":["string","null"],"format":"date-time","description":"When the outcome was decided. `None` while still `Pending`."},"from_version":{"type":"string","description":"Version the attempt started from."},"previous_binary_path":{"type":["string","null"],"description":"Where the replaced binary was kept, so a bad release can be reverted by\nhand (`mv `). Set once the swap completes."},"started_at":{"type":"string","format":"date-time","example":"2026-08-06T09:12:31Z"},"status":{"$ref":"#/components/schemas/SelfUpdateStatus"},"to_version":{"type":["string","null"],"description":"Version the attempt targeted. `None` if it failed before resolving one."},"triggered_by_user_id":{"type":["integer","null"],"format":"int32","description":"User who clicked the button. `None` for attempts started by the CLI."}}},"SelfUpdateBlocker":{"type":"string","description":"Why a one-click update is unavailable. Exactly one is reported — the most\nfundamental blocker wins, so the operator fixes the real problem first\nrather than clearing one only to hit the next.","enum":["disabled_by_flag","disabled_by_setting","not_supported","binary_not_writable","unsupported_platform","in_progress"]},"SelfUpdatePhase":{"type":"string","description":"Where an in-flight update has got to. Polled by the console so a long\ndownload shows progress instead of an indefinite spinner.","enum":["idle","resolving","downloading","verifying","installing","restarting","pending_restart","failed"]},"SelfUpdateRestartMode":{"type":"string","description":"What happens to the running process once the new binary is in place.","enum":["automatic","manual"]},"SelfUpdateSettings":{"type":"object","description":"Controls the console's one-click \"Update now\" action.","properties":{"channel":{"type":["string","null"],"description":"Release channel this install tracks: `stable`, `beta` or `nightly`.\n\n`None` (the default) means \"infer from the running version tag\", which\nis what the CLI has always done — a `-nightly.` build tracks nightly, a\n`-beta.N` build tracks beta, a plain tag tracks stable. Setting it\nexplicitly pins the channel, so an operator can move a nightly box back\nonto stable without reinstalling.","default":null,"example":"stable"},"enabled":{"type":"boolean","description":"Allow admins to apply a release and restart the server from the console.\n`true` by default: the action is permission-gated, audited, and only\never installs an official release whose published SHA-256 matches.\n\nTurning this off hides nothing — the console still shows the update\nbanner and the manual command, it just refuses to run it for you.","default":true,"example":true}}},"SelfUpdateStatus":{"type":"string","description":"Outcome of an update attempt, as persisted in the journal.","enum":["pending","succeeded","installed_pending_restart","failed"]},"SendEmailRequestBody":{"type":"object","required":["from","to","subject"],"properties":{"bcc":{"type":["array","null"],"items":{"type":"string"},"description":"BCC recipients"},"cc":{"type":["array","null"],"items":{"type":"string"},"description":"CC recipients"},"from":{"type":"string","description":"Sender email address (domain will be auto-extracted for lookup)","example":"hello@updates.example.com"},"from_name":{"type":["string","null"],"description":"Sender display name","example":"My App"},"headers":{"type":["object","null"],"description":"Custom headers","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"html":{"type":["string","null"],"description":"HTML body content","example":"

Hello World

"},"reply_to":{"type":["string","null"],"description":"Reply-to address"},"subject":{"type":"string","description":"Email subject","example":"Welcome to our platform!"},"tags":{"type":["array","null"],"items":{"type":"string"},"description":"Tags for categorization","example":["welcome","onboarding"]},"text":{"type":["string","null"],"description":"Plain text body content","example":"Hello World"},"to":{"type":"array","items":{"type":"string"},"description":"Recipient email addresses","example":["user@example.com"]},"track_clicks":{"type":["boolean","null"],"description":"Enable click tracking (link rewriting). Defaults to false."},"track_opens":{"type":["boolean","null"],"description":"Enable open tracking (tracking pixel injection). Defaults to false."}}},"SendEmailResponseBody":{"type":"object","required":["id","status"],"properties":{"id":{"type":"string","description":"Email ID","example":"550e8400-e29b-41d4-a716-446655440000"},"provider_message_id":{"type":["string","null"],"description":"Provider message ID"},"status":{"type":"string","description":"Email status","example":"sent"}}},"SendMessageRequest":{"type":"object","required":["content"],"properties":{"content":{"type":"string"},"page_context":{"type":["string","null"],"description":"Optional, client-supplied description of the page/entity the user is\ncurrently viewing (e.g. a trace in a project). Injected into the model's\nview of this turn only — never stored or shown in history. Capped server\nside; oversized values are ignored rather than rejected."}}},"SensitiveConfigValueResponse":{"type":"object","required":["value"],"properties":{"value":{"type":"string"}}},"SensitiveMcpConfigValueResponse":{"type":"object","required":["value"],"properties":{"value":{"type":"string"}}},"SensitiveValueResponse":{"type":"object","required":["value"],"properties":{"value":{"type":"string"}}},"SentryChunkUploadResponse":{"type":"object","required":["url","chunkSize","chunksPerRequest","maxFileSize","maxRequestSize","concurrency","hashAlgorithm","compression","accept"],"properties":{"accept":{"type":"array","items":{"type":"string"}},"chunkSize":{"type":"integer","format":"int64","minimum":0},"chunksPerRequest":{"type":"integer","format":"int32","minimum":0},"compression":{"type":"array","items":{"type":"string"}},"concurrency":{"type":"integer","format":"int32","minimum":0},"hashAlgorithm":{"type":"string"},"maxFileSize":{"type":"integer","format":"int64","minimum":0},"maxRequestSize":{"type":"integer","format":"int64","minimum":0},"url":{"type":"string"}}},"SentryCreateReleaseRequest":{"type":"object","required":["version"],"properties":{"projects":{"type":"array","items":{"type":"string"},"description":"Project slugs this release belongs to"},"version":{"type":"string","description":"Release version identifier"}}},"SentryEventRequest":{"type":"object","properties":{"event_id":{"type":["string","null"]},"message":{"type":["string","null"]},"platform":{"type":["string","null"]},"timestamp":{"type":["string","null"]}}},"SentryEventResponse":{"type":"object","required":["id"],"properties":{"id":{"type":"string"}}},"SentryReleaseFileResponse":{"type":"object","required":["id","name","headers","size","sha1","dateCreated"],"properties":{"dateCreated":{"type":"string"},"dist":{"type":["string","null"]},"headers":{},"id":{"type":"string"},"name":{"type":"string"},"sha1":{"type":"string"},"size":{"type":"integer","format":"int64"}}},"SentryReleaseProjectRef":{"type":"object","required":["name","slug"],"properties":{"name":{"type":"string"},"slug":{"type":"string"}}},"SentryReleaseResponse":{"type":"object","required":["version","dateCreated","shortVersion","projects"],"properties":{"dateCreated":{"type":"string"},"dateReleased":{"type":["string","null"]},"projects":{"type":"array","items":{"$ref":"#/components/schemas/SentryReleaseProjectRef"}},"shortVersion":{"type":"string"},"version":{"type":"string"}}},"SeriesStateEntry":{"type":"object","description":"One series' persisted state snapshot for a dynamic rule (ADR-026 follow-up):\nthe state after the latest tick, the value evaluated this tick, and the open\nalarm id (when firing). Serialized into the `series_states` jsonb column keyed\nby the human-readable [`series_label`]; the alert response decodes it back.","required":["state","value"],"properties":{"alarm_id":{"type":["integer","null"],"format":"int32","description":"The open alarm's id when the series is firing; `null` when ok."},"state":{"type":"string","description":"`firing` or `ok` for this series after the latest tick."},"value":{"type":"number","format":"double","description":"The value the rule evaluated for this series this tick."}}},"ServiceAccessInfo":{"type":"object","description":"Response containing information about how the service is being accessed","required":["access_mode","can_create_domains"],"properties":{"access_mode":{"type":"string","description":"Mode of access: \"local\", \"direct\", \"nat\", or \"cloudflare_tunnel\""},"can_create_domains":{"type":"boolean","description":"Whether domain creation is allowed in this mode"},"domain_creation_error":{"type":["string","null"],"description":"Error message if domain creation is not allowed"},"private_ip":{"type":["string","null"],"description":"Server's private/local IP address (always returned if available)"},"public_ip":{"type":["string","null"],"description":"Server's public IP address (always returned if available)"}}},"ServiceAction":{"type":"string","description":"What to do with a service during migration","enum":["create","link-external","skip"]},"ServiceAlertRuleResponse":{"type":"object","description":"Wire representation of a monitoring alert rule.\n\nRegistered under a domain-prefixed OpenAPI schema name to avoid colliding\nwith `temps-error-tracking`'s unrelated `AlertRuleResponse` (utoipa keys\nschemas by their bare struct name, so without `as = ...` the last crate to\nregister would silently shadow this one in the merged spec / generated SDK).","required":["id","name","metric_name","threshold","comparator","severity","for_duration_secs","enabled"],"properties":{"comparator":{"type":"string"},"deployment_id":{"type":["integer","null"],"format":"int32"},"enabled":{"type":"boolean"},"for_duration_secs":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"metric_name":{"type":"string"},"name":{"type":"string"},"service_id":{"type":["integer","null"],"format":"int32"},"severity":{"type":"string"},"silenced_until":{"type":["string","null"]},"threshold":{"type":"number","format":"double"}}},"ServiceBackupEntryResponse":{"type":"object","description":"A single backup entry in the per-service backup list.","required":["id","backup_id","name","state","backup_type","started_at","s3_location","compression_type","s3_source_id","s3_source_name","external_service_backup_id"],"properties":{"backup_id":{"type":"string","description":"UUID string assigned at backup creation time."},"backup_type":{"type":"string","description":"Backup variant (e.g. \"full\", \"incremental\")."},"compression_type":{"type":"string","description":"Compression algorithm used (e.g. \"gzip\")."},"error_message":{"type":["string","null"],"description":"Engine-reported error message, populated when `state = \"failed\"`."},"external_service_backup_id":{"type":"integer","format":"int32","description":"Row ID from `external_service_backups`."},"finished_at":{"type":["string","null"],"description":"ISO 8601 timestamp when the backup finished, if known.","example":"2025-01-15T14:35:00Z"},"id":{"type":"integer","format":"int32","description":"Row ID from the `backups` table."},"name":{"type":"string","description":"Human-friendly display name."},"s3_location":{"type":"string","description":"Object key or `s3://` URL for the backup data."},"s3_source_id":{"type":"integer","format":"int32","description":"FK to `s3_sources.id`."},"s3_source_name":{"type":"string","description":"Human-readable name of the S3 source."},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Size of the backup in bytes, if available."},"started_at":{"type":"string","description":"ISO 8601 timestamp when the backup started.","example":"2025-01-15T14:30:00Z"},"state":{"type":"string","description":"Current state: \"completed\", \"running\", \"failed\"."}}},"ServiceBackupListResponse":{"type":"object","description":"Paginated list of backups for a specific external service.\n\nReturned by `GET /backups/external-services/{service_id}/backups`.","required":["backups","total","page","page_size"],"properties":{"backups":{"type":"array","items":{"$ref":"#/components/schemas/ServiceBackupEntryResponse"},"description":"Backups belonging to this service, newest first."},"page":{"type":"integer","format":"int64","description":"Current page (1-based)."},"page_size":{"type":"integer","format":"int64","description":"Number of items per page."},"total":{"type":"integer","format":"int64","description":"Total number of backups for this service across all pages."}}},"ServiceCreateAlertRuleRequest":{"type":"object","description":"Request body for creating an alert rule on an external service.\n\nDomain-prefixed schema name — see [`AlertRuleResponse`] for why.","required":["name","metric_name","threshold","comparator","severity"],"properties":{"comparator":{"type":"string","description":"One of `>`, `<`, `>=`, `<=`."},"enabled":{"type":"boolean"},"for_duration_secs":{"type":"integer","format":"int32","description":"Seconds the breach must persist before the alarm fires (0 = immediate)."},"metric_name":{"type":"string"},"name":{"type":"string"},"severity":{"type":"string","description":"`\"warning\"` or `\"critical\"`."},"threshold":{"type":"number","format":"double"}}},"ServiceHealthResponse":{"type":"object","required":["service_id","consecutive_failures","recent_checks"],"properties":{"consecutive_failures":{"type":"integer","format":"int32","description":"Consecutive failed probes. Alert fires at 3."},"last_checked_at":{"type":["string","null"]},"last_error":{"type":["string","null"]},"recent_checks":{"type":"array","items":{"$ref":"#/components/schemas/HealthCheckEntryResponse"},"description":"Most recent checks, newest-first (capped at `limit`)."},"response_time_ms":{"type":["integer","null"],"format":"int32"},"service_id":{"type":"integer","format":"int32"},"status":{"type":["string","null"],"description":"Current health. `null` if the service has not been probed yet.","example":"operational"},"uptime_24h_percent":{"type":["number","null"],"format":"double","description":"Uptime percentage over the last 24 hours (0.0 — 100.0).\n`null` when there is not enough history."}}},"ServiceHealthStatusBatchResponse":{"type":"object","required":["statuses"],"properties":{"statuses":{"type":"array","items":{"$ref":"#/components/schemas/ServiceHealthStatusEntryResponse"}}}},"ServiceHealthStatusEntryResponse":{"type":"object","required":["service_id","consecutive_failures"],"properties":{"consecutive_failures":{"type":"integer","format":"int32"},"last_checked_at":{"type":["string","null"]},"service_id":{"type":"integer","format":"int32"},"status":{"type":["string","null"],"description":"\"operational\" | \"degraded\" | \"down\". `null` when the service has not\nbeen probed yet.","example":"operational"}}},"ServiceMemberInfo":{"type":"object","description":"Public info about a cluster member.","required":["id","role","container_name","status","ordinal"],"properties":{"compute_ip":{"type":["string","null"],"description":"Container's IP on the `temps-overlay` multi-host network. Populated\nby the lifecycle hook (ADR-011 Phase 3); `None` on single-host\nclusters where the overlay isn't attached."},"container_name":{"type":"string"},"hostname":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"live_state":{"type":["string","null"],"description":"Live FSM state from the pg_auto_failover monitor (`primary`,\n`secondary`, `catchingup`, `report_lsn`, …). `None` when the\nmonitor is unreachable, the service is not a cluster, or the row\nis the monitor itself.\n\n**The UI must render the role badge from this field**, falling\nback to `role` only when `live_state` is null. `role` is now\nconfig-only (`monitor` or `replica`); flipping the badge to\n\"primary\" when the monitor elects a new one used to require a\nreconciler that lagged ~5s behind real failovers — and during\nthat window the UI showed two primaries. `live_state` is read\ndirectly from the monitor on every list, so it can never lag."},"node_id":{"type":["integer","null"],"format":"int32"},"ordinal":{"type":"integer","format":"int32"},"port":{"type":["integer","null"],"format":"int32"},"provisioning_error":{"type":["string","null"],"description":"Most recent provisioning failure message, when `status='failed'`.\nSet by the background task so the UI can show *why* the new\nreplica didn't come up."},"provisioning_step":{"type":["string","null"],"description":"Last-attempted phase of the async `add_cluster_member` background\ntask (e.g. `validating`, `provisioning_container`, `done`,\n`failed`). `None` for members not created through that flow —\nthe UI falls back to the `status` column for those."},"role":{"type":"string"},"status":{"type":"string"}}},"ServiceParameter":{"type":"object","required":["name","required","encrypted","description"],"properties":{"choices":{"type":["array","null"],"items":{"type":"string"}},"default_value":{"type":["string","null"]},"description":{"type":"string"},"encrypted":{"type":"boolean"},"name":{"type":"string"},"required":{"type":"boolean"},"validation_pattern":{"type":["string","null"]}}},"ServicePlan":{"type":"object","description":"Plan for migrating a single service (database, cache, etc.)","required":["name","service_type","action","action_description"],"properties":{"action":{"$ref":"#/components/schemas/ServiceAction","description":"What to do with this service"},"action_description":{"type":"string","description":"Human-readable explanation of what this action means"},"data_implications":{"type":"array","items":{"$ref":"#/components/schemas/DataImplication"},"description":"Data implications specific to this service"},"env_var_mappings":{"type":"object","description":"Environment variable key mappings: source_key -> temps_key\n\nFor example, Vercel's `POSTGRES_URL` might map to Temps' `DATABASE_URL`.\nBoth keys will be set during migration so the app works with either.","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"name":{"type":"string","description":"Human-readable service name"},"parameters":{"type":"object","description":"Parameters for creating the service in Temps","additionalProperties":{},"propertyNames":{"type":"string"}},"service_type":{"type":"string","description":"Service type (maps to temps-providers ServiceType)"},"version":{"type":["string","null"],"description":"Service version to create (e.g., \"16\" for Postgres 16)"}}},"ServiceResourceLimits":{"type":"object","description":"Optional cgroup resource limits applied to a service container.\n\nAll fields are `Option`: `None` means \"no limit\" (the kernel default),\nmatching Docker's behavior when the corresponding `HostConfig` field is\nleft at zero. Operators opt in to limits explicitly through the\n`PATCH /external-services/{id}/resources` endpoint or by writing the\n`resources` block into `ServiceConfig::parameters` at create time.\n\nThese map directly onto bollard fields:\n- `memory_mb` → `HostConfig.memory` (bytes)\n- `memory_swap_mb`→ `HostConfig.memory_swap` (bytes; ≥ memory)\n- `nano_cpus` → `HostConfig.nano_cpus` (1e9 = 1 full CPU)\n- `cpu_shares` → `HostConfig.cpu_shares` (relative weight, default 1024)\n- `shm_size_mb` → `HostConfig.shm_size` (bytes; default 64 MiB)\n\nIMPORTANT: enabling hard memory limits causes the kernel OOM killer to\nterminate the container when the working set exceeds the limit. The\ncontainer will restart (RestartPolicy::ALWAYS) but in-flight queries\nfail. Surface this clearly in any UI that lets users set limits.","properties":{"cpu_shares":{"type":["integer","null"],"format":"int64","description":"Relative CPU weight (default 1024). Only used when `nano_cpus` is None."},"memory_mb":{"type":["integer","null"],"format":"int64","description":"Hard memory limit in MiB. None = unlimited."},"memory_swap_mb":{"type":["integer","null"],"format":"int64","description":"Memory + swap limit in MiB. None = unlimited.\nMUST be >= memory_mb when both are set; Docker rejects the request otherwise.\nSet equal to `memory_mb` to disable swap entirely."},"nano_cpus":{"type":["integer","null"],"format":"int64","description":"CPU quota in nano-cpus. 1_000_000_000 = 1 full CPU core. None = unlimited."},"shm_size_mb":{"type":["integer","null"],"format":"int64","description":"Shared memory (/dev/shm) size in MiB. None = Docker default (64 MiB).\nMaps to HostConfig.shm_size (bytes). PostgreSQL uses /dev/shm for parallel\nquery workers and large work_mem; the 64 MiB default causes \"could not\nresize shared memory segment ... No space left on device\" under load.\nNOTE: shm_size is fixed at container-create time — Docker's live update\nAPI cannot change it, so changing this value recreates the container."}}},"ServiceRuntimeReport":{"type":"object","description":"Aggregate runtime info for an external service. For standalone services,\n`members` has exactly one entry. For clusters, one entry per member.","required":["service_id","topology","members"],"properties":{"members":{"type":"array","items":{"$ref":"#/components/schemas/ContainerRuntimeInfo"}},"service_id":{"type":"integer","format":"int32"},"topology":{"type":"string"}}},"ServiceStatsReport":{"type":"object","required":["service_id","topology","members"],"properties":{"members":{"type":"array","items":{"$ref":"#/components/schemas/ContainerStatsSample"}},"service_id":{"type":"integer","format":"int32"},"topology":{"type":"string"}}},"ServiceTypeInfo":{"type":"object","required":["service_type","parameters"],"properties":{"parameters":{"type":"array","items":{"$ref":"#/components/schemas/ServiceParameter"},"example":"[{\"name\": \"host\", \"required\": true, \"encrypted\": false, \"description\": \"Database host\"}]"},"service_type":{"$ref":"#/components/schemas/ServiceTypeRoute"}}},"ServiceTypeRoute":{"type":"string","enum":["mariadb","mongodb","postgres","redis","s3","kv","blob","rustfs","minio"]},"ServiceUpdateAlertRuleRequest":{"type":"object","description":"Request body for updating an existing alert rule.\n\nDomain-prefixed schema name — see [`AlertRuleResponse`] for why.","properties":{"comparator":{"type":["string","null"]},"enabled":{"type":["boolean","null"]},"for_duration_secs":{"type":["integer","null"],"format":"int32"},"metric_name":{"type":["string","null"]},"name":{"type":["string","null"]},"severity":{"type":["string","null"]},"threshold":{"type":["number","null"],"format":"double"}}},"SesCredentialsRequest":{"type":"object","required":["access_key_id","secret_access_key"],"properties":{"access_key_id":{"type":"string","example":"AKIAIOSFODNN7EXAMPLE"},"secret_access_key":{"type":"string","example":"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"}}},"SessionDetails":{"type":"object","required":["session_id","visitor_id","started_at","duration_seconds","is_bounced","is_engaged","page_views"],"properties":{"duration_seconds":{"type":"integer","format":"int64"},"ended_at":{"type":["string","null"],"format":"date-time","example":"2024-01-01T00:00:00"},"entry_path":{"type":["string","null"]},"exit_path":{"type":["string","null"]},"is_bounced":{"type":"boolean"},"is_engaged":{"type":"boolean"},"page_views":{"type":"integer","format":"int64"},"referrer":{"type":["string","null"]},"session_id":{"type":"integer","format":"int32"},"started_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"visitor_id":{"type":"string"}}},"SessionDetailsQuery":{"type":"object","required":["project_id"],"properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"}}},"SessionEvent":{"type":"object","required":["id","timestamp"],"properties":{"event_data":{},"event_name":{"type":["string","null"]},"event_type":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"page_title":{"type":["string","null"]},"page_url":{"type":["string","null"]},"timestamp":{"type":"string"}}},"SessionEventDto":{"type":"object","required":["id","session_id","data","timestamp"],"properties":{"data":{},"event_type":{"type":["integer","null"],"format":"int32"},"id":{"type":"integer","format":"int32"},"session_id":{"type":"integer","format":"int32"},"timestamp":{"type":"integer","format":"int64"}}},"SessionEventsQuery":{"type":"object","required":["project_id"],"properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"}}},"SessionEventsResponse":{"type":"object","required":["session_id","events","total_count","offset","limit"],"properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/SessionEvent"}},"limit":{"type":"integer","format":"int32"},"offset":{"type":"integer","format":"int32"},"session_id":{"type":"integer","format":"int32"},"total_count":{"type":"integer","format":"int64"}}},"SessionLogsQuery":{"type":"object","required":["project_id"],"properties":{"end_date":{"type":["string","null"],"format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32"},"offset":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"sort_order":{"type":["string","null"]},"start_date":{"type":["string","null"],"format":"date-time"},"visitor_id":{"type":["integer","null"],"format":"int32"}}},"SessionLogsResponse":{"type":"object","required":["session_id","logs","total_count","offset","limit"],"properties":{"limit":{"type":"integer","format":"int32"},"logs":{"type":"array","items":{"$ref":"#/components/schemas/SessionRequestLog"}},"offset":{"type":"integer","format":"int32"},"session_id":{"type":"integer","format":"int32"},"total_count":{"type":"integer","format":"int64"}}},"SessionReplayEventsRequest":{"type":"object","required":["sessionId","events"],"properties":{"events":{"type":"string"},"sessionId":{"type":"string"}}},"SessionReplayInfoDto":{"type":"object","required":["id","visitor_id"],"properties":{"created_at":{"type":["string","null"]},"duration":{"type":["integer","null"],"format":"int32"},"id":{"type":"string"},"language":{"type":["string","null"]},"screen_height":{"type":["integer","null"],"format":"int32"},"screen_width":{"type":["integer","null"],"format":"int32"},"timezone":{"type":["string","null"]},"url":{"type":["string","null"]},"user_agent":{"type":["string","null"]},"viewport_height":{"type":["integer","null"],"format":"int32"},"viewport_width":{"type":["integer","null"],"format":"int32"},"visitor_id":{"type":"integer","format":"int32"}}},"SessionReplayInitRequest":{"type":"object","required":["sessionId"],"properties":{"colorDepth":{"type":["integer","null"],"format":"int32","minimum":0},"language":{"type":["string","null"]},"screenHeight":{"type":["integer","null"],"format":"int32","minimum":0},"screenWidth":{"type":["integer","null"],"format":"int32","minimum":0},"sessionId":{"type":"string"},"timestamp":{"type":["string","null"]},"timezone":{"type":["string","null"]},"url":{"type":["string","null"]},"userAgent":{"type":["string","null"]},"viewportHeight":{"type":["integer","null"],"format":"int32","minimum":0},"viewportWidth":{"type":["integer","null"],"format":"int32","minimum":0}}},"SessionReplayInitResponse":{"type":"object","required":["session_id","message"],"properties":{"message":{"type":"string"},"session_id":{"type":"string"}}},"SessionReplayWithEventsDto":{"type":"object","required":["session","events"],"properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/SessionEventDto"}},"session":{"$ref":"#/components/schemas/SessionReplayWithVisitorDto"}}},"SessionReplayWithVisitorDto":{"type":"object","required":["id","session_replay_id","visitor_id","visitor_uuid","visitor_project_id","visitor_environment_id","visitor_first_seen","visitor_last_seen","visitor_is_crawler"],"properties":{"browser":{"type":["string","null"]},"browser_version":{"type":["string","null"]},"created_at":{"type":["string","null"]},"device_type":{"type":["string","null"]},"duration":{"type":["integer","null"],"format":"int32"},"id":{"type":"integer","format":"int32"},"language":{"type":["string","null"]},"operating_system":{"type":["string","null"]},"operating_system_version":{"type":["string","null"]},"screen_height":{"type":["integer","null"],"format":"int32"},"screen_width":{"type":["integer","null"],"format":"int32"},"session_replay_id":{"type":"string"},"timezone":{"type":["string","null"]},"url":{"type":["string","null"]},"user_agent":{"type":["string","null"]},"viewport_height":{"type":["integer","null"],"format":"int32"},"viewport_width":{"type":["integer","null"],"format":"int32"},"visitor_city":{"type":["string","null"]},"visitor_country":{"type":["string","null"]},"visitor_country_code":{"type":["string","null"]},"visitor_crawler_name":{"type":["string","null"]},"visitor_custom_data":{},"visitor_environment_id":{"type":"integer","format":"int32"},"visitor_first_seen":{"type":"string"},"visitor_id":{"type":"integer","format":"int32"},"visitor_is_crawler":{"type":"boolean"},"visitor_last_seen":{"type":"string"},"visitor_project_id":{"type":"integer","format":"int32"},"visitor_region":{"type":["string","null"]},"visitor_uuid":{"type":"string"}}},"SessionRequestLog":{"type":"object","required":["id","method","path","status_code","created_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"id":{"type":"integer","format":"int32"},"method":{"type":"string"},"path":{"type":"string"},"referrer":{"type":["string","null"]},"request_headers":{"type":["string","null"]},"response_headers":{"type":["string","null"]},"response_time_ms":{"type":["integer","null"],"format":"int32"},"status_code":{"type":"integer","format":"int32"},"user_agent":{"type":["string","null"]}}},"SessionSummary":{"type":"object","required":["session_id","started_at","duration_seconds","page_views","events_count","requests_count","is_bounced","is_engaged"],"properties":{"duration_seconds":{"type":"integer","format":"int64"},"ended_at":{"type":["string","null"],"format":"date-time","example":"2024-01-01T00:00:00"},"entry_path":{"type":["string","null"]},"events_count":{"type":"integer","format":"int64"},"exit_path":{"type":["string","null"]},"is_bounced":{"type":"boolean"},"is_engaged":{"type":"boolean"},"page_views":{"type":"integer","format":"int64"},"referrer":{"type":["string","null"]},"requests_count":{"type":"integer","format":"int64"},"session_id":{"type":"integer","format":"int32"},"started_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"}}},"SetFlagEnvironmentRequest":{"type":"object","properties":{"enabled":{"type":["boolean","null"],"description":"The kill switch. `false` makes the flag serve its default regardless of\nany override — and, once targeting exists, regardless of any rule."},"value":{"description":"Tri-state: absent leaves the override, `null` clears it (inherit the\nflag default), anything else sets it. Must match `value_type`."}}},"SetPreviewPasswordBody":{"type":"object","required":["password"],"properties":{"password":{"type":"string","description":"Plaintext password to protect the sandbox's preview URLs. Hashed\nserver-side with argon2id — we never persist or echo this back.\nMust be between 8 and 256 characters."}}},"SetPreviewPasswordResponse":{"type":"object","required":["preview_password_hint"],"properties":{"preview_password_hint":{"type":"string","description":"Last 4 chars of the password we just stored. Surface in the UI so\nusers can confirm which password is live without re-entering it."}}},"SetRequest":{"type":"object","description":"Request to set a value","required":["key","value"],"properties":{"ex":{"type":["integer","null"],"format":"int64","description":"Expire in seconds","example":3600},"key":{"type":"string","description":"The key to set","example":"user:123"},"nx":{"type":"boolean","description":"Only set if key does not exist"},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1},"px":{"type":["integer","null"],"format":"int64","description":"Expire in milliseconds"},"value":{"description":"The value to store (can be any JSON value)"},"xx":{"type":"boolean","description":"Only set if key exists"}}},"SetResponse":{"type":"object","description":"Response for set operation","required":["result"],"properties":{"result":{"type":"string","description":"Always \"OK\" on success","example":"OK"}}},"SettingsUpdateResponse":{"type":"object","description":"Response for successful settings update","required":["message"],"properties":{"message":{"type":"string"}}},"SetupDnsChallengeRequest":{"type":"object","description":"Request to setup DNS challenge records using a configured DNS provider","required":["dns_provider_id"],"properties":{"dns_provider_id":{"type":"integer","format":"int32","description":"The ID of the DNS provider to use for creating the TXT records"}}},"SetupDnsChallengeResponse":{"type":"object","description":"Response from DNS challenge setup operation","required":["success","records_created","total_records","results","message"],"properties":{"message":{"type":"string","description":"Human-readable summary message"},"records_created":{"type":"integer","format":"int32","description":"Number of TXT records that were successfully created","minimum":0},"results":{"type":"array","items":{"$ref":"#/components/schemas/DnsChallengeRecordResult"},"description":"Results for each individual TXT record"},"success":{"type":"boolean","description":"Overall success status (true if all records were created)"},"total_records":{"type":"integer","format":"int32","description":"Total number of TXT records required for the challenge","minimum":0}}},"SetupDnsRequest":{"type":"object","description":"Request to setup DNS records using a configured DNS provider","required":["dns_provider_id"],"properties":{"dns_provider_id":{"type":"integer","format":"int32","description":"The ID of the DNS provider to use for creating records"}}},"SetupDnsResponse":{"type":"object","description":"Response from DNS setup operation","required":["success","records_created","total_records","results","message"],"properties":{"message":{"type":"string","description":"Human-readable summary message"},"records_created":{"type":"integer","format":"int32","description":"Number of records that were successfully created","minimum":0},"results":{"type":"array","items":{"$ref":"#/components/schemas/DnsRecordSetupResult"},"description":"Results for each individual record"},"success":{"type":"boolean","description":"Overall success status"},"total_records":{"type":"integer","format":"int32","description":"Total number of records attempted","minimum":0}}},"SiblingRef":{"type":"object","description":"A sibling project that shares the same `trace_id` and has opted in to\ncross-project trace sharing (`cross_project_trace_sharing = TRUE`).\n\nReturned by `CrossProjectTraceService::find_sibling_projects` and exposed\nby the Phase 1 `GET /otel/traces/cross-project/{trace_id}` endpoint.","required":["project_id","project_name","project_slug","first_seen"],"properties":{"first_seen":{"type":"string","format":"date-time"},"project_id":{"type":"integer","format":"int32"},"project_name":{"type":"string"},"project_slug":{"type":"string","description":"URL slug used to link into the sibling project's single-project trace view."}}},"SkillDefinitionResponse":{"type":"object","required":["id","slug","name","content","has_archive","created_at","updated_at"],"properties":{"content":{"type":"string"},"created_at":{"type":"string"},"description":{"type":["string","null"]},"has_archive":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"project_id":{"type":["integer","null"],"format":"int32"},"slug":{"type":"string"},"updated_at":{"type":"string"}}},"SlackConfig":{"type":"object","required":["webhook_url"],"properties":{"channel":{"type":["string","null"]},"webhook_url":{"type":"string"}}},"SlowQueriesResponse":{"type":"object","description":"Response envelope for the slow-queries list endpoint.","required":["queries","page","page_size","total_count"],"properties":{"page":{"type":"integer","format":"int32","description":"Current page number (1-based).","minimum":0},"page_size":{"type":"integer","format":"int32","description":"Number of rows per page used for this request.","minimum":0},"queries":{"type":"array","items":{"$ref":"#/components/schemas/SlowQueryRow"},"description":"Ordered list of query stats, slowest first by mean_exec_time_ms."},"total_count":{"type":"integer","format":"int64","description":"Total number of qualifying rows across all pages.","minimum":0}}},"SlowQueryRow":{"type":"object","description":"A single entry from `pg_stat_statements`, representing one normalized\nquery fingerprint and its aggregate execution stats.","required":["query","database","calls","total_exec_time_ms","mean_exec_time_ms","rows"],"properties":{"cache_hit_ratio":{"type":["number","null"],"format":"double","description":"Shared block cache hit ratio (0.0–1.0).\n`None` when total block accesses are zero (e.g. function-only queries)."},"calls":{"type":"integer","format":"int64","description":"Number of times this query was executed."},"database":{"type":"string","description":"Name of the database this query ran against. `(dropped database)`\nwhen the originating database no longer exists but\n`pg_stat_statements` still holds stats for it."},"mean_exec_time_ms":{"type":"number","format":"double","description":"Average wall-clock time per execution, in milliseconds."},"query":{"type":"string","description":"Normalized query text (parameter literals replaced with `$N`)."},"rows":{"type":"integer","format":"int64","description":"Total number of rows returned or affected."},"total_exec_time_ms":{"type":"number","format":"double","description":"Total wall-clock time spent executing this query, in milliseconds."}}},"SmartFilter":{"oneOf":[{"type":"object","description":"Match specific page path","required":["value","type"],"properties":{"type":{"type":"string","enum":["page_path"]},"value":{"type":"string","description":"Match specific page path"}}},{"type":"object","description":"Match specific hostname","required":["value","type"],"properties":{"type":{"type":"string","enum":["hostname"]},"value":{"type":"string","description":"Match specific hostname"}}},{"type":"object","description":"Match UTM source","required":["value","type"],"properties":{"type":{"type":"string","enum":["utm_source"]},"value":{"type":"string","description":"Match UTM source"}}},{"type":"object","description":"Match UTM campaign","required":["value","type"],"properties":{"type":{"type":"string","enum":["utm_campaign"]},"value":{"type":"string","description":"Match UTM campaign"}}},{"type":"object","description":"Match UTM medium","required":["value","type"],"properties":{"type":{"type":"string","enum":["utm_medium"]},"value":{"type":"string","description":"Match UTM medium"}}},{"type":"object","description":"Match referrer hostname","required":["value","type"],"properties":{"type":{"type":"string","enum":["referrer_hostname"]},"value":{"type":"string","description":"Match referrer hostname"}}},{"type":"object","description":"Match specific channel (organic, paid, direct, referral, etc.)","required":["value","type"],"properties":{"type":{"type":"string","enum":["channel"]},"value":{"type":"string","description":"Match specific channel (organic, paid, direct, referral, etc.)"}}},{"type":"object","description":"Match device type (mobile, desktop, tablet)","required":["value","type"],"properties":{"type":{"type":"string","enum":["device_type"]},"value":{"type":"string","description":"Match device type (mobile, desktop, tablet)"}}},{"type":"object","description":"Match browser","required":["value","type"],"properties":{"type":{"type":"string","enum":["browser"]},"value":{"type":"string","description":"Match browser"}}},{"type":"object","description":"Match operating system","required":["value","type"],"properties":{"type":{"type":"string","enum":["operating_system"]},"value":{"type":"string","description":"Match operating system"}}},{"type":"object","description":"Match language","required":["value","type"],"properties":{"type":{"type":"string","enum":["language"]},"value":{"type":"string","description":"Match language"}}},{"type":"object","description":"Match custom event_data by JSON path\nFormat: {\"path\": \"user.plan\", \"value\": \"premium\"}\nThis will match events where event_data->'user'->>'plan' = 'premium'","required":["value","type"],"properties":{"type":{"type":"string","enum":["custom_data"]},"value":{"type":"object","description":"Match custom event_data by JSON path\nFormat: {\"path\": \"user.plan\", \"value\": \"premium\"}\nThis will match events where event_data->'user'->>'plan' = 'premium'","required":["path","value"],"properties":{"path":{"type":"string"},"value":{"type":"string"}}}}}],"description":"Smart filter presets for common funnel patterns"},"SmokeTestResponse":{"type":"object","required":["passed","environment","cli_installed","cli_authenticated"],"properties":{"auth_info":{"type":["string","null"],"description":"Auth email / method"},"cli_authenticated":{"type":"boolean","description":"Claude CLI authenticated?"},"cli_installed":{"type":"boolean","description":"Claude CLI installed?"},"cli_version":{"type":["string","null"],"description":"Claude CLI version"},"detail":{"type":["string","null"],"description":"Full output for debugging"},"environment":{"type":"string","description":"Where the test ran: \"host\" or \"sandbox\""},"passed":{"type":"boolean","description":"Whether the smoke test passed"},"setup_hint":{"type":["string","null"],"description":"What the user needs to do if the test failed"}}},"SmtpCredentialsRequest":{"type":"object","description":"Generic SMTP credentials request body.\n\nWorks with any SMTP relay — AWS SES SMTP endpoints, Sendgrid, Mailgun,\nPostmark, or a self-hosted Postfix. Use this when you only have SMTP\ncredentials (i.e. you cannot create identities via the upstream API).","required":["host","port"],"properties":{"accept_invalid_certs":{"type":"boolean","description":"Accept self-signed certificates. Only safe for local testing."},"encryption":{"$ref":"#/components/schemas/SmtpEncryptionRoute","description":"TLS mode. Defaults to STARTTLS."},"host":{"type":"string","description":"SMTP host, e.g. `email-smtp.eu-west-1.amazonaws.com`.","example":"email-smtp.eu-west-1.amazonaws.com"},"password":{"type":["string","null"],"description":"SMTP password / API token. Required when `username` is set."},"port":{"type":"integer","format":"int32","description":"SMTP port (587 for STARTTLS, 465 for implicit TLS, 25/1025 for plain).","example":587,"minimum":0},"username":{"type":["string","null"],"description":"SMTP username. Leave empty for unauthenticated relays.","example":"AKIAIOSFODNN7EXAMPLE"}}},"SmtpEncryptionRoute":{"type":"string","description":"TLS mode for the SMTP relay.","enum":["starttls","tls","none"]},"SmtpResult":{"type":"object","description":"SMTP validation result","required":["can_connect_smtp","has_full_inbox","is_catch_all","is_deliverable","is_disabled"],"properties":{"can_connect_smtp":{"type":"boolean","description":"Whether we could connect to the SMTP server"},"error":{"type":["string","null"],"description":"Error message if SMTP check failed"},"has_full_inbox":{"type":"boolean","description":"Whether the mailbox appears to have a full inbox"},"is_catch_all":{"type":"boolean","description":"Whether this is a catch-all domain"},"is_deliverable":{"type":"boolean","description":"Whether the email is deliverable"},"is_disabled":{"type":"boolean","description":"Whether the mailbox is disabled"}}},"SourceArchiveUpload":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary"}}},"SourceBackupEntry":{"type":"object","description":"Entry in the source backup index. Covers both DB-tracked backups\n(have a row in `backups`) and S3-scan discoveries (raw S3 objects with\nno DB row — used for disaster-recovery from another Temps instance).","required":["id","backup_id","name","backup_type","created_at","location","metadata_location","source","state"],"properties":{"backup_id":{"type":"string","description":"UUID identifier from the DB row. Empty for S3-scan entries.","example":"550e8400-e29b-41d4-a716-446655440000"},"backup_type":{"type":"string","description":"Backup variant as recorded by the backup pipeline (e.g. \"full\").","example":"full"},"created_at":{"type":"string","description":"When the backup was created. For S3-scan entries this is the\nobject's LastModified time.","example":"2024-01-15T14:30:00.123Z"},"engine":{"type":["string","null"],"description":"Engine that produced the backup (\"postgres\", \"redis\", \"mongodb\",\n\"s3\", \"rustfs\"). Used by the UI to mark engine-compat with the\ntarget service.","example":"postgres"},"format":{"type":["string","null"],"description":"Storage format: \"walg\" for continuous-archive (PITR-capable),\n\"pg_dump\" for point-in-time dumps, \"\" for non-postgres.","example":"walg"},"id":{"type":"integer","format":"int32","description":"DB row id. Zero for S3-scan entries that have no DB row.","example":1},"location":{"type":"string","description":"Raw S3 URL / key where the backup sits. For Postgres WAL-G backups\nthis starts with `s3://`; for pg_dump-style backups it's the\nrelative object key.","example":"s3://bucket/external_services/postgres/svc-name/walg"},"metadata_location":{"type":"string","description":"Sidecar metadata.json location, if any. Empty when none.","example":""},"name":{"type":"string","description":"Human-friendly display name (\"postgres backup (svc-name)\" for DB\nrows, or a synthesized label derived from the S3 path for scans).","example":"postgres backup (postgres-n4ea)"},"origin_service_name":{"type":["string","null"],"description":"Name of the service that produced the backup. For S3-scan entries\nthis is parsed from the S3 path.","example":"postgres-n4ea"},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Size of the backup in bytes, if known.","example":1024000},"source":{"type":"string","description":"Provenance: \"db\" for rows in this Temps, \"s3_scan\" for objects\ndiscovered by the S3 bucket walk (e.g., backups made by another\nTemps instance).","example":"db"},"state":{"type":"string","description":"Observed state (\"completed\", \"running\", \"failed\") — DB only.\nEmpty string for S3-scan entries.","example":"completed"}}},"SourceBackupIndexResponse":{"type":"object","description":"Response type for source backup index","required":["backups","last_updated"],"properties":{"backups":{"type":"array","items":{"$ref":"#/components/schemas/SourceBackupEntry"},"description":"List of backups in the source"},"last_updated":{"type":"string","description":"When the index was last updated","example":"2024-01-15T14:30:00.123Z"}}},"SourceBody":{"oneOf":[{"type":"object","required":["url","type"],"properties":{"depth":{"type":["integer","null"],"format":"int32","minimum":0},"git_connection_id":{"type":["integer","null"],"format":"int32"},"password":{"type":["string","null"]},"revision":{"type":["string","null"]},"type":{"type":"string","enum":["git"]},"url":{"type":"string"},"username":{"type":["string","null"]}}},{"type":"object","required":["url","type"],"properties":{"type":{"type":"string","enum":["tarball"]},"url":{"type":"string"}}}],"description":"Initial content to seed into the sandbox work dir. Mirrors the\n`@vercel/sandbox` `source` option. `type` is one of:\n- `git` — clone `url`; optionally check out `revision`\n- `tarball` — download `url` (must be tar or tar.gz) and extract\n\nFor private git repos, pass credentials one of two ways:\n1. **Inline (SDK-compatible):** `username` + `password`. GitHub\n tokens use `username: \"x-access-token\"`.\n2. **Stored connection (temps-native):** `git_connection_id`\n references a row in the caller's git provider connections. Temps\n resolves the token server-side and injects it safely.\n\n`git_connection_id` is mutually exclusive with `username`/`password`."},"SourceFileListResponse":{"type":"object","required":["source_files","total"],"properties":{"source_files":{"type":"array","items":{"$ref":"#/components/schemas/SourceFileResponse"}},"total":{"type":"integer","minimum":0}}},"SourceFileResponse":{"type":"object","required":["id","project_id","release","file_path","size_bytes","created_at"],"properties":{"checksum":{"type":["string","null"]},"created_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"file_path":{"type":"string"},"id":{"type":"integer","format":"int32"},"project_id":{"type":"integer","format":"int32"},"release":{"type":"string"},"size_bytes":{"type":"integer","format":"int64"}}},"SourceMapListResponse":{"type":"object","required":["source_maps","total"],"properties":{"source_maps":{"type":"array","items":{"$ref":"#/components/schemas/SourceMapResponse"}},"total":{"type":"integer","minimum":0}}},"SourceMapResponse":{"type":"object","required":["id","project_id","release","file_path","size_bytes","created_at"],"properties":{"checksum":{"type":["string","null"]},"created_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"dist":{"type":["string","null"]},"file_path":{"type":"string"},"id":{"type":"integer","format":"int32"},"project_id":{"type":"integer","format":"int32"},"release":{"type":"string"},"size_bytes":{"type":"integer","format":"int64"}}},"SourceType":{"type":"string","description":"Source type for project deployments\n\nDetermines where the deployment artifacts come from:\n- `Git`: Source code from a Git repository (traditional flow)\n- `DockerImage`: Pre-built Docker image from external registry\n- `StaticFiles`: Pre-built static files uploaded as a bundle\n- `UploadedSource`: Source archive uploaded without a Git repository\n- `Manual`: Flexible type that accepts any deployment method","enum":["git","docker_image","static_files","uploaded_source","manual"]},"SpanEvent":{"type":"object","description":"A span event (log-like annotation on a span).","required":["timestamp","name","attributes"],"properties":{"attributes":{"type":"object","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"name":{"type":"string"},"timestamp":{"type":"string","format":"date-time"}}},"SpanKind":{"type":"string","description":"Span kind.","enum":["UNSPECIFIED","INTERNAL","SERVER","CLIENT","PRODUCER","CONSUMER"]},"SpanRecord":{"type":"object","description":"A single trace span ready for storage.","required":["project_id","resource","trace_id","span_id","name","kind","start_time","end_time","duration_ms","status_code","status_message","attributes","events"],"properties":{"attributes":{"type":"object","description":"Raw key/value pairs exactly as reported by the instrumenting library.\nNumeric values are NOT guaranteed to share `duration_ms`'s unit — they\nmay be seconds, milliseconds, microseconds, or nanoseconds depending on\nthe exporter's own convention, and the unit is not labeled here.","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"deployment_id":{"type":["integer","null"],"format":"int32"},"duration_ms":{"type":"number","format":"double","description":"Span duration in milliseconds. The only field on this struct guaranteed\nto be in milliseconds."},"end_time":{"type":"string","format":"date-time"},"events":{"type":"array","items":{"$ref":"#/components/schemas/SpanEvent"}},"kind":{"$ref":"#/components/schemas/SpanKind"},"name":{"type":"string"},"parent_span_id":{"type":["string","null"]},"project_id":{"type":"integer","format":"int32"},"resource":{"$ref":"#/components/schemas/ResourceInfo"},"span_id":{"type":"string"},"start_time":{"type":"string","format":"date-time"},"status_code":{"$ref":"#/components/schemas/SpanStatusCode"},"status_message":{"type":"string"},"trace_id":{"type":"string"}}},"SpanRow":{"type":"object","required":["id","ts","trace_id","span_id","service","operation","attributes","attributes_truncated"],"properties":{"attributes":{},"attributes_truncated":{"type":"boolean"},"deployment_id":{"type":["integer","null"],"format":"int32"},"duration_ms":{"type":["number","null"],"format":"double"},"environment_id":{"type":["integer","null"],"format":"int32"},"id":{"type":"string"},"operation":{"type":"string"},"parent_span_id":{"type":["string","null"]},"service":{"type":"string"},"span_id":{"type":"string"},"status":{"type":["string","null"]},"trace_id":{"type":"string"},"ts":{"type":"string","format":"date-time"}}},"SpanStatusCode":{"type":"string","description":"Span status code.","enum":["UNSET","OK","ERROR"]},"SpeedMetricsPayload":{"type":"object","description":"Speed metrics payload for recording web vitals","properties":{"cls":{"type":["number","null"],"format":"float","description":"Cumulative Layout Shift (score)"},"fcp":{"type":["number","null"],"format":"float","description":"First Contentful Paint (milliseconds)"},"fid":{"type":["number","null"],"format":"float","description":"First Input Delay (milliseconds)"},"inp":{"type":["number","null"],"format":"float","description":"Interaction to Next Paint (milliseconds)"},"language":{"type":["string","null"],"description":"Browser language"},"lcp":{"type":["number","null"],"format":"float","description":"Largest Contentful Paint (milliseconds)"},"pathname":{"type":["string","null"],"description":"Page pathname"},"query":{"type":["string","null"],"description":"Query string"},"screenHeight":{"type":["integer","null"],"format":"int32","description":"Screen height in pixels"},"screenWidth":{"type":["integer","null"],"format":"int32","description":"Screen width in pixels"},"ttfb":{"type":["number","null"],"format":"float","description":"Time to First Byte (milliseconds)"},"viewportHeight":{"type":["integer","null"],"format":"int32","description":"Viewport height in pixels"},"viewportWidth":{"type":["integer","null"],"format":"int32","description":"Viewport width in pixels"}}},"SpeedSegmentFilters":{"type":"object","description":"Optional segment filters for the performance read endpoints, mirroring\nanalytics' `VisitorSegmentFilters`. Each filter narrows results to samples\nmatching the dimension value, so metrics can be scoped to e.g. one page,\none browser, or one country. Geographic filters resolve via\n`ip_geolocations`; the rest live directly on `performance_metrics`.","properties":{"filter_browser":{"type":["string","null"],"description":"Browser name (matches `performance_metrics.browser`)"},"filter_city":{"type":["string","null"],"description":"Geolocation city (matches `ip_geolocations.city`)"},"filter_country":{"type":["string","null"],"description":"Geolocation country (matches `ip_geolocations.country`)"},"filter_operating_system":{"type":["string","null"],"description":"Operating system (matches `performance_metrics.operating_system`)"},"filter_path":{"type":["string","null"],"description":"Page pathname (matches `performance_metrics.pathname`)"},"filter_region":{"type":["string","null"],"description":"Geolocation region (matches `ip_geolocations.region`)"}}},"StaleSlot":{"type":"object","required":["slot_name","active","retained_bytes"],"properties":{"active":{"type":"boolean"},"retained_bytes":{"type":"integer","format":"int64"},"slot_name":{"type":"string"}}},"StartAnalysisRequest":{"type":"object","required":["error_group_id"],"properties":{"branch":{"type":["string","null"],"description":"Branch to clone instead of the project's main branch."},"error_group_id":{"type":"integer","format":"int32"},"max_turns":{"type":["integer","null"],"format":"int32","description":"Per-run turn cap applied to every phase (1–200). Only enforced for\nCLIs with a turn flag (Claude Code). `None` uses the provider's\nconfigured defaults."},"model":{"type":["string","null"],"description":"Model id for the chosen provider. `None` uses the provider's saved\ndefault model."},"provider":{"type":["string","null"],"description":"AI provider id (\"claude_cli\", \"codex_cli\", \"opencode\"). `None` uses\nthe platform default provider."},"user_context":{"type":["string","null"],"description":"Free-text notes for the model (extra context about the error, retry\nguidance, constraints). Included verbatim in the analysis prompt."}}},"StartPgUpgradeRequest":{"type":"object","required":["from_version","to_version","from_image","to_image"],"properties":{"from_image":{"type":"string","example":"postgres:16-bookworm"},"from_version":{"type":"string","example":"16"},"to_image":{"type":"string","example":"postgres:17-bookworm"},"to_version":{"type":"string","example":"17"}}},"StartRestoreRequest":{"allOf":[{"$ref":"#/components/schemas/RestoreRequestMode","description":"Requested restore mode. See `RestoreRequestMode`."},{"type":"object","properties":{"backup_engine":{"type":["string","null"],"description":"Engine of the backup when specified by `backup_location`\n(\"postgres\", \"redis\", \"mongodb\", \"s3\"). Ignored when `backup_id`\nis used — we infer from the DB row."},"backup_id":{"type":["integer","null"],"format":"int32","description":"DB id of the backup to restore from. Either `backup_id` or\n`backup_location` MUST be provided. Use `backup_id` when restoring\na backup this Temps instance recorded."},"backup_location":{"type":["string","null"],"description":"Raw S3 URL / key of the backup — used when restoring a backup\ndiscovered by S3 scan (i.e., produced by another Temps instance).\nRequires `backup_engine` and `s3_source_id` to also be set."},"s3_source_id":{"type":["integer","null"],"format":"int32","description":"S3 source the `backup_location` lives in. Ignored when `backup_id`\nis used."}}}]},"StartUpdateRequest":{"type":"object","description":"Optional pin for the version to install.","properties":{"version":{"type":["string","null"],"description":"Release tag to install (e.g. `v0.2.0`). Omit to take the newest release\non the channel this install already tracks."}}},"StartUpdateResponse":{"type":"object","description":"Acknowledgement that an update was accepted and is running.","required":["current_version","estimated_restart_secs","restart_mode","message"],"properties":{"current_version":{"type":"string","description":"Version the server is running as it accepts this request."},"estimated_restart_secs":{"type":"integer","format":"int64","description":"How long to allow for the server to come back before treating the\nrestart as failed. `0` when nothing restarts.","minimum":0},"message":{"type":"string"},"restart_mode":{"$ref":"#/components/schemas/SelfUpdateRestartMode","description":"`automatic` (temps restarts itself) or `manual` (installed only)."}}},"StatResponse":{"type":"object","required":["path","exists","is_dir","is_file","size"],"properties":{"exists":{"type":"boolean"},"is_dir":{"type":"boolean"},"is_file":{"type":"boolean"},"path":{"type":"string"},"size":{"type":"integer","format":"int64","minimum":0}}},"StaticBundleResponse":{"type":"object","required":["id","project_id","blob_path","content_type","size_bytes","uploaded_at","created_at"],"properties":{"blob_path":{"type":"string"},"checksum":{"type":["string","null"]},"content_type":{"type":"string"},"created_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"format":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"metadata":{},"original_filename":{"type":["string","null"]},"project_id":{"type":"integer","format":"int32"},"size_bytes":{"type":"integer","format":"int64"},"uploaded_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"}}},"StaticParams":{"type":"object","description":"Static threshold detector: compare the aggregated `value` against `threshold`.","required":["comparator","threshold"],"properties":{"comparator":{"$ref":"#/components/schemas/Comparator","description":"How `value` is compared against `threshold`."},"threshold":{"type":"number","format":"double","description":"The threshold the aggregated value is compared against."}}},"StaticPresetConfig":{"type":"object","description":"Configuration for static site presets (Vite, Next.js, Docusaurus, etc.)\nThese presets build static sites that are served via a web server","properties":{"buildCommand":{"type":["string","null"],"description":"Custom build command (overrides preset default)","example":"npm run build:production"},"buildContext":{"type":["string","null"],"description":"Custom build context path (relative to repository root)\nUseful for monorepo setups where the app is in a subdirectory","example":"./apps/frontend"},"installCommand":{"type":["string","null"],"description":"Custom install command (overrides auto-detected package manager)","example":"npm ci"},"outputDir":{"type":["string","null"],"description":"Custom output directory (overrides preset default)\nCommon values: \"dist\", \"build\", \".next\", \"out\"","example":"dist"}}},"StatsFilters":{"type":"object","description":"Filters for statistics queries","properties":{"client_ip":{"type":["string","null"]},"deployment_id":{"type":["integer","null"],"format":"int32"},"device_type":{"type":["string","null"]},"environment_id":{"type":["integer","null"],"format":"int32"},"has_project":{"type":["boolean","null"],"description":"When true, only count requests that matched a project (project_id IS NOT NULL).\nUsed by the health dashboard so totals match the per-project cards."},"host":{"type":["string","null"]},"is_bot":{"type":["boolean","null"]},"method":{"type":["string","null"]},"project_id":{"type":["integer","null"],"format":"int32"},"request_source":{"type":["string","null"]},"routing_status":{"type":["string","null"]},"status_code":{"type":["integer","null"],"format":"int32"},"status_code_class":{"type":["string","null"],"description":"Filter by status code class (e.g. \"2xx\", \"3xx\", \"4xx\", \"5xx\")"}}},"StatusBucket":{"type":"object","required":["bucket_start","status","total_checks","operational_count","degraded_count","down_count","uptime_percentage"],"properties":{"avg_response_time_ms":{"type":["number","null"],"format":"double"},"bucket_start":{"type":"string","format":"date-time"},"degraded_count":{"type":"integer","format":"int64"},"down_count":{"type":"integer","format":"int64"},"max_response_time_ms":{"type":["number","null"],"format":"double"},"min_response_time_ms":{"type":["number","null"],"format":"double"},"operational_count":{"type":"integer","format":"int64"},"p50_response_time_ms":{"type":["number","null"],"format":"double"},"p95_response_time_ms":{"type":["number","null"],"format":"double"},"p99_response_time_ms":{"type":["number","null"],"format":"double"},"status":{"type":"string"},"total_checks":{"type":"integer","format":"int64"},"uptime_percentage":{"type":"number","format":"double"}}},"StatusBucketedResponse":{"type":"object","required":["monitor_id","interval","buckets"],"properties":{"buckets":{"type":"array","items":{"$ref":"#/components/schemas/StatusBucket"}},"interval":{"type":"string"},"monitor_id":{"type":"integer","format":"int32"}}},"StatusCodeCount":{"type":"object","required":["status_code","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"percentage":{"type":"number","format":"double"},"status_code":{"type":"integer","format":"int32"}}},"StatusCodesQuery":{"type":"object","required":["start_date","end_date","project_id"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"StatusPageOverview":{"type":"object","required":["status","monitors","recent_incidents"],"properties":{"monitors":{"type":"array","items":{"$ref":"#/components/schemas/MonitorStatus"}},"recent_incidents":{"type":"array","items":{"$ref":"#/components/schemas/IncidentResponse"}},"status":{"type":"string"}}},"StepConversionResponse":{"type":"object","required":["step_id","step_name","step_order","completions","conversion_rate","drop_off_rate","average_time_to_complete_seconds"],"properties":{"average_time_to_complete_seconds":{"type":"number","format":"double"},"completions":{"type":"integer","format":"int64","minimum":0},"conversion_rate":{"type":"number","format":"double"},"drop_off_rate":{"type":"number","format":"double"},"step_id":{"type":"integer","format":"int32"},"step_name":{"type":"string"},"step_order":{"type":"integer","format":"int32"}}},"StepResourceType":{"type":"string","description":"What kind of resource a migration step operates on","enum":["project","environment","deployment","environment-variable","service","domain","git-link","other"]},"StepResult":{"type":"object","description":"Result of executing a single migration step","required":["step_id","step_title","success","skipped","message","created_resources","duration_seconds"],"properties":{"created_resources":{"type":"array","items":{"$ref":"#/components/schemas/CreatedResource"},"description":"Resources created by this step"},"duration_seconds":{"type":"number","format":"double","description":"Duration of this step"},"message":{"type":"string","description":"Human-readable message about what happened"},"skipped":{"type":"boolean","description":"Whether this step was skipped"},"step_id":{"type":"string","description":"Step ID (matches `MigrationStep.id`)"},"step_title":{"type":"string","description":"Step title (for display)"},"success":{"type":"boolean","description":"Whether this step succeeded"}}},"StepUpResponse":{"type":"object","required":["expires_at"],"properties":{"expires_at":{"type":"string","format":"date-time","description":"ISO 8601 timestamp after which sensitive actions require verification\nagain."}}},"StopSequence":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]},"StorageQuota":{"type":"object","description":"Quota usage information for a project.","required":["project_id","metrics_bytes","traces_bytes","logs_bytes","total_bytes","limit_bytes","usage_pct"],"properties":{"limit_bytes":{"type":"integer","format":"int64","minimum":0},"logs_bytes":{"type":"integer","format":"int64","minimum":0},"metrics_bytes":{"type":"integer","format":"int64","minimum":0},"project_id":{"type":"integer","format":"int32"},"total_bytes":{"type":"integer","format":"int64","minimum":0},"traces_bytes":{"type":"integer","format":"int64","minimum":0},"usage_pct":{"type":"number","format":"double"}}},"StripeConfig":{"type":"object","properties":{"include_unpriced_charges":{"type":"boolean","description":"When an allowlist is set, should we still ingest charges that\nlack a price reference (e.g. standalone `charge.succeeded` without\na subscription)? Default true — charges don't belong to a SKU."},"metered_mode":{"$ref":"#/components/schemas/MeteredMode","description":"How to compute MRR for metered / tiered / hybrid subscriptions."},"price_allowlist":{"type":"array","items":{"type":"string"},"description":"Only events tagged with one of these Stripe price IDs are ingested.\nEmpty = accept all prices."},"product_allowlist":{"type":"array","items":{"type":"string"},"description":"Only events tagged with one of these Stripe product IDs are\ningested. Empty = accept all products. Combined with\n`price_allowlist` via OR — if either list has a match, accept."}}},"SupervisorKind":{"type":"string","description":"What (if anything) will restart the process after it exits.","enum":["systemd","launchd","container","none"]},"SyncedRepositoryListQuery":{"type":"object","properties":{"direction":{"type":["string","null"]},"git_provider_connection_id":{"type":["integer","null"],"format":"int32"},"language":{"type":["string","null"]},"owner":{"type":["string","null"]},"page":{"type":["integer","null"],"format":"int64","minimum":0},"per_page":{"type":["integer","null"],"format":"int64","minimum":0},"private":{"type":["boolean","null"]},"search":{"type":["string","null"]},"sort":{"type":["string","null"]}}},"SyntaxResult":{"type":"object","description":"Syntax validation result","required":["is_valid_syntax"],"properties":{"domain":{"type":["string","null"],"description":"The domain part of the email","example":"gmail.com"},"is_valid_syntax":{"type":"boolean","description":"Whether the email syntax is valid"},"suggestion":{"type":["string","null"],"description":"Suggested email correction if available"},"username":{"type":["string","null"],"description":"The username part of the email","example":"someone"}}},"TagInfo":{"type":"object","required":["name","commit_sha"],"properties":{"commit_sha":{"type":"string"},"name":{"type":"string"}}},"TagListResponse":{"type":"object","required":["tags"],"properties":{"tags":{"type":"array","items":{"$ref":"#/components/schemas/TagInfo"}}}},"TailLogsRequest":{"type":"object","required":["project_id","service","env"],"properties":{"env":{"type":"string"},"external_service_id":{"type":["integer","null"],"format":"int32","description":"When set, tail an imported/managed external service's logs instead of\na project's (`project_id` is ignored in this mode)."},"levels":{"type":"array","items":{"type":"string"}},"project_id":{"type":"integer","format":"int32","description":"Project ID (integer, as used by the rest of the platform)"},"service":{"type":"string"},"text":{"type":["string","null"]}}},"TargetRecommendation":{"type":"object","description":"The temps/Hetzner target sizing and savings estimate","required":["server_type","vcpus","memory_gb","monthly_eur","fits_single_node","sizing_basis","rationale"],"properties":{"fits_single_node":{"type":"boolean","description":"Whether the workloads fit a single recommended server. When `false`,\nthe rationale explains the multi-node option (temps worker nodes)."},"memory_gb":{"type":"integer","format":"int32","description":"Memory (GB) of the recommended server"},"monthly_eur":{"type":"number","format":"double","description":"Estimated monthly price of the recommended server in EUR"},"monthly_savings_usd":{"type":["number","null"],"format":"double","description":"Estimated monthly savings in USD (current cost minus target cost,\ntreating EUR≈USD for the rough comparison — disclaimed in `notes`).\n`None` when the current cost is unknown."},"rationale":{"type":"string","description":"Human-readable recommendation summary"},"server_type":{"type":"string","description":"Recommended Hetzner server type (e.g. \"cpx32\")"},"sizing_basis":{"type":"string","description":"What the sizing was based on, e.g. \"2× measured usage + temps\nplatform overhead\" or \"resource requests (no metrics available)\""},"vcpus":{"type":"integer","format":"int32","description":"vCPUs of the recommended server"},"yearly_savings_usd":{"type":["number","null"],"format":"double","description":"`monthly_savings_usd × 12`"}}},"TeamListResponse":{"type":"object","required":["teams","total","page","page_size"],"properties":{"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"teams":{"type":"array","items":{"$ref":"#/components/schemas/TeamResponse"}},"total":{"type":"integer","format":"int64","minimum":0}}},"TeamMemberResponse":{"type":"object","required":["id","team_id","user_id","role","added_by","created_at","updated_at"],"properties":{"added_by":{"type":"integer","format":"int32"},"created_at":{"type":"string","format":"date-time","example":"2026-07-30T12:15:47.609192Z"},"id":{"type":"integer","format":"int32"},"role":{"$ref":"#/components/schemas/TeamRole","description":"The source of this member's project-scoped permissions, intersected\nwith `project_team_access.role`."},"team_id":{"type":"integer","format":"int32"},"updated_at":{"type":"string","format":"date-time","example":"2026-07-30T12:15:47.609192Z"},"user_email":{"type":["string","null"],"description":"The member's email, joined from `users`."},"user_id":{"type":"integer","format":"int32"},"user_name":{"type":["string","null"],"description":"The member's display name, joined from `users`. `None` if the\nreferenced user no longer exists."}}},"TeamResponse":{"type":"object","required":["id","name","slug","created_by","created_at","updated_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2026-07-30T12:15:47.609192Z"},"created_by":{"type":"integer","format":"int32"},"description":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"slug":{"type":"string"},"updated_at":{"type":"string","format":"date-time","example":"2026-07-30T12:15:47.609192Z"}}},"TeamRole":{"type":"string","description":"Role a user holds within a team, or that a team holds on a project.\n\nNamed `TeamRole` rather than `Role` to keep it distinct from\n`temps_auth::permissions::Role`, which is the instance-wide role\n(Admin/User/…) attached to a session. The two are orthogonal: the\ninstance-wide role decides whether you may touch a resource *kind* at\nall, `TeamRole` decides what you may do *within a project* you have\nteam access to. See `temps_teams::fixed_role_permissions` for the\nproject-scoped permission set each variant maps to.\n\nStored as a `varchar(32)` rather than a Postgres enum so the role set\ncan evolve in pure migration code without a schema-level enum\nalteration blocking a downgrade.","enum":["owner","admin","deployer","viewer"]},"TemplateResponse":{"type":"object","description":"Response type for a single template","required":["slug","name","git","preset","tags","features","services","env_vars","is_featured"],"properties":{"description":{"type":["string","null"],"description":"Short description"},"env_vars":{"type":"array","items":{"$ref":"#/components/schemas/EnvVarTemplateResponse"},"description":"Environment variables template"},"exposed_port":{"type":["integer","null"],"format":"int32","description":"Container port the prebuilt image listens on (image deploys only)."},"features":{"type":"array","items":{"type":"string"},"description":"Feature highlights"},"git":{"$ref":"#/components/schemas/GitRefResponse","description":"Git repository reference"},"health_check_path":{"type":["string","null"],"description":"HTTP health-check path probed after the container starts (image deploys)."},"image":{"type":["string","null"],"description":"Prebuilt Docker image reference. When set, the one-click deploy pulls and\nruns this image directly (no build); when absent it builds from `git`."},"image_url":{"type":["string","null"],"description":"URL to template image/icon"},"is_featured":{"type":"boolean","description":"Whether the template is featured/promoted"},"name":{"type":"string","description":"Display name"},"preset":{"type":"string","description":"Framework/preset to use"},"screenshot_url":{"type":["string","null"],"description":"URL to a wide screenshot/banner preview of the deployed template.\nAbsent for templates that don't have one captured yet."},"services":{"type":"array","items":{"type":"string"},"description":"Required external services"},"slug":{"type":"string","description":"Unique identifier for the template (used in URLs)"},"tags":{"type":"array","items":{"type":"string"},"description":"Tags/categories for filtering"}}},"TestEmailRequest":{"type":"object","description":"Request body for testing an email provider","required":["from"],"properties":{"from":{"type":"string","description":"Sender email address (must be verified with the provider)","example":"test@example.com"},"from_name":{"type":["string","null"],"description":"Sender display name","example":"My App"}}},"TestEmailResponse":{"type":"object","description":"Response for test email endpoint","required":["success","sent_to"],"properties":{"error":{"type":["string","null"],"description":"Error message if the test failed"},"provider_message_id":{"type":["string","null"],"description":"Provider message ID if successful"},"sent_to":{"type":"string","description":"The email address the test was sent to","example":"user@example.com"},"success":{"type":"boolean","description":"Whether the test email was sent successfully"}}},"TestProviderKeyRequest":{"type":"object","required":["provider","api_key"],"properties":{"api_key":{"type":"string","description":"The raw API key to test"},"base_url":{"type":["string","null"],"description":"Optional custom base URL"},"provider":{"type":"string","description":"Provider ID: \"openai\", \"anthropic\", \"xai\", \"gemini\""}}},"TestProviderKeyResponse":{"type":"object","required":["success","provider","latency_ms"],"properties":{"error":{"type":["string","null"],"description":"Error message if the test failed"},"latency_ms":{"type":"integer","format":"int64","description":"Response time in milliseconds","minimum":0},"provider":{"type":"string"},"success":{"type":"boolean"}}},"TestProviderResponse":{"type":"object","required":["success"],"properties":{"message":{"type":["string","null"]},"success":{"type":"boolean"}}},"TimeBucketStats":{"type":"object","description":"Time bucket statistics response","required":["bucket","request_count","avg_response_time_ms","error_count","total_request_bytes","total_response_bytes"],"properties":{"avg_response_time_ms":{"type":"number","format":"double","description":"Average response time in milliseconds"},"bucket":{"type":"string","description":"Bucket timestamp in RFC3339 format","example":"2025-10-23T12:00:00Z"},"error_count":{"type":"integer","format":"int64","description":"Number of errors (status >= 400)"},"request_count":{"type":"integer","format":"int64","description":"Total number of requests in this bucket"},"total_request_bytes":{"type":"integer","format":"int64","description":"Total request bytes"},"total_response_bytes":{"type":"integer","format":"int64","description":"Total response bytes"}}},"TimeBucketStatsResponse":{"type":"object","description":"Response for time bucket stats","required":["stats","start_time","end_time","bucket_interval"],"properties":{"bucket_interval":{"type":"string"},"end_time":{"type":"string"},"start_time":{"type":"string"},"stats":{"type":"array","items":{"$ref":"#/components/schemas/TimeBucketStats"}}}},"TimeseriesBucket":{"type":"object","required":["bucket","request_count","input_tokens","output_tokens","avg_latency_ms"],"properties":{"avg_latency_ms":{"type":"number","format":"double"},"bucket":{"type":"string","description":"ISO 8601 timestamp"},"input_tokens":{"type":"integer","format":"int64"},"output_tokens":{"type":"integer","format":"int64"},"request_count":{"type":"integer","format":"int64"}}},"TimeseriesQueryParams":{"type":"object","properties":{"bucket":{"type":["string","null"],"description":"Bucket size: \"hour\", \"day\", \"week\" (defaults to \"day\")"},"conversation_id":{"type":["string","null"],"description":"Filter by conversation ID"},"from":{"type":["string","null"],"description":"ISO 8601 start time (defaults to 24h ago)"},"model":{"type":["string","null"],"description":"Filter by model name"},"provider":{"type":["string","null"],"description":"Filter by provider name"},"tags":{"type":["string","null"],"description":"Filter by tags (comma-separated, AND logic)"},"to":{"type":["string","null"],"description":"ISO 8601 end time (defaults to now)"},"user_id":{"type":["integer","null"],"format":"int32","description":"Filter by user ID"}}},"TlsMode":{"type":"string","enum":["None","Starttls","Tls"]},"TodayStatsResponse":{"type":"object","description":"Today's stats response","required":["total_requests","date"],"properties":{"date":{"type":"string","description":"Date for which stats are returned","example":"2025-10-23"},"total_requests":{"type":"integer","format":"int64","description":"Total requests today"}}},"ToggleDeploymentMetricsRequest":{"type":"object","description":"Request body to toggle OTLP metric ingestion for a deployment.","required":["enabled"],"properties":{"enabled":{"type":"boolean","description":"Whether to enable (`true`) or disable (`false`) metric ingestion."},"path":{"type":["string","null"],"description":"Prometheus scrape path (optional, defaults to `/metrics`)."},"port":{"type":["integer","null"],"format":"int32","description":"Prometheus scrape port (optional).","minimum":0}}},"ToggleServiceMetricsRequest":{"type":"object","description":"Request body to toggle metric collection for an external service.","required":["enabled"],"properties":{"enabled":{"type":"boolean","description":"Whether to enable (`true`) or disable (`false`) metric collection."}}},"TokenRenewalRequest":{"type":"object","required":["refresh_token"],"properties":{"refresh_token":{"type":"string"}}},"ToolCallEvent":{"type":"object","description":"Payload for the `tool_call` SSE event: the model is about to run a tool.\nSerialized as compact single-line JSON onto one `data:` line.","required":["id","name","arguments"],"properties":{"arguments":{"type":"string","description":"The raw JSON-args string the model emitted."},"id":{"type":"string"},"name":{"type":"string"}}},"ToolInfo":{"type":"object","description":"One persisted tool invocation + its result, attached to an assistant message.","required":["id","name","arguments"],"properties":{"arguments":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"},"result":{"type":["string","null"]}}},"ToolResultEvent":{"type":"object","description":"Payload for the `tool_result` SSE event: a tool finished running. Serialized\nas compact single-line JSON; `content` is JSON-string-escaped so it stays on\none `data:` line even when long.","required":["id","name","content"],"properties":{"content":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"}}},"TopModelsQueryParams":{"type":"object","properties":{"from":{"type":["string","null"],"description":"ISO 8601 start time (defaults to 24h ago)"},"limit":{"type":["integer","null"],"format":"int64","description":"Max results (defaults to 10)","minimum":0},"tags":{"type":["string","null"],"description":"Filter by tags (comma-separated, AND logic)"},"to":{"type":["string","null"],"description":"ISO 8601 end time (defaults to now)"},"user_id":{"type":["integer","null"],"format":"int32","description":"Filter by user ID"}}},"TraceProjectRef":{"type":"object","description":"All projects that contributed spans to a trace, including their sharing flag.\n\nReturned by `CrossProjectTraceService::find_trace_projects`.","required":["project_id","project_name","project_slug","first_seen","sharing"],"properties":{"first_seen":{"type":"string","format":"date-time"},"project_id":{"type":"integer","format":"int32"},"project_name":{"type":"string"},"project_slug":{"type":"string","description":"URL slug used to link into the project's single-project trace view."},"sharing":{"type":"boolean","description":"Whether this project has `cross_project_trace_sharing = true`."}}},"TraceSummariesResponse":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/TraceSummary"}},"total":{"type":["integer","null"],"format":"int64","description":"Total traces matching the filters, ignoring pagination. Omitted when\nthe request passed `include_total=false`, in which case the caller\nasked not to pay for the count — treat its absence as \"unknown\", not\nas zero.","minimum":0}}},"TraceSummary":{"type":"object","description":"A trace summary for the list view — one row per trace, aggregated from spans.","required":["trace_id","root_span_name","service_name","kind","status_code","start_time","duration_ms","span_count","error_count"],"properties":{"deployment_environment":{"type":["string","null"],"description":"The deployment environment from the root span's resource attributes (e.g. \"production\")."},"duration_ms":{"type":"number","format":"double"},"error_count":{"type":"integer","format":"int64"},"kind":{"$ref":"#/components/schemas/SpanKind"},"root_span_name":{"type":"string"},"service_name":{"type":"string"},"span_count":{"type":"integer","format":"int64"},"start_time":{"type":"string","format":"date-time"},"status_code":{"$ref":"#/components/schemas/SpanStatusCode"},"trace_id":{"type":"string"}}},"TracesResponse":{"type":"object","required":["data","count"],"properties":{"count":{"type":"integer","minimum":0},"data":{"type":"array","items":{"$ref":"#/components/schemas/SpanRecord"}}}},"TrackedLinkResponse":{"type":"object","description":"Tracked link with click count","required":["link_index","original_url","click_count"],"properties":{"click_count":{"type":"integer","format":"int32"},"link_index":{"type":"integer","format":"int32"},"original_url":{"type":"string"}}},"TrackingEventResponse":{"type":"object","description":"Email tracking event","required":["id","email_id","event_type","created_at"],"properties":{"created_at":{"type":"string"},"email_id":{"type":"string"},"event_type":{"type":"string"},"id":{"type":"integer","format":"int64"},"ip_address":{"type":["string","null"]},"link_index":{"type":["integer","null"],"format":"int32"},"link_url":{"type":["string","null"]},"user_agent":{"type":["string","null"]}}},"TriggerAgentRequest":{"type":"object","properties":{"trigger_source_id":{"type":["integer","null"],"format":"int32"},"trigger_source_type":{"type":["string","null"]},"user_context":{"type":["string","null"],"description":"Optional context from the user (e.g. a research topic, bug description, or instructions)."}}},"TriggerDigestResponse":{"type":"object","required":["success","message"],"properties":{"message":{"type":"string"},"success":{"type":"boolean"}}},"TriggerPipelinePayload":{"type":"object","properties":{"branch":{"type":["string","null"]},"commit":{"type":["string","null"]},"environment_id":{"type":["integer","null"],"format":"int32","description":"Optional environment ID - if not provided, will use the project's preview environment"},"tag":{"type":["string","null"]}}},"TriggerPipelineResponse":{"type":"object","required":["message","project_id","environment_id"],"properties":{"branch":{"type":["string","null"]},"commit":{"type":["string","null"]},"environment_id":{"type":"integer","format":"int32"},"message":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"tag":{"type":["string","null"]}}},"TriggerScanRequest":{"type":"object","required":["environment_id"],"properties":{"environment_id":{"type":"integer","format":"int32","description":"Environment ID to scan (uses the current deployment for this environment)","example":1}}},"TriggerScanResponse":{"type":"object","required":["scan_id","status","message"],"properties":{"message":{"type":"string"},"scan_id":{"type":"integer","format":"int32"},"status":{"type":"string"}}},"TtlRequest":{"type":"object","description":"Request to get TTL for a key","required":["key"],"properties":{"key":{"type":"string","description":"The key to check TTL for","example":"session:abc"},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1}}},"TtlResponse":{"type":"object","description":"Response for TTL operation","required":["ttl"],"properties":{"ttl":{"type":"integer","format":"int64","description":"TTL in seconds, -1 if no expiration, -2 if key doesn't exist","example":3600}}},"TxtRecord":{"type":"object","required":["name","value"],"properties":{"name":{"type":"string"},"value":{"type":"string"}}},"UiManifest":{"type":"object","description":"Describes the plugin's embedded UI bundle.","required":["entry_js"],"properties":{"css":{"type":"array","items":{"type":"string"},"description":"CSS files to load"},"entry_js":{"type":"string","description":"JavaScript entry point filename relative to the bundle root"},"routes":{"type":"array","items":{"$ref":"#/components/schemas/UiRoute"},"description":"Client-side routes the plugin handles"}}},"UiRoute":{"type":"object","description":"A client-side route provided by the plugin UI.","required":["path","title"],"properties":{"path":{"type":"string","description":"Route path pattern (e.g., \"/my-plugin\", \"/my-plugin/:id\")"},"title":{"type":"string","description":"Page title for breadcrumbs"}}},"UndrainNodeResponse":{"type":"object","description":"Response after undraining (reactivating) a node.","required":["id","name","status","message"],"properties":{"id":{"type":"integer","format":"int32"},"message":{"type":"string"},"name":{"type":"string"},"status":{"type":"string"}}},"UnifiedTrace":{"type":"object","description":"Merged cross-project trace result (Phase 2 unified waterfall).\n\nSpans are sorted by `start_time ASC`. At most 20 projects and 10,000\nspans total are included; `truncated` / `truncated_projects` signal when\nthe caps were hit.","required":["trace_id","projects","spans","start_time","end_time","total_duration_ms","span_count","error_count","has_redacted_spans","truncated","truncated_projects"],"properties":{"end_time":{"type":"string","format":"date-time"},"error_count":{"type":"integer","minimum":0},"has_redacted_spans":{"type":"boolean","description":"`true` when at least one project has `cross_project_trace_sharing = false`\nand its spans were therefore excluded from the result set."},"projects":{"type":"array","items":{"$ref":"#/components/schemas/ProjectRef"},"description":"Projects that contributed spans to this result set."},"span_count":{"type":"integer","minimum":0},"spans":{"type":"array","items":{"$ref":"#/components/schemas/AnnotatedSpan"},"description":"Annotated, merged span list sorted by `start_time ASC`."},"start_time":{"type":"string","format":"date-time"},"total_duration_ms":{"type":"number","format":"double","description":"Trace wall-clock duration in milliseconds (`end_time – start_time`)."},"trace_id":{"type":"string"},"truncated":{"type":"boolean","description":"`true` when the 20-project or 10,000-span cap was hit."},"truncated_projects":{"type":"array","items":{"type":"integer","format":"int32"},"description":"project_ids excluded due to truncation (most-recent first_seen dropped first)."}}},"UniqueCountsQuery":{"type":"object","description":"Query parameters for unique counts over time frame","required":["start_date","end_date"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32","description":"Optional deployment filter"},"end_date":{"type":"string","format":"date-time","description":"End date for the query range"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Optional environment filter"},"metric":{"type":"string","description":"Metric to count: \"sessions\" (unique sessions), \"visitors\" (unique visitors),\n\"returning_visitors\" (visitors seen before the range), or \"page_views\"\n(total page views) (default: \"sessions\")"},"start_date":{"type":"string","format":"date-time","description":"Start date for the query range"}}},"UniqueCountsResponse":{"type":"object","required":["count"],"properties":{"count":{"type":"integer","format":"int64"}}},"UnsupportedFeature":{"type":"object","description":"A feature from the source platform that cannot be migrated","required":["feature","reason"],"properties":{"alternative":{"type":["string","null"],"description":"Suggested alternative in Temps (if any)"},"feature":{"type":"string","description":"Feature name (e.g., \"Edge Middleware\", \"Serverless Functions\", \"Cron Jobs\")"},"reason":{"type":"string","description":"Why it can't be migrated"}}},"UpdateAdminGateRequest":{"type":"object","required":["allowed_ips","allowed_hosts","trust_forwarded_for"],"properties":{"allowed_hosts":{"type":"array","items":{"type":"string"}},"allowed_ips":{"type":"array","items":{"type":"string"}},"trust_forwarded_for":{"type":"boolean"}}},"UpdateAiProviderRequest":{"type":"object","description":"Body for `PATCH /settings/ai-providers/{provider_id}` — updates\nprovider-scoped settings (just the default model for now) without\ntouching the credential. Keeping credentials out of this shape means\nthe UI can auto-save model changes on select, without forcing the user\nto re-paste their token or config file.\nName-spaced schema name avoids an OpenAPI collision with\n`temps-notifications::UpdateProviderRequest`, which has different fields.\nBoth are exposed as `utoipa::ToSchema`; without the override the merged\nOpenAPI doc would silently shadow one struct with the other and break\ngenerated CLI/web clients.","properties":{"default_model":{"type":["string","null"],"description":"New default model id. `None` or an empty string clears the stored\nvalue so the CLI falls back to its own default."},"max_turns_analysis":{"type":["integer","null"],"format":"int32","description":"Default max turns for the autofixer analysis phase (1–200). `0`\nclears the stored value (built-in default applies); omitted/`None`\nleaves the current value unchanged — so a PATCH that only updates\n`default_model` doesn't wipe the turn settings."},"max_turns_feedback":{"type":["integer","null"],"format":"int32","description":"Default max turns for autofixer feedback rounds (1–200). `0` clears;\nomitted leaves unchanged."},"max_turns_fix":{"type":["integer","null"],"format":"int32","description":"Default max turns for the autofixer fix phase (1–200). `0` clears;\nomitted leaves unchanged."}}},"UpdateAiProviderResponse":{"type":"object","required":["provider_id"],"properties":{"default_model":{"type":["string","null"]},"max_turns_analysis":{"type":["integer","null"],"format":"int32"},"max_turns_feedback":{"type":["integer","null"],"format":"int32"},"max_turns_fix":{"type":["integer","null"],"format":"int32"},"provider_id":{"type":"string"}}},"UpdateAlertRuleRequest":{"type":"object","properties":{"cooldown_minutes":{"type":["integer","null"],"format":"int32"},"enabled":{"type":["boolean","null"]},"environment_filter":{"type":["integer","null"],"format":"int32"},"error_level_filter":{"type":["string","null"]},"name":{"type":["string","null"]},"notification_priority":{"type":["string","null"]},"trigger_config":{},"trigger_type":{"type":["string","null"]}}},"UpdateApiKeyRequest":{"type":"object","properties":{"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"is_active":{"type":["boolean","null"]},"name":{"type":["string","null"]},"permissions":{"type":["array","null"],"items":{"type":"string"},"example":["projects:read","deployments:read"]}}},"UpdateAutomaticDeployRequest":{"type":"object","required":["automatic_deploy"],"properties":{"automatic_deploy":{"type":"boolean"}}},"UpdateBackupScheduleRequest":{"type":"object","description":"Request body for updating an existing backup schedule via `PATCH /api/backups/schedules/{id}`.\n\nAll fields are optional; only present fields are updated. Absent fields\nleave the corresponding column unchanged.","properties":{"description":{"type":["string","null"],"description":"New human-readable description. Pass an empty string `\"\"` to clear."},"enabled":{"type":["boolean","null"],"description":"Enable or disable the schedule. Skipped when `None`."},"include_control_plane":{"type":["boolean","null"],"description":"Toggle whether the control-plane backup is produced on every run."},"max_runtime_secs":{"type":["integer","null"],"format":"int64","description":"Per-schedule wall-clock timeout override (seconds).\n\n- `None` (field absent) — leave current value unchanged\n- `Some(None)` (field present, JSON `null`) — clear override; fall back to engine default\n- `Some(Some(n))` — set to `n` seconds (must be >= 60)"},"name":{"type":["string","null"],"description":"New schedule name. Skipped when `None`. Must not be empty if provided."},"retention_period":{"type":["integer","null"],"format":"int32","description":"Days to retain backups produced by this schedule. Must be >= 1."},"schedule_expression":{"type":["string","null"],"description":"New cron expression. When changed, `next_run` is recomputed."},"tags":{"type":["array","null"],"items":{"type":"string"},"description":"Replace the full tag list. Skipped when `None`."},"target_all_services":{"type":["boolean","null"],"description":"Toggle between \"back up every database\" (`true`) and \"back up only\nthe explicit list\" (`false`). When set to `true`, the server clears\nthe explicit membership rows for this schedule."}}},"UpdateBlobRequest":{"type":"object","description":"Request to update Blob service configuration","properties":{"docker_image":{"type":["string","null"],"description":"Docker image to use (e.g., \"rustfs/rustfs:1.0.0-alpha.98\")","example":"rustfs/rustfs:1.0.0-alpha.98"}}},"UpdateBlobResponse":{"type":"object","description":"Response after updating Blob service","required":["success","message","status"],"properties":{"message":{"type":"string","description":"Human-readable message","example":"Blob service updated successfully"},"status":{"$ref":"#/components/schemas/BlobStatusResponse","description":"Current status"},"success":{"type":"boolean","description":"Whether the operation succeeded","example":true}}},"UpdateCapabilityResponse":{"type":"object","description":"Whether this install can apply a release update on request, and how the last\nattempt went.\n\nDeliberately answerable even when the answer is \"no\": an operator who cannot\nuse the button still needs to know *why* and what to run instead, so this\nnever 404s or returns an empty body when the feature is unavailable.","required":["can_apply","allowed","manual_command","current_version","channel","channel_is_pinned","supervisor","restart_mode","binary_path","phase"],"properties":{"allowed":{"type":"boolean","description":"Whether the *caller* holds `platform:update`. Distinct from `can_apply`,\nwhich describes the server: the console shows the action only when both\nare true, so a reader is never offered a button that would 403."},"binary_path":{"type":"string","description":"Binary that would be replaced."},"blocker":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SelfUpdateBlocker","description":"Machine-readable reason `can_apply` is false (`disabled_by_flag`,\n`disabled_by_setting`, `container`, `no_supervisor`, `binary_not_writable`,\n`unsupported_platform`, `in_progress`)."}]},"can_apply":{"type":"boolean","description":"True only when a request would actually download, install and restart."},"caveat":{"type":["string","null"],"description":"Non-blocking warning to show with the confirmation (split topology)."},"channel":{"type":"string","description":"Channel actually tracked, after applying the configured override or\nfalling back to inference from the running version tag."},"channel_is_pinned":{"type":"boolean","description":"True when `channel` was set explicitly in settings rather than inferred."},"current_version":{"type":"string","description":"Version tag of the running binary. Always present — the version page\nneeds it whether or not an update exists."},"last_attempt":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SelfUpdateAttempt","description":"Most recent attempt, including one resolved during this boot — this is\nhow the console reports the outcome of an update that restarted it."}]},"manual_command":{"type":"string","description":"The equivalent command to run by hand. Always present."},"phase":{"$ref":"#/components/schemas/SelfUpdatePhase","description":"Phase of an in-flight attempt: `idle` when none is running."},"phase_error":{"type":["string","null"],"description":"Failure detail while `phase` is `failed`."},"reason":{"type":["string","null"],"description":"Operator-facing explanation of `blocker`."},"restart_mode":{"$ref":"#/components/schemas/SelfUpdateRestartMode","description":"`automatic` when applying an update also restarts temps; `manual` when\nit only installs the binary and the operator restarts on their own\nschedule. Lets the console set expectations before the click."},"supervisor":{"$ref":"#/components/schemas/SupervisorKind","description":"What would restart the process: `systemd`, `launchd`, `container`, `none`."}}},"UpdateCloudflareProviderRequest":{"type":"object","required":["config"],"properties":{"config":{"$ref":"#/components/schemas/CloudflareConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":["string","null"]}}},"UpdateConfigBody":{"type":"object","properties":{"config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ProviderConfig","description":"Typed provider configuration. Setting `config` to `null` clears\nthe stored config back to the accept-everything default. The\nconfig's `provider` tag must match the integration's provider."}]}}},"UpdateCustomDomainRequest":{"type":"object","properties":{"branch":{"type":["string","null"]},"domain":{"type":["string","null"]},"environment_id":{"type":["integer","null"],"format":"int32"},"redirect_to":{"type":["string","null"]},"service_name":{"type":["string","null"],"description":"Docker Compose service name this domain routes to (empty string clears it)"},"status_code":{"type":["integer","null"],"format":"int32"}}},"UpdateDashboardRequest":{"type":"object","properties":{"layout":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DashboardLayout"}]},"name":{"type":["string","null"]}}},"UpdateDeploymentConfigRequest":{"type":"object","properties":{"automaticDeploy":{"type":["boolean","null"]},"cpuLimit":{"type":["integer","null"],"format":"int32"},"cpuRequest":{"type":["integer","null"],"format":"int32"},"crossArchitectureBuilds":{"type":["boolean","null"],"description":"Build one image per architecture the eligible nodes run. Off by\ndefault; environments inherit this and may override it. Cross-builds\nare emulated on the control plane and substantially slower, so they are\nopted into rather than triggered by cluster topology."},"exposedPort":{"type":["integer","null"],"format":"int32"},"memoryLimit":{"type":["integer","null"],"format":"int32"},"memoryRequest":{"type":["integer","null"],"format":"int32"},"performanceMetricsEnabled":{"type":["boolean","null"]},"replicas":{"type":["integer","null"],"format":"int32"},"security":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SecurityConfig"}]},"sessionRecordingEnabled":{"type":["boolean","null"]}}},"UpdateDeploymentTokenRequest":{"type":"object","properties":{"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"is_active":{"type":["boolean","null"]},"name":{"type":["string","null"]},"permissions":{"type":["array","null"],"items":{"type":"string"},"example":["visitors:enrich","emails:send"]}}},"UpdateDnsProviderRequest":{"type":"object","description":"Request to update a DNS provider","properties":{"credentials":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DnsProviderCredentials","description":"New credentials"}]},"description":{"type":["string","null"],"description":"New description"},"is_active":{"type":["boolean","null"],"description":"Active status"},"name":{"type":["string","null"],"description":"New name"}}},"UpdateEmailProviderRequest":{"type":"object","description":"Request body for `PATCH /email-providers/{id}`.\n\nAll fields are optional. Omit any field to leave it unchanged. The\n`provider_type` is immutable — to switch providers, delete the row and\ncreate a new one. For credentials, supplying any credential variant\nre-encrypts the stored blob; omitting them preserves the existing secret\n(so operators can rename without re-typing passwords).","properties":{"is_active":{"type":["boolean","null"]},"name":{"type":["string","null"],"example":"My AWS SES"},"region":{"type":["string","null"],"example":"us-east-1"},"scaleway_credentials":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ScalewayCredentialsRequest"}]},"ses_credentials":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SesCredentialsRequest"}]},"smtp_credentials":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SmtpCredentialsRequest"}]},"sns_topic_arn":{"type":["string","null"],"description":"Rotate or clear the exact SNS topic allowed for this SES provider.\nOmit to preserve it, send `null` to clear it, or send a string to set it."}}},"UpdateEnvironmentSettingsRequest":{"type":"object","properties":{"anti_affinity":{"type":["boolean","null"],"description":"Anti-affinity: spread replicas across different nodes.\nWhen enabled, the scheduler avoids placing two replicas of the same\nenvironment on the same node. Defaults to `true`."},"attack_mode":{"type":["boolean","null"],"description":"Per-environment CAPTCHA attack-mode override (tri-state):\n- absent → leave the current override unchanged\n- JSON `null` → clear the override (inherit the project-level setting)\n- `true`/`false` → override the project setting for this environment"},"automatic_deploy":{"type":["boolean","null"],"description":"Enable/disable automatic deployments for this environment"},"branch":{"type":["string","null"]},"cpu_limit":{"type":["integer","null"],"format":"int32","description":"Maximum (limit) CPU in microcores. Send JSON `null` to clear → \"no limit\".\nAbsent leaves the current value unchanged."},"cpu_request":{"type":["integer","null"],"format":"int32","description":"Minimum (request) CPU in microcores. Send JSON `null` to clear (no request).\nAbsent leaves the current value unchanged."},"cross_architecture_builds":{"type":["boolean","null"],"description":"Build one image per architecture the eligible nodes run (overrides the\nproject-level setting). Off by default: cross-architecture builds are\nemulated on the control plane and substantially slower, so they are\nopted into per environment rather than triggered by cluster topology."},"exposed_port":{"type":["integer","null"],"format":"int32","description":"Port exposed by the container (overrides project-level port for this environment)\n\nPriority order for port resolution:\n1. Image EXPOSE directive (auto-detected from built image)\n2. This environment-level exposed_port (overrides project setting)\n3. Project-level exposed_port (fallback)\n4. Default: 3000","example":8080},"force_https":{"type":["boolean","null"],"description":"Per-environment HTTP→HTTPS redirect override (tri-state):\n- absent → leave the current override unchanged\n- JSON `null` → clear the override (inherit the proxy default, which\n redirects only when the host has an active TLS certificate)\n- `true` → always redirect plain HTTP to HTTPS for this environment,\n even when no local certificate exists (TLS terminated upstream)\n- `false` → never redirect this environment, even when a certificate does\n exist\n\nRequests under `/.well-known/acme-challenge/` are never redirected\nregardless of this setting, so ACME HTTP-01 validation always completes."},"idle_timeout_seconds":{"type":["integer","null"],"format":"int32","description":"Seconds of inactivity before stopping containers (60-86400). Default: 300."},"memory_limit":{"type":["integer","null"],"format":"int32","description":"Maximum (limit) memory in MB. Send JSON `null` to clear → \"no limit\".\nAbsent leaves the current value unchanged."},"memory_request":{"type":["integer","null"],"format":"int32","description":"Minimum (request) memory in MB. Send JSON `null` to clear (no request).\nAbsent leaves the current value unchanged."},"on_demand":{"type":["boolean","null"],"description":"Enable on-demand mode (scale-to-zero). Containers are stopped after\nidle_timeout_seconds of no traffic and started on the next request."},"password":{"type":["string","null"],"description":"Set a password to protect this environment. The proxy will show an HTML\npassword form before allowing access. The password is bcrypt-hashed\nserver-side and never stored in plaintext.\nSend an empty string to remove password protection."},"performance_metrics_enabled":{"type":["boolean","null"],"description":"Enable/disable performance metrics collection"},"protected":{"type":["boolean","null"],"description":"When true, git pushes do NOT auto-deploy to this environment.\nDeployments must be promoted from another environment."},"replicas":{"type":["integer","null"],"format":"int32"},"security":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SecurityConfig","description":"Security configuration for this environment (overrides project-level settings)"}]},"session_recording_enabled":{"type":["boolean","null"],"description":"Enable/disable session recording"},"target_labels":{"description":"Label selector for node-based scheduling (overrides project-level setting).\nSame key with array value -> OR, different keys -> AND.\nExample: `{\"region\": [\"us\", \"asia\"], \"gpu\": \"true\"}`"},"target_nodes":{"type":["array","null"],"items":{"type":"integer","format":"int32"},"description":"Optional list of node IDs to deploy to (overrides project-level setting)"},"wake_timeout_seconds":{"type":["integer","null"],"format":"int32","description":"Max seconds to wait for containers to start on wake (5-120). Default: 30."}}},"UpdateEnvironmentSubdomainRequest":{"type":"object","description":"Request to rename an environment's auto-managed subdomain.\n\nThe subdomain is the host label inserted in front of the platform's\npreview domain (e.g. `myapp` in `myapp.preview.temps.sh`). Renaming\nreplaces the previous subdomain entirely — the old hostname stops\nresolving immediately after this request succeeds.","required":["subdomain"],"properties":{"subdomain":{"type":"string","description":"New subdomain label. Must be a DNS-safe slug (lowercase letters,\ndigits, and hyphens, 1-63 characters). The value is slugified\nserver-side, so casing and disallowed characters are normalized.","example":"myapp"}}},"UpdateEnvironmentVariableRequest":{"type":"object","required":["key","environment_ids"],"properties":{"environment_ids":{"type":"array","items":{"type":"integer","format":"int32"}},"include_in_preview":{"type":"boolean"},"is_secret":{"type":["boolean","null"],"description":"Optional secret-flag transition.\n- `Some(true)` promotes a regular var to a secret.\n- `Some(false)` is rejected if the row is already secret (one-way flag).\n- `None` (omitted) leaves the flag unchanged."},"key":{"type":"string"},"value":{"type":["string","null"],"description":"New plaintext value. `None` (omitted) keeps the existing ciphertext,\nwhich is the only way to edit a secret env var without re-typing its\nvalue (e.g. changing which environments it applies to)."}}},"UpdateErrorGroupRequest":{"type":"object","required":["status"],"properties":{"assigned_to":{"type":["string","null"]},"status":{"type":"string"}}},"UpdateExternalServiceRequest":{"type":"object","required":["parameters"],"properties":{"docker_image":{"type":["string","null"],"description":"Docker image to use for the service (e.g., \"gotempsh/postgres-walg:18-bookworm\", \"timescale/timescaledb-ha:pg18\")\nWhen provided, the service will be recreated with the new image while preserving data"},"parameters":{"type":"object","additionalProperties":{},"propertyNames":{"type":"string"}}}},"UpdateFlagRequest":{"type":"object","properties":{"client_visible":{"type":["boolean","null"]},"default_value":{"description":"Must match the flag's existing `value_type`."},"description":{"type":["string","null"],"description":"Tri-state: absent leaves it, `null` clears it, a string sets it."}}},"UpdateGitSettingsRequest":{"type":"object","required":["main_branch","repo_owner","repo_name","directory"],"properties":{"directory":{"type":"string"},"git_provider_connection_id":{"type":["integer","null"],"format":"int32"},"git_url":{"type":["string","null"],"description":"Git clone URL for public repositories"},"is_public_repo":{"type":["boolean","null"],"description":"Whether this is a public repository (no git provider connection needed)"},"main_branch":{"type":"string"},"preset":{"type":["string","null"]},"preset_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PresetConfigSchema","description":"Preset-specific configuration (e.g., Dockerfile path for Docker preset)\n\nExample for Dockerfile preset:\n```json\n{\n \"dockerfilePath\": \"docker/Dockerfile\",\n \"buildContext\": \"./api\"\n}\n```"}]},"repo_name":{"type":"string"},"repo_owner":{"type":"string"}}},"UpdateIncidentStatusRequest":{"type":"object","required":["status","message"],"properties":{"message":{"type":"string"},"status":{"type":"string"}}},"UpdateIpAccessControlRequest":{"type":"object","description":"Request to update an IP access control rule","properties":{"action":{"type":["string","null"],"description":"Optional new action"},"ip_address":{"type":["string","null"],"description":"Optional new IP address"},"reason":{"type":["string","null"],"description":"Optional new reason"}}},"UpdateKvRequest":{"type":"object","description":"Request to update KV service configuration","properties":{"docker_image":{"type":["string","null"],"description":"Docker image to use (e.g., \"gotempsh/redis-walg:8-bookworm\")","example":"gotempsh/redis-walg:8-bookworm"}}},"UpdateKvResponse":{"type":"object","description":"Response after updating KV service","required":["success","message","status"],"properties":{"message":{"type":"string","description":"Status message","example":"KV service updated successfully"},"status":{"$ref":"#/components/schemas/KvStatusResponse","description":"Current service status"},"success":{"type":"boolean","description":"Whether the operation succeeded"}}},"UpdateManagedDomainApiRequest":{"type":"object","description":"Request to update a managed domain's settings.","properties":{"auto_manage":{"type":["boolean","null"],"description":"Toggle automatic DNS management for this domain."},"generated_hostname_mode":{"type":["string","null"],"description":"`\"standard\"` or `\"flat\"`. Persisted as-is; switching to `\"flat\"` does not\nrecompute existing hostnames — use the apply endpoint for that."},"sync_generated_records":{"type":["boolean","null"],"description":"Toggle DNS record sync for this domain."}}},"UpdateMcpRequest":{"type":"object","required":["config"],"properties":{"config":{"type":"object"},"description":{"type":["string","null"]},"name":{"type":["string","null"]}}},"UpdateMemberRoleRequest":{"type":"object","description":"The new fixed role for an existing membership.","required":["role"],"properties":{"role":{"$ref":"#/components/schemas/TeamRole"}}},"UpdateMetricAlertRequest":{"type":"object","properties":{"aggregation":{"type":["string","null"]},"detection_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DetectionConfig","description":"Replaces the detector wholesale when present (absent = leave unchanged)."}]},"dynamic_alerts":{"type":["boolean","null"],"description":"Toggles per-series (\"dynamic\") alerting (absent = leave unchanged)."},"enabled":{"type":["boolean","null"]},"for_duration_secs":{"type":["integer","null"],"format":"int32"},"group_by":{"type":["array","null"],"items":{"type":"string"},"description":"Replaces the group_by keys wholesale when present (absent = leave unchanged)."},"grouped_notification_threshold":{"type":["integer","null"],"format":"int32","description":"Updates the notification-grouping threshold (absent = leave unchanged)."},"label_filters":{"type":["array","null"],"items":{"type":"array","items":false,"prefixItems":[{"type":"string"},{"type":"string"}]},"description":"Replaces the label filters wholesale when present (absent = leave unchanged)."},"max_series":{"type":["integer","null"],"format":"int32","description":"Updates the dynamic-alerting cardinality cap (absent = leave unchanged)."},"metric_name":{"type":["string","null"]},"name":{"type":["string","null"]},"severity":{"type":["string","null"]},"window_secs":{"type":["integer","null"],"format":"int32"}}},"UpdateNotificationEmailProviderRequest":{"type":"object","required":["config"],"properties":{"config":{"$ref":"#/components/schemas/EmailConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":["string","null"]}}},"UpdateOidcProviderRequest":{"type":"object","properties":{"client_id":{"type":["string","null"]},"client_secret":{"type":["string","null"]},"default_role":{"type":["string","null"]},"enabled":{"type":["boolean","null"]},"group_claim":{"type":["string","null"]},"issuer_url":{"type":["string","null"]},"jit_provisioning":{"type":["boolean","null"]},"name":{"type":["string","null"]},"role_claim":{"type":["string","null"]},"scopes":{"type":["string","null"]},"template":{"type":["string","null"]},"trust_idp_email":{"type":["boolean","null"]}}},"UpdatePreferencesRequest":{"type":"object","required":["preferences"],"properties":{"preferences":{"$ref":"#/components/schemas/NotificationPreferencesResponse"}}},"UpdateProjectSecretRequest":{"type":"object","description":"Request to update a project secret. The `value` field is optional — omit it\nto rotate only the environment scoping / preview flag without touching the\nciphertext.","properties":{"environment_ids":{"type":"array","items":{"type":"integer","format":"int32"}},"include_in_preview":{"type":"boolean"},"value":{"type":["string","null"],"description":"New plaintext value, <= 1 MiB. Omit to keep the existing value."}}},"UpdateProjectSettingsRequest":{"type":"object","properties":{"ai_alert_summaries_enabled":{"type":["boolean","null"],"description":"Opt in to AI summarization of metric alert notifications (ADR-021)."},"ai_debug_chat_enabled":{"type":["boolean","null"],"description":"Opt in to AI debugging chat, e.g. on deployment failures (ADR-023)."},"ai_write_actions_enabled":{"type":["boolean","null"],"description":"Opt in to AI propose-then-confirm write capability."},"attack_mode":{"type":["boolean","null"],"description":"Enable/disable attack mode (CAPTCHA protection) for all project environments"},"cross_project_trace_sharing":{"type":["boolean","null"],"description":"ADR-027 Phase 3 opt-out: set to false to suppress this project's traces\nfrom appearing in cross-project discovery results. Default true (consistent\nwith the OSS global-observability model). Omit to leave unchanged."},"directory":{"type":["string","null"]},"enable_preview_environments":{"type":["boolean","null"],"description":"Enable automatic preview environment creation for each branch"},"error_source_context_enabled":{"type":["boolean","null"],"description":"Opt in to native error-tracking source context (source-file upload +\nsource code shown in stack traces)."},"error_source_root":{"type":["string","null"],"description":"Set the auto-capture source root (relative to the checkout). Send an\nempty string to clear it back to the build-context default. Omit to\nleave unchanged."},"git_provider_connection_id":{"type":["integer","null"],"format":"int32"},"main_branch":{"type":["string","null"]},"preset":{"type":["string","null"]},"preset_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PresetConfigSchema","description":"Preset-specific configuration (e.g., Dockerfile path for Docker preset)\n\nExample for Dockerfile preset:\n```json\n{\n \"dockerfilePath\": \"docker/Dockerfile\",\n \"buildContext\": \"./api\"\n}\n```"}]},"preview_envs_idle_timeout_seconds":{"type":["integer","null"],"format":"int32","description":"Idle timeout (seconds, 60..=86400) for on-demand preview environments."},"preview_envs_on_demand":{"type":["boolean","null"],"description":"When true, newly-created preview environments default to on-demand mode."},"preview_envs_wake_timeout_seconds":{"type":["integer","null"],"format":"int32","description":"Wake timeout (seconds, 5..=120) for on-demand preview environments."},"repo_name":{"type":["string","null"]},"repo_owner":{"type":["string","null"]},"slug":{"type":["string","null"]}}},"UpdateProviderCredentialsRequest":{"type":"object","description":"Partial-update payload for provider credentials. Every field is optional;\nonly the fields the user re-enters are applied. The server validates that\nthe fields supplied make sense for the provider's current auth_method\n(e.g. `app_id` + `private_key` only apply to GitHub Apps).","properties":{"app_id":{"type":["string","null"],"description":"Application ID (GitHub App integer as string; GitLab App string)."},"app_secret":{"type":["string","null"],"description":"GitLab App secret (not used by GitHub App — use `client_secret`)."},"client_id":{"type":["string","null"],"description":"OAuth client ID (GitLab OAuth, GitHub App)."},"client_secret":{"type":["string","null"],"description":"OAuth client secret (GitLab OAuth, GitHub App)."},"private_key":{"type":["string","null"],"description":"GitHub App private key (PEM)."},"redirect_uri":{"type":["string","null"],"description":"OAuth redirect URI (GitLab OAuth / GitLab App)."},"token":{"type":["string","null"],"description":"PAT for PAT-type providers."},"webhook_secret":{"type":["string","null"],"description":"GitHub App webhook secret."}}},"UpdateProviderKeyRequest":{"type":"object","properties":{"api_key":{"type":["string","null"]},"base_url":{"type":["string","null"],"description":"Double-Option: absent = leave unchanged, present-null = clear (revert to\nthe provider's default endpoint), present-value = set."},"default_model":{"type":["string","null"],"description":"Double-Option: absent = leave unchanged, present-null = clear the pinned\nmodel (revert to the per-provider default), present-value = set."},"display_name":{"type":["string","null"]},"is_active":{"type":["boolean","null"]}}},"UpdateProviderRequest":{"type":"object","properties":{"config":{},"enabled":{"type":["boolean","null"]},"name":{"type":["string","null"]}}},"UpdateRouteRequest":{"type":"object","required":["host","port","enabled"],"properties":{"enabled":{"type":"boolean"},"host":{"type":"string"},"port":{"type":"integer","format":"int32"},"route_type":{"type":["string","null"],"description":"Route type: \"http\" (default) matches on HTTP Host header,\n\"tls\" matches on TLS SNI hostname for TCP passthrough"}}},"UpdateS3SourceRequest":{"type":"object","properties":{"access_key_id":{"type":["string","null"],"description":"Optional new access key ID","example":"AKIAXXXXXXXXXXXXXXXX"},"bucket_name":{"type":["string","null"],"description":"Optional new bucket name"},"bucket_path":{"type":["string","null"],"description":"Optional new bucket path"},"endpoint":{"type":["string","null"],"description":"Optional new endpoint URL for S3-compatible services","example":"http://minio.example.com:9000"},"force_path_style":{"type":["boolean","null"],"description":"Optional new path-style addressing setting","example":true},"name":{"type":["string","null"],"description":"Optional new name for the source"},"region":{"type":["string","null"],"description":"Optional new region"},"secret_key":{"type":["string","null"],"description":"Optional new secret key"}}},"UpdateSecretBody":{"type":"object","required":["signing_secret"],"properties":{"signing_secret":{"type":"string","description":"New signing secret from the provider's dashboard. Encrypted at\nrest; never returned in any API response."}}},"UpdateSelfRequest":{"type":"object","properties":{"email":{"type":["string","null"],"example":"john.doe@example.com"},"name":{"type":["string","null"],"example":"John Doe"}}},"UpdateSessionDurationRequest":{"type":"object","required":["duration"],"properties":{"duration":{"type":"integer","format":"int32"}}},"UpdateSessionDurationResponse":{"type":"object","required":["message"],"properties":{"message":{"type":"string"}}},"UpdateSkillRequest":{"type":"object","properties":{"content":{"type":["string","null"]},"description":{"type":["string","null"]},"name":{"type":["string","null"]}}},"UpdateSlackProviderRequest":{"type":"object","required":["config"],"properties":{"config":{"$ref":"#/components/schemas/SlackConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":["string","null"]}}},"UpdateSpeedMetricsPayload":{"type":"object","description":"Update speed metrics payload for late-loading metrics","properties":{"cls":{"type":["number","null"],"format":"float","description":"Cumulative Layout Shift (score)"},"inp":{"type":["number","null"],"format":"float","description":"Interaction to Next Paint (milliseconds)"}}},"UpdateStatusResponse":{"type":"object","description":"Result of the background release-update check, driving the web console's\nupgrade banner. All optional fields are set together iff\n`update_available` is true.","required":["update_available","docs_url"],"properties":{"channel":{"type":["string","null"],"description":"Channel the install tracks: `stable` or `beta`."},"checked_at":{"type":["string","null"],"description":"When the check that found the update ran (ISO 8601, UTC)."},"current_version":{"type":["string","null"],"description":"Version tag of the running binary, e.g. `v0.1.0-beta.45`."},"docs_url":{"type":"string","description":"Docs page with upgrade instructions. Always present so the UI links\nthe same page regardless of update state."},"latest_version":{"type":["string","null"],"description":"Newest published tag on this install's channel."},"release_url":{"type":["string","null"],"description":"Release-notes page (GitHub release) for the newer version."},"update_available":{"type":"boolean","description":"True when a newer release than the running binary has been published\non this install's channel."}}},"UpdateTeamRequest":{"type":"object","properties":{"description":{"type":["string","null"]},"name":{"type":["string","null"]}}},"UpdateTokenRequest":{"type":"object","required":["access_token"],"properties":{"access_token":{"type":"string"},"refresh_token":{"type":["string","null"]}}},"UpdateTokenResponse":{"type":"object","required":["connection_id","message","is_active"],"properties":{"connection_id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"message":{"type":"string"}}},"UpdateUserRequest":{"type":"object","properties":{"email":{"type":["string","null"],"example":"john.doe@example.com"},"name":{"type":["string","null"],"example":"John Doe"}}},"UpdateWebhookProviderRequest":{"type":"object","required":["config"],"properties":{"config":{"$ref":"#/components/schemas/WebhookConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":["string","null"]}}},"UpdateWebhookRequestBody":{"type":"object","properties":{"enabled":{"type":["boolean","null"],"description":"Whether the webhook is enabled"},"events":{"type":["array","null"],"items":{"type":"string"},"description":"Event types to subscribe to"},"secret":{"type":["string","null"],"description":"Secret for HMAC signature verification"},"url":{"type":["string","null"],"description":"Target URL for webhook delivery"}}},"UpgradeExternalServiceRequest":{"type":"object","required":["docker_image"],"properties":{"docker_image":{"type":"string","description":"Docker image to upgrade to (e.g., \"gotempsh/postgres-walg:18-bookworm\")\nThis will trigger pg_upgrade for PostgreSQL or equivalent upgrade procedures for other services","example":"gotempsh/postgres-walg:18-bookworm"}}},"UpgradeRequest":{"type":"object","required":["image"],"properties":{"image":{"type":"string","description":"Image reference to pull and run (e.g.\n`ghcr.io/gotempsh/temps-preview-gateway:latest`). Empty resets to default."}}},"UpsertAgentRequest":{"type":"object","properties":{"ai_model":{"type":["string","null"],"description":"Preferred model identifier for the CLI. `Some(\"\")` clears the stored value."},"ai_provider":{"type":["string","null"]},"ai_provider_key_id":{"type":["integer","null"],"format":"int32"},"api_key":{"type":["string","null"],"description":"Plain-text API key — will be encrypted before storage"},"branch_prefix":{"type":["string","null"]},"config_repo_branch":{"type":["string","null"],"description":"Branch of the config repo to use (default: \"main\")."},"config_repo_url":{"type":["string","null"],"description":"Private config repo containing .claude/ directory (skills, MCP, plugins)."},"cooldown_minutes":{"type":["integer","null"],"format":"int32"},"daily_budget_cents":{"type":["integer","null"],"format":"int32"},"deliverable":{"type":["string","null"]},"description":{"type":["string","null"]},"enabled":{"type":["boolean","null"]},"max_turns":{"type":["integer","null"],"format":"int32"},"mcp_servers_config":{"description":"MCP servers config (Claude Code settings.json mcpServers format).\nCredential-bearing legacy inline objects are write-only: normal reads\nmask them, and updates must omit this field to preserve existing values."},"name":{"type":["string","null"]},"prompt":{"type":["string","null"]},"sandbox_enabled":{"type":["boolean","null"]},"skills_config":{"description":"Skills config as JSON array."},"slug":{"type":["string","null"]},"timeout_seconds":{"type":["integer","null"],"format":"int32"},"tools_config":{"description":"Tools config as JSON array. Custom-tool webhook URLs and headers are\nwrite-only; omit this field on update to preserve them."},"trigger_config":{"description":"Trigger configuration JSON: { \"error\": { \"new_issue\": true, \"regression\": true }, \"manual\": true }"}}},"UpsertSecretRequest":{"type":"object","required":["name","value"],"properties":{"description":{"type":["string","null"]},"mount_path":{"type":["string","null"],"description":"Required for \"file\" type secrets — absolute path inside the sandbox"},"name":{"type":"string"},"secret_type":{"type":"string","description":"\"env\" (environment variable) or \"file\" (written to mount_path)"},"value":{"type":"string"}}},"UptimeDataPoint":{"type":"object","required":["timestamp","status"],"properties":{"error_message":{"type":["string","null"]},"response_time_ms":{"type":["integer","null"],"format":"int32"},"status":{"type":"string"},"timestamp":{"type":"string","format":"date-time"}}},"UptimeHistoryResponse":{"type":"object","required":["monitor_id","uptime_data"],"properties":{"monitor_id":{"type":"integer","format":"int32"},"uptime_data":{"type":"array","items":{"$ref":"#/components/schemas/UptimeDataPoint"}}}},"UsageFilter":{"type":"object","description":"Filters for querying AI usage data.\n\nCost bounds are expressed in microcents (the unit stored in\n`estimated_cost_microcents`). At most one of `gte`/`gt` and one of\n`lte`/`lt` is meaningful per query; if both are set the stricter wins\nnaturally because they are ANDead together.","properties":{"conversation_id":{"type":["string","null"]},"cost_gt":{"type":["integer","null"],"format":"int64","description":"Cost strictly greater-than, in microcents."},"cost_gte":{"type":["integer","null"],"format":"int64","description":"Cost greater-than-or-equal, in microcents."},"cost_lt":{"type":["integer","null"],"format":"int64","description":"Cost strictly less-than, in microcents."},"cost_lte":{"type":["integer","null"],"format":"int64","description":"Cost less-than-or-equal, in microcents."},"model":{"type":["string","null"]},"provider":{"type":["string","null"]},"status":{"type":["integer","null"],"format":"int32","description":"Filter by HTTP status code (exact match)."},"tags":{"type":["string","null"],"description":"Comma-separated tags to filter by (AND logic)."},"tokens_gt":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) strictly greater-than."},"tokens_gte":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) greater-than-or-equal."},"tokens_lt":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) strictly less-than."},"tokens_lte":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) less-than-or-equal."},"user_id":{"type":["integer","null"],"format":"int32"}}},"UsageInfo":{"type":"object","required":["prompt_tokens","completion_tokens","total_tokens"],"properties":{"completion_tokens":{"type":"integer","format":"int64"},"prompt_tokens":{"type":"integer","format":"int64"},"total_tokens":{"type":"integer","format":"int64"}}},"UsageLogEntry":{"type":"object","required":["id","timestamp","provider","model","input_tokens","output_tokens","latency_ms","estimated_cost_microcents","status","is_streaming","is_byok","tags"],"properties":{"conversation_id":{"type":["string","null"]},"estimated_cost_microcents":{"type":"integer","format":"int64"},"id":{"type":"integer","format":"int64"},"input_tokens":{"type":"integer","format":"int64"},"is_byok":{"type":"boolean"},"is_streaming":{"type":"boolean"},"latency_ms":{"type":"integer","format":"int32"},"model":{"type":"string"},"output_tokens":{"type":"integer","format":"int64"},"provider":{"type":"string"},"request_id":{"type":["string","null"]},"status":{"type":"integer","format":"int32"},"tags":{"type":"array","items":{"type":"string"}},"timestamp":{"type":"string"},"trace_id":{"type":["string","null"]}}},"UsageLogPage":{"type":"object","description":"A page of recent usage log entries plus the total count for pagination.","required":["entries","total"],"properties":{"entries":{"type":"array","items":{"$ref":"#/components/schemas/UsageLogEntry"},"description":"The usage log entries for the requested page."},"total":{"type":"integer","format":"int64","description":"Total number of entries matching the filter (across all pages)."}}},"UsageQueryParams":{"type":"object","properties":{"conversation_id":{"type":["string","null"],"description":"Filter by conversation ID"},"from":{"type":["string","null"],"description":"ISO 8601 start time (defaults to 24h ago)"},"model":{"type":["string","null"],"description":"Filter by model name"},"provider":{"type":["string","null"],"description":"Filter by provider name"},"tags":{"type":["string","null"],"description":"Filter by tags (comma-separated, AND logic)"},"to":{"type":["string","null"],"description":"ISO 8601 end time (defaults to now)"},"user_id":{"type":["integer","null"],"format":"int32","description":"Filter by user ID"}}},"UsageSource":{"type":"string","description":"How the \"actual usage\" numbers were obtained","enum":["metrics-api","requests-only","unavailable"]},"UsageSummary":{"type":"object","required":["total_requests","total_input_tokens","total_output_tokens","total_tokens","avg_latency_ms","total_cost_microcents","error_count","streaming_count","byok_count"],"properties":{"avg_latency_ms":{"type":"number","format":"double"},"byok_count":{"type":"integer","format":"int64"},"error_count":{"type":"integer","format":"int64"},"streaming_count":{"type":"integer","format":"int64"},"total_cost_microcents":{"type":"integer","format":"int64"},"total_input_tokens":{"type":"integer","format":"int64"},"total_output_tokens":{"type":"integer","format":"int64"},"total_requests":{"type":"integer","format":"int64"},"total_tokens":{"type":"integer","format":"int64"}}},"UserResponse":{"type":"object","required":["id","username","name","avatar_url","mfa_enabled","role"],"properties":{"avatar_url":{"type":"string"},"email":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"mfa_enabled":{"type":"boolean"},"name":{"type":"string"},"role":{"type":"string","description":"User's role (e.g., \"admin\", \"user\", \"demo\")"},"username":{"type":"string"}}},"ValidateEmailRequest":{"type":"object","description":"Request body for validating an email address","required":["email"],"properties":{"email":{"type":"string","description":"Email address to validate","example":"someone@gmail.com"}},"additionalProperties":false},"ValidateEmailResponse":{"type":"object","description":"Complete email validation response","required":["email","is_reachable","syntax","mx","misc","smtp"],"properties":{"email":{"type":"string","description":"The email address that was validated","example":"someone@gmail.com"},"is_reachable":{"$ref":"#/components/schemas/ReachabilityStatus","description":"Overall reachability status: safe, risky, invalid, or unknown"},"misc":{"$ref":"#/components/schemas/MiscResult","description":"Miscellaneous validation result"},"mx":{"$ref":"#/components/schemas/MxResult","description":"MX record validation result"},"smtp":{"$ref":"#/components/schemas/SmtpResult","description":"SMTP validation result"},"syntax":{"$ref":"#/components/schemas/SyntaxResult","description":"Syntax validation result"}}},"ValidationLevel":{"type":"string","description":"Validation severity level","enum":["info","warning","error","critical"]},"ValidationReport":{"type":"object","description":"Complete validation report","required":["results","overall_status","summary"],"properties":{"overall_status":{"$ref":"#/components/schemas/ValidationStatus","description":"Overall status"},"results":{"type":"array","items":{"$ref":"#/components/schemas/ValidationResult"},"description":"All validation results"},"summary":{"$ref":"#/components/schemas/ValidationSummary","description":"Summary statistics"}}},"ValidationResponse":{"type":"object","required":["connection_id","is_valid","message"],"properties":{"connection_id":{"type":"integer","format":"int32"},"is_valid":{"type":"boolean"},"message":{"type":"string"}}},"ValidationResult":{"type":"object","description":"Result of a validation check","required":["rule_id","rule_name","level","passed","message","affected_resources"],"properties":{"affected_resources":{"type":"array","items":{"type":"string"},"description":"Affected resources/fields"},"level":{"$ref":"#/components/schemas/ValidationLevel","description":"Validation level"},"message":{"type":"string","description":"Message describing the result"},"passed":{"type":"boolean","description":"Whether the validation passed"},"remediation":{"type":["string","null"],"description":"Suggested remediation (if failed)"},"rule_id":{"type":"string","description":"Rule that was checked"},"rule_name":{"type":"string","description":"Human-readable rule name"}}},"ValidationStatus":{"type":"string","description":"Overall validation status","enum":["passed","passed-with-warnings","failed-with-warnings","failed"]},"ValidationSummary":{"type":"object","description":"Validation summary statistics","required":["total_count","passed_count","failed_count","info_count","warning_count","error_count","critical_count"],"properties":{"critical_count":{"type":"integer","description":"Critical-level results","minimum":0},"error_count":{"type":"integer","description":"Error-level results","minimum":0},"failed_count":{"type":"integer","description":"Validations that failed","minimum":0},"info_count":{"type":"integer","description":"Info-level results","minimum":0},"passed_count":{"type":"integer","description":"Validations that passed","minimum":0},"total_count":{"type":"integer","description":"Total validations run","minimum":0},"warning_count":{"type":"integer","description":"Warning-level results","minimum":0}}},"VerifyMfaRequest":{"type":"object","required":["code"],"properties":{"code":{"type":"string"}}},"VerifyStepUpRequest":{"type":"object","required":["code"],"properties":{"code":{"type":"string","description":"Current TOTP value or an unused recovery code."}}},"ViewItem":{"type":"object","required":["label","value"],"properties":{"label":{"type":"string","format":"date-time"},"value":{"type":"integer","format":"int64"}}},"ViewsOverTime":{"type":"object","required":["items","metric","present_index"],"properties":{"comparison_labels":{"type":["array","null"],"items":{"type":"string"}},"comparison_plot":{"type":["array","null"],"items":{"type":"integer","format":"int64"}},"full_intervals":{"type":["array","null"],"items":{"type":"string"}},"items":{"type":"array","items":{"$ref":"#/components/schemas/ViewItem"}},"metric":{"type":"string"},"present_index":{"type":"integer","minimum":0}}},"ViewsOverTimeQuery":{"type":"object","required":["start_date","end_date","project_id"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"VisitorDetails":{"type":"object","required":["id","visitor_id","project_id","environment_id","first_seen","last_seen","is_crawler"],"properties":{"city":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"crawler_name":{"type":["string","null"]},"custom_data":{},"environment_id":{"type":"integer","format":"int32"},"first_channel":{"type":["string","null"],"description":"Marketing channel from the first visit (e.g. \"Organic Search\", \"Direct\")"},"first_referrer":{"type":["string","null"],"description":"Full referrer URL from the visitor's first session"},"first_referrer_hostname":{"type":["string","null"],"description":"Hostname extracted from first_referrer"},"first_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"id":{"type":"integer","format":"int32"},"ip_address":{"type":["string","null"]},"ip_address_id":{"type":["integer","null"],"format":"int32"},"is_crawler":{"type":"boolean"},"is_eu":{"type":["boolean","null"]},"last_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"latitude":{"type":["number","null"],"format":"double"},"longitude":{"type":["number","null"],"format":"double"},"project_id":{"type":"integer","format":"int32"},"region":{"type":["string","null"]},"timezone":{"type":["string","null"]},"user_agent":{"type":["string","null"]},"visitor_id":{"type":"string"}}},"VisitorFacetValue":{"type":"object","description":"A single facet value with its visitor count. Used to populate filter\ndropdowns on the visitors page (e.g. \"Germany — 1,234 visitors\").","required":["value","count"],"properties":{"code":{"type":["string","null"],"description":"Optional secondary code for the value. Currently only populated for\nthe `country` facet, where it carries the 2-letter ISO country code\nso the UI can render a flag without re-mapping."},"count":{"type":"integer","format":"int64","description":"Distinct visitor count matching this value in the current segment."},"value":{"type":"string","description":"The dimension value (e.g. \"United States\", \"Chrome\", \"google.com\").\n`None` is encoded as the literal string \"Direct\" for referrer and as\nthe empty string for the rest."}}},"VisitorFacets":{"type":"object","description":"All filter dropdown contents in one response. Each list is the top N\nvalues for that dimension within the current date range and segment\n(excluding the dimension being queried so the dropdown still shows\nalternatives when a value is already selected).","required":["country","region","city","channel","referrer"],"properties":{"channel":{"type":"array","items":{"$ref":"#/components/schemas/VisitorFacetValue"}},"city":{"type":"array","items":{"$ref":"#/components/schemas/VisitorFacetValue"}},"country":{"type":"array","items":{"$ref":"#/components/schemas/VisitorFacetValue"}},"referrer":{"type":"array","items":{"$ref":"#/components/schemas/VisitorFacetValue"}},"region":{"type":"array","items":{"$ref":"#/components/schemas/VisitorFacetValue"}}}},"VisitorFacetsQuery":{"allOf":[{"$ref":"#/components/schemas/VisitorSegmentFilters"},{"type":"object","required":["start_date","end_date","project_id"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"has_activity_only":{"type":["boolean","null"]},"include_crawlers":{"type":["boolean","null"]},"per_facet_limit":{"type":["integer","null"],"format":"int32","description":"Maximum number of values returned per dimension (default: 50, max: 200)."},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}}],"description":"Query parameters for the visitor-facets endpoint. Mirrors the shape of\n`VisitorsListQuery` so the same segment filters apply — facet counts are\nalways computed against the *currently filtered* visitor pool, minus the\ndimension being aggregated."},"VisitorInfo":{"type":"object","required":["id","visitor_id","project_id","environment_id","first_seen","last_seen","is_crawler"],"properties":{"city":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"crawler_name":{"type":["string","null"]},"current_page":{"type":["string","null"],"description":"Most recent page path visited by this visitor"},"custom_data":{},"environment_id":{"type":"integer","format":"int32"},"first_channel":{"type":["string","null"],"description":"Marketing channel from the first visit (e.g. \"Organic Search\", \"Direct\")"},"first_referrer":{"type":["string","null"],"description":"Full referrer URL from the visitor's first session"},"first_referrer_hostname":{"type":["string","null"],"description":"Hostname extracted from first_referrer"},"first_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"id":{"type":"integer","format":"int32"},"ip_address":{"type":["string","null"]},"ip_address_id":{"type":["integer","null"],"format":"int32"},"is_crawler":{"type":"boolean"},"is_eu":{"type":["boolean","null"]},"last_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"latitude":{"type":["number","null"],"format":"double"},"longitude":{"type":["number","null"],"format":"double"},"project_id":{"type":"integer","format":"int32"},"region":{"type":["string","null"]},"timezone":{"type":["string","null"]},"user_agent":{"type":["string","null"]},"visitor_id":{"type":"string"}}},"VisitorJourneyQuery":{"type":"object","required":["project_id"],"properties":{"limit_sessions":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"}}},"VisitorJourneyResponse":{"type":"object","description":"Complete visitor journey response","required":["visitor_id","total_sessions","total_events","sessions"],"properties":{"sessions":{"type":"array","items":{"$ref":"#/components/schemas/JourneySession"},"description":"Sessions with their events, ordered newest first"},"total_events":{"type":"integer","format":"int64","description":"Total number of events across all sessions"},"total_sessions":{"type":"integer","format":"int64","description":"Total number of sessions"},"visitor_id":{"type":"integer","format":"int32","description":"Visitor internal ID"}}},"VisitorLocationsQuery":{"type":"object","required":["start_date","end_date","project_id"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"granularity":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/LocationGranularity"}]},"limit":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"VisitorRecord":{"type":"object","required":["id","visitor_id","project_id","created_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"custom_data":{},"id":{"type":"integer","format":"int32"},"project_id":{"type":"integer","format":"int32"},"visitor_id":{"type":"string"}}},"VisitorSegmentFilters":{"type":"object","description":"Optional segment filters for [`VisitorsListQuery`]. Each filter narrows the\nresult set to visitors who match the given dimension value within the date\nrange. All filters resolve against `visitor` / `ip_geolocations` — by\ndesign we never touch the events hypertable here so filtering stays fast\nregardless of event volume.","properties":{"filter_channel":{"type":["string","null"],"description":"First-touch marketing channel (matches `visitor.first_channel`)"},"filter_city":{"type":["string","null"],"description":"Geolocation city (matches `ip_geolocations.city`)"},"filter_country":{"type":["string","null"],"description":"Geolocation country (matches `ip_geolocations.country`)"},"filter_referrer":{"type":["string","null"],"description":"First-touch referrer hostname (matches `visitor.first_referrer_hostname`)"},"filter_region":{"type":["string","null"],"description":"Geolocation region (matches `ip_geolocations.region`)"}}},"VisitorSessionsQuery":{"type":"object","required":["project_id"],"properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"}}},"VisitorSessionsResponse":{"type":"object","required":["visitor_id","sessions","total_sessions"],"properties":{"sessions":{"type":"array","items":{"$ref":"#/components/schemas/SessionSummary"}},"total_sessions":{"type":"integer","format":"int64"},"visitor_id":{"type":"string"}}},"VisitorStats":{"type":"object","required":["visitor_id","first_seen","last_seen","total_sessions","total_page_views","total_events","average_session_duration","bounce_rate","engagement_rate","top_pages","top_referrers","devices_used","locations"],"properties":{"average_session_duration":{"type":"number","format":"double"},"bounce_rate":{"type":"number","format":"double"},"devices_used":{"type":"array","items":{"type":"string"}},"engagement_rate":{"type":"number","format":"double"},"first_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"last_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"locations":{"type":"array","items":{"$ref":"#/components/schemas/LocationInfo"}},"top_pages":{"type":"array","items":{"$ref":"#/components/schemas/PageVisit"}},"top_referrers":{"type":"array","items":{"type":"string"}},"total_events":{"type":"integer","format":"int64"},"total_page_views":{"type":"integer","format":"int64"},"total_sessions":{"type":"integer","format":"int64"},"visitor_id":{"type":"integer","format":"int32"}}},"VisitorWithGeolocation":{"type":"object","required":["id","visitor_id","project_id","environment_id","first_seen","last_seen","is_crawler"],"properties":{"city":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"crawler_name":{"type":["string","null"]},"custom_data":{},"environment_id":{"type":"integer","format":"int32"},"first_channel":{"type":["string","null"],"description":"Marketing channel from the first visit (e.g. \"Organic Search\", \"Direct\")"},"first_referrer":{"type":["string","null"],"description":"Full referrer URL from the visitor's first session"},"first_referrer_hostname":{"type":["string","null"],"description":"Hostname extracted from first_referrer"},"first_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"id":{"type":"integer","format":"int32"},"ip_address":{"type":["string","null"]},"is_crawler":{"type":"boolean"},"is_eu":{"type":["boolean","null"]},"last_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"latitude":{"type":["number","null"],"format":"double"},"longitude":{"type":["number","null"],"format":"double"},"project_id":{"type":"integer","format":"int32"},"region":{"type":["string","null"]},"timezone":{"type":["string","null"]},"user_agent":{"type":["string","null"]},"visitor_id":{"type":"string"}}},"VisitorsListQuery":{"allOf":[{"$ref":"#/components/schemas/VisitorSegmentFilters"},{"type":"object","required":["start_date","end_date","project_id"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"has_activity_only":{"type":["boolean","null"],"description":"Filter to only include visitors with recorded activity (events/sessions).\nWhen true, excludes \"ghost\" visitors that have no events."},"include_crawlers":{"type":["boolean","null"]},"limit":{"type":["integer","null"],"format":"int32"},"offset":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}}]},"VisitorsResponse":{"type":"object","required":["visitors","total_count","filtered_count"],"properties":{"filtered_count":{"type":"integer","format":"int64"},"total_count":{"type":"integer","format":"int64"},"visitors":{"type":"array","items":{"$ref":"#/components/schemas/VisitorInfo"}}}},"VolumeMount":{"type":"object","description":"Volume mount in deployment","required":["source","destination","read_only","type"],"properties":{"destination":{"type":"string","description":"Destination path in container"},"read_only":{"type":"boolean","description":"Read-only flag"},"source":{"type":"string","description":"Source (volume name or path)"},"type":{"$ref":"#/components/schemas/VolumeType","description":"Volume type"}}},"VolumeType":{"type":"string","description":"Volume type","enum":["bind","volume","tmpfs"]},"VulnerabilityResponse":{"type":"object","required":["id","scan_id","vulnerability_id","package_name","installed_version","severity","title","created_at"],"properties":{"class":{"type":["string","null"],"example":"os-pkgs"},"created_at":{"type":"string","example":"2025-12-08T12:15:47.609192Z"},"cvss_score":{"type":["number","null"],"format":"float"},"description":{"type":["string","null"]},"fixed_version":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"installed_version":{"type":"string"},"last_modified_date":{"type":["string","null"],"example":"2025-12-08T12:15:47.609192Z"},"package_name":{"type":"string"},"primary_url":{"type":["string","null"]},"published_date":{"type":["string","null"],"example":"2025-12-08T12:15:47.609192Z"},"references":{},"scan_id":{"type":"integer","format":"int32"},"severity":{"type":"string"},"target":{"type":["string","null"],"example":"alpine:3.18 (alpine 3.18.0)"},"title":{"type":"string"},"type":{"type":["string","null"],"example":"alpine"},"vulnerability_id":{"type":"string"}}},"WalWarning":{"oneOf":[{"type":"object","description":"`pg_wal` is significantly larger than `max_wal_size`.","required":["pg_wal_bytes","max_wal_size_bytes","ratio","kind"],"properties":{"kind":{"type":"string","enum":["wal_bloat"]},"max_wal_size_bytes":{"type":"integer","format":"int64"},"pg_wal_bytes":{"type":"integer","format":"int64"},"ratio":{"type":"number","format":"double"}}},{"type":"object","description":"A replication slot is holding WAL it's not consuming.","required":["slot_name","retained_bytes","active","kind"],"properties":{"active":{"type":"boolean"},"kind":{"type":"string","enum":["stale_slot"]},"retained_bytes":{"type":"integer","format":"int64"},"slot_name":{"type":"string"}}},{"type":"object","description":"`archive_status/*.ready` count exceeds threshold — `archive_command`\nis either failing or running slower than WAL generation.","required":["ready_count","kind"],"properties":{"kind":{"type":"string","enum":["archive_backlog"]},"ready_count":{"type":"integer","format":"int64"}}},{"type":"object","description":"`archive_mode = on` but `archive_command` is empty / `/bin/true`.\nWAL accumulates forever waiting for a destination that never accepts.","required":["kind"],"properties":{"kind":{"type":"string","enum":["archive_mode_without_command"]}}},{"type":"object","description":"Oldest WAL segment is older than `WAL_NOT_RECYCLED_AGE_SECS`.\nIndependent signal: something is blocking recycling even if total\nsize hasn't exploded yet.","required":["oldest_age_secs","kind"],"properties":{"kind":{"type":"string","enum":["wal_not_recycled"]},"oldest_age_secs":{"type":"integer","format":"int64"}}}],"description":"One actionable warning surfaced to the UI.\n\nEach variant carries the data needed to render a remediation hint without\nthe frontend re-querying anything."},"WalWarningSeverity":{"type":"string","enum":["warning","critical"]},"WebhookConfig":{"type":"object","description":"Configuration for a generic webhook notification provider","required":["url"],"properties":{"headers":{"type":"object","description":"Custom headers to include in the request (e.g., for authentication tokens)","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"},"example":{"Authorization":"Bearer your-token","X-Custom-Header":"custom-value"}},"method":{"type":"string","description":"HTTP method to use (POST, PUT, PATCH). Defaults to POST.","example":"POST"},"timeout_secs":{"type":"integer","format":"int64","description":"Request timeout in seconds. Defaults to 30.","example":30,"minimum":0},"url":{"type":"string","description":"The URL to send webhook requests to","example":"https://api.example.com/notifications"}}},"WebhookDeliveryResponse":{"type":"object","required":["id","webhook_id","event_type","event_id","payload","success","attempt_number","created_at"],"properties":{"attempt_number":{"type":"integer","format":"int32"},"created_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"delivered_at":{"type":["string","null"],"format":"date-time"},"error_message":{"type":["string","null"]},"event_id":{"type":"string"},"event_type":{"type":"string"},"id":{"type":"integer","format":"int32"},"payload":{"type":"string","description":"JSON payload that was sent to the webhook endpoint","example":{"event_type":"deployment.succeeded","data":{"deployment_id":123}}},"status_code":{"type":["integer","null"],"format":"int32"},"success":{"type":"boolean"},"webhook_id":{"type":"integer","format":"int32"}}},"WebhookResponse":{"type":"object","required":["id","project_id","url","events","enabled","has_secret","created_at","updated_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"enabled":{"type":"boolean"},"events":{"type":"array","items":{"type":"string"}},"has_secret":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"project_id":{"type":"integer","format":"int32"},"updated_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"url":{"type":"string"}}},"WebhookTriggerRequest":{"allOf":[{"description":"Arbitrary JSON payload from the caller. Passed to the agent as user_context."}]},"WebhookTriggerResponse":{"type":"object","required":["run_id","status"],"properties":{"run_id":{"type":"integer","format":"int32"},"status":{"type":"string"}}},"WorkflowDryRunRequest":{"type":"object","required":["yaml"],"properties":{"cpu_limit":{"type":["number","null"],"format":"double","description":"Optional CPU override applied after parsing YAML (clamped server-side).\nWhen `Some`, this takes precedence over `cpu_limit` inside the YAML —\nlets the CLI pass `--cpu` without rewriting the YAML text."},"error_group_id":{"type":["integer","null"],"format":"int32","description":"Optional error group to link this dry-run to. When set, the executor's\n`load_error_context` path injects `{{error_type}}` / `{{error_message}}`\n/ `{{stack_trace}}` into the prompt — same behaviour as a committed\nworkflow triggered with `trigger_source_type = \"error_group\"`. Must\nbelong to `project_id` (handler enforces)."},"memory_limit_mb":{"type":["integer","null"],"format":"int64","description":"Optional memory override in MB (clamped server-side). Same precedence\nrule as `cpu_limit`.","minimum":0},"user_context":{"type":["string","null"],"description":"Optional context appended to the prompt (e.g. \"test against staging\nonly\"). Mirrors `TriggerAgentRequest.user_context`."},"yaml":{"type":"string","description":"Full WorkflowYamlConfig as YAML text. Server validates and re-serializes\nbefore storing on the run row."}}},"WorkloadDescriptor":{"type":"object","description":"Brief descriptor for discovered workloads (used in listing)","required":["id","workload_type","status","labels"],"properties":{"created_at":{"type":["string","null"],"format":"date-time","description":"Creation timestamp"},"id":{"$ref":"#/components/schemas/WorkloadId","description":"Unique ID in source system"},"image":{"type":["string","null"],"description":"Image/build reference (for containers)"},"labels":{"type":"object","description":"Labels/tags from source system","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"name":{"type":["string","null"],"description":"Workload name (if any)"},"status":{"$ref":"#/components/schemas/WorkloadStatus","description":"Current status"},"workload_type":{"$ref":"#/components/schemas/WorkloadType","description":"Workload type (container, function, static-site, etc.)"}}},"WorkloadId":{"type":"string","description":"Unique identifier for a workload in the source system"},"WorkloadStatus":{"type":"string","description":"Workload status in source system","enum":["running","paused","stopped","exited","failed","deployed","building","unknown"]},"WorkloadType":{"type":"string","description":"Workload type","enum":["container","function","static-site","server-side-app","worker","database","message-queue","cache","cron-job","other"]},"WriteFileBody":{"type":"object","required":["path","contents_b64"],"properties":{"contents_b64":{"type":"string","description":"File contents, base64-encoded. Required — lets callers ship binary\ndata over JSON without charset games."},"mode":{"type":["integer","null"],"format":"int32","description":"Unix permission mask (e.g. 0o644). Defaults to 0o644 when absent.","minimum":0},"path":{"type":"string","description":"Absolute path inside the sandbox. Must start with `/`."}},"additionalProperties":false},"WriteFilesBody":{"type":"object","required":["files"],"properties":{"files":{"type":"array","items":{"$ref":"#/components/schemas/WriteFileBody"},"description":"List of files to write. Each entry must include an absolute\n`path` and base64-encoded `contents_b64`. Empty list is a no-op."}},"additionalProperties":false},"WriteFilesResponse":{"type":"object","required":["written"],"properties":{"written":{"type":"integer","description":"Number of files successfully written before the first failure\n(if any). On full success this equals `files.len()`.","minimum":0}}},"ZoneListResponse":{"type":"object","description":"Zone list response","required":["zones"],"properties":{"zones":{"type":"array","items":{"$ref":"#/components/schemas/DnsZone"}}}}},"securitySchemes":{"bearer_auth":{"type":"http","scheme":"bearer","description":"Bearer token authentication. Use format: `Bearer `. Supports API keys (starting with `tk_`), CLI tokens, and session tokens."}}},"tags":[{"name":"Events","description":"Analytics events tracking endpoints"},{"name":"Metrics","description":"Analytics metrics collection endpoints including performance web vitals"},{"name":"Funnels","description":"Funnel management endpoints"},{"name":"Analytics","description":"Analytics and session replay management"},{"name":"Performance","description":"Performance metrics management"},{"name":"geo","description":"Geolocation API endpoints"},{"name":"Platform","description":"Platform information and compatibility"},{"name":"Teams","description":"Teams and project-scoped access"},{"name":"Git Providers","description":"Git provider management endpoints"},{"name":"Repositories","description":"Repository management endpoints"},{"name":"Public Repositories","description":"Endpoints for accessing public repositories without authentication. Supports GitHub and GitLab."},{"name":"Notification Providers","description":"Notification provider management endpoints"},{"name":"Notification Preferences","description":"User notification preferences and settings"},{"name":"DNS Providers","description":"DNS provider management endpoints"},{"name":"Internal DNS","description":"Per-node DNS resolver sync (ADR-011)"},{"name":"Domains","description":"Domain management endpoints"},{"name":"Email Providers","description":"Email provider management endpoints"},{"name":"Email Domains","description":"Email domain management and verification"},{"name":"Emails","description":"Email sending and retrieval"},{"name":"Email Tracking","description":"Email open and click tracking"},{"name":"Email Validation","description":"Email address validation and verification"},{"name":"Webhooks","description":"Webhook management endpoints"},{"name":"Webhook Deliveries","description":"Webhook delivery history and retry endpoints"},{"name":"External Services","description":"External service integration endpoints"},{"name":"External Services - Query","description":"Data querying and exploration endpoints"},{"name":"Metrics","description":"Time-series metrics and alert rule endpoints"},{"name":"KV Store","description":"Key-Value storage operations"},{"name":"KV Management","description":"KV service management operations"},{"name":"Blob","description":"Blob storage operations"},{"name":"Blob Management","description":"Blob service management operations"},{"name":"Feature Flags","description":"Runtime configuration that changes without a redeploy"},{"name":"Environments","description":"Environment management operations"},{"name":"Secrets","description":"File-mounted secrets (/run/secrets/)"},{"name":"Projects","description":"Project management endpoints"},{"name":"Presets","description":"Available deployment presets"},{"name":"Templates","description":"Project template endpoints"},{"name":"Custom Domains","description":"Custom domain management for projects"},{"name":"error-tracking","description":"Error tracking data fetching endpoints"},{"name":"Vulnerability Scans","description":"Vulnerability scan management endpoints"},{"name":"Agents","description":"Autonomous AI agents, autofixer (interactive AI debugging), skills/MCP definitions, and preview gateway management."},{"name":"Crons","description":"Cron jobs management API"},{"name":"Sandboxes","description":"Standalone sandbox API (`/v1/sandboxes/*`) for running isolated containers."},{"name":"Logs","description":"Log search, context, live tail, and retention management"},{"name":"Imports","description":"Import workloads from external sources"},{"name":"Status Page","description":"Status page and monitoring endpoints"},{"name":"OTel Ingest","description":"OTLP/HTTP ingest endpoints (protobuf)"},{"name":"OTel","description":"Query endpoints for the monitoring UI"},{"name":"GenAI","description":"GenAI agent activity tracing endpoints"},{"name":"Alarms","description":"Unified alarm history — list, summarise, acknowledge, resolve"},{"name":"Authentication","description":"Authentication and authorization endpoints"},{"name":"Users","description":"User management endpoints"},{"name":"Backups","description":"Backup management endpoints"},{"name":"Restore","description":"External service restore operations"},{"name":"Revenue","description":"Per-project revenue tracking integrations and analytics"},{"name":"Observability","description":"Unified observability event stream — runtime logs, requests, spans, errors, revenue"},{"name":"AI Gateway","description":"OpenAI-compatible chat, embeddings, and model endpoints"},{"name":"AI Gateway Admin","description":"Provider key management endpoints"},{"name":"AI Gateway Usage","description":"Usage analytics and reporting endpoints"},{"name":"AI Gateway Pricing","description":"Model pricing endpoints"},{"name":"API Keys","description":"API key management endpoints"},{"name":"Load Balancer","description":"Load balancer management endpoints"},{"name":"IP Access Control","description":"IP access control management endpoints"},{"name":"Files","description":"Static file serving endpoints"},{"name":"External Plugins","description":"External plugin management and discovery"}]} diff --git a/apps/temps-cli/src/api/index.ts b/apps/temps-cli/src/api/index.ts index d17e13d8a..3952c8d1d 100644 --- a/apps/temps-cli/src/api/index.ts +++ b/apps/temps-cli/src/api/index.ts @@ -1,4 +1,4 @@ // This file is auto-generated by @hey-api/openapi-ts -export { acknowledgeAlarm, activateAiProvider, activateApiKey, activateConnection, activateProvider, addClusterMember, addContext, addEnvironmentDomain, addEvents, addManagedDomain, addSessionReplayEvents, addTeamMember, adminDrainNode, adminDrainStatus, adminGetNode, adminListNodeContainers, adminListNodes, adminRemoveNode, adminUndrainNode, applyHostnameMode, archiveConversation, archiveFlag, assignRole, attachScheduleServices, blobCopy, blobDelete, blobDisable, blobDownload, blobEnable, blobHead, blobList, blobPut, blobStatus, blobUpdate, cancel, cancelBackup, cancelDeployment, cancelDomainOrder, cancelPgUpgrade, cancelRun, cancelScheduleRun, changePasswordSelf, changeProjectSource, changeRequiredPassword, chatCompletions, checkAnalyticsHasEvents, checkCommitExists, checkDomainStatus, checkExplorerSupport, checkIpBlocked, checkProviderDeletionSafety, chunkUploadOptions, cleanupExpiredBackups, clearPreviewPassword, cliDeviceApprove, cliDeviceDeny, cliDeviceLookup, cliDevicePoll, cliDeviceStart, cliLogout, cmd, cmdKill, cmdLogs, confirmPendingAction, containerMetricsGetHistory, createAgent, createAlert, createAlertRule, createApiKey, createBackupSchedule, createBitbucketProvider, createCloudflareProvider, createConversation, createCustomDomain, createDashboard, createDeploymentToken, createDnsProvider, createDomain, createDsn, createEmailDomain, createEmailProvider, createEnvironment, createEnvironmentVariable, createFlag, createFunnel, createGenericProvider, createGiteaPatProvider, createGithubPatProvider, createGitlabOauthProvider, createGitlabPatProvider, createGitProvider, createGlobalMcp, createGlobalSkill, createIncident, createIpAccessControl, createMcp, createMonitor, createNotificationEmailProvider, createNotificationProvider, createOidcProvider, createOidcRoleMapping, createOrRecreateOrder, createPlan, createPr, createProject, createProjectFromTemplate, createProjectRelease, createProjectSecret, createProviderKey, createRelease, createRoute, createS3Source, createSandbox, createService, createSkill, createSlackProvider, createTeam, createUser, createWebhook, createWebhookProvider, deactivateApiKey, deactivateConnection, deactivateProvider, deleteAgent, deleteAlert, deleteAlertRule, deleteApiKey, deleteBackup, deleteBackupSchedule, deleteConnection, deleteCustomDomain, deleteDashboard, deleteDeploymentToken, deleteDnsProvider, deleteDomain, deleteEmailDomain, deleteEmailProvider, deleteEnvironment, deleteEnvironmentDomain, deleteEnvironmentVariable, deleteExternalImage, deleteFunnel, deleteGitProvider, deleteGlobalMcp, deleteGlobalSkill, deleteIpAccessControl, deleteMcp, deleteMonitor, deleteNotificationProvider, deleteOidcProvider, deleteOidcRoleMapping, deletePreferences, deleteProject, deleteProjectSecret, deleteProviderKey, deleteProviderSafely, deleteReleaseSourceFiles, deleteReleaseSourceMaps, deleteRoute, deleteS3Source, deleteScan, deleteSecret, deleteService, deleteSessionReplay, deleteSkill, deleteSourceMap, deleteStaticBundle, deleteTeam, deleteUser, deleteWebhook, deployFromImage, deployFromImageUpload, deployFromStatic, deployFromUploadedSource, deploymentMetricsGetLatest, deploymentMetricsGetRange, deploymentMetricsToggle, destroySandbox, detachScheduleService, detectPublicPresets, disableBackupSchedule, disableMfa, discoverWorkloads, domain, downloadGlobalSkillArchive, downloadObject, downloadSkillArchive, emailStatus, embeddings, enableBackupSchedule, enrichVisitor, exec, execDetached, executeDeploymentOperation, executeImport, extendTimeout, externalServiceEnablePgStatStatements, externalServiceMetricsByDatabase, externalServiceMetricsCreateAlertRule, externalServiceMetricsDeleteAlertRule, externalServiceMetricsGetAlertRules, externalServiceMetricsGetLatest, externalServiceMetricsGetRange, externalServiceMetricsStatus, externalServiceMetricsToggle, externalServiceMetricsUpdateAlertRule, externalServiceResetPgStatStatements, finalizeOrder, finalizeProjectRelease, findConversation, generateJoinToken, generatePresetDockerfile, getAccessInfo, getActiveVisitors, getActivityGraph, getAdminGate, getAgent, getAggregatedBuckets, getAiAgentBreakdown, getAiAgentPages, getAiAgentTimeline, getAiPageBreakdown, getAiStatusBreakdown, getAlert, getAlertRule, getAllRepositoriesByName, getAnalyticsActiveVisitors, getAnalyticsEventsCount, getAnalyticsSessionEvents, getAnalyticsVisitorSessions, getApiKey, getApiKeyPermissions, getAuditLog, getBackup, getBackupSchedule, getBranchesByRepositoryId, getBucketedIncidents, getBucketedStatus, getChallengeToken, getChatReadiness, getCliStatus, getClusterHealth, getClusterMember, getCmd, getContainerDetail, getContainerEnvironmentVariable, getContainerInfo, getContainerLogs, getContainerLogsById, getContainerMetrics, getConversation, getConversationDetail, getConversations, getCronById, getCronExecutions, getCrossProjectTraceSiblings, getCurrentMonitorStatus, getCurrentUser, getCustomDomain, getDashboard, getDashboardProjectsAnalytics, getDelivery, getDeployment, getDeploymentContainerLogContent, getDeploymentJobLogs, getDeploymentJobs, getDeploymentOperations, getDeploymentOperationStatus, getDeploymentToken, getDiskStatus, getDnsChanges, getDnsProvider, getDomain, getDomainByHost, getDomainById, getDomainByName, getDomainDnsRecords, getDomainOrder, getEmail, getEmailEvents, getEmailLinks, getEmailProvider, getEmailStats, getEmailTracking, getEmailTrackingStatus, getEntityInfo, getEnvironment, getEnvironmentCrons, getEnvironmentDomains, getEnvironments, getEnvironmentVariables, getEnvironmentVariableValue, getErrorDashboardStats, getErrorEvent, getErrorGroup, getErrorStats, getErrorTimeSeries, getEventDetail, getEventEntries, getEventsCount, getEventsTimeline, getEventTypeBreakdown, getEventVisitors, getExternalImage, getFile, getFlag, getFlagSnapshot, getFunnelMetrics, getGenaiTrace, getGeneralStats, getGitProvider, getGlobalEvents, getGlobalEventStats, getGlobalMcp, getGlobalSandboxStatus, getGlobalSkill, getGroupedPageMetrics, getHealth, getHourlyVisits, getHttpChallengeDebug, getImportStatus, getIncident, getIncidentUpdates, getIpAccessControl, getIpGeolocation, getJoinTokenStatus, getLastDeployment, getLatestScan, getLatestScansPerEnvironment, getLiveVisitorsList, getLogContext, getMcp, getMetricsOverTime, getMonitor, getNotificationProvider, getOnDemandCertStatus, getOrCreateDsn, getPageFlow, getPageHourlySessions, getPagePathDetail, getPagePaths, getPagePathsSparklines, getPagePathVisitors, getPendingAction, getPerformanceMetrics, getPgUpgrade, getPgUpgradeLogs, getPipelineStats, getPlatformInfo, getPostgresWalHealth, getPreferences, getPreviewGatewayLogs, getPreviewGatewaySettings, getPreviewGatewayStatus, getPricing, getPrivateIp, getProject, getProjectAlarmsSummary, getProjectBySlug, getProjectDeployments, getProjects, getProjectServiceEnvironmentVariables, getProjectSessionReplays, getProjectsHealth, getProjectsMonitorHealth, getProjectStatistics, getProjectTemplate, getPropertyBreakdown, getPropertyTimeline, getProviderConnections, getProviderMetadata, getProvidersMetadata, getProxyLogById, getProxyLogByRequestId, getProxyLogs, getPublicBranches, getPublicIp, getPublicRepository, getQuota, getRecentActivity, getRemoteExternalImage, getRepositoryBranches, getRepositoryById, getRepositoryByName, getRepositoryPresetByName, getRepositoryPresetLive, getRepositoryTags, getResolvedEnvironmentVariables, getResolvedEnvironmentVariableValue, getRestoreCapabilities, getRestoreRun, getRoute, getRun, getRunWithLogs, getS3Credentials, getS3Source, getSandbox, getSandboxStatus, getScan, getScanByDeployment, getScanVulnerabilities, getService, getServiceBySlug, getServiceEnvironmentVariable, getServiceEnvironmentVariables, getServiceHealthStatus, getServicePreviewEnvironmentVariableNames, getServicePreviewEnvironmentVariablesMasked, getServiceRuntime, getServiceStats, getServiceTypeParameters, getServiceTypes, getSessionDetails, getSessionEvents, getSessionLogs, getSessionReplay, getSessionReplayEvents, getSettings, getSkill, getSlowQueries, getStaticBundle, getStatusOverview, getTagsByRepositoryId, getTeam, getTimeBucketStats, getTodayStats, getTrace, getUnifiedTrace, getUniqueCounts, getUniqueEvents, getUpdateCapability, getUpdateStatus, getUptimeHistory, getUsageByProvider, getUsageRecent, getUsageSummary, getUsageTimeseries, getUsageTopModels, getVisitorByGuid, getVisitorById, getVisitorDetails, getVisitorFacets, getVisitorInfo, getVisitorJourney, getVisitors, getVisitorSessions, getVisitorStats, getWebhook, grantProjectAccess, handleGitProviderOauthCallback, hasAnalyticsEvents, hasErrorGroups, hasPerformanceMetrics, importExternalService, ingestLogs, ingestLogsByPath, ingestMetrics, ingestMetricsByPath, ingestSentryEnvelope, ingestSentryEvent, ingestTraces, ingestTracesByPath, initSessionReplay, inspectDropArchive, jobLogs, jobStatus, killJob, kvDel, kvDisable, kvEnable, kvExpire, kvGet, kvIncr, kvKeys, kvSet, kvStatus, kvTtl, kvUpdate, latestRunForSource, linkCustomDomainToCertificate, linkServiceToProject, listAgentRuns, listAgents, listAiProviders, listAlertRules, listAlerts, listAllConversations, listAllRuns, listApiKeys, listAuditLogs, listAvailableContainers, listBackupAlerts, listBackupChildren, listBackupSchedules, listBackupsForSchedule, listCommitsByRepositoryId, listConnections, listContainers, listContainersAtPath, listConversations, listCustomDomainsForProject, listDashboards, listDeliveries, listDeploymentContainerLogs, listDeploymentTokens, listDnsProviders, listDomains, listDsns, listEmailDomains, listEmailProviders, listEmails, listEnrollmentTokens, listEntities, listErrorEvents, listErrorGroups, listEvents, listEventTypes, listExternalImages, listExternalPlugins, listExternalServiceBackups, listFlags, listFunnels, listGitProviders, listGlobalMcps, listGlobalSkills, listIncidents, listInsights, listIpAccessControl, listJobs, listKnownAiAgents, listManagedDomains, listMcps, listMetricLabelKeys, listMetricLabelValues, listMetricNames, listModels, listMonitors, listNotificationProviders, listOidcProviders, listOidcProviderUsers, listOidcRoleMappings, listOnDemandCerts, listOrders, listPeers, listPendingActions, listPgUpgrades, listPresets, listProjectAccess, listProjectAlarms, listProjectScans, listProjectSecrets, listProjectServices, listProjectTemplates, listProjectTemplateTags, listProviderKeys, listProviderZones, listPublicProviders, listReleaseFiles, listReleases, listRemoteExternalImages, listRepositoriesByConnection, listRepositoriesByProvider, listRestoreRunsForService, listRootContainers, listRoutes, listS3Sources, listSandboxes, listScheduleRunJobs, listScheduleRuns, listScheduleServices, listSecrets, listServiceHealthStatuses, listServiceProjects, listServices, listServiceSchedules, listSkills, listSourceBackups, listSourceFiles, listSourceMaps, listSources, listStaticBundles, listSyncedRepositories, listTeamMembers, listTeamProjects, listTeams, listUsers, listWebhooks, login, logout, lookupDnsARecords, mintEnrollmentToken, mkdir, nodeHeartbeat, nodeMetricsGetRange, observabilityFullEvent, observabilityListEvents, oidcCallback, type Options, patchAdminGate, patchPreviewGatewaySettings, pauseDeployment, pauseSandbox, planRestore, postDnsAck, previewAlert, previewFunnelMetrics, previewHostnameMode, promoteClusterMember, promoteDeployment, provisionDomain, purgeProjectLogs, pushExternalImage, queryData, queryGenaiTraces, queryLogs, queryMetrics, queryTraces, queryTraceSummaries, readFile, reAnalyze, rebuildSandboxImage, recordConsoleEvent, recordEventMetrics, recordFlagExposure, recordSpeedMetrics, refreshRouteTable, regenerateDsn, registerExternalImage, registerNode, reinstallGitlabWebhook, rejectPendingAction, reloadPlugins, removeClusterMember, removeManagedDomain, removeRole, removeTeamMember, renameConversation, renewDomain, requestPasswordReset, resetPassword, resizeSandbox, resolveAlarm, restartContainer, restartPreviewGateway, restartSandbox, restoreFlag, restoreUser, resumeDeployment, resumeSandbox, retryCluster, retryDelivery, retryPgUpgrade, retryRun, revealGlobalMcpConfig, revealMcpConfig, revealNotificationProviderConfig, revealServiceParameter, revenueCreateIntegration, revenueDeleteIntegration, revenueGlobalEvents, revenueImportInvoicesCsv, revenueImportSubscriptionsCsv, revenueListIntegrations, revenueListProviders, revenueMetricsCustomers, revenueMetricsGlobalMrr, revenueMetricsGlobalSummary, revenueMetricsMrr, revenueMetricsSummary, revenueRecentEvents, revenueRotateToken, revenueUpdateConfig, revenueUpdateSecret, revokeDsn, revokeEnrollmentToken, revokeJoinToken, revokeProjectAccess, rollbackPgUpgrade, rollbackToDeployment, rootfsGc, rootfsReport, rotateApiKey, rotateDeploymentToken, runBackupForSource, runConnectionHealthCheck, runExternalServiceBackup, runScheduleNow, sandboxCreatePreviewLink, saveAgentToken, saveAiProviderCredential, searchLogs, sendEmail, sendMessage, setDefaultS3Source, setFlagEnvironment, setPreviewPassword, setupDns, setupDnsChallenge, setupEmailTracking, setupMfa, sleepEnvironment, smokeTestAgent, sourceSandbox, startAnalysis, startContainer, startFix, startGitProviderOauth, startOidcLoginBySlug, startPgUpgrade, startRestore, startService, startUpdate, statPath, stopContainer, stopSandbox, stopService, streamContainerMetrics, streamEvents, streamRunEvents, syncRepositories, tailDeploymentJobLogs, tailLogs, teardownDeployment, teardownEnvironment, testNotificationProvider, testOidcProvider, testProvider, testProviderConnection, testProviderKeyById, testProviderKeyInline, testS3ConnectionPreview, testS3SourceConnection, trackClick, trackOpen, triggerAgent, triggerProjectPipeline, triggerScan, triggerServiceHealthCheck, triggerWeeklyDigest, unlinkServiceFromProject, updateAgent, updateAiProvider, updateAlert, updateAlertRule, updateApiKey, updateAutomaticDeploy, updateBackupSchedule, updateCloudflareProvider, updateConnectionToken, updateCustomDomain, updateDashboard, updateDeploymentToken, updateEmailProvider, updateEnvironmentSettings, updateEnvironmentSubdomain, updateEnvironmentVariable, updateErrorGroup, updateFlag, updateFunnel, updateGitProviderCredentials, updateGitSettings, updateGlobalMcp, updateGlobalSkill, updateIncidentStatus, updateIpAccessControl, updateManagedDomain, updateMcp, updateNotificationEmailProvider, updateNotificationProvider, updateOidcProvider, updatePreferences, updateProject, updateProjectDeploymentConfig, updateProjectSecret, updateProjectSettings, updateProvider, updateProviderKey, updateRoute, updateS3Source, updateSelf, updateService, updateServiceResources, updateSessionDuration, updateSettings, updateSkill, updateSlackProvider, updateSpeedMetrics, updateTeam, updateTeamMemberRole, updateUser, updateWebhook, updateWebhookProvider, upgradePreviewGateway, upgradeService, uploadGlobalSkill, uploadReleaseFile, uploadSkill, uploadSourceFile, uploadSourceMap, uploadStaticBundle, upsertSecret, validateConnection, validateEmail, verifyAndEnableMfa, verifyDomain, verifyEmail, verifyManagedDomain, verifyMfaChallenge, verifyStepUp, wakeEnvironment, webhookTrigger, workflowDryRun, writeFile, writeFiles } from './sdk.gen'; -export type { AcknowledgeAlarmData, AcknowledgeAlarmErrors, AcknowledgeAlarmResponses, AcmeOrderResponse, ActivateAiProviderData, ActivateAiProviderErrors, ActivateAiProviderResponse, ActivateAiProviderResponses, ActivateApiKeyData, ActivateApiKeyErrors, ActivateApiKeyResponse, ActivateApiKeyResponses, ActivateConnectionData, ActivateConnectionErrors, ActivateConnectionResponses, ActivateProviderData, ActivateProviderErrors, ActivateProviderResponse, ActivateProviderResponses, ActiveVisitor, ActiveVisitorsQuery, ActiveVisitorsResponse, ActivityDay, ActivityEvent, ActivityGraphQuery, ActivityGraphResponse, AddClusterMemberData, AddClusterMemberErrors, AddClusterMemberRequest, AddClusterMemberResponse, AddClusterMemberResponses, AddContextData, AddContextErrors, AddContextRequest, AddContextResponses, AddEnvironmentDomainData, AddEnvironmentDomainErrors, AddEnvironmentDomainRequest, AddEnvironmentDomainResponse, AddEnvironmentDomainResponses, AddEventsData, AddEventsError, AddEventsErrors, AddEventsRequest, AddEventsResponse, AddEventsResponse2, AddEventsResponses, AddManagedDomainApiRequest, AddManagedDomainData, AddManagedDomainErrors, AddManagedDomainResponse, AddManagedDomainResponses, AddSessionReplayEventsData, AddSessionReplayEventsError, AddSessionReplayEventsErrors, AddSessionReplayEventsResponse, AddSessionReplayEventsResponses, AddTeamMemberData, AddTeamMemberErrors, AddTeamMemberResponse, AddTeamMemberResponses, AdminDrainNodeData, AdminDrainNodeErrors, AdminDrainNodeResponse, AdminDrainNodeResponses, AdminDrainStatusData, AdminDrainStatusErrors, AdminDrainStatusResponse, AdminDrainStatusResponses, AdminGateResponse, AdminGateSource, AdminGetNodeData, AdminGetNodeErrors, AdminGetNodeResponse, AdminGetNodeResponses, AdminListNodeContainersData, AdminListNodeContainersErrors, AdminListNodeContainersResponse, AdminListNodeContainersResponses, AdminListNodesData, AdminListNodesErrors, AdminListNodesResponse, AdminListNodesResponses, AdminRemoveNodeData, AdminRemoveNodeErrors, AdminRemoveNodeResponse, AdminRemoveNodeResponses, AdminUndrainNodeData, AdminUndrainNodeErrors, AdminUndrainNodeResponse, AdminUndrainNodeResponses, AgentConfigResponse, AgentRunLogResponse, AgentRunResponse, AgentRunWithLogsResponse, AgentSandboxSettings, AgentSandboxSettingsMasked, AggregatedBucketItem, AggregatedBucketsQuery, AggregatedBucketsResponse, AggregationLevel, AggregationTemporality, AiAgentBreakdownResponse, AiAgentBreakdownRow, AiAgentDescriptor, AiAgentPageRow, AiAgentPagesResponse, AiAgentTimelineResponse, AiAgentTimelineRow, AiChatLimitsSettings, AiConfigSettings, AiPageBreakdownResponse, AiPageBreakdownRow, AiStatusBreakdownResponse, AiStatusBreakdownRow, AlarmListResponse, AlarmResponse, AlarmSummaryResponse, AlertRuleResponse, AllocEntry, AnalyticsSessionEventsResponse, AnnotatedSpan, AnomalyAlgorithm, AnomalyParams, AnomalyPreviewPointResponse, AnomalyPreviewRequest, AnomalyPreviewResponse, ApiKeyListResponse, ApiKeyResponse, ApplyHostnameModeData, ApplyHostnameModeErrors, ApplyHostnameModeRequest, ApplyHostnameModeResponse, ApplyHostnameModeResponses, AppSettings, AppSettingsResponse, ArchiveConversationData, ArchiveConversationErrors, ArchiveConversationResponse, ArchiveConversationResponses, ArchiveFlagData, ArchiveFlagErrors, ArchiveFlagResponse, ArchiveFlagResponse2, ArchiveFlagResponses, ArchiveMode, AssignRoleData, AssignRoleErrors, AssignRoleRequest, AssignRoleResponses, AttachScheduleServicesData, AttachScheduleServicesError, AttachScheduleServicesErrors, AttachScheduleServicesRequest, AttachScheduleServicesResponse, AttachScheduleServicesResponse2, AttachScheduleServicesResponses, AuditLogIpInfo, AuditLogResponse, AuditLogUserInfo, AuthFlavorDto, AuthResponse, AuthStatusResponse, AuthTokenResponse, AutofixerRunResponse, AutofixerRunWithLogsResponse, AutofixRunConfig, AutoWatchParams, AvailableContainerInfo, AvailablePermissions, BackupAlertListResponse, BackupAlertResponse, BackupResponse, BackupScheduleResponse, BitbucketAuthInput, BlobCopyData, BlobCopyError, BlobCopyErrors, BlobCopyResponse, BlobCopyResponses, BlobDeleteData, BlobDeleteError, BlobDeleteErrors, BlobDeleteResponse, BlobDeleteResponses, BlobDisableData, BlobDisableErrors, BlobDisableResponse, BlobDisableResponses, BlobDownloadData, BlobDownloadError, BlobDownloadErrors, BlobDownloadResponses, BlobEnableData, BlobEnableErrors, BlobEnableResponse, BlobEnableResponses, BlobHeadData, BlobHeadError, BlobHeadErrors, BlobHeadResponses, BlobListData, BlobListError, BlobListErrors, BlobListResponse, BlobListResponses, BlobPutData, BlobPutError, BlobPutErrors, BlobPutResponse, BlobPutResponses, BlobResponse, BlobStatusData, BlobStatusErrors, BlobStatusResponse, BlobStatusResponse2, BlobStatusResponses, BlobUpdateData, BlobUpdateErrors, BlobUpdateResponse, BlobUpdateResponses, BranchInfo, BranchListResponse, BrowserCount, BrowsersQuery, BuildConfiguration, BuildLimitsSettings, CancelBackupData, CancelBackupError, CancelBackupErrors, CancelBackupResponse, CancelBackupResponse2, CancelBackupResponses, CancelData, CancelDeploymentData, CancelDeploymentErrors, CancelDeploymentResponse, CancelDeploymentResponses, CancelDomainOrderData, CancelDomainOrderErrors, CancelDomainOrderResponse, CancelDomainOrderResponses, CancelErrors, CancelPgUpgradeData, CancelPgUpgradeErrors, CancelPgUpgradeResponse, CancelPgUpgradeResponses, CancelResponses, CancelRunData, CancelRunErrors, CancelRunResponse, CancelRunResponses, CancelScheduleRunData, CancelScheduleRunError, CancelScheduleRunErrors, CancelScheduleRunResponse, CancelScheduleRunResponses, CertStatusResponse, ChallengeConfig, ChallengeError, ChallengeValidationStatus, ChangePasswordRequest, ChangePasswordSelfData, ChangePasswordSelfErrors, ChangePasswordSelfResponse, ChangePasswordSelfResponses, ChangeProjectSourceData, ChangeProjectSourceErrors, ChangeProjectSourceRequest, ChangeProjectSourceResponse, ChangeProjectSourceResponses, ChangeRequiredPasswordData, ChangeRequiredPasswordErrors, ChangeRequiredPasswordResponse, ChangeRequiredPasswordResponses, ChatCompletionChoice, ChatCompletionRequest, ChatCompletionResponse, ChatCompletionsData, ChatCompletionsError, ChatCompletionsErrors, ChatCompletionsResponse, ChatCompletionsResponses, ChatMessage, ChatReadinessResponse, CheckAnalyticsHasEventsData, CheckAnalyticsHasEventsErrors, CheckAnalyticsHasEventsResponse, CheckAnalyticsHasEventsResponses, CheckCommitExistsData, CheckCommitExistsErrors, CheckCommitExistsResponse, CheckCommitExistsResponses, CheckDomainStatusData, CheckDomainStatusErrors, CheckDomainStatusResponse, CheckDomainStatusResponses, CheckExplorerSupportData, CheckExplorerSupportErrors, CheckExplorerSupportResponse, CheckExplorerSupportResponses, CheckIpBlockedData, CheckIpBlockedError, CheckIpBlockedErrors, CheckIpBlockedResponses, CheckProviderDeletionSafetyData, CheckProviderDeletionSafetyErrors, CheckProviderDeletionSafetyResponse, CheckProviderDeletionSafetyResponses, ChildBackupEntryResponse, ChildBackupListResponse, ChunkUploadOptionsData, ChunkUploadOptionsResponse, ChunkUploadOptionsResponses, CleanupExpiredBackupsData, CleanupExpiredBackupsError, CleanupExpiredBackupsErrors, CleanupExpiredBackupsRequest, CleanupExpiredBackupsResponse, CleanupExpiredBackupsResponses, ClearPreviewPasswordData, ClearPreviewPasswordErrors, ClearPreviewPasswordResponse, ClearPreviewPasswordResponses, CliDeviceApproveData, CliDeviceApproveErrors, CliDeviceApproveRequest, CliDeviceApproveResponse, CliDeviceApproveResponse2, CliDeviceApproveResponses, CliDeviceDenyData, CliDeviceDenyErrors, CliDeviceDenyResponse, CliDeviceDenyResponses, CliDeviceLookupData, CliDeviceLookupErrors, CliDeviceLookupResponse, CliDeviceLookupResponse2, CliDeviceLookupResponses, CliDevicePollData, CliDevicePollErrors, CliDevicePollRequest, CliDevicePollResponse, CliDevicePollResponse2, CliDevicePollResponses, CliDeviceStartData, CliDeviceStartErrors, CliDeviceStartRequest, CliDeviceStartResponse, CliDeviceStartResponse2, CliDeviceStartResponses, ClientOptions, CliLoginRequest, CliLogoutData, CliLogoutErrors, CliLogoutResponse, CliLogoutResponses, CloudflareConfig, CloudProvider, ClusterCapacity, ClusterDnsSettings, ClusterHealthReportResponse, ClusterMemberHealthResponse, ClusterMemberRequest, CmdBody, CmdData, CmdErrors, CmdInner, CmdKillBody, CmdKillData, CmdKillErrors, CmdKillResponse, CmdKillResponses, CmdLogsData, CmdLogsErrors, CmdLogsResponses, CmdResponse, CmdResponse2, CmdResponses, CommitExistsResponse, CommitInfo, CommitListResponse, Comparator, ComposePublicPort, ConfirmPendingActionData, ConfirmPendingActionErrors, ConfirmPendingActionResponse, ConfirmPendingActionResponses, ConnectionListQuery, ConnectionListResponse, ConnectionResponse, ConnectionTestResult, ConsoleEventPayload, ContainerActionResponse, ContainerDetailResponse, ContainerEnvironmentVariableValueResponse, ContainerInfoResponse, ContainerInventoryItem, ContainerListResponse, ContainerLogSettings, ContainerLogsQuery, ContainerMetricHistoryPoint, ContainerMetricsGetHistoryData, ContainerMetricsGetHistoryErrors, ContainerMetricsGetHistoryResponse, ContainerMetricsGetHistoryResponses, ContainerMetricsHistoryQuery, ContainerMetricsResponse, ContainerResponse, ContainerRuntimeInfo, ContainerStatsSample, ContentPart, ContextLine, ContextLogsRequest, ContextLogsResponse, ConversationDetailResponse, ConversationResponse, ConversationsQueryParams, ConversationSummary, CopyBlobRequest, CostAnalysis, CreateAgentData, CreateAgentErrors, CreateAgentResponse, CreateAgentResponses, CreateAlertData, CreateAlertError, CreateAlertErrors, CreateAlertResponse, CreateAlertResponses, CreateAlertRuleData, CreateAlertRuleErrors, CreateAlertRuleRequest, CreateAlertRuleResponse, CreateAlertRuleResponses, CreateApiKeyData, CreateApiKeyErrors, CreateApiKeyRequest, CreateApiKeyResponse, CreateApiKeyResponse2, CreateApiKeyResponses, CreateBackupScheduleData, CreateBackupScheduleError, CreateBackupScheduleErrors, CreateBackupScheduleRequest, CreateBackupScheduleResponse, CreateBackupScheduleResponses, CreateBitbucketProviderData, CreateBitbucketProviderErrors, CreateBitbucketProviderResponse, CreateBitbucketProviderResponses, CreateBitbucketRequest, CreateCloudflareProviderData, CreateCloudflareProviderErrors, CreateCloudflareProviderRequest, CreateCloudflareProviderResponse, CreateCloudflareProviderResponses, CreateConversationData, CreateConversationErrors, CreateConversationRequest, CreateConversationResponse, CreateConversationResponses, CreateCustomDomainData, CreateCustomDomainErrors, CreateCustomDomainResponse, CreateCustomDomainResponses, CreateDashboardData, CreateDashboardError, CreateDashboardErrors, CreateDashboardRequest, CreateDashboardResponse, CreateDashboardResponses, CreateDeploymentTokenData, CreateDeploymentTokenErrors, CreateDeploymentTokenRequest, CreateDeploymentTokenResponse, CreateDeploymentTokenResponse2, CreateDeploymentTokenResponses, CreateDnsProviderData, CreateDnsProviderErrors, CreateDnsProviderRequest, CreateDnsProviderResponse, CreateDnsProviderResponses, CreateDomainData, CreateDomainErrors, CreateDomainRequest, CreateDomainResponse, CreateDomainResponses, CreatedResource, CreateDsnData, CreateDsnErrors, CreateDsnRequest, CreateDsnResponse, CreateDsnResponses, CreateEmailDomainData, CreateEmailDomainErrors, CreateEmailDomainRequest, CreateEmailDomainResponse, CreateEmailDomainResponses, CreateEmailProviderData, CreateEmailProviderErrors, CreateEmailProviderRequest, CreateEmailProviderResponse, CreateEmailProviderResponses, CreateEnvironmentData, CreateEnvironmentErrors, CreateEnvironmentRequest, CreateEnvironmentResponse, CreateEnvironmentResponses, CreateEnvironmentVariableData, CreateEnvironmentVariableErrors, CreateEnvironmentVariableRequest, CreateEnvironmentVariableResponse, CreateEnvironmentVariableResponses, CreateExternalServiceRequest, CreateFlagData, CreateFlagErrors, CreateFlagRequest, CreateFlagResponse, CreateFlagResponses, CreateFunnelData, CreateFunnelErrors, CreateFunnelRequest, CreateFunnelResponse, CreateFunnelResponse2, CreateFunnelResponses, CreateFunnelStep, CreateGenericProviderData, CreateGenericProviderErrors, CreateGenericProviderResponse, CreateGenericProviderResponses, CreateGenericRequest, CreateGiteaPatProviderData, CreateGiteaPatProviderErrors, CreateGiteaPatProviderResponse, CreateGiteaPatProviderResponses, CreateGiteaPatRequest, CreateGithubPatProviderData, CreateGithubPatProviderErrors, CreateGithubPatProviderResponse, CreateGithubPatProviderResponses, CreateGitHubPatRequest, CreateGitlabOauthProviderData, CreateGitlabOauthProviderErrors, CreateGitlabOauthProviderResponse, CreateGitlabOauthProviderResponses, CreateGitLabOAuthRequest, CreateGitlabPatProviderData, CreateGitlabPatProviderErrors, CreateGitlabPatProviderResponse, CreateGitlabPatProviderResponses, CreateGitLabPatRequest, CreateGitProviderData, CreateGitProviderErrors, CreateGitProviderResponse, CreateGitProviderResponses, CreateGlobalMcpData, CreateGlobalMcpErrors, CreateGlobalMcpResponse, CreateGlobalMcpResponses, CreateGlobalSkillData, CreateGlobalSkillErrors, CreateGlobalSkillResponse, CreateGlobalSkillResponses, CreateIncidentData, CreateIncidentErrors, CreateIncidentRequest, CreateIncidentResponse, CreateIncidentResponses, CreateIntegrationBody, CreateIpAccessControlData, CreateIpAccessControlError, CreateIpAccessControlErrors, CreateIpAccessControlRequest, CreateIpAccessControlResponse, CreateIpAccessControlResponses, CreateMcpData, CreateMcpErrors, CreateMcpRequest, CreateMcpResponse, CreateMcpResponses, CreateMetricAlertRequest, CreateMonitorData, CreateMonitorErrors, CreateMonitorRequest, CreateMonitorResponse, CreateMonitorResponses, CreateNotificationEmailProviderData, CreateNotificationEmailProviderErrors, CreateNotificationEmailProviderRequest, CreateNotificationEmailProviderResponse, CreateNotificationEmailProviderResponses, CreateNotificationProviderData, CreateNotificationProviderErrors, CreateNotificationProviderResponse, CreateNotificationProviderResponses, CreateOidcProviderData, CreateOidcProviderErrors, CreateOidcProviderRequest, CreateOidcProviderResponse, CreateOidcProviderResponses, CreateOidcRoleMappingData, CreateOidcRoleMappingRequest, CreateOidcRoleMappingResponse, CreateOidcRoleMappingResponses, CreateOrRecreateOrderData, CreateOrRecreateOrderErrors, CreateOrRecreateOrderResponse, CreateOrRecreateOrderResponses, CreatePlanData, CreatePlanErrors, CreatePlanRequest, CreatePlanResponse, CreatePlanResponse2, CreatePlanResponses, CreatePrData, CreatePrErrors, CreateProjectAccessRequest, CreateProjectData, CreateProjectErrors, CreateProjectFromTemplateData, CreateProjectFromTemplateErrors, CreateProjectFromTemplateRequest, CreateProjectFromTemplateResponse, CreateProjectFromTemplateResponse2, CreateProjectFromTemplateResponses, CreateProjectReleaseData, CreateProjectReleaseErrors, CreateProjectReleaseResponse, CreateProjectReleaseResponses, CreateProjectRequest, CreateProjectResponse, CreateProjectResponses, CreateProjectSecretData, CreateProjectSecretErrors, CreateProjectSecretRequest, CreateProjectSecretResponse, CreateProjectSecretResponses, CreateProviderKeyData, CreateProviderKeyError, CreateProviderKeyErrors, CreateProviderKeyRequest, CreateProviderKeyResponse, CreateProviderKeyResponses, CreateProviderRequest, CreatePrResponse, CreatePrResponse2, CreatePrResponses, CreateReleaseData, CreateReleaseErrors, CreateReleaseResponse, CreateReleaseResponses, CreateRouteData, CreateRouteErrors, CreateRouteRequest, CreateRouteResponse, CreateRouteResponses, CreateS3SourceData, CreateS3SourceError, CreateS3SourceErrors, CreateS3SourceRequest, CreateS3SourceResponse, CreateS3SourceResponses, CreateSandboxBody, CreateSandboxData, CreateSandboxErrors, CreateSandboxResponse, CreateSandboxResponses, CreateServiceData, CreateServiceErrors, CreateServiceResponse, CreateServiceResponses, CreateSkillData, CreateSkillErrors, CreateSkillRequest, CreateSkillResponse, CreateSkillResponses, CreateSlackProviderData, CreateSlackProviderErrors, CreateSlackProviderRequest, CreateSlackProviderResponse, CreateSlackProviderResponses, CreateTeamData, CreateTeamErrors, CreateTeamMemberRequest, CreateTeamRequest, CreateTeamResponse, CreateTeamResponses, CreateUserData, CreateUserErrors, CreateUserRequest, CreateUserResponse, CreateUserResponses, CreateWebhookData, CreateWebhookErrors, CreateWebhookProviderData, CreateWebhookProviderErrors, CreateWebhookProviderRequest, CreateWebhookProviderResponse, CreateWebhookProviderResponses, CreateWebhookRequestBody, CreateWebhookResponse, CreateWebhookResponses, CronExecutionInfo, CronInfo, CrossProjectSiblingRef, CrossProjectTraceResponse, CurrentStatusResponse, CustomDomainRequest, CustomDomainResponse, CustomerMovementResponse, DashboardLayout, DashboardProjectsAnalyticsQuery, DashboardProjectsAnalyticsResponse, DashboardSection, DashboardTile, DatabaseMetricsResponse, DatabaseMetricsRow, DataImplication, DataImplicationSeverity, DeactivateApiKeyData, DeactivateApiKeyErrors, DeactivateApiKeyResponse, DeactivateApiKeyResponses, DeactivateConnectionData, DeactivateConnectionErrors, DeactivateConnectionResponses, DeactivateProviderData, DeactivateProviderErrors, DeactivateProviderResponses, DeleteAgentData, DeleteAgentErrors, DeleteAgentResponse, DeleteAgentResponses, DeleteAlertData, DeleteAlertError, DeleteAlertErrors, DeleteAlertResponse, DeleteAlertResponses, DeleteAlertRuleData, DeleteAlertRuleErrors, DeleteAlertRuleResponse, DeleteAlertRuleResponses, DeleteApiKeyData, DeleteApiKeyErrors, DeleteApiKeyResponse, DeleteApiKeyResponses, DeleteBackupData, DeleteBackupError, DeleteBackupErrors, DeleteBackupResponse, DeleteBackupResponses, DeleteBackupScheduleData, DeleteBackupScheduleError, DeleteBackupScheduleErrors, DeleteBackupScheduleResponse, DeleteBackupScheduleResponses, DeleteBlobRequest, DeleteBlobResponse, DeleteConnectionData, DeleteConnectionErrors, DeleteConnectionResponse, DeleteConnectionResponses, DeleteCustomDomainData, DeleteCustomDomainErrors, DeleteCustomDomainResponse, DeleteCustomDomainResponses, DeleteDashboardData, DeleteDashboardError, DeleteDashboardErrors, DeleteDashboardResponse, DeleteDashboardResponses, DeleteDeploymentTokenData, DeleteDeploymentTokenErrors, DeleteDeploymentTokenResponse, DeleteDeploymentTokenResponses, DeleteDnsProviderData, DeleteDnsProviderErrors, DeleteDnsProviderResponse, DeleteDnsProviderResponses, DeleteDomainData, DeleteDomainErrors, DeleteDomainResponse, DeleteDomainResponses, DeleteEmailDomainData, DeleteEmailDomainErrors, DeleteEmailDomainResponse, DeleteEmailDomainResponses, DeleteEmailProviderData, DeleteEmailProviderErrors, DeleteEmailProviderResponse, DeleteEmailProviderResponses, DeleteEnvironmentData, DeleteEnvironmentDomainData, DeleteEnvironmentDomainErrors, DeleteEnvironmentDomainResponse, DeleteEnvironmentDomainResponses, DeleteEnvironmentErrors, DeleteEnvironmentResponse, DeleteEnvironmentResponses, DeleteEnvironmentVariableData, DeleteEnvironmentVariableErrors, DeleteEnvironmentVariableResponse, DeleteEnvironmentVariableResponses, DeleteExternalImageData, DeleteExternalImageErrors, DeleteExternalImageResponse, DeleteExternalImageResponses, DeleteFunnelData, DeleteFunnelErrors, DeleteFunnelResponses, DeleteGitProviderData, DeleteGitProviderErrors, DeleteGitProviderResponse, DeleteGitProviderResponses, DeleteGlobalMcpData, DeleteGlobalMcpErrors, DeleteGlobalMcpResponse, DeleteGlobalMcpResponses, DeleteGlobalSkillData, DeleteGlobalSkillErrors, DeleteGlobalSkillResponse, DeleteGlobalSkillResponses, DeleteIpAccessControlData, DeleteIpAccessControlError, DeleteIpAccessControlErrors, DeleteIpAccessControlResponse, DeleteIpAccessControlResponses, DeleteMcpData, DeleteMcpErrors, DeleteMcpResponse, DeleteMcpResponses, DeleteMonitorData, DeleteMonitorErrors, DeleteMonitorResponse, DeleteMonitorResponses, DeleteNotificationProviderData, DeleteNotificationProviderErrors, DeleteNotificationProviderResponse, DeleteNotificationProviderResponses, DeleteOidcProviderData, DeleteOidcProviderResponse, DeleteOidcProviderResponses, DeleteOidcRoleMappingData, DeleteOidcRoleMappingResponse, DeleteOidcRoleMappingResponses, DeletePreferencesData, DeletePreferencesErrors, DeletePreferencesResponse, DeletePreferencesResponses, DeleteProjectData, DeleteProjectErrors, DeleteProjectResponse, DeleteProjectResponses, DeleteProjectSecretData, DeleteProjectSecretErrors, DeleteProjectSecretResponse, DeleteProjectSecretResponses, DeleteProviderKeyData, DeleteProviderKeyError, DeleteProviderKeyErrors, DeleteProviderKeyResponse, DeleteProviderKeyResponses, DeleteProviderSafelyData, DeleteProviderSafelyErrors, DeleteProviderSafelyResponse, DeleteProviderSafelyResponses, DeleteReleaseSourceFilesData, DeleteReleaseSourceFilesErrors, DeleteReleaseSourceFilesResponse, DeleteReleaseSourceFilesResponses, DeleteReleaseSourceMapsData, DeleteReleaseSourceMapsErrors, DeleteReleaseSourceMapsResponse, DeleteReleaseSourceMapsResponses, DeleteResponse, DeleteRouteData, DeleteRouteErrors, DeleteRouteResponse, DeleteRouteResponses, DeleteS3SourceData, DeleteS3SourceError, DeleteS3SourceErrors, DeleteS3SourceResponse, DeleteS3SourceResponses, DeleteScanData, DeleteScanError, DeleteScanErrors, DeleteScanResponse, DeleteScanResponses, DeleteSecretData, DeleteSecretErrors, DeleteSecretResponse, DeleteSecretResponses, DeleteServiceData, DeleteServiceErrors, DeleteServiceResponse, DeleteServiceResponses, DeleteSessionReplayData, DeleteSessionReplayError, DeleteSessionReplayErrors, DeleteSessionReplayResponses, DeleteSkillData, DeleteSkillErrors, DeleteSkillResponse, DeleteSkillResponses, DeleteSourceMapData, DeleteSourceMapErrors, DeleteSourceMapResponse, DeleteSourceMapResponses, DeleteStaticBundleData, DeleteStaticBundleErrors, DeleteStaticBundleResponse, DeleteStaticBundleResponses, DeleteTeamData, DeleteTeamErrors, DeleteTeamResponse, DeleteTeamResponses, DeleteUserData, DeleteUserErrors, DeleteUserResponse, DeleteUserResponses, DeleteWebhookData, DeleteWebhookErrors, DeleteWebhookResponse, DeleteWebhookResponses, DelRequest, DelResponse, DeployFromImageData, DeployFromImageErrors, DeployFromImageRequest, DeployFromImageResponse, DeployFromImageResponses, DeployFromImageUploadData, DeployFromImageUploadErrors, DeployFromImageUploadQuery, DeployFromImageUploadResponse, DeployFromImageUploadResponses, DeployFromStaticData, DeployFromStaticErrors, DeployFromStaticRequest, DeployFromStaticResponse, DeployFromStaticResponses, DeployFromUploadedSourceData, DeployFromUploadedSourceErrors, DeployFromUploadedSourceResponse, DeployFromUploadedSourceResponses, DeploymentConfig, DeploymentConfigSnapshot, DeploymentConfiguration, DeploymentContainerLogContentResponse, DeploymentContainerLogResponse, DeploymentContainerLogsListResponse, DeploymentEnvironmentResponse, DeploymentJobResponse, DeploymentJobsResponse, DeploymentListResponse, DeploymentMetadata, DeploymentMetricsGetLatestData, DeploymentMetricsGetLatestErrors, DeploymentMetricsGetLatestResponse, DeploymentMetricsGetLatestResponses, DeploymentMetricsGetRangeData, DeploymentMetricsGetRangeErrors, DeploymentMetricsGetRangeResponse, DeploymentMetricsGetRangeResponses, DeploymentMetricsToggleData, DeploymentMetricsToggleErrors, DeploymentMetricsToggleResponses, DeploymentResponse, DeploymentStateResponse, DeploymentStrategy, DeploymentTokenListResponse, DeploymentTokenResponse, DestroySandboxData, DestroySandboxErrors, DestroySandboxResponse, DestroySandboxResponses, DetachScheduleServiceData, DetachScheduleServiceError, DetachScheduleServiceErrors, DetachScheduleServiceResponse, DetachScheduleServiceResponses, DetectionConfig, DetectPublicPresetsData, DetectPublicPresetsErrors, DetectPublicPresetsResponse, DetectPublicPresetsResponses, DeviceCount, DigestSections, Direction, DisableBackupScheduleData, DisableBackupScheduleErrors, DisableBackupScheduleResponse, DisableBackupScheduleResponses, DisableBlobResponse, DisableKvResponse, DisableMfaData, DisableMfaErrors, DisableMfaRequest, DisableMfaResponse, DisableMfaResponses, DiscoverRequest, DiscoverResponse, DiscoverWorkloadsData, DiscoverWorkloadsErrors, DiscoverWorkloadsResponse, DiscoverWorkloadsResponses, DiskInfo, DiskSpaceAlert, DiskSpaceAlertSettings, DiskSpaceCheckResult, DnsAckRequest, DnsAckResponse, DnsChallengeRecordResult, DnsChangesResponse, DnsCompletionResponse, DnsLookupError, DnsLookupRequest, DnsLookupResponse, DnsProviderCredentials, DnsProviderResponse, DnsProviderSettings, DnsProviderSettingsMasked, DnsProviderType, DnsRecord, DnsRecordChange, DnsRecordContent, DnsRecordResponse, DnsRecordSetupResult, DnsRecordStatusResponse, DnsZone, DockerComposePresetConfig, DockerfilePresetConfig, DockerfileVariant, DockerRegistrySettings, DockerRegistrySettingsMasked, DomainAction, DomainChallengeResponse, DomainData, DomainEnvironmentResponse, DomainError, DomainErrors, DomainPlan, DomainResponse, DomainResponse2, DomainResponses, DownloadGlobalSkillArchiveData, DownloadGlobalSkillArchiveErrors, DownloadGlobalSkillArchiveResponse, DownloadGlobalSkillArchiveResponses, DownloadObjectData, DownloadObjectErrors, DownloadObjectResponse, DownloadObjectResponses, DownloadSkillArchiveData, DownloadSkillArchiveErrors, DownloadSkillArchiveResponse, DownloadSkillArchiveResponses, DrainNodeResponse, DrainStatusResponse, DropArchiveUpload, DropInspectionResponse, DropOffPoint, DropPresetCandidate, EmailConfig, EmailDomainResponse, EmailDomainWithDnsResponse, EmailProviderResponse, EmailProviderTypeRoute, EmailRequest, EmailResponse, EmailStatsResponse, EmailStatusData, EmailStatusErrors, EmailStatusResponse, EmailStatusResponse2, EmailStatusResponses, EmailTrackingResponse, EmailTrackingSetupResponse, EmailTrackingStatusResponse, EmbeddingData, EmbeddingInput, EmbeddingRequest, EmbeddingResponse, EmbeddingsData, EmbeddingsError, EmbeddingsErrors, EmbeddingsResponse, EmbeddingsResponses, EmbeddingUsage, EnableBackupScheduleData, EnableBackupScheduleErrors, EnableBackupScheduleResponse, EnableBackupScheduleResponses, EnableBlobRequest, EnableBlobResponse, EnableKvRequest, EnableKvResponse, EnablePgStatStatementsResponse, EndpointDto, EnqueuedJob, EnrichVisitorData, EnrichVisitorErrors, EnrichVisitorRequest, EnrichVisitorResponse, EnrichVisitorResponse2, EnrichVisitorResponses, EnrollmentTokenInfo, EnrollmentTokenListResponse, EntityInfoResponse, EntityResponse, EnvironmentConfiguration, EnvironmentDomainResponse, EnvironmentInfo, EnvironmentResponse, EnvironmentVariable, EnvironmentVariableInfo, EnvironmentVariableResponse, EnvironmentVariableValueResponse, EnvVarInput, EnvVarIntegrationInfo, EnvVarResponse, EnvVarTemplateResponse, ErrorDashboardStatsQuery, ErrorDashboardStatsResponse, ErrorEventResponse, ErrorGroupResponse, ErrorGroupStatsResponse, ErrorResponse, ErrorRow, ErrorTimeSeriesDataResponse, ErrorTimeSeriesQuery, EventActivityBucket, EventBreakdown, EventBrowserStats, EventCount, EventCountryStats, EventDetailQuery, EventDetailResponse, EventEntriesQuery, EventEntriesResponse, EventEntryInfo, EventKind, EventMetricsPayload, EventReferrerStats, EventsCountQuery, EventsResponse, EventTimeline, EventTimelineQuery, EventType, EventTypeBreakdown, EventTypeBreakdownQuery, EventTypeResponse, EventTypesResponse, EventVisitorInfo, EventVisitorsQuery, EventVisitorsResponse, ExecBody, ExecData, ExecDetachedData, ExecDetachedErrors, ExecDetachedResponse, ExecDetachedResponse2, ExecDetachedResponses, ExecErrors, ExecResponse, ExecResponse2, ExecResponses, ExecuteDeploymentOperationData, ExecuteDeploymentOperationErrors, ExecuteDeploymentOperationResponse, ExecuteDeploymentOperationResponses, ExecuteImportData, ExecuteImportErrors, ExecuteImportRequest, ExecuteImportResponse, ExecuteImportResponse2, ExecuteImportResponses, ExecuteOperationRequest, ExpireRequest, ExpireResponse, ExplorerSupportResponse, ExtendTimeoutBody, ExtendTimeoutData, ExtendTimeoutErrors, ExtendTimeoutResponse, ExtendTimeoutResponses, ExternalImageResponse, ExternalServiceBackupResponse, ExternalServiceDetails, ExternalServiceEnablePgStatStatementsData, ExternalServiceEnablePgStatStatementsErrors, ExternalServiceEnablePgStatStatementsResponse, ExternalServiceEnablePgStatStatementsResponses, ExternalServiceInfo, ExternalServiceMetricsByDatabaseData, ExternalServiceMetricsByDatabaseErrors, ExternalServiceMetricsByDatabaseResponse, ExternalServiceMetricsByDatabaseResponses, ExternalServiceMetricsCreateAlertRuleData, ExternalServiceMetricsCreateAlertRuleErrors, ExternalServiceMetricsCreateAlertRuleResponse, ExternalServiceMetricsCreateAlertRuleResponses, ExternalServiceMetricsDeleteAlertRuleData, ExternalServiceMetricsDeleteAlertRuleErrors, ExternalServiceMetricsDeleteAlertRuleResponse, ExternalServiceMetricsDeleteAlertRuleResponses, ExternalServiceMetricsGetAlertRulesData, ExternalServiceMetricsGetAlertRulesErrors, ExternalServiceMetricsGetAlertRulesResponse, ExternalServiceMetricsGetAlertRulesResponses, ExternalServiceMetricsGetLatestData, ExternalServiceMetricsGetLatestErrors, ExternalServiceMetricsGetLatestResponse, ExternalServiceMetricsGetLatestResponses, ExternalServiceMetricsGetRangeData, ExternalServiceMetricsGetRangeErrors, ExternalServiceMetricsGetRangeResponse, ExternalServiceMetricsGetRangeResponses, ExternalServiceMetricsStatusData, ExternalServiceMetricsStatusErrors, ExternalServiceMetricsStatusResponse, ExternalServiceMetricsStatusResponses, ExternalServiceMetricsToggleData, ExternalServiceMetricsToggleErrors, ExternalServiceMetricsToggleResponses, ExternalServiceMetricsUpdateAlertRuleData, ExternalServiceMetricsUpdateAlertRuleErrors, ExternalServiceMetricsUpdateAlertRuleResponse, ExternalServiceMetricsUpdateAlertRuleResponses, ExternalServiceResetPgStatStatementsData, ExternalServiceResetPgStatStatementsErrors, ExternalServiceResetPgStatStatementsResponse, ExternalServiceResetPgStatStatementsResponses, ExternalServiceSummary, FieldResponse, FinalizeOrderData, FinalizeOrderErrors, FinalizeOrderResponse, FinalizeOrderResponses, FinalizeProjectReleaseData, FinalizeProjectReleaseErrors, FinalizeProjectReleaseResponse, FinalizeProjectReleaseResponses, FindConversationData, FindConversationErrors, FindConversationResponse, FindConversationResponses, FiringSeriesEntry, FlagEnvironmentResponse, FlagListResponse, FlagResponse, FlagSnapshot, FlagSnapshotResponse, FlagValueType, ForecastAlgorithm, ForecastParams, FullError, FullEvent, FullRequest, FunnelMetricsResponse, FunnelResponse, GatewayStatus, GenAiEvent, GenAiSpanDetail, GenAiTraceDetailResponse, GenAiTraceSummariesResponse, GenAiTraceSummary, GeneralStatsQuery, GeneralStatsResponse, GenerateDockerfileRequest, GenerateDockerfileResponse, GenerateJoinTokenData, GenerateJoinTokenErrors, GenerateJoinTokenResponse, GenerateJoinTokenResponse2, GenerateJoinTokenResponses, GeneratePresetDockerfileData, GeneratePresetDockerfileErrors, GeneratePresetDockerfileResponse, GeneratePresetDockerfileResponses, GeoLocationResponse, GeoRestrictionsConfig, GetAccessInfoData, GetAccessInfoErrors, GetAccessInfoResponse, GetAccessInfoResponses, GetActiveVisitorsData, GetActiveVisitorsErrors, GetActiveVisitorsResponse, GetActiveVisitorsResponses, GetActivityGraphData, GetActivityGraphErrors, GetActivityGraphResponse, GetActivityGraphResponses, GetAdminGateData, GetAdminGateErrors, GetAdminGateResponse, GetAdminGateResponses, GetAgentData, GetAgentErrors, GetAgentResponse, GetAgentResponses, GetAggregatedBucketsData, GetAggregatedBucketsErrors, GetAggregatedBucketsResponse, GetAggregatedBucketsResponses, GetAiAgentBreakdownData, GetAiAgentBreakdownError, GetAiAgentBreakdownErrors, GetAiAgentBreakdownResponse, GetAiAgentBreakdownResponses, GetAiAgentPagesData, GetAiAgentPagesError, GetAiAgentPagesErrors, GetAiAgentPagesResponse, GetAiAgentPagesResponses, GetAiAgentTimelineData, GetAiAgentTimelineError, GetAiAgentTimelineErrors, GetAiAgentTimelineResponse, GetAiAgentTimelineResponses, GetAiPageBreakdownData, GetAiPageBreakdownError, GetAiPageBreakdownErrors, GetAiPageBreakdownResponse, GetAiPageBreakdownResponses, GetAiStatusBreakdownData, GetAiStatusBreakdownError, GetAiStatusBreakdownErrors, GetAiStatusBreakdownResponse, GetAiStatusBreakdownResponses, GetAlertData, GetAlertError, GetAlertErrors, GetAlertResponse, GetAlertResponses, GetAlertRuleData, GetAlertRuleErrors, GetAlertRuleResponse, GetAlertRuleResponses, GetAllRepositoriesByNameData, GetAllRepositoriesByNameErrors, GetAllRepositoriesByNameResponse, GetAllRepositoriesByNameResponses, GetAnalyticsActiveVisitorsData, GetAnalyticsActiveVisitorsErrors, GetAnalyticsActiveVisitorsResponse, GetAnalyticsActiveVisitorsResponses, GetAnalyticsEventsCountData, GetAnalyticsEventsCountErrors, GetAnalyticsEventsCountResponse, GetAnalyticsEventsCountResponses, GetAnalyticsSessionEventsData, GetAnalyticsSessionEventsErrors, GetAnalyticsSessionEventsResponse, GetAnalyticsSessionEventsResponses, GetAnalyticsVisitorSessionsData, GetAnalyticsVisitorSessionsErrors, GetAnalyticsVisitorSessionsResponse, GetAnalyticsVisitorSessionsResponses, GetApiKeyData, GetApiKeyErrors, GetApiKeyPermissionsData, GetApiKeyPermissionsErrors, GetApiKeyPermissionsResponse, GetApiKeyPermissionsResponses, GetApiKeyResponse, GetApiKeyResponses, GetAuditLogData, GetAuditLogErrors, GetAuditLogResponse, GetAuditLogResponses, GetBackupData, GetBackupError, GetBackupErrors, GetBackupResponse, GetBackupResponses, GetBackupScheduleData, GetBackupScheduleErrors, GetBackupScheduleResponse, GetBackupScheduleResponses, GetBranchesByRepositoryIdData, GetBranchesByRepositoryIdErrors, GetBranchesByRepositoryIdResponse, GetBranchesByRepositoryIdResponses, GetBucketedIncidentsData, GetBucketedIncidentsErrors, GetBucketedIncidentsResponse, GetBucketedIncidentsResponses, GetBucketedStatusData, GetBucketedStatusErrors, GetBucketedStatusResponse, GetBucketedStatusResponses, GetChallengeTokenData, GetChallengeTokenErrors, GetChallengeTokenResponse, GetChallengeTokenResponses, GetChatReadinessData, GetChatReadinessErrors, GetChatReadinessResponse, GetChatReadinessResponses, GetCliStatusData, GetCliStatusErrors, GetCliStatusResponses, GetClusterHealthData, GetClusterHealthErrors, GetClusterHealthResponse, GetClusterHealthResponses, GetClusterMemberData, GetClusterMemberErrors, GetClusterMemberResponse, GetClusterMemberResponses, GetCmdData, GetCmdErrors, GetCmdResponse, GetCmdResponses, GetContainerDetailData, GetContainerDetailErrors, GetContainerDetailResponse, GetContainerDetailResponses, GetContainerEnvironmentVariableData, GetContainerEnvironmentVariableErrors, GetContainerEnvironmentVariableResponse, GetContainerEnvironmentVariableResponses, GetContainerInfoData, GetContainerInfoErrors, GetContainerInfoResponse, GetContainerInfoResponses, GetContainerLogsByIdData, GetContainerLogsByIdErrors, GetContainerLogsData, GetContainerLogsErrors, GetContainerMetricsData, GetContainerMetricsErrors, GetContainerMetricsResponse, GetContainerMetricsResponses, GetConversationData, GetConversationDetailData, GetConversationDetailError, GetConversationDetailErrors, GetConversationDetailResponse, GetConversationDetailResponses, GetConversationErrors, GetConversationResponse, GetConversationResponses, GetConversationsData, GetConversationsError, GetConversationsErrors, GetConversationsResponse, GetConversationsResponses, GetCronByIdData, GetCronByIdErrors, GetCronByIdResponse, GetCronByIdResponses, GetCronExecutionsData, GetCronExecutionsErrors, GetCronExecutionsResponse, GetCronExecutionsResponses, GetCrossProjectTraceSiblingsData, GetCrossProjectTraceSiblingsError, GetCrossProjectTraceSiblingsErrors, GetCrossProjectTraceSiblingsResponse, GetCrossProjectTraceSiblingsResponses, GetCurrentMonitorStatusData, GetCurrentMonitorStatusErrors, GetCurrentMonitorStatusResponse, GetCurrentMonitorStatusResponses, GetCurrentUserData, GetCurrentUserErrors, GetCurrentUserResponse, GetCurrentUserResponses, GetCustomDomainData, GetCustomDomainErrors, GetCustomDomainResponse, GetCustomDomainResponses, GetDashboardData, GetDashboardError, GetDashboardErrors, GetDashboardProjectsAnalyticsData, GetDashboardProjectsAnalyticsErrors, GetDashboardProjectsAnalyticsResponse, GetDashboardProjectsAnalyticsResponses, GetDashboardResponse, GetDashboardResponses, GetDeliveryData, GetDeliveryErrors, GetDeliveryResponse, GetDeliveryResponses, GetDeploymentContainerLogContentData, GetDeploymentContainerLogContentErrors, GetDeploymentContainerLogContentResponse, GetDeploymentContainerLogContentResponses, GetDeploymentData, GetDeploymentErrors, GetDeploymentJobLogsData, GetDeploymentJobLogsErrors, GetDeploymentJobLogsResponse, GetDeploymentJobLogsResponses, GetDeploymentJobsData, GetDeploymentJobsErrors, GetDeploymentJobsResponse, GetDeploymentJobsResponses, GetDeploymentOperationsData, GetDeploymentOperationsErrors, GetDeploymentOperationsResponse, GetDeploymentOperationsResponses, GetDeploymentOperationStatusData, GetDeploymentOperationStatusErrors, GetDeploymentOperationStatusResponse, GetDeploymentOperationStatusResponses, GetDeploymentResponse, GetDeploymentResponses, GetDeploymentsParams, GetDeploymentTokenData, GetDeploymentTokenErrors, GetDeploymentTokenResponse, GetDeploymentTokenResponses, GetDiskStatusData, GetDiskStatusErrors, GetDiskStatusResponse, GetDiskStatusResponses, GetDnsChangesData, GetDnsChangesErrors, GetDnsChangesResponse, GetDnsChangesResponses, GetDnsProviderData, GetDnsProviderErrors, GetDnsProviderResponse, GetDnsProviderResponses, GetDomainByHostData, GetDomainByHostErrors, GetDomainByHostResponse, GetDomainByHostResponses, GetDomainByIdData, GetDomainByIdErrors, GetDomainByIdResponse, GetDomainByIdResponses, GetDomainByNameData, GetDomainByNameErrors, GetDomainByNameResponse, GetDomainByNameResponses, GetDomainData, GetDomainDnsRecordsData, GetDomainDnsRecordsErrors, GetDomainDnsRecordsResponse, GetDomainDnsRecordsResponses, GetDomainErrors, GetDomainOrderData, GetDomainOrderErrors, GetDomainOrderResponse, GetDomainOrderResponses, GetDomainResponse, GetDomainResponses, GetEmailData, GetEmailErrors, GetEmailEventsData, GetEmailEventsErrors, GetEmailEventsResponse, GetEmailEventsResponses, GetEmailLinksData, GetEmailLinksErrors, GetEmailLinksResponse, GetEmailLinksResponses, GetEmailProviderData, GetEmailProviderErrors, GetEmailProviderResponse, GetEmailProviderResponses, GetEmailResponse, GetEmailResponses, GetEmailStatsData, GetEmailStatsErrors, GetEmailStatsResponse, GetEmailStatsResponses, GetEmailTrackingData, GetEmailTrackingErrors, GetEmailTrackingResponse, GetEmailTrackingResponses, GetEmailTrackingStatusData, GetEmailTrackingStatusErrors, GetEmailTrackingStatusResponse, GetEmailTrackingStatusResponses, GetEntityInfoData, GetEntityInfoErrors, GetEntityInfoResponse, GetEntityInfoResponses, GetEnvironmentCronsData, GetEnvironmentCronsErrors, GetEnvironmentCronsResponse, GetEnvironmentCronsResponses, GetEnvironmentData, GetEnvironmentDomainsData, GetEnvironmentDomainsErrors, GetEnvironmentDomainsResponse, GetEnvironmentDomainsResponses, GetEnvironmentErrors, GetEnvironmentResponse, GetEnvironmentResponses, GetEnvironmentsData, GetEnvironmentsErrors, GetEnvironmentsResponse, GetEnvironmentsResponses, GetEnvironmentVariablesData, GetEnvironmentVariablesErrors, GetEnvironmentVariablesQuery, GetEnvironmentVariablesResponse, GetEnvironmentVariablesResponses, GetEnvironmentVariableValueData, GetEnvironmentVariableValueErrors, GetEnvironmentVariableValueResponse, GetEnvironmentVariableValueResponses, GetErrorDashboardStatsData, GetErrorDashboardStatsErrors, GetErrorDashboardStatsResponse, GetErrorDashboardStatsResponses, GetErrorEventData, GetErrorEventErrors, GetErrorEventResponse, GetErrorEventResponses, GetErrorGroupData, GetErrorGroupErrors, GetErrorGroupResponse, GetErrorGroupResponses, GetErrorStatsData, GetErrorStatsErrors, GetErrorStatsResponse, GetErrorStatsResponses, GetErrorTimeSeriesData, GetErrorTimeSeriesErrors, GetErrorTimeSeriesResponse, GetErrorTimeSeriesResponses, GetEventDetailData, GetEventDetailErrors, GetEventDetailResponse, GetEventDetailResponses, GetEventEntriesData, GetEventEntriesErrors, GetEventEntriesResponse, GetEventEntriesResponses, GetEventsCountData, GetEventsCountErrors, GetEventsCountResponse, GetEventsCountResponses, GetEventsTimelineData, GetEventsTimelineErrors, GetEventsTimelineResponse, GetEventsTimelineResponses, GetEventTypeBreakdownData, GetEventTypeBreakdownErrors, GetEventTypeBreakdownResponse, GetEventTypeBreakdownResponses, GetEventVisitorsData, GetEventVisitorsErrors, GetEventVisitorsResponse, GetEventVisitorsResponses, GetExternalImageData, GetExternalImageErrors, GetExternalImageResponse, GetExternalImageResponses, GetFileData, GetFileErrors, GetFileResponse, GetFileResponses, GetFlagData, GetFlagErrors, GetFlagResponse, GetFlagResponses, GetFlagSnapshotData, GetFlagSnapshotErrors, GetFlagSnapshotResponse, GetFlagSnapshotResponses, GetFunnelMetricsData, GetFunnelMetricsErrors, GetFunnelMetricsQuery, GetFunnelMetricsResponse, GetFunnelMetricsResponses, GetGenaiTraceData, GetGenaiTraceError, GetGenaiTraceErrors, GetGenaiTraceResponse, GetGenaiTraceResponses, GetGeneralStatsData, GetGeneralStatsErrors, GetGeneralStatsResponse, GetGeneralStatsResponses, GetGitProviderData, GetGitProviderErrors, GetGitProviderResponse, GetGitProviderResponses, GetGlobalEventsData, GetGlobalEventsErrors, GetGlobalEventsResponse, GetGlobalEventsResponses, GetGlobalEventStatsData, GetGlobalEventStatsErrors, GetGlobalEventStatsResponse, GetGlobalEventStatsResponses, GetGlobalMcpData, GetGlobalMcpErrors, GetGlobalMcpResponse, GetGlobalMcpResponses, GetGlobalSandboxStatusData, GetGlobalSandboxStatusErrors, GetGlobalSandboxStatusResponse, GetGlobalSandboxStatusResponses, GetGlobalSkillData, GetGlobalSkillErrors, GetGlobalSkillResponse, GetGlobalSkillResponses, GetGroupedPageMetricsData, GetGroupedPageMetricsError, GetGroupedPageMetricsErrors, GetGroupedPageMetricsResponse, GetGroupedPageMetricsResponses, GetHealthData, GetHealthError, GetHealthErrors, GetHealthResponse, GetHealthResponses, GetHourlyVisitsData, GetHourlyVisitsErrors, GetHourlyVisitsResponse, GetHourlyVisitsResponses, GetHttpChallengeDebugData, GetHttpChallengeDebugErrors, GetHttpChallengeDebugResponse, GetHttpChallengeDebugResponses, GetImportStatusData, GetImportStatusErrors, GetImportStatusResponse, GetImportStatusResponses, GetIncidentData, GetIncidentErrors, GetIncidentResponse, GetIncidentResponses, GetIncidentUpdatesData, GetIncidentUpdatesErrors, GetIncidentUpdatesResponse, GetIncidentUpdatesResponses, GetIpAccessControlData, GetIpAccessControlError, GetIpAccessControlErrors, GetIpAccessControlResponse, GetIpAccessControlResponses, GetIpGeolocationData, GetIpGeolocationError, GetIpGeolocationErrors, GetIpGeolocationResponse, GetIpGeolocationResponses, GetJoinTokenStatusData, GetJoinTokenStatusErrors, GetJoinTokenStatusResponse, GetJoinTokenStatusResponses, GetLastDeploymentData, GetLastDeploymentErrors, GetLastDeploymentResponse, GetLastDeploymentResponses, GetLatestScanData, GetLatestScanError, GetLatestScanErrors, GetLatestScanResponse, GetLatestScanResponses, GetLatestScansPerEnvironmentData, GetLatestScansPerEnvironmentError, GetLatestScansPerEnvironmentErrors, GetLatestScansPerEnvironmentResponse, GetLatestScansPerEnvironmentResponses, GetLiveVisitorsListData, GetLiveVisitorsListErrors, GetLiveVisitorsListResponse, GetLiveVisitorsListResponses, GetLogContextData, GetLogContextError, GetLogContextErrors, GetLogContextResponse, GetLogContextResponses, GetMcpData, GetMcpErrors, GetMcpResponse, GetMcpResponses, GetMetricsOverTimeData, GetMetricsOverTimeError, GetMetricsOverTimeErrors, GetMetricsOverTimeResponse, GetMetricsOverTimeResponses, GetMonitorData, GetMonitorErrors, GetMonitorResponse, GetMonitorResponses, GetNotificationProviderData, GetNotificationProviderErrors, GetNotificationProviderResponse, GetNotificationProviderResponses, GetOnDemandCertStatusData, GetOnDemandCertStatusErrors, GetOnDemandCertStatusResponse, GetOnDemandCertStatusResponses, GetOrCreateDsnData, GetOrCreateDsnErrors, GetOrCreateDsnRequest, GetOrCreateDsnResponse, GetOrCreateDsnResponses, GetPageFlowData, GetPageFlowErrors, GetPageFlowResponse, GetPageFlowResponses, GetPageHourlySessionsData, GetPageHourlySessionsErrors, GetPageHourlySessionsResponse, GetPageHourlySessionsResponses, GetPagePathDetailData, GetPagePathDetailErrors, GetPagePathDetailResponse, GetPagePathDetailResponses, GetPagePathsData, GetPagePathsErrors, GetPagePathsResponse, GetPagePathsResponses, GetPagePathsSparklinesData, GetPagePathsSparklinesErrors, GetPagePathsSparklinesResponse, GetPagePathsSparklinesResponses, GetPagePathVisitorsData, GetPagePathVisitorsErrors, GetPagePathVisitorsResponse, GetPagePathVisitorsResponses, GetPendingActionData, GetPendingActionErrors, GetPendingActionResponse, GetPendingActionResponses, GetPerformanceMetricsData, GetPerformanceMetricsError, GetPerformanceMetricsErrors, GetPerformanceMetricsResponse, GetPerformanceMetricsResponses, GetPgUpgradeData, GetPgUpgradeErrors, GetPgUpgradeLogsData, GetPgUpgradeLogsErrors, GetPgUpgradeLogsResponse, GetPgUpgradeLogsResponses, GetPgUpgradeResponse, GetPgUpgradeResponses, GetPipelineStatsData, GetPipelineStatsError, GetPipelineStatsErrors, GetPipelineStatsResponse, GetPipelineStatsResponses, GetPlatformInfoData, GetPlatformInfoErrors, GetPlatformInfoResponse, GetPlatformInfoResponses, GetPostgresWalHealthData, GetPostgresWalHealthErrors, GetPostgresWalHealthResponse, GetPostgresWalHealthResponses, GetPreferencesData, GetPreferencesErrors, GetPreferencesResponse, GetPreferencesResponses, GetPreviewGatewayLogsData, GetPreviewGatewayLogsResponse, GetPreviewGatewayLogsResponses, GetPreviewGatewaySettingsData, GetPreviewGatewaySettingsResponse, GetPreviewGatewaySettingsResponses, GetPreviewGatewayStatusData, GetPreviewGatewayStatusResponse, GetPreviewGatewayStatusResponses, GetPricingData, GetPricingError, GetPricingErrors, GetPricingResponse, GetPricingResponses, GetPrivateIpData, GetPrivateIpErrors, GetPrivateIpResponses, GetProjectAlarmsSummaryData, GetProjectAlarmsSummaryErrors, GetProjectAlarmsSummaryResponse, GetProjectAlarmsSummaryResponses, GetProjectBySlugData, GetProjectBySlugErrors, GetProjectBySlugResponse, GetProjectBySlugResponses, GetProjectData, GetProjectDeploymentsData, GetProjectDeploymentsErrors, GetProjectDeploymentsResponse, GetProjectDeploymentsResponses, GetProjectErrors, GetProjectResponse, GetProjectResponses, GetProjectsData, GetProjectSecretsQuery, GetProjectsErrors, GetProjectServiceEnvironmentVariablesData, GetProjectServiceEnvironmentVariablesErrors, GetProjectServiceEnvironmentVariablesResponse, GetProjectServiceEnvironmentVariablesResponses, GetProjectSessionReplaysData, GetProjectSessionReplaysError, GetProjectSessionReplaysErrors, GetProjectSessionReplaysQuery, GetProjectSessionReplaysResponse, GetProjectSessionReplaysResponse2, GetProjectSessionReplaysResponses, GetProjectsHealthData, GetProjectsHealthError, GetProjectsHealthErrors, GetProjectsHealthResponse, GetProjectsHealthResponses, GetProjectsMonitorHealthData, GetProjectsMonitorHealthErrors, GetProjectsMonitorHealthResponse, GetProjectsMonitorHealthResponses, GetProjectsResponse, GetProjectsResponses, GetProjectStatisticsData, GetProjectStatisticsErrors, GetProjectStatisticsResponse, GetProjectStatisticsResponses, GetProjectTemplateData, GetProjectTemplateErrors, GetProjectTemplateResponse, GetProjectTemplateResponses, GetPropertyBreakdownData, GetPropertyBreakdownErrors, GetPropertyBreakdownResponse, GetPropertyBreakdownResponses, GetPropertyTimelineData, GetPropertyTimelineErrors, GetPropertyTimelineResponse, GetPropertyTimelineResponses, GetProviderConnectionsData, GetProviderConnectionsErrors, GetProviderConnectionsResponse, GetProviderConnectionsResponses, GetProviderMetadataData, GetProviderMetadataErrors, GetProviderMetadataResponse, GetProviderMetadataResponses, GetProvidersMetadataData, GetProvidersMetadataErrors, GetProvidersMetadataResponse, GetProvidersMetadataResponses, GetProxyLogByIdData, GetProxyLogByIdError, GetProxyLogByIdErrors, GetProxyLogByIdResponse, GetProxyLogByIdResponses, GetProxyLogByRequestIdData, GetProxyLogByRequestIdError, GetProxyLogByRequestIdErrors, GetProxyLogByRequestIdResponse, GetProxyLogByRequestIdResponses, GetProxyLogsData, GetProxyLogsError, GetProxyLogsErrors, GetProxyLogsResponse, GetProxyLogsResponses, GetPublicBranchesData, GetPublicBranchesErrors, GetPublicBranchesResponse, GetPublicBranchesResponses, GetPublicIpData, GetPublicIpErrors, GetPublicIpResponses, GetPublicRepositoryData, GetPublicRepositoryErrors, GetPublicRepositoryResponse, GetPublicRepositoryResponses, GetQuotaData, GetQuotaError, GetQuotaErrors, GetQuotaResponse, GetQuotaResponses, GetRecentActivityData, GetRecentActivityErrors, GetRecentActivityResponse, GetRecentActivityResponses, GetRemoteExternalImageData, GetRemoteExternalImageErrors, GetRemoteExternalImageResponse, GetRemoteExternalImageResponses, GetRepositoryBranchesData, GetRepositoryBranchesErrors, GetRepositoryBranchesResponse, GetRepositoryBranchesResponses, GetRepositoryByIdData, GetRepositoryByIdErrors, GetRepositoryByIdResponse, GetRepositoryByIdResponses, GetRepositoryByNameData, GetRepositoryByNameErrors, GetRepositoryByNameResponse, GetRepositoryByNameResponses, GetRepositoryPresetByNameData, GetRepositoryPresetByNameErrors, GetRepositoryPresetByNameResponse, GetRepositoryPresetByNameResponses, GetRepositoryPresetLiveData, GetRepositoryPresetLiveErrors, GetRepositoryPresetLiveResponse, GetRepositoryPresetLiveResponses, GetRepositoryTagsData, GetRepositoryTagsErrors, GetRepositoryTagsResponse, GetRepositoryTagsResponses, GetRequest, GetResolvedEnvironmentVariablesData, GetResolvedEnvironmentVariablesErrors, GetResolvedEnvironmentVariablesResponse, GetResolvedEnvironmentVariablesResponses, GetResolvedEnvironmentVariableValueData, GetResolvedEnvironmentVariableValueErrors, GetResolvedEnvironmentVariableValueResponse, GetResolvedEnvironmentVariableValueResponses, GetResponse, GetRestoreCapabilitiesData, GetRestoreCapabilitiesError, GetRestoreCapabilitiesErrors, GetRestoreCapabilitiesResponse, GetRestoreCapabilitiesResponses, GetRestoreRunData, GetRestoreRunError, GetRestoreRunErrors, GetRestoreRunResponse, GetRestoreRunResponses, GetRouteData, GetRouteErrors, GetRouteResponse, GetRouteResponses, GetRunData, GetRunErrors, GetRunResponse, GetRunResponses, GetRunWithLogsData, GetRunWithLogsErrors, GetRunWithLogsResponse, GetRunWithLogsResponses, GetS3CredentialsData, GetS3CredentialsErrors, GetS3CredentialsResponse, GetS3CredentialsResponses, GetS3SourceData, GetS3SourceError, GetS3SourceErrors, GetS3SourceResponse, GetS3SourceResponses, GetSandboxData, GetSandboxErrors, GetSandboxResponse, GetSandboxResponses, GetSandboxStatusData, GetSandboxStatusErrors, GetSandboxStatusResponse, GetSandboxStatusResponses, GetScanByDeploymentData, GetScanByDeploymentError, GetScanByDeploymentErrors, GetScanByDeploymentResponse, GetScanByDeploymentResponses, GetScanData, GetScanError, GetScanErrors, GetScanResponse, GetScanResponses, GetScanVulnerabilitiesData, GetScanVulnerabilitiesError, GetScanVulnerabilitiesErrors, GetScanVulnerabilitiesResponse, GetScanVulnerabilitiesResponses, GetServiceBySlugData, GetServiceBySlugErrors, GetServiceBySlugResponse, GetServiceBySlugResponses, GetServiceData, GetServiceEnvironmentVariableData, GetServiceEnvironmentVariableErrors, GetServiceEnvironmentVariableResponse, GetServiceEnvironmentVariableResponses, GetServiceEnvironmentVariablesData, GetServiceEnvironmentVariablesErrors, GetServiceEnvironmentVariablesResponse, GetServiceEnvironmentVariablesResponses, GetServiceErrors, GetServiceHealthStatusData, GetServiceHealthStatusErrors, GetServiceHealthStatusResponse, GetServiceHealthStatusResponses, GetServicePreviewEnvironmentVariableNamesData, GetServicePreviewEnvironmentVariableNamesErrors, GetServicePreviewEnvironmentVariableNamesResponse, GetServicePreviewEnvironmentVariableNamesResponses, GetServicePreviewEnvironmentVariablesMaskedData, GetServicePreviewEnvironmentVariablesMaskedErrors, GetServicePreviewEnvironmentVariablesMaskedResponse, GetServicePreviewEnvironmentVariablesMaskedResponses, GetServiceResponse, GetServiceResponses, GetServiceRuntimeData, GetServiceRuntimeErrors, GetServiceRuntimeResponse, GetServiceRuntimeResponses, GetServiceStatsData, GetServiceStatsErrors, GetServiceStatsResponse, GetServiceStatsResponses, GetServiceTypeParametersData, GetServiceTypeParametersErrors, GetServiceTypeParametersResponses, GetServiceTypesData, GetServiceTypesErrors, GetServiceTypesResponse, GetServiceTypesResponses, GetSessionDetailsData, GetSessionDetailsErrors, GetSessionDetailsResponse, GetSessionDetailsResponses, GetSessionEventsData, GetSessionEventsErrors, GetSessionEventsResponse, GetSessionEventsResponses, GetSessionLogsData, GetSessionLogsErrors, GetSessionLogsResponse, GetSessionLogsResponses, GetSessionReplayData, GetSessionReplayError, GetSessionReplayErrors, GetSessionReplayEventsData, GetSessionReplayEventsError, GetSessionReplayEventsErrors, GetSessionReplayEventsResponse, GetSessionReplayEventsResponses, GetSessionReplayResponse, GetSessionReplayResponse2, GetSessionReplayResponses, GetSettingsData, GetSettingsErrors, GetSettingsResponse, GetSettingsResponses, GetSkillData, GetSkillErrors, GetSkillResponse, GetSkillResponses, GetSlowQueriesData, GetSlowQueriesErrors, GetSlowQueriesResponse, GetSlowQueriesResponses, GetStaticBundleData, GetStaticBundleErrors, GetStaticBundleResponse, GetStaticBundleResponses, GetStatusOverviewData, GetStatusOverviewErrors, GetStatusOverviewResponse, GetStatusOverviewResponses, GetTagsByRepositoryIdData, GetTagsByRepositoryIdErrors, GetTagsByRepositoryIdResponse, GetTagsByRepositoryIdResponses, GetTeamData, GetTeamErrors, GetTeamResponse, GetTeamResponses, GetTimeBucketStatsData, GetTimeBucketStatsError, GetTimeBucketStatsErrors, GetTimeBucketStatsResponse, GetTimeBucketStatsResponses, GetTodayStatsData, GetTodayStatsError, GetTodayStatsErrors, GetTodayStatsResponse, GetTodayStatsResponses, GetTraceData, GetTraceError, GetTraceErrors, GetTraceResponse, GetTraceResponses, GetUnifiedTraceData, GetUnifiedTraceError, GetUnifiedTraceErrors, GetUnifiedTraceResponse, GetUnifiedTraceResponses, GetUniqueCountsData, GetUniqueCountsErrors, GetUniqueCountsResponse, GetUniqueCountsResponses, GetUniqueEventsData, GetUniqueEventsErrors, GetUniqueEventsQuery, GetUniqueEventsResponse, GetUniqueEventsResponses, GetUpdateCapabilityData, GetUpdateCapabilityErrors, GetUpdateCapabilityResponse, GetUpdateCapabilityResponses, GetUpdateStatusData, GetUpdateStatusErrors, GetUpdateStatusResponse, GetUpdateStatusResponses, GetUptimeHistoryData, GetUptimeHistoryErrors, GetUptimeHistoryResponse, GetUptimeHistoryResponses, GetUsageByProviderData, GetUsageByProviderError, GetUsageByProviderErrors, GetUsageByProviderResponse, GetUsageByProviderResponses, GetUsageRecentData, GetUsageRecentError, GetUsageRecentErrors, GetUsageRecentResponse, GetUsageRecentResponses, GetUsageSummaryData, GetUsageSummaryError, GetUsageSummaryErrors, GetUsageSummaryResponse, GetUsageSummaryResponses, GetUsageTimeseriesData, GetUsageTimeseriesError, GetUsageTimeseriesErrors, GetUsageTimeseriesResponse, GetUsageTimeseriesResponses, GetUsageTopModelsData, GetUsageTopModelsError, GetUsageTopModelsErrors, GetUsageTopModelsResponse, GetUsageTopModelsResponses, GetVisitorByGuidData, GetVisitorByGuidErrors, GetVisitorByGuidResponse, GetVisitorByGuidResponses, GetVisitorByIdData, GetVisitorByIdErrors, GetVisitorByIdResponse, GetVisitorByIdResponses, GetVisitorDetailsData, GetVisitorDetailsErrors, GetVisitorDetailsResponse, GetVisitorDetailsResponses, GetVisitorFacetsData, GetVisitorFacetsErrors, GetVisitorFacetsResponse, GetVisitorFacetsResponses, GetVisitorInfoData, GetVisitorInfoErrors, GetVisitorInfoResponse, GetVisitorInfoResponses, GetVisitorJourneyData, GetVisitorJourneyErrors, GetVisitorJourneyResponse, GetVisitorJourneyResponses, GetVisitorsData, GetVisitorsErrors, GetVisitorSessionsData, GetVisitorSessionsError, GetVisitorSessionsErrors, GetVisitorSessionsQuery, GetVisitorSessionsResponse, GetVisitorSessionsResponse2, GetVisitorSessionsResponses, GetVisitorsResponse, GetVisitorsResponses, GetVisitorStatsData, GetVisitorStatsErrors, GetVisitorStatsResponse, GetVisitorStatsResponses, GetWebhookData, GetWebhookErrors, GetWebhookResponse, GetWebhookResponses, GitPushEvent, GitRefResponse, GitSourcePlan, GlobalConversationResponse, GlobalEventStatsResponse, GlobalMrrResponse, GlobalRecentEventResponse, GlobalRevenueSummaryResponse, GrantProjectAccessData, GrantProjectAccessErrors, GrantProjectAccessResponse, GrantProjectAccessResponses, GroupedPageMetric, GroupedPageMetricsQuery, GroupedPageMetricsResponse, HandleGitProviderOauthCallbackData, HandleGitProviderOauthCallbackErrors, HasAnalyticsEventsData, HasAnalyticsEventsErrors, HasAnalyticsEventsResponse, HasAnalyticsEventsResponse2, HasAnalyticsEventsResponses, HasErrorGroupsData, HasErrorGroupsErrors, HasErrorGroupsResponse, HasErrorGroupsResponse2, HasErrorGroupsResponses, HasEventsQuery, HasEventsResponse, HasMetricsQuery, HasMetricsResponse, HasPerformanceMetricsData, HasPerformanceMetricsError, HasPerformanceMetricsErrors, HasPerformanceMetricsResponse, HasPerformanceMetricsResponses, HealthCheckConfiguration, HealthCheckEntryResponse, HealthResponse, HealthStatus, HealthSummary, HeartbeatApiRequest, HeartbeatResponse, HierarchyLevel, HistogramSummary, HostnameChange, HostnamePreviewResponse, HourlyPageSessions, HourlyVisitsQuery, HttpChallengeDebugResponse, ImportCredentials, ImportExecutionStatus, ImportExternalServiceData, ImportExternalServiceErrors, ImportExternalServiceRequest, ImportExternalServiceResponse, ImportExternalServiceResponses, ImportOutcomeResponse, ImportPlan, ImportRowErrorResponse, ImportSelector, ImportSource, ImportSourceCapabilities, ImportSourceInfo, ImportStatusResponse, IncidentBucket, IncidentBucketedResponse, IncidentResponse, IncidentUpdateResponse, IncrRequest, IncrResponse, IngestLogsByPathData, IngestLogsByPathError, IngestLogsByPathErrors, IngestLogsByPathResponses, IngestLogsData, IngestLogsError, IngestLogsErrors, IngestLogsResponses, IngestMetricsByPathData, IngestMetricsByPathError, IngestMetricsByPathErrors, IngestMetricsByPathResponses, IngestMetricsData, IngestMetricsError, IngestMetricsErrors, IngestMetricsResponses, IngestSentryEnvelopeData, IngestSentryEnvelopeErrors, IngestSentryEnvelopeResponses, IngestSentryEventData, IngestSentryEventErrors, IngestSentryEventResponse, IngestSentryEventResponses, IngestTracesByPathData, IngestTracesByPathError, IngestTracesByPathErrors, IngestTracesByPathResponses, IngestTracesData, IngestTracesError, IngestTracesErrors, IngestTracesResponses, InitAuthResponse, InitSessionReplayData, InitSessionReplayError, InitSessionReplayErrors, InitSessionReplayResponse, InitSessionReplayResponses, Insight, InsightSeverity, InsightsResponse, InsightStatus, InspectDropArchiveData, InspectDropArchiveErrors, InspectDropArchiveResponse, InspectDropArchiveResponses, IntegrationResponse, IpAccessControlQuery, IpAccessControlResponse, JobLogsData, JobLogsErrors, JobLogsResponses, JobStatusData, JobStatusErrors, JobStatusResponse, JobStatusResponse2, JobStatusResponses, JobSummaryResponse, JoinTokenStatusResponse, JourneyEvent, JourneySession, KeysRequest, KeysResponse, KillJobBody, KillJobData, KillJobErrors, KillJobResponse, KillJobResponses, KnownAiAgentsResponse, KvDelData, KvDelErrors, KvDelResponse, KvDelResponses, KvDisableData, KvDisableErrors, KvDisableResponse, KvDisableResponses, KvEnableData, KvEnableErrors, KvEnableResponse, KvEnableResponses, KvExpireData, KvExpireErrors, KvExpireResponse, KvExpireResponses, KvGetData, KvGetErrors, KvGetResponse, KvGetResponses, KvIncrData, KvIncrErrors, KvIncrResponse, KvIncrResponses, KvKeysData, KvKeysErrors, KvKeysResponse, KvKeysResponses, KvSetData, KvSetErrors, KvSetResponse, KvSetResponses, KvStatusData, KvStatusErrors, KvStatusResponse, KvStatusResponse2, KvStatusResponses, KvTtlData, KvTtlErrors, KvTtlResponse, KvTtlResponses, KvUpdateData, KvUpdateErrors, KvUpdateResponse, KvUpdateResponses, LatestRunForSourceData, LatestRunForSourceErrors, LatestRunForSourceResponse, LatestRunForSourceResponses, LemonSqueezyConfig, LetsEncryptSettings, LineContext, LinkCustomDomainToCertificateData, LinkCustomDomainToCertificateErrors, LinkCustomDomainToCertificateResponse, LinkCustomDomainToCertificateResponses, LinkServiceRequest, LinkServiceToProjectData, LinkServiceToProjectErrors, LinkServiceToProjectResponse, LinkServiceToProjectResponses, ListAgentRunsData, ListAgentRunsErrors, ListAgentRunsResponse, ListAgentRunsResponses, ListAgentsData, ListAgentsErrors, ListAgentsResponse, ListAgentsResponse2, ListAgentsResponses, ListAiProvidersData, ListAiProvidersErrors, ListAiProvidersResponse, ListAiProvidersResponses, ListAlertRulesData, ListAlertRulesErrors, ListAlertRulesResponse, ListAlertRulesResponses, ListAlertsData, ListAlertsError, ListAlertsErrors, ListAlertsResponse, ListAlertsResponses, ListAllConversationsData, ListAllConversationsErrors, ListAllConversationsResponse, ListAllConversationsResponses, ListAllRunsData, ListAllRunsErrors, ListAllRunsResponse, ListAllRunsResponses, ListApiKeysData, ListApiKeysErrors, ListApiKeysQuery, ListApiKeysResponse, ListApiKeysResponses, ListAuditLogsData, ListAuditLogsErrors, ListAuditLogsQuery, ListAuditLogsResponse, ListAuditLogsResponses, ListAvailableContainersData, ListAvailableContainersErrors, ListAvailableContainersResponse, ListAvailableContainersResponses, ListBackupAlertsData, ListBackupAlertsError, ListBackupAlertsErrors, ListBackupAlertsResponse, ListBackupAlertsResponses, ListBackupChildrenData, ListBackupChildrenError, ListBackupChildrenErrors, ListBackupChildrenResponse, ListBackupChildrenResponses, ListBackupSchedulesData, ListBackupSchedulesError, ListBackupSchedulesErrors, ListBackupSchedulesResponse, ListBackupSchedulesResponses, ListBackupsForScheduleData, ListBackupsForScheduleErrors, ListBackupsForScheduleResponse, ListBackupsForScheduleResponses, ListBlobsQuery, ListBlobsResponse, ListCommitsByRepositoryIdData, ListCommitsByRepositoryIdErrors, ListCommitsByRepositoryIdResponse, ListCommitsByRepositoryIdResponses, ListConnectionsData, ListConnectionsErrors, ListConnectionsResponse, ListConnectionsResponses, ListContainersAtPathData, ListContainersAtPathErrors, ListContainersAtPathResponse, ListContainersAtPathResponses, ListContainersData, ListContainersErrors, ListContainersResponse, ListContainersResponses, ListConversationsData, ListConversationsErrors, ListConversationsResponse, ListConversationsResponses, ListCustomDomainsForProjectData, ListCustomDomainsForProjectErrors, ListCustomDomainsForProjectResponse, ListCustomDomainsForProjectResponses, ListCustomDomainsResponse, ListDashboardsData, ListDashboardsError, ListDashboardsErrors, ListDashboardsResponse, ListDashboardsResponses, ListDeliveriesData, ListDeliveriesErrors, ListDeliveriesResponse, ListDeliveriesResponses, ListDeploymentContainerLogsData, ListDeploymentContainerLogsErrors, ListDeploymentContainerLogsResponse, ListDeploymentContainerLogsResponses, ListDeploymentTokensData, ListDeploymentTokensErrors, ListDeploymentTokensQuery, ListDeploymentTokensResponse, ListDeploymentTokensResponses, ListDnsProvidersData, ListDnsProvidersErrors, ListDnsProvidersResponse, ListDnsProvidersResponses, ListDomainsData, ListDomainsErrors, ListDomainsResponse, ListDomainsResponse2, ListDomainsResponses, ListDsnsData, ListDsnsErrors, ListDsnsResponse, ListDsnsResponses, ListEmailDomainsData, ListEmailDomainsErrors, ListEmailDomainsResponse, ListEmailDomainsResponses, ListEmailProvidersData, ListEmailProvidersErrors, ListEmailProvidersResponse, ListEmailProvidersResponses, ListEmailsData, ListEmailsErrors, ListEmailsResponse, ListEmailsResponses, ListEnrollmentTokensData, ListEnrollmentTokensErrors, ListEnrollmentTokensResponse, ListEnrollmentTokensResponses, ListEntitiesData, ListEntitiesErrors, ListEntitiesQuery, ListEntitiesResponse, ListEntitiesResponses, ListErrorEventsData, ListErrorEventsErrors, ListErrorEventsQuery, ListErrorEventsResponse, ListErrorEventsResponses, ListErrorGroupsData, ListErrorGroupsErrors, ListErrorGroupsQuery, ListErrorGroupsResponse, ListErrorGroupsResponses, ListEventsData, ListEventsResponse, ListEventsResponses, ListEventTypesData, ListEventTypesResponse, ListEventTypesResponses, ListExternalImagesData, ListExternalImagesErrors, ListExternalImagesResponse, ListExternalImagesResponses, ListExternalPluginsData, ListExternalPluginsErrors, ListExternalPluginsResponse, ListExternalPluginsResponses, ListExternalServiceBackupsData, ListExternalServiceBackupsError, ListExternalServiceBackupsErrors, ListExternalServiceBackupsResponse, ListExternalServiceBackupsResponses, ListFlagsData, ListFlagsErrors, ListFlagsResponse, ListFlagsResponses, ListFunnelsData, ListFunnelsErrors, ListFunnelsResponse, ListFunnelsResponses, ListGitProvidersData, ListGitProvidersErrors, ListGitProvidersResponse, ListGitProvidersResponses, ListGlobalMcpsData, ListGlobalMcpsErrors, ListGlobalMcpsResponse, ListGlobalMcpsResponses, ListGlobalSkillsData, ListGlobalSkillsErrors, ListGlobalSkillsResponse, ListGlobalSkillsResponses, ListIncidentsData, ListIncidentsErrors, ListIncidentsResponses, ListInsightsData, ListInsightsError, ListInsightsErrors, ListInsightsResponse, ListInsightsResponses, ListIpAccessControlData, ListIpAccessControlError, ListIpAccessControlErrors, ListIpAccessControlResponse, ListIpAccessControlResponses, ListJobsData, ListJobsErrors, ListJobsResponse, ListJobsResponse2, ListJobsResponses, ListKnownAiAgentsData, ListKnownAiAgentsError, ListKnownAiAgentsErrors, ListKnownAiAgentsResponse, ListKnownAiAgentsResponses, ListManagedDomainsData, ListManagedDomainsErrors, ListManagedDomainsResponse, ListManagedDomainsResponses, ListMcpsData, ListMcpsErrors, ListMcpsResponse, ListMcpsResponse2, ListMcpsResponses, ListMetricLabelKeysData, ListMetricLabelKeysError, ListMetricLabelKeysErrors, ListMetricLabelKeysResponse, ListMetricLabelKeysResponses, ListMetricLabelValuesData, ListMetricLabelValuesError, ListMetricLabelValuesErrors, ListMetricLabelValuesResponse, ListMetricLabelValuesResponses, ListMetricNamesData, ListMetricNamesError, ListMetricNamesErrors, ListMetricNamesResponse, ListMetricNamesResponses, ListModelsData, ListModelsError, ListModelsErrors, ListModelsResponse, ListModelsResponses, ListMonitorsData, ListMonitorsErrors, ListMonitorsResponse, ListMonitorsResponses, ListNotificationProvidersData, ListNotificationProvidersErrors, ListNotificationProvidersResponse, ListNotificationProvidersResponses, ListOidcProvidersData, ListOidcProvidersResponse, ListOidcProvidersResponses, ListOidcProviderUsersData, ListOidcProviderUsersErrors, ListOidcProviderUsersResponse, ListOidcProviderUsersResponses, ListOidcRoleMappingsData, ListOidcRoleMappingsResponse, ListOidcRoleMappingsResponses, ListOnDemandCertsData, ListOnDemandCertsErrors, ListOnDemandCertsResponse, ListOnDemandCertsResponse2, ListOnDemandCertsResponses, ListOrdersData, ListOrdersErrors, ListOrdersResponse, ListOrdersResponse2, ListOrdersResponses, ListPeersData, ListPeersErrors, ListPeersResponse, ListPeersResponses, ListPendingActionsData, ListPendingActionsErrors, ListPendingActionsResponse, ListPendingActionsResponses, ListPgUpgradesData, ListPgUpgradesErrors, ListPgUpgradesResponse, ListPgUpgradesResponses, ListPresetsData, ListPresetsErrors, ListPresetsResponse, ListPresetsResponse2, ListPresetsResponses, ListProjectAccessData, ListProjectAccessErrors, ListProjectAccessResponse, ListProjectAccessResponses, ListProjectAlarmsData, ListProjectAlarmsErrors, ListProjectAlarmsResponse, ListProjectAlarmsResponses, ListProjectScansData, ListProjectScansError, ListProjectScansErrors, ListProjectScansResponse, ListProjectScansResponses, ListProjectSecretsData, ListProjectSecretsErrors, ListProjectSecretsResponse, ListProjectSecretsResponses, ListProjectServicesData, ListProjectServicesErrors, ListProjectServicesResponse, ListProjectServicesResponses, ListProjectTemplatesData, ListProjectTemplatesErrors, ListProjectTemplatesResponse, ListProjectTemplatesResponses, ListProjectTemplateTagsData, ListProjectTemplateTagsErrors, ListProjectTemplateTagsResponse, ListProjectTemplateTagsResponses, ListProviderKeysData, ListProviderKeysError, ListProviderKeysErrors, ListProviderKeysResponse, ListProviderKeysResponses, ListProviderZonesData, ListProviderZonesErrors, ListProviderZonesResponse, ListProviderZonesResponses, ListPublicProvidersData, ListPublicProvidersResponse, ListPublicProvidersResponses, ListReleaseFilesData, ListReleaseFilesErrors, ListReleaseFilesResponse, ListReleaseFilesResponses, ListReleasesData, ListReleasesErrors, ListReleasesResponse, ListReleasesResponses, ListRemoteExternalImagesData, ListRemoteExternalImagesErrors, ListRemoteExternalImagesResponse, ListRemoteExternalImagesResponses, ListRepositoriesByConnectionData, ListRepositoriesByConnectionErrors, ListRepositoriesByConnectionResponse, ListRepositoriesByConnectionResponses, ListRepositoriesByProviderData, ListRepositoriesByProviderErrors, ListRepositoriesByProviderResponse, ListRepositoriesByProviderResponses, ListRestoreRunsForServiceData, ListRestoreRunsForServiceResponse, ListRestoreRunsForServiceResponses, ListRootContainersData, ListRootContainersErrors, ListRootContainersResponse, ListRootContainersResponses, ListRoutesData, ListRoutesErrors, ListRoutesResponse, ListRoutesResponses, ListRunsResponse, ListS3SourcesData, ListS3SourcesError, ListS3SourcesErrors, ListS3SourcesResponse, ListS3SourcesResponses, ListSandboxesData, ListSandboxesResponse, ListSandboxesResponse2, ListSandboxesResponses, ListScansQuery, ListScheduleRunJobsData, ListScheduleRunJobsError, ListScheduleRunJobsErrors, ListScheduleRunJobsResponse, ListScheduleRunJobsResponses, ListScheduleRunsData, ListScheduleRunsError, ListScheduleRunsErrors, ListScheduleRunsResponse, ListScheduleRunsResponses, ListScheduleServicesData, ListScheduleServicesError, ListScheduleServicesErrors, ListScheduleServicesResponse, ListScheduleServicesResponses, ListSecretsData, ListSecretsErrors, ListSecretsResponse, ListSecretsResponse2, ListSecretsResponses, ListServiceHealthStatusesData, ListServiceHealthStatusesErrors, ListServiceHealthStatusesResponse, ListServiceHealthStatusesResponses, ListServiceProjectsData, ListServiceProjectsErrors, ListServiceProjectsResponse, ListServiceProjectsResponses, ListServiceSchedulesData, ListServiceSchedulesError, ListServiceSchedulesErrors, ListServiceSchedulesResponse, ListServiceSchedulesResponses, ListServicesData, ListServicesErrors, ListServicesResponse, ListServicesResponses, ListSkillsData, ListSkillsErrors, ListSkillsResponse, ListSkillsResponse2, ListSkillsResponses, ListSourceBackupsData, ListSourceBackupsError, ListSourceBackupsErrors, ListSourceBackupsResponse, ListSourceBackupsResponses, ListSourceFilesData, ListSourceFilesErrors, ListSourceFilesResponse, ListSourceFilesResponses, ListSourceMapsData, ListSourceMapsErrors, ListSourceMapsResponse, ListSourceMapsResponses, ListSourcesData, ListSourcesErrors, ListSourcesResponse, ListSourcesResponses, ListStaticBundlesData, ListStaticBundlesErrors, ListStaticBundlesResponse, ListStaticBundlesResponses, ListSyncedRepositoriesData, ListSyncedRepositoriesErrors, ListSyncedRepositoriesResponse, ListSyncedRepositoriesResponses, ListTagsResponse, ListTeamMembersData, ListTeamMembersErrors, ListTeamMembersResponse, ListTeamMembersResponses, ListTeamProjectsData, ListTeamProjectsErrors, ListTeamProjectsResponse, ListTeamProjectsResponses, ListTeamsData, ListTeamsErrors, ListTeamsResponse, ListTeamsResponses, ListTemplatesQuery, ListTemplatesResponse, ListUsersData, ListUsersErrors, ListUsersResponse, ListUsersResponses, ListVulnerabilitiesQuery, ListWebhooksData, ListWebhooksErrors, ListWebhooksResponse, ListWebhooksResponses, LiveVisitorInfo, LiveVisitorsListResponse, LocationCount, LocationGranularity, LocationInfo, LoginData, LoginErrors, LoginRequest, LoginResponse, LoginResponses, LogLevel, LogoutData, LogoutErrors, LogoutResponses, LogRecord, LogSearchLine, LogSeverity, LogSource, LogsQuery, LogsResponse, LogStream, LookupDnsARecordsData, LookupDnsARecordsError, LookupDnsARecordsErrors, LookupDnsARecordsResponse, LookupDnsARecordsResponses, ManagedDomainResponse, ManualAction, ManualActionTiming, McpDefinitionResponse, MessageContent, MessagePart, MessageResponse, MeteredMode, MetricAggregation, MetricBucket, MetricDataPoint, MetricsOverTimeResponse, MetricsQuery, MetricsRangeQuery, MetricsStatusResponse, MetricsStoreKind, MetricsSummaryResponse, MetricType, MfaRequiredResponse, MfaSetupResponse, MfaVerificationRequest, MigrationStep, MigrationSummary, MintEnrollmentTokenData, MintEnrollmentTokenErrors, MintEnrollmentTokenRequest, MintEnrollmentTokenResponse, MintEnrollmentTokenResponse2, MintEnrollmentTokenResponses, MiscResult, MkdirBody, MkdirData, MkdirErrors, MkdirResponse, MkdirResponses, ModelInfo, ModelListResponse, ModelPricing, ModelUsage, MonitoringSettings, MonitoringSettingsMasked, MonitorResponse, MonitorStatus, MrrBucketResponse, MultiNodeSettings, MultiNodeSettingsMasked, MxResult, NavEntry, NavSection, NetworkConfiguration, NetworkMode, NixpacksPresetConfig, NixpacksProvider, NodeContainerListResponse, NodeContainerResponse, NodeCostInfo, NodeHeartbeatData, NodeHeartbeatErrors, NodeHeartbeatResponse, NodeHeartbeatResponses, NodeInfoResponse, NodeListResponse, NodeMetricsGetRangeData, NodeMetricsGetRangeErrors, NodeMetricsGetRangeResponse, NodeMetricsGetRangeResponses, NotificationPreferencesResponse, NotificationProviderResponse, ObservabilityCompressionSettings, ObservabilityEvent, ObservabilityFullEventData, ObservabilityFullEventError, ObservabilityFullEventErrors, ObservabilityFullEventResponse, ObservabilityFullEventResponses, ObservabilityListEventsData, ObservabilityListEventsError, ObservabilityListEventsErrors, ObservabilityListEventsResponse, ObservabilityListEventsResponses, ObservabilityRetentionSettings, OidcCallbackData, OidcProviderResponse, OidcProvidersListResponse, OidcProviderSummary, OidcProviderUserResponse, OidcRoleMappingResponse, OidcTestConnectionResponse, OnDemandCertAttemptResponse, OnDemandCertRow, OnDemandTlsSettings, OpenAiError, OpenAiErrorResponse, OperatingSystemCount, OperationResultResponse, OperationResultsResponse, OtelDashboardResponse, OtelDashboardsResponse, OtelMetricAlertRuleResponse, OtelMetricAlertsResponse, OtelMetricLabelKeysResponse, OtelMetricLabelValuesResponse, OtelMetricNamesResponse, OtelMetricsResponse, OutlierAlgorithm, OutlierParams, OverprovisioningAssessment, OverprovisioningVerdict, PageActivityBucket, PageCountryStats, PageFlowEntry, PageFlowQuery, PageFlowResponse, PageHourlySessionsQuery, PageHourlySessionsResponse, PagePathDetailQuery, PagePathDetailResponse, PagePathInfo, PagePathSparkline, PagePathSparklinePoint, PagePathsQuery, PagePathsResponse, PagePathsSparklineQuery, PagePathsSparklineResponse, PagePathVisitorsQuery, PagePathVisitorsResponse, PageReferrerStats, PagesComparisonResponse, PageSessionComparison, PageSessionStats, PageSessionStatsQuery, PageTransition, PageVisit, PageVisitorSession, PaginatedEmailsResponse, PaginatedEntitiesResponse, PaginatedErrorEventsResponse, PaginatedErrorGroupsResponse, PaginatedEventsResponse, PaginatedExternalImagesResponse, PaginatedProjectList, PaginatedStaticBundlesResponse, Pagination, PaginationMeta, PaginationParams, PasswordProtectionConfig, PatchAdminGateData, PatchAdminGateErrors, PatchAdminGateResponse, PatchAdminGateResponses, PatchPreviewGatewaySettingsData, PatchPreviewGatewaySettingsResponse, PatchPreviewGatewaySettingsResponses, PatchSettingsRequest, PathVisitors, PathVisitorsAnalyticsQuery, PathVisitorsResponse, PauseDeploymentData, PauseDeploymentErrors, PauseDeploymentResponse, PauseDeploymentResponses, PauseSandboxData, PauseSandboxErrors, PauseSandboxResponse, PauseSandboxResponses, PeerEntry, PeerListResponse, PendingActionResponse, PerformanceMetricsQuery, PerformanceMetricsResponse, PermissionInfo, PgUpgradeLogResponse, PgUpgradeResponse, PipelineStats, PipelineStatsResponse, PlanComplexity, PlanMetadata, PlanRestoreData, PlanRestoreError, PlanRestoreErrors, PlanRestoreResponse, PlanRestoreResponses, PlanSourceBackup, PlanTarget, PlatformInfo, PluginManifest, PortMapping, PostDnsAckData, PostDnsAckErrors, PostDnsAckResponse, PostDnsAckResponses, PostgresWalHealth, PresetConfigSchema, PresetInfo, PresetResponse, PreviewAlertData, PreviewAlertError, PreviewAlertErrors, PreviewAlertResponse, PreviewAlertResponses, PreviewFunnelMetricsData, PreviewFunnelMetricsErrors, PreviewFunnelMetricsResponse, PreviewFunnelMetricsResponses, PreviewGatewaySettings, PreviewGatewaySettingsMasked, PreviewGatewaySettingsResponse, PreviewHostnameModeData, PreviewHostnameModeErrors, PreviewHostnameModeResponse, PreviewHostnameModeResponses, PreviewShareLinkBody, PreviewShareLinkResponse, PricingResponse, ProblemDetails, ProjectAccessResponse, ProjectConfiguration, ProjectDashboardAnalytics, ProjectDsnResponse, ProjectHealthSummary, ProjectInfo, ProjectMonitorHealth, ProjectPresetResponse, ProjectQuery, ProjectRef, ProjectResponse, ProjectSecretEnvironmentInfo, ProjectSecretResponse, ProjectServiceInfo, ProjectsHealthResponse, ProjectsMonitorHealthResponse, ProjectStatisticsResponse, ProjectStatsBreakdown, ProjectType, ProjectUsageInfoResponse, PromoteClusterMemberData, PromoteClusterMemberErrors, PromoteClusterMemberResponses, PromoteDeploymentData, PromoteDeploymentErrors, PromoteDeploymentRequest, PromoteDeploymentResponse, PromoteDeploymentResponses, PropertyBreakdownItem, PropertyBreakdownQuery, PropertyBreakdownResponse, PropertyColumn, PropertyTimelineItem, PropertyTimelineQuery, PropertyTimelineResponse, Protocol, ProviderCatalogDto, ProviderCatalogResponse, ProviderConfig, ProviderConfigMasked, ProviderDeletionCheckResponse, ProviderDescriptor, ProviderKeyResponse, ProviderMetadata, ProviderResponse, ProviderUsage, ProvisionDomainData, ProvisionDomainErrors, ProvisionDomainResponse, ProvisionDomainResponses, ProvisionResponse, ProxyLogResponse, ProxyLogsPaginatedResponse, PublicHostnameStrategy, PublicPresetResponse, PublicRepositoryInfo, PurgeLogsRequest, PurgeProjectLogsData, PurgeProjectLogsError, PurgeProjectLogsErrors, PurgeProjectLogsResponses, PushedExternalImageResponse, PushExternalImageData, PushExternalImageErrors, PushExternalImageResponse, PushExternalImageResponses, PushImageRequest, QueryDataData, QueryDataErrors, QueryDataRequest, QueryDataResponse, QueryDataResponse2, QueryDataResponses, QueryGenaiTracesData, QueryGenaiTracesError, QueryGenaiTracesErrors, QueryGenaiTracesResponse, QueryGenaiTracesResponses, QueryLogsData, QueryLogsError, QueryLogsErrors, QueryLogsResponse, QueryLogsResponses, QueryMetricsData, QueryMetricsError, QueryMetricsErrors, QueryMetricsResponse, QueryMetricsResponses, QueryTracesData, QueryTracesError, QueryTracesErrors, QueryTracesResponse, QueryTracesResponses, QueryTraceSummariesData, QueryTraceSummariesError, QueryTraceSummariesErrors, QueryTraceSummariesResponse, QueryTraceSummariesResponses, QuotaResponse, RateLimitConfig, RateLimitSettings, ReachabilityStatus, ReadFileData, ReadFileErrors, ReadFileResponse, ReadFileResponse2, ReadFileResponses, ReAnalyzeData, ReAnalyzeErrors, ReAnalyzeResponses, RebuildSandboxImageData, RebuildSandboxImageErrors, RebuildSandboxImageResponses, RecentActivityQuery, RecentActivityResponse, RecentEventResponse, RecentQueryParams, RecordConsoleEventData, RecordConsoleEventErrors, RecordConsoleEventResponses, RecordEventMetricsData, RecordEventMetricsErrors, RecordEventMetricsResponse, RecordEventMetricsResponses, RecordExposureRequest, RecordExposureResponse, RecordFlagExposureData, RecordFlagExposureErrors, RecordFlagExposureResponse, RecordFlagExposureResponses, RecordListResponse, RecordSpeedMetricsData, RecordSpeedMetricsError, RecordSpeedMetricsErrors, RecordSpeedMetricsResponse, RecordSpeedMetricsResponses, RecoveryTarget, ReferrerCount, ReferrersAnalyticsQuery, RefreshRouteTableData, RefreshRouteTableErrors, RefreshRouteTableResponse, RefreshRouteTableResponses, RegenerateDsnData, RegenerateDsnErrors, RegenerateDsnRequest, RegenerateDsnResponse, RegenerateDsnResponses, RegisterExternalImageData, RegisterExternalImageErrors, RegisterExternalImageResponse, RegisterExternalImageResponses, RegisterImageRequest, RegisterNodeApiRequest, RegisterNodeData, RegisterNodeErrors, RegisterNodeResponse, RegisterNodeResponse2, RegisterNodeResponses, RegisterRequest, ReinstallGitlabWebhookData, ReinstallGitlabWebhookErrors, ReinstallGitlabWebhookResponse, ReinstallGitlabWebhookResponses, ReinstallWebhookResponse, RejectPendingActionData, RejectPendingActionErrors, RejectPendingActionResponse, RejectPendingActionResponses, ReleaseListResponse, ReloadPluginsData, ReloadPluginsErrors, ReloadPluginsResponse, ReloadPluginsResponses, ReloadResponse, RemoteDeploymentResponse, RemoveClusterMemberData, RemoveClusterMemberErrors, RemoveClusterMemberResponse, RemoveClusterMemberResponses, RemoveManagedDomainData, RemoveManagedDomainErrors, RemoveManagedDomainResponse, RemoveManagedDomainResponses, RemoveNodeResponse, RemoveRoleData, RemoveRoleErrors, RemoveRoleResponse, RemoveRoleResponses, RemoveTeamMemberData, RemoveTeamMemberErrors, RemoveTeamMemberResponse, RemoveTeamMemberResponses, RenameConversationData, RenameConversationErrors, RenameConversationRequest, RenameConversationResponse, RenameConversationResponses, RenewDomainData, RenewDomainErrors, RenewDomainResponse, RenewDomainResponses, RepositoryListQuery, RepositoryListResponse, RepositoryPresetResponse, RepositoryResponse, RepositorySyncStartedResponse, RequestPasswordResetData, RequestPasswordResetErrors, RequestPasswordResetResponse, RequestPasswordResetResponses, RequestRow, RequiredPasswordChangeRequest, RequiredPasswordChangeResponse, ResetPasswordData, ResetPasswordErrors, ResetPasswordRequest, ResetPasswordResponse, ResetPasswordResponses, ResetPgStatStatementsRequest, ResetPgStatStatementsResponse, ResizeSandboxBody, ResizeSandboxData, ResizeSandboxErrors, ResizeSandboxResponse, ResizeSandboxResponses, ResolveAlarmData, ResolveAlarmErrors, ResolveAlarmResponses, ResolvedEnvVarResponse, ResolvedEnvVarSource, ResourceCounts, ResourceFootprint, ResourceInfo, ResourceLimitApplyResult, ResourceLimits, ResourceLimitsResponse, ResourceLimitsUpdateResponse, ResourcesBody, RestartContainerData, RestartContainerErrors, RestartContainerResponse, RestartContainerResponses, RestartPreviewGatewayData, RestartPreviewGatewayResponse, RestartPreviewGatewayResponses, RestartSandboxData, RestartSandboxErrors, RestartSandboxResponse, RestartSandboxResponses, RestoreCapabilities, RestoreCapabilitiesResponse, RestoreFlagData, RestoreFlagErrors, RestoreFlagResponse, RestoreFlagResponses, RestorePlan, RestoreRequestMode, RestoreRunView, RestoreUserData, RestoreUserErrors, RestoreUserResponse, RestoreUserResponses, ResumeDeploymentData, ResumeDeploymentErrors, ResumeDeploymentResponse, ResumeDeploymentResponses, ResumeSandboxData, ResumeSandboxErrors, ResumeSandboxResponse, ResumeSandboxResponses, RetentionCleanupFailure, RetentionCleanupReport, RetryClusterData, RetryClusterErrors, RetryClusterRequest, RetryClusterResponse, RetryClusterResponses, RetryDeliveryData, RetryDeliveryErrors, RetryDeliveryResponse, RetryDeliveryResponses, RetryPgUpgradeData, RetryPgUpgradeErrors, RetryPgUpgradeResponse, RetryPgUpgradeResponses, RetryRunData, RetryRunErrors, RetryRunResponse, RetryRunResponses, RevealGlobalMcpConfigData, RevealGlobalMcpConfigErrors, RevealGlobalMcpConfigResponse, RevealGlobalMcpConfigResponses, RevealMcpConfigData, RevealMcpConfigErrors, RevealMcpConfigResponse, RevealMcpConfigResponses, RevealNotificationProviderConfigData, RevealNotificationProviderConfigErrors, RevealNotificationProviderConfigResponse, RevealNotificationProviderConfigResponses, RevealServiceParameterData, RevealServiceParameterErrors, RevealServiceParameterResponse, RevealServiceParameterResponses, RevenueCreateIntegrationData, RevenueCreateIntegrationErrors, RevenueCreateIntegrationResponse, RevenueCreateIntegrationResponses, RevenueDeleteIntegrationData, RevenueDeleteIntegrationResponse, RevenueDeleteIntegrationResponses, RevenueGlobalEventsData, RevenueGlobalEventsResponse, RevenueGlobalEventsResponses, RevenueImportInvoicesCsvData, RevenueImportInvoicesCsvErrors, RevenueImportInvoicesCsvResponse, RevenueImportInvoicesCsvResponses, RevenueImportSubscriptionsCsvData, RevenueImportSubscriptionsCsvErrors, RevenueImportSubscriptionsCsvResponse, RevenueImportSubscriptionsCsvResponses, RevenueListIntegrationsData, RevenueListIntegrationsResponse, RevenueListIntegrationsResponses, RevenueListProvidersData, RevenueListProvidersResponse, RevenueListProvidersResponses, RevenueMetricsCustomersData, RevenueMetricsCustomersResponse, RevenueMetricsCustomersResponses, RevenueMetricsGlobalMrrData, RevenueMetricsGlobalMrrResponse, RevenueMetricsGlobalMrrResponses, RevenueMetricsGlobalSummaryData, RevenueMetricsGlobalSummaryResponse, RevenueMetricsGlobalSummaryResponses, RevenueMetricsMrrData, RevenueMetricsMrrResponse, RevenueMetricsMrrResponses, RevenueMetricsSummaryData, RevenueMetricsSummaryResponse, RevenueMetricsSummaryResponses, RevenueRecentEventsData, RevenueRecentEventsResponse, RevenueRecentEventsResponses, RevenueRotateTokenData, RevenueRotateTokenResponse, RevenueRotateTokenResponses, RevenueRow, RevenueUpdateConfigData, RevenueUpdateConfigErrors, RevenueUpdateConfigResponse, RevenueUpdateConfigResponses, RevenueUpdateSecretData, RevenueUpdateSecretErrors, RevenueUpdateSecretResponse, RevenueUpdateSecretResponses, RevokeDsnData, RevokeDsnErrors, RevokeDsnResponse, RevokeDsnResponses, RevokeEnrollmentTokenData, RevokeEnrollmentTokenErrors, RevokeEnrollmentTokenResponse, RevokeEnrollmentTokenResponses, RevokeJoinTokenData, RevokeJoinTokenErrors, RevokeJoinTokenResponse, RevokeJoinTokenResponses, RevokeProjectAccessData, RevokeProjectAccessErrors, RevokeProjectAccessResponse, RevokeProjectAccessResponses, RiskLevel, RoleInfo, RollbackPgUpgradeData, RollbackPgUpgradeErrors, RollbackPgUpgradeResponse, RollbackPgUpgradeResponses, RollbackToDeploymentData, RollbackToDeploymentErrors, RollbackToDeploymentResponse, RollbackToDeploymentResponses, RootfsCacheEntry, RootfsGcData, RootfsGcReport, RootfsGcResponses, RootfsReport, RootfsReportData, RootfsReportResponses, RootfsVmEntry, RotateApiKeyData, RotateApiKeyErrors, RotateApiKeyResponse, RotateApiKeyResponses, RotateDeploymentTokenData, RotateDeploymentTokenErrors, RotateDeploymentTokenResponse, RotateDeploymentTokenResponses, RouteRefreshResponse, RouteResponse, RouteRole, RouteUser, RouteUserWithRoles, RunBackupForSourceData, RunBackupForSourceError, RunBackupForSourceErrors, RunBackupForSourceResponse, RunBackupForSourceResponses, RunBackupRequest, RunConnectionHealthCheckData, RunConnectionHealthCheckErrors, RunConnectionHealthCheckResponse, RunConnectionHealthCheckResponses, RunExternalServiceBackupData, RunExternalServiceBackupError, RunExternalServiceBackupErrors, RunExternalServiceBackupRequest, RunExternalServiceBackupResponse, RunExternalServiceBackupResponses, RunScheduleNowData, RunScheduleNowError, RunScheduleNowErrors, RunScheduleNowResponse, RunScheduleNowResponses, S3ConnectionTestResponse, S3CredentialsResponse, S3SourceResponse, S3SourceResponseWritable, SandboxCreatePreviewLinkData, SandboxCreatePreviewLinkErrors, SandboxCreatePreviewLinkResponse, SandboxCreatePreviewLinkResponses, SandboxDomainResponse, SandboxEvent, SandboxEventsResponse, SandboxInner, SandboxResponse, SandboxRoute, SandboxStatusResponse, SaveAgentTokenData, SaveAgentTokenErrors, SaveAgentTokenRequest, SaveAgentTokenResponse, SaveAgentTokenResponse2, SaveAgentTokenResponses, SaveAiProviderCredentialData, SaveAiProviderCredentialErrors, SaveAiProviderCredentialResponse, SaveAiProviderCredentialResponses, SaveCredentialRequest, SaveCredentialResponse, ScalewayCredentialsRequest, ScanResponse, ScheduleRunEntry, ScheduleRunJobEntry, ScheduleRunListResponse, ScheduleRunResponse, ScheduleRunSummary, ScheduleRunSummaryList, ScreenshotSettings, SearchLogsData, SearchLogsError, SearchLogsErrors, SearchLogsRequest, SearchLogsResponse, SearchLogsResponse2, SearchLogsResponses, SearchMode, Seasonality, SecretResponse, SecurityConfig, SecurityHeadersConfig, SecurityHeadersSettings, SelfUpdateAttempt, SelfUpdateBlocker, SelfUpdatePhase, SelfUpdateSettings, SelfUpdateStatus, SendEmailData, SendEmailErrors, SendEmailRequestBody, SendEmailResponse, SendEmailResponseBody, SendEmailResponses, SendMessageData, SendMessageErrors, SendMessageRequest, SendMessageResponses, SensitiveConfigValueResponse, SensitiveMcpConfigValueResponse, SensitiveValueResponse, SentryChunkUploadResponse, SentryCreateReleaseRequest, SentryEventRequest, SentryEventResponse, SentryReleaseFileResponse, SentryReleaseProjectRef, SentryReleaseResponse, SeriesStateEntry, ServiceAccessInfo, ServiceAction, ServiceAlertRuleResponse, ServiceBackupEntryResponse, ServiceBackupListResponse, ServiceCreateAlertRuleRequest, ServiceHealthResponse, ServiceHealthStatusBatchResponse, ServiceHealthStatusEntryResponse, ServiceMemberInfo, ServiceParameter, ServicePlan, ServiceResourceLimits, ServiceRuntimeReport, ServiceStatsReport, ServiceTypeInfo, ServiceTypeRoute, ServiceUpdateAlertRuleRequest, SesCredentialsRequest, SessionDetails, SessionDetailsQuery, SessionEvent, SessionEventDto, SessionEventsQuery, SessionEventsResponse, SessionLogsQuery, SessionLogsResponse, SessionReplayEventsRequest, SessionReplayInfoDto, SessionReplayInitRequest, SessionReplayInitResponse, SessionReplayWithEventsDto, SessionReplayWithVisitorDto, SessionRequestLog, SessionSummary, SetDefaultS3SourceData, SetDefaultS3SourceError, SetDefaultS3SourceErrors, SetDefaultS3SourceResponse, SetDefaultS3SourceResponses, SetFlagEnvironmentData, SetFlagEnvironmentErrors, SetFlagEnvironmentRequest, SetFlagEnvironmentResponse, SetFlagEnvironmentResponses, SetPreviewPasswordBody, SetPreviewPasswordData, SetPreviewPasswordErrors, SetPreviewPasswordResponse, SetPreviewPasswordResponse2, SetPreviewPasswordResponses, SetRequest, SetResponse, SettingsUpdateResponse, SetupDnsChallengeData, SetupDnsChallengeErrors, SetupDnsChallengeRequest, SetupDnsChallengeResponse, SetupDnsChallengeResponse2, SetupDnsChallengeResponses, SetupDnsData, SetupDnsErrors, SetupDnsRequest, SetupDnsResponse, SetupDnsResponse2, SetupDnsResponses, SetupEmailTrackingData, SetupEmailTrackingErrors, SetupEmailTrackingResponse, SetupEmailTrackingResponses, SetupMfaData, SetupMfaErrors, SetupMfaResponse, SetupMfaResponses, SiblingRef, SkillDefinitionResponse, SlackConfig, SleepEnvironmentData, SleepEnvironmentErrors, SleepEnvironmentResponse, SleepEnvironmentResponses, SlowQueriesResponse, SlowQueryRow, SmartFilter, SmokeTestAgentData, SmokeTestAgentErrors, SmokeTestAgentResponse, SmokeTestAgentResponses, SmokeTestResponse, SmtpCredentialsRequest, SmtpEncryptionRoute, SmtpResult, SourceArchiveUpload, SourceBackupEntry, SourceBackupIndexResponse, SourceBody, SourceFileListResponse, SourceFileResponse, SourceMapListResponse, SourceMapResponse, SourceSandboxData, SourceSandboxErrors, SourceSandboxResponse, SourceSandboxResponses, SourceType, SpanEvent, SpanKind, SpanRecord, SpanRow, SpanStatusCode, SpeedMetricsPayload, SpeedSegmentFilters, StaleSlot, StartAnalysisData, StartAnalysisErrors, StartAnalysisRequest, StartAnalysisResponse, StartAnalysisResponses, StartContainerData, StartContainerErrors, StartContainerResponse, StartContainerResponses, StartFixData, StartFixErrors, StartFixResponses, StartGitProviderOauthData, StartGitProviderOauthErrors, StartOidcLoginBySlugData, StartOidcLoginBySlugErrors, StartPgUpgradeData, StartPgUpgradeErrors, StartPgUpgradeRequest, StartPgUpgradeResponse, StartPgUpgradeResponses, StartRestoreData, StartRestoreError, StartRestoreErrors, StartRestoreRequest, StartRestoreResponse, StartRestoreResponses, StartServiceData, StartServiceErrors, StartServiceResponse, StartServiceResponses, StartUpdateData, StartUpdateError, StartUpdateErrors, StartUpdateRequest, StartUpdateResponse, StartUpdateResponse2, StartUpdateResponses, StaticBundleResponse, StaticParams, StaticPresetConfig, StatPathData, StatPathErrors, StatPathResponse, StatPathResponses, StatResponse, StatsFilters, StatusBucket, StatusBucketedResponse, StatusCodeCount, StatusCodesQuery, StatusPageOverview, StepConversionResponse, StepResourceType, StepResult, StepUpResponse, StopContainerData, StopContainerErrors, StopContainerResponse, StopContainerResponses, StopSandboxData, StopSandboxErrors, StopSandboxResponse, StopSandboxResponses, StopSequence, StopServiceData, StopServiceErrors, StopServiceResponse, StopServiceResponses, StorageQuota, StreamContainerMetricsData, StreamContainerMetricsErrors, StreamContainerMetricsResponses, StreamEventsData, StreamEventsErrors, StreamEventsResponses, StreamRunEventsData, StreamRunEventsErrors, StreamRunEventsResponses, StripeConfig, SupervisorKind, SyncedRepositoryListQuery, SyncRepositoriesData, SyncRepositoriesErrors, SyncRepositoriesResponse, SyncRepositoriesResponses, SyntaxResult, TagInfo, TagListResponse, TailDeploymentJobLogsData, TailDeploymentJobLogsErrors, TailLogsData, TailLogsError, TailLogsErrors, TailLogsRequest, TailLogsResponses, TargetRecommendation, TeamListResponse, TeamMemberResponse, TeamResponse, TeamRole, TeardownDeploymentData, TeardownDeploymentErrors, TeardownDeploymentResponse, TeardownDeploymentResponses, TeardownEnvironmentData, TeardownEnvironmentErrors, TeardownEnvironmentResponse, TeardownEnvironmentResponses, TemplateResponse, TestEmailRequest, TestEmailResponse, TestNotificationProviderData, TestNotificationProviderErrors, TestNotificationProviderResponse, TestNotificationProviderResponses, TestOidcProviderData, TestOidcProviderResponse, TestOidcProviderResponses, TestProviderConnectionData, TestProviderConnectionErrors, TestProviderConnectionResponse, TestProviderConnectionResponses, TestProviderData, TestProviderErrors, TestProviderKeyByIdData, TestProviderKeyByIdError, TestProviderKeyByIdErrors, TestProviderKeyByIdResponse, TestProviderKeyByIdResponses, TestProviderKeyInlineData, TestProviderKeyInlineError, TestProviderKeyInlineErrors, TestProviderKeyInlineResponse, TestProviderKeyInlineResponses, TestProviderKeyRequest, TestProviderKeyResponse, TestProviderResponse, TestProviderResponse2, TestProviderResponses, TestS3ConnectionPreviewData, TestS3ConnectionPreviewError, TestS3ConnectionPreviewErrors, TestS3ConnectionPreviewResponse, TestS3ConnectionPreviewResponses, TestS3SourceConnectionData, TestS3SourceConnectionError, TestS3SourceConnectionErrors, TestS3SourceConnectionResponse, TestS3SourceConnectionResponses, TimeBucketStats, TimeBucketStatsResponse, TimeseriesBucket, TimeseriesQueryParams, TlsMode, TodayStatsResponse, ToggleDeploymentMetricsRequest, ToggleServiceMetricsRequest, TokenRenewalRequest, ToolCallEvent, ToolInfo, ToolResultEvent, TopModelsQueryParams, TraceProjectRef, TracesResponse, TraceSummariesResponse, TraceSummary, TrackClickData, TrackClickErrors, TrackedLinkResponse, TrackingEventResponse, TrackOpenData, TrackOpenErrors, TrackOpenResponses, TriggerAgentData, TriggerAgentErrors, TriggerAgentRequest, TriggerAgentResponse, TriggerAgentResponses, TriggerDigestResponse, TriggerPipelinePayload, TriggerPipelineResponse, TriggerProjectPipelineData, TriggerProjectPipelineErrors, TriggerProjectPipelineResponse, TriggerProjectPipelineResponses, TriggerScanData, TriggerScanError, TriggerScanErrors, TriggerScanRequest, TriggerScanResponse, TriggerScanResponse2, TriggerScanResponses, TriggerServiceHealthCheckData, TriggerServiceHealthCheckErrors, TriggerServiceHealthCheckResponse, TriggerServiceHealthCheckResponses, TriggerWeeklyDigestData, TriggerWeeklyDigestErrors, TriggerWeeklyDigestResponse, TriggerWeeklyDigestResponses, TtlRequest, TtlResponse, TxtRecord, UiManifest, UiRoute, UndrainNodeResponse, UnifiedTrace, UniqueCountsQuery, UniqueCountsResponse, UnlinkServiceFromProjectData, UnlinkServiceFromProjectErrors, UnlinkServiceFromProjectResponse, UnlinkServiceFromProjectResponses, UnsupportedFeature, UpdateAdminGateRequest, UpdateAgentData, UpdateAgentErrors, UpdateAgentResponse, UpdateAgentResponses, UpdateAiProviderData, UpdateAiProviderErrors, UpdateAiProviderRequest, UpdateAiProviderResponse, UpdateAiProviderResponse2, UpdateAiProviderResponses, UpdateAlertData, UpdateAlertError, UpdateAlertErrors, UpdateAlertResponse, UpdateAlertResponses, UpdateAlertRuleData, UpdateAlertRuleErrors, UpdateAlertRuleRequest, UpdateAlertRuleResponse, UpdateAlertRuleResponses, UpdateApiKeyData, UpdateApiKeyErrors, UpdateApiKeyRequest, UpdateApiKeyResponse, UpdateApiKeyResponses, UpdateAutomaticDeployData, UpdateAutomaticDeployErrors, UpdateAutomaticDeployRequest, UpdateAutomaticDeployResponse, UpdateAutomaticDeployResponses, UpdateBackupScheduleData, UpdateBackupScheduleError, UpdateBackupScheduleErrors, UpdateBackupScheduleRequest, UpdateBackupScheduleResponse, UpdateBackupScheduleResponses, UpdateBlobRequest, UpdateBlobResponse, UpdateCapabilityResponse, UpdateCloudflareProviderData, UpdateCloudflareProviderErrors, UpdateCloudflareProviderRequest, UpdateCloudflareProviderResponse, UpdateCloudflareProviderResponses, UpdateConfigBody, UpdateConnectionTokenData, UpdateConnectionTokenErrors, UpdateConnectionTokenResponse, UpdateConnectionTokenResponses, UpdateCustomDomainData, UpdateCustomDomainErrors, UpdateCustomDomainRequest, UpdateCustomDomainResponse, UpdateCustomDomainResponses, UpdateDashboardData, UpdateDashboardError, UpdateDashboardErrors, UpdateDashboardRequest, UpdateDashboardResponse, UpdateDashboardResponses, UpdateDeploymentConfigRequest, UpdateDeploymentTokenData, UpdateDeploymentTokenErrors, UpdateDeploymentTokenRequest, UpdateDeploymentTokenResponse, UpdateDeploymentTokenResponses, UpdateDnsProviderRequest, UpdateEmailProviderData, UpdateEmailProviderErrors, UpdateEmailProviderRequest, UpdateEmailProviderResponse, UpdateEmailProviderResponses, UpdateEnvironmentSettingsData, UpdateEnvironmentSettingsErrors, UpdateEnvironmentSettingsRequest, UpdateEnvironmentSettingsResponse, UpdateEnvironmentSettingsResponses, UpdateEnvironmentSubdomainData, UpdateEnvironmentSubdomainErrors, UpdateEnvironmentSubdomainRequest, UpdateEnvironmentSubdomainResponse, UpdateEnvironmentSubdomainResponses, UpdateEnvironmentVariableData, UpdateEnvironmentVariableErrors, UpdateEnvironmentVariableRequest, UpdateEnvironmentVariableResponse, UpdateEnvironmentVariableResponses, UpdateErrorGroupData, UpdateErrorGroupErrors, UpdateErrorGroupRequest, UpdateErrorGroupResponses, UpdateExternalServiceRequest, UpdateFlagData, UpdateFlagErrors, UpdateFlagRequest, UpdateFlagResponse, UpdateFlagResponses, UpdateFunnelData, UpdateFunnelErrors, UpdateFunnelResponses, UpdateGitProviderCredentialsData, UpdateGitProviderCredentialsErrors, UpdateGitProviderCredentialsResponse, UpdateGitProviderCredentialsResponses, UpdateGitSettingsData, UpdateGitSettingsErrors, UpdateGitSettingsRequest, UpdateGitSettingsResponse, UpdateGitSettingsResponses, UpdateGlobalMcpData, UpdateGlobalMcpErrors, UpdateGlobalMcpResponse, UpdateGlobalMcpResponses, UpdateGlobalSkillData, UpdateGlobalSkillErrors, UpdateGlobalSkillResponse, UpdateGlobalSkillResponses, UpdateIncidentStatusData, UpdateIncidentStatusErrors, UpdateIncidentStatusRequest, UpdateIncidentStatusResponse, UpdateIncidentStatusResponses, UpdateIpAccessControlData, UpdateIpAccessControlError, UpdateIpAccessControlErrors, UpdateIpAccessControlRequest, UpdateIpAccessControlResponse, UpdateIpAccessControlResponses, UpdateKvRequest, UpdateKvResponse, UpdateManagedDomainApiRequest, UpdateManagedDomainData, UpdateManagedDomainErrors, UpdateManagedDomainResponse, UpdateManagedDomainResponses, UpdateMcpData, UpdateMcpErrors, UpdateMcpRequest, UpdateMcpResponse, UpdateMcpResponses, UpdateMemberRoleRequest, UpdateMetricAlertRequest, UpdateNotificationEmailProviderData, UpdateNotificationEmailProviderErrors, UpdateNotificationEmailProviderRequest, UpdateNotificationEmailProviderResponse, UpdateNotificationEmailProviderResponses, UpdateNotificationProviderData, UpdateNotificationProviderErrors, UpdateNotificationProviderResponse, UpdateNotificationProviderResponses, UpdateOidcProviderData, UpdateOidcProviderRequest, UpdateOidcProviderResponse, UpdateOidcProviderResponses, UpdatePreferencesData, UpdatePreferencesErrors, UpdatePreferencesRequest, UpdatePreferencesResponse, UpdatePreferencesResponses, UpdateProjectData, UpdateProjectDeploymentConfigData, UpdateProjectDeploymentConfigErrors, UpdateProjectDeploymentConfigResponse, UpdateProjectDeploymentConfigResponses, UpdateProjectErrors, UpdateProjectResponse, UpdateProjectResponses, UpdateProjectSecretData, UpdateProjectSecretErrors, UpdateProjectSecretRequest, UpdateProjectSecretResponse, UpdateProjectSecretResponses, UpdateProjectSettingsData, UpdateProjectSettingsErrors, UpdateProjectSettingsRequest, UpdateProjectSettingsResponse, UpdateProjectSettingsResponses, UpdateProviderCredentialsRequest, UpdateProviderData, UpdateProviderErrors, UpdateProviderKeyData, UpdateProviderKeyError, UpdateProviderKeyErrors, UpdateProviderKeyRequest, UpdateProviderKeyResponse, UpdateProviderKeyResponses, UpdateProviderRequest, UpdateProviderResponse, UpdateProviderResponses, UpdateRouteData, UpdateRouteErrors, UpdateRouteRequest, UpdateRouteResponse, UpdateRouteResponses, UpdateS3SourceData, UpdateS3SourceError, UpdateS3SourceErrors, UpdateS3SourceRequest, UpdateS3SourceResponse, UpdateS3SourceResponses, UpdateSecretBody, UpdateSelfData, UpdateSelfErrors, UpdateSelfRequest, UpdateSelfResponse, UpdateSelfResponses, UpdateServiceData, UpdateServiceErrors, UpdateServiceResourcesData, UpdateServiceResourcesErrors, UpdateServiceResourcesResponse, UpdateServiceResourcesResponses, UpdateServiceResponse, UpdateServiceResponses, UpdateSessionDurationData, UpdateSessionDurationError, UpdateSessionDurationErrors, UpdateSessionDurationRequest, UpdateSessionDurationResponse, UpdateSessionDurationResponse2, UpdateSessionDurationResponses, UpdateSettingsData, UpdateSettingsErrors, UpdateSettingsResponse, UpdateSettingsResponses, UpdateSkillData, UpdateSkillErrors, UpdateSkillRequest, UpdateSkillResponse, UpdateSkillResponses, UpdateSlackProviderData, UpdateSlackProviderErrors, UpdateSlackProviderRequest, UpdateSlackProviderResponse, UpdateSlackProviderResponses, UpdateSpeedMetricsData, UpdateSpeedMetricsError, UpdateSpeedMetricsErrors, UpdateSpeedMetricsPayload, UpdateSpeedMetricsResponse, UpdateSpeedMetricsResponses, UpdateStatusResponse, UpdateTeamData, UpdateTeamErrors, UpdateTeamMemberRoleData, UpdateTeamMemberRoleErrors, UpdateTeamMemberRoleResponse, UpdateTeamMemberRoleResponses, UpdateTeamRequest, UpdateTeamResponse, UpdateTeamResponses, UpdateTokenRequest, UpdateTokenResponse, UpdateUserData, UpdateUserErrors, UpdateUserRequest, UpdateUserResponse, UpdateUserResponses, UpdateWebhookData, UpdateWebhookErrors, UpdateWebhookProviderData, UpdateWebhookProviderErrors, UpdateWebhookProviderRequest, UpdateWebhookProviderResponse, UpdateWebhookProviderResponses, UpdateWebhookRequestBody, UpdateWebhookResponse, UpdateWebhookResponses, UpgradeExternalServiceRequest, UpgradePreviewGatewayData, UpgradePreviewGatewayResponse, UpgradePreviewGatewayResponses, UpgradeRequest, UpgradeServiceData, UpgradeServiceErrors, UpgradeServiceResponse, UpgradeServiceResponses, UploadGlobalSkillData, UploadGlobalSkillErrors, UploadGlobalSkillResponse, UploadGlobalSkillResponses, UploadReleaseFileData, UploadReleaseFileErrors, UploadReleaseFileResponse, UploadReleaseFileResponses, UploadSkillData, UploadSkillErrors, UploadSkillResponse, UploadSkillResponses, UploadSourceFileData, UploadSourceFileErrors, UploadSourceFileResponse, UploadSourceFileResponses, UploadSourceMapData, UploadSourceMapErrors, UploadSourceMapResponse, UploadSourceMapResponses, UploadStaticBundleData, UploadStaticBundleErrors, UploadStaticBundleResponse, UploadStaticBundleResponses, UpsertAgentRequest, UpsertSecretData, UpsertSecretErrors, UpsertSecretRequest, UpsertSecretResponse, UpsertSecretResponses, UptimeDataPoint, UptimeHistoryResponse, UsageFilter, UsageInfo, UsageLogEntry, UsageLogPage, UsageQueryParams, UsageSource, UsageSummary, UserResponse, ValidateConnectionData, ValidateConnectionErrors, ValidateConnectionResponse, ValidateConnectionResponses, ValidateEmailData, ValidateEmailErrors, ValidateEmailRequest, ValidateEmailResponse, ValidateEmailResponse2, ValidateEmailResponses, ValidationLevel, ValidationReport, ValidationResponse, ValidationResult, ValidationStatus, ValidationSummary, VerifyAndEnableMfaData, VerifyAndEnableMfaErrors, VerifyAndEnableMfaResponse, VerifyAndEnableMfaResponses, VerifyDomainData, VerifyDomainErrors, VerifyDomainResponse, VerifyDomainResponses, VerifyEmailData, VerifyEmailErrors, VerifyEmailResponse, VerifyEmailResponses, VerifyManagedDomainData, VerifyManagedDomainErrors, VerifyManagedDomainResponse, VerifyManagedDomainResponses, VerifyMfaChallengeData, VerifyMfaChallengeErrors, VerifyMfaChallengeResponse, VerifyMfaChallengeResponses, VerifyMfaRequest, VerifyStepUpData, VerifyStepUpErrors, VerifyStepUpRequest, VerifyStepUpResponse, VerifyStepUpResponses, ViewItem, ViewsOverTime, ViewsOverTimeQuery, VisitorDetails, VisitorFacets, VisitorFacetsQuery, VisitorFacetValue, VisitorInfo, VisitorJourneyQuery, VisitorJourneyResponse, VisitorLocationsQuery, VisitorRecord, VisitorSegmentFilters, VisitorSessionsQuery, VisitorSessionsResponse, VisitorsListQuery, VisitorsResponse, VisitorStats, VisitorWithGeolocation, VolumeMount, VolumeType, VulnerabilityResponse, WakeEnvironmentData, WakeEnvironmentErrors, WakeEnvironmentResponse, WakeEnvironmentResponses, WalWarning, WalWarningSeverity, WebhookConfig, WebhookDeliveryResponse, WebhookResponse, WebhookTriggerData, WebhookTriggerErrors, WebhookTriggerRequest, WebhookTriggerResponse, WebhookTriggerResponse2, WebhookTriggerResponses, WorkflowDryRunData, WorkflowDryRunErrors, WorkflowDryRunRequest, WorkflowDryRunResponse, WorkflowDryRunResponses, WorkloadDescriptor, WorkloadId, WorkloadStatus, WorkloadType, WriteFileBody, WriteFileData, WriteFileErrors, WriteFileResponse, WriteFileResponses, WriteFilesBody, WriteFilesData, WriteFilesErrors, WriteFilesResponse, WriteFilesResponse2, WriteFilesResponses, ZoneListResponse } from './types.gen'; +export { acknowledgeAlarm, activateAiProvider, activateApiKey, activateConnection, activateProvider, addClusterMember, addContext, addEnvironmentDomain, addEvents, addManagedDomain, addSessionReplayEvents, addTeamMember, adminDrainNode, adminDrainStatus, adminGetNode, adminListNodeContainers, adminListNodes, adminRemoveNode, adminUndrainNode, applyHostnameMode, archiveConversation, archiveFlag, assignRole, attachScheduleServices, blobCopy, blobDelete, blobDisable, blobDownload, blobEnable, blobHead, blobList, blobPut, blobStatus, blobUpdate, cancel, cancelBackup, cancelDeployment, cancelDomainOrder, cancelPgUpgrade, cancelRun, cancelScheduleRun, changePasswordSelf, changeProjectSource, changeRequiredPassword, chatCompletions, checkAnalyticsHasEvents, checkCommitExists, checkDomainStatus, checkExplorerSupport, checkForUpdate, checkIpBlocked, checkProviderDeletionSafety, chunkUploadOptions, cleanupExpiredBackups, clearPreviewPassword, cliDeviceApprove, cliDeviceDeny, cliDeviceLookup, cliDevicePoll, cliDeviceStart, cliLogout, cmd, cmdKill, cmdLogs, confirmPendingAction, containerMetricsGetHistory, createAgent, createAlert, createAlertRule, createApiKey, createBackupSchedule, createBitbucketProvider, createCloudflareProvider, createConversation, createCustomDomain, createDashboard, createDeploymentToken, createDnsProvider, createDomain, createDsn, createEmailDomain, createEmailProvider, createEnvironment, createEnvironmentVariable, createFlag, createFunnel, createGenericProvider, createGiteaPatProvider, createGithubPatProvider, createGitlabOauthProvider, createGitlabPatProvider, createGitProvider, createGlobalMcp, createGlobalSkill, createIncident, createIpAccessControl, createMcp, createMonitor, createNotificationEmailProvider, createNotificationProvider, createOidcProvider, createOidcRoleMapping, createOrRecreateOrder, createPlan, createPr, createProject, createProjectFromTemplate, createProjectRelease, createProjectSecret, createProviderKey, createRelease, createRoute, createS3Source, createSandbox, createService, createSkill, createSlackProvider, createTeam, createUser, createWebhook, createWebhookProvider, deactivateApiKey, deactivateConnection, deactivateProvider, deleteAgent, deleteAlert, deleteAlertRule, deleteApiKey, deleteBackup, deleteBackupSchedule, deleteConnection, deleteCustomDomain, deleteDashboard, deleteDeploymentToken, deleteDnsProvider, deleteDomain, deleteEmailDomain, deleteEmailProvider, deleteEnvironment, deleteEnvironmentDomain, deleteEnvironmentVariable, deleteExternalImage, deleteFunnel, deleteGitProvider, deleteGlobalMcp, deleteGlobalSkill, deleteIpAccessControl, deleteMcp, deleteMonitor, deleteNotificationProvider, deleteOidcProvider, deleteOidcRoleMapping, deletePreferences, deleteProject, deleteProjectSecret, deleteProviderKey, deleteProviderSafely, deleteReleaseSourceFiles, deleteReleaseSourceMaps, deleteRoute, deleteS3Source, deleteScan, deleteSecret, deleteService, deleteSessionReplay, deleteSkill, deleteSourceMap, deleteStaticBundle, deleteTeam, deleteUser, deleteWebhook, deployFromImage, deployFromImageUpload, deployFromStatic, deployFromUploadedSource, deploymentMetricsGetLatest, deploymentMetricsGetRange, deploymentMetricsToggle, destroySandbox, detachScheduleService, detectPublicPresets, disableBackupSchedule, disableMfa, discoverWorkloads, domain, downloadGlobalSkillArchive, downloadObject, downloadSkillArchive, emailStatus, embeddings, enableBackupSchedule, enrichVisitor, exec, execDetached, executeDeploymentOperation, executeImport, extendTimeout, externalServiceEnablePgStatStatements, externalServiceMetricsByDatabase, externalServiceMetricsCreateAlertRule, externalServiceMetricsDeleteAlertRule, externalServiceMetricsGetAlertRules, externalServiceMetricsGetLatest, externalServiceMetricsGetRange, externalServiceMetricsStatus, externalServiceMetricsToggle, externalServiceMetricsUpdateAlertRule, externalServiceResetPgStatStatements, finalizeOrder, finalizeProjectRelease, findConversation, generateJoinToken, generatePresetDockerfile, getAccessInfo, getActiveVisitors, getActivityGraph, getAdminGate, getAgent, getAggregatedBuckets, getAiAgentBreakdown, getAiAgentPages, getAiAgentTimeline, getAiPageBreakdown, getAiStatusBreakdown, getAlert, getAlertRule, getAllRepositoriesByName, getAnalyticsActiveVisitors, getAnalyticsEventsCount, getAnalyticsSessionEvents, getAnalyticsVisitorSessions, getApiKey, getApiKeyPermissions, getAuditLog, getBackup, getBackupSchedule, getBranchesByRepositoryId, getBucketedIncidents, getBucketedStatus, getChallengeToken, getChatReadiness, getCliStatus, getClusterHealth, getClusterMember, getCmd, getContainerDetail, getContainerEnvironmentVariable, getContainerInfo, getContainerLogs, getContainerLogsById, getContainerMetrics, getConversation, getConversationDetail, getConversations, getCronById, getCronExecutions, getCrossProjectTraceSiblings, getCurrentMonitorStatus, getCurrentUser, getCustomDomain, getDashboard, getDashboardProjectsAnalytics, getDelivery, getDeployment, getDeploymentContainerLogContent, getDeploymentJobLogs, getDeploymentJobs, getDeploymentOperations, getDeploymentOperationStatus, getDeploymentToken, getDiskStatus, getDnsChanges, getDnsProvider, getDomain, getDomainByHost, getDomainById, getDomainByName, getDomainDnsRecords, getDomainOrder, getEmail, getEmailEvents, getEmailLinks, getEmailProvider, getEmailStats, getEmailTracking, getEmailTrackingStatus, getEntityInfo, getEnvironment, getEnvironmentCrons, getEnvironmentDomains, getEnvironments, getEnvironmentVariables, getEnvironmentVariableValue, getErrorDashboardStats, getErrorEvent, getErrorGroup, getErrorStats, getErrorTimeSeries, getEventDetail, getEventEntries, getEventsCount, getEventsTimeline, getEventTypeBreakdown, getEventVisitors, getExternalImage, getFile, getFlag, getFlagSnapshot, getFunnelMetrics, getGenaiTrace, getGeneralStats, getGitProvider, getGlobalEvents, getGlobalEventStats, getGlobalMcp, getGlobalSandboxStatus, getGlobalSkill, getGroupedPageMetrics, getHealth, getHourlyVisits, getHttpChallengeDebug, getImportStatus, getIncident, getIncidentUpdates, getIpAccessControl, getIpGeolocation, getJoinTokenStatus, getLastDeployment, getLatestScan, getLatestScansPerEnvironment, getLiveVisitorsList, getLogContext, getMcp, getMetricsOverTime, getMonitor, getNotificationProvider, getOnDemandCertStatus, getOrCreateDsn, getPageFlow, getPageHourlySessions, getPagePathDetail, getPagePaths, getPagePathsSparklines, getPagePathVisitors, getPendingAction, getPerformanceMetrics, getPgUpgrade, getPgUpgradeLogs, getPipelineStats, getPlatformInfo, getPostgresWalHealth, getPreferences, getPreviewGatewayLogs, getPreviewGatewaySettings, getPreviewGatewayStatus, getPricing, getPrivateIp, getProject, getProjectAlarmsSummary, getProjectBySlug, getProjectDeployments, getProjects, getProjectServiceEnvironmentVariables, getProjectSessionReplays, getProjectsHealth, getProjectsMonitorHealth, getProjectStatistics, getProjectTemplate, getPropertyBreakdown, getPropertyTimeline, getProviderConnections, getProviderMetadata, getProvidersMetadata, getProxyLogById, getProxyLogByRequestId, getProxyLogs, getPublicBranches, getPublicIp, getPublicRepository, getQuota, getRecentActivity, getRemoteExternalImage, getRepositoryBranches, getRepositoryById, getRepositoryByName, getRepositoryPresetByName, getRepositoryPresetLive, getRepositoryTags, getResolvedEnvironmentVariables, getResolvedEnvironmentVariableValue, getRestoreCapabilities, getRestoreRun, getRoute, getRun, getRunWithLogs, getS3Credentials, getS3Source, getSandbox, getSandboxStatus, getScan, getScanByDeployment, getScanVulnerabilities, getService, getServiceBySlug, getServiceEnvironmentVariable, getServiceEnvironmentVariables, getServiceHealthStatus, getServicePreviewEnvironmentVariableNames, getServicePreviewEnvironmentVariablesMasked, getServiceRuntime, getServiceStats, getServiceTypeParameters, getServiceTypes, getSessionDetails, getSessionEvents, getSessionLogs, getSessionReplay, getSessionReplayEvents, getSettings, getSkill, getSlowQueries, getStaticBundle, getStatusOverview, getTagsByRepositoryId, getTeam, getTimeBucketStats, getTodayStats, getTrace, getUnifiedTrace, getUniqueCounts, getUniqueEvents, getUpdateCapability, getUpdateStatus, getUptimeHistory, getUsageByProvider, getUsageRecent, getUsageSummary, getUsageTimeseries, getUsageTopModels, getVisitorByGuid, getVisitorById, getVisitorDetails, getVisitorFacets, getVisitorInfo, getVisitorJourney, getVisitors, getVisitorSessions, getVisitorStats, getWebhook, grantProjectAccess, handleGitProviderOauthCallback, hasAnalyticsEvents, hasErrorGroups, hasPerformanceMetrics, importExternalService, ingestLogs, ingestLogsByPath, ingestMetrics, ingestMetricsByPath, ingestSentryEnvelope, ingestSentryEvent, ingestTraces, ingestTracesByPath, initSessionReplay, inspectDropArchive, jobLogs, jobStatus, killJob, kvDel, kvDisable, kvEnable, kvExpire, kvGet, kvIncr, kvKeys, kvSet, kvStatus, kvTtl, kvUpdate, latestRunForSource, linkCustomDomainToCertificate, linkServiceToProject, listAgentRuns, listAgents, listAiProviders, listAlertRules, listAlerts, listAllConversations, listAllRuns, listApiKeys, listAuditLogs, listAvailableContainers, listBackupAlerts, listBackupChildren, listBackupSchedules, listBackupsForSchedule, listCommitsByRepositoryId, listConnections, listContainers, listContainersAtPath, listConversations, listCustomDomainsForProject, listDashboards, listDeliveries, listDeploymentContainerLogs, listDeploymentTokens, listDnsProviders, listDomains, listDsns, listEmailDomains, listEmailProviders, listEmails, listEnrollmentTokens, listEntities, listErrorEvents, listErrorGroups, listEvents, listEventTypes, listExternalImages, listExternalPlugins, listExternalServiceBackups, listFlags, listFunnels, listGitProviders, listGlobalMcps, listGlobalSkills, listIncidents, listInsights, listIpAccessControl, listJobs, listKnownAiAgents, listManagedDomains, listMcps, listMetricLabelKeys, listMetricLabelValues, listMetricNames, listModels, listMonitors, listNotificationProviders, listOidcProviders, listOidcProviderUsers, listOidcRoleMappings, listOnDemandCerts, listOrders, listPeers, listPendingActions, listPgUpgrades, listPresets, listProjectAccess, listProjectAlarms, listProjectScans, listProjectSecrets, listProjectServices, listProjectTemplates, listProjectTemplateTags, listProviderKeys, listProviderZones, listPublicProviders, listReleaseFiles, listReleases, listRemoteExternalImages, listRepositoriesByConnection, listRepositoriesByProvider, listRestoreRunsForService, listRootContainers, listRoutes, listS3Sources, listSandboxes, listScheduleRunJobs, listScheduleRuns, listScheduleServices, listSecrets, listServiceHealthStatuses, listServiceProjects, listServices, listServiceSchedules, listSkills, listSourceBackups, listSourceFiles, listSourceMaps, listSources, listStaticBundles, listSyncedRepositories, listTeamMembers, listTeamProjects, listTeams, listUsers, listWebhooks, login, logout, lookupDnsARecords, mintEnrollmentToken, mkdir, nodeHeartbeat, nodeMetricsGetRange, observabilityFullEvent, observabilityListEvents, oidcCallback, type Options, patchAdminGate, patchPreviewGatewaySettings, pauseDeployment, pauseSandbox, planRestore, postDnsAck, previewAlert, previewFunnelMetrics, previewHostnameMode, promoteClusterMember, promoteDeployment, provisionDomain, purgeProjectLogs, pushExternalImage, queryData, queryGenaiTraces, queryLogs, queryMetrics, queryTraces, queryTraceSummaries, readFile, reAnalyze, rebuildSandboxImage, recordConsoleEvent, recordEventMetrics, recordFlagExposure, recordSpeedMetrics, refreshRouteTable, regenerateDsn, registerExternalImage, registerNode, reinstallGitlabWebhook, rejectPendingAction, reloadPlugins, removeClusterMember, removeManagedDomain, removeRole, removeTeamMember, renameConversation, renewDomain, requestPasswordReset, resetPassword, resizeSandbox, resolveAlarm, restartContainer, restartPreviewGateway, restartSandbox, restoreFlag, restoreUser, resumeDeployment, resumeSandbox, retryCluster, retryDelivery, retryPgUpgrade, retryRun, revealGlobalMcpConfig, revealMcpConfig, revealNotificationProviderConfig, revealServiceParameter, revenueCreateIntegration, revenueDeleteIntegration, revenueGlobalEvents, revenueImportInvoicesCsv, revenueImportSubscriptionsCsv, revenueListIntegrations, revenueListProviders, revenueMetricsCustomers, revenueMetricsGlobalMrr, revenueMetricsGlobalSummary, revenueMetricsMrr, revenueMetricsSummary, revenueRecentEvents, revenueRotateToken, revenueUpdateConfig, revenueUpdateSecret, revokeDsn, revokeEnrollmentToken, revokeJoinToken, revokeProjectAccess, rollbackPgUpgrade, rollbackToDeployment, rootfsGc, rootfsReport, rotateApiKey, rotateDeploymentToken, runBackupForSource, runConnectionHealthCheck, runExternalServiceBackup, runScheduleNow, sandboxCreatePreviewLink, saveAgentToken, saveAiProviderCredential, searchLogs, sendEmail, sendMessage, setDefaultS3Source, setFlagEnvironment, setPreviewPassword, setupDns, setupDnsChallenge, setupEmailTracking, setupMfa, sleepEnvironment, smokeTestAgent, sourceSandbox, startAnalysis, startContainer, startFix, startGitProviderOauth, startOidcLoginBySlug, startPgUpgrade, startRestore, startService, startUpdate, statPath, stopContainer, stopSandbox, stopService, streamContainerMetrics, streamEvents, streamRunEvents, syncRepositories, tailDeploymentJobLogs, tailLogs, teardownDeployment, teardownEnvironment, testNotificationProvider, testOidcProvider, testProvider, testProviderConnection, testProviderKeyById, testProviderKeyInline, testS3ConnectionPreview, testS3SourceConnection, trackClick, trackOpen, triggerAgent, triggerProjectPipeline, triggerScan, triggerServiceHealthCheck, triggerWeeklyDigest, unlinkServiceFromProject, updateAgent, updateAiProvider, updateAlert, updateAlertRule, updateApiKey, updateAutomaticDeploy, updateBackupSchedule, updateCloudflareProvider, updateConnectionToken, updateCustomDomain, updateDashboard, updateDeploymentToken, updateEmailProvider, updateEnvironmentSettings, updateEnvironmentSubdomain, updateEnvironmentVariable, updateErrorGroup, updateFlag, updateFunnel, updateGitProviderCredentials, updateGitSettings, updateGlobalMcp, updateGlobalSkill, updateIncidentStatus, updateIpAccessControl, updateManagedDomain, updateMcp, updateNotificationEmailProvider, updateNotificationProvider, updateOidcProvider, updatePreferences, updateProject, updateProjectDeploymentConfig, updateProjectSecret, updateProjectSettings, updateProvider, updateProviderKey, updateRoute, updateS3Source, updateSelf, updateService, updateServiceResources, updateSessionDuration, updateSettings, updateSkill, updateSlackProvider, updateSpeedMetrics, updateTeam, updateTeamMemberRole, updateUser, updateWebhook, updateWebhookProvider, upgradePreviewGateway, upgradeService, uploadGlobalSkill, uploadReleaseFile, uploadSkill, uploadSourceFile, uploadSourceMap, uploadStaticBundle, upsertSecret, validateConnection, validateEmail, verifyAndEnableMfa, verifyDomain, verifyEmail, verifyManagedDomain, verifyMfaChallenge, verifyStepUp, wakeEnvironment, webhookTrigger, workflowDryRun, writeFile, writeFiles } from './sdk.gen'; +export type { AcknowledgeAlarmData, AcknowledgeAlarmErrors, AcknowledgeAlarmResponses, AcmeOrderResponse, ActivateAiProviderData, ActivateAiProviderErrors, ActivateAiProviderResponse, ActivateAiProviderResponses, ActivateApiKeyData, ActivateApiKeyErrors, ActivateApiKeyResponse, ActivateApiKeyResponses, ActivateConnectionData, ActivateConnectionErrors, ActivateConnectionResponses, ActivateProviderData, ActivateProviderErrors, ActivateProviderResponse, ActivateProviderResponses, ActiveVisitor, ActiveVisitorsQuery, ActiveVisitorsResponse, ActivityDay, ActivityEvent, ActivityGraphQuery, ActivityGraphResponse, AddClusterMemberData, AddClusterMemberErrors, AddClusterMemberRequest, AddClusterMemberResponse, AddClusterMemberResponses, AddContextData, AddContextErrors, AddContextRequest, AddContextResponses, AddEnvironmentDomainData, AddEnvironmentDomainErrors, AddEnvironmentDomainRequest, AddEnvironmentDomainResponse, AddEnvironmentDomainResponses, AddEventsData, AddEventsError, AddEventsErrors, AddEventsRequest, AddEventsResponse, AddEventsResponse2, AddEventsResponses, AddManagedDomainApiRequest, AddManagedDomainData, AddManagedDomainErrors, AddManagedDomainResponse, AddManagedDomainResponses, AddSessionReplayEventsData, AddSessionReplayEventsError, AddSessionReplayEventsErrors, AddSessionReplayEventsResponse, AddSessionReplayEventsResponses, AddTeamMemberData, AddTeamMemberErrors, AddTeamMemberResponse, AddTeamMemberResponses, AdminDrainNodeData, AdminDrainNodeErrors, AdminDrainNodeResponse, AdminDrainNodeResponses, AdminDrainStatusData, AdminDrainStatusErrors, AdminDrainStatusResponse, AdminDrainStatusResponses, AdminGateResponse, AdminGateSource, AdminGetNodeData, AdminGetNodeErrors, AdminGetNodeResponse, AdminGetNodeResponses, AdminListNodeContainersData, AdminListNodeContainersErrors, AdminListNodeContainersResponse, AdminListNodeContainersResponses, AdminListNodesData, AdminListNodesErrors, AdminListNodesResponse, AdminListNodesResponses, AdminRemoveNodeData, AdminRemoveNodeErrors, AdminRemoveNodeResponse, AdminRemoveNodeResponses, AdminUndrainNodeData, AdminUndrainNodeErrors, AdminUndrainNodeResponse, AdminUndrainNodeResponses, AgentConfigResponse, AgentRunLogResponse, AgentRunResponse, AgentRunWithLogsResponse, AgentSandboxSettings, AgentSandboxSettingsMasked, AggregatedBucketItem, AggregatedBucketsQuery, AggregatedBucketsResponse, AggregationLevel, AggregationTemporality, AiAgentBreakdownResponse, AiAgentBreakdownRow, AiAgentDescriptor, AiAgentPageRow, AiAgentPagesResponse, AiAgentTimelineResponse, AiAgentTimelineRow, AiChatLimitsSettings, AiConfigSettings, AiPageBreakdownResponse, AiPageBreakdownRow, AiStatusBreakdownResponse, AiStatusBreakdownRow, AlarmListResponse, AlarmResponse, AlarmSummaryResponse, AlertRuleResponse, AllocEntry, AnalyticsSessionEventsResponse, AnnotatedSpan, AnomalyAlgorithm, AnomalyParams, AnomalyPreviewPointResponse, AnomalyPreviewRequest, AnomalyPreviewResponse, ApiKeyListResponse, ApiKeyResponse, ApplyHostnameModeData, ApplyHostnameModeErrors, ApplyHostnameModeRequest, ApplyHostnameModeResponse, ApplyHostnameModeResponses, AppSettings, AppSettingsResponse, ArchiveConversationData, ArchiveConversationErrors, ArchiveConversationResponse, ArchiveConversationResponses, ArchiveFlagData, ArchiveFlagErrors, ArchiveFlagResponse, ArchiveFlagResponse2, ArchiveFlagResponses, ArchiveMode, AssignRoleData, AssignRoleErrors, AssignRoleRequest, AssignRoleResponses, AttachScheduleServicesData, AttachScheduleServicesError, AttachScheduleServicesErrors, AttachScheduleServicesRequest, AttachScheduleServicesResponse, AttachScheduleServicesResponse2, AttachScheduleServicesResponses, AuditLogIpInfo, AuditLogResponse, AuditLogUserInfo, AuthFlavorDto, AuthResponse, AuthStatusResponse, AuthTokenResponse, AutofixerRunResponse, AutofixerRunWithLogsResponse, AutofixRunConfig, AutoWatchParams, AvailableContainerInfo, AvailablePermissions, BackupAlertListResponse, BackupAlertResponse, BackupResponse, BackupScheduleResponse, BitbucketAuthInput, BlobCopyData, BlobCopyError, BlobCopyErrors, BlobCopyResponse, BlobCopyResponses, BlobDeleteData, BlobDeleteError, BlobDeleteErrors, BlobDeleteResponse, BlobDeleteResponses, BlobDisableData, BlobDisableErrors, BlobDisableResponse, BlobDisableResponses, BlobDownloadData, BlobDownloadError, BlobDownloadErrors, BlobDownloadResponses, BlobEnableData, BlobEnableErrors, BlobEnableResponse, BlobEnableResponses, BlobHeadData, BlobHeadError, BlobHeadErrors, BlobHeadResponses, BlobListData, BlobListError, BlobListErrors, BlobListResponse, BlobListResponses, BlobPutData, BlobPutError, BlobPutErrors, BlobPutResponse, BlobPutResponses, BlobResponse, BlobStatusData, BlobStatusErrors, BlobStatusResponse, BlobStatusResponse2, BlobStatusResponses, BlobUpdateData, BlobUpdateErrors, BlobUpdateResponse, BlobUpdateResponses, BranchInfo, BranchListResponse, BrowserCount, BrowsersQuery, BuildConfiguration, BuildLimitsSettings, CancelBackupData, CancelBackupError, CancelBackupErrors, CancelBackupResponse, CancelBackupResponse2, CancelBackupResponses, CancelData, CancelDeploymentData, CancelDeploymentErrors, CancelDeploymentResponse, CancelDeploymentResponses, CancelDomainOrderData, CancelDomainOrderErrors, CancelDomainOrderResponse, CancelDomainOrderResponses, CancelErrors, CancelPgUpgradeData, CancelPgUpgradeErrors, CancelPgUpgradeResponse, CancelPgUpgradeResponses, CancelResponses, CancelRunData, CancelRunErrors, CancelRunResponse, CancelRunResponses, CancelScheduleRunData, CancelScheduleRunError, CancelScheduleRunErrors, CancelScheduleRunResponse, CancelScheduleRunResponses, CertStatusResponse, ChallengeConfig, ChallengeError, ChallengeValidationStatus, ChangePasswordRequest, ChangePasswordSelfData, ChangePasswordSelfErrors, ChangePasswordSelfResponse, ChangePasswordSelfResponses, ChangeProjectSourceData, ChangeProjectSourceErrors, ChangeProjectSourceRequest, ChangeProjectSourceResponse, ChangeProjectSourceResponses, ChangeRequiredPasswordData, ChangeRequiredPasswordErrors, ChangeRequiredPasswordResponse, ChangeRequiredPasswordResponses, ChatCompletionChoice, ChatCompletionRequest, ChatCompletionResponse, ChatCompletionsData, ChatCompletionsError, ChatCompletionsErrors, ChatCompletionsResponse, ChatCompletionsResponses, ChatMessage, ChatReadinessResponse, CheckAnalyticsHasEventsData, CheckAnalyticsHasEventsErrors, CheckAnalyticsHasEventsResponse, CheckAnalyticsHasEventsResponses, CheckCommitExistsData, CheckCommitExistsErrors, CheckCommitExistsResponse, CheckCommitExistsResponses, CheckDomainStatusData, CheckDomainStatusErrors, CheckDomainStatusResponse, CheckDomainStatusResponses, CheckExplorerSupportData, CheckExplorerSupportErrors, CheckExplorerSupportResponse, CheckExplorerSupportResponses, CheckForUpdateData, CheckForUpdateError, CheckForUpdateErrors, CheckForUpdateResponse, CheckForUpdateResponses, CheckIpBlockedData, CheckIpBlockedError, CheckIpBlockedErrors, CheckIpBlockedResponses, CheckProviderDeletionSafetyData, CheckProviderDeletionSafetyErrors, CheckProviderDeletionSafetyResponse, CheckProviderDeletionSafetyResponses, ChildBackupEntryResponse, ChildBackupListResponse, ChunkUploadOptionsData, ChunkUploadOptionsResponse, ChunkUploadOptionsResponses, CleanupExpiredBackupsData, CleanupExpiredBackupsError, CleanupExpiredBackupsErrors, CleanupExpiredBackupsRequest, CleanupExpiredBackupsResponse, CleanupExpiredBackupsResponses, ClearPreviewPasswordData, ClearPreviewPasswordErrors, ClearPreviewPasswordResponse, ClearPreviewPasswordResponses, CliDeviceApproveData, CliDeviceApproveErrors, CliDeviceApproveRequest, CliDeviceApproveResponse, CliDeviceApproveResponse2, CliDeviceApproveResponses, CliDeviceDenyData, CliDeviceDenyErrors, CliDeviceDenyResponse, CliDeviceDenyResponses, CliDeviceLookupData, CliDeviceLookupErrors, CliDeviceLookupResponse, CliDeviceLookupResponse2, CliDeviceLookupResponses, CliDevicePollData, CliDevicePollErrors, CliDevicePollRequest, CliDevicePollResponse, CliDevicePollResponse2, CliDevicePollResponses, CliDeviceStartData, CliDeviceStartErrors, CliDeviceStartRequest, CliDeviceStartResponse, CliDeviceStartResponse2, CliDeviceStartResponses, ClientOptions, CliLoginRequest, CliLogoutData, CliLogoutErrors, CliLogoutResponse, CliLogoutResponses, CloudflareConfig, CloudProvider, ClusterCapacity, ClusterDnsSettings, ClusterHealthReportResponse, ClusterMemberHealthResponse, ClusterMemberRequest, CmdBody, CmdData, CmdErrors, CmdInner, CmdKillBody, CmdKillData, CmdKillErrors, CmdKillResponse, CmdKillResponses, CmdLogsData, CmdLogsErrors, CmdLogsResponses, CmdResponse, CmdResponse2, CmdResponses, CommitExistsResponse, CommitInfo, CommitListResponse, Comparator, ComposePublicPort, ConfirmPendingActionData, ConfirmPendingActionErrors, ConfirmPendingActionResponse, ConfirmPendingActionResponses, ConnectionListQuery, ConnectionListResponse, ConnectionResponse, ConnectionTestResult, ConsoleEventPayload, ContainerActionResponse, ContainerDetailResponse, ContainerEnvironmentVariableValueResponse, ContainerInfoResponse, ContainerInventoryItem, ContainerListResponse, ContainerLogSettings, ContainerLogsQuery, ContainerMetricHistoryPoint, ContainerMetricsGetHistoryData, ContainerMetricsGetHistoryErrors, ContainerMetricsGetHistoryResponse, ContainerMetricsGetHistoryResponses, ContainerMetricsHistoryQuery, ContainerMetricsResponse, ContainerResponse, ContainerRuntimeInfo, ContainerStatsSample, ContentPart, ContextLine, ContextLogsRequest, ContextLogsResponse, ConversationDetailResponse, ConversationResponse, ConversationsQueryParams, ConversationSummary, CopyBlobRequest, CostAnalysis, CreateAgentData, CreateAgentErrors, CreateAgentResponse, CreateAgentResponses, CreateAlertData, CreateAlertError, CreateAlertErrors, CreateAlertResponse, CreateAlertResponses, CreateAlertRuleData, CreateAlertRuleErrors, CreateAlertRuleRequest, CreateAlertRuleResponse, CreateAlertRuleResponses, CreateApiKeyData, CreateApiKeyErrors, CreateApiKeyRequest, CreateApiKeyResponse, CreateApiKeyResponse2, CreateApiKeyResponses, CreateBackupScheduleData, CreateBackupScheduleError, CreateBackupScheduleErrors, CreateBackupScheduleRequest, CreateBackupScheduleResponse, CreateBackupScheduleResponses, CreateBitbucketProviderData, CreateBitbucketProviderErrors, CreateBitbucketProviderResponse, CreateBitbucketProviderResponses, CreateBitbucketRequest, CreateCloudflareProviderData, CreateCloudflareProviderErrors, CreateCloudflareProviderRequest, CreateCloudflareProviderResponse, CreateCloudflareProviderResponses, CreateConversationData, CreateConversationErrors, CreateConversationRequest, CreateConversationResponse, CreateConversationResponses, CreateCustomDomainData, CreateCustomDomainErrors, CreateCustomDomainResponse, CreateCustomDomainResponses, CreateDashboardData, CreateDashboardError, CreateDashboardErrors, CreateDashboardRequest, CreateDashboardResponse, CreateDashboardResponses, CreateDeploymentTokenData, CreateDeploymentTokenErrors, CreateDeploymentTokenRequest, CreateDeploymentTokenResponse, CreateDeploymentTokenResponse2, CreateDeploymentTokenResponses, CreateDnsProviderData, CreateDnsProviderErrors, CreateDnsProviderRequest, CreateDnsProviderResponse, CreateDnsProviderResponses, CreateDomainData, CreateDomainErrors, CreateDomainRequest, CreateDomainResponse, CreateDomainResponses, CreatedResource, CreateDsnData, CreateDsnErrors, CreateDsnRequest, CreateDsnResponse, CreateDsnResponses, CreateEmailDomainData, CreateEmailDomainErrors, CreateEmailDomainRequest, CreateEmailDomainResponse, CreateEmailDomainResponses, CreateEmailProviderData, CreateEmailProviderErrors, CreateEmailProviderRequest, CreateEmailProviderResponse, CreateEmailProviderResponses, CreateEnvironmentData, CreateEnvironmentErrors, CreateEnvironmentRequest, CreateEnvironmentResponse, CreateEnvironmentResponses, CreateEnvironmentVariableData, CreateEnvironmentVariableErrors, CreateEnvironmentVariableRequest, CreateEnvironmentVariableResponse, CreateEnvironmentVariableResponses, CreateExternalServiceRequest, CreateFlagData, CreateFlagErrors, CreateFlagRequest, CreateFlagResponse, CreateFlagResponses, CreateFunnelData, CreateFunnelErrors, CreateFunnelRequest, CreateFunnelResponse, CreateFunnelResponse2, CreateFunnelResponses, CreateFunnelStep, CreateGenericProviderData, CreateGenericProviderErrors, CreateGenericProviderResponse, CreateGenericProviderResponses, CreateGenericRequest, CreateGiteaPatProviderData, CreateGiteaPatProviderErrors, CreateGiteaPatProviderResponse, CreateGiteaPatProviderResponses, CreateGiteaPatRequest, CreateGithubPatProviderData, CreateGithubPatProviderErrors, CreateGithubPatProviderResponse, CreateGithubPatProviderResponses, CreateGitHubPatRequest, CreateGitlabOauthProviderData, CreateGitlabOauthProviderErrors, CreateGitlabOauthProviderResponse, CreateGitlabOauthProviderResponses, CreateGitLabOAuthRequest, CreateGitlabPatProviderData, CreateGitlabPatProviderErrors, CreateGitlabPatProviderResponse, CreateGitlabPatProviderResponses, CreateGitLabPatRequest, CreateGitProviderData, CreateGitProviderErrors, CreateGitProviderResponse, CreateGitProviderResponses, CreateGlobalMcpData, CreateGlobalMcpErrors, CreateGlobalMcpResponse, CreateGlobalMcpResponses, CreateGlobalSkillData, CreateGlobalSkillErrors, CreateGlobalSkillResponse, CreateGlobalSkillResponses, CreateIncidentData, CreateIncidentErrors, CreateIncidentRequest, CreateIncidentResponse, CreateIncidentResponses, CreateIntegrationBody, CreateIpAccessControlData, CreateIpAccessControlError, CreateIpAccessControlErrors, CreateIpAccessControlRequest, CreateIpAccessControlResponse, CreateIpAccessControlResponses, CreateMcpData, CreateMcpErrors, CreateMcpRequest, CreateMcpResponse, CreateMcpResponses, CreateMetricAlertRequest, CreateMonitorData, CreateMonitorErrors, CreateMonitorRequest, CreateMonitorResponse, CreateMonitorResponses, CreateNotificationEmailProviderData, CreateNotificationEmailProviderErrors, CreateNotificationEmailProviderRequest, CreateNotificationEmailProviderResponse, CreateNotificationEmailProviderResponses, CreateNotificationProviderData, CreateNotificationProviderErrors, CreateNotificationProviderResponse, CreateNotificationProviderResponses, CreateOidcProviderData, CreateOidcProviderErrors, CreateOidcProviderRequest, CreateOidcProviderResponse, CreateOidcProviderResponses, CreateOidcRoleMappingData, CreateOidcRoleMappingRequest, CreateOidcRoleMappingResponse, CreateOidcRoleMappingResponses, CreateOrRecreateOrderData, CreateOrRecreateOrderErrors, CreateOrRecreateOrderResponse, CreateOrRecreateOrderResponses, CreatePlanData, CreatePlanErrors, CreatePlanRequest, CreatePlanResponse, CreatePlanResponse2, CreatePlanResponses, CreatePrData, CreatePrErrors, CreateProjectAccessRequest, CreateProjectData, CreateProjectErrors, CreateProjectFromTemplateData, CreateProjectFromTemplateErrors, CreateProjectFromTemplateRequest, CreateProjectFromTemplateResponse, CreateProjectFromTemplateResponse2, CreateProjectFromTemplateResponses, CreateProjectReleaseData, CreateProjectReleaseErrors, CreateProjectReleaseResponse, CreateProjectReleaseResponses, CreateProjectRequest, CreateProjectResponse, CreateProjectResponses, CreateProjectSecretData, CreateProjectSecretErrors, CreateProjectSecretRequest, CreateProjectSecretResponse, CreateProjectSecretResponses, CreateProviderKeyData, CreateProviderKeyError, CreateProviderKeyErrors, CreateProviderKeyRequest, CreateProviderKeyResponse, CreateProviderKeyResponses, CreateProviderRequest, CreatePrResponse, CreatePrResponse2, CreatePrResponses, CreateReleaseData, CreateReleaseErrors, CreateReleaseResponse, CreateReleaseResponses, CreateRouteData, CreateRouteErrors, CreateRouteRequest, CreateRouteResponse, CreateRouteResponses, CreateS3SourceData, CreateS3SourceError, CreateS3SourceErrors, CreateS3SourceRequest, CreateS3SourceResponse, CreateS3SourceResponses, CreateSandboxBody, CreateSandboxData, CreateSandboxErrors, CreateSandboxResponse, CreateSandboxResponses, CreateServiceData, CreateServiceErrors, CreateServiceResponse, CreateServiceResponses, CreateSkillData, CreateSkillErrors, CreateSkillRequest, CreateSkillResponse, CreateSkillResponses, CreateSlackProviderData, CreateSlackProviderErrors, CreateSlackProviderRequest, CreateSlackProviderResponse, CreateSlackProviderResponses, CreateTeamData, CreateTeamErrors, CreateTeamMemberRequest, CreateTeamRequest, CreateTeamResponse, CreateTeamResponses, CreateUserData, CreateUserErrors, CreateUserRequest, CreateUserResponse, CreateUserResponses, CreateWebhookData, CreateWebhookErrors, CreateWebhookProviderData, CreateWebhookProviderErrors, CreateWebhookProviderRequest, CreateWebhookProviderResponse, CreateWebhookProviderResponses, CreateWebhookRequestBody, CreateWebhookResponse, CreateWebhookResponses, CronExecutionInfo, CronInfo, CrossProjectSiblingRef, CrossProjectTraceResponse, CurrentStatusResponse, CustomDomainRequest, CustomDomainResponse, CustomerMovementResponse, DashboardLayout, DashboardProjectsAnalyticsQuery, DashboardProjectsAnalyticsResponse, DashboardSection, DashboardTile, DatabaseMetricsResponse, DatabaseMetricsRow, DataImplication, DataImplicationSeverity, DeactivateApiKeyData, DeactivateApiKeyErrors, DeactivateApiKeyResponse, DeactivateApiKeyResponses, DeactivateConnectionData, DeactivateConnectionErrors, DeactivateConnectionResponses, DeactivateProviderData, DeactivateProviderErrors, DeactivateProviderResponses, DeleteAgentData, DeleteAgentErrors, DeleteAgentResponse, DeleteAgentResponses, DeleteAlertData, DeleteAlertError, DeleteAlertErrors, DeleteAlertResponse, DeleteAlertResponses, DeleteAlertRuleData, DeleteAlertRuleErrors, DeleteAlertRuleResponse, DeleteAlertRuleResponses, DeleteApiKeyData, DeleteApiKeyErrors, DeleteApiKeyResponse, DeleteApiKeyResponses, DeleteBackupData, DeleteBackupError, DeleteBackupErrors, DeleteBackupResponse, DeleteBackupResponses, DeleteBackupScheduleData, DeleteBackupScheduleError, DeleteBackupScheduleErrors, DeleteBackupScheduleResponse, DeleteBackupScheduleResponses, DeleteBlobRequest, DeleteBlobResponse, DeleteConnectionData, DeleteConnectionErrors, DeleteConnectionResponse, DeleteConnectionResponses, DeleteCustomDomainData, DeleteCustomDomainErrors, DeleteCustomDomainResponse, DeleteCustomDomainResponses, DeleteDashboardData, DeleteDashboardError, DeleteDashboardErrors, DeleteDashboardResponse, DeleteDashboardResponses, DeleteDeploymentTokenData, DeleteDeploymentTokenErrors, DeleteDeploymentTokenResponse, DeleteDeploymentTokenResponses, DeleteDnsProviderData, DeleteDnsProviderErrors, DeleteDnsProviderResponse, DeleteDnsProviderResponses, DeleteDomainData, DeleteDomainErrors, DeleteDomainResponse, DeleteDomainResponses, DeleteEmailDomainData, DeleteEmailDomainErrors, DeleteEmailDomainResponse, DeleteEmailDomainResponses, DeleteEmailProviderData, DeleteEmailProviderErrors, DeleteEmailProviderResponse, DeleteEmailProviderResponses, DeleteEnvironmentData, DeleteEnvironmentDomainData, DeleteEnvironmentDomainErrors, DeleteEnvironmentDomainResponse, DeleteEnvironmentDomainResponses, DeleteEnvironmentErrors, DeleteEnvironmentResponse, DeleteEnvironmentResponses, DeleteEnvironmentVariableData, DeleteEnvironmentVariableErrors, DeleteEnvironmentVariableResponse, DeleteEnvironmentVariableResponses, DeleteExternalImageData, DeleteExternalImageErrors, DeleteExternalImageResponse, DeleteExternalImageResponses, DeleteFunnelData, DeleteFunnelErrors, DeleteFunnelResponses, DeleteGitProviderData, DeleteGitProviderErrors, DeleteGitProviderResponse, DeleteGitProviderResponses, DeleteGlobalMcpData, DeleteGlobalMcpErrors, DeleteGlobalMcpResponse, DeleteGlobalMcpResponses, DeleteGlobalSkillData, DeleteGlobalSkillErrors, DeleteGlobalSkillResponse, DeleteGlobalSkillResponses, DeleteIpAccessControlData, DeleteIpAccessControlError, DeleteIpAccessControlErrors, DeleteIpAccessControlResponse, DeleteIpAccessControlResponses, DeleteMcpData, DeleteMcpErrors, DeleteMcpResponse, DeleteMcpResponses, DeleteMonitorData, DeleteMonitorErrors, DeleteMonitorResponse, DeleteMonitorResponses, DeleteNotificationProviderData, DeleteNotificationProviderErrors, DeleteNotificationProviderResponse, DeleteNotificationProviderResponses, DeleteOidcProviderData, DeleteOidcProviderResponse, DeleteOidcProviderResponses, DeleteOidcRoleMappingData, DeleteOidcRoleMappingResponse, DeleteOidcRoleMappingResponses, DeletePreferencesData, DeletePreferencesErrors, DeletePreferencesResponse, DeletePreferencesResponses, DeleteProjectData, DeleteProjectErrors, DeleteProjectResponse, DeleteProjectResponses, DeleteProjectSecretData, DeleteProjectSecretErrors, DeleteProjectSecretResponse, DeleteProjectSecretResponses, DeleteProviderKeyData, DeleteProviderKeyError, DeleteProviderKeyErrors, DeleteProviderKeyResponse, DeleteProviderKeyResponses, DeleteProviderSafelyData, DeleteProviderSafelyErrors, DeleteProviderSafelyResponse, DeleteProviderSafelyResponses, DeleteReleaseSourceFilesData, DeleteReleaseSourceFilesErrors, DeleteReleaseSourceFilesResponse, DeleteReleaseSourceFilesResponses, DeleteReleaseSourceMapsData, DeleteReleaseSourceMapsErrors, DeleteReleaseSourceMapsResponse, DeleteReleaseSourceMapsResponses, DeleteResponse, DeleteRouteData, DeleteRouteErrors, DeleteRouteResponse, DeleteRouteResponses, DeleteS3SourceData, DeleteS3SourceError, DeleteS3SourceErrors, DeleteS3SourceResponse, DeleteS3SourceResponses, DeleteScanData, DeleteScanError, DeleteScanErrors, DeleteScanResponse, DeleteScanResponses, DeleteSecretData, DeleteSecretErrors, DeleteSecretResponse, DeleteSecretResponses, DeleteServiceData, DeleteServiceErrors, DeleteServiceResponse, DeleteServiceResponses, DeleteSessionReplayData, DeleteSessionReplayError, DeleteSessionReplayErrors, DeleteSessionReplayResponses, DeleteSkillData, DeleteSkillErrors, DeleteSkillResponse, DeleteSkillResponses, DeleteSourceMapData, DeleteSourceMapErrors, DeleteSourceMapResponse, DeleteSourceMapResponses, DeleteStaticBundleData, DeleteStaticBundleErrors, DeleteStaticBundleResponse, DeleteStaticBundleResponses, DeleteTeamData, DeleteTeamErrors, DeleteTeamResponse, DeleteTeamResponses, DeleteUserData, DeleteUserErrors, DeleteUserResponse, DeleteUserResponses, DeleteWebhookData, DeleteWebhookErrors, DeleteWebhookResponse, DeleteWebhookResponses, DelRequest, DelResponse, DeployFromImageData, DeployFromImageErrors, DeployFromImageRequest, DeployFromImageResponse, DeployFromImageResponses, DeployFromImageUploadData, DeployFromImageUploadErrors, DeployFromImageUploadQuery, DeployFromImageUploadResponse, DeployFromImageUploadResponses, DeployFromStaticData, DeployFromStaticErrors, DeployFromStaticRequest, DeployFromStaticResponse, DeployFromStaticResponses, DeployFromUploadedSourceData, DeployFromUploadedSourceErrors, DeployFromUploadedSourceResponse, DeployFromUploadedSourceResponses, DeploymentConfig, DeploymentConfigSnapshot, DeploymentConfiguration, DeploymentContainerLogContentResponse, DeploymentContainerLogResponse, DeploymentContainerLogsListResponse, DeploymentEnvironmentResponse, DeploymentJobResponse, DeploymentJobsResponse, DeploymentListResponse, DeploymentMetadata, DeploymentMetricsGetLatestData, DeploymentMetricsGetLatestErrors, DeploymentMetricsGetLatestResponse, DeploymentMetricsGetLatestResponses, DeploymentMetricsGetRangeData, DeploymentMetricsGetRangeErrors, DeploymentMetricsGetRangeResponse, DeploymentMetricsGetRangeResponses, DeploymentMetricsToggleData, DeploymentMetricsToggleErrors, DeploymentMetricsToggleResponses, DeploymentResponse, DeploymentStateResponse, DeploymentStrategy, DeploymentTokenListResponse, DeploymentTokenResponse, DestroySandboxData, DestroySandboxErrors, DestroySandboxResponse, DestroySandboxResponses, DetachScheduleServiceData, DetachScheduleServiceError, DetachScheduleServiceErrors, DetachScheduleServiceResponse, DetachScheduleServiceResponses, DetectionConfig, DetectPublicPresetsData, DetectPublicPresetsErrors, DetectPublicPresetsResponse, DetectPublicPresetsResponses, DeviceCount, DigestSections, Direction, DisableBackupScheduleData, DisableBackupScheduleErrors, DisableBackupScheduleResponse, DisableBackupScheduleResponses, DisableBlobResponse, DisableKvResponse, DisableMfaData, DisableMfaErrors, DisableMfaRequest, DisableMfaResponse, DisableMfaResponses, DiscoverRequest, DiscoverResponse, DiscoverWorkloadsData, DiscoverWorkloadsErrors, DiscoverWorkloadsResponse, DiscoverWorkloadsResponses, DiskInfo, DiskSpaceAlert, DiskSpaceAlertSettings, DiskSpaceCheckResult, DnsAckRequest, DnsAckResponse, DnsChallengeRecordResult, DnsChangesResponse, DnsCompletionResponse, DnsLookupError, DnsLookupRequest, DnsLookupResponse, DnsProviderCredentials, DnsProviderResponse, DnsProviderSettings, DnsProviderSettingsMasked, DnsProviderType, DnsRecord, DnsRecordChange, DnsRecordContent, DnsRecordResponse, DnsRecordSetupResult, DnsRecordStatusResponse, DnsZone, DockerComposePresetConfig, DockerfilePresetConfig, DockerfileVariant, DockerRegistrySettings, DockerRegistrySettingsMasked, DomainAction, DomainChallengeResponse, DomainData, DomainEnvironmentResponse, DomainError, DomainErrors, DomainPlan, DomainResponse, DomainResponse2, DomainResponses, DownloadGlobalSkillArchiveData, DownloadGlobalSkillArchiveErrors, DownloadGlobalSkillArchiveResponse, DownloadGlobalSkillArchiveResponses, DownloadObjectData, DownloadObjectErrors, DownloadObjectResponse, DownloadObjectResponses, DownloadSkillArchiveData, DownloadSkillArchiveErrors, DownloadSkillArchiveResponse, DownloadSkillArchiveResponses, DrainNodeResponse, DrainStatusResponse, DropArchiveUpload, DropInspectionResponse, DropOffPoint, DropPresetCandidate, EmailConfig, EmailDomainResponse, EmailDomainWithDnsResponse, EmailProviderResponse, EmailProviderTypeRoute, EmailRequest, EmailResponse, EmailStatsResponse, EmailStatusData, EmailStatusErrors, EmailStatusResponse, EmailStatusResponse2, EmailStatusResponses, EmailTrackingResponse, EmailTrackingSetupResponse, EmailTrackingStatusResponse, EmbeddingData, EmbeddingInput, EmbeddingRequest, EmbeddingResponse, EmbeddingsData, EmbeddingsError, EmbeddingsErrors, EmbeddingsResponse, EmbeddingsResponses, EmbeddingUsage, EnableBackupScheduleData, EnableBackupScheduleErrors, EnableBackupScheduleResponse, EnableBackupScheduleResponses, EnableBlobRequest, EnableBlobResponse, EnableKvRequest, EnableKvResponse, EnablePgStatStatementsResponse, EndpointDto, EnqueuedJob, EnrichVisitorData, EnrichVisitorErrors, EnrichVisitorRequest, EnrichVisitorResponse, EnrichVisitorResponse2, EnrichVisitorResponses, EnrollmentTokenInfo, EnrollmentTokenListResponse, EntityInfoResponse, EntityResponse, EnvironmentConfiguration, EnvironmentDomainResponse, EnvironmentInfo, EnvironmentResponse, EnvironmentVariable, EnvironmentVariableInfo, EnvironmentVariableResponse, EnvironmentVariableValueResponse, EnvVarInput, EnvVarIntegrationInfo, EnvVarResponse, EnvVarTemplateResponse, ErrorDashboardStatsQuery, ErrorDashboardStatsResponse, ErrorEventResponse, ErrorGroupResponse, ErrorGroupStatsResponse, ErrorResponse, ErrorRow, ErrorTimeSeriesDataResponse, ErrorTimeSeriesQuery, EventActivityBucket, EventBreakdown, EventBrowserStats, EventCount, EventCountryStats, EventDetailQuery, EventDetailResponse, EventEntriesQuery, EventEntriesResponse, EventEntryInfo, EventKind, EventMetricsPayload, EventReferrerStats, EventsCountQuery, EventsResponse, EventTimeline, EventTimelineQuery, EventType, EventTypeBreakdown, EventTypeBreakdownQuery, EventTypeResponse, EventTypesResponse, EventVisitorInfo, EventVisitorsQuery, EventVisitorsResponse, ExecBody, ExecData, ExecDetachedData, ExecDetachedErrors, ExecDetachedResponse, ExecDetachedResponse2, ExecDetachedResponses, ExecErrors, ExecResponse, ExecResponse2, ExecResponses, ExecuteDeploymentOperationData, ExecuteDeploymentOperationErrors, ExecuteDeploymentOperationResponse, ExecuteDeploymentOperationResponses, ExecuteImportData, ExecuteImportErrors, ExecuteImportRequest, ExecuteImportResponse, ExecuteImportResponse2, ExecuteImportResponses, ExecuteOperationRequest, ExpireRequest, ExpireResponse, ExplorerSupportResponse, ExtendTimeoutBody, ExtendTimeoutData, ExtendTimeoutErrors, ExtendTimeoutResponse, ExtendTimeoutResponses, ExternalImageResponse, ExternalServiceBackupResponse, ExternalServiceDetails, ExternalServiceEnablePgStatStatementsData, ExternalServiceEnablePgStatStatementsErrors, ExternalServiceEnablePgStatStatementsResponse, ExternalServiceEnablePgStatStatementsResponses, ExternalServiceInfo, ExternalServiceMetricsByDatabaseData, ExternalServiceMetricsByDatabaseErrors, ExternalServiceMetricsByDatabaseResponse, ExternalServiceMetricsByDatabaseResponses, ExternalServiceMetricsCreateAlertRuleData, ExternalServiceMetricsCreateAlertRuleErrors, ExternalServiceMetricsCreateAlertRuleResponse, ExternalServiceMetricsCreateAlertRuleResponses, ExternalServiceMetricsDeleteAlertRuleData, ExternalServiceMetricsDeleteAlertRuleErrors, ExternalServiceMetricsDeleteAlertRuleResponse, ExternalServiceMetricsDeleteAlertRuleResponses, ExternalServiceMetricsGetAlertRulesData, ExternalServiceMetricsGetAlertRulesErrors, ExternalServiceMetricsGetAlertRulesResponse, ExternalServiceMetricsGetAlertRulesResponses, ExternalServiceMetricsGetLatestData, ExternalServiceMetricsGetLatestErrors, ExternalServiceMetricsGetLatestResponse, ExternalServiceMetricsGetLatestResponses, ExternalServiceMetricsGetRangeData, ExternalServiceMetricsGetRangeErrors, ExternalServiceMetricsGetRangeResponse, ExternalServiceMetricsGetRangeResponses, ExternalServiceMetricsStatusData, ExternalServiceMetricsStatusErrors, ExternalServiceMetricsStatusResponse, ExternalServiceMetricsStatusResponses, ExternalServiceMetricsToggleData, ExternalServiceMetricsToggleErrors, ExternalServiceMetricsToggleResponses, ExternalServiceMetricsUpdateAlertRuleData, ExternalServiceMetricsUpdateAlertRuleErrors, ExternalServiceMetricsUpdateAlertRuleResponse, ExternalServiceMetricsUpdateAlertRuleResponses, ExternalServiceResetPgStatStatementsData, ExternalServiceResetPgStatStatementsErrors, ExternalServiceResetPgStatStatementsResponse, ExternalServiceResetPgStatStatementsResponses, ExternalServiceSummary, FieldResponse, FinalizeOrderData, FinalizeOrderErrors, FinalizeOrderResponse, FinalizeOrderResponses, FinalizeProjectReleaseData, FinalizeProjectReleaseErrors, FinalizeProjectReleaseResponse, FinalizeProjectReleaseResponses, FindConversationData, FindConversationErrors, FindConversationResponse, FindConversationResponses, FiringSeriesEntry, FlagEnvironmentResponse, FlagListResponse, FlagResponse, FlagSnapshot, FlagSnapshotResponse, FlagValueType, ForecastAlgorithm, ForecastParams, FullError, FullEvent, FullRequest, FunnelMetricsResponse, FunnelResponse, GatewayStatus, GenAiEvent, GenAiSpanDetail, GenAiTraceDetailResponse, GenAiTraceSummariesResponse, GenAiTraceSummary, GeneralStatsQuery, GeneralStatsResponse, GenerateDockerfileRequest, GenerateDockerfileResponse, GenerateJoinTokenData, GenerateJoinTokenErrors, GenerateJoinTokenResponse, GenerateJoinTokenResponse2, GenerateJoinTokenResponses, GeneratePresetDockerfileData, GeneratePresetDockerfileErrors, GeneratePresetDockerfileResponse, GeneratePresetDockerfileResponses, GeoLocationResponse, GeoRestrictionsConfig, GetAccessInfoData, GetAccessInfoErrors, GetAccessInfoResponse, GetAccessInfoResponses, GetActiveVisitorsData, GetActiveVisitorsErrors, GetActiveVisitorsResponse, GetActiveVisitorsResponses, GetActivityGraphData, GetActivityGraphErrors, GetActivityGraphResponse, GetActivityGraphResponses, GetAdminGateData, GetAdminGateErrors, GetAdminGateResponse, GetAdminGateResponses, GetAgentData, GetAgentErrors, GetAgentResponse, GetAgentResponses, GetAggregatedBucketsData, GetAggregatedBucketsErrors, GetAggregatedBucketsResponse, GetAggregatedBucketsResponses, GetAiAgentBreakdownData, GetAiAgentBreakdownError, GetAiAgentBreakdownErrors, GetAiAgentBreakdownResponse, GetAiAgentBreakdownResponses, GetAiAgentPagesData, GetAiAgentPagesError, GetAiAgentPagesErrors, GetAiAgentPagesResponse, GetAiAgentPagesResponses, GetAiAgentTimelineData, GetAiAgentTimelineError, GetAiAgentTimelineErrors, GetAiAgentTimelineResponse, GetAiAgentTimelineResponses, GetAiPageBreakdownData, GetAiPageBreakdownError, GetAiPageBreakdownErrors, GetAiPageBreakdownResponse, GetAiPageBreakdownResponses, GetAiStatusBreakdownData, GetAiStatusBreakdownError, GetAiStatusBreakdownErrors, GetAiStatusBreakdownResponse, GetAiStatusBreakdownResponses, GetAlertData, GetAlertError, GetAlertErrors, GetAlertResponse, GetAlertResponses, GetAlertRuleData, GetAlertRuleErrors, GetAlertRuleResponse, GetAlertRuleResponses, GetAllRepositoriesByNameData, GetAllRepositoriesByNameErrors, GetAllRepositoriesByNameResponse, GetAllRepositoriesByNameResponses, GetAnalyticsActiveVisitorsData, GetAnalyticsActiveVisitorsErrors, GetAnalyticsActiveVisitorsResponse, GetAnalyticsActiveVisitorsResponses, GetAnalyticsEventsCountData, GetAnalyticsEventsCountErrors, GetAnalyticsEventsCountResponse, GetAnalyticsEventsCountResponses, GetAnalyticsSessionEventsData, GetAnalyticsSessionEventsErrors, GetAnalyticsSessionEventsResponse, GetAnalyticsSessionEventsResponses, GetAnalyticsVisitorSessionsData, GetAnalyticsVisitorSessionsErrors, GetAnalyticsVisitorSessionsResponse, GetAnalyticsVisitorSessionsResponses, GetApiKeyData, GetApiKeyErrors, GetApiKeyPermissionsData, GetApiKeyPermissionsErrors, GetApiKeyPermissionsResponse, GetApiKeyPermissionsResponses, GetApiKeyResponse, GetApiKeyResponses, GetAuditLogData, GetAuditLogErrors, GetAuditLogResponse, GetAuditLogResponses, GetBackupData, GetBackupError, GetBackupErrors, GetBackupResponse, GetBackupResponses, GetBackupScheduleData, GetBackupScheduleErrors, GetBackupScheduleResponse, GetBackupScheduleResponses, GetBranchesByRepositoryIdData, GetBranchesByRepositoryIdErrors, GetBranchesByRepositoryIdResponse, GetBranchesByRepositoryIdResponses, GetBucketedIncidentsData, GetBucketedIncidentsErrors, GetBucketedIncidentsResponse, GetBucketedIncidentsResponses, GetBucketedStatusData, GetBucketedStatusErrors, GetBucketedStatusResponse, GetBucketedStatusResponses, GetChallengeTokenData, GetChallengeTokenErrors, GetChallengeTokenResponse, GetChallengeTokenResponses, GetChatReadinessData, GetChatReadinessErrors, GetChatReadinessResponse, GetChatReadinessResponses, GetCliStatusData, GetCliStatusErrors, GetCliStatusResponses, GetClusterHealthData, GetClusterHealthErrors, GetClusterHealthResponse, GetClusterHealthResponses, GetClusterMemberData, GetClusterMemberErrors, GetClusterMemberResponse, GetClusterMemberResponses, GetCmdData, GetCmdErrors, GetCmdResponse, GetCmdResponses, GetContainerDetailData, GetContainerDetailErrors, GetContainerDetailResponse, GetContainerDetailResponses, GetContainerEnvironmentVariableData, GetContainerEnvironmentVariableErrors, GetContainerEnvironmentVariableResponse, GetContainerEnvironmentVariableResponses, GetContainerInfoData, GetContainerInfoErrors, GetContainerInfoResponse, GetContainerInfoResponses, GetContainerLogsByIdData, GetContainerLogsByIdErrors, GetContainerLogsData, GetContainerLogsErrors, GetContainerMetricsData, GetContainerMetricsErrors, GetContainerMetricsResponse, GetContainerMetricsResponses, GetConversationData, GetConversationDetailData, GetConversationDetailError, GetConversationDetailErrors, GetConversationDetailResponse, GetConversationDetailResponses, GetConversationErrors, GetConversationResponse, GetConversationResponses, GetConversationsData, GetConversationsError, GetConversationsErrors, GetConversationsResponse, GetConversationsResponses, GetCronByIdData, GetCronByIdErrors, GetCronByIdResponse, GetCronByIdResponses, GetCronExecutionsData, GetCronExecutionsErrors, GetCronExecutionsResponse, GetCronExecutionsResponses, GetCrossProjectTraceSiblingsData, GetCrossProjectTraceSiblingsError, GetCrossProjectTraceSiblingsErrors, GetCrossProjectTraceSiblingsResponse, GetCrossProjectTraceSiblingsResponses, GetCurrentMonitorStatusData, GetCurrentMonitorStatusErrors, GetCurrentMonitorStatusResponse, GetCurrentMonitorStatusResponses, GetCurrentUserData, GetCurrentUserErrors, GetCurrentUserResponse, GetCurrentUserResponses, GetCustomDomainData, GetCustomDomainErrors, GetCustomDomainResponse, GetCustomDomainResponses, GetDashboardData, GetDashboardError, GetDashboardErrors, GetDashboardProjectsAnalyticsData, GetDashboardProjectsAnalyticsErrors, GetDashboardProjectsAnalyticsResponse, GetDashboardProjectsAnalyticsResponses, GetDashboardResponse, GetDashboardResponses, GetDeliveryData, GetDeliveryErrors, GetDeliveryResponse, GetDeliveryResponses, GetDeploymentContainerLogContentData, GetDeploymentContainerLogContentErrors, GetDeploymentContainerLogContentResponse, GetDeploymentContainerLogContentResponses, GetDeploymentData, GetDeploymentErrors, GetDeploymentJobLogsData, GetDeploymentJobLogsErrors, GetDeploymentJobLogsResponse, GetDeploymentJobLogsResponses, GetDeploymentJobsData, GetDeploymentJobsErrors, GetDeploymentJobsResponse, GetDeploymentJobsResponses, GetDeploymentOperationsData, GetDeploymentOperationsErrors, GetDeploymentOperationsResponse, GetDeploymentOperationsResponses, GetDeploymentOperationStatusData, GetDeploymentOperationStatusErrors, GetDeploymentOperationStatusResponse, GetDeploymentOperationStatusResponses, GetDeploymentResponse, GetDeploymentResponses, GetDeploymentsParams, GetDeploymentTokenData, GetDeploymentTokenErrors, GetDeploymentTokenResponse, GetDeploymentTokenResponses, GetDiskStatusData, GetDiskStatusErrors, GetDiskStatusResponse, GetDiskStatusResponses, GetDnsChangesData, GetDnsChangesErrors, GetDnsChangesResponse, GetDnsChangesResponses, GetDnsProviderData, GetDnsProviderErrors, GetDnsProviderResponse, GetDnsProviderResponses, GetDomainByHostData, GetDomainByHostErrors, GetDomainByHostResponse, GetDomainByHostResponses, GetDomainByIdData, GetDomainByIdErrors, GetDomainByIdResponse, GetDomainByIdResponses, GetDomainByNameData, GetDomainByNameErrors, GetDomainByNameResponse, GetDomainByNameResponses, GetDomainData, GetDomainDnsRecordsData, GetDomainDnsRecordsErrors, GetDomainDnsRecordsResponse, GetDomainDnsRecordsResponses, GetDomainErrors, GetDomainOrderData, GetDomainOrderErrors, GetDomainOrderResponse, GetDomainOrderResponses, GetDomainResponse, GetDomainResponses, GetEmailData, GetEmailErrors, GetEmailEventsData, GetEmailEventsErrors, GetEmailEventsResponse, GetEmailEventsResponses, GetEmailLinksData, GetEmailLinksErrors, GetEmailLinksResponse, GetEmailLinksResponses, GetEmailProviderData, GetEmailProviderErrors, GetEmailProviderResponse, GetEmailProviderResponses, GetEmailResponse, GetEmailResponses, GetEmailStatsData, GetEmailStatsErrors, GetEmailStatsResponse, GetEmailStatsResponses, GetEmailTrackingData, GetEmailTrackingErrors, GetEmailTrackingResponse, GetEmailTrackingResponses, GetEmailTrackingStatusData, GetEmailTrackingStatusErrors, GetEmailTrackingStatusResponse, GetEmailTrackingStatusResponses, GetEntityInfoData, GetEntityInfoErrors, GetEntityInfoResponse, GetEntityInfoResponses, GetEnvironmentCronsData, GetEnvironmentCronsErrors, GetEnvironmentCronsResponse, GetEnvironmentCronsResponses, GetEnvironmentData, GetEnvironmentDomainsData, GetEnvironmentDomainsErrors, GetEnvironmentDomainsResponse, GetEnvironmentDomainsResponses, GetEnvironmentErrors, GetEnvironmentResponse, GetEnvironmentResponses, GetEnvironmentsData, GetEnvironmentsErrors, GetEnvironmentsResponse, GetEnvironmentsResponses, GetEnvironmentVariablesData, GetEnvironmentVariablesErrors, GetEnvironmentVariablesQuery, GetEnvironmentVariablesResponse, GetEnvironmentVariablesResponses, GetEnvironmentVariableValueData, GetEnvironmentVariableValueErrors, GetEnvironmentVariableValueResponse, GetEnvironmentVariableValueResponses, GetErrorDashboardStatsData, GetErrorDashboardStatsErrors, GetErrorDashboardStatsResponse, GetErrorDashboardStatsResponses, GetErrorEventData, GetErrorEventErrors, GetErrorEventResponse, GetErrorEventResponses, GetErrorGroupData, GetErrorGroupErrors, GetErrorGroupResponse, GetErrorGroupResponses, GetErrorStatsData, GetErrorStatsErrors, GetErrorStatsResponse, GetErrorStatsResponses, GetErrorTimeSeriesData, GetErrorTimeSeriesErrors, GetErrorTimeSeriesResponse, GetErrorTimeSeriesResponses, GetEventDetailData, GetEventDetailErrors, GetEventDetailResponse, GetEventDetailResponses, GetEventEntriesData, GetEventEntriesErrors, GetEventEntriesResponse, GetEventEntriesResponses, GetEventsCountData, GetEventsCountErrors, GetEventsCountResponse, GetEventsCountResponses, GetEventsTimelineData, GetEventsTimelineErrors, GetEventsTimelineResponse, GetEventsTimelineResponses, GetEventTypeBreakdownData, GetEventTypeBreakdownErrors, GetEventTypeBreakdownResponse, GetEventTypeBreakdownResponses, GetEventVisitorsData, GetEventVisitorsErrors, GetEventVisitorsResponse, GetEventVisitorsResponses, GetExternalImageData, GetExternalImageErrors, GetExternalImageResponse, GetExternalImageResponses, GetFileData, GetFileErrors, GetFileResponse, GetFileResponses, GetFlagData, GetFlagErrors, GetFlagResponse, GetFlagResponses, GetFlagSnapshotData, GetFlagSnapshotErrors, GetFlagSnapshotResponse, GetFlagSnapshotResponses, GetFunnelMetricsData, GetFunnelMetricsErrors, GetFunnelMetricsQuery, GetFunnelMetricsResponse, GetFunnelMetricsResponses, GetGenaiTraceData, GetGenaiTraceError, GetGenaiTraceErrors, GetGenaiTraceResponse, GetGenaiTraceResponses, GetGeneralStatsData, GetGeneralStatsErrors, GetGeneralStatsResponse, GetGeneralStatsResponses, GetGitProviderData, GetGitProviderErrors, GetGitProviderResponse, GetGitProviderResponses, GetGlobalEventsData, GetGlobalEventsErrors, GetGlobalEventsResponse, GetGlobalEventsResponses, GetGlobalEventStatsData, GetGlobalEventStatsErrors, GetGlobalEventStatsResponse, GetGlobalEventStatsResponses, GetGlobalMcpData, GetGlobalMcpErrors, GetGlobalMcpResponse, GetGlobalMcpResponses, GetGlobalSandboxStatusData, GetGlobalSandboxStatusErrors, GetGlobalSandboxStatusResponse, GetGlobalSandboxStatusResponses, GetGlobalSkillData, GetGlobalSkillErrors, GetGlobalSkillResponse, GetGlobalSkillResponses, GetGroupedPageMetricsData, GetGroupedPageMetricsError, GetGroupedPageMetricsErrors, GetGroupedPageMetricsResponse, GetGroupedPageMetricsResponses, GetHealthData, GetHealthError, GetHealthErrors, GetHealthResponse, GetHealthResponses, GetHourlyVisitsData, GetHourlyVisitsErrors, GetHourlyVisitsResponse, GetHourlyVisitsResponses, GetHttpChallengeDebugData, GetHttpChallengeDebugErrors, GetHttpChallengeDebugResponse, GetHttpChallengeDebugResponses, GetImportStatusData, GetImportStatusErrors, GetImportStatusResponse, GetImportStatusResponses, GetIncidentData, GetIncidentErrors, GetIncidentResponse, GetIncidentResponses, GetIncidentUpdatesData, GetIncidentUpdatesErrors, GetIncidentUpdatesResponse, GetIncidentUpdatesResponses, GetIpAccessControlData, GetIpAccessControlError, GetIpAccessControlErrors, GetIpAccessControlResponse, GetIpAccessControlResponses, GetIpGeolocationData, GetIpGeolocationError, GetIpGeolocationErrors, GetIpGeolocationResponse, GetIpGeolocationResponses, GetJoinTokenStatusData, GetJoinTokenStatusErrors, GetJoinTokenStatusResponse, GetJoinTokenStatusResponses, GetLastDeploymentData, GetLastDeploymentErrors, GetLastDeploymentResponse, GetLastDeploymentResponses, GetLatestScanData, GetLatestScanError, GetLatestScanErrors, GetLatestScanResponse, GetLatestScanResponses, GetLatestScansPerEnvironmentData, GetLatestScansPerEnvironmentError, GetLatestScansPerEnvironmentErrors, GetLatestScansPerEnvironmentResponse, GetLatestScansPerEnvironmentResponses, GetLiveVisitorsListData, GetLiveVisitorsListErrors, GetLiveVisitorsListResponse, GetLiveVisitorsListResponses, GetLogContextData, GetLogContextError, GetLogContextErrors, GetLogContextResponse, GetLogContextResponses, GetMcpData, GetMcpErrors, GetMcpResponse, GetMcpResponses, GetMetricsOverTimeData, GetMetricsOverTimeError, GetMetricsOverTimeErrors, GetMetricsOverTimeResponse, GetMetricsOverTimeResponses, GetMonitorData, GetMonitorErrors, GetMonitorResponse, GetMonitorResponses, GetNotificationProviderData, GetNotificationProviderErrors, GetNotificationProviderResponse, GetNotificationProviderResponses, GetOnDemandCertStatusData, GetOnDemandCertStatusErrors, GetOnDemandCertStatusResponse, GetOnDemandCertStatusResponses, GetOrCreateDsnData, GetOrCreateDsnErrors, GetOrCreateDsnRequest, GetOrCreateDsnResponse, GetOrCreateDsnResponses, GetPageFlowData, GetPageFlowErrors, GetPageFlowResponse, GetPageFlowResponses, GetPageHourlySessionsData, GetPageHourlySessionsErrors, GetPageHourlySessionsResponse, GetPageHourlySessionsResponses, GetPagePathDetailData, GetPagePathDetailErrors, GetPagePathDetailResponse, GetPagePathDetailResponses, GetPagePathsData, GetPagePathsErrors, GetPagePathsResponse, GetPagePathsResponses, GetPagePathsSparklinesData, GetPagePathsSparklinesErrors, GetPagePathsSparklinesResponse, GetPagePathsSparklinesResponses, GetPagePathVisitorsData, GetPagePathVisitorsErrors, GetPagePathVisitorsResponse, GetPagePathVisitorsResponses, GetPendingActionData, GetPendingActionErrors, GetPendingActionResponse, GetPendingActionResponses, GetPerformanceMetricsData, GetPerformanceMetricsError, GetPerformanceMetricsErrors, GetPerformanceMetricsResponse, GetPerformanceMetricsResponses, GetPgUpgradeData, GetPgUpgradeErrors, GetPgUpgradeLogsData, GetPgUpgradeLogsErrors, GetPgUpgradeLogsResponse, GetPgUpgradeLogsResponses, GetPgUpgradeResponse, GetPgUpgradeResponses, GetPipelineStatsData, GetPipelineStatsError, GetPipelineStatsErrors, GetPipelineStatsResponse, GetPipelineStatsResponses, GetPlatformInfoData, GetPlatformInfoErrors, GetPlatformInfoResponse, GetPlatformInfoResponses, GetPostgresWalHealthData, GetPostgresWalHealthErrors, GetPostgresWalHealthResponse, GetPostgresWalHealthResponses, GetPreferencesData, GetPreferencesErrors, GetPreferencesResponse, GetPreferencesResponses, GetPreviewGatewayLogsData, GetPreviewGatewayLogsResponse, GetPreviewGatewayLogsResponses, GetPreviewGatewaySettingsData, GetPreviewGatewaySettingsResponse, GetPreviewGatewaySettingsResponses, GetPreviewGatewayStatusData, GetPreviewGatewayStatusResponse, GetPreviewGatewayStatusResponses, GetPricingData, GetPricingError, GetPricingErrors, GetPricingResponse, GetPricingResponses, GetPrivateIpData, GetPrivateIpErrors, GetPrivateIpResponses, GetProjectAlarmsSummaryData, GetProjectAlarmsSummaryErrors, GetProjectAlarmsSummaryResponse, GetProjectAlarmsSummaryResponses, GetProjectBySlugData, GetProjectBySlugErrors, GetProjectBySlugResponse, GetProjectBySlugResponses, GetProjectData, GetProjectDeploymentsData, GetProjectDeploymentsErrors, GetProjectDeploymentsResponse, GetProjectDeploymentsResponses, GetProjectErrors, GetProjectResponse, GetProjectResponses, GetProjectsData, GetProjectSecretsQuery, GetProjectsErrors, GetProjectServiceEnvironmentVariablesData, GetProjectServiceEnvironmentVariablesErrors, GetProjectServiceEnvironmentVariablesResponse, GetProjectServiceEnvironmentVariablesResponses, GetProjectSessionReplaysData, GetProjectSessionReplaysError, GetProjectSessionReplaysErrors, GetProjectSessionReplaysQuery, GetProjectSessionReplaysResponse, GetProjectSessionReplaysResponse2, GetProjectSessionReplaysResponses, GetProjectsHealthData, GetProjectsHealthError, GetProjectsHealthErrors, GetProjectsHealthResponse, GetProjectsHealthResponses, GetProjectsMonitorHealthData, GetProjectsMonitorHealthErrors, GetProjectsMonitorHealthResponse, GetProjectsMonitorHealthResponses, GetProjectsResponse, GetProjectsResponses, GetProjectStatisticsData, GetProjectStatisticsErrors, GetProjectStatisticsResponse, GetProjectStatisticsResponses, GetProjectTemplateData, GetProjectTemplateErrors, GetProjectTemplateResponse, GetProjectTemplateResponses, GetPropertyBreakdownData, GetPropertyBreakdownErrors, GetPropertyBreakdownResponse, GetPropertyBreakdownResponses, GetPropertyTimelineData, GetPropertyTimelineErrors, GetPropertyTimelineResponse, GetPropertyTimelineResponses, GetProviderConnectionsData, GetProviderConnectionsErrors, GetProviderConnectionsResponse, GetProviderConnectionsResponses, GetProviderMetadataData, GetProviderMetadataErrors, GetProviderMetadataResponse, GetProviderMetadataResponses, GetProvidersMetadataData, GetProvidersMetadataErrors, GetProvidersMetadataResponse, GetProvidersMetadataResponses, GetProxyLogByIdData, GetProxyLogByIdError, GetProxyLogByIdErrors, GetProxyLogByIdResponse, GetProxyLogByIdResponses, GetProxyLogByRequestIdData, GetProxyLogByRequestIdError, GetProxyLogByRequestIdErrors, GetProxyLogByRequestIdResponse, GetProxyLogByRequestIdResponses, GetProxyLogsData, GetProxyLogsError, GetProxyLogsErrors, GetProxyLogsResponse, GetProxyLogsResponses, GetPublicBranchesData, GetPublicBranchesErrors, GetPublicBranchesResponse, GetPublicBranchesResponses, GetPublicIpData, GetPublicIpErrors, GetPublicIpResponses, GetPublicRepositoryData, GetPublicRepositoryErrors, GetPublicRepositoryResponse, GetPublicRepositoryResponses, GetQuotaData, GetQuotaError, GetQuotaErrors, GetQuotaResponse, GetQuotaResponses, GetRecentActivityData, GetRecentActivityErrors, GetRecentActivityResponse, GetRecentActivityResponses, GetRemoteExternalImageData, GetRemoteExternalImageErrors, GetRemoteExternalImageResponse, GetRemoteExternalImageResponses, GetRepositoryBranchesData, GetRepositoryBranchesErrors, GetRepositoryBranchesResponse, GetRepositoryBranchesResponses, GetRepositoryByIdData, GetRepositoryByIdErrors, GetRepositoryByIdResponse, GetRepositoryByIdResponses, GetRepositoryByNameData, GetRepositoryByNameErrors, GetRepositoryByNameResponse, GetRepositoryByNameResponses, GetRepositoryPresetByNameData, GetRepositoryPresetByNameErrors, GetRepositoryPresetByNameResponse, GetRepositoryPresetByNameResponses, GetRepositoryPresetLiveData, GetRepositoryPresetLiveErrors, GetRepositoryPresetLiveResponse, GetRepositoryPresetLiveResponses, GetRepositoryTagsData, GetRepositoryTagsErrors, GetRepositoryTagsResponse, GetRepositoryTagsResponses, GetRequest, GetResolvedEnvironmentVariablesData, GetResolvedEnvironmentVariablesErrors, GetResolvedEnvironmentVariablesResponse, GetResolvedEnvironmentVariablesResponses, GetResolvedEnvironmentVariableValueData, GetResolvedEnvironmentVariableValueErrors, GetResolvedEnvironmentVariableValueResponse, GetResolvedEnvironmentVariableValueResponses, GetResponse, GetRestoreCapabilitiesData, GetRestoreCapabilitiesError, GetRestoreCapabilitiesErrors, GetRestoreCapabilitiesResponse, GetRestoreCapabilitiesResponses, GetRestoreRunData, GetRestoreRunError, GetRestoreRunErrors, GetRestoreRunResponse, GetRestoreRunResponses, GetRouteData, GetRouteErrors, GetRouteResponse, GetRouteResponses, GetRunData, GetRunErrors, GetRunResponse, GetRunResponses, GetRunWithLogsData, GetRunWithLogsErrors, GetRunWithLogsResponse, GetRunWithLogsResponses, GetS3CredentialsData, GetS3CredentialsErrors, GetS3CredentialsResponse, GetS3CredentialsResponses, GetS3SourceData, GetS3SourceError, GetS3SourceErrors, GetS3SourceResponse, GetS3SourceResponses, GetSandboxData, GetSandboxErrors, GetSandboxResponse, GetSandboxResponses, GetSandboxStatusData, GetSandboxStatusErrors, GetSandboxStatusResponse, GetSandboxStatusResponses, GetScanByDeploymentData, GetScanByDeploymentError, GetScanByDeploymentErrors, GetScanByDeploymentResponse, GetScanByDeploymentResponses, GetScanData, GetScanError, GetScanErrors, GetScanResponse, GetScanResponses, GetScanVulnerabilitiesData, GetScanVulnerabilitiesError, GetScanVulnerabilitiesErrors, GetScanVulnerabilitiesResponse, GetScanVulnerabilitiesResponses, GetServiceBySlugData, GetServiceBySlugErrors, GetServiceBySlugResponse, GetServiceBySlugResponses, GetServiceData, GetServiceEnvironmentVariableData, GetServiceEnvironmentVariableErrors, GetServiceEnvironmentVariableResponse, GetServiceEnvironmentVariableResponses, GetServiceEnvironmentVariablesData, GetServiceEnvironmentVariablesErrors, GetServiceEnvironmentVariablesResponse, GetServiceEnvironmentVariablesResponses, GetServiceErrors, GetServiceHealthStatusData, GetServiceHealthStatusErrors, GetServiceHealthStatusResponse, GetServiceHealthStatusResponses, GetServicePreviewEnvironmentVariableNamesData, GetServicePreviewEnvironmentVariableNamesErrors, GetServicePreviewEnvironmentVariableNamesResponse, GetServicePreviewEnvironmentVariableNamesResponses, GetServicePreviewEnvironmentVariablesMaskedData, GetServicePreviewEnvironmentVariablesMaskedErrors, GetServicePreviewEnvironmentVariablesMaskedResponse, GetServicePreviewEnvironmentVariablesMaskedResponses, GetServiceResponse, GetServiceResponses, GetServiceRuntimeData, GetServiceRuntimeErrors, GetServiceRuntimeResponse, GetServiceRuntimeResponses, GetServiceStatsData, GetServiceStatsErrors, GetServiceStatsResponse, GetServiceStatsResponses, GetServiceTypeParametersData, GetServiceTypeParametersErrors, GetServiceTypeParametersResponses, GetServiceTypesData, GetServiceTypesErrors, GetServiceTypesResponse, GetServiceTypesResponses, GetSessionDetailsData, GetSessionDetailsErrors, GetSessionDetailsResponse, GetSessionDetailsResponses, GetSessionEventsData, GetSessionEventsErrors, GetSessionEventsResponse, GetSessionEventsResponses, GetSessionLogsData, GetSessionLogsErrors, GetSessionLogsResponse, GetSessionLogsResponses, GetSessionReplayData, GetSessionReplayError, GetSessionReplayErrors, GetSessionReplayEventsData, GetSessionReplayEventsError, GetSessionReplayEventsErrors, GetSessionReplayEventsResponse, GetSessionReplayEventsResponses, GetSessionReplayResponse, GetSessionReplayResponse2, GetSessionReplayResponses, GetSettingsData, GetSettingsErrors, GetSettingsResponse, GetSettingsResponses, GetSkillData, GetSkillErrors, GetSkillResponse, GetSkillResponses, GetSlowQueriesData, GetSlowQueriesErrors, GetSlowQueriesResponse, GetSlowQueriesResponses, GetStaticBundleData, GetStaticBundleErrors, GetStaticBundleResponse, GetStaticBundleResponses, GetStatusOverviewData, GetStatusOverviewErrors, GetStatusOverviewResponse, GetStatusOverviewResponses, GetTagsByRepositoryIdData, GetTagsByRepositoryIdErrors, GetTagsByRepositoryIdResponse, GetTagsByRepositoryIdResponses, GetTeamData, GetTeamErrors, GetTeamResponse, GetTeamResponses, GetTimeBucketStatsData, GetTimeBucketStatsError, GetTimeBucketStatsErrors, GetTimeBucketStatsResponse, GetTimeBucketStatsResponses, GetTodayStatsData, GetTodayStatsError, GetTodayStatsErrors, GetTodayStatsResponse, GetTodayStatsResponses, GetTraceData, GetTraceError, GetTraceErrors, GetTraceResponse, GetTraceResponses, GetUnifiedTraceData, GetUnifiedTraceError, GetUnifiedTraceErrors, GetUnifiedTraceResponse, GetUnifiedTraceResponses, GetUniqueCountsData, GetUniqueCountsErrors, GetUniqueCountsResponse, GetUniqueCountsResponses, GetUniqueEventsData, GetUniqueEventsErrors, GetUniqueEventsQuery, GetUniqueEventsResponse, GetUniqueEventsResponses, GetUpdateCapabilityData, GetUpdateCapabilityErrors, GetUpdateCapabilityResponse, GetUpdateCapabilityResponses, GetUpdateStatusData, GetUpdateStatusErrors, GetUpdateStatusResponse, GetUpdateStatusResponses, GetUptimeHistoryData, GetUptimeHistoryErrors, GetUptimeHistoryResponse, GetUptimeHistoryResponses, GetUsageByProviderData, GetUsageByProviderError, GetUsageByProviderErrors, GetUsageByProviderResponse, GetUsageByProviderResponses, GetUsageRecentData, GetUsageRecentError, GetUsageRecentErrors, GetUsageRecentResponse, GetUsageRecentResponses, GetUsageSummaryData, GetUsageSummaryError, GetUsageSummaryErrors, GetUsageSummaryResponse, GetUsageSummaryResponses, GetUsageTimeseriesData, GetUsageTimeseriesError, GetUsageTimeseriesErrors, GetUsageTimeseriesResponse, GetUsageTimeseriesResponses, GetUsageTopModelsData, GetUsageTopModelsError, GetUsageTopModelsErrors, GetUsageTopModelsResponse, GetUsageTopModelsResponses, GetVisitorByGuidData, GetVisitorByGuidErrors, GetVisitorByGuidResponse, GetVisitorByGuidResponses, GetVisitorByIdData, GetVisitorByIdErrors, GetVisitorByIdResponse, GetVisitorByIdResponses, GetVisitorDetailsData, GetVisitorDetailsErrors, GetVisitorDetailsResponse, GetVisitorDetailsResponses, GetVisitorFacetsData, GetVisitorFacetsErrors, GetVisitorFacetsResponse, GetVisitorFacetsResponses, GetVisitorInfoData, GetVisitorInfoErrors, GetVisitorInfoResponse, GetVisitorInfoResponses, GetVisitorJourneyData, GetVisitorJourneyErrors, GetVisitorJourneyResponse, GetVisitorJourneyResponses, GetVisitorsData, GetVisitorsErrors, GetVisitorSessionsData, GetVisitorSessionsError, GetVisitorSessionsErrors, GetVisitorSessionsQuery, GetVisitorSessionsResponse, GetVisitorSessionsResponse2, GetVisitorSessionsResponses, GetVisitorsResponse, GetVisitorsResponses, GetVisitorStatsData, GetVisitorStatsErrors, GetVisitorStatsResponse, GetVisitorStatsResponses, GetWebhookData, GetWebhookErrors, GetWebhookResponse, GetWebhookResponses, GitPushEvent, GitRefResponse, GitSourcePlan, GlobalConversationResponse, GlobalEventStatsResponse, GlobalMrrResponse, GlobalRecentEventResponse, GlobalRevenueSummaryResponse, GrantProjectAccessData, GrantProjectAccessErrors, GrantProjectAccessResponse, GrantProjectAccessResponses, GroupedPageMetric, GroupedPageMetricsQuery, GroupedPageMetricsResponse, HandleGitProviderOauthCallbackData, HandleGitProviderOauthCallbackErrors, HasAnalyticsEventsData, HasAnalyticsEventsErrors, HasAnalyticsEventsResponse, HasAnalyticsEventsResponse2, HasAnalyticsEventsResponses, HasErrorGroupsData, HasErrorGroupsErrors, HasErrorGroupsResponse, HasErrorGroupsResponse2, HasErrorGroupsResponses, HasEventsQuery, HasEventsResponse, HasMetricsQuery, HasMetricsResponse, HasPerformanceMetricsData, HasPerformanceMetricsError, HasPerformanceMetricsErrors, HasPerformanceMetricsResponse, HasPerformanceMetricsResponses, HealthCheckConfiguration, HealthCheckEntryResponse, HealthResponse, HealthStatus, HealthSummary, HeartbeatApiRequest, HeartbeatResponse, HierarchyLevel, HistogramSummary, HostnameChange, HostnamePreviewResponse, HourlyPageSessions, HourlyVisitsQuery, HttpChallengeDebugResponse, ImportCredentials, ImportExecutionStatus, ImportExternalServiceData, ImportExternalServiceErrors, ImportExternalServiceRequest, ImportExternalServiceResponse, ImportExternalServiceResponses, ImportOutcomeResponse, ImportPlan, ImportRowErrorResponse, ImportSelector, ImportSource, ImportSourceCapabilities, ImportSourceInfo, ImportStatusResponse, IncidentBucket, IncidentBucketedResponse, IncidentResponse, IncidentUpdateResponse, IncrRequest, IncrResponse, IngestLogsByPathData, IngestLogsByPathError, IngestLogsByPathErrors, IngestLogsByPathResponses, IngestLogsData, IngestLogsError, IngestLogsErrors, IngestLogsResponses, IngestMetricsByPathData, IngestMetricsByPathError, IngestMetricsByPathErrors, IngestMetricsByPathResponses, IngestMetricsData, IngestMetricsError, IngestMetricsErrors, IngestMetricsResponses, IngestSentryEnvelopeData, IngestSentryEnvelopeErrors, IngestSentryEnvelopeResponses, IngestSentryEventData, IngestSentryEventErrors, IngestSentryEventResponse, IngestSentryEventResponses, IngestTracesByPathData, IngestTracesByPathError, IngestTracesByPathErrors, IngestTracesByPathResponses, IngestTracesData, IngestTracesError, IngestTracesErrors, IngestTracesResponses, InitAuthResponse, InitSessionReplayData, InitSessionReplayError, InitSessionReplayErrors, InitSessionReplayResponse, InitSessionReplayResponses, Insight, InsightSeverity, InsightsResponse, InsightStatus, InspectDropArchiveData, InspectDropArchiveErrors, InspectDropArchiveResponse, InspectDropArchiveResponses, IntegrationResponse, IpAccessControlQuery, IpAccessControlResponse, JobLogsData, JobLogsErrors, JobLogsResponses, JobStatusData, JobStatusErrors, JobStatusResponse, JobStatusResponse2, JobStatusResponses, JobSummaryResponse, JoinTokenStatusResponse, JourneyEvent, JourneySession, KeysRequest, KeysResponse, KillJobBody, KillJobData, KillJobErrors, KillJobResponse, KillJobResponses, KnownAiAgentsResponse, KvDelData, KvDelErrors, KvDelResponse, KvDelResponses, KvDisableData, KvDisableErrors, KvDisableResponse, KvDisableResponses, KvEnableData, KvEnableErrors, KvEnableResponse, KvEnableResponses, KvExpireData, KvExpireErrors, KvExpireResponse, KvExpireResponses, KvGetData, KvGetErrors, KvGetResponse, KvGetResponses, KvIncrData, KvIncrErrors, KvIncrResponse, KvIncrResponses, KvKeysData, KvKeysErrors, KvKeysResponse, KvKeysResponses, KvSetData, KvSetErrors, KvSetResponse, KvSetResponses, KvStatusData, KvStatusErrors, KvStatusResponse, KvStatusResponse2, KvStatusResponses, KvTtlData, KvTtlErrors, KvTtlResponse, KvTtlResponses, KvUpdateData, KvUpdateErrors, KvUpdateResponse, KvUpdateResponses, LatestRunForSourceData, LatestRunForSourceErrors, LatestRunForSourceResponse, LatestRunForSourceResponses, LemonSqueezyConfig, LetsEncryptSettings, LineContext, LinkCustomDomainToCertificateData, LinkCustomDomainToCertificateErrors, LinkCustomDomainToCertificateResponse, LinkCustomDomainToCertificateResponses, LinkServiceRequest, LinkServiceToProjectData, LinkServiceToProjectErrors, LinkServiceToProjectResponse, LinkServiceToProjectResponses, ListAgentRunsData, ListAgentRunsErrors, ListAgentRunsResponse, ListAgentRunsResponses, ListAgentsData, ListAgentsErrors, ListAgentsResponse, ListAgentsResponse2, ListAgentsResponses, ListAiProvidersData, ListAiProvidersErrors, ListAiProvidersResponse, ListAiProvidersResponses, ListAlertRulesData, ListAlertRulesErrors, ListAlertRulesResponse, ListAlertRulesResponses, ListAlertsData, ListAlertsError, ListAlertsErrors, ListAlertsResponse, ListAlertsResponses, ListAllConversationsData, ListAllConversationsErrors, ListAllConversationsResponse, ListAllConversationsResponses, ListAllRunsData, ListAllRunsErrors, ListAllRunsResponse, ListAllRunsResponses, ListApiKeysData, ListApiKeysErrors, ListApiKeysQuery, ListApiKeysResponse, ListApiKeysResponses, ListAuditLogsData, ListAuditLogsErrors, ListAuditLogsQuery, ListAuditLogsResponse, ListAuditLogsResponses, ListAvailableContainersData, ListAvailableContainersErrors, ListAvailableContainersResponse, ListAvailableContainersResponses, ListBackupAlertsData, ListBackupAlertsError, ListBackupAlertsErrors, ListBackupAlertsResponse, ListBackupAlertsResponses, ListBackupChildrenData, ListBackupChildrenError, ListBackupChildrenErrors, ListBackupChildrenResponse, ListBackupChildrenResponses, ListBackupSchedulesData, ListBackupSchedulesError, ListBackupSchedulesErrors, ListBackupSchedulesResponse, ListBackupSchedulesResponses, ListBackupsForScheduleData, ListBackupsForScheduleErrors, ListBackupsForScheduleResponse, ListBackupsForScheduleResponses, ListBlobsQuery, ListBlobsResponse, ListCommitsByRepositoryIdData, ListCommitsByRepositoryIdErrors, ListCommitsByRepositoryIdResponse, ListCommitsByRepositoryIdResponses, ListConnectionsData, ListConnectionsErrors, ListConnectionsResponse, ListConnectionsResponses, ListContainersAtPathData, ListContainersAtPathErrors, ListContainersAtPathResponse, ListContainersAtPathResponses, ListContainersData, ListContainersErrors, ListContainersResponse, ListContainersResponses, ListConversationsData, ListConversationsErrors, ListConversationsResponse, ListConversationsResponses, ListCustomDomainsForProjectData, ListCustomDomainsForProjectErrors, ListCustomDomainsForProjectResponse, ListCustomDomainsForProjectResponses, ListCustomDomainsResponse, ListDashboardsData, ListDashboardsError, ListDashboardsErrors, ListDashboardsResponse, ListDashboardsResponses, ListDeliveriesData, ListDeliveriesErrors, ListDeliveriesResponse, ListDeliveriesResponses, ListDeploymentContainerLogsData, ListDeploymentContainerLogsErrors, ListDeploymentContainerLogsResponse, ListDeploymentContainerLogsResponses, ListDeploymentTokensData, ListDeploymentTokensErrors, ListDeploymentTokensQuery, ListDeploymentTokensResponse, ListDeploymentTokensResponses, ListDnsProvidersData, ListDnsProvidersErrors, ListDnsProvidersResponse, ListDnsProvidersResponses, ListDomainsData, ListDomainsErrors, ListDomainsResponse, ListDomainsResponse2, ListDomainsResponses, ListDsnsData, ListDsnsErrors, ListDsnsResponse, ListDsnsResponses, ListEmailDomainsData, ListEmailDomainsErrors, ListEmailDomainsResponse, ListEmailDomainsResponses, ListEmailProvidersData, ListEmailProvidersErrors, ListEmailProvidersResponse, ListEmailProvidersResponses, ListEmailsData, ListEmailsErrors, ListEmailsResponse, ListEmailsResponses, ListEnrollmentTokensData, ListEnrollmentTokensErrors, ListEnrollmentTokensResponse, ListEnrollmentTokensResponses, ListEntitiesData, ListEntitiesErrors, ListEntitiesQuery, ListEntitiesResponse, ListEntitiesResponses, ListErrorEventsData, ListErrorEventsErrors, ListErrorEventsQuery, ListErrorEventsResponse, ListErrorEventsResponses, ListErrorGroupsData, ListErrorGroupsErrors, ListErrorGroupsQuery, ListErrorGroupsResponse, ListErrorGroupsResponses, ListEventsData, ListEventsResponse, ListEventsResponses, ListEventTypesData, ListEventTypesResponse, ListEventTypesResponses, ListExternalImagesData, ListExternalImagesErrors, ListExternalImagesResponse, ListExternalImagesResponses, ListExternalPluginsData, ListExternalPluginsErrors, ListExternalPluginsResponse, ListExternalPluginsResponses, ListExternalServiceBackupsData, ListExternalServiceBackupsError, ListExternalServiceBackupsErrors, ListExternalServiceBackupsResponse, ListExternalServiceBackupsResponses, ListFlagsData, ListFlagsErrors, ListFlagsResponse, ListFlagsResponses, ListFunnelsData, ListFunnelsErrors, ListFunnelsResponse, ListFunnelsResponses, ListGitProvidersData, ListGitProvidersErrors, ListGitProvidersResponse, ListGitProvidersResponses, ListGlobalMcpsData, ListGlobalMcpsErrors, ListGlobalMcpsResponse, ListGlobalMcpsResponses, ListGlobalSkillsData, ListGlobalSkillsErrors, ListGlobalSkillsResponse, ListGlobalSkillsResponses, ListIncidentsData, ListIncidentsErrors, ListIncidentsResponses, ListInsightsData, ListInsightsError, ListInsightsErrors, ListInsightsResponse, ListInsightsResponses, ListIpAccessControlData, ListIpAccessControlError, ListIpAccessControlErrors, ListIpAccessControlResponse, ListIpAccessControlResponses, ListJobsData, ListJobsErrors, ListJobsResponse, ListJobsResponse2, ListJobsResponses, ListKnownAiAgentsData, ListKnownAiAgentsError, ListKnownAiAgentsErrors, ListKnownAiAgentsResponse, ListKnownAiAgentsResponses, ListManagedDomainsData, ListManagedDomainsErrors, ListManagedDomainsResponse, ListManagedDomainsResponses, ListMcpsData, ListMcpsErrors, ListMcpsResponse, ListMcpsResponse2, ListMcpsResponses, ListMetricLabelKeysData, ListMetricLabelKeysError, ListMetricLabelKeysErrors, ListMetricLabelKeysResponse, ListMetricLabelKeysResponses, ListMetricLabelValuesData, ListMetricLabelValuesError, ListMetricLabelValuesErrors, ListMetricLabelValuesResponse, ListMetricLabelValuesResponses, ListMetricNamesData, ListMetricNamesError, ListMetricNamesErrors, ListMetricNamesResponse, ListMetricNamesResponses, ListModelsData, ListModelsError, ListModelsErrors, ListModelsResponse, ListModelsResponses, ListMonitorsData, ListMonitorsErrors, ListMonitorsResponse, ListMonitorsResponses, ListNotificationProvidersData, ListNotificationProvidersErrors, ListNotificationProvidersResponse, ListNotificationProvidersResponses, ListOidcProvidersData, ListOidcProvidersResponse, ListOidcProvidersResponses, ListOidcProviderUsersData, ListOidcProviderUsersErrors, ListOidcProviderUsersResponse, ListOidcProviderUsersResponses, ListOidcRoleMappingsData, ListOidcRoleMappingsResponse, ListOidcRoleMappingsResponses, ListOnDemandCertsData, ListOnDemandCertsErrors, ListOnDemandCertsResponse, ListOnDemandCertsResponse2, ListOnDemandCertsResponses, ListOrdersData, ListOrdersErrors, ListOrdersResponse, ListOrdersResponse2, ListOrdersResponses, ListPeersData, ListPeersErrors, ListPeersResponse, ListPeersResponses, ListPendingActionsData, ListPendingActionsErrors, ListPendingActionsResponse, ListPendingActionsResponses, ListPgUpgradesData, ListPgUpgradesErrors, ListPgUpgradesResponse, ListPgUpgradesResponses, ListPresetsData, ListPresetsErrors, ListPresetsResponse, ListPresetsResponse2, ListPresetsResponses, ListProjectAccessData, ListProjectAccessErrors, ListProjectAccessResponse, ListProjectAccessResponses, ListProjectAlarmsData, ListProjectAlarmsErrors, ListProjectAlarmsResponse, ListProjectAlarmsResponses, ListProjectScansData, ListProjectScansError, ListProjectScansErrors, ListProjectScansResponse, ListProjectScansResponses, ListProjectSecretsData, ListProjectSecretsErrors, ListProjectSecretsResponse, ListProjectSecretsResponses, ListProjectServicesData, ListProjectServicesErrors, ListProjectServicesResponse, ListProjectServicesResponses, ListProjectTemplatesData, ListProjectTemplatesErrors, ListProjectTemplatesResponse, ListProjectTemplatesResponses, ListProjectTemplateTagsData, ListProjectTemplateTagsErrors, ListProjectTemplateTagsResponse, ListProjectTemplateTagsResponses, ListProviderKeysData, ListProviderKeysError, ListProviderKeysErrors, ListProviderKeysResponse, ListProviderKeysResponses, ListProviderZonesData, ListProviderZonesErrors, ListProviderZonesResponse, ListProviderZonesResponses, ListPublicProvidersData, ListPublicProvidersResponse, ListPublicProvidersResponses, ListReleaseFilesData, ListReleaseFilesErrors, ListReleaseFilesResponse, ListReleaseFilesResponses, ListReleasesData, ListReleasesErrors, ListReleasesResponse, ListReleasesResponses, ListRemoteExternalImagesData, ListRemoteExternalImagesErrors, ListRemoteExternalImagesResponse, ListRemoteExternalImagesResponses, ListRepositoriesByConnectionData, ListRepositoriesByConnectionErrors, ListRepositoriesByConnectionResponse, ListRepositoriesByConnectionResponses, ListRepositoriesByProviderData, ListRepositoriesByProviderErrors, ListRepositoriesByProviderResponse, ListRepositoriesByProviderResponses, ListRestoreRunsForServiceData, ListRestoreRunsForServiceResponse, ListRestoreRunsForServiceResponses, ListRootContainersData, ListRootContainersErrors, ListRootContainersResponse, ListRootContainersResponses, ListRoutesData, ListRoutesErrors, ListRoutesResponse, ListRoutesResponses, ListRunsResponse, ListS3SourcesData, ListS3SourcesError, ListS3SourcesErrors, ListS3SourcesResponse, ListS3SourcesResponses, ListSandboxesData, ListSandboxesResponse, ListSandboxesResponse2, ListSandboxesResponses, ListScansQuery, ListScheduleRunJobsData, ListScheduleRunJobsError, ListScheduleRunJobsErrors, ListScheduleRunJobsResponse, ListScheduleRunJobsResponses, ListScheduleRunsData, ListScheduleRunsError, ListScheduleRunsErrors, ListScheduleRunsResponse, ListScheduleRunsResponses, ListScheduleServicesData, ListScheduleServicesError, ListScheduleServicesErrors, ListScheduleServicesResponse, ListScheduleServicesResponses, ListSecretsData, ListSecretsErrors, ListSecretsResponse, ListSecretsResponse2, ListSecretsResponses, ListServiceHealthStatusesData, ListServiceHealthStatusesErrors, ListServiceHealthStatusesResponse, ListServiceHealthStatusesResponses, ListServiceProjectsData, ListServiceProjectsErrors, ListServiceProjectsResponse, ListServiceProjectsResponses, ListServiceSchedulesData, ListServiceSchedulesError, ListServiceSchedulesErrors, ListServiceSchedulesResponse, ListServiceSchedulesResponses, ListServicesData, ListServicesErrors, ListServicesResponse, ListServicesResponses, ListSkillsData, ListSkillsErrors, ListSkillsResponse, ListSkillsResponse2, ListSkillsResponses, ListSourceBackupsData, ListSourceBackupsError, ListSourceBackupsErrors, ListSourceBackupsResponse, ListSourceBackupsResponses, ListSourceFilesData, ListSourceFilesErrors, ListSourceFilesResponse, ListSourceFilesResponses, ListSourceMapsData, ListSourceMapsErrors, ListSourceMapsResponse, ListSourceMapsResponses, ListSourcesData, ListSourcesErrors, ListSourcesResponse, ListSourcesResponses, ListStaticBundlesData, ListStaticBundlesErrors, ListStaticBundlesResponse, ListStaticBundlesResponses, ListSyncedRepositoriesData, ListSyncedRepositoriesErrors, ListSyncedRepositoriesResponse, ListSyncedRepositoriesResponses, ListTagsResponse, ListTeamMembersData, ListTeamMembersErrors, ListTeamMembersResponse, ListTeamMembersResponses, ListTeamProjectsData, ListTeamProjectsErrors, ListTeamProjectsResponse, ListTeamProjectsResponses, ListTeamsData, ListTeamsErrors, ListTeamsResponse, ListTeamsResponses, ListTemplatesQuery, ListTemplatesResponse, ListUsersData, ListUsersErrors, ListUsersResponse, ListUsersResponses, ListVulnerabilitiesQuery, ListWebhooksData, ListWebhooksErrors, ListWebhooksResponse, ListWebhooksResponses, LiveVisitorInfo, LiveVisitorsListResponse, LocationCount, LocationGranularity, LocationInfo, LoginData, LoginErrors, LoginRequest, LoginResponse, LoginResponses, LogLevel, LogoutData, LogoutErrors, LogoutResponses, LogRecord, LogSearchLine, LogSeverity, LogSource, LogsQuery, LogsResponse, LogStream, LookupDnsARecordsData, LookupDnsARecordsError, LookupDnsARecordsErrors, LookupDnsARecordsResponse, LookupDnsARecordsResponses, ManagedDomainResponse, ManualAction, ManualActionTiming, McpDefinitionResponse, MessageContent, MessagePart, MessageResponse, MeteredMode, MetricAggregation, MetricBucket, MetricDataPoint, MetricsOverTimeResponse, MetricsQuery, MetricsRangeQuery, MetricsStatusResponse, MetricsStoreKind, MetricsSummaryResponse, MetricType, MfaRequiredResponse, MfaSetupResponse, MfaVerificationRequest, MigrationStep, MigrationSummary, MintEnrollmentTokenData, MintEnrollmentTokenErrors, MintEnrollmentTokenRequest, MintEnrollmentTokenResponse, MintEnrollmentTokenResponse2, MintEnrollmentTokenResponses, MiscResult, MkdirBody, MkdirData, MkdirErrors, MkdirResponse, MkdirResponses, ModelInfo, ModelListResponse, ModelPricing, ModelUsage, MonitoringSettings, MonitoringSettingsMasked, MonitorResponse, MonitorStatus, MrrBucketResponse, MultiNodeSettings, MultiNodeSettingsMasked, MxResult, NavEntry, NavSection, NetworkConfiguration, NetworkMode, NixpacksPresetConfig, NixpacksProvider, NodeContainerListResponse, NodeContainerResponse, NodeCostInfo, NodeHeartbeatData, NodeHeartbeatErrors, NodeHeartbeatResponse, NodeHeartbeatResponses, NodeInfoResponse, NodeListResponse, NodeMetricsGetRangeData, NodeMetricsGetRangeErrors, NodeMetricsGetRangeResponse, NodeMetricsGetRangeResponses, NotificationPreferencesResponse, NotificationProviderResponse, ObservabilityCompressionSettings, ObservabilityEvent, ObservabilityFullEventData, ObservabilityFullEventError, ObservabilityFullEventErrors, ObservabilityFullEventResponse, ObservabilityFullEventResponses, ObservabilityListEventsData, ObservabilityListEventsError, ObservabilityListEventsErrors, ObservabilityListEventsResponse, ObservabilityListEventsResponses, ObservabilityRetentionSettings, OidcCallbackData, OidcProviderResponse, OidcProvidersListResponse, OidcProviderSummary, OidcProviderUserResponse, OidcRoleMappingResponse, OidcTestConnectionResponse, OnDemandCertAttemptResponse, OnDemandCertRow, OnDemandTlsSettings, OpenAiError, OpenAiErrorResponse, OperatingSystemCount, OperationResultResponse, OperationResultsResponse, OtelDashboardResponse, OtelDashboardsResponse, OtelMetricAlertRuleResponse, OtelMetricAlertsResponse, OtelMetricLabelKeysResponse, OtelMetricLabelValuesResponse, OtelMetricNamesResponse, OtelMetricsResponse, OutlierAlgorithm, OutlierParams, OverprovisioningAssessment, OverprovisioningVerdict, PageActivityBucket, PageCountryStats, PageFlowEntry, PageFlowQuery, PageFlowResponse, PageHourlySessionsQuery, PageHourlySessionsResponse, PagePathDetailQuery, PagePathDetailResponse, PagePathInfo, PagePathSparkline, PagePathSparklinePoint, PagePathsQuery, PagePathsResponse, PagePathsSparklineQuery, PagePathsSparklineResponse, PagePathVisitorsQuery, PagePathVisitorsResponse, PageReferrerStats, PagesComparisonResponse, PageSessionComparison, PageSessionStats, PageSessionStatsQuery, PageTransition, PageVisit, PageVisitorSession, PaginatedEmailsResponse, PaginatedEntitiesResponse, PaginatedErrorEventsResponse, PaginatedErrorGroupsResponse, PaginatedEventsResponse, PaginatedExternalImagesResponse, PaginatedProjectList, PaginatedStaticBundlesResponse, Pagination, PaginationMeta, PaginationParams, PasswordProtectionConfig, PatchAdminGateData, PatchAdminGateErrors, PatchAdminGateResponse, PatchAdminGateResponses, PatchPreviewGatewaySettingsData, PatchPreviewGatewaySettingsResponse, PatchPreviewGatewaySettingsResponses, PatchSettingsRequest, PathVisitors, PathVisitorsAnalyticsQuery, PathVisitorsResponse, PauseDeploymentData, PauseDeploymentErrors, PauseDeploymentResponse, PauseDeploymentResponses, PauseSandboxData, PauseSandboxErrors, PauseSandboxResponse, PauseSandboxResponses, PeerEntry, PeerListResponse, PendingActionResponse, PerformanceMetricsQuery, PerformanceMetricsResponse, PermissionInfo, PgUpgradeLogResponse, PgUpgradeResponse, PipelineStats, PipelineStatsResponse, PlanComplexity, PlanMetadata, PlanRestoreData, PlanRestoreError, PlanRestoreErrors, PlanRestoreResponse, PlanRestoreResponses, PlanSourceBackup, PlanTarget, PlatformInfo, PluginManifest, PortMapping, PostDnsAckData, PostDnsAckErrors, PostDnsAckResponse, PostDnsAckResponses, PostgresWalHealth, PresetConfigSchema, PresetInfo, PresetResponse, PreviewAlertData, PreviewAlertError, PreviewAlertErrors, PreviewAlertResponse, PreviewAlertResponses, PreviewFunnelMetricsData, PreviewFunnelMetricsErrors, PreviewFunnelMetricsResponse, PreviewFunnelMetricsResponses, PreviewGatewaySettings, PreviewGatewaySettingsMasked, PreviewGatewaySettingsResponse, PreviewHostnameModeData, PreviewHostnameModeErrors, PreviewHostnameModeResponse, PreviewHostnameModeResponses, PreviewShareLinkBody, PreviewShareLinkResponse, PricingResponse, ProblemDetails, ProjectAccessResponse, ProjectConfiguration, ProjectDashboardAnalytics, ProjectDsnResponse, ProjectHealthSummary, ProjectInfo, ProjectMonitorHealth, ProjectPresetResponse, ProjectQuery, ProjectRef, ProjectResponse, ProjectSecretEnvironmentInfo, ProjectSecretResponse, ProjectServiceInfo, ProjectsHealthResponse, ProjectsMonitorHealthResponse, ProjectStatisticsResponse, ProjectStatsBreakdown, ProjectType, ProjectUsageInfoResponse, PromoteClusterMemberData, PromoteClusterMemberErrors, PromoteClusterMemberResponses, PromoteDeploymentData, PromoteDeploymentErrors, PromoteDeploymentRequest, PromoteDeploymentResponse, PromoteDeploymentResponses, PropertyBreakdownItem, PropertyBreakdownQuery, PropertyBreakdownResponse, PropertyColumn, PropertyTimelineItem, PropertyTimelineQuery, PropertyTimelineResponse, Protocol, ProviderCatalogDto, ProviderCatalogResponse, ProviderConfig, ProviderConfigMasked, ProviderDeletionCheckResponse, ProviderDescriptor, ProviderKeyResponse, ProviderMetadata, ProviderResponse, ProviderUsage, ProvisionDomainData, ProvisionDomainErrors, ProvisionDomainResponse, ProvisionDomainResponses, ProvisionResponse, ProxyLogResponse, ProxyLogsPaginatedResponse, PublicHostnameStrategy, PublicPresetResponse, PublicRepositoryInfo, PurgeLogsRequest, PurgeProjectLogsData, PurgeProjectLogsError, PurgeProjectLogsErrors, PurgeProjectLogsResponses, PushedExternalImageResponse, PushExternalImageData, PushExternalImageErrors, PushExternalImageResponse, PushExternalImageResponses, PushImageRequest, QueryDataData, QueryDataErrors, QueryDataRequest, QueryDataResponse, QueryDataResponse2, QueryDataResponses, QueryGenaiTracesData, QueryGenaiTracesError, QueryGenaiTracesErrors, QueryGenaiTracesResponse, QueryGenaiTracesResponses, QueryLogsData, QueryLogsError, QueryLogsErrors, QueryLogsResponse, QueryLogsResponses, QueryMetricsData, QueryMetricsError, QueryMetricsErrors, QueryMetricsResponse, QueryMetricsResponses, QueryTracesData, QueryTracesError, QueryTracesErrors, QueryTracesResponse, QueryTracesResponses, QueryTraceSummariesData, QueryTraceSummariesError, QueryTraceSummariesErrors, QueryTraceSummariesResponse, QueryTraceSummariesResponses, QuotaResponse, RateLimitConfig, RateLimitSettings, ReachabilityStatus, ReadFileData, ReadFileErrors, ReadFileResponse, ReadFileResponse2, ReadFileResponses, ReAnalyzeData, ReAnalyzeErrors, ReAnalyzeResponses, RebuildSandboxImageData, RebuildSandboxImageErrors, RebuildSandboxImageResponses, RecentActivityQuery, RecentActivityResponse, RecentEventResponse, RecentQueryParams, RecordConsoleEventData, RecordConsoleEventErrors, RecordConsoleEventResponses, RecordEventMetricsData, RecordEventMetricsErrors, RecordEventMetricsResponse, RecordEventMetricsResponses, RecordExposureRequest, RecordExposureResponse, RecordFlagExposureData, RecordFlagExposureErrors, RecordFlagExposureResponse, RecordFlagExposureResponses, RecordListResponse, RecordSpeedMetricsData, RecordSpeedMetricsError, RecordSpeedMetricsErrors, RecordSpeedMetricsResponse, RecordSpeedMetricsResponses, RecoveryTarget, ReferrerCount, ReferrersAnalyticsQuery, RefreshRouteTableData, RefreshRouteTableErrors, RefreshRouteTableResponse, RefreshRouteTableResponses, RegenerateDsnData, RegenerateDsnErrors, RegenerateDsnRequest, RegenerateDsnResponse, RegenerateDsnResponses, RegisterExternalImageData, RegisterExternalImageErrors, RegisterExternalImageResponse, RegisterExternalImageResponses, RegisterImageRequest, RegisterNodeApiRequest, RegisterNodeData, RegisterNodeErrors, RegisterNodeResponse, RegisterNodeResponse2, RegisterNodeResponses, RegisterRequest, ReinstallGitlabWebhookData, ReinstallGitlabWebhookErrors, ReinstallGitlabWebhookResponse, ReinstallGitlabWebhookResponses, ReinstallWebhookResponse, RejectPendingActionData, RejectPendingActionErrors, RejectPendingActionResponse, RejectPendingActionResponses, ReleaseCheckResult, ReleaseListResponse, ReloadPluginsData, ReloadPluginsErrors, ReloadPluginsResponse, ReloadPluginsResponses, ReloadResponse, RemoteDeploymentResponse, RemoveClusterMemberData, RemoveClusterMemberErrors, RemoveClusterMemberResponse, RemoveClusterMemberResponses, RemoveManagedDomainData, RemoveManagedDomainErrors, RemoveManagedDomainResponse, RemoveManagedDomainResponses, RemoveNodeResponse, RemoveRoleData, RemoveRoleErrors, RemoveRoleResponse, RemoveRoleResponses, RemoveTeamMemberData, RemoveTeamMemberErrors, RemoveTeamMemberResponse, RemoveTeamMemberResponses, RenameConversationData, RenameConversationErrors, RenameConversationRequest, RenameConversationResponse, RenameConversationResponses, RenewDomainData, RenewDomainErrors, RenewDomainResponse, RenewDomainResponses, RepositoryListQuery, RepositoryListResponse, RepositoryPresetResponse, RepositoryResponse, RepositorySyncStartedResponse, RequestPasswordResetData, RequestPasswordResetErrors, RequestPasswordResetResponse, RequestPasswordResetResponses, RequestRow, RequiredPasswordChangeRequest, RequiredPasswordChangeResponse, ResetPasswordData, ResetPasswordErrors, ResetPasswordRequest, ResetPasswordResponse, ResetPasswordResponses, ResetPgStatStatementsRequest, ResetPgStatStatementsResponse, ResizeSandboxBody, ResizeSandboxData, ResizeSandboxErrors, ResizeSandboxResponse, ResizeSandboxResponses, ResolveAlarmData, ResolveAlarmErrors, ResolveAlarmResponses, ResolvedEnvVarResponse, ResolvedEnvVarSource, ResourceCounts, ResourceFootprint, ResourceInfo, ResourceLimitApplyResult, ResourceLimits, ResourceLimitsResponse, ResourceLimitsUpdateResponse, ResourcesBody, RestartContainerData, RestartContainerErrors, RestartContainerResponse, RestartContainerResponses, RestartPreviewGatewayData, RestartPreviewGatewayResponse, RestartPreviewGatewayResponses, RestartSandboxData, RestartSandboxErrors, RestartSandboxResponse, RestartSandboxResponses, RestoreCapabilities, RestoreCapabilitiesResponse, RestoreFlagData, RestoreFlagErrors, RestoreFlagResponse, RestoreFlagResponses, RestorePlan, RestoreRequestMode, RestoreRunView, RestoreUserData, RestoreUserErrors, RestoreUserResponse, RestoreUserResponses, ResumeDeploymentData, ResumeDeploymentErrors, ResumeDeploymentResponse, ResumeDeploymentResponses, ResumeSandboxData, ResumeSandboxErrors, ResumeSandboxResponse, ResumeSandboxResponses, RetentionCleanupFailure, RetentionCleanupReport, RetryClusterData, RetryClusterErrors, RetryClusterRequest, RetryClusterResponse, RetryClusterResponses, RetryDeliveryData, RetryDeliveryErrors, RetryDeliveryResponse, RetryDeliveryResponses, RetryPgUpgradeData, RetryPgUpgradeErrors, RetryPgUpgradeResponse, RetryPgUpgradeResponses, RetryRunData, RetryRunErrors, RetryRunResponse, RetryRunResponses, RevealGlobalMcpConfigData, RevealGlobalMcpConfigErrors, RevealGlobalMcpConfigResponse, RevealGlobalMcpConfigResponses, RevealMcpConfigData, RevealMcpConfigErrors, RevealMcpConfigResponse, RevealMcpConfigResponses, RevealNotificationProviderConfigData, RevealNotificationProviderConfigErrors, RevealNotificationProviderConfigResponse, RevealNotificationProviderConfigResponses, RevealServiceParameterData, RevealServiceParameterErrors, RevealServiceParameterResponse, RevealServiceParameterResponses, RevenueCreateIntegrationData, RevenueCreateIntegrationErrors, RevenueCreateIntegrationResponse, RevenueCreateIntegrationResponses, RevenueDeleteIntegrationData, RevenueDeleteIntegrationResponse, RevenueDeleteIntegrationResponses, RevenueGlobalEventsData, RevenueGlobalEventsResponse, RevenueGlobalEventsResponses, RevenueImportInvoicesCsvData, RevenueImportInvoicesCsvErrors, RevenueImportInvoicesCsvResponse, RevenueImportInvoicesCsvResponses, RevenueImportSubscriptionsCsvData, RevenueImportSubscriptionsCsvErrors, RevenueImportSubscriptionsCsvResponse, RevenueImportSubscriptionsCsvResponses, RevenueListIntegrationsData, RevenueListIntegrationsResponse, RevenueListIntegrationsResponses, RevenueListProvidersData, RevenueListProvidersResponse, RevenueListProvidersResponses, RevenueMetricsCustomersData, RevenueMetricsCustomersResponse, RevenueMetricsCustomersResponses, RevenueMetricsGlobalMrrData, RevenueMetricsGlobalMrrResponse, RevenueMetricsGlobalMrrResponses, RevenueMetricsGlobalSummaryData, RevenueMetricsGlobalSummaryResponse, RevenueMetricsGlobalSummaryResponses, RevenueMetricsMrrData, RevenueMetricsMrrResponse, RevenueMetricsMrrResponses, RevenueMetricsSummaryData, RevenueMetricsSummaryResponse, RevenueMetricsSummaryResponses, RevenueRecentEventsData, RevenueRecentEventsResponse, RevenueRecentEventsResponses, RevenueRotateTokenData, RevenueRotateTokenResponse, RevenueRotateTokenResponses, RevenueRow, RevenueUpdateConfigData, RevenueUpdateConfigErrors, RevenueUpdateConfigResponse, RevenueUpdateConfigResponses, RevenueUpdateSecretData, RevenueUpdateSecretErrors, RevenueUpdateSecretResponse, RevenueUpdateSecretResponses, RevokeDsnData, RevokeDsnErrors, RevokeDsnResponse, RevokeDsnResponses, RevokeEnrollmentTokenData, RevokeEnrollmentTokenErrors, RevokeEnrollmentTokenResponse, RevokeEnrollmentTokenResponses, RevokeJoinTokenData, RevokeJoinTokenErrors, RevokeJoinTokenResponse, RevokeJoinTokenResponses, RevokeProjectAccessData, RevokeProjectAccessErrors, RevokeProjectAccessResponse, RevokeProjectAccessResponses, RiskLevel, RoleInfo, RollbackPgUpgradeData, RollbackPgUpgradeErrors, RollbackPgUpgradeResponse, RollbackPgUpgradeResponses, RollbackToDeploymentData, RollbackToDeploymentErrors, RollbackToDeploymentResponse, RollbackToDeploymentResponses, RootfsCacheEntry, RootfsGcData, RootfsGcReport, RootfsGcResponses, RootfsReport, RootfsReportData, RootfsReportResponses, RootfsVmEntry, RotateApiKeyData, RotateApiKeyErrors, RotateApiKeyResponse, RotateApiKeyResponses, RotateDeploymentTokenData, RotateDeploymentTokenErrors, RotateDeploymentTokenResponse, RotateDeploymentTokenResponses, RouteRefreshResponse, RouteResponse, RouteRole, RouteUser, RouteUserWithRoles, RunBackupForSourceData, RunBackupForSourceError, RunBackupForSourceErrors, RunBackupForSourceResponse, RunBackupForSourceResponses, RunBackupRequest, RunConnectionHealthCheckData, RunConnectionHealthCheckErrors, RunConnectionHealthCheckResponse, RunConnectionHealthCheckResponses, RunExternalServiceBackupData, RunExternalServiceBackupError, RunExternalServiceBackupErrors, RunExternalServiceBackupRequest, RunExternalServiceBackupResponse, RunExternalServiceBackupResponses, RunScheduleNowData, RunScheduleNowError, RunScheduleNowErrors, RunScheduleNowResponse, RunScheduleNowResponses, S3ConnectionTestResponse, S3CredentialsResponse, S3SourceResponse, S3SourceResponseWritable, SandboxCreatePreviewLinkData, SandboxCreatePreviewLinkErrors, SandboxCreatePreviewLinkResponse, SandboxCreatePreviewLinkResponses, SandboxDomainResponse, SandboxEvent, SandboxEventsResponse, SandboxInner, SandboxResponse, SandboxRoute, SandboxStatusResponse, SaveAgentTokenData, SaveAgentTokenErrors, SaveAgentTokenRequest, SaveAgentTokenResponse, SaveAgentTokenResponse2, SaveAgentTokenResponses, SaveAiProviderCredentialData, SaveAiProviderCredentialErrors, SaveAiProviderCredentialResponse, SaveAiProviderCredentialResponses, SaveCredentialRequest, SaveCredentialResponse, ScalewayCredentialsRequest, ScanResponse, ScheduleRunEntry, ScheduleRunJobEntry, ScheduleRunListResponse, ScheduleRunResponse, ScheduleRunSummary, ScheduleRunSummaryList, ScreenshotSettings, SearchLogsData, SearchLogsError, SearchLogsErrors, SearchLogsRequest, SearchLogsResponse, SearchLogsResponse2, SearchLogsResponses, SearchMode, Seasonality, SecretResponse, SecurityConfig, SecurityHeadersConfig, SecurityHeadersSettings, SelfUpdateAttempt, SelfUpdateBlocker, SelfUpdatePhase, SelfUpdateRestartMode, SelfUpdateSettings, SelfUpdateStatus, SendEmailData, SendEmailErrors, SendEmailRequestBody, SendEmailResponse, SendEmailResponseBody, SendEmailResponses, SendMessageData, SendMessageErrors, SendMessageRequest, SendMessageResponses, SensitiveConfigValueResponse, SensitiveMcpConfigValueResponse, SensitiveValueResponse, SentryChunkUploadResponse, SentryCreateReleaseRequest, SentryEventRequest, SentryEventResponse, SentryReleaseFileResponse, SentryReleaseProjectRef, SentryReleaseResponse, SeriesStateEntry, ServiceAccessInfo, ServiceAction, ServiceAlertRuleResponse, ServiceBackupEntryResponse, ServiceBackupListResponse, ServiceCreateAlertRuleRequest, ServiceHealthResponse, ServiceHealthStatusBatchResponse, ServiceHealthStatusEntryResponse, ServiceMemberInfo, ServiceParameter, ServicePlan, ServiceResourceLimits, ServiceRuntimeReport, ServiceStatsReport, ServiceTypeInfo, ServiceTypeRoute, ServiceUpdateAlertRuleRequest, SesCredentialsRequest, SessionDetails, SessionDetailsQuery, SessionEvent, SessionEventDto, SessionEventsQuery, SessionEventsResponse, SessionLogsQuery, SessionLogsResponse, SessionReplayEventsRequest, SessionReplayInfoDto, SessionReplayInitRequest, SessionReplayInitResponse, SessionReplayWithEventsDto, SessionReplayWithVisitorDto, SessionRequestLog, SessionSummary, SetDefaultS3SourceData, SetDefaultS3SourceError, SetDefaultS3SourceErrors, SetDefaultS3SourceResponse, SetDefaultS3SourceResponses, SetFlagEnvironmentData, SetFlagEnvironmentErrors, SetFlagEnvironmentRequest, SetFlagEnvironmentResponse, SetFlagEnvironmentResponses, SetPreviewPasswordBody, SetPreviewPasswordData, SetPreviewPasswordErrors, SetPreviewPasswordResponse, SetPreviewPasswordResponse2, SetPreviewPasswordResponses, SetRequest, SetResponse, SettingsUpdateResponse, SetupDnsChallengeData, SetupDnsChallengeErrors, SetupDnsChallengeRequest, SetupDnsChallengeResponse, SetupDnsChallengeResponse2, SetupDnsChallengeResponses, SetupDnsData, SetupDnsErrors, SetupDnsRequest, SetupDnsResponse, SetupDnsResponse2, SetupDnsResponses, SetupEmailTrackingData, SetupEmailTrackingErrors, SetupEmailTrackingResponse, SetupEmailTrackingResponses, SetupMfaData, SetupMfaErrors, SetupMfaResponse, SetupMfaResponses, SiblingRef, SkillDefinitionResponse, SlackConfig, SleepEnvironmentData, SleepEnvironmentErrors, SleepEnvironmentResponse, SleepEnvironmentResponses, SlowQueriesResponse, SlowQueryRow, SmartFilter, SmokeTestAgentData, SmokeTestAgentErrors, SmokeTestAgentResponse, SmokeTestAgentResponses, SmokeTestResponse, SmtpCredentialsRequest, SmtpEncryptionRoute, SmtpResult, SourceArchiveUpload, SourceBackupEntry, SourceBackupIndexResponse, SourceBody, SourceFileListResponse, SourceFileResponse, SourceMapListResponse, SourceMapResponse, SourceSandboxData, SourceSandboxErrors, SourceSandboxResponse, SourceSandboxResponses, SourceType, SpanEvent, SpanKind, SpanRecord, SpanRow, SpanStatusCode, SpeedMetricsPayload, SpeedSegmentFilters, StaleSlot, StartAnalysisData, StartAnalysisErrors, StartAnalysisRequest, StartAnalysisResponse, StartAnalysisResponses, StartContainerData, StartContainerErrors, StartContainerResponse, StartContainerResponses, StartFixData, StartFixErrors, StartFixResponses, StartGitProviderOauthData, StartGitProviderOauthErrors, StartOidcLoginBySlugData, StartOidcLoginBySlugErrors, StartPgUpgradeData, StartPgUpgradeErrors, StartPgUpgradeRequest, StartPgUpgradeResponse, StartPgUpgradeResponses, StartRestoreData, StartRestoreError, StartRestoreErrors, StartRestoreRequest, StartRestoreResponse, StartRestoreResponses, StartServiceData, StartServiceErrors, StartServiceResponse, StartServiceResponses, StartUpdateData, StartUpdateError, StartUpdateErrors, StartUpdateRequest, StartUpdateResponse, StartUpdateResponse2, StartUpdateResponses, StaticBundleResponse, StaticParams, StaticPresetConfig, StatPathData, StatPathErrors, StatPathResponse, StatPathResponses, StatResponse, StatsFilters, StatusBucket, StatusBucketedResponse, StatusCodeCount, StatusCodesQuery, StatusPageOverview, StepConversionResponse, StepResourceType, StepResult, StepUpResponse, StopContainerData, StopContainerErrors, StopContainerResponse, StopContainerResponses, StopSandboxData, StopSandboxErrors, StopSandboxResponse, StopSandboxResponses, StopSequence, StopServiceData, StopServiceErrors, StopServiceResponse, StopServiceResponses, StorageQuota, StreamContainerMetricsData, StreamContainerMetricsErrors, StreamContainerMetricsResponses, StreamEventsData, StreamEventsErrors, StreamEventsResponses, StreamRunEventsData, StreamRunEventsErrors, StreamRunEventsResponses, StripeConfig, SupervisorKind, SyncedRepositoryListQuery, SyncRepositoriesData, SyncRepositoriesErrors, SyncRepositoriesResponse, SyncRepositoriesResponses, SyntaxResult, TagInfo, TagListResponse, TailDeploymentJobLogsData, TailDeploymentJobLogsErrors, TailLogsData, TailLogsError, TailLogsErrors, TailLogsRequest, TailLogsResponses, TargetRecommendation, TeamListResponse, TeamMemberResponse, TeamResponse, TeamRole, TeardownDeploymentData, TeardownDeploymentErrors, TeardownDeploymentResponse, TeardownDeploymentResponses, TeardownEnvironmentData, TeardownEnvironmentErrors, TeardownEnvironmentResponse, TeardownEnvironmentResponses, TemplateResponse, TestEmailRequest, TestEmailResponse, TestNotificationProviderData, TestNotificationProviderErrors, TestNotificationProviderResponse, TestNotificationProviderResponses, TestOidcProviderData, TestOidcProviderResponse, TestOidcProviderResponses, TestProviderConnectionData, TestProviderConnectionErrors, TestProviderConnectionResponse, TestProviderConnectionResponses, TestProviderData, TestProviderErrors, TestProviderKeyByIdData, TestProviderKeyByIdError, TestProviderKeyByIdErrors, TestProviderKeyByIdResponse, TestProviderKeyByIdResponses, TestProviderKeyInlineData, TestProviderKeyInlineError, TestProviderKeyInlineErrors, TestProviderKeyInlineResponse, TestProviderKeyInlineResponses, TestProviderKeyRequest, TestProviderKeyResponse, TestProviderResponse, TestProviderResponse2, TestProviderResponses, TestS3ConnectionPreviewData, TestS3ConnectionPreviewError, TestS3ConnectionPreviewErrors, TestS3ConnectionPreviewResponse, TestS3ConnectionPreviewResponses, TestS3SourceConnectionData, TestS3SourceConnectionError, TestS3SourceConnectionErrors, TestS3SourceConnectionResponse, TestS3SourceConnectionResponses, TimeBucketStats, TimeBucketStatsResponse, TimeseriesBucket, TimeseriesQueryParams, TlsMode, TodayStatsResponse, ToggleDeploymentMetricsRequest, ToggleServiceMetricsRequest, TokenRenewalRequest, ToolCallEvent, ToolInfo, ToolResultEvent, TopModelsQueryParams, TraceProjectRef, TracesResponse, TraceSummariesResponse, TraceSummary, TrackClickData, TrackClickErrors, TrackedLinkResponse, TrackingEventResponse, TrackOpenData, TrackOpenErrors, TrackOpenResponses, TriggerAgentData, TriggerAgentErrors, TriggerAgentRequest, TriggerAgentResponse, TriggerAgentResponses, TriggerDigestResponse, TriggerPipelinePayload, TriggerPipelineResponse, TriggerProjectPipelineData, TriggerProjectPipelineErrors, TriggerProjectPipelineResponse, TriggerProjectPipelineResponses, TriggerScanData, TriggerScanError, TriggerScanErrors, TriggerScanRequest, TriggerScanResponse, TriggerScanResponse2, TriggerScanResponses, TriggerServiceHealthCheckData, TriggerServiceHealthCheckErrors, TriggerServiceHealthCheckResponse, TriggerServiceHealthCheckResponses, TriggerWeeklyDigestData, TriggerWeeklyDigestErrors, TriggerWeeklyDigestResponse, TriggerWeeklyDigestResponses, TtlRequest, TtlResponse, TxtRecord, UiManifest, UiRoute, UndrainNodeResponse, UnifiedTrace, UniqueCountsQuery, UniqueCountsResponse, UnlinkServiceFromProjectData, UnlinkServiceFromProjectErrors, UnlinkServiceFromProjectResponse, UnlinkServiceFromProjectResponses, UnsupportedFeature, UpdateAdminGateRequest, UpdateAgentData, UpdateAgentErrors, UpdateAgentResponse, UpdateAgentResponses, UpdateAiProviderData, UpdateAiProviderErrors, UpdateAiProviderRequest, UpdateAiProviderResponse, UpdateAiProviderResponse2, UpdateAiProviderResponses, UpdateAlertData, UpdateAlertError, UpdateAlertErrors, UpdateAlertResponse, UpdateAlertResponses, UpdateAlertRuleData, UpdateAlertRuleErrors, UpdateAlertRuleRequest, UpdateAlertRuleResponse, UpdateAlertRuleResponses, UpdateApiKeyData, UpdateApiKeyErrors, UpdateApiKeyRequest, UpdateApiKeyResponse, UpdateApiKeyResponses, UpdateAutomaticDeployData, UpdateAutomaticDeployErrors, UpdateAutomaticDeployRequest, UpdateAutomaticDeployResponse, UpdateAutomaticDeployResponses, UpdateBackupScheduleData, UpdateBackupScheduleError, UpdateBackupScheduleErrors, UpdateBackupScheduleRequest, UpdateBackupScheduleResponse, UpdateBackupScheduleResponses, UpdateBlobRequest, UpdateBlobResponse, UpdateCapabilityResponse, UpdateCloudflareProviderData, UpdateCloudflareProviderErrors, UpdateCloudflareProviderRequest, UpdateCloudflareProviderResponse, UpdateCloudflareProviderResponses, UpdateConfigBody, UpdateConnectionTokenData, UpdateConnectionTokenErrors, UpdateConnectionTokenResponse, UpdateConnectionTokenResponses, UpdateCustomDomainData, UpdateCustomDomainErrors, UpdateCustomDomainRequest, UpdateCustomDomainResponse, UpdateCustomDomainResponses, UpdateDashboardData, UpdateDashboardError, UpdateDashboardErrors, UpdateDashboardRequest, UpdateDashboardResponse, UpdateDashboardResponses, UpdateDeploymentConfigRequest, UpdateDeploymentTokenData, UpdateDeploymentTokenErrors, UpdateDeploymentTokenRequest, UpdateDeploymentTokenResponse, UpdateDeploymentTokenResponses, UpdateDnsProviderRequest, UpdateEmailProviderData, UpdateEmailProviderErrors, UpdateEmailProviderRequest, UpdateEmailProviderResponse, UpdateEmailProviderResponses, UpdateEnvironmentSettingsData, UpdateEnvironmentSettingsErrors, UpdateEnvironmentSettingsRequest, UpdateEnvironmentSettingsResponse, UpdateEnvironmentSettingsResponses, UpdateEnvironmentSubdomainData, UpdateEnvironmentSubdomainErrors, UpdateEnvironmentSubdomainRequest, UpdateEnvironmentSubdomainResponse, UpdateEnvironmentSubdomainResponses, UpdateEnvironmentVariableData, UpdateEnvironmentVariableErrors, UpdateEnvironmentVariableRequest, UpdateEnvironmentVariableResponse, UpdateEnvironmentVariableResponses, UpdateErrorGroupData, UpdateErrorGroupErrors, UpdateErrorGroupRequest, UpdateErrorGroupResponses, UpdateExternalServiceRequest, UpdateFlagData, UpdateFlagErrors, UpdateFlagRequest, UpdateFlagResponse, UpdateFlagResponses, UpdateFunnelData, UpdateFunnelErrors, UpdateFunnelResponses, UpdateGitProviderCredentialsData, UpdateGitProviderCredentialsErrors, UpdateGitProviderCredentialsResponse, UpdateGitProviderCredentialsResponses, UpdateGitSettingsData, UpdateGitSettingsErrors, UpdateGitSettingsRequest, UpdateGitSettingsResponse, UpdateGitSettingsResponses, UpdateGlobalMcpData, UpdateGlobalMcpErrors, UpdateGlobalMcpResponse, UpdateGlobalMcpResponses, UpdateGlobalSkillData, UpdateGlobalSkillErrors, UpdateGlobalSkillResponse, UpdateGlobalSkillResponses, UpdateIncidentStatusData, UpdateIncidentStatusErrors, UpdateIncidentStatusRequest, UpdateIncidentStatusResponse, UpdateIncidentStatusResponses, UpdateIpAccessControlData, UpdateIpAccessControlError, UpdateIpAccessControlErrors, UpdateIpAccessControlRequest, UpdateIpAccessControlResponse, UpdateIpAccessControlResponses, UpdateKvRequest, UpdateKvResponse, UpdateManagedDomainApiRequest, UpdateManagedDomainData, UpdateManagedDomainErrors, UpdateManagedDomainResponse, UpdateManagedDomainResponses, UpdateMcpData, UpdateMcpErrors, UpdateMcpRequest, UpdateMcpResponse, UpdateMcpResponses, UpdateMemberRoleRequest, UpdateMetricAlertRequest, UpdateNotificationEmailProviderData, UpdateNotificationEmailProviderErrors, UpdateNotificationEmailProviderRequest, UpdateNotificationEmailProviderResponse, UpdateNotificationEmailProviderResponses, UpdateNotificationProviderData, UpdateNotificationProviderErrors, UpdateNotificationProviderResponse, UpdateNotificationProviderResponses, UpdateOidcProviderData, UpdateOidcProviderRequest, UpdateOidcProviderResponse, UpdateOidcProviderResponses, UpdatePreferencesData, UpdatePreferencesErrors, UpdatePreferencesRequest, UpdatePreferencesResponse, UpdatePreferencesResponses, UpdateProjectData, UpdateProjectDeploymentConfigData, UpdateProjectDeploymentConfigErrors, UpdateProjectDeploymentConfigResponse, UpdateProjectDeploymentConfigResponses, UpdateProjectErrors, UpdateProjectResponse, UpdateProjectResponses, UpdateProjectSecretData, UpdateProjectSecretErrors, UpdateProjectSecretRequest, UpdateProjectSecretResponse, UpdateProjectSecretResponses, UpdateProjectSettingsData, UpdateProjectSettingsErrors, UpdateProjectSettingsRequest, UpdateProjectSettingsResponse, UpdateProjectSettingsResponses, UpdateProviderCredentialsRequest, UpdateProviderData, UpdateProviderErrors, UpdateProviderKeyData, UpdateProviderKeyError, UpdateProviderKeyErrors, UpdateProviderKeyRequest, UpdateProviderKeyResponse, UpdateProviderKeyResponses, UpdateProviderRequest, UpdateProviderResponse, UpdateProviderResponses, UpdateRouteData, UpdateRouteErrors, UpdateRouteRequest, UpdateRouteResponse, UpdateRouteResponses, UpdateS3SourceData, UpdateS3SourceError, UpdateS3SourceErrors, UpdateS3SourceRequest, UpdateS3SourceResponse, UpdateS3SourceResponses, UpdateSecretBody, UpdateSelfData, UpdateSelfErrors, UpdateSelfRequest, UpdateSelfResponse, UpdateSelfResponses, UpdateServiceData, UpdateServiceErrors, UpdateServiceResourcesData, UpdateServiceResourcesErrors, UpdateServiceResourcesResponse, UpdateServiceResourcesResponses, UpdateServiceResponse, UpdateServiceResponses, UpdateSessionDurationData, UpdateSessionDurationError, UpdateSessionDurationErrors, UpdateSessionDurationRequest, UpdateSessionDurationResponse, UpdateSessionDurationResponse2, UpdateSessionDurationResponses, UpdateSettingsData, UpdateSettingsErrors, UpdateSettingsResponse, UpdateSettingsResponses, UpdateSkillData, UpdateSkillErrors, UpdateSkillRequest, UpdateSkillResponse, UpdateSkillResponses, UpdateSlackProviderData, UpdateSlackProviderErrors, UpdateSlackProviderRequest, UpdateSlackProviderResponse, UpdateSlackProviderResponses, UpdateSpeedMetricsData, UpdateSpeedMetricsError, UpdateSpeedMetricsErrors, UpdateSpeedMetricsPayload, UpdateSpeedMetricsResponse, UpdateSpeedMetricsResponses, UpdateStatusResponse, UpdateTeamData, UpdateTeamErrors, UpdateTeamMemberRoleData, UpdateTeamMemberRoleErrors, UpdateTeamMemberRoleResponse, UpdateTeamMemberRoleResponses, UpdateTeamRequest, UpdateTeamResponse, UpdateTeamResponses, UpdateTokenRequest, UpdateTokenResponse, UpdateUserData, UpdateUserErrors, UpdateUserRequest, UpdateUserResponse, UpdateUserResponses, UpdateWebhookData, UpdateWebhookErrors, UpdateWebhookProviderData, UpdateWebhookProviderErrors, UpdateWebhookProviderRequest, UpdateWebhookProviderResponse, UpdateWebhookProviderResponses, UpdateWebhookRequestBody, UpdateWebhookResponse, UpdateWebhookResponses, UpgradeExternalServiceRequest, UpgradePreviewGatewayData, UpgradePreviewGatewayResponse, UpgradePreviewGatewayResponses, UpgradeRequest, UpgradeServiceData, UpgradeServiceErrors, UpgradeServiceResponse, UpgradeServiceResponses, UploadGlobalSkillData, UploadGlobalSkillErrors, UploadGlobalSkillResponse, UploadGlobalSkillResponses, UploadReleaseFileData, UploadReleaseFileErrors, UploadReleaseFileResponse, UploadReleaseFileResponses, UploadSkillData, UploadSkillErrors, UploadSkillResponse, UploadSkillResponses, UploadSourceFileData, UploadSourceFileErrors, UploadSourceFileResponse, UploadSourceFileResponses, UploadSourceMapData, UploadSourceMapErrors, UploadSourceMapResponse, UploadSourceMapResponses, UploadStaticBundleData, UploadStaticBundleErrors, UploadStaticBundleResponse, UploadStaticBundleResponses, UpsertAgentRequest, UpsertSecretData, UpsertSecretErrors, UpsertSecretRequest, UpsertSecretResponse, UpsertSecretResponses, UptimeDataPoint, UptimeHistoryResponse, UsageFilter, UsageInfo, UsageLogEntry, UsageLogPage, UsageQueryParams, UsageSource, UsageSummary, UserResponse, ValidateConnectionData, ValidateConnectionErrors, ValidateConnectionResponse, ValidateConnectionResponses, ValidateEmailData, ValidateEmailErrors, ValidateEmailRequest, ValidateEmailResponse, ValidateEmailResponse2, ValidateEmailResponses, ValidationLevel, ValidationReport, ValidationResponse, ValidationResult, ValidationStatus, ValidationSummary, VerifyAndEnableMfaData, VerifyAndEnableMfaErrors, VerifyAndEnableMfaResponse, VerifyAndEnableMfaResponses, VerifyDomainData, VerifyDomainErrors, VerifyDomainResponse, VerifyDomainResponses, VerifyEmailData, VerifyEmailErrors, VerifyEmailResponse, VerifyEmailResponses, VerifyManagedDomainData, VerifyManagedDomainErrors, VerifyManagedDomainResponse, VerifyManagedDomainResponses, VerifyMfaChallengeData, VerifyMfaChallengeErrors, VerifyMfaChallengeResponse, VerifyMfaChallengeResponses, VerifyMfaRequest, VerifyStepUpData, VerifyStepUpErrors, VerifyStepUpRequest, VerifyStepUpResponse, VerifyStepUpResponses, ViewItem, ViewsOverTime, ViewsOverTimeQuery, VisitorDetails, VisitorFacets, VisitorFacetsQuery, VisitorFacetValue, VisitorInfo, VisitorJourneyQuery, VisitorJourneyResponse, VisitorLocationsQuery, VisitorRecord, VisitorSegmentFilters, VisitorSessionsQuery, VisitorSessionsResponse, VisitorsListQuery, VisitorsResponse, VisitorStats, VisitorWithGeolocation, VolumeMount, VolumeType, VulnerabilityResponse, WakeEnvironmentData, WakeEnvironmentErrors, WakeEnvironmentResponse, WakeEnvironmentResponses, WalWarning, WalWarningSeverity, WebhookConfig, WebhookDeliveryResponse, WebhookResponse, WebhookTriggerData, WebhookTriggerErrors, WebhookTriggerRequest, WebhookTriggerResponse, WebhookTriggerResponse2, WebhookTriggerResponses, WorkflowDryRunData, WorkflowDryRunErrors, WorkflowDryRunRequest, WorkflowDryRunResponse, WorkflowDryRunResponses, WorkloadDescriptor, WorkloadId, WorkloadStatus, WorkloadType, WriteFileBody, WriteFileData, WriteFileErrors, WriteFileResponse, WriteFileResponses, WriteFilesBody, WriteFilesData, WriteFilesErrors, WriteFilesResponse, WriteFilesResponse2, WriteFilesResponses, ZoneListResponse } from './types.gen'; diff --git a/apps/temps-cli/src/api/sdk.gen.ts b/apps/temps-cli/src/api/sdk.gen.ts index f68ed82c5..a01e5bb1d 100644 --- a/apps/temps-cli/src/api/sdk.gen.ts +++ b/apps/temps-cli/src/api/sdk.gen.ts @@ -2,7 +2,7 @@ import { type Client, type ClientMeta, formDataBodySerializer, type Options as Options2, type RequestResult, type ServerSentEventsResult, type TDataShape } from './client'; import { client } from './client.gen'; -import type { AcknowledgeAlarmData, AcknowledgeAlarmErrors, AcknowledgeAlarmResponses, ActivateAiProviderData, ActivateAiProviderErrors, ActivateAiProviderResponses, ActivateApiKeyData, ActivateApiKeyErrors, ActivateApiKeyResponses, ActivateConnectionData, ActivateConnectionErrors, ActivateConnectionResponses, ActivateProviderData, ActivateProviderErrors, ActivateProviderResponses, AddClusterMemberData, AddClusterMemberErrors, AddClusterMemberResponses, AddContextData, AddContextErrors, AddContextResponses, AddEnvironmentDomainData, AddEnvironmentDomainErrors, AddEnvironmentDomainResponses, AddEventsData, AddEventsErrors, AddEventsResponses, AddManagedDomainData, AddManagedDomainErrors, AddManagedDomainResponses, AddSessionReplayEventsData, AddSessionReplayEventsErrors, AddSessionReplayEventsResponses, AddTeamMemberData, AddTeamMemberErrors, AddTeamMemberResponses, AdminDrainNodeData, AdminDrainNodeErrors, AdminDrainNodeResponses, AdminDrainStatusData, AdminDrainStatusErrors, AdminDrainStatusResponses, AdminGetNodeData, AdminGetNodeErrors, AdminGetNodeResponses, AdminListNodeContainersData, AdminListNodeContainersErrors, AdminListNodeContainersResponses, AdminListNodesData, AdminListNodesErrors, AdminListNodesResponses, AdminRemoveNodeData, AdminRemoveNodeErrors, AdminRemoveNodeResponses, AdminUndrainNodeData, AdminUndrainNodeErrors, AdminUndrainNodeResponses, ApplyHostnameModeData, ApplyHostnameModeErrors, ApplyHostnameModeResponses, ArchiveConversationData, ArchiveConversationErrors, ArchiveConversationResponses, ArchiveFlagData, ArchiveFlagErrors, ArchiveFlagResponses, AssignRoleData, AssignRoleErrors, AssignRoleResponses, AttachScheduleServicesData, AttachScheduleServicesErrors, AttachScheduleServicesResponses, BlobCopyData, BlobCopyErrors, BlobCopyResponses, BlobDeleteData, BlobDeleteErrors, BlobDeleteResponses, BlobDisableData, BlobDisableErrors, BlobDisableResponses, BlobDownloadData, BlobDownloadErrors, BlobDownloadResponses, BlobEnableData, BlobEnableErrors, BlobEnableResponses, BlobHeadData, BlobHeadErrors, BlobHeadResponses, BlobListData, BlobListErrors, BlobListResponses, BlobPutData, BlobPutErrors, BlobPutResponses, BlobStatusData, BlobStatusErrors, BlobStatusResponses, BlobUpdateData, BlobUpdateErrors, BlobUpdateResponses, CancelBackupData, CancelBackupErrors, CancelBackupResponses, CancelData, CancelDeploymentData, CancelDeploymentErrors, CancelDeploymentResponses, CancelDomainOrderData, CancelDomainOrderErrors, CancelDomainOrderResponses, CancelErrors, CancelPgUpgradeData, CancelPgUpgradeErrors, CancelPgUpgradeResponses, CancelResponses, CancelRunData, CancelRunErrors, CancelRunResponses, CancelScheduleRunData, CancelScheduleRunErrors, CancelScheduleRunResponses, ChangePasswordSelfData, ChangePasswordSelfErrors, ChangePasswordSelfResponses, ChangeProjectSourceData, ChangeProjectSourceErrors, ChangeProjectSourceResponses, ChangeRequiredPasswordData, ChangeRequiredPasswordErrors, ChangeRequiredPasswordResponses, ChatCompletionsData, ChatCompletionsErrors, ChatCompletionsResponses, CheckAnalyticsHasEventsData, CheckAnalyticsHasEventsErrors, CheckAnalyticsHasEventsResponses, CheckCommitExistsData, CheckCommitExistsErrors, CheckCommitExistsResponses, CheckDomainStatusData, CheckDomainStatusErrors, CheckDomainStatusResponses, CheckExplorerSupportData, CheckExplorerSupportErrors, CheckExplorerSupportResponses, CheckIpBlockedData, CheckIpBlockedErrors, CheckIpBlockedResponses, CheckProviderDeletionSafetyData, CheckProviderDeletionSafetyErrors, CheckProviderDeletionSafetyResponses, ChunkUploadOptionsData, ChunkUploadOptionsResponses, CleanupExpiredBackupsData, CleanupExpiredBackupsErrors, CleanupExpiredBackupsResponses, ClearPreviewPasswordData, ClearPreviewPasswordErrors, ClearPreviewPasswordResponses, CliDeviceApproveData, CliDeviceApproveErrors, CliDeviceApproveResponses, CliDeviceDenyData, CliDeviceDenyErrors, CliDeviceDenyResponses, CliDeviceLookupData, CliDeviceLookupErrors, CliDeviceLookupResponses, CliDevicePollData, CliDevicePollErrors, CliDevicePollResponses, CliDeviceStartData, CliDeviceStartErrors, CliDeviceStartResponses, CliLogoutData, CliLogoutErrors, CliLogoutResponses, CmdData, CmdErrors, CmdKillData, CmdKillErrors, CmdKillResponses, CmdLogsData, CmdLogsErrors, CmdLogsResponses, CmdResponses, ConfirmPendingActionData, ConfirmPendingActionErrors, ConfirmPendingActionResponses, ContainerMetricsGetHistoryData, ContainerMetricsGetHistoryErrors, ContainerMetricsGetHistoryResponses, CreateAgentData, CreateAgentErrors, CreateAgentResponses, CreateAlertData, CreateAlertErrors, CreateAlertResponses, CreateAlertRuleData, CreateAlertRuleErrors, CreateAlertRuleResponses, CreateApiKeyData, CreateApiKeyErrors, CreateApiKeyResponses, CreateBackupScheduleData, CreateBackupScheduleErrors, CreateBackupScheduleResponses, CreateBitbucketProviderData, CreateBitbucketProviderErrors, CreateBitbucketProviderResponses, CreateCloudflareProviderData, CreateCloudflareProviderErrors, CreateCloudflareProviderResponses, CreateConversationData, CreateConversationErrors, CreateConversationResponses, CreateCustomDomainData, CreateCustomDomainErrors, CreateCustomDomainResponses, CreateDashboardData, CreateDashboardErrors, CreateDashboardResponses, CreateDeploymentTokenData, CreateDeploymentTokenErrors, CreateDeploymentTokenResponses, CreateDnsProviderData, CreateDnsProviderErrors, CreateDnsProviderResponses, CreateDomainData, CreateDomainErrors, CreateDomainResponses, CreateDsnData, CreateDsnErrors, CreateDsnResponses, CreateEmailDomainData, CreateEmailDomainErrors, CreateEmailDomainResponses, CreateEmailProviderData, CreateEmailProviderErrors, CreateEmailProviderResponses, CreateEnvironmentData, CreateEnvironmentErrors, CreateEnvironmentResponses, CreateEnvironmentVariableData, CreateEnvironmentVariableErrors, CreateEnvironmentVariableResponses, CreateFlagData, CreateFlagErrors, CreateFlagResponses, CreateFunnelData, CreateFunnelErrors, CreateFunnelResponses, CreateGenericProviderData, CreateGenericProviderErrors, CreateGenericProviderResponses, CreateGiteaPatProviderData, CreateGiteaPatProviderErrors, CreateGiteaPatProviderResponses, CreateGithubPatProviderData, CreateGithubPatProviderErrors, CreateGithubPatProviderResponses, CreateGitlabOauthProviderData, CreateGitlabOauthProviderErrors, CreateGitlabOauthProviderResponses, CreateGitlabPatProviderData, CreateGitlabPatProviderErrors, CreateGitlabPatProviderResponses, CreateGitProviderData, CreateGitProviderErrors, CreateGitProviderResponses, CreateGlobalMcpData, CreateGlobalMcpErrors, CreateGlobalMcpResponses, CreateGlobalSkillData, CreateGlobalSkillErrors, CreateGlobalSkillResponses, CreateIncidentData, CreateIncidentErrors, CreateIncidentResponses, CreateIpAccessControlData, CreateIpAccessControlErrors, CreateIpAccessControlResponses, CreateMcpData, CreateMcpErrors, CreateMcpResponses, CreateMonitorData, CreateMonitorErrors, CreateMonitorResponses, CreateNotificationEmailProviderData, CreateNotificationEmailProviderErrors, CreateNotificationEmailProviderResponses, CreateNotificationProviderData, CreateNotificationProviderErrors, CreateNotificationProviderResponses, CreateOidcProviderData, CreateOidcProviderErrors, CreateOidcProviderResponses, CreateOidcRoleMappingData, CreateOidcRoleMappingResponses, CreateOrRecreateOrderData, CreateOrRecreateOrderErrors, CreateOrRecreateOrderResponses, CreatePlanData, CreatePlanErrors, CreatePlanResponses, CreatePrData, CreatePrErrors, CreateProjectData, CreateProjectErrors, CreateProjectFromTemplateData, CreateProjectFromTemplateErrors, CreateProjectFromTemplateResponses, CreateProjectReleaseData, CreateProjectReleaseErrors, CreateProjectReleaseResponses, CreateProjectResponses, CreateProjectSecretData, CreateProjectSecretErrors, CreateProjectSecretResponses, CreateProviderKeyData, CreateProviderKeyErrors, CreateProviderKeyResponses, CreatePrResponses, CreateReleaseData, CreateReleaseErrors, CreateReleaseResponses, CreateRouteData, CreateRouteErrors, CreateRouteResponses, CreateS3SourceData, CreateS3SourceErrors, CreateS3SourceResponses, CreateSandboxData, CreateSandboxErrors, CreateSandboxResponses, CreateServiceData, CreateServiceErrors, CreateServiceResponses, CreateSkillData, CreateSkillErrors, CreateSkillResponses, CreateSlackProviderData, CreateSlackProviderErrors, CreateSlackProviderResponses, CreateTeamData, CreateTeamErrors, CreateTeamResponses, CreateUserData, CreateUserErrors, CreateUserResponses, CreateWebhookData, CreateWebhookErrors, CreateWebhookProviderData, CreateWebhookProviderErrors, CreateWebhookProviderResponses, CreateWebhookResponses, DeactivateApiKeyData, DeactivateApiKeyErrors, DeactivateApiKeyResponses, DeactivateConnectionData, DeactivateConnectionErrors, DeactivateConnectionResponses, DeactivateProviderData, DeactivateProviderErrors, DeactivateProviderResponses, DeleteAgentData, DeleteAgentErrors, DeleteAgentResponses, DeleteAlertData, DeleteAlertErrors, DeleteAlertResponses, DeleteAlertRuleData, DeleteAlertRuleErrors, DeleteAlertRuleResponses, DeleteApiKeyData, DeleteApiKeyErrors, DeleteApiKeyResponses, DeleteBackupData, DeleteBackupErrors, DeleteBackupResponses, DeleteBackupScheduleData, DeleteBackupScheduleErrors, DeleteBackupScheduleResponses, DeleteConnectionData, DeleteConnectionErrors, DeleteConnectionResponses, DeleteCustomDomainData, DeleteCustomDomainErrors, DeleteCustomDomainResponses, DeleteDashboardData, DeleteDashboardErrors, DeleteDashboardResponses, DeleteDeploymentTokenData, DeleteDeploymentTokenErrors, DeleteDeploymentTokenResponses, DeleteDnsProviderData, DeleteDnsProviderErrors, DeleteDnsProviderResponses, DeleteDomainData, DeleteDomainErrors, DeleteDomainResponses, DeleteEmailDomainData, DeleteEmailDomainErrors, DeleteEmailDomainResponses, DeleteEmailProviderData, DeleteEmailProviderErrors, DeleteEmailProviderResponses, DeleteEnvironmentData, DeleteEnvironmentDomainData, DeleteEnvironmentDomainErrors, DeleteEnvironmentDomainResponses, DeleteEnvironmentErrors, DeleteEnvironmentResponses, DeleteEnvironmentVariableData, DeleteEnvironmentVariableErrors, DeleteEnvironmentVariableResponses, DeleteExternalImageData, DeleteExternalImageErrors, DeleteExternalImageResponses, DeleteFunnelData, DeleteFunnelErrors, DeleteFunnelResponses, DeleteGitProviderData, DeleteGitProviderErrors, DeleteGitProviderResponses, DeleteGlobalMcpData, DeleteGlobalMcpErrors, DeleteGlobalMcpResponses, DeleteGlobalSkillData, DeleteGlobalSkillErrors, DeleteGlobalSkillResponses, DeleteIpAccessControlData, DeleteIpAccessControlErrors, DeleteIpAccessControlResponses, DeleteMcpData, DeleteMcpErrors, DeleteMcpResponses, DeleteMonitorData, DeleteMonitorErrors, DeleteMonitorResponses, DeleteNotificationProviderData, DeleteNotificationProviderErrors, DeleteNotificationProviderResponses, DeleteOidcProviderData, DeleteOidcProviderResponses, DeleteOidcRoleMappingData, DeleteOidcRoleMappingResponses, DeletePreferencesData, DeletePreferencesErrors, DeletePreferencesResponses, DeleteProjectData, DeleteProjectErrors, DeleteProjectResponses, DeleteProjectSecretData, DeleteProjectSecretErrors, DeleteProjectSecretResponses, DeleteProviderKeyData, DeleteProviderKeyErrors, DeleteProviderKeyResponses, DeleteProviderSafelyData, DeleteProviderSafelyErrors, DeleteProviderSafelyResponses, DeleteReleaseSourceFilesData, DeleteReleaseSourceFilesErrors, DeleteReleaseSourceFilesResponses, DeleteReleaseSourceMapsData, DeleteReleaseSourceMapsErrors, DeleteReleaseSourceMapsResponses, DeleteRouteData, DeleteRouteErrors, DeleteRouteResponses, DeleteS3SourceData, DeleteS3SourceErrors, DeleteS3SourceResponses, DeleteScanData, DeleteScanErrors, DeleteScanResponses, DeleteSecretData, DeleteSecretErrors, DeleteSecretResponses, DeleteServiceData, DeleteServiceErrors, DeleteServiceResponses, DeleteSessionReplayData, DeleteSessionReplayErrors, DeleteSessionReplayResponses, DeleteSkillData, DeleteSkillErrors, DeleteSkillResponses, DeleteSourceMapData, DeleteSourceMapErrors, DeleteSourceMapResponses, DeleteStaticBundleData, DeleteStaticBundleErrors, DeleteStaticBundleResponses, DeleteTeamData, DeleteTeamErrors, DeleteTeamResponses, DeleteUserData, DeleteUserErrors, DeleteUserResponses, DeleteWebhookData, DeleteWebhookErrors, DeleteWebhookResponses, DeployFromImageData, DeployFromImageErrors, DeployFromImageResponses, DeployFromImageUploadData, DeployFromImageUploadErrors, DeployFromImageUploadResponses, DeployFromStaticData, DeployFromStaticErrors, DeployFromStaticResponses, DeployFromUploadedSourceData, DeployFromUploadedSourceErrors, DeployFromUploadedSourceResponses, DeploymentMetricsGetLatestData, DeploymentMetricsGetLatestErrors, DeploymentMetricsGetLatestResponses, DeploymentMetricsGetRangeData, DeploymentMetricsGetRangeErrors, DeploymentMetricsGetRangeResponses, DeploymentMetricsToggleData, DeploymentMetricsToggleErrors, DeploymentMetricsToggleResponses, DestroySandboxData, DestroySandboxErrors, DestroySandboxResponses, DetachScheduleServiceData, DetachScheduleServiceErrors, DetachScheduleServiceResponses, DetectPublicPresetsData, DetectPublicPresetsErrors, DetectPublicPresetsResponses, DisableBackupScheduleData, DisableBackupScheduleErrors, DisableBackupScheduleResponses, DisableMfaData, DisableMfaErrors, DisableMfaResponses, DiscoverWorkloadsData, DiscoverWorkloadsErrors, DiscoverWorkloadsResponses, DomainData, DomainErrors, DomainResponses, DownloadGlobalSkillArchiveData, DownloadGlobalSkillArchiveErrors, DownloadGlobalSkillArchiveResponses, DownloadObjectData, DownloadObjectErrors, DownloadObjectResponses, DownloadSkillArchiveData, DownloadSkillArchiveErrors, DownloadSkillArchiveResponses, EmailStatusData, EmailStatusErrors, EmailStatusResponses, EmbeddingsData, EmbeddingsErrors, EmbeddingsResponses, EnableBackupScheduleData, EnableBackupScheduleErrors, EnableBackupScheduleResponses, EnrichVisitorData, EnrichVisitorErrors, EnrichVisitorResponses, ExecData, ExecDetachedData, ExecDetachedErrors, ExecDetachedResponses, ExecErrors, ExecResponses, ExecuteDeploymentOperationData, ExecuteDeploymentOperationErrors, ExecuteDeploymentOperationResponses, ExecuteImportData, ExecuteImportErrors, ExecuteImportResponses, ExtendTimeoutData, ExtendTimeoutErrors, ExtendTimeoutResponses, ExternalServiceEnablePgStatStatementsData, ExternalServiceEnablePgStatStatementsErrors, ExternalServiceEnablePgStatStatementsResponses, ExternalServiceMetricsByDatabaseData, ExternalServiceMetricsByDatabaseErrors, ExternalServiceMetricsByDatabaseResponses, ExternalServiceMetricsCreateAlertRuleData, ExternalServiceMetricsCreateAlertRuleErrors, ExternalServiceMetricsCreateAlertRuleResponses, ExternalServiceMetricsDeleteAlertRuleData, ExternalServiceMetricsDeleteAlertRuleErrors, ExternalServiceMetricsDeleteAlertRuleResponses, ExternalServiceMetricsGetAlertRulesData, ExternalServiceMetricsGetAlertRulesErrors, ExternalServiceMetricsGetAlertRulesResponses, ExternalServiceMetricsGetLatestData, ExternalServiceMetricsGetLatestErrors, ExternalServiceMetricsGetLatestResponses, ExternalServiceMetricsGetRangeData, ExternalServiceMetricsGetRangeErrors, ExternalServiceMetricsGetRangeResponses, ExternalServiceMetricsStatusData, ExternalServiceMetricsStatusErrors, ExternalServiceMetricsStatusResponses, ExternalServiceMetricsToggleData, ExternalServiceMetricsToggleErrors, ExternalServiceMetricsToggleResponses, ExternalServiceMetricsUpdateAlertRuleData, ExternalServiceMetricsUpdateAlertRuleErrors, ExternalServiceMetricsUpdateAlertRuleResponses, ExternalServiceResetPgStatStatementsData, ExternalServiceResetPgStatStatementsErrors, ExternalServiceResetPgStatStatementsResponses, FinalizeOrderData, FinalizeOrderErrors, FinalizeOrderResponses, FinalizeProjectReleaseData, FinalizeProjectReleaseErrors, FinalizeProjectReleaseResponses, FindConversationData, FindConversationErrors, FindConversationResponses, GenerateJoinTokenData, GenerateJoinTokenErrors, GenerateJoinTokenResponses, GeneratePresetDockerfileData, GeneratePresetDockerfileErrors, GeneratePresetDockerfileResponses, GetAccessInfoData, GetAccessInfoErrors, GetAccessInfoResponses, GetActiveVisitorsData, GetActiveVisitorsErrors, GetActiveVisitorsResponses, GetActivityGraphData, GetActivityGraphErrors, GetActivityGraphResponses, GetAdminGateData, GetAdminGateErrors, GetAdminGateResponses, GetAgentData, GetAgentErrors, GetAgentResponses, GetAggregatedBucketsData, GetAggregatedBucketsErrors, GetAggregatedBucketsResponses, GetAiAgentBreakdownData, GetAiAgentBreakdownErrors, GetAiAgentBreakdownResponses, GetAiAgentPagesData, GetAiAgentPagesErrors, GetAiAgentPagesResponses, GetAiAgentTimelineData, GetAiAgentTimelineErrors, GetAiAgentTimelineResponses, GetAiPageBreakdownData, GetAiPageBreakdownErrors, GetAiPageBreakdownResponses, GetAiStatusBreakdownData, GetAiStatusBreakdownErrors, GetAiStatusBreakdownResponses, GetAlertData, GetAlertErrors, GetAlertResponses, GetAlertRuleData, GetAlertRuleErrors, GetAlertRuleResponses, GetAllRepositoriesByNameData, GetAllRepositoriesByNameErrors, GetAllRepositoriesByNameResponses, GetAnalyticsActiveVisitorsData, GetAnalyticsActiveVisitorsErrors, GetAnalyticsActiveVisitorsResponses, GetAnalyticsEventsCountData, GetAnalyticsEventsCountErrors, GetAnalyticsEventsCountResponses, GetAnalyticsSessionEventsData, GetAnalyticsSessionEventsErrors, GetAnalyticsSessionEventsResponses, GetAnalyticsVisitorSessionsData, GetAnalyticsVisitorSessionsErrors, GetAnalyticsVisitorSessionsResponses, GetApiKeyData, GetApiKeyErrors, GetApiKeyPermissionsData, GetApiKeyPermissionsErrors, GetApiKeyPermissionsResponses, GetApiKeyResponses, GetAuditLogData, GetAuditLogErrors, GetAuditLogResponses, GetBackupData, GetBackupErrors, GetBackupResponses, GetBackupScheduleData, GetBackupScheduleErrors, GetBackupScheduleResponses, GetBranchesByRepositoryIdData, GetBranchesByRepositoryIdErrors, GetBranchesByRepositoryIdResponses, GetBucketedIncidentsData, GetBucketedIncidentsErrors, GetBucketedIncidentsResponses, GetBucketedStatusData, GetBucketedStatusErrors, GetBucketedStatusResponses, GetChallengeTokenData, GetChallengeTokenErrors, GetChallengeTokenResponses, GetChatReadinessData, GetChatReadinessErrors, GetChatReadinessResponses, GetCliStatusData, GetCliStatusErrors, GetCliStatusResponses, GetClusterHealthData, GetClusterHealthErrors, GetClusterHealthResponses, GetClusterMemberData, GetClusterMemberErrors, GetClusterMemberResponses, GetCmdData, GetCmdErrors, GetCmdResponses, GetContainerDetailData, GetContainerDetailErrors, GetContainerDetailResponses, GetContainerEnvironmentVariableData, GetContainerEnvironmentVariableErrors, GetContainerEnvironmentVariableResponses, GetContainerInfoData, GetContainerInfoErrors, GetContainerInfoResponses, GetContainerLogsByIdData, GetContainerLogsByIdErrors, GetContainerLogsData, GetContainerLogsErrors, GetContainerMetricsData, GetContainerMetricsErrors, GetContainerMetricsResponses, GetConversationData, GetConversationDetailData, GetConversationDetailErrors, GetConversationDetailResponses, GetConversationErrors, GetConversationResponses, GetConversationsData, GetConversationsErrors, GetConversationsResponses, GetCronByIdData, GetCronByIdErrors, GetCronByIdResponses, GetCronExecutionsData, GetCronExecutionsErrors, GetCronExecutionsResponses, GetCrossProjectTraceSiblingsData, GetCrossProjectTraceSiblingsErrors, GetCrossProjectTraceSiblingsResponses, GetCurrentMonitorStatusData, GetCurrentMonitorStatusErrors, GetCurrentMonitorStatusResponses, GetCurrentUserData, GetCurrentUserErrors, GetCurrentUserResponses, GetCustomDomainData, GetCustomDomainErrors, GetCustomDomainResponses, GetDashboardData, GetDashboardErrors, GetDashboardProjectsAnalyticsData, GetDashboardProjectsAnalyticsErrors, GetDashboardProjectsAnalyticsResponses, GetDashboardResponses, GetDeliveryData, GetDeliveryErrors, GetDeliveryResponses, GetDeploymentContainerLogContentData, GetDeploymentContainerLogContentErrors, GetDeploymentContainerLogContentResponses, GetDeploymentData, GetDeploymentErrors, GetDeploymentJobLogsData, GetDeploymentJobLogsErrors, GetDeploymentJobLogsResponses, GetDeploymentJobsData, GetDeploymentJobsErrors, GetDeploymentJobsResponses, GetDeploymentOperationsData, GetDeploymentOperationsErrors, GetDeploymentOperationsResponses, GetDeploymentOperationStatusData, GetDeploymentOperationStatusErrors, GetDeploymentOperationStatusResponses, GetDeploymentResponses, GetDeploymentTokenData, GetDeploymentTokenErrors, GetDeploymentTokenResponses, GetDiskStatusData, GetDiskStatusErrors, GetDiskStatusResponses, GetDnsChangesData, GetDnsChangesErrors, GetDnsChangesResponses, GetDnsProviderData, GetDnsProviderErrors, GetDnsProviderResponses, GetDomainByHostData, GetDomainByHostErrors, GetDomainByHostResponses, GetDomainByIdData, GetDomainByIdErrors, GetDomainByIdResponses, GetDomainByNameData, GetDomainByNameErrors, GetDomainByNameResponses, GetDomainData, GetDomainDnsRecordsData, GetDomainDnsRecordsErrors, GetDomainDnsRecordsResponses, GetDomainErrors, GetDomainOrderData, GetDomainOrderErrors, GetDomainOrderResponses, GetDomainResponses, GetEmailData, GetEmailErrors, GetEmailEventsData, GetEmailEventsErrors, GetEmailEventsResponses, GetEmailLinksData, GetEmailLinksErrors, GetEmailLinksResponses, GetEmailProviderData, GetEmailProviderErrors, GetEmailProviderResponses, GetEmailResponses, GetEmailStatsData, GetEmailStatsErrors, GetEmailStatsResponses, GetEmailTrackingData, GetEmailTrackingErrors, GetEmailTrackingResponses, GetEmailTrackingStatusData, GetEmailTrackingStatusErrors, GetEmailTrackingStatusResponses, GetEntityInfoData, GetEntityInfoErrors, GetEntityInfoResponses, GetEnvironmentCronsData, GetEnvironmentCronsErrors, GetEnvironmentCronsResponses, GetEnvironmentData, GetEnvironmentDomainsData, GetEnvironmentDomainsErrors, GetEnvironmentDomainsResponses, GetEnvironmentErrors, GetEnvironmentResponses, GetEnvironmentsData, GetEnvironmentsErrors, GetEnvironmentsResponses, GetEnvironmentVariablesData, GetEnvironmentVariablesErrors, GetEnvironmentVariablesResponses, GetEnvironmentVariableValueData, GetEnvironmentVariableValueErrors, GetEnvironmentVariableValueResponses, GetErrorDashboardStatsData, GetErrorDashboardStatsErrors, GetErrorDashboardStatsResponses, GetErrorEventData, GetErrorEventErrors, GetErrorEventResponses, GetErrorGroupData, GetErrorGroupErrors, GetErrorGroupResponses, GetErrorStatsData, GetErrorStatsErrors, GetErrorStatsResponses, GetErrorTimeSeriesData, GetErrorTimeSeriesErrors, GetErrorTimeSeriesResponses, GetEventDetailData, GetEventDetailErrors, GetEventDetailResponses, GetEventEntriesData, GetEventEntriesErrors, GetEventEntriesResponses, GetEventsCountData, GetEventsCountErrors, GetEventsCountResponses, GetEventsTimelineData, GetEventsTimelineErrors, GetEventsTimelineResponses, GetEventTypeBreakdownData, GetEventTypeBreakdownErrors, GetEventTypeBreakdownResponses, GetEventVisitorsData, GetEventVisitorsErrors, GetEventVisitorsResponses, GetExternalImageData, GetExternalImageErrors, GetExternalImageResponses, GetFileData, GetFileErrors, GetFileResponses, GetFlagData, GetFlagErrors, GetFlagResponses, GetFlagSnapshotData, GetFlagSnapshotErrors, GetFlagSnapshotResponses, GetFunnelMetricsData, GetFunnelMetricsErrors, GetFunnelMetricsResponses, GetGenaiTraceData, GetGenaiTraceErrors, GetGenaiTraceResponses, GetGeneralStatsData, GetGeneralStatsErrors, GetGeneralStatsResponses, GetGitProviderData, GetGitProviderErrors, GetGitProviderResponses, GetGlobalEventsData, GetGlobalEventsErrors, GetGlobalEventsResponses, GetGlobalEventStatsData, GetGlobalEventStatsErrors, GetGlobalEventStatsResponses, GetGlobalMcpData, GetGlobalMcpErrors, GetGlobalMcpResponses, GetGlobalSandboxStatusData, GetGlobalSandboxStatusErrors, GetGlobalSandboxStatusResponses, GetGlobalSkillData, GetGlobalSkillErrors, GetGlobalSkillResponses, GetGroupedPageMetricsData, GetGroupedPageMetricsErrors, GetGroupedPageMetricsResponses, GetHealthData, GetHealthErrors, GetHealthResponses, GetHourlyVisitsData, GetHourlyVisitsErrors, GetHourlyVisitsResponses, GetHttpChallengeDebugData, GetHttpChallengeDebugErrors, GetHttpChallengeDebugResponses, GetImportStatusData, GetImportStatusErrors, GetImportStatusResponses, GetIncidentData, GetIncidentErrors, GetIncidentResponses, GetIncidentUpdatesData, GetIncidentUpdatesErrors, GetIncidentUpdatesResponses, GetIpAccessControlData, GetIpAccessControlErrors, GetIpAccessControlResponses, GetIpGeolocationData, GetIpGeolocationErrors, GetIpGeolocationResponses, GetJoinTokenStatusData, GetJoinTokenStatusErrors, GetJoinTokenStatusResponses, GetLastDeploymentData, GetLastDeploymentErrors, GetLastDeploymentResponses, GetLatestScanData, GetLatestScanErrors, GetLatestScanResponses, GetLatestScansPerEnvironmentData, GetLatestScansPerEnvironmentErrors, GetLatestScansPerEnvironmentResponses, GetLiveVisitorsListData, GetLiveVisitorsListErrors, GetLiveVisitorsListResponses, GetLogContextData, GetLogContextErrors, GetLogContextResponses, GetMcpData, GetMcpErrors, GetMcpResponses, GetMetricsOverTimeData, GetMetricsOverTimeErrors, GetMetricsOverTimeResponses, GetMonitorData, GetMonitorErrors, GetMonitorResponses, GetNotificationProviderData, GetNotificationProviderErrors, GetNotificationProviderResponses, GetOnDemandCertStatusData, GetOnDemandCertStatusErrors, GetOnDemandCertStatusResponses, GetOrCreateDsnData, GetOrCreateDsnErrors, GetOrCreateDsnResponses, GetPageFlowData, GetPageFlowErrors, GetPageFlowResponses, GetPageHourlySessionsData, GetPageHourlySessionsErrors, GetPageHourlySessionsResponses, GetPagePathDetailData, GetPagePathDetailErrors, GetPagePathDetailResponses, GetPagePathsData, GetPagePathsErrors, GetPagePathsResponses, GetPagePathsSparklinesData, GetPagePathsSparklinesErrors, GetPagePathsSparklinesResponses, GetPagePathVisitorsData, GetPagePathVisitorsErrors, GetPagePathVisitorsResponses, GetPendingActionData, GetPendingActionErrors, GetPendingActionResponses, GetPerformanceMetricsData, GetPerformanceMetricsErrors, GetPerformanceMetricsResponses, GetPgUpgradeData, GetPgUpgradeErrors, GetPgUpgradeLogsData, GetPgUpgradeLogsErrors, GetPgUpgradeLogsResponses, GetPgUpgradeResponses, GetPipelineStatsData, GetPipelineStatsErrors, GetPipelineStatsResponses, GetPlatformInfoData, GetPlatformInfoErrors, GetPlatformInfoResponses, GetPostgresWalHealthData, GetPostgresWalHealthErrors, GetPostgresWalHealthResponses, GetPreferencesData, GetPreferencesErrors, GetPreferencesResponses, GetPreviewGatewayLogsData, GetPreviewGatewayLogsResponses, GetPreviewGatewaySettingsData, GetPreviewGatewaySettingsResponses, GetPreviewGatewayStatusData, GetPreviewGatewayStatusResponses, GetPricingData, GetPricingErrors, GetPricingResponses, GetPrivateIpData, GetPrivateIpErrors, GetPrivateIpResponses, GetProjectAlarmsSummaryData, GetProjectAlarmsSummaryErrors, GetProjectAlarmsSummaryResponses, GetProjectBySlugData, GetProjectBySlugErrors, GetProjectBySlugResponses, GetProjectData, GetProjectDeploymentsData, GetProjectDeploymentsErrors, GetProjectDeploymentsResponses, GetProjectErrors, GetProjectResponses, GetProjectsData, GetProjectsErrors, GetProjectServiceEnvironmentVariablesData, GetProjectServiceEnvironmentVariablesErrors, GetProjectServiceEnvironmentVariablesResponses, GetProjectSessionReplaysData, GetProjectSessionReplaysErrors, GetProjectSessionReplaysResponses, GetProjectsHealthData, GetProjectsHealthErrors, GetProjectsHealthResponses, GetProjectsMonitorHealthData, GetProjectsMonitorHealthErrors, GetProjectsMonitorHealthResponses, GetProjectsResponses, GetProjectStatisticsData, GetProjectStatisticsErrors, GetProjectStatisticsResponses, GetProjectTemplateData, GetProjectTemplateErrors, GetProjectTemplateResponses, GetPropertyBreakdownData, GetPropertyBreakdownErrors, GetPropertyBreakdownResponses, GetPropertyTimelineData, GetPropertyTimelineErrors, GetPropertyTimelineResponses, GetProviderConnectionsData, GetProviderConnectionsErrors, GetProviderConnectionsResponses, GetProviderMetadataData, GetProviderMetadataErrors, GetProviderMetadataResponses, GetProvidersMetadataData, GetProvidersMetadataErrors, GetProvidersMetadataResponses, GetProxyLogByIdData, GetProxyLogByIdErrors, GetProxyLogByIdResponses, GetProxyLogByRequestIdData, GetProxyLogByRequestIdErrors, GetProxyLogByRequestIdResponses, GetProxyLogsData, GetProxyLogsErrors, GetProxyLogsResponses, GetPublicBranchesData, GetPublicBranchesErrors, GetPublicBranchesResponses, GetPublicIpData, GetPublicIpErrors, GetPublicIpResponses, GetPublicRepositoryData, GetPublicRepositoryErrors, GetPublicRepositoryResponses, GetQuotaData, GetQuotaErrors, GetQuotaResponses, GetRecentActivityData, GetRecentActivityErrors, GetRecentActivityResponses, GetRemoteExternalImageData, GetRemoteExternalImageErrors, GetRemoteExternalImageResponses, GetRepositoryBranchesData, GetRepositoryBranchesErrors, GetRepositoryBranchesResponses, GetRepositoryByIdData, GetRepositoryByIdErrors, GetRepositoryByIdResponses, GetRepositoryByNameData, GetRepositoryByNameErrors, GetRepositoryByNameResponses, GetRepositoryPresetByNameData, GetRepositoryPresetByNameErrors, GetRepositoryPresetByNameResponses, GetRepositoryPresetLiveData, GetRepositoryPresetLiveErrors, GetRepositoryPresetLiveResponses, GetRepositoryTagsData, GetRepositoryTagsErrors, GetRepositoryTagsResponses, GetResolvedEnvironmentVariablesData, GetResolvedEnvironmentVariablesErrors, GetResolvedEnvironmentVariablesResponses, GetResolvedEnvironmentVariableValueData, GetResolvedEnvironmentVariableValueErrors, GetResolvedEnvironmentVariableValueResponses, GetRestoreCapabilitiesData, GetRestoreCapabilitiesErrors, GetRestoreCapabilitiesResponses, GetRestoreRunData, GetRestoreRunErrors, GetRestoreRunResponses, GetRouteData, GetRouteErrors, GetRouteResponses, GetRunData, GetRunErrors, GetRunResponses, GetRunWithLogsData, GetRunWithLogsErrors, GetRunWithLogsResponses, GetS3CredentialsData, GetS3CredentialsErrors, GetS3CredentialsResponses, GetS3SourceData, GetS3SourceErrors, GetS3SourceResponses, GetSandboxData, GetSandboxErrors, GetSandboxResponses, GetSandboxStatusData, GetSandboxStatusErrors, GetSandboxStatusResponses, GetScanByDeploymentData, GetScanByDeploymentErrors, GetScanByDeploymentResponses, GetScanData, GetScanErrors, GetScanResponses, GetScanVulnerabilitiesData, GetScanVulnerabilitiesErrors, GetScanVulnerabilitiesResponses, GetServiceBySlugData, GetServiceBySlugErrors, GetServiceBySlugResponses, GetServiceData, GetServiceEnvironmentVariableData, GetServiceEnvironmentVariableErrors, GetServiceEnvironmentVariableResponses, GetServiceEnvironmentVariablesData, GetServiceEnvironmentVariablesErrors, GetServiceEnvironmentVariablesResponses, GetServiceErrors, GetServiceHealthStatusData, GetServiceHealthStatusErrors, GetServiceHealthStatusResponses, GetServicePreviewEnvironmentVariableNamesData, GetServicePreviewEnvironmentVariableNamesErrors, GetServicePreviewEnvironmentVariableNamesResponses, GetServicePreviewEnvironmentVariablesMaskedData, GetServicePreviewEnvironmentVariablesMaskedErrors, GetServicePreviewEnvironmentVariablesMaskedResponses, GetServiceResponses, GetServiceRuntimeData, GetServiceRuntimeErrors, GetServiceRuntimeResponses, GetServiceStatsData, GetServiceStatsErrors, GetServiceStatsResponses, GetServiceTypeParametersData, GetServiceTypeParametersErrors, GetServiceTypeParametersResponses, GetServiceTypesData, GetServiceTypesErrors, GetServiceTypesResponses, GetSessionDetailsData, GetSessionDetailsErrors, GetSessionDetailsResponses, GetSessionEventsData, GetSessionEventsErrors, GetSessionEventsResponses, GetSessionLogsData, GetSessionLogsErrors, GetSessionLogsResponses, GetSessionReplayData, GetSessionReplayErrors, GetSessionReplayEventsData, GetSessionReplayEventsErrors, GetSessionReplayEventsResponses, GetSessionReplayResponses, GetSettingsData, GetSettingsErrors, GetSettingsResponses, GetSkillData, GetSkillErrors, GetSkillResponses, GetSlowQueriesData, GetSlowQueriesErrors, GetSlowQueriesResponses, GetStaticBundleData, GetStaticBundleErrors, GetStaticBundleResponses, GetStatusOverviewData, GetStatusOverviewErrors, GetStatusOverviewResponses, GetTagsByRepositoryIdData, GetTagsByRepositoryIdErrors, GetTagsByRepositoryIdResponses, GetTeamData, GetTeamErrors, GetTeamResponses, GetTimeBucketStatsData, GetTimeBucketStatsErrors, GetTimeBucketStatsResponses, GetTodayStatsData, GetTodayStatsErrors, GetTodayStatsResponses, GetTraceData, GetTraceErrors, GetTraceResponses, GetUnifiedTraceData, GetUnifiedTraceErrors, GetUnifiedTraceResponses, GetUniqueCountsData, GetUniqueCountsErrors, GetUniqueCountsResponses, GetUniqueEventsData, GetUniqueEventsErrors, GetUniqueEventsResponses, GetUpdateCapabilityData, GetUpdateCapabilityErrors, GetUpdateCapabilityResponses, GetUpdateStatusData, GetUpdateStatusErrors, GetUpdateStatusResponses, GetUptimeHistoryData, GetUptimeHistoryErrors, GetUptimeHistoryResponses, GetUsageByProviderData, GetUsageByProviderErrors, GetUsageByProviderResponses, GetUsageRecentData, GetUsageRecentErrors, GetUsageRecentResponses, GetUsageSummaryData, GetUsageSummaryErrors, GetUsageSummaryResponses, GetUsageTimeseriesData, GetUsageTimeseriesErrors, GetUsageTimeseriesResponses, GetUsageTopModelsData, GetUsageTopModelsErrors, GetUsageTopModelsResponses, GetVisitorByGuidData, GetVisitorByGuidErrors, GetVisitorByGuidResponses, GetVisitorByIdData, GetVisitorByIdErrors, GetVisitorByIdResponses, GetVisitorDetailsData, GetVisitorDetailsErrors, GetVisitorDetailsResponses, GetVisitorFacetsData, GetVisitorFacetsErrors, GetVisitorFacetsResponses, GetVisitorInfoData, GetVisitorInfoErrors, GetVisitorInfoResponses, GetVisitorJourneyData, GetVisitorJourneyErrors, GetVisitorJourneyResponses, GetVisitorsData, GetVisitorsErrors, GetVisitorSessionsData, GetVisitorSessionsErrors, GetVisitorSessionsResponses, GetVisitorsResponses, GetVisitorStatsData, GetVisitorStatsErrors, GetVisitorStatsResponses, GetWebhookData, GetWebhookErrors, GetWebhookResponses, GrantProjectAccessData, GrantProjectAccessErrors, GrantProjectAccessResponses, HandleGitProviderOauthCallbackData, HandleGitProviderOauthCallbackErrors, HasAnalyticsEventsData, HasAnalyticsEventsErrors, HasAnalyticsEventsResponses, HasErrorGroupsData, HasErrorGroupsErrors, HasErrorGroupsResponses, HasPerformanceMetricsData, HasPerformanceMetricsErrors, HasPerformanceMetricsResponses, ImportExternalServiceData, ImportExternalServiceErrors, ImportExternalServiceResponses, IngestLogsByPathData, IngestLogsByPathErrors, IngestLogsByPathResponses, IngestLogsData, IngestLogsErrors, IngestLogsResponses, IngestMetricsByPathData, IngestMetricsByPathErrors, IngestMetricsByPathResponses, IngestMetricsData, IngestMetricsErrors, IngestMetricsResponses, IngestSentryEnvelopeData, IngestSentryEnvelopeErrors, IngestSentryEnvelopeResponses, IngestSentryEventData, IngestSentryEventErrors, IngestSentryEventResponses, IngestTracesByPathData, IngestTracesByPathErrors, IngestTracesByPathResponses, IngestTracesData, IngestTracesErrors, IngestTracesResponses, InitSessionReplayData, InitSessionReplayErrors, InitSessionReplayResponses, InspectDropArchiveData, InspectDropArchiveErrors, InspectDropArchiveResponses, JobLogsData, JobLogsErrors, JobLogsResponses, JobStatusData, JobStatusErrors, JobStatusResponses, KillJobData, KillJobErrors, KillJobResponses, KvDelData, KvDelErrors, KvDelResponses, KvDisableData, KvDisableErrors, KvDisableResponses, KvEnableData, KvEnableErrors, KvEnableResponses, KvExpireData, KvExpireErrors, KvExpireResponses, KvGetData, KvGetErrors, KvGetResponses, KvIncrData, KvIncrErrors, KvIncrResponses, KvKeysData, KvKeysErrors, KvKeysResponses, KvSetData, KvSetErrors, KvSetResponses, KvStatusData, KvStatusErrors, KvStatusResponses, KvTtlData, KvTtlErrors, KvTtlResponses, KvUpdateData, KvUpdateErrors, KvUpdateResponses, LatestRunForSourceData, LatestRunForSourceErrors, LatestRunForSourceResponses, LinkCustomDomainToCertificateData, LinkCustomDomainToCertificateErrors, LinkCustomDomainToCertificateResponses, LinkServiceToProjectData, LinkServiceToProjectErrors, LinkServiceToProjectResponses, ListAgentRunsData, ListAgentRunsErrors, ListAgentRunsResponses, ListAgentsData, ListAgentsErrors, ListAgentsResponses, ListAiProvidersData, ListAiProvidersErrors, ListAiProvidersResponses, ListAlertRulesData, ListAlertRulesErrors, ListAlertRulesResponses, ListAlertsData, ListAlertsErrors, ListAlertsResponses, ListAllConversationsData, ListAllConversationsErrors, ListAllConversationsResponses, ListAllRunsData, ListAllRunsErrors, ListAllRunsResponses, ListApiKeysData, ListApiKeysErrors, ListApiKeysResponses, ListAuditLogsData, ListAuditLogsErrors, ListAuditLogsResponses, ListAvailableContainersData, ListAvailableContainersErrors, ListAvailableContainersResponses, ListBackupAlertsData, ListBackupAlertsErrors, ListBackupAlertsResponses, ListBackupChildrenData, ListBackupChildrenErrors, ListBackupChildrenResponses, ListBackupSchedulesData, ListBackupSchedulesErrors, ListBackupSchedulesResponses, ListBackupsForScheduleData, ListBackupsForScheduleErrors, ListBackupsForScheduleResponses, ListCommitsByRepositoryIdData, ListCommitsByRepositoryIdErrors, ListCommitsByRepositoryIdResponses, ListConnectionsData, ListConnectionsErrors, ListConnectionsResponses, ListContainersAtPathData, ListContainersAtPathErrors, ListContainersAtPathResponses, ListContainersData, ListContainersErrors, ListContainersResponses, ListConversationsData, ListConversationsErrors, ListConversationsResponses, ListCustomDomainsForProjectData, ListCustomDomainsForProjectErrors, ListCustomDomainsForProjectResponses, ListDashboardsData, ListDashboardsErrors, ListDashboardsResponses, ListDeliveriesData, ListDeliveriesErrors, ListDeliveriesResponses, ListDeploymentContainerLogsData, ListDeploymentContainerLogsErrors, ListDeploymentContainerLogsResponses, ListDeploymentTokensData, ListDeploymentTokensErrors, ListDeploymentTokensResponses, ListDnsProvidersData, ListDnsProvidersErrors, ListDnsProvidersResponses, ListDomainsData, ListDomainsErrors, ListDomainsResponses, ListDsnsData, ListDsnsErrors, ListDsnsResponses, ListEmailDomainsData, ListEmailDomainsErrors, ListEmailDomainsResponses, ListEmailProvidersData, ListEmailProvidersErrors, ListEmailProvidersResponses, ListEmailsData, ListEmailsErrors, ListEmailsResponses, ListEnrollmentTokensData, ListEnrollmentTokensErrors, ListEnrollmentTokensResponses, ListEntitiesData, ListEntitiesErrors, ListEntitiesResponses, ListErrorEventsData, ListErrorEventsErrors, ListErrorEventsResponses, ListErrorGroupsData, ListErrorGroupsErrors, ListErrorGroupsResponses, ListEventsData, ListEventsResponses, ListEventTypesData, ListEventTypesResponses, ListExternalImagesData, ListExternalImagesErrors, ListExternalImagesResponses, ListExternalPluginsData, ListExternalPluginsErrors, ListExternalPluginsResponses, ListExternalServiceBackupsData, ListExternalServiceBackupsErrors, ListExternalServiceBackupsResponses, ListFlagsData, ListFlagsErrors, ListFlagsResponses, ListFunnelsData, ListFunnelsErrors, ListFunnelsResponses, ListGitProvidersData, ListGitProvidersErrors, ListGitProvidersResponses, ListGlobalMcpsData, ListGlobalMcpsErrors, ListGlobalMcpsResponses, ListGlobalSkillsData, ListGlobalSkillsErrors, ListGlobalSkillsResponses, ListIncidentsData, ListIncidentsErrors, ListIncidentsResponses, ListInsightsData, ListInsightsErrors, ListInsightsResponses, ListIpAccessControlData, ListIpAccessControlErrors, ListIpAccessControlResponses, ListJobsData, ListJobsErrors, ListJobsResponses, ListKnownAiAgentsData, ListKnownAiAgentsErrors, ListKnownAiAgentsResponses, ListManagedDomainsData, ListManagedDomainsErrors, ListManagedDomainsResponses, ListMcpsData, ListMcpsErrors, ListMcpsResponses, ListMetricLabelKeysData, ListMetricLabelKeysErrors, ListMetricLabelKeysResponses, ListMetricLabelValuesData, ListMetricLabelValuesErrors, ListMetricLabelValuesResponses, ListMetricNamesData, ListMetricNamesErrors, ListMetricNamesResponses, ListModelsData, ListModelsErrors, ListModelsResponses, ListMonitorsData, ListMonitorsErrors, ListMonitorsResponses, ListNotificationProvidersData, ListNotificationProvidersErrors, ListNotificationProvidersResponses, ListOidcProvidersData, ListOidcProvidersResponses, ListOidcProviderUsersData, ListOidcProviderUsersErrors, ListOidcProviderUsersResponses, ListOidcRoleMappingsData, ListOidcRoleMappingsResponses, ListOnDemandCertsData, ListOnDemandCertsErrors, ListOnDemandCertsResponses, ListOrdersData, ListOrdersErrors, ListOrdersResponses, ListPeersData, ListPeersErrors, ListPeersResponses, ListPendingActionsData, ListPendingActionsErrors, ListPendingActionsResponses, ListPgUpgradesData, ListPgUpgradesErrors, ListPgUpgradesResponses, ListPresetsData, ListPresetsErrors, ListPresetsResponses, ListProjectAccessData, ListProjectAccessErrors, ListProjectAccessResponses, ListProjectAlarmsData, ListProjectAlarmsErrors, ListProjectAlarmsResponses, ListProjectScansData, ListProjectScansErrors, ListProjectScansResponses, ListProjectSecretsData, ListProjectSecretsErrors, ListProjectSecretsResponses, ListProjectServicesData, ListProjectServicesErrors, ListProjectServicesResponses, ListProjectTemplatesData, ListProjectTemplatesErrors, ListProjectTemplatesResponses, ListProjectTemplateTagsData, ListProjectTemplateTagsErrors, ListProjectTemplateTagsResponses, ListProviderKeysData, ListProviderKeysErrors, ListProviderKeysResponses, ListProviderZonesData, ListProviderZonesErrors, ListProviderZonesResponses, ListPublicProvidersData, ListPublicProvidersResponses, ListReleaseFilesData, ListReleaseFilesErrors, ListReleaseFilesResponses, ListReleasesData, ListReleasesErrors, ListReleasesResponses, ListRemoteExternalImagesData, ListRemoteExternalImagesErrors, ListRemoteExternalImagesResponses, ListRepositoriesByConnectionData, ListRepositoriesByConnectionErrors, ListRepositoriesByConnectionResponses, ListRepositoriesByProviderData, ListRepositoriesByProviderErrors, ListRepositoriesByProviderResponses, ListRestoreRunsForServiceData, ListRestoreRunsForServiceResponses, ListRootContainersData, ListRootContainersErrors, ListRootContainersResponses, ListRoutesData, ListRoutesErrors, ListRoutesResponses, ListS3SourcesData, ListS3SourcesErrors, ListS3SourcesResponses, ListSandboxesData, ListSandboxesResponses, ListScheduleRunJobsData, ListScheduleRunJobsErrors, ListScheduleRunJobsResponses, ListScheduleRunsData, ListScheduleRunsErrors, ListScheduleRunsResponses, ListScheduleServicesData, ListScheduleServicesErrors, ListScheduleServicesResponses, ListSecretsData, ListSecretsErrors, ListSecretsResponses, ListServiceHealthStatusesData, ListServiceHealthStatusesErrors, ListServiceHealthStatusesResponses, ListServiceProjectsData, ListServiceProjectsErrors, ListServiceProjectsResponses, ListServiceSchedulesData, ListServiceSchedulesErrors, ListServiceSchedulesResponses, ListServicesData, ListServicesErrors, ListServicesResponses, ListSkillsData, ListSkillsErrors, ListSkillsResponses, ListSourceBackupsData, ListSourceBackupsErrors, ListSourceBackupsResponses, ListSourceFilesData, ListSourceFilesErrors, ListSourceFilesResponses, ListSourceMapsData, ListSourceMapsErrors, ListSourceMapsResponses, ListSourcesData, ListSourcesErrors, ListSourcesResponses, ListStaticBundlesData, ListStaticBundlesErrors, ListStaticBundlesResponses, ListSyncedRepositoriesData, ListSyncedRepositoriesErrors, ListSyncedRepositoriesResponses, ListTeamMembersData, ListTeamMembersErrors, ListTeamMembersResponses, ListTeamProjectsData, ListTeamProjectsErrors, ListTeamProjectsResponses, ListTeamsData, ListTeamsErrors, ListTeamsResponses, ListUsersData, ListUsersErrors, ListUsersResponses, ListWebhooksData, ListWebhooksErrors, ListWebhooksResponses, LoginData, LoginErrors, LoginResponses, LogoutData, LogoutErrors, LogoutResponses, LookupDnsARecordsData, LookupDnsARecordsErrors, LookupDnsARecordsResponses, MintEnrollmentTokenData, MintEnrollmentTokenErrors, MintEnrollmentTokenResponses, MkdirData, MkdirErrors, MkdirResponses, NodeHeartbeatData, NodeHeartbeatErrors, NodeHeartbeatResponses, NodeMetricsGetRangeData, NodeMetricsGetRangeErrors, NodeMetricsGetRangeResponses, ObservabilityFullEventData, ObservabilityFullEventErrors, ObservabilityFullEventResponses, ObservabilityListEventsData, ObservabilityListEventsErrors, ObservabilityListEventsResponses, OidcCallbackData, PatchAdminGateData, PatchAdminGateErrors, PatchAdminGateResponses, PatchPreviewGatewaySettingsData, PatchPreviewGatewaySettingsResponses, PauseDeploymentData, PauseDeploymentErrors, PauseDeploymentResponses, PauseSandboxData, PauseSandboxErrors, PauseSandboxResponses, PlanRestoreData, PlanRestoreErrors, PlanRestoreResponses, PostDnsAckData, PostDnsAckErrors, PostDnsAckResponses, PreviewAlertData, PreviewAlertErrors, PreviewAlertResponses, PreviewFunnelMetricsData, PreviewFunnelMetricsErrors, PreviewFunnelMetricsResponses, PreviewHostnameModeData, PreviewHostnameModeErrors, PreviewHostnameModeResponses, PromoteClusterMemberData, PromoteClusterMemberErrors, PromoteClusterMemberResponses, PromoteDeploymentData, PromoteDeploymentErrors, PromoteDeploymentResponses, ProvisionDomainData, ProvisionDomainErrors, ProvisionDomainResponses, PurgeProjectLogsData, PurgeProjectLogsErrors, PurgeProjectLogsResponses, PushExternalImageData, PushExternalImageErrors, PushExternalImageResponses, QueryDataData, QueryDataErrors, QueryDataResponses, QueryGenaiTracesData, QueryGenaiTracesErrors, QueryGenaiTracesResponses, QueryLogsData, QueryLogsErrors, QueryLogsResponses, QueryMetricsData, QueryMetricsErrors, QueryMetricsResponses, QueryTracesData, QueryTracesErrors, QueryTracesResponses, QueryTraceSummariesData, QueryTraceSummariesErrors, QueryTraceSummariesResponses, ReadFileData, ReadFileErrors, ReadFileResponses, ReAnalyzeData, ReAnalyzeErrors, ReAnalyzeResponses, RebuildSandboxImageData, RebuildSandboxImageErrors, RebuildSandboxImageResponses, RecordConsoleEventData, RecordConsoleEventErrors, RecordConsoleEventResponses, RecordEventMetricsData, RecordEventMetricsErrors, RecordEventMetricsResponses, RecordFlagExposureData, RecordFlagExposureErrors, RecordFlagExposureResponses, RecordSpeedMetricsData, RecordSpeedMetricsErrors, RecordSpeedMetricsResponses, RefreshRouteTableData, RefreshRouteTableErrors, RefreshRouteTableResponses, RegenerateDsnData, RegenerateDsnErrors, RegenerateDsnResponses, RegisterExternalImageData, RegisterExternalImageErrors, RegisterExternalImageResponses, RegisterNodeData, RegisterNodeErrors, RegisterNodeResponses, ReinstallGitlabWebhookData, ReinstallGitlabWebhookErrors, ReinstallGitlabWebhookResponses, RejectPendingActionData, RejectPendingActionErrors, RejectPendingActionResponses, ReloadPluginsData, ReloadPluginsErrors, ReloadPluginsResponses, RemoveClusterMemberData, RemoveClusterMemberErrors, RemoveClusterMemberResponses, RemoveManagedDomainData, RemoveManagedDomainErrors, RemoveManagedDomainResponses, RemoveRoleData, RemoveRoleErrors, RemoveRoleResponses, RemoveTeamMemberData, RemoveTeamMemberErrors, RemoveTeamMemberResponses, RenameConversationData, RenameConversationErrors, RenameConversationResponses, RenewDomainData, RenewDomainErrors, RenewDomainResponses, RequestPasswordResetData, RequestPasswordResetErrors, RequestPasswordResetResponses, ResetPasswordData, ResetPasswordErrors, ResetPasswordResponses, ResizeSandboxData, ResizeSandboxErrors, ResizeSandboxResponses, ResolveAlarmData, ResolveAlarmErrors, ResolveAlarmResponses, RestartContainerData, RestartContainerErrors, RestartContainerResponses, RestartPreviewGatewayData, RestartPreviewGatewayResponses, RestartSandboxData, RestartSandboxErrors, RestartSandboxResponses, RestoreFlagData, RestoreFlagErrors, RestoreFlagResponses, RestoreUserData, RestoreUserErrors, RestoreUserResponses, ResumeDeploymentData, ResumeDeploymentErrors, ResumeDeploymentResponses, ResumeSandboxData, ResumeSandboxErrors, ResumeSandboxResponses, RetryClusterData, RetryClusterErrors, RetryClusterResponses, RetryDeliveryData, RetryDeliveryErrors, RetryDeliveryResponses, RetryPgUpgradeData, RetryPgUpgradeErrors, RetryPgUpgradeResponses, RetryRunData, RetryRunErrors, RetryRunResponses, RevealGlobalMcpConfigData, RevealGlobalMcpConfigErrors, RevealGlobalMcpConfigResponses, RevealMcpConfigData, RevealMcpConfigErrors, RevealMcpConfigResponses, RevealNotificationProviderConfigData, RevealNotificationProviderConfigErrors, RevealNotificationProviderConfigResponses, RevealServiceParameterData, RevealServiceParameterErrors, RevealServiceParameterResponses, RevenueCreateIntegrationData, RevenueCreateIntegrationErrors, RevenueCreateIntegrationResponses, RevenueDeleteIntegrationData, RevenueDeleteIntegrationResponses, RevenueGlobalEventsData, RevenueGlobalEventsResponses, RevenueImportInvoicesCsvData, RevenueImportInvoicesCsvErrors, RevenueImportInvoicesCsvResponses, RevenueImportSubscriptionsCsvData, RevenueImportSubscriptionsCsvErrors, RevenueImportSubscriptionsCsvResponses, RevenueListIntegrationsData, RevenueListIntegrationsResponses, RevenueListProvidersData, RevenueListProvidersResponses, RevenueMetricsCustomersData, RevenueMetricsCustomersResponses, RevenueMetricsGlobalMrrData, RevenueMetricsGlobalMrrResponses, RevenueMetricsGlobalSummaryData, RevenueMetricsGlobalSummaryResponses, RevenueMetricsMrrData, RevenueMetricsMrrResponses, RevenueMetricsSummaryData, RevenueMetricsSummaryResponses, RevenueRecentEventsData, RevenueRecentEventsResponses, RevenueRotateTokenData, RevenueRotateTokenResponses, RevenueUpdateConfigData, RevenueUpdateConfigErrors, RevenueUpdateConfigResponses, RevenueUpdateSecretData, RevenueUpdateSecretErrors, RevenueUpdateSecretResponses, RevokeDsnData, RevokeDsnErrors, RevokeDsnResponses, RevokeEnrollmentTokenData, RevokeEnrollmentTokenErrors, RevokeEnrollmentTokenResponses, RevokeJoinTokenData, RevokeJoinTokenErrors, RevokeJoinTokenResponses, RevokeProjectAccessData, RevokeProjectAccessErrors, RevokeProjectAccessResponses, RollbackPgUpgradeData, RollbackPgUpgradeErrors, RollbackPgUpgradeResponses, RollbackToDeploymentData, RollbackToDeploymentErrors, RollbackToDeploymentResponses, RootfsGcData, RootfsGcResponses, RootfsReportData, RootfsReportResponses, RotateApiKeyData, RotateApiKeyErrors, RotateApiKeyResponses, RotateDeploymentTokenData, RotateDeploymentTokenErrors, RotateDeploymentTokenResponses, RunBackupForSourceData, RunBackupForSourceErrors, RunBackupForSourceResponses, RunConnectionHealthCheckData, RunConnectionHealthCheckErrors, RunConnectionHealthCheckResponses, RunExternalServiceBackupData, RunExternalServiceBackupErrors, RunExternalServiceBackupResponses, RunScheduleNowData, RunScheduleNowErrors, RunScheduleNowResponses, SandboxCreatePreviewLinkData, SandboxCreatePreviewLinkErrors, SandboxCreatePreviewLinkResponses, SaveAgentTokenData, SaveAgentTokenErrors, SaveAgentTokenResponses, SaveAiProviderCredentialData, SaveAiProviderCredentialErrors, SaveAiProviderCredentialResponses, SearchLogsData, SearchLogsErrors, SearchLogsResponses, SendEmailData, SendEmailErrors, SendEmailResponses, SendMessageData, SendMessageErrors, SendMessageResponses, SetDefaultS3SourceData, SetDefaultS3SourceErrors, SetDefaultS3SourceResponses, SetFlagEnvironmentData, SetFlagEnvironmentErrors, SetFlagEnvironmentResponses, SetPreviewPasswordData, SetPreviewPasswordErrors, SetPreviewPasswordResponses, SetupDnsChallengeData, SetupDnsChallengeErrors, SetupDnsChallengeResponses, SetupDnsData, SetupDnsErrors, SetupDnsResponses, SetupEmailTrackingData, SetupEmailTrackingErrors, SetupEmailTrackingResponses, SetupMfaData, SetupMfaErrors, SetupMfaResponses, SleepEnvironmentData, SleepEnvironmentErrors, SleepEnvironmentResponses, SmokeTestAgentData, SmokeTestAgentErrors, SmokeTestAgentResponses, SourceSandboxData, SourceSandboxErrors, SourceSandboxResponses, StartAnalysisData, StartAnalysisErrors, StartAnalysisResponses, StartContainerData, StartContainerErrors, StartContainerResponses, StartFixData, StartFixErrors, StartFixResponses, StartGitProviderOauthData, StartGitProviderOauthErrors, StartOidcLoginBySlugData, StartOidcLoginBySlugErrors, StartPgUpgradeData, StartPgUpgradeErrors, StartPgUpgradeResponses, StartRestoreData, StartRestoreErrors, StartRestoreResponses, StartServiceData, StartServiceErrors, StartServiceResponses, StartUpdateData, StartUpdateErrors, StartUpdateResponses, StatPathData, StatPathErrors, StatPathResponses, StopContainerData, StopContainerErrors, StopContainerResponses, StopSandboxData, StopSandboxErrors, StopSandboxResponses, StopServiceData, StopServiceErrors, StopServiceResponses, StreamContainerMetricsData, StreamContainerMetricsErrors, StreamContainerMetricsResponses, StreamEventsData, StreamEventsErrors, StreamEventsResponses, StreamRunEventsData, StreamRunEventsErrors, StreamRunEventsResponses, SyncRepositoriesData, SyncRepositoriesErrors, SyncRepositoriesResponses, TailDeploymentJobLogsData, TailDeploymentJobLogsErrors, TailLogsData, TailLogsErrors, TailLogsResponses, TeardownDeploymentData, TeardownDeploymentErrors, TeardownDeploymentResponses, TeardownEnvironmentData, TeardownEnvironmentErrors, TeardownEnvironmentResponses, TestNotificationProviderData, TestNotificationProviderErrors, TestNotificationProviderResponses, TestOidcProviderData, TestOidcProviderResponses, TestProviderConnectionData, TestProviderConnectionErrors, TestProviderConnectionResponses, TestProviderData, TestProviderErrors, TestProviderKeyByIdData, TestProviderKeyByIdErrors, TestProviderKeyByIdResponses, TestProviderKeyInlineData, TestProviderKeyInlineErrors, TestProviderKeyInlineResponses, TestProviderResponses, TestS3ConnectionPreviewData, TestS3ConnectionPreviewErrors, TestS3ConnectionPreviewResponses, TestS3SourceConnectionData, TestS3SourceConnectionErrors, TestS3SourceConnectionResponses, TrackClickData, TrackClickErrors, TrackOpenData, TrackOpenErrors, TrackOpenResponses, TriggerAgentData, TriggerAgentErrors, TriggerAgentResponses, TriggerProjectPipelineData, TriggerProjectPipelineErrors, TriggerProjectPipelineResponses, TriggerScanData, TriggerScanErrors, TriggerScanResponses, TriggerServiceHealthCheckData, TriggerServiceHealthCheckErrors, TriggerServiceHealthCheckResponses, TriggerWeeklyDigestData, TriggerWeeklyDigestErrors, TriggerWeeklyDigestResponses, UnlinkServiceFromProjectData, UnlinkServiceFromProjectErrors, UnlinkServiceFromProjectResponses, UpdateAgentData, UpdateAgentErrors, UpdateAgentResponses, UpdateAiProviderData, UpdateAiProviderErrors, UpdateAiProviderResponses, UpdateAlertData, UpdateAlertErrors, UpdateAlertResponses, UpdateAlertRuleData, UpdateAlertRuleErrors, UpdateAlertRuleResponses, UpdateApiKeyData, UpdateApiKeyErrors, UpdateApiKeyResponses, UpdateAutomaticDeployData, UpdateAutomaticDeployErrors, UpdateAutomaticDeployResponses, UpdateBackupScheduleData, UpdateBackupScheduleErrors, UpdateBackupScheduleResponses, UpdateCloudflareProviderData, UpdateCloudflareProviderErrors, UpdateCloudflareProviderResponses, UpdateConnectionTokenData, UpdateConnectionTokenErrors, UpdateConnectionTokenResponses, UpdateCustomDomainData, UpdateCustomDomainErrors, UpdateCustomDomainResponses, UpdateDashboardData, UpdateDashboardErrors, UpdateDashboardResponses, UpdateDeploymentTokenData, UpdateDeploymentTokenErrors, UpdateDeploymentTokenResponses, UpdateEmailProviderData, UpdateEmailProviderErrors, UpdateEmailProviderResponses, UpdateEnvironmentSettingsData, UpdateEnvironmentSettingsErrors, UpdateEnvironmentSettingsResponses, UpdateEnvironmentSubdomainData, UpdateEnvironmentSubdomainErrors, UpdateEnvironmentSubdomainResponses, UpdateEnvironmentVariableData, UpdateEnvironmentVariableErrors, UpdateEnvironmentVariableResponses, UpdateErrorGroupData, UpdateErrorGroupErrors, UpdateErrorGroupResponses, UpdateFlagData, UpdateFlagErrors, UpdateFlagResponses, UpdateFunnelData, UpdateFunnelErrors, UpdateFunnelResponses, UpdateGitProviderCredentialsData, UpdateGitProviderCredentialsErrors, UpdateGitProviderCredentialsResponses, UpdateGitSettingsData, UpdateGitSettingsErrors, UpdateGitSettingsResponses, UpdateGlobalMcpData, UpdateGlobalMcpErrors, UpdateGlobalMcpResponses, UpdateGlobalSkillData, UpdateGlobalSkillErrors, UpdateGlobalSkillResponses, UpdateIncidentStatusData, UpdateIncidentStatusErrors, UpdateIncidentStatusResponses, UpdateIpAccessControlData, UpdateIpAccessControlErrors, UpdateIpAccessControlResponses, UpdateManagedDomainData, UpdateManagedDomainErrors, UpdateManagedDomainResponses, UpdateMcpData, UpdateMcpErrors, UpdateMcpResponses, UpdateNotificationEmailProviderData, UpdateNotificationEmailProviderErrors, UpdateNotificationEmailProviderResponses, UpdateNotificationProviderData, UpdateNotificationProviderErrors, UpdateNotificationProviderResponses, UpdateOidcProviderData, UpdateOidcProviderResponses, UpdatePreferencesData, UpdatePreferencesErrors, UpdatePreferencesResponses, UpdateProjectData, UpdateProjectDeploymentConfigData, UpdateProjectDeploymentConfigErrors, UpdateProjectDeploymentConfigResponses, UpdateProjectErrors, UpdateProjectResponses, UpdateProjectSecretData, UpdateProjectSecretErrors, UpdateProjectSecretResponses, UpdateProjectSettingsData, UpdateProjectSettingsErrors, UpdateProjectSettingsResponses, UpdateProviderData, UpdateProviderErrors, UpdateProviderKeyData, UpdateProviderKeyErrors, UpdateProviderKeyResponses, UpdateProviderResponses, UpdateRouteData, UpdateRouteErrors, UpdateRouteResponses, UpdateS3SourceData, UpdateS3SourceErrors, UpdateS3SourceResponses, UpdateSelfData, UpdateSelfErrors, UpdateSelfResponses, UpdateServiceData, UpdateServiceErrors, UpdateServiceResourcesData, UpdateServiceResourcesErrors, UpdateServiceResourcesResponses, UpdateServiceResponses, UpdateSessionDurationData, UpdateSessionDurationErrors, UpdateSessionDurationResponses, UpdateSettingsData, UpdateSettingsErrors, UpdateSettingsResponses, UpdateSkillData, UpdateSkillErrors, UpdateSkillResponses, UpdateSlackProviderData, UpdateSlackProviderErrors, UpdateSlackProviderResponses, UpdateSpeedMetricsData, UpdateSpeedMetricsErrors, UpdateSpeedMetricsResponses, UpdateTeamData, UpdateTeamErrors, UpdateTeamMemberRoleData, UpdateTeamMemberRoleErrors, UpdateTeamMemberRoleResponses, UpdateTeamResponses, UpdateUserData, UpdateUserErrors, UpdateUserResponses, UpdateWebhookData, UpdateWebhookErrors, UpdateWebhookProviderData, UpdateWebhookProviderErrors, UpdateWebhookProviderResponses, UpdateWebhookResponses, UpgradePreviewGatewayData, UpgradePreviewGatewayResponses, UpgradeServiceData, UpgradeServiceErrors, UpgradeServiceResponses, UploadGlobalSkillData, UploadGlobalSkillErrors, UploadGlobalSkillResponses, UploadReleaseFileData, UploadReleaseFileErrors, UploadReleaseFileResponses, UploadSkillData, UploadSkillErrors, UploadSkillResponses, UploadSourceFileData, UploadSourceFileErrors, UploadSourceFileResponses, UploadSourceMapData, UploadSourceMapErrors, UploadSourceMapResponses, UploadStaticBundleData, UploadStaticBundleErrors, UploadStaticBundleResponses, UpsertSecretData, UpsertSecretErrors, UpsertSecretResponses, ValidateConnectionData, ValidateConnectionErrors, ValidateConnectionResponses, ValidateEmailData, ValidateEmailErrors, ValidateEmailResponses, VerifyAndEnableMfaData, VerifyAndEnableMfaErrors, VerifyAndEnableMfaResponses, VerifyDomainData, VerifyDomainErrors, VerifyDomainResponses, VerifyEmailData, VerifyEmailErrors, VerifyEmailResponses, VerifyManagedDomainData, VerifyManagedDomainErrors, VerifyManagedDomainResponses, VerifyMfaChallengeData, VerifyMfaChallengeErrors, VerifyMfaChallengeResponses, VerifyStepUpData, VerifyStepUpErrors, VerifyStepUpResponses, WakeEnvironmentData, WakeEnvironmentErrors, WakeEnvironmentResponses, WebhookTriggerData, WebhookTriggerErrors, WebhookTriggerResponses, WorkflowDryRunData, WorkflowDryRunErrors, WorkflowDryRunResponses, WriteFileData, WriteFileErrors, WriteFileResponses, WriteFilesData, WriteFilesErrors, WriteFilesResponses } from './types.gen'; +import type { AcknowledgeAlarmData, AcknowledgeAlarmErrors, AcknowledgeAlarmResponses, ActivateAiProviderData, ActivateAiProviderErrors, ActivateAiProviderResponses, ActivateApiKeyData, ActivateApiKeyErrors, ActivateApiKeyResponses, ActivateConnectionData, ActivateConnectionErrors, ActivateConnectionResponses, ActivateProviderData, ActivateProviderErrors, ActivateProviderResponses, AddClusterMemberData, AddClusterMemberErrors, AddClusterMemberResponses, AddContextData, AddContextErrors, AddContextResponses, AddEnvironmentDomainData, AddEnvironmentDomainErrors, AddEnvironmentDomainResponses, AddEventsData, AddEventsErrors, AddEventsResponses, AddManagedDomainData, AddManagedDomainErrors, AddManagedDomainResponses, AddSessionReplayEventsData, AddSessionReplayEventsErrors, AddSessionReplayEventsResponses, AddTeamMemberData, AddTeamMemberErrors, AddTeamMemberResponses, AdminDrainNodeData, AdminDrainNodeErrors, AdminDrainNodeResponses, AdminDrainStatusData, AdminDrainStatusErrors, AdminDrainStatusResponses, AdminGetNodeData, AdminGetNodeErrors, AdminGetNodeResponses, AdminListNodeContainersData, AdminListNodeContainersErrors, AdminListNodeContainersResponses, AdminListNodesData, AdminListNodesErrors, AdminListNodesResponses, AdminRemoveNodeData, AdminRemoveNodeErrors, AdminRemoveNodeResponses, AdminUndrainNodeData, AdminUndrainNodeErrors, AdminUndrainNodeResponses, ApplyHostnameModeData, ApplyHostnameModeErrors, ApplyHostnameModeResponses, ArchiveConversationData, ArchiveConversationErrors, ArchiveConversationResponses, ArchiveFlagData, ArchiveFlagErrors, ArchiveFlagResponses, AssignRoleData, AssignRoleErrors, AssignRoleResponses, AttachScheduleServicesData, AttachScheduleServicesErrors, AttachScheduleServicesResponses, BlobCopyData, BlobCopyErrors, BlobCopyResponses, BlobDeleteData, BlobDeleteErrors, BlobDeleteResponses, BlobDisableData, BlobDisableErrors, BlobDisableResponses, BlobDownloadData, BlobDownloadErrors, BlobDownloadResponses, BlobEnableData, BlobEnableErrors, BlobEnableResponses, BlobHeadData, BlobHeadErrors, BlobHeadResponses, BlobListData, BlobListErrors, BlobListResponses, BlobPutData, BlobPutErrors, BlobPutResponses, BlobStatusData, BlobStatusErrors, BlobStatusResponses, BlobUpdateData, BlobUpdateErrors, BlobUpdateResponses, CancelBackupData, CancelBackupErrors, CancelBackupResponses, CancelData, CancelDeploymentData, CancelDeploymentErrors, CancelDeploymentResponses, CancelDomainOrderData, CancelDomainOrderErrors, CancelDomainOrderResponses, CancelErrors, CancelPgUpgradeData, CancelPgUpgradeErrors, CancelPgUpgradeResponses, CancelResponses, CancelRunData, CancelRunErrors, CancelRunResponses, CancelScheduleRunData, CancelScheduleRunErrors, CancelScheduleRunResponses, ChangePasswordSelfData, ChangePasswordSelfErrors, ChangePasswordSelfResponses, ChangeProjectSourceData, ChangeProjectSourceErrors, ChangeProjectSourceResponses, ChangeRequiredPasswordData, ChangeRequiredPasswordErrors, ChangeRequiredPasswordResponses, ChatCompletionsData, ChatCompletionsErrors, ChatCompletionsResponses, CheckAnalyticsHasEventsData, CheckAnalyticsHasEventsErrors, CheckAnalyticsHasEventsResponses, CheckCommitExistsData, CheckCommitExistsErrors, CheckCommitExistsResponses, CheckDomainStatusData, CheckDomainStatusErrors, CheckDomainStatusResponses, CheckExplorerSupportData, CheckExplorerSupportErrors, CheckExplorerSupportResponses, CheckForUpdateData, CheckForUpdateErrors, CheckForUpdateResponses, CheckIpBlockedData, CheckIpBlockedErrors, CheckIpBlockedResponses, CheckProviderDeletionSafetyData, CheckProviderDeletionSafetyErrors, CheckProviderDeletionSafetyResponses, ChunkUploadOptionsData, ChunkUploadOptionsResponses, CleanupExpiredBackupsData, CleanupExpiredBackupsErrors, CleanupExpiredBackupsResponses, ClearPreviewPasswordData, ClearPreviewPasswordErrors, ClearPreviewPasswordResponses, CliDeviceApproveData, CliDeviceApproveErrors, CliDeviceApproveResponses, CliDeviceDenyData, CliDeviceDenyErrors, CliDeviceDenyResponses, CliDeviceLookupData, CliDeviceLookupErrors, CliDeviceLookupResponses, CliDevicePollData, CliDevicePollErrors, CliDevicePollResponses, CliDeviceStartData, CliDeviceStartErrors, CliDeviceStartResponses, CliLogoutData, CliLogoutErrors, CliLogoutResponses, CmdData, CmdErrors, CmdKillData, CmdKillErrors, CmdKillResponses, CmdLogsData, CmdLogsErrors, CmdLogsResponses, CmdResponses, ConfirmPendingActionData, ConfirmPendingActionErrors, ConfirmPendingActionResponses, ContainerMetricsGetHistoryData, ContainerMetricsGetHistoryErrors, ContainerMetricsGetHistoryResponses, CreateAgentData, CreateAgentErrors, CreateAgentResponses, CreateAlertData, CreateAlertErrors, CreateAlertResponses, CreateAlertRuleData, CreateAlertRuleErrors, CreateAlertRuleResponses, CreateApiKeyData, CreateApiKeyErrors, CreateApiKeyResponses, CreateBackupScheduleData, CreateBackupScheduleErrors, CreateBackupScheduleResponses, CreateBitbucketProviderData, CreateBitbucketProviderErrors, CreateBitbucketProviderResponses, CreateCloudflareProviderData, CreateCloudflareProviderErrors, CreateCloudflareProviderResponses, CreateConversationData, CreateConversationErrors, CreateConversationResponses, CreateCustomDomainData, CreateCustomDomainErrors, CreateCustomDomainResponses, CreateDashboardData, CreateDashboardErrors, CreateDashboardResponses, CreateDeploymentTokenData, CreateDeploymentTokenErrors, CreateDeploymentTokenResponses, CreateDnsProviderData, CreateDnsProviderErrors, CreateDnsProviderResponses, CreateDomainData, CreateDomainErrors, CreateDomainResponses, CreateDsnData, CreateDsnErrors, CreateDsnResponses, CreateEmailDomainData, CreateEmailDomainErrors, CreateEmailDomainResponses, CreateEmailProviderData, CreateEmailProviderErrors, CreateEmailProviderResponses, CreateEnvironmentData, CreateEnvironmentErrors, CreateEnvironmentResponses, CreateEnvironmentVariableData, CreateEnvironmentVariableErrors, CreateEnvironmentVariableResponses, CreateFlagData, CreateFlagErrors, CreateFlagResponses, CreateFunnelData, CreateFunnelErrors, CreateFunnelResponses, CreateGenericProviderData, CreateGenericProviderErrors, CreateGenericProviderResponses, CreateGiteaPatProviderData, CreateGiteaPatProviderErrors, CreateGiteaPatProviderResponses, CreateGithubPatProviderData, CreateGithubPatProviderErrors, CreateGithubPatProviderResponses, CreateGitlabOauthProviderData, CreateGitlabOauthProviderErrors, CreateGitlabOauthProviderResponses, CreateGitlabPatProviderData, CreateGitlabPatProviderErrors, CreateGitlabPatProviderResponses, CreateGitProviderData, CreateGitProviderErrors, CreateGitProviderResponses, CreateGlobalMcpData, CreateGlobalMcpErrors, CreateGlobalMcpResponses, CreateGlobalSkillData, CreateGlobalSkillErrors, CreateGlobalSkillResponses, CreateIncidentData, CreateIncidentErrors, CreateIncidentResponses, CreateIpAccessControlData, CreateIpAccessControlErrors, CreateIpAccessControlResponses, CreateMcpData, CreateMcpErrors, CreateMcpResponses, CreateMonitorData, CreateMonitorErrors, CreateMonitorResponses, CreateNotificationEmailProviderData, CreateNotificationEmailProviderErrors, CreateNotificationEmailProviderResponses, CreateNotificationProviderData, CreateNotificationProviderErrors, CreateNotificationProviderResponses, CreateOidcProviderData, CreateOidcProviderErrors, CreateOidcProviderResponses, CreateOidcRoleMappingData, CreateOidcRoleMappingResponses, CreateOrRecreateOrderData, CreateOrRecreateOrderErrors, CreateOrRecreateOrderResponses, CreatePlanData, CreatePlanErrors, CreatePlanResponses, CreatePrData, CreatePrErrors, CreateProjectData, CreateProjectErrors, CreateProjectFromTemplateData, CreateProjectFromTemplateErrors, CreateProjectFromTemplateResponses, CreateProjectReleaseData, CreateProjectReleaseErrors, CreateProjectReleaseResponses, CreateProjectResponses, CreateProjectSecretData, CreateProjectSecretErrors, CreateProjectSecretResponses, CreateProviderKeyData, CreateProviderKeyErrors, CreateProviderKeyResponses, CreatePrResponses, CreateReleaseData, CreateReleaseErrors, CreateReleaseResponses, CreateRouteData, CreateRouteErrors, CreateRouteResponses, CreateS3SourceData, CreateS3SourceErrors, CreateS3SourceResponses, CreateSandboxData, CreateSandboxErrors, CreateSandboxResponses, CreateServiceData, CreateServiceErrors, CreateServiceResponses, CreateSkillData, CreateSkillErrors, CreateSkillResponses, CreateSlackProviderData, CreateSlackProviderErrors, CreateSlackProviderResponses, CreateTeamData, CreateTeamErrors, CreateTeamResponses, CreateUserData, CreateUserErrors, CreateUserResponses, CreateWebhookData, CreateWebhookErrors, CreateWebhookProviderData, CreateWebhookProviderErrors, CreateWebhookProviderResponses, CreateWebhookResponses, DeactivateApiKeyData, DeactivateApiKeyErrors, DeactivateApiKeyResponses, DeactivateConnectionData, DeactivateConnectionErrors, DeactivateConnectionResponses, DeactivateProviderData, DeactivateProviderErrors, DeactivateProviderResponses, DeleteAgentData, DeleteAgentErrors, DeleteAgentResponses, DeleteAlertData, DeleteAlertErrors, DeleteAlertResponses, DeleteAlertRuleData, DeleteAlertRuleErrors, DeleteAlertRuleResponses, DeleteApiKeyData, DeleteApiKeyErrors, DeleteApiKeyResponses, DeleteBackupData, DeleteBackupErrors, DeleteBackupResponses, DeleteBackupScheduleData, DeleteBackupScheduleErrors, DeleteBackupScheduleResponses, DeleteConnectionData, DeleteConnectionErrors, DeleteConnectionResponses, DeleteCustomDomainData, DeleteCustomDomainErrors, DeleteCustomDomainResponses, DeleteDashboardData, DeleteDashboardErrors, DeleteDashboardResponses, DeleteDeploymentTokenData, DeleteDeploymentTokenErrors, DeleteDeploymentTokenResponses, DeleteDnsProviderData, DeleteDnsProviderErrors, DeleteDnsProviderResponses, DeleteDomainData, DeleteDomainErrors, DeleteDomainResponses, DeleteEmailDomainData, DeleteEmailDomainErrors, DeleteEmailDomainResponses, DeleteEmailProviderData, DeleteEmailProviderErrors, DeleteEmailProviderResponses, DeleteEnvironmentData, DeleteEnvironmentDomainData, DeleteEnvironmentDomainErrors, DeleteEnvironmentDomainResponses, DeleteEnvironmentErrors, DeleteEnvironmentResponses, DeleteEnvironmentVariableData, DeleteEnvironmentVariableErrors, DeleteEnvironmentVariableResponses, DeleteExternalImageData, DeleteExternalImageErrors, DeleteExternalImageResponses, DeleteFunnelData, DeleteFunnelErrors, DeleteFunnelResponses, DeleteGitProviderData, DeleteGitProviderErrors, DeleteGitProviderResponses, DeleteGlobalMcpData, DeleteGlobalMcpErrors, DeleteGlobalMcpResponses, DeleteGlobalSkillData, DeleteGlobalSkillErrors, DeleteGlobalSkillResponses, DeleteIpAccessControlData, DeleteIpAccessControlErrors, DeleteIpAccessControlResponses, DeleteMcpData, DeleteMcpErrors, DeleteMcpResponses, DeleteMonitorData, DeleteMonitorErrors, DeleteMonitorResponses, DeleteNotificationProviderData, DeleteNotificationProviderErrors, DeleteNotificationProviderResponses, DeleteOidcProviderData, DeleteOidcProviderResponses, DeleteOidcRoleMappingData, DeleteOidcRoleMappingResponses, DeletePreferencesData, DeletePreferencesErrors, DeletePreferencesResponses, DeleteProjectData, DeleteProjectErrors, DeleteProjectResponses, DeleteProjectSecretData, DeleteProjectSecretErrors, DeleteProjectSecretResponses, DeleteProviderKeyData, DeleteProviderKeyErrors, DeleteProviderKeyResponses, DeleteProviderSafelyData, DeleteProviderSafelyErrors, DeleteProviderSafelyResponses, DeleteReleaseSourceFilesData, DeleteReleaseSourceFilesErrors, DeleteReleaseSourceFilesResponses, DeleteReleaseSourceMapsData, DeleteReleaseSourceMapsErrors, DeleteReleaseSourceMapsResponses, DeleteRouteData, DeleteRouteErrors, DeleteRouteResponses, DeleteS3SourceData, DeleteS3SourceErrors, DeleteS3SourceResponses, DeleteScanData, DeleteScanErrors, DeleteScanResponses, DeleteSecretData, DeleteSecretErrors, DeleteSecretResponses, DeleteServiceData, DeleteServiceErrors, DeleteServiceResponses, DeleteSessionReplayData, DeleteSessionReplayErrors, DeleteSessionReplayResponses, DeleteSkillData, DeleteSkillErrors, DeleteSkillResponses, DeleteSourceMapData, DeleteSourceMapErrors, DeleteSourceMapResponses, DeleteStaticBundleData, DeleteStaticBundleErrors, DeleteStaticBundleResponses, DeleteTeamData, DeleteTeamErrors, DeleteTeamResponses, DeleteUserData, DeleteUserErrors, DeleteUserResponses, DeleteWebhookData, DeleteWebhookErrors, DeleteWebhookResponses, DeployFromImageData, DeployFromImageErrors, DeployFromImageResponses, DeployFromImageUploadData, DeployFromImageUploadErrors, DeployFromImageUploadResponses, DeployFromStaticData, DeployFromStaticErrors, DeployFromStaticResponses, DeployFromUploadedSourceData, DeployFromUploadedSourceErrors, DeployFromUploadedSourceResponses, DeploymentMetricsGetLatestData, DeploymentMetricsGetLatestErrors, DeploymentMetricsGetLatestResponses, DeploymentMetricsGetRangeData, DeploymentMetricsGetRangeErrors, DeploymentMetricsGetRangeResponses, DeploymentMetricsToggleData, DeploymentMetricsToggleErrors, DeploymentMetricsToggleResponses, DestroySandboxData, DestroySandboxErrors, DestroySandboxResponses, DetachScheduleServiceData, DetachScheduleServiceErrors, DetachScheduleServiceResponses, DetectPublicPresetsData, DetectPublicPresetsErrors, DetectPublicPresetsResponses, DisableBackupScheduleData, DisableBackupScheduleErrors, DisableBackupScheduleResponses, DisableMfaData, DisableMfaErrors, DisableMfaResponses, DiscoverWorkloadsData, DiscoverWorkloadsErrors, DiscoverWorkloadsResponses, DomainData, DomainErrors, DomainResponses, DownloadGlobalSkillArchiveData, DownloadGlobalSkillArchiveErrors, DownloadGlobalSkillArchiveResponses, DownloadObjectData, DownloadObjectErrors, DownloadObjectResponses, DownloadSkillArchiveData, DownloadSkillArchiveErrors, DownloadSkillArchiveResponses, EmailStatusData, EmailStatusErrors, EmailStatusResponses, EmbeddingsData, EmbeddingsErrors, EmbeddingsResponses, EnableBackupScheduleData, EnableBackupScheduleErrors, EnableBackupScheduleResponses, EnrichVisitorData, EnrichVisitorErrors, EnrichVisitorResponses, ExecData, ExecDetachedData, ExecDetachedErrors, ExecDetachedResponses, ExecErrors, ExecResponses, ExecuteDeploymentOperationData, ExecuteDeploymentOperationErrors, ExecuteDeploymentOperationResponses, ExecuteImportData, ExecuteImportErrors, ExecuteImportResponses, ExtendTimeoutData, ExtendTimeoutErrors, ExtendTimeoutResponses, ExternalServiceEnablePgStatStatementsData, ExternalServiceEnablePgStatStatementsErrors, ExternalServiceEnablePgStatStatementsResponses, ExternalServiceMetricsByDatabaseData, ExternalServiceMetricsByDatabaseErrors, ExternalServiceMetricsByDatabaseResponses, ExternalServiceMetricsCreateAlertRuleData, ExternalServiceMetricsCreateAlertRuleErrors, ExternalServiceMetricsCreateAlertRuleResponses, ExternalServiceMetricsDeleteAlertRuleData, ExternalServiceMetricsDeleteAlertRuleErrors, ExternalServiceMetricsDeleteAlertRuleResponses, ExternalServiceMetricsGetAlertRulesData, ExternalServiceMetricsGetAlertRulesErrors, ExternalServiceMetricsGetAlertRulesResponses, ExternalServiceMetricsGetLatestData, ExternalServiceMetricsGetLatestErrors, ExternalServiceMetricsGetLatestResponses, ExternalServiceMetricsGetRangeData, ExternalServiceMetricsGetRangeErrors, ExternalServiceMetricsGetRangeResponses, ExternalServiceMetricsStatusData, ExternalServiceMetricsStatusErrors, ExternalServiceMetricsStatusResponses, ExternalServiceMetricsToggleData, ExternalServiceMetricsToggleErrors, ExternalServiceMetricsToggleResponses, ExternalServiceMetricsUpdateAlertRuleData, ExternalServiceMetricsUpdateAlertRuleErrors, ExternalServiceMetricsUpdateAlertRuleResponses, ExternalServiceResetPgStatStatementsData, ExternalServiceResetPgStatStatementsErrors, ExternalServiceResetPgStatStatementsResponses, FinalizeOrderData, FinalizeOrderErrors, FinalizeOrderResponses, FinalizeProjectReleaseData, FinalizeProjectReleaseErrors, FinalizeProjectReleaseResponses, FindConversationData, FindConversationErrors, FindConversationResponses, GenerateJoinTokenData, GenerateJoinTokenErrors, GenerateJoinTokenResponses, GeneratePresetDockerfileData, GeneratePresetDockerfileErrors, GeneratePresetDockerfileResponses, GetAccessInfoData, GetAccessInfoErrors, GetAccessInfoResponses, GetActiveVisitorsData, GetActiveVisitorsErrors, GetActiveVisitorsResponses, GetActivityGraphData, GetActivityGraphErrors, GetActivityGraphResponses, GetAdminGateData, GetAdminGateErrors, GetAdminGateResponses, GetAgentData, GetAgentErrors, GetAgentResponses, GetAggregatedBucketsData, GetAggregatedBucketsErrors, GetAggregatedBucketsResponses, GetAiAgentBreakdownData, GetAiAgentBreakdownErrors, GetAiAgentBreakdownResponses, GetAiAgentPagesData, GetAiAgentPagesErrors, GetAiAgentPagesResponses, GetAiAgentTimelineData, GetAiAgentTimelineErrors, GetAiAgentTimelineResponses, GetAiPageBreakdownData, GetAiPageBreakdownErrors, GetAiPageBreakdownResponses, GetAiStatusBreakdownData, GetAiStatusBreakdownErrors, GetAiStatusBreakdownResponses, GetAlertData, GetAlertErrors, GetAlertResponses, GetAlertRuleData, GetAlertRuleErrors, GetAlertRuleResponses, GetAllRepositoriesByNameData, GetAllRepositoriesByNameErrors, GetAllRepositoriesByNameResponses, GetAnalyticsActiveVisitorsData, GetAnalyticsActiveVisitorsErrors, GetAnalyticsActiveVisitorsResponses, GetAnalyticsEventsCountData, GetAnalyticsEventsCountErrors, GetAnalyticsEventsCountResponses, GetAnalyticsSessionEventsData, GetAnalyticsSessionEventsErrors, GetAnalyticsSessionEventsResponses, GetAnalyticsVisitorSessionsData, GetAnalyticsVisitorSessionsErrors, GetAnalyticsVisitorSessionsResponses, GetApiKeyData, GetApiKeyErrors, GetApiKeyPermissionsData, GetApiKeyPermissionsErrors, GetApiKeyPermissionsResponses, GetApiKeyResponses, GetAuditLogData, GetAuditLogErrors, GetAuditLogResponses, GetBackupData, GetBackupErrors, GetBackupResponses, GetBackupScheduleData, GetBackupScheduleErrors, GetBackupScheduleResponses, GetBranchesByRepositoryIdData, GetBranchesByRepositoryIdErrors, GetBranchesByRepositoryIdResponses, GetBucketedIncidentsData, GetBucketedIncidentsErrors, GetBucketedIncidentsResponses, GetBucketedStatusData, GetBucketedStatusErrors, GetBucketedStatusResponses, GetChallengeTokenData, GetChallengeTokenErrors, GetChallengeTokenResponses, GetChatReadinessData, GetChatReadinessErrors, GetChatReadinessResponses, GetCliStatusData, GetCliStatusErrors, GetCliStatusResponses, GetClusterHealthData, GetClusterHealthErrors, GetClusterHealthResponses, GetClusterMemberData, GetClusterMemberErrors, GetClusterMemberResponses, GetCmdData, GetCmdErrors, GetCmdResponses, GetContainerDetailData, GetContainerDetailErrors, GetContainerDetailResponses, GetContainerEnvironmentVariableData, GetContainerEnvironmentVariableErrors, GetContainerEnvironmentVariableResponses, GetContainerInfoData, GetContainerInfoErrors, GetContainerInfoResponses, GetContainerLogsByIdData, GetContainerLogsByIdErrors, GetContainerLogsData, GetContainerLogsErrors, GetContainerMetricsData, GetContainerMetricsErrors, GetContainerMetricsResponses, GetConversationData, GetConversationDetailData, GetConversationDetailErrors, GetConversationDetailResponses, GetConversationErrors, GetConversationResponses, GetConversationsData, GetConversationsErrors, GetConversationsResponses, GetCronByIdData, GetCronByIdErrors, GetCronByIdResponses, GetCronExecutionsData, GetCronExecutionsErrors, GetCronExecutionsResponses, GetCrossProjectTraceSiblingsData, GetCrossProjectTraceSiblingsErrors, GetCrossProjectTraceSiblingsResponses, GetCurrentMonitorStatusData, GetCurrentMonitorStatusErrors, GetCurrentMonitorStatusResponses, GetCurrentUserData, GetCurrentUserErrors, GetCurrentUserResponses, GetCustomDomainData, GetCustomDomainErrors, GetCustomDomainResponses, GetDashboardData, GetDashboardErrors, GetDashboardProjectsAnalyticsData, GetDashboardProjectsAnalyticsErrors, GetDashboardProjectsAnalyticsResponses, GetDashboardResponses, GetDeliveryData, GetDeliveryErrors, GetDeliveryResponses, GetDeploymentContainerLogContentData, GetDeploymentContainerLogContentErrors, GetDeploymentContainerLogContentResponses, GetDeploymentData, GetDeploymentErrors, GetDeploymentJobLogsData, GetDeploymentJobLogsErrors, GetDeploymentJobLogsResponses, GetDeploymentJobsData, GetDeploymentJobsErrors, GetDeploymentJobsResponses, GetDeploymentOperationsData, GetDeploymentOperationsErrors, GetDeploymentOperationsResponses, GetDeploymentOperationStatusData, GetDeploymentOperationStatusErrors, GetDeploymentOperationStatusResponses, GetDeploymentResponses, GetDeploymentTokenData, GetDeploymentTokenErrors, GetDeploymentTokenResponses, GetDiskStatusData, GetDiskStatusErrors, GetDiskStatusResponses, GetDnsChangesData, GetDnsChangesErrors, GetDnsChangesResponses, GetDnsProviderData, GetDnsProviderErrors, GetDnsProviderResponses, GetDomainByHostData, GetDomainByHostErrors, GetDomainByHostResponses, GetDomainByIdData, GetDomainByIdErrors, GetDomainByIdResponses, GetDomainByNameData, GetDomainByNameErrors, GetDomainByNameResponses, GetDomainData, GetDomainDnsRecordsData, GetDomainDnsRecordsErrors, GetDomainDnsRecordsResponses, GetDomainErrors, GetDomainOrderData, GetDomainOrderErrors, GetDomainOrderResponses, GetDomainResponses, GetEmailData, GetEmailErrors, GetEmailEventsData, GetEmailEventsErrors, GetEmailEventsResponses, GetEmailLinksData, GetEmailLinksErrors, GetEmailLinksResponses, GetEmailProviderData, GetEmailProviderErrors, GetEmailProviderResponses, GetEmailResponses, GetEmailStatsData, GetEmailStatsErrors, GetEmailStatsResponses, GetEmailTrackingData, GetEmailTrackingErrors, GetEmailTrackingResponses, GetEmailTrackingStatusData, GetEmailTrackingStatusErrors, GetEmailTrackingStatusResponses, GetEntityInfoData, GetEntityInfoErrors, GetEntityInfoResponses, GetEnvironmentCronsData, GetEnvironmentCronsErrors, GetEnvironmentCronsResponses, GetEnvironmentData, GetEnvironmentDomainsData, GetEnvironmentDomainsErrors, GetEnvironmentDomainsResponses, GetEnvironmentErrors, GetEnvironmentResponses, GetEnvironmentsData, GetEnvironmentsErrors, GetEnvironmentsResponses, GetEnvironmentVariablesData, GetEnvironmentVariablesErrors, GetEnvironmentVariablesResponses, GetEnvironmentVariableValueData, GetEnvironmentVariableValueErrors, GetEnvironmentVariableValueResponses, GetErrorDashboardStatsData, GetErrorDashboardStatsErrors, GetErrorDashboardStatsResponses, GetErrorEventData, GetErrorEventErrors, GetErrorEventResponses, GetErrorGroupData, GetErrorGroupErrors, GetErrorGroupResponses, GetErrorStatsData, GetErrorStatsErrors, GetErrorStatsResponses, GetErrorTimeSeriesData, GetErrorTimeSeriesErrors, GetErrorTimeSeriesResponses, GetEventDetailData, GetEventDetailErrors, GetEventDetailResponses, GetEventEntriesData, GetEventEntriesErrors, GetEventEntriesResponses, GetEventsCountData, GetEventsCountErrors, GetEventsCountResponses, GetEventsTimelineData, GetEventsTimelineErrors, GetEventsTimelineResponses, GetEventTypeBreakdownData, GetEventTypeBreakdownErrors, GetEventTypeBreakdownResponses, GetEventVisitorsData, GetEventVisitorsErrors, GetEventVisitorsResponses, GetExternalImageData, GetExternalImageErrors, GetExternalImageResponses, GetFileData, GetFileErrors, GetFileResponses, GetFlagData, GetFlagErrors, GetFlagResponses, GetFlagSnapshotData, GetFlagSnapshotErrors, GetFlagSnapshotResponses, GetFunnelMetricsData, GetFunnelMetricsErrors, GetFunnelMetricsResponses, GetGenaiTraceData, GetGenaiTraceErrors, GetGenaiTraceResponses, GetGeneralStatsData, GetGeneralStatsErrors, GetGeneralStatsResponses, GetGitProviderData, GetGitProviderErrors, GetGitProviderResponses, GetGlobalEventsData, GetGlobalEventsErrors, GetGlobalEventsResponses, GetGlobalEventStatsData, GetGlobalEventStatsErrors, GetGlobalEventStatsResponses, GetGlobalMcpData, GetGlobalMcpErrors, GetGlobalMcpResponses, GetGlobalSandboxStatusData, GetGlobalSandboxStatusErrors, GetGlobalSandboxStatusResponses, GetGlobalSkillData, GetGlobalSkillErrors, GetGlobalSkillResponses, GetGroupedPageMetricsData, GetGroupedPageMetricsErrors, GetGroupedPageMetricsResponses, GetHealthData, GetHealthErrors, GetHealthResponses, GetHourlyVisitsData, GetHourlyVisitsErrors, GetHourlyVisitsResponses, GetHttpChallengeDebugData, GetHttpChallengeDebugErrors, GetHttpChallengeDebugResponses, GetImportStatusData, GetImportStatusErrors, GetImportStatusResponses, GetIncidentData, GetIncidentErrors, GetIncidentResponses, GetIncidentUpdatesData, GetIncidentUpdatesErrors, GetIncidentUpdatesResponses, GetIpAccessControlData, GetIpAccessControlErrors, GetIpAccessControlResponses, GetIpGeolocationData, GetIpGeolocationErrors, GetIpGeolocationResponses, GetJoinTokenStatusData, GetJoinTokenStatusErrors, GetJoinTokenStatusResponses, GetLastDeploymentData, GetLastDeploymentErrors, GetLastDeploymentResponses, GetLatestScanData, GetLatestScanErrors, GetLatestScanResponses, GetLatestScansPerEnvironmentData, GetLatestScansPerEnvironmentErrors, GetLatestScansPerEnvironmentResponses, GetLiveVisitorsListData, GetLiveVisitorsListErrors, GetLiveVisitorsListResponses, GetLogContextData, GetLogContextErrors, GetLogContextResponses, GetMcpData, GetMcpErrors, GetMcpResponses, GetMetricsOverTimeData, GetMetricsOverTimeErrors, GetMetricsOverTimeResponses, GetMonitorData, GetMonitorErrors, GetMonitorResponses, GetNotificationProviderData, GetNotificationProviderErrors, GetNotificationProviderResponses, GetOnDemandCertStatusData, GetOnDemandCertStatusErrors, GetOnDemandCertStatusResponses, GetOrCreateDsnData, GetOrCreateDsnErrors, GetOrCreateDsnResponses, GetPageFlowData, GetPageFlowErrors, GetPageFlowResponses, GetPageHourlySessionsData, GetPageHourlySessionsErrors, GetPageHourlySessionsResponses, GetPagePathDetailData, GetPagePathDetailErrors, GetPagePathDetailResponses, GetPagePathsData, GetPagePathsErrors, GetPagePathsResponses, GetPagePathsSparklinesData, GetPagePathsSparklinesErrors, GetPagePathsSparklinesResponses, GetPagePathVisitorsData, GetPagePathVisitorsErrors, GetPagePathVisitorsResponses, GetPendingActionData, GetPendingActionErrors, GetPendingActionResponses, GetPerformanceMetricsData, GetPerformanceMetricsErrors, GetPerformanceMetricsResponses, GetPgUpgradeData, GetPgUpgradeErrors, GetPgUpgradeLogsData, GetPgUpgradeLogsErrors, GetPgUpgradeLogsResponses, GetPgUpgradeResponses, GetPipelineStatsData, GetPipelineStatsErrors, GetPipelineStatsResponses, GetPlatformInfoData, GetPlatformInfoErrors, GetPlatformInfoResponses, GetPostgresWalHealthData, GetPostgresWalHealthErrors, GetPostgresWalHealthResponses, GetPreferencesData, GetPreferencesErrors, GetPreferencesResponses, GetPreviewGatewayLogsData, GetPreviewGatewayLogsResponses, GetPreviewGatewaySettingsData, GetPreviewGatewaySettingsResponses, GetPreviewGatewayStatusData, GetPreviewGatewayStatusResponses, GetPricingData, GetPricingErrors, GetPricingResponses, GetPrivateIpData, GetPrivateIpErrors, GetPrivateIpResponses, GetProjectAlarmsSummaryData, GetProjectAlarmsSummaryErrors, GetProjectAlarmsSummaryResponses, GetProjectBySlugData, GetProjectBySlugErrors, GetProjectBySlugResponses, GetProjectData, GetProjectDeploymentsData, GetProjectDeploymentsErrors, GetProjectDeploymentsResponses, GetProjectErrors, GetProjectResponses, GetProjectsData, GetProjectsErrors, GetProjectServiceEnvironmentVariablesData, GetProjectServiceEnvironmentVariablesErrors, GetProjectServiceEnvironmentVariablesResponses, GetProjectSessionReplaysData, GetProjectSessionReplaysErrors, GetProjectSessionReplaysResponses, GetProjectsHealthData, GetProjectsHealthErrors, GetProjectsHealthResponses, GetProjectsMonitorHealthData, GetProjectsMonitorHealthErrors, GetProjectsMonitorHealthResponses, GetProjectsResponses, GetProjectStatisticsData, GetProjectStatisticsErrors, GetProjectStatisticsResponses, GetProjectTemplateData, GetProjectTemplateErrors, GetProjectTemplateResponses, GetPropertyBreakdownData, GetPropertyBreakdownErrors, GetPropertyBreakdownResponses, GetPropertyTimelineData, GetPropertyTimelineErrors, GetPropertyTimelineResponses, GetProviderConnectionsData, GetProviderConnectionsErrors, GetProviderConnectionsResponses, GetProviderMetadataData, GetProviderMetadataErrors, GetProviderMetadataResponses, GetProvidersMetadataData, GetProvidersMetadataErrors, GetProvidersMetadataResponses, GetProxyLogByIdData, GetProxyLogByIdErrors, GetProxyLogByIdResponses, GetProxyLogByRequestIdData, GetProxyLogByRequestIdErrors, GetProxyLogByRequestIdResponses, GetProxyLogsData, GetProxyLogsErrors, GetProxyLogsResponses, GetPublicBranchesData, GetPublicBranchesErrors, GetPublicBranchesResponses, GetPublicIpData, GetPublicIpErrors, GetPublicIpResponses, GetPublicRepositoryData, GetPublicRepositoryErrors, GetPublicRepositoryResponses, GetQuotaData, GetQuotaErrors, GetQuotaResponses, GetRecentActivityData, GetRecentActivityErrors, GetRecentActivityResponses, GetRemoteExternalImageData, GetRemoteExternalImageErrors, GetRemoteExternalImageResponses, GetRepositoryBranchesData, GetRepositoryBranchesErrors, GetRepositoryBranchesResponses, GetRepositoryByIdData, GetRepositoryByIdErrors, GetRepositoryByIdResponses, GetRepositoryByNameData, GetRepositoryByNameErrors, GetRepositoryByNameResponses, GetRepositoryPresetByNameData, GetRepositoryPresetByNameErrors, GetRepositoryPresetByNameResponses, GetRepositoryPresetLiveData, GetRepositoryPresetLiveErrors, GetRepositoryPresetLiveResponses, GetRepositoryTagsData, GetRepositoryTagsErrors, GetRepositoryTagsResponses, GetResolvedEnvironmentVariablesData, GetResolvedEnvironmentVariablesErrors, GetResolvedEnvironmentVariablesResponses, GetResolvedEnvironmentVariableValueData, GetResolvedEnvironmentVariableValueErrors, GetResolvedEnvironmentVariableValueResponses, GetRestoreCapabilitiesData, GetRestoreCapabilitiesErrors, GetRestoreCapabilitiesResponses, GetRestoreRunData, GetRestoreRunErrors, GetRestoreRunResponses, GetRouteData, GetRouteErrors, GetRouteResponses, GetRunData, GetRunErrors, GetRunResponses, GetRunWithLogsData, GetRunWithLogsErrors, GetRunWithLogsResponses, GetS3CredentialsData, GetS3CredentialsErrors, GetS3CredentialsResponses, GetS3SourceData, GetS3SourceErrors, GetS3SourceResponses, GetSandboxData, GetSandboxErrors, GetSandboxResponses, GetSandboxStatusData, GetSandboxStatusErrors, GetSandboxStatusResponses, GetScanByDeploymentData, GetScanByDeploymentErrors, GetScanByDeploymentResponses, GetScanData, GetScanErrors, GetScanResponses, GetScanVulnerabilitiesData, GetScanVulnerabilitiesErrors, GetScanVulnerabilitiesResponses, GetServiceBySlugData, GetServiceBySlugErrors, GetServiceBySlugResponses, GetServiceData, GetServiceEnvironmentVariableData, GetServiceEnvironmentVariableErrors, GetServiceEnvironmentVariableResponses, GetServiceEnvironmentVariablesData, GetServiceEnvironmentVariablesErrors, GetServiceEnvironmentVariablesResponses, GetServiceErrors, GetServiceHealthStatusData, GetServiceHealthStatusErrors, GetServiceHealthStatusResponses, GetServicePreviewEnvironmentVariableNamesData, GetServicePreviewEnvironmentVariableNamesErrors, GetServicePreviewEnvironmentVariableNamesResponses, GetServicePreviewEnvironmentVariablesMaskedData, GetServicePreviewEnvironmentVariablesMaskedErrors, GetServicePreviewEnvironmentVariablesMaskedResponses, GetServiceResponses, GetServiceRuntimeData, GetServiceRuntimeErrors, GetServiceRuntimeResponses, GetServiceStatsData, GetServiceStatsErrors, GetServiceStatsResponses, GetServiceTypeParametersData, GetServiceTypeParametersErrors, GetServiceTypeParametersResponses, GetServiceTypesData, GetServiceTypesErrors, GetServiceTypesResponses, GetSessionDetailsData, GetSessionDetailsErrors, GetSessionDetailsResponses, GetSessionEventsData, GetSessionEventsErrors, GetSessionEventsResponses, GetSessionLogsData, GetSessionLogsErrors, GetSessionLogsResponses, GetSessionReplayData, GetSessionReplayErrors, GetSessionReplayEventsData, GetSessionReplayEventsErrors, GetSessionReplayEventsResponses, GetSessionReplayResponses, GetSettingsData, GetSettingsErrors, GetSettingsResponses, GetSkillData, GetSkillErrors, GetSkillResponses, GetSlowQueriesData, GetSlowQueriesErrors, GetSlowQueriesResponses, GetStaticBundleData, GetStaticBundleErrors, GetStaticBundleResponses, GetStatusOverviewData, GetStatusOverviewErrors, GetStatusOverviewResponses, GetTagsByRepositoryIdData, GetTagsByRepositoryIdErrors, GetTagsByRepositoryIdResponses, GetTeamData, GetTeamErrors, GetTeamResponses, GetTimeBucketStatsData, GetTimeBucketStatsErrors, GetTimeBucketStatsResponses, GetTodayStatsData, GetTodayStatsErrors, GetTodayStatsResponses, GetTraceData, GetTraceErrors, GetTraceResponses, GetUnifiedTraceData, GetUnifiedTraceErrors, GetUnifiedTraceResponses, GetUniqueCountsData, GetUniqueCountsErrors, GetUniqueCountsResponses, GetUniqueEventsData, GetUniqueEventsErrors, GetUniqueEventsResponses, GetUpdateCapabilityData, GetUpdateCapabilityErrors, GetUpdateCapabilityResponses, GetUpdateStatusData, GetUpdateStatusErrors, GetUpdateStatusResponses, GetUptimeHistoryData, GetUptimeHistoryErrors, GetUptimeHistoryResponses, GetUsageByProviderData, GetUsageByProviderErrors, GetUsageByProviderResponses, GetUsageRecentData, GetUsageRecentErrors, GetUsageRecentResponses, GetUsageSummaryData, GetUsageSummaryErrors, GetUsageSummaryResponses, GetUsageTimeseriesData, GetUsageTimeseriesErrors, GetUsageTimeseriesResponses, GetUsageTopModelsData, GetUsageTopModelsErrors, GetUsageTopModelsResponses, GetVisitorByGuidData, GetVisitorByGuidErrors, GetVisitorByGuidResponses, GetVisitorByIdData, GetVisitorByIdErrors, GetVisitorByIdResponses, GetVisitorDetailsData, GetVisitorDetailsErrors, GetVisitorDetailsResponses, GetVisitorFacetsData, GetVisitorFacetsErrors, GetVisitorFacetsResponses, GetVisitorInfoData, GetVisitorInfoErrors, GetVisitorInfoResponses, GetVisitorJourneyData, GetVisitorJourneyErrors, GetVisitorJourneyResponses, GetVisitorsData, GetVisitorsErrors, GetVisitorSessionsData, GetVisitorSessionsErrors, GetVisitorSessionsResponses, GetVisitorsResponses, GetVisitorStatsData, GetVisitorStatsErrors, GetVisitorStatsResponses, GetWebhookData, GetWebhookErrors, GetWebhookResponses, GrantProjectAccessData, GrantProjectAccessErrors, GrantProjectAccessResponses, HandleGitProviderOauthCallbackData, HandleGitProviderOauthCallbackErrors, HasAnalyticsEventsData, HasAnalyticsEventsErrors, HasAnalyticsEventsResponses, HasErrorGroupsData, HasErrorGroupsErrors, HasErrorGroupsResponses, HasPerformanceMetricsData, HasPerformanceMetricsErrors, HasPerformanceMetricsResponses, ImportExternalServiceData, ImportExternalServiceErrors, ImportExternalServiceResponses, IngestLogsByPathData, IngestLogsByPathErrors, IngestLogsByPathResponses, IngestLogsData, IngestLogsErrors, IngestLogsResponses, IngestMetricsByPathData, IngestMetricsByPathErrors, IngestMetricsByPathResponses, IngestMetricsData, IngestMetricsErrors, IngestMetricsResponses, IngestSentryEnvelopeData, IngestSentryEnvelopeErrors, IngestSentryEnvelopeResponses, IngestSentryEventData, IngestSentryEventErrors, IngestSentryEventResponses, IngestTracesByPathData, IngestTracesByPathErrors, IngestTracesByPathResponses, IngestTracesData, IngestTracesErrors, IngestTracesResponses, InitSessionReplayData, InitSessionReplayErrors, InitSessionReplayResponses, InspectDropArchiveData, InspectDropArchiveErrors, InspectDropArchiveResponses, JobLogsData, JobLogsErrors, JobLogsResponses, JobStatusData, JobStatusErrors, JobStatusResponses, KillJobData, KillJobErrors, KillJobResponses, KvDelData, KvDelErrors, KvDelResponses, KvDisableData, KvDisableErrors, KvDisableResponses, KvEnableData, KvEnableErrors, KvEnableResponses, KvExpireData, KvExpireErrors, KvExpireResponses, KvGetData, KvGetErrors, KvGetResponses, KvIncrData, KvIncrErrors, KvIncrResponses, KvKeysData, KvKeysErrors, KvKeysResponses, KvSetData, KvSetErrors, KvSetResponses, KvStatusData, KvStatusErrors, KvStatusResponses, KvTtlData, KvTtlErrors, KvTtlResponses, KvUpdateData, KvUpdateErrors, KvUpdateResponses, LatestRunForSourceData, LatestRunForSourceErrors, LatestRunForSourceResponses, LinkCustomDomainToCertificateData, LinkCustomDomainToCertificateErrors, LinkCustomDomainToCertificateResponses, LinkServiceToProjectData, LinkServiceToProjectErrors, LinkServiceToProjectResponses, ListAgentRunsData, ListAgentRunsErrors, ListAgentRunsResponses, ListAgentsData, ListAgentsErrors, ListAgentsResponses, ListAiProvidersData, ListAiProvidersErrors, ListAiProvidersResponses, ListAlertRulesData, ListAlertRulesErrors, ListAlertRulesResponses, ListAlertsData, ListAlertsErrors, ListAlertsResponses, ListAllConversationsData, ListAllConversationsErrors, ListAllConversationsResponses, ListAllRunsData, ListAllRunsErrors, ListAllRunsResponses, ListApiKeysData, ListApiKeysErrors, ListApiKeysResponses, ListAuditLogsData, ListAuditLogsErrors, ListAuditLogsResponses, ListAvailableContainersData, ListAvailableContainersErrors, ListAvailableContainersResponses, ListBackupAlertsData, ListBackupAlertsErrors, ListBackupAlertsResponses, ListBackupChildrenData, ListBackupChildrenErrors, ListBackupChildrenResponses, ListBackupSchedulesData, ListBackupSchedulesErrors, ListBackupSchedulesResponses, ListBackupsForScheduleData, ListBackupsForScheduleErrors, ListBackupsForScheduleResponses, ListCommitsByRepositoryIdData, ListCommitsByRepositoryIdErrors, ListCommitsByRepositoryIdResponses, ListConnectionsData, ListConnectionsErrors, ListConnectionsResponses, ListContainersAtPathData, ListContainersAtPathErrors, ListContainersAtPathResponses, ListContainersData, ListContainersErrors, ListContainersResponses, ListConversationsData, ListConversationsErrors, ListConversationsResponses, ListCustomDomainsForProjectData, ListCustomDomainsForProjectErrors, ListCustomDomainsForProjectResponses, ListDashboardsData, ListDashboardsErrors, ListDashboardsResponses, ListDeliveriesData, ListDeliveriesErrors, ListDeliveriesResponses, ListDeploymentContainerLogsData, ListDeploymentContainerLogsErrors, ListDeploymentContainerLogsResponses, ListDeploymentTokensData, ListDeploymentTokensErrors, ListDeploymentTokensResponses, ListDnsProvidersData, ListDnsProvidersErrors, ListDnsProvidersResponses, ListDomainsData, ListDomainsErrors, ListDomainsResponses, ListDsnsData, ListDsnsErrors, ListDsnsResponses, ListEmailDomainsData, ListEmailDomainsErrors, ListEmailDomainsResponses, ListEmailProvidersData, ListEmailProvidersErrors, ListEmailProvidersResponses, ListEmailsData, ListEmailsErrors, ListEmailsResponses, ListEnrollmentTokensData, ListEnrollmentTokensErrors, ListEnrollmentTokensResponses, ListEntitiesData, ListEntitiesErrors, ListEntitiesResponses, ListErrorEventsData, ListErrorEventsErrors, ListErrorEventsResponses, ListErrorGroupsData, ListErrorGroupsErrors, ListErrorGroupsResponses, ListEventsData, ListEventsResponses, ListEventTypesData, ListEventTypesResponses, ListExternalImagesData, ListExternalImagesErrors, ListExternalImagesResponses, ListExternalPluginsData, ListExternalPluginsErrors, ListExternalPluginsResponses, ListExternalServiceBackupsData, ListExternalServiceBackupsErrors, ListExternalServiceBackupsResponses, ListFlagsData, ListFlagsErrors, ListFlagsResponses, ListFunnelsData, ListFunnelsErrors, ListFunnelsResponses, ListGitProvidersData, ListGitProvidersErrors, ListGitProvidersResponses, ListGlobalMcpsData, ListGlobalMcpsErrors, ListGlobalMcpsResponses, ListGlobalSkillsData, ListGlobalSkillsErrors, ListGlobalSkillsResponses, ListIncidentsData, ListIncidentsErrors, ListIncidentsResponses, ListInsightsData, ListInsightsErrors, ListInsightsResponses, ListIpAccessControlData, ListIpAccessControlErrors, ListIpAccessControlResponses, ListJobsData, ListJobsErrors, ListJobsResponses, ListKnownAiAgentsData, ListKnownAiAgentsErrors, ListKnownAiAgentsResponses, ListManagedDomainsData, ListManagedDomainsErrors, ListManagedDomainsResponses, ListMcpsData, ListMcpsErrors, ListMcpsResponses, ListMetricLabelKeysData, ListMetricLabelKeysErrors, ListMetricLabelKeysResponses, ListMetricLabelValuesData, ListMetricLabelValuesErrors, ListMetricLabelValuesResponses, ListMetricNamesData, ListMetricNamesErrors, ListMetricNamesResponses, ListModelsData, ListModelsErrors, ListModelsResponses, ListMonitorsData, ListMonitorsErrors, ListMonitorsResponses, ListNotificationProvidersData, ListNotificationProvidersErrors, ListNotificationProvidersResponses, ListOidcProvidersData, ListOidcProvidersResponses, ListOidcProviderUsersData, ListOidcProviderUsersErrors, ListOidcProviderUsersResponses, ListOidcRoleMappingsData, ListOidcRoleMappingsResponses, ListOnDemandCertsData, ListOnDemandCertsErrors, ListOnDemandCertsResponses, ListOrdersData, ListOrdersErrors, ListOrdersResponses, ListPeersData, ListPeersErrors, ListPeersResponses, ListPendingActionsData, ListPendingActionsErrors, ListPendingActionsResponses, ListPgUpgradesData, ListPgUpgradesErrors, ListPgUpgradesResponses, ListPresetsData, ListPresetsErrors, ListPresetsResponses, ListProjectAccessData, ListProjectAccessErrors, ListProjectAccessResponses, ListProjectAlarmsData, ListProjectAlarmsErrors, ListProjectAlarmsResponses, ListProjectScansData, ListProjectScansErrors, ListProjectScansResponses, ListProjectSecretsData, ListProjectSecretsErrors, ListProjectSecretsResponses, ListProjectServicesData, ListProjectServicesErrors, ListProjectServicesResponses, ListProjectTemplatesData, ListProjectTemplatesErrors, ListProjectTemplatesResponses, ListProjectTemplateTagsData, ListProjectTemplateTagsErrors, ListProjectTemplateTagsResponses, ListProviderKeysData, ListProviderKeysErrors, ListProviderKeysResponses, ListProviderZonesData, ListProviderZonesErrors, ListProviderZonesResponses, ListPublicProvidersData, ListPublicProvidersResponses, ListReleaseFilesData, ListReleaseFilesErrors, ListReleaseFilesResponses, ListReleasesData, ListReleasesErrors, ListReleasesResponses, ListRemoteExternalImagesData, ListRemoteExternalImagesErrors, ListRemoteExternalImagesResponses, ListRepositoriesByConnectionData, ListRepositoriesByConnectionErrors, ListRepositoriesByConnectionResponses, ListRepositoriesByProviderData, ListRepositoriesByProviderErrors, ListRepositoriesByProviderResponses, ListRestoreRunsForServiceData, ListRestoreRunsForServiceResponses, ListRootContainersData, ListRootContainersErrors, ListRootContainersResponses, ListRoutesData, ListRoutesErrors, ListRoutesResponses, ListS3SourcesData, ListS3SourcesErrors, ListS3SourcesResponses, ListSandboxesData, ListSandboxesResponses, ListScheduleRunJobsData, ListScheduleRunJobsErrors, ListScheduleRunJobsResponses, ListScheduleRunsData, ListScheduleRunsErrors, ListScheduleRunsResponses, ListScheduleServicesData, ListScheduleServicesErrors, ListScheduleServicesResponses, ListSecretsData, ListSecretsErrors, ListSecretsResponses, ListServiceHealthStatusesData, ListServiceHealthStatusesErrors, ListServiceHealthStatusesResponses, ListServiceProjectsData, ListServiceProjectsErrors, ListServiceProjectsResponses, ListServiceSchedulesData, ListServiceSchedulesErrors, ListServiceSchedulesResponses, ListServicesData, ListServicesErrors, ListServicesResponses, ListSkillsData, ListSkillsErrors, ListSkillsResponses, ListSourceBackupsData, ListSourceBackupsErrors, ListSourceBackupsResponses, ListSourceFilesData, ListSourceFilesErrors, ListSourceFilesResponses, ListSourceMapsData, ListSourceMapsErrors, ListSourceMapsResponses, ListSourcesData, ListSourcesErrors, ListSourcesResponses, ListStaticBundlesData, ListStaticBundlesErrors, ListStaticBundlesResponses, ListSyncedRepositoriesData, ListSyncedRepositoriesErrors, ListSyncedRepositoriesResponses, ListTeamMembersData, ListTeamMembersErrors, ListTeamMembersResponses, ListTeamProjectsData, ListTeamProjectsErrors, ListTeamProjectsResponses, ListTeamsData, ListTeamsErrors, ListTeamsResponses, ListUsersData, ListUsersErrors, ListUsersResponses, ListWebhooksData, ListWebhooksErrors, ListWebhooksResponses, LoginData, LoginErrors, LoginResponses, LogoutData, LogoutErrors, LogoutResponses, LookupDnsARecordsData, LookupDnsARecordsErrors, LookupDnsARecordsResponses, MintEnrollmentTokenData, MintEnrollmentTokenErrors, MintEnrollmentTokenResponses, MkdirData, MkdirErrors, MkdirResponses, NodeHeartbeatData, NodeHeartbeatErrors, NodeHeartbeatResponses, NodeMetricsGetRangeData, NodeMetricsGetRangeErrors, NodeMetricsGetRangeResponses, ObservabilityFullEventData, ObservabilityFullEventErrors, ObservabilityFullEventResponses, ObservabilityListEventsData, ObservabilityListEventsErrors, ObservabilityListEventsResponses, OidcCallbackData, PatchAdminGateData, PatchAdminGateErrors, PatchAdminGateResponses, PatchPreviewGatewaySettingsData, PatchPreviewGatewaySettingsResponses, PauseDeploymentData, PauseDeploymentErrors, PauseDeploymentResponses, PauseSandboxData, PauseSandboxErrors, PauseSandboxResponses, PlanRestoreData, PlanRestoreErrors, PlanRestoreResponses, PostDnsAckData, PostDnsAckErrors, PostDnsAckResponses, PreviewAlertData, PreviewAlertErrors, PreviewAlertResponses, PreviewFunnelMetricsData, PreviewFunnelMetricsErrors, PreviewFunnelMetricsResponses, PreviewHostnameModeData, PreviewHostnameModeErrors, PreviewHostnameModeResponses, PromoteClusterMemberData, PromoteClusterMemberErrors, PromoteClusterMemberResponses, PromoteDeploymentData, PromoteDeploymentErrors, PromoteDeploymentResponses, ProvisionDomainData, ProvisionDomainErrors, ProvisionDomainResponses, PurgeProjectLogsData, PurgeProjectLogsErrors, PurgeProjectLogsResponses, PushExternalImageData, PushExternalImageErrors, PushExternalImageResponses, QueryDataData, QueryDataErrors, QueryDataResponses, QueryGenaiTracesData, QueryGenaiTracesErrors, QueryGenaiTracesResponses, QueryLogsData, QueryLogsErrors, QueryLogsResponses, QueryMetricsData, QueryMetricsErrors, QueryMetricsResponses, QueryTracesData, QueryTracesErrors, QueryTracesResponses, QueryTraceSummariesData, QueryTraceSummariesErrors, QueryTraceSummariesResponses, ReadFileData, ReadFileErrors, ReadFileResponses, ReAnalyzeData, ReAnalyzeErrors, ReAnalyzeResponses, RebuildSandboxImageData, RebuildSandboxImageErrors, RebuildSandboxImageResponses, RecordConsoleEventData, RecordConsoleEventErrors, RecordConsoleEventResponses, RecordEventMetricsData, RecordEventMetricsErrors, RecordEventMetricsResponses, RecordFlagExposureData, RecordFlagExposureErrors, RecordFlagExposureResponses, RecordSpeedMetricsData, RecordSpeedMetricsErrors, RecordSpeedMetricsResponses, RefreshRouteTableData, RefreshRouteTableErrors, RefreshRouteTableResponses, RegenerateDsnData, RegenerateDsnErrors, RegenerateDsnResponses, RegisterExternalImageData, RegisterExternalImageErrors, RegisterExternalImageResponses, RegisterNodeData, RegisterNodeErrors, RegisterNodeResponses, ReinstallGitlabWebhookData, ReinstallGitlabWebhookErrors, ReinstallGitlabWebhookResponses, RejectPendingActionData, RejectPendingActionErrors, RejectPendingActionResponses, ReloadPluginsData, ReloadPluginsErrors, ReloadPluginsResponses, RemoveClusterMemberData, RemoveClusterMemberErrors, RemoveClusterMemberResponses, RemoveManagedDomainData, RemoveManagedDomainErrors, RemoveManagedDomainResponses, RemoveRoleData, RemoveRoleErrors, RemoveRoleResponses, RemoveTeamMemberData, RemoveTeamMemberErrors, RemoveTeamMemberResponses, RenameConversationData, RenameConversationErrors, RenameConversationResponses, RenewDomainData, RenewDomainErrors, RenewDomainResponses, RequestPasswordResetData, RequestPasswordResetErrors, RequestPasswordResetResponses, ResetPasswordData, ResetPasswordErrors, ResetPasswordResponses, ResizeSandboxData, ResizeSandboxErrors, ResizeSandboxResponses, ResolveAlarmData, ResolveAlarmErrors, ResolveAlarmResponses, RestartContainerData, RestartContainerErrors, RestartContainerResponses, RestartPreviewGatewayData, RestartPreviewGatewayResponses, RestartSandboxData, RestartSandboxErrors, RestartSandboxResponses, RestoreFlagData, RestoreFlagErrors, RestoreFlagResponses, RestoreUserData, RestoreUserErrors, RestoreUserResponses, ResumeDeploymentData, ResumeDeploymentErrors, ResumeDeploymentResponses, ResumeSandboxData, ResumeSandboxErrors, ResumeSandboxResponses, RetryClusterData, RetryClusterErrors, RetryClusterResponses, RetryDeliveryData, RetryDeliveryErrors, RetryDeliveryResponses, RetryPgUpgradeData, RetryPgUpgradeErrors, RetryPgUpgradeResponses, RetryRunData, RetryRunErrors, RetryRunResponses, RevealGlobalMcpConfigData, RevealGlobalMcpConfigErrors, RevealGlobalMcpConfigResponses, RevealMcpConfigData, RevealMcpConfigErrors, RevealMcpConfigResponses, RevealNotificationProviderConfigData, RevealNotificationProviderConfigErrors, RevealNotificationProviderConfigResponses, RevealServiceParameterData, RevealServiceParameterErrors, RevealServiceParameterResponses, RevenueCreateIntegrationData, RevenueCreateIntegrationErrors, RevenueCreateIntegrationResponses, RevenueDeleteIntegrationData, RevenueDeleteIntegrationResponses, RevenueGlobalEventsData, RevenueGlobalEventsResponses, RevenueImportInvoicesCsvData, RevenueImportInvoicesCsvErrors, RevenueImportInvoicesCsvResponses, RevenueImportSubscriptionsCsvData, RevenueImportSubscriptionsCsvErrors, RevenueImportSubscriptionsCsvResponses, RevenueListIntegrationsData, RevenueListIntegrationsResponses, RevenueListProvidersData, RevenueListProvidersResponses, RevenueMetricsCustomersData, RevenueMetricsCustomersResponses, RevenueMetricsGlobalMrrData, RevenueMetricsGlobalMrrResponses, RevenueMetricsGlobalSummaryData, RevenueMetricsGlobalSummaryResponses, RevenueMetricsMrrData, RevenueMetricsMrrResponses, RevenueMetricsSummaryData, RevenueMetricsSummaryResponses, RevenueRecentEventsData, RevenueRecentEventsResponses, RevenueRotateTokenData, RevenueRotateTokenResponses, RevenueUpdateConfigData, RevenueUpdateConfigErrors, RevenueUpdateConfigResponses, RevenueUpdateSecretData, RevenueUpdateSecretErrors, RevenueUpdateSecretResponses, RevokeDsnData, RevokeDsnErrors, RevokeDsnResponses, RevokeEnrollmentTokenData, RevokeEnrollmentTokenErrors, RevokeEnrollmentTokenResponses, RevokeJoinTokenData, RevokeJoinTokenErrors, RevokeJoinTokenResponses, RevokeProjectAccessData, RevokeProjectAccessErrors, RevokeProjectAccessResponses, RollbackPgUpgradeData, RollbackPgUpgradeErrors, RollbackPgUpgradeResponses, RollbackToDeploymentData, RollbackToDeploymentErrors, RollbackToDeploymentResponses, RootfsGcData, RootfsGcResponses, RootfsReportData, RootfsReportResponses, RotateApiKeyData, RotateApiKeyErrors, RotateApiKeyResponses, RotateDeploymentTokenData, RotateDeploymentTokenErrors, RotateDeploymentTokenResponses, RunBackupForSourceData, RunBackupForSourceErrors, RunBackupForSourceResponses, RunConnectionHealthCheckData, RunConnectionHealthCheckErrors, RunConnectionHealthCheckResponses, RunExternalServiceBackupData, RunExternalServiceBackupErrors, RunExternalServiceBackupResponses, RunScheduleNowData, RunScheduleNowErrors, RunScheduleNowResponses, SandboxCreatePreviewLinkData, SandboxCreatePreviewLinkErrors, SandboxCreatePreviewLinkResponses, SaveAgentTokenData, SaveAgentTokenErrors, SaveAgentTokenResponses, SaveAiProviderCredentialData, SaveAiProviderCredentialErrors, SaveAiProviderCredentialResponses, SearchLogsData, SearchLogsErrors, SearchLogsResponses, SendEmailData, SendEmailErrors, SendEmailResponses, SendMessageData, SendMessageErrors, SendMessageResponses, SetDefaultS3SourceData, SetDefaultS3SourceErrors, SetDefaultS3SourceResponses, SetFlagEnvironmentData, SetFlagEnvironmentErrors, SetFlagEnvironmentResponses, SetPreviewPasswordData, SetPreviewPasswordErrors, SetPreviewPasswordResponses, SetupDnsChallengeData, SetupDnsChallengeErrors, SetupDnsChallengeResponses, SetupDnsData, SetupDnsErrors, SetupDnsResponses, SetupEmailTrackingData, SetupEmailTrackingErrors, SetupEmailTrackingResponses, SetupMfaData, SetupMfaErrors, SetupMfaResponses, SleepEnvironmentData, SleepEnvironmentErrors, SleepEnvironmentResponses, SmokeTestAgentData, SmokeTestAgentErrors, SmokeTestAgentResponses, SourceSandboxData, SourceSandboxErrors, SourceSandboxResponses, StartAnalysisData, StartAnalysisErrors, StartAnalysisResponses, StartContainerData, StartContainerErrors, StartContainerResponses, StartFixData, StartFixErrors, StartFixResponses, StartGitProviderOauthData, StartGitProviderOauthErrors, StartOidcLoginBySlugData, StartOidcLoginBySlugErrors, StartPgUpgradeData, StartPgUpgradeErrors, StartPgUpgradeResponses, StartRestoreData, StartRestoreErrors, StartRestoreResponses, StartServiceData, StartServiceErrors, StartServiceResponses, StartUpdateData, StartUpdateErrors, StartUpdateResponses, StatPathData, StatPathErrors, StatPathResponses, StopContainerData, StopContainerErrors, StopContainerResponses, StopSandboxData, StopSandboxErrors, StopSandboxResponses, StopServiceData, StopServiceErrors, StopServiceResponses, StreamContainerMetricsData, StreamContainerMetricsErrors, StreamContainerMetricsResponses, StreamEventsData, StreamEventsErrors, StreamEventsResponses, StreamRunEventsData, StreamRunEventsErrors, StreamRunEventsResponses, SyncRepositoriesData, SyncRepositoriesErrors, SyncRepositoriesResponses, TailDeploymentJobLogsData, TailDeploymentJobLogsErrors, TailLogsData, TailLogsErrors, TailLogsResponses, TeardownDeploymentData, TeardownDeploymentErrors, TeardownDeploymentResponses, TeardownEnvironmentData, TeardownEnvironmentErrors, TeardownEnvironmentResponses, TestNotificationProviderData, TestNotificationProviderErrors, TestNotificationProviderResponses, TestOidcProviderData, TestOidcProviderResponses, TestProviderConnectionData, TestProviderConnectionErrors, TestProviderConnectionResponses, TestProviderData, TestProviderErrors, TestProviderKeyByIdData, TestProviderKeyByIdErrors, TestProviderKeyByIdResponses, TestProviderKeyInlineData, TestProviderKeyInlineErrors, TestProviderKeyInlineResponses, TestProviderResponses, TestS3ConnectionPreviewData, TestS3ConnectionPreviewErrors, TestS3ConnectionPreviewResponses, TestS3SourceConnectionData, TestS3SourceConnectionErrors, TestS3SourceConnectionResponses, TrackClickData, TrackClickErrors, TrackOpenData, TrackOpenErrors, TrackOpenResponses, TriggerAgentData, TriggerAgentErrors, TriggerAgentResponses, TriggerProjectPipelineData, TriggerProjectPipelineErrors, TriggerProjectPipelineResponses, TriggerScanData, TriggerScanErrors, TriggerScanResponses, TriggerServiceHealthCheckData, TriggerServiceHealthCheckErrors, TriggerServiceHealthCheckResponses, TriggerWeeklyDigestData, TriggerWeeklyDigestErrors, TriggerWeeklyDigestResponses, UnlinkServiceFromProjectData, UnlinkServiceFromProjectErrors, UnlinkServiceFromProjectResponses, UpdateAgentData, UpdateAgentErrors, UpdateAgentResponses, UpdateAiProviderData, UpdateAiProviderErrors, UpdateAiProviderResponses, UpdateAlertData, UpdateAlertErrors, UpdateAlertResponses, UpdateAlertRuleData, UpdateAlertRuleErrors, UpdateAlertRuleResponses, UpdateApiKeyData, UpdateApiKeyErrors, UpdateApiKeyResponses, UpdateAutomaticDeployData, UpdateAutomaticDeployErrors, UpdateAutomaticDeployResponses, UpdateBackupScheduleData, UpdateBackupScheduleErrors, UpdateBackupScheduleResponses, UpdateCloudflareProviderData, UpdateCloudflareProviderErrors, UpdateCloudflareProviderResponses, UpdateConnectionTokenData, UpdateConnectionTokenErrors, UpdateConnectionTokenResponses, UpdateCustomDomainData, UpdateCustomDomainErrors, UpdateCustomDomainResponses, UpdateDashboardData, UpdateDashboardErrors, UpdateDashboardResponses, UpdateDeploymentTokenData, UpdateDeploymentTokenErrors, UpdateDeploymentTokenResponses, UpdateEmailProviderData, UpdateEmailProviderErrors, UpdateEmailProviderResponses, UpdateEnvironmentSettingsData, UpdateEnvironmentSettingsErrors, UpdateEnvironmentSettingsResponses, UpdateEnvironmentSubdomainData, UpdateEnvironmentSubdomainErrors, UpdateEnvironmentSubdomainResponses, UpdateEnvironmentVariableData, UpdateEnvironmentVariableErrors, UpdateEnvironmentVariableResponses, UpdateErrorGroupData, UpdateErrorGroupErrors, UpdateErrorGroupResponses, UpdateFlagData, UpdateFlagErrors, UpdateFlagResponses, UpdateFunnelData, UpdateFunnelErrors, UpdateFunnelResponses, UpdateGitProviderCredentialsData, UpdateGitProviderCredentialsErrors, UpdateGitProviderCredentialsResponses, UpdateGitSettingsData, UpdateGitSettingsErrors, UpdateGitSettingsResponses, UpdateGlobalMcpData, UpdateGlobalMcpErrors, UpdateGlobalMcpResponses, UpdateGlobalSkillData, UpdateGlobalSkillErrors, UpdateGlobalSkillResponses, UpdateIncidentStatusData, UpdateIncidentStatusErrors, UpdateIncidentStatusResponses, UpdateIpAccessControlData, UpdateIpAccessControlErrors, UpdateIpAccessControlResponses, UpdateManagedDomainData, UpdateManagedDomainErrors, UpdateManagedDomainResponses, UpdateMcpData, UpdateMcpErrors, UpdateMcpResponses, UpdateNotificationEmailProviderData, UpdateNotificationEmailProviderErrors, UpdateNotificationEmailProviderResponses, UpdateNotificationProviderData, UpdateNotificationProviderErrors, UpdateNotificationProviderResponses, UpdateOidcProviderData, UpdateOidcProviderResponses, UpdatePreferencesData, UpdatePreferencesErrors, UpdatePreferencesResponses, UpdateProjectData, UpdateProjectDeploymentConfigData, UpdateProjectDeploymentConfigErrors, UpdateProjectDeploymentConfigResponses, UpdateProjectErrors, UpdateProjectResponses, UpdateProjectSecretData, UpdateProjectSecretErrors, UpdateProjectSecretResponses, UpdateProjectSettingsData, UpdateProjectSettingsErrors, UpdateProjectSettingsResponses, UpdateProviderData, UpdateProviderErrors, UpdateProviderKeyData, UpdateProviderKeyErrors, UpdateProviderKeyResponses, UpdateProviderResponses, UpdateRouteData, UpdateRouteErrors, UpdateRouteResponses, UpdateS3SourceData, UpdateS3SourceErrors, UpdateS3SourceResponses, UpdateSelfData, UpdateSelfErrors, UpdateSelfResponses, UpdateServiceData, UpdateServiceErrors, UpdateServiceResourcesData, UpdateServiceResourcesErrors, UpdateServiceResourcesResponses, UpdateServiceResponses, UpdateSessionDurationData, UpdateSessionDurationErrors, UpdateSessionDurationResponses, UpdateSettingsData, UpdateSettingsErrors, UpdateSettingsResponses, UpdateSkillData, UpdateSkillErrors, UpdateSkillResponses, UpdateSlackProviderData, UpdateSlackProviderErrors, UpdateSlackProviderResponses, UpdateSpeedMetricsData, UpdateSpeedMetricsErrors, UpdateSpeedMetricsResponses, UpdateTeamData, UpdateTeamErrors, UpdateTeamMemberRoleData, UpdateTeamMemberRoleErrors, UpdateTeamMemberRoleResponses, UpdateTeamResponses, UpdateUserData, UpdateUserErrors, UpdateUserResponses, UpdateWebhookData, UpdateWebhookErrors, UpdateWebhookProviderData, UpdateWebhookProviderErrors, UpdateWebhookProviderResponses, UpdateWebhookResponses, UpgradePreviewGatewayData, UpgradePreviewGatewayResponses, UpgradeServiceData, UpgradeServiceErrors, UpgradeServiceResponses, UploadGlobalSkillData, UploadGlobalSkillErrors, UploadGlobalSkillResponses, UploadReleaseFileData, UploadReleaseFileErrors, UploadReleaseFileResponses, UploadSkillData, UploadSkillErrors, UploadSkillResponses, UploadSourceFileData, UploadSourceFileErrors, UploadSourceFileResponses, UploadSourceMapData, UploadSourceMapErrors, UploadSourceMapResponses, UploadStaticBundleData, UploadStaticBundleErrors, UploadStaticBundleResponses, UpsertSecretData, UpsertSecretErrors, UpsertSecretResponses, ValidateConnectionData, ValidateConnectionErrors, ValidateConnectionResponses, ValidateEmailData, ValidateEmailErrors, ValidateEmailResponses, VerifyAndEnableMfaData, VerifyAndEnableMfaErrors, VerifyAndEnableMfaResponses, VerifyDomainData, VerifyDomainErrors, VerifyDomainResponses, VerifyEmailData, VerifyEmailErrors, VerifyEmailResponses, VerifyManagedDomainData, VerifyManagedDomainErrors, VerifyManagedDomainResponses, VerifyMfaChallengeData, VerifyMfaChallengeErrors, VerifyMfaChallengeResponses, VerifyStepUpData, VerifyStepUpErrors, VerifyStepUpResponses, WakeEnvironmentData, WakeEnvironmentErrors, WakeEnvironmentResponses, WebhookTriggerData, WebhookTriggerErrors, WebhookTriggerResponses, WorkflowDryRunData, WorkflowDryRunErrors, WorkflowDryRunResponses, WriteFileData, WriteFileErrors, WriteFileResponses, WriteFilesData, WriteFilesErrors, WriteFilesResponses } from './types.gen'; export type Options = Options2 & { /** @@ -7272,6 +7272,16 @@ export const getUpdateStatus = (options?: ...options }); +/** + * Ask the release API for the newest version on this install's channel, now, + * instead of waiting for the background notifier's next pass. + */ +export const checkForUpdate = (options?: Options): RequestResult => (options?.client ?? client).post({ + security: [{ scheme: 'bearer', type: 'http' }], + url: '/settings/update/check', + ...options +}); + export const listTeams = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/teams', diff --git a/apps/temps-cli/src/api/types.gen.ts b/apps/temps-cli/src/api/types.gen.ts index aadd5314d..6168bdf13 100644 --- a/apps/temps-cli/src/api/types.gen.ts +++ b/apps/temps-cli/src/api/types.gen.ts @@ -13184,6 +13184,34 @@ export type ReinstallWebhookResponse = { message: string; }; +/** + * Outcome of an operator-triggered release check. + */ +export type ReleaseCheckResult = { + /** + * Channel that was queried. + */ + channel: string; + /** + * Version tag of the running binary. + */ + current_version: string; + /** + * Newest release published on that channel, if any could be resolved. + */ + latest_version?: string | null; + /** + * Release-notes page for `latest_version`. + */ + release_url?: string | null; + /** + * True when `latest_version` is strictly newer than what is running. + * False on a channel whose newest release is older — which is normal and + * expected right after switching a nightly box onto stable. + */ + update_available: boolean; +}; + export type ReleaseListResponse = { releases: Array; }; @@ -14508,18 +14536,33 @@ export type SelfUpdateAttempt = { * fundamental blocker wins, so the operator fixes the real problem first * rather than clearing one only to hit the next. */ -export type SelfUpdateBlocker = 'disabled_by_flag' | 'disabled_by_setting' | 'container' | 'no_supervisor' | 'binary_not_writable' | 'unsupported_platform' | 'in_progress'; +export type SelfUpdateBlocker = 'disabled_by_flag' | 'disabled_by_setting' | 'not_supported' | 'binary_not_writable' | 'unsupported_platform' | 'in_progress'; /** * Where an in-flight update has got to. Polled by the console so a long * download shows progress instead of an indefinite spinner. */ -export type SelfUpdatePhase = 'idle' | 'resolving' | 'downloading' | 'verifying' | 'installing' | 'restarting' | 'failed'; +export type SelfUpdatePhase = 'idle' | 'resolving' | 'downloading' | 'verifying' | 'installing' | 'restarting' | 'pending_restart' | 'failed'; + +/** + * What happens to the running process once the new binary is in place. + */ +export type SelfUpdateRestartMode = 'automatic' | 'manual'; /** * Controls the console's one-click "Update now" action. */ export type SelfUpdateSettings = { + /** + * Release channel this install tracks: `stable`, `beta` or `nightly`. + * + * `None` (the default) means "infer from the running version tag", which + * is what the CLI has always done — a `-nightly.` build tracks nightly, a + * `-beta.N` build tracks beta, a plain tag tracks stable. Setting it + * explicitly pins the channel, so an operator can move a nightly box back + * onto stable without reinstalling. + */ + channel?: string | null; /** * Allow admins to apply a release and restart the server from the console. * `true` by default: the action is permission-gated, audited, and only @@ -14534,7 +14577,7 @@ export type SelfUpdateSettings = { /** * Outcome of an update attempt, as persisted in the journal. */ -export type SelfUpdateStatus = 'pending' | 'succeeded' | 'failed'; +export type SelfUpdateStatus = 'pending' | 'succeeded' | 'installed_pending_restart' | 'failed'; export type SendEmailRequestBody = { /** @@ -16126,10 +16169,14 @@ export type StartUpdateResponse = { current_version: string; /** * How long to allow for the server to come back before treating the - * restart as failed. + * restart as failed. `0` when nothing restarts. */ estimated_restart_secs: number; message: string; + /** + * `automatic` (temps restarts itself) or `manual` (installed only). + */ + restart_mode: SelfUpdateRestartMode; }; export type StatResponse = { @@ -17317,6 +17364,20 @@ export type UpdateCapabilityResponse = { * Non-blocking warning to show with the confirmation (split topology). */ caveat?: string | null; + /** + * Channel actually tracked, after applying the configured override or + * falling back to inference from the running version tag. + */ + channel: string; + /** + * True when `channel` was set explicitly in settings rather than inferred. + */ + channel_is_pinned: boolean; + /** + * Version tag of the running binary. Always present — the version page + * needs it whether or not an update exists. + */ + current_version: string; last_attempt?: null | SelfUpdateAttempt; /** * The equivalent command to run by hand. Always present. @@ -17334,6 +17395,12 @@ export type UpdateCapabilityResponse = { * Operator-facing explanation of `blocker`. */ reason?: string | null; + /** + * `automatic` when applying an update also restarts temps; `manual` when + * it only installs the binary and the operator restarts on their own + * schedule. Lets the console set expectations before the click. + */ + restart_mode: SelfUpdateRestartMode; /** * What would restart the process: `systemd`, `launchd`, `container`, `none`. */ @@ -47410,6 +47477,43 @@ export type GetUpdateStatusResponses = { export type GetUpdateStatusResponse = GetUpdateStatusResponses[keyof GetUpdateStatusResponses]; +export type CheckForUpdateData = { + body?: never; + path?: never; + query?: never; + url: '/settings/update/check'; +}; + +export type CheckForUpdateErrors = { + /** + * Unauthorized + */ + 401: unknown; + /** + * Insufficient permissions + */ + 403: unknown; + /** + * This process cannot check for updates + */ + 501: ProblemDetails; + /** + * The release API could not be reached + */ + 502: ProblemDetails; +}; + +export type CheckForUpdateError = CheckForUpdateErrors[keyof CheckForUpdateErrors]; + +export type CheckForUpdateResponses = { + /** + * Result of the release check + */ + 200: ReleaseCheckResult; +}; + +export type CheckForUpdateResponse = CheckForUpdateResponses[keyof CheckForUpdateResponses]; + export type ListTeamsData = { body?: never; path?: never; diff --git a/apps/temps-cli/src/commands/platform/index.ts b/apps/temps-cli/src/commands/platform/index.ts index aba60a118..0c2ec8620 100644 --- a/apps/temps-cli/src/commands/platform/index.ts +++ b/apps/temps-cli/src/commands/platform/index.ts @@ -9,6 +9,9 @@ import { getUpdateCapability, getUpdateStatus, startUpdate, + checkForUpdate, + getSettings, + updateSettings, } from '../../api/sdk.gen.js' import { withSpinner } from '../../ui/spinner.js' import { promptConfirm } from '../../ui/prompts.js' @@ -52,6 +55,20 @@ export function registerPlatformCommands(program: Command): void { .option('--json', 'Output in JSON format') .action(updateStatusAction) + update + .command('check') + .description('Ask the release API for the newest version on this channel now') + .option('--json', 'Output in JSON format') + .action(updateCheckAction) + + update + .command('channel [channel]') + .description( + 'Show or set the release channel: stable, beta, nightly, or "auto" to follow the installed version' + ) + .option('--json', 'Output in JSON format') + .action(updateChannelAction) + update .command('apply') .description('Install a release on the server and restart it') @@ -390,3 +407,118 @@ async function waitForUpdateOutcome( } return null } + +/** Valid channels, plus the sentinel that clears an explicit pin. */ +const UPDATE_CHANNELS = ['stable', 'beta', 'nightly'] as const +const CHANNEL_AUTO = 'auto' + +/** Force a release check instead of waiting for the server's periodic one. */ +async function updateCheckAction(options: { json?: boolean }): Promise { + await requireAuth() + await setupClient() + + const result = await withSpinner('Checking the release API...', async () => { + const { data, error: err } = await checkForUpdate({ client }) + if (err) { + throw new Error(getErrorMessage(err)) + } + return data + }) + + if (options.json) { + json(result) + return + } + + newline() + header(`${icons.globe} Release Check`) + keyValue('Channel', result?.channel ?? colors.muted('unknown')) + keyValue('Current', result?.current_version ?? colors.muted('unknown')) + keyValue('Latest', result?.latest_version ?? colors.muted('none published')) + if (result?.update_available) { + success('An update is available. Run `temps platform update apply` to install it.') + if (result.release_url) { + keyValue('Release notes', result.release_url) + } + } else { + // Not necessarily "nothing newer exists" — on a more stable channel the + // newest release is often older than a nightly build, which is expected. + info('Nothing newer on this channel.') + } + newline() +} + +/** Show or pin the release channel this server tracks. */ +async function updateChannelAction( + channel: string | undefined, + options: { json?: boolean } +): Promise { + await requireAuth() + await setupClient() + + if (!channel) { + const capability = await withSpinner('Fetching channel...', async () => { + const { data, error: err } = await getUpdateCapability({ client }) + if (err) { + throw new Error(getErrorMessage(err)) + } + return data + }) + if (options.json) { + json({ + channel: capability?.channel, + pinned: capability?.channel_is_pinned, + }) + return + } + newline() + keyValue('Channel', capability?.channel ?? colors.muted('unknown')) + keyValue( + 'Source', + capability?.channel_is_pinned + ? 'pinned in settings' + : 'inferred from the installed version' + ) + newline() + return + } + + const requested = channel.trim().toLowerCase() + const isAuto = requested === CHANNEL_AUTO + if (!isAuto && !UPDATE_CHANNELS.includes(requested as (typeof UPDATE_CHANNELS)[number])) { + error( + `Unknown channel '${channel}'. Use one of: ${UPDATE_CHANNELS.join(', ')}, or ${CHANNEL_AUTO}.` + ) + process.exitCode = 1 + return + } + + await withSpinner('Updating channel...', async () => { + // The settings PUT replaces the whole document, so read-modify-write is + // required — sending only `self_update` would reset every other field. + const { data: current, error: readErr } = await getSettings({ client }) + if (readErr || !current) { + throw new Error(readErr ? getErrorMessage(readErr) : 'Could not read settings') + } + const { error: writeErr } = await updateSettings({ + client, + body: { + ...current, + self_update: { + enabled: current.self_update?.enabled ?? true, + channel: isAuto ? null : requested, + }, + } as never, + }) + if (writeErr) { + throw new Error(getErrorMessage(writeErr)) + } + }) + + success( + isAuto + ? 'Channel now follows the installed version.' + : `Now tracking the ${requested} channel.` + ) + info('Run `temps platform update check` to look for releases on it.') +} diff --git a/crates/temps-cli/src/commands/serve/mod.rs b/crates/temps-cli/src/commands/serve/mod.rs index 4e53be841..70b577f02 100644 --- a/crates/temps-cli/src/commands/serve/mod.rs +++ b/crates/temps-cli/src/commands/serve/mod.rs @@ -334,6 +334,10 @@ impl ServeCommand { rt.spawn(crate::commands::upgrade::update_notifier_loop( update_status.clone(), update_check_interval, + Arc::new(temps_config::ConfigService::new( + serve_config.clone(), + db.clone(), + )), )); // Companion to the notifier above: the notifier says a release exists, @@ -355,6 +359,7 @@ impl ServeCommand { serve_config.data_dir.clone(), self.disable_self_update, self_update_caveat, + update_status.clone(), )); // Connect to Docker once and share the handle between: diff --git a/crates/temps-cli/src/commands/serve/self_update.rs b/crates/temps-cli/src/commands/serve/self_update.rs index 7a99d38c1..75439d33f 100644 --- a/crates/temps-cli/src/commands/serve/self_update.rs +++ b/crates/temps-cli/src/commands/serve/self_update.rs @@ -7,11 +7,15 @@ //! back after it exits, and (b) reporting the outcome of an operation that by //! definition kills the process that started it. //! -//! **How the restart works.** Nothing in temps restarts temps. The binary is -//! swapped on disk and the process exits; whatever supervises it (systemd -//! `Restart=always`, launchd `KeepAlive`) starts it again, now on the new -//! binary. That is why an install with no supervisor is refused up front rather -//! than left dead — see `detect_supervisor`. +//! **How the restart works.** Nothing in temps restarts temps. Where a +//! supervisor is detected (systemd `Restart=always`, launchd `KeepAlive`) the +//! binary is swapped and the process exits, and the supervisor brings it back +//! on the new one. Where no supervisor is detected the binary is still +//! installed — the operator asked for the update and gets it — but the process +//! deliberately keeps running the OLD version instead of exiting into an +//! outage nothing would recover from. The capability says which of the two +//! will happen BEFORE the click, and the result says the update is not live +//! until temps is restarted. See `detect_supervisor` and `SelfUpdateRestartMode`. //! //! **How the outcome is reported.** The attempt is written to //! `/self-update.json` as `pending` immediately before exiting, and @@ -25,15 +29,18 @@ use std::sync::{Arc, RwLock}; use chrono::Utc; use temps_core::{ - SelfUpdateAttempt, SelfUpdateBlocker, SelfUpdateCapability, SelfUpdateError, SelfUpdatePhase, - SelfUpdateStatus, SelfUpdater, StartedSelfUpdate, SupervisorKind, SELF_UPDATE_JOURNAL_FILE, + AvailableUpdate, ReleaseCheckResult, SelfUpdateAttempt, SelfUpdateBlocker, + SelfUpdateCapability, SelfUpdateError, SelfUpdatePhase, SelfUpdatePolicy, + SelfUpdateRestartMode, SelfUpdateStatus, SelfUpdater, StartedSelfUpdate, SupervisorKind, + UpdateStatusSlot, SELF_UPDATE_JOURNAL_FILE, }; use tracing::{error, info, warn}; use crate::commands::upgrade::{ check_write_permission, current_version_tag, download_asset, download_asset_text, extract_binary_from_tarball, fetch_latest_release_in_channel, fetch_specific_release, - platform_target, replace_binary, verify_checksum, GitHubRelease, UpgradeChannel, + is_newer_version, platform_target, replace_binary, verify_checksum, GitHubRelease, + UpgradeChannel, }; /// Grace period between accepting the update and exiting the process. Long @@ -46,6 +53,10 @@ const RESTART_GRACE: std::time::Duration = std::time::Duration::from_millis(1_50 /// init). Advisory only — it drives the polling timeout, nothing else. const ESTIMATED_RESTART_SECS: u64 = 45; +/// Bound on an operator-triggered check so a hung release API cannot leave the +/// request (and the spinner behind it) waiting indefinitely. +const CHECK_NOW_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(15); + #[derive(Debug, Default)] struct UpdaterState { phase: SelfUpdatePhase, @@ -63,9 +74,11 @@ pub struct BinarySelfUpdater { /// the settings toggle, nothing reachable over HTTP can clear it. disabled_by_flag: bool, supervisor: SupervisorKind, - /// Topology caveat surfaced with the confirmation (see the field of the - /// same name on `SelfUpdateCapability`). - caveat: Option, + /// Split-topology note supplied by the caller, merged into `caveats()`. + topology_caveat: Option, + /// Shared notice slot the background notifier also writes. An on-demand + /// check republishes it so the banner and the version page never disagree. + update_status: Arc, state: Arc>, } @@ -74,7 +87,12 @@ impl BinarySelfUpdater { /// process. Never fails: a bad journal or an unresolvable binary path /// degrades to "self-update unavailable", which the capability endpoint /// reports with a reason. - pub fn new(data_dir: PathBuf, disabled_by_flag: bool, caveat: Option) -> Self { + pub fn new( + data_dir: PathBuf, + disabled_by_flag: bool, + topology_caveat: Option, + update_status: Arc, + ) -> Self { let binary_path = std::env::current_exe() .map(|p| std::fs::canonicalize(&p).unwrap_or(p)) .unwrap_or_else(|e| { @@ -95,7 +113,8 @@ impl BinarySelfUpdater { data_dir, disabled_by_flag, supervisor, - caveat, + topology_caveat, + update_status, state: Arc::new(RwLock::new(UpdaterState::default())), }; @@ -131,11 +150,17 @@ impl BinarySelfUpdater { } }; - if attempt.status != SelfUpdateStatus::Pending { + // `InstalledPendingRestart` is resolvable too: the operator may be + // restarting right now, which is exactly this boot. + if !matches!( + attempt.status, + SelfUpdateStatus::Pending | SelfUpdateStatus::InstalledPendingRestart + ) { return Some(attempt); } let running = current_version_tag(); + let awaiting_manual_restart = attempt.status == SelfUpdateStatus::InstalledPendingRestart; attempt.finished_at = Some(Utc::now()); if attempt.to_version.as_deref() == Some(running.as_str()) { attempt.status = SelfUpdateStatus::Succeeded; @@ -144,6 +169,17 @@ impl BinarySelfUpdater { to = %running, "Self-update completed: restarted on the new version" ); + } else if awaiting_manual_restart { + // Still on the old binary, but nothing ever promised otherwise: + // this install is waiting on a restart the operator hasn't done. + // Calling that a failure would hide a pending upgrade, so the + // attempt stays exactly where it is. + attempt.finished_at = None; + info!( + installed = ?attempt.to_version, + running = %running, + "A self-update is installed and waiting for a restart" + ); } else { attempt.status = SelfUpdateStatus::Failed; let target = attempt @@ -177,21 +213,49 @@ impl BinarySelfUpdater { /// Always answerable — there is no state in which the manual path is gone. fn manual_command(&self, blocker: Option) -> String { match blocker { - Some(SelfUpdateBlocker::Container) => { + Some(SelfUpdateBlocker::BinaryNotWritable) => "sudo temps upgrade".to_string(), + _ if self.supervisor == SupervisorKind::Container => { "docker compose pull && docker compose up -d".to_string() } - Some(SelfUpdateBlocker::BinaryNotWritable) => "sudo temps upgrade".to_string(), _ => "temps upgrade".to_string(), } } + /// Everything true about this install that the operator should know before + /// clicking, but that does not stop the update. Composed rather than + /// single-valued because a split-topology console in a container has two + /// separate things worth saying. + fn caveats(&self) -> Option { + let mut parts: Vec = Vec::new(); + match self.supervisor { + SupervisorKind::Container => parts.push( + "This server runs in a container. The new binary is written into the container's \ + filesystem and survives a restart, but recreating the container (for example \ + `docker compose up -d` after an image change) reverts it to the image's version \ + — update your image tag for a durable upgrade." + .to_string(), + ), + SupervisorKind::None => parts.push( + "No process supervisor was detected, so temps cannot restart itself. The new \ + binary will be installed and temps will keep serving the current version until \ + you restart it." + .to_string(), + ), + SupervisorKind::Systemd | SupervisorKind::Launchd => {} + } + if let Some(topology) = &self.topology_caveat { + parts.push(topology.clone()); + } + (!parts.is_empty()).then(|| parts.join(" ")) + } + /// First blocker that applies, or `None` when an update can run. /// /// Order is deliberate: an explicit operator decision (`--disable-self-update`, /// then the settings toggle) is reported before any environmental problem, /// because "you turned this off" is the honest answer even on a host that /// also happens to be unsupervised. - fn find_blocker(&self, enabled_in_settings: bool) -> Option<(SelfUpdateBlocker, String)> { + fn find_blocker(&self, policy: &SelfUpdatePolicy) -> Option<(SelfUpdateBlocker, String)> { if self.disabled_by_flag { return Some(( SelfUpdateBlocker::DisabledByFlag, @@ -200,7 +264,7 @@ impl BinarySelfUpdater { .to_string(), )); } - if !enabled_in_settings { + if !policy.enabled { return Some(( SelfUpdateBlocker::DisabledBySetting, "One-click updates are turned off in Settings → Platform. An admin can re-enable \ @@ -208,24 +272,9 @@ impl BinarySelfUpdater { .to_string(), )); } - if self.supervisor == SupervisorKind::Container { - return Some(( - SelfUpdateBlocker::Container, - "This server runs inside a container, where the binary comes from the image. \ - Replacing it would be undone the next time the container is recreated — pull a \ - newer image tag instead." - .to_string(), - )); - } - if !self.supervisor.restarts_on_exit() { - return Some(( - SelfUpdateBlocker::NoSupervisor, - "No process supervisor was detected (no systemd or launchd), so nothing would \ - restart the server after it exits. Run temps under a service manager, or upgrade \ - from the command line." - .to_string(), - )); - } + // NOTE: a missing supervisor is deliberately NOT a blocker. Installing + // the binary is still exactly what the operator asked for; only the + // restart is out of reach, and `restart_mode` says so up front. if let Err(e) = platform_target() { return Some((SelfUpdateBlocker::UnsupportedPlatform, e.to_string())); } @@ -270,9 +319,30 @@ impl BinarySelfUpdater { } } +/// Resolve the channel to track: the operator's explicit setting, else the one +/// implied by the running version tag. An unparsable setting falls back to +/// inference rather than erroring, so a bad value can never wedge the checker. +pub(crate) fn resolve_channel( + configured: Option<&str>, + current_version: &str, +) -> (UpgradeChannel, bool) { + match configured.and_then(UpgradeChannel::from_setting) { + Some(channel) => (channel, true), + None => ( + UpgradeChannel::for_installed_version(current_version), + false, + ), + } +} + +#[async_trait::async_trait] impl SelfUpdater for BinarySelfUpdater { - fn capability(&self, enabled_in_settings: bool) -> SelfUpdateCapability { - let blocker = self.find_blocker(enabled_in_settings); + fn capability(&self, policy: &SelfUpdatePolicy) -> SelfUpdateCapability { + let blocker = self.find_blocker(policy); + let current_version = current_version_tag(); + // The capability also backs the version page, so it reports the + // effective channel even when no update is pending. + let (channel, pinned) = resolve_channel(policy.channel.as_deref(), ¤t_version); let (phase, phase_error, last_attempt) = match self.state.read() { Ok(state) => ( state.phase, @@ -294,9 +364,13 @@ impl SelfUpdater for BinarySelfUpdater { blocker: blocker.as_ref().map(|(b, _)| *b), reason: blocker.as_ref().map(|(_, r)| r.clone()), manual_command: self.manual_command(blocker.as_ref().map(|(b, _)| *b)), + current_version: current_version.clone(), + channel: channel.as_str().to_string(), + channel_is_pinned: pinned, supervisor: self.supervisor, + restart_mode: self.supervisor.restart_mode(), binary_path: self.binary_path.display().to_string(), - caveat: self.caveat.clone(), + caveat: self.caveats(), phase, phase_error, last_attempt, @@ -307,9 +381,9 @@ impl SelfUpdater for BinarySelfUpdater { &self, target_version: Option, triggered_by_user_id: Option, - enabled_in_settings: bool, + policy: &SelfUpdatePolicy, ) -> Result { - if let Some((blocker, reason)) = self.find_blocker(enabled_in_settings) { + if let Some((blocker, reason)) = self.find_blocker(policy) { if blocker == SelfUpdateBlocker::InProgress { let phase = self .state @@ -326,12 +400,16 @@ impl SelfUpdater for BinarySelfUpdater { let current_version = current_version_tag(); self.set_phase(SelfUpdatePhase::Resolving, None); + let restart_mode = self.supervisor.restart_mode(); + let (channel, _) = resolve_channel(policy.channel.as_deref(), ¤t_version); let job = UpdateJob { binary_path: self.binary_path.clone(), journal_path: self.journal_path(), from_version: current_version.clone(), target_version, triggered_by_user_id, + restart_mode, + channel, state: self.state.clone(), }; tokio::spawn(job.run()); @@ -339,14 +417,74 @@ impl SelfUpdater for BinarySelfUpdater { info!( user_id = ?triggered_by_user_id, from = %current_version, + restart_mode = restart_mode.as_str(), "Self-update accepted; downloading in the background" ); Ok(StartedSelfUpdate { current_version, - estimated_restart_secs: ESTIMATED_RESTART_SECS, + // Nothing goes down in manual mode, so the caller has nothing to + // wait out. + estimated_restart_secs: match restart_mode { + SelfUpdateRestartMode::Automatic => ESTIMATED_RESTART_SECS, + SelfUpdateRestartMode::Manual => 0, + }, + restart_mode, }) } + + async fn check_now(&self, channel: Option) -> Result { + let current_version = current_version_tag(); + let (channel, _) = resolve_channel(channel.as_deref(), ¤t_version); + + let release = + tokio::time::timeout(CHECK_NOW_TIMEOUT, fetch_latest_release_in_channel(channel)) + .await + .map_err(|_| { + format!( + "Checking the {} channel timed out after {}s.", + channel.as_str(), + CHECK_NOW_TIMEOUT.as_secs() + ) + })? + .map_err(|e| format!("Could not check the {} channel: {e}", channel.as_str()))?; + + let update_available = is_newer_version(&release.tag_name, ¤t_version); + if update_available { + self.update_status.set(AvailableUpdate { + current_version: current_version.clone(), + latest_version: release.tag_name.clone(), + channel: channel.as_str().to_string(), + release_url: release.html_url.clone(), + checked_at: Utc::now(), + }); + } else { + // Clear rather than leave the previous notice: after switching from + // nightly to stable the newest stable is OLDER, so it can never + // overwrite the stale nightly notice and the banner would lie. + self.update_status.clear(); + } + + info!( + channel = channel.as_str(), + current = %current_version, + latest = %release.tag_name, + update_available, + "Release check requested from the console" + ); + + Ok(ReleaseCheckResult { + channel: channel.as_str().to_string(), + current_version, + latest_version: Some(release.tag_name), + release_url: Some(release.html_url), + update_available, + }) + } + + fn available_update(&self) -> Option { + self.update_status.get() + } } /// The background half of an update: everything between "accepted" and "the @@ -358,6 +496,9 @@ struct UpdateJob { from_version: String, target_version: Option, triggered_by_user_id: Option, + restart_mode: SelfUpdateRestartMode, + /// Channel the "newest release" lookup uses when no version is pinned. + channel: UpgradeChannel, state: Arc>, } @@ -372,19 +513,35 @@ impl UpdateJob { async fn run(self) { let started_at = Utc::now(); match self.execute(started_at).await { - Ok(target) => { - // The swap is done and the journal says `pending`. Exiting is - // now the whole job: the supervisor brings us back on the new - // binary and the next boot resolves the journal entry. - self.set_phase(SelfUpdatePhase::Restarting, None); - warn!( - from = %self.from_version, - to = %target, - "Binary replaced — exiting so the supervisor restarts temps on the new version" - ); - tokio::time::sleep(RESTART_GRACE).await; - std::process::exit(0); - } + Ok(target) => match self.restart_mode { + SelfUpdateRestartMode::Automatic => { + // The swap is done and the journal says `pending`. Exiting + // is now the whole job: the supervisor brings us back on + // the new binary and the next boot resolves the journal. + self.set_phase(SelfUpdatePhase::Restarting, None); + warn!( + from = %self.from_version, + to = %target, + "Binary replaced — exiting so the supervisor restarts temps on the new version" + ); + tokio::time::sleep(RESTART_GRACE).await; + std::process::exit(0); + } + SelfUpdateRestartMode::Manual => { + // Installed, but exiting here would take the server down + // with nothing to bring it back. Keep serving the old + // binary and make the outstanding restart obvious. + self.set_phase(SelfUpdatePhase::PendingRestart, None); + warn!( + from = %self.from_version, + to = %target, + "Binary replaced, but no supervisor was detected — temps is STILL RUNNING \ + {} and will pick up {} when you restart it", + self.from_version, + target + ); + } + }, Err(e) => { let message = e.to_string(); error!( @@ -494,9 +651,18 @@ impl UpdateJob { let attempt = SelfUpdateAttempt { from_version: self.from_version.clone(), to_version: Some(to_version.clone()), - status: SelfUpdateStatus::Pending, + // `Pending` means "we are about to exit, resolve this on the next + // boot". In manual mode nothing exits, so the attempt is already + // as finished as it can get until the operator restarts. + status: match self.restart_mode { + SelfUpdateRestartMode::Automatic => SelfUpdateStatus::Pending, + SelfUpdateRestartMode::Manual => SelfUpdateStatus::InstalledPendingRestart, + }, started_at, - finished_at: None, + finished_at: match self.restart_mode { + SelfUpdateRestartMode::Automatic => None, + SelfUpdateRestartMode::Manual => Some(Utc::now()), + }, triggered_by_user_id: self.triggered_by_user_id, error: None, previous_binary_path: backup_path.map(|p| p.display().to_string()), @@ -515,10 +681,7 @@ impl UpdateJob { async fn resolve_release(&self) -> anyhow::Result { match &self.target_version { Some(version) => fetch_specific_release(version).await, - None => { - let channel = UpgradeChannel::for_installed_version(&self.from_version); - fetch_latest_release_in_channel(channel).await - } + None => fetch_latest_release_in_channel(self.channel).await, } } } @@ -682,11 +845,20 @@ mod tests { data_dir: dir.to_path_buf(), disabled_by_flag, supervisor, - caveat: None, + topology_caveat: None, + update_status: Arc::new(UpdateStatusSlot::new()), state: Arc::new(RwLock::new(UpdaterState::default())), } } + /// Settings-backed policy for tests: enabled/disabled, channel inferred. + fn policy(enabled: bool) -> SelfUpdatePolicy { + SelfUpdatePolicy { + enabled, + channel: None, + } + } + fn temp_dir(name: &str) -> PathBuf { let dir = std::env::temp_dir().join(format!("temps-self-update-test-{name}")); let _ = std::fs::remove_dir_all(&dir); @@ -698,7 +870,7 @@ mod tests { #[test] fn test_flag_blocks_even_when_everything_else_is_fine() { let dir = temp_dir("flag"); - let cap = updater(&dir, true, SupervisorKind::Systemd).capability(true); + let cap = updater(&dir, true, SupervisorKind::Systemd).capability(&policy(true)); assert!(!cap.can_apply); assert_eq!(cap.blocker, Some(SelfUpdateBlocker::DisabledByFlag)); // The reason must say the flag cannot be cleared from the UI, or an @@ -712,7 +884,7 @@ mod tests { // Both off: the flag is the one the operator cannot undo in the UI, so // it must be the reported blocker. let dir = temp_dir("flag-wins"); - let cap = updater(&dir, true, SupervisorKind::Systemd).capability(false); + let cap = updater(&dir, true, SupervisorKind::Systemd).capability(&policy(false)); assert_eq!(cap.blocker, Some(SelfUpdateBlocker::DisabledByFlag)); let _ = std::fs::remove_dir_all(&dir); } @@ -720,39 +892,70 @@ mod tests { #[test] fn test_settings_toggle_blocks() { let dir = temp_dir("setting"); - let cap = updater(&dir, false, SupervisorKind::Systemd).capability(false); + let cap = updater(&dir, false, SupervisorKind::Systemd).capability(&policy(false)); assert!(!cap.can_apply); assert_eq!(cap.blocker, Some(SelfUpdateBlocker::DisabledBySetting)); let _ = std::fs::remove_dir_all(&dir); } #[test] - fn test_container_is_never_updatable() { + fn test_container_installs_with_a_caveat_instead_of_being_refused() { let dir = temp_dir("container"); - let cap = updater(&dir, false, SupervisorKind::Container).capability(true); - assert!(!cap.can_apply); - assert_eq!(cap.blocker, Some(SelfUpdateBlocker::Container)); - // Must point at the image, not at `temps upgrade`, which would be - // undone on the next container recreate. + let cap = updater(&dir, false, SupervisorKind::Container).capability(&policy(true)); + // The operator asked for the binary to be updated; a container is a + // reason to warn, not to refuse. + assert!(cap.can_apply, "blocked by {:?}", cap.blocker); + assert_eq!(cap.restart_mode, SelfUpdateRestartMode::Manual); + // ...but they must be told the swap does not survive a recreate. + let caveat = cap.caveat.expect("container needs a caveat"); + assert!( + caveat.contains("recreating") || caveat.contains("recreate"), + "{caveat}" + ); + // The durable fix points at the image, not `temps upgrade`. assert!(cap.manual_command.contains("docker")); let _ = std::fs::remove_dir_all(&dir); } #[test] - fn test_unsupervised_is_refused() { + fn test_unsupervised_installs_without_restarting() { let dir = temp_dir("unsupervised"); - let cap = updater(&dir, false, SupervisorKind::None).capability(true); - assert!(!cap.can_apply); - assert_eq!(cap.blocker, Some(SelfUpdateBlocker::NoSupervisor)); - // The manual path always remains available. + let cap = updater(&dir, false, SupervisorKind::None).capability(&policy(true)); + // Installing still works with no supervisor — only the restart is out + // of reach, and that is stated rather than used as a refusal. + assert!(cap.can_apply, "blocked by {:?}", cap.blocker); + assert_eq!(cap.blocker, None); + assert_eq!(cap.restart_mode, SelfUpdateRestartMode::Manual); + let caveat = cap.caveat.expect("manual restart needs a caveat"); + assert!(caveat.contains("restart it"), "{caveat}"); assert_eq!(cap.manual_command, "temps upgrade"); let _ = std::fs::remove_dir_all(&dir); } + #[test] + fn test_supervised_install_restarts_automatically_and_has_no_caveat() { + let dir = temp_dir("supervised-mode"); + let cap = updater(&dir, false, SupervisorKind::Systemd).capability(&policy(true)); + assert_eq!(cap.restart_mode, SelfUpdateRestartMode::Automatic); + assert_eq!(cap.caveat, None); + let _ = std::fs::remove_dir_all(&dir); + } + + #[test] + fn test_split_topology_caveat_is_kept_alongside_the_restart_caveat() { + let dir = temp_dir("caveats"); + let mut u = updater(&dir, false, SupervisorKind::None); + u.topology_caveat = Some("Console only; restart the proxy too.".to_string()); + let caveat = u.capability(&policy(true)).caveat.expect("both caveats"); + assert!(caveat.contains("restart it"), "{caveat}"); + assert!(caveat.contains("restart the proxy too"), "{caveat}"); + let _ = std::fs::remove_dir_all(&dir); + } + #[test] fn test_supervised_install_can_apply() { let dir = temp_dir("ok"); - let cap = updater(&dir, false, SupervisorKind::Systemd).capability(true); + let cap = updater(&dir, false, SupervisorKind::Systemd).capability(&policy(true)); assert!( cap.can_apply, "blocked by {:?}: {:?}", @@ -767,7 +970,7 @@ mod tests { fn test_start_refused_when_disabled_reports_blocker() { let dir = temp_dir("start-refused"); let err = updater(&dir, false, SupervisorKind::Systemd) - .start(None, Some(1), false) + .start(None, Some(1), &policy(false)) .expect_err("must refuse when disabled in settings"); assert_eq!(err.blocker(), SelfUpdateBlocker::DisabledBySetting); let _ = std::fs::remove_dir_all(&dir); @@ -779,7 +982,7 @@ mod tests { let updater = updater(&dir, false, SupervisorKind::Systemd); updater.set_phase(SelfUpdatePhase::Downloading, None); let err = updater - .start(None, Some(1), true) + .start(None, Some(1), &policy(true)) .expect_err("must refuse a concurrent attempt"); assert!(matches!(err, SelfUpdateError::AlreadyRunning { .. })); let _ = std::fs::remove_dir_all(&dir); @@ -792,7 +995,7 @@ mod tests { let dir = temp_dir("retry"); let updater = updater(&dir, false, SupervisorKind::Systemd); updater.set_phase(SelfUpdatePhase::Failed, Some("network down".to_string())); - let cap = updater.capability(true); + let cap = updater.capability(&policy(true)); assert!(cap.can_apply); assert_eq!(cap.phase, SelfUpdatePhase::Failed); assert_eq!(cap.phase_error.as_deref(), Some("network down")); @@ -879,6 +1082,55 @@ mod tests { let _ = std::fs::remove_dir_all(&dir); } + #[test] + fn test_installed_pending_restart_survives_a_restart_on_the_old_version() { + // The operator installed an update but has not restarted yet. Booting + // the OLD binary must not turn that into a failure — the new binary is + // still sitting there waiting. + let dir = temp_dir("journal-pending-restart"); + let attempt = SelfUpdateAttempt { + from_version: current_version_tag(), + to_version: Some("v999.0.0".to_string()), + status: SelfUpdateStatus::InstalledPendingRestart, + started_at: Utc::now(), + finished_at: Some(Utc::now()), + triggered_by_user_id: Some(1), + error: None, + previous_binary_path: None, + }; + write_journal(&dir.join(SELF_UPDATE_JOURNAL_FILE), &attempt).expect("write journal"); + + let resolved = updater(&dir, false, SupervisorKind::None) + .reconcile_journal() + .expect("journal entry"); + assert_eq!(resolved.status, SelfUpdateStatus::InstalledPendingRestart); + assert_eq!(resolved.error, None, "waiting is not a failure"); + let _ = std::fs::remove_dir_all(&dir); + } + + #[test] + fn test_installed_pending_restart_resolves_once_the_new_version_boots() { + let dir = temp_dir("journal-pending-done"); + let running = current_version_tag(); + let attempt = SelfUpdateAttempt { + from_version: "v0.0.1".to_string(), + to_version: Some(running.clone()), + status: SelfUpdateStatus::InstalledPendingRestart, + started_at: Utc::now(), + finished_at: Some(Utc::now()), + triggered_by_user_id: Some(1), + error: None, + previous_binary_path: None, + }; + write_journal(&dir.join(SELF_UPDATE_JOURNAL_FILE), &attempt).expect("write journal"); + + let resolved = updater(&dir, false, SupervisorKind::None) + .reconcile_journal() + .expect("journal entry"); + assert_eq!(resolved.status, SelfUpdateStatus::Succeeded); + let _ = std::fs::remove_dir_all(&dir); + } + #[test] fn test_missing_journal_is_not_an_error() { let dir = temp_dir("journal-absent"); diff --git a/crates/temps-cli/src/commands/upgrade.rs b/crates/temps-cli/src/commands/upgrade.rs index 02b3bd519..4da0978c3 100644 --- a/crates/temps-cli/src/commands/upgrade.rs +++ b/crates/temps-cli/src/commands/upgrade.rs @@ -64,7 +64,19 @@ fn is_nightly_tag(tag: &str) -> bool { } impl UpgradeChannel { - fn as_str(self) -> &'static str { + /// Parse a channel configured in settings. Unknown values return `None` so + /// the caller falls back to inferring from the running version rather than + /// silently tracking the wrong channel. + pub fn from_setting(value: &str) -> Option { + match value.trim().to_ascii_lowercase().as_str() { + "stable" => Some(Self::Stable), + "beta" => Some(Self::Beta), + "nightly" => Some(Self::Nightly), + _ => None, + } + } + + pub fn as_str(self) -> &'static str { match self { Self::Stable => "stable", Self::Beta => "beta", @@ -747,7 +759,7 @@ fn version_sort_key(tag: &str) -> Option { /// exotic tags. This is deliberately stricter than `temps upgrade`, which /// treats any tag difference as upgradeable (including downgrades the /// operator explicitly pins with `--version`). -fn is_newer_version(candidate: &str, current: &str) -> bool { +pub(crate) fn is_newer_version(candidate: &str, current: &str) -> bool { match (version_sort_key(candidate), version_sort_key(current)) { (Some(candidate_key), Some(current_key)) => candidate_key > current_key, _ => false, @@ -759,9 +771,13 @@ fn is_newer_version(candidate: &str, current: &str) -> bool { /// binary. Every failure path (network, GitHub quota, unparsable tags) /// collapses to `None` with a debug log — the notifier is advisory and must /// never surface errors to an operator who didn't ask for a check. -pub async fn check_for_newer_release() -> Option { +pub async fn check_for_newer_release(configured_channel: Option<&str>) -> Option { let current_version = current_version_tag(); - let channel = UpgradeChannel::for_installed_version(¤t_version); + // An explicit channel from settings wins; otherwise fall back to the tag + // the running binary carries, which is what the CLI has always done. + let channel = configured_channel + .and_then(UpgradeChannel::from_setting) + .unwrap_or_else(|| UpgradeChannel::for_installed_version(¤t_version)); let release = match tokio::time::timeout( UPDATE_CHECK_TIMEOUT, @@ -815,10 +831,18 @@ pub async fn check_for_newer_release() -> Option { pub async fn update_notifier_loop( slot: Arc, interval: std::time::Duration, + config_service: Arc, ) { tokio::time::sleep(UPDATE_CHECK_STARTUP_DELAY).await; loop { - if let Some(notice) = check_for_newer_release().await { + // Re-read every pass so switching channel in the console takes effect + // on the next check instead of requiring a restart. + let configured_channel = config_service + .get_settings() + .await + .ok() + .and_then(|s| s.self_update.channel); + if let Some(notice) = check_for_newer_release(configured_channel.as_deref()).await { tracing::warn!( current_version = %notice.current_version, latest_version = %notice.latest_version, diff --git a/crates/temps-config/src/handler.rs b/crates/temps-config/src/handler.rs index 56112f854..d9b38134e 100644 --- a/crates/temps-config/src/handler.rs +++ b/crates/temps-config/src/handler.rs @@ -508,6 +508,7 @@ impl AppSettingsResponse { get_update_status, get_update_capability, start_update, + check_for_update, get_disk_status, update_settings, generate_join_token, @@ -553,7 +554,9 @@ impl AppSettingsResponse { temps_core::SelfUpdateAttempt, temps_core::SelfUpdateBlocker, temps_core::SelfUpdatePhase, + temps_core::SelfUpdateRestartMode, temps_core::SelfUpdateStatus, + temps_core::ReleaseCheckResult, temps_core::SupervisorKind, )), info( @@ -574,6 +577,7 @@ pub fn configure_routes() -> Router> { "/settings/update", get(get_update_capability).post(start_update), ) + .route("/settings/update/check", post(check_for_update)) .route("/settings/disk-status", get(get_disk_status)) .route("/settings/join-token/generate", post(generate_join_token)) .route("/settings/join-token", delete(revoke_join_token)) @@ -905,8 +909,20 @@ pub struct UpdateCapabilityResponse { pub caveat: Option, /// The equivalent command to run by hand. Always present. pub manual_command: String, + /// Version tag of the running binary. Always present — the version page + /// needs it whether or not an update exists. + pub current_version: String, + /// Channel actually tracked, after applying the configured override or + /// falling back to inference from the running version tag. + pub channel: String, + /// True when `channel` was set explicitly in settings rather than inferred. + pub channel_is_pinned: bool, /// What would restart the process: `systemd`, `launchd`, `container`, `none`. pub supervisor: temps_core::SupervisorKind, + /// `automatic` when applying an update also restarts temps; `manual` when + /// it only installs the binary and the operator restarts on their own + /// schedule. Lets the console set expectations before the click. + pub restart_mode: temps_core::SelfUpdateRestartMode, /// Binary that would be replaced. pub binary_path: String, /// Phase of an in-flight attempt: `idle` when none is running. @@ -932,11 +948,33 @@ pub struct StartUpdateResponse { /// Version the server is running as it accepts this request. pub current_version: String, /// How long to allow for the server to come back before treating the - /// restart as failed. + /// restart as failed. `0` when nothing restarts. pub estimated_restart_secs: u64, + /// `automatic` (temps restarts itself) or `manual` (installed only). + pub restart_mode: temps_core::SelfUpdateRestartMode, pub message: String, } +/// Read the database-backed half of the update policy. +/// +/// Fails CLOSED: if settings cannot be read we must not report (or act on) a +/// capability the operator may have deliberately turned off. +async fn load_self_update_policy(app_state: &SettingsState) -> temps_core::SelfUpdatePolicy { + match app_state.config_service.get_settings().await { + Ok(settings) => temps_core::SelfUpdatePolicy { + enabled: settings.self_update.enabled, + channel: settings.self_update.channel, + }, + Err(e) => { + error!("Could not read self-update settings, treating as disabled: {e}"); + temps_core::SelfUpdatePolicy { + enabled: false, + channel: None, + } + } + } +} + /// Build the "no updater registered in this process" answer. /// /// Reached in hosts that run the settings API without owning the process @@ -947,7 +985,7 @@ fn updater_unavailable_response(allowed: bool) -> UpdateCapabilityResponse { UpdateCapabilityResponse { can_apply: false, allowed, - blocker: Some(temps_core::SelfUpdateBlocker::NoSupervisor), + blocker: Some(temps_core::SelfUpdateBlocker::NotSupported), reason: Some( "This process does not manage the temps binary, so it cannot apply an update. \ Upgrade from the command line on the host instead." @@ -955,7 +993,11 @@ fn updater_unavailable_response(allowed: bool) -> UpdateCapabilityResponse { ), caveat: None, manual_command: "temps upgrade".to_string(), + current_version: String::new(), + channel: "unknown".to_string(), + channel_is_pinned: false, supervisor: temps_core::SupervisorKind::None, + restart_mode: temps_core::SelfUpdateRestartMode::Manual, binary_path: String::new(), phase: temps_core::SelfUpdatePhase::Idle, phase_error: None, @@ -963,6 +1005,49 @@ fn updater_unavailable_response(allowed: bool) -> UpdateCapabilityResponse { } } +/// Ask the release API for the newest version on this install's channel, now, +/// instead of waiting for the background notifier's next pass. +#[utoipa::path( + tag = "Settings", + post, + path = "/settings/update/check", + responses( + (status = 200, description = "Result of the release check", body = temps_core::ReleaseCheckResult), + (status = 401, description = "Unauthorized"), + (status = 403, description = "Insufficient permissions"), + (status = 502, description = "The release API could not be reached", body = temps_core::ProblemDetails), + (status = 501, description = "This process cannot check for updates", body = temps_core::ProblemDetails) + ), + security(("bearer_auth" = [])) +)] +async fn check_for_update( + RequireAuth(auth): RequireAuth, + State(app_state): State>, +) -> Result { + // A read-only network probe that changes no state the operator can't + // already see, so it sits with the rest of the settings reads. + permission_guard!(auth, SettingsRead); + + let Some(updater) = app_state.self_updater.as_ref() else { + return Err(ErrorBuilder::new(StatusCode::NOT_IMPLEMENTED) + .title("Update Checks Not Supported Here") + .detail("This process does not track temps releases.") + .build()); + }; + + let policy = load_self_update_policy(&app_state).await; + let result = updater.check_now(policy.channel).await.map_err(|reason| { + // Upstream reachability, not a client mistake — say so plainly so the + // operator looks at egress rather than at their own request. + ErrorBuilder::new(StatusCode::BAD_GATEWAY) + .title("Release Check Failed") + .detail(reason) + .build() + })?; + + Ok(Json(result)) +} + /// Report whether a release update can be applied from the console. #[utoipa::path( tag = "Settings", @@ -990,18 +1075,7 @@ async fn get_update_capability( return Ok(Json(updater_unavailable_response(allowed))); }; - // The database toggle is only half the answer; the updater combines it with - // the launch flag and the environment to decide what is actually possible. - let enabled_in_settings = app_state - .config_service - .get_settings() - .await - .map(|s| s.self_update.enabled) - // Fail closed: if the setting cannot be read we must not report a - // capability the operator may have turned off. - .unwrap_or(false); - - let capability = updater.capability(enabled_in_settings); + let capability = updater.capability(&load_self_update_policy(&app_state).await); Ok(Json(UpdateCapabilityResponse { // Describes the SERVER only. Permission is reported separately as // `allowed` so a blocked install and an under-privileged caller stay @@ -1013,7 +1087,11 @@ async fn get_update_capability( reason: capability.reason, caveat: capability.caveat, manual_command: capability.manual_command, + current_version: capability.current_version, + channel: capability.channel, + channel_is_pinned: capability.channel_is_pinned, supervisor: capability.supervisor, + restart_mode: capability.restart_mode, binary_path: capability.binary_path, phase: capability.phase, phase_error: capability.phase_error, @@ -1062,18 +1140,11 @@ async fn start_update( .build()); }; - let enabled_in_settings = app_state - .config_service - .get_settings() - .await - .map(|s| s.self_update.enabled) - .unwrap_or(false); - let started = updater .start( request.version.clone(), Some(auth.user_id()), - enabled_in_settings, + &load_self_update_policy(&app_state).await, ) .map_err(self_update_error_to_problem)?; @@ -1105,8 +1176,17 @@ async fn start_update( Json(StartUpdateResponse { current_version: started.current_version, estimated_restart_secs: started.estimated_restart_secs, - message: "Update started. The server will restart when the new binary is installed." - .to_string(), + restart_mode: started.restart_mode, + message: match started.restart_mode { + temps_core::SelfUpdateRestartMode::Automatic => { + "Update started. The server will restart when the new binary is installed." + } + temps_core::SelfUpdateRestartMode::Manual => { + "Update started. The new binary will be installed, but temps keeps running \ + the current version until you restart it." + } + } + .to_string(), }), )) } @@ -1127,8 +1207,7 @@ fn self_update_error_to_problem(error: temps_core::SelfUpdateError) -> Problem { "Self-Update Disabled" } SelfUpdateBlocker::InProgress => "Update Already Running", - SelfUpdateBlocker::Container => "Self-Update Not Possible In A Container", - SelfUpdateBlocker::NoSupervisor => "No Process Supervisor", + SelfUpdateBlocker::NotSupported => "Self-Update Not Supported Here", SelfUpdateBlocker::BinaryNotWritable => "Binary Not Writable", SelfUpdateBlocker::UnsupportedPlatform => "Unsupported Platform", }; diff --git a/crates/temps-core/src/app_settings.rs b/crates/temps-core/src/app_settings.rs index 1e3d1cd38..c770eb0ce 100644 --- a/crates/temps-core/src/app_settings.rs +++ b/crates/temps-core/src/app_settings.rs @@ -933,11 +933,24 @@ pub struct SelfUpdateSettings { /// banner and the manual command, it just refuses to run it for you. #[schema(example = true)] pub enabled: bool, + + /// Release channel this install tracks: `stable`, `beta` or `nightly`. + /// + /// `None` (the default) means "infer from the running version tag", which + /// is what the CLI has always done — a `-nightly.` build tracks nightly, a + /// `-beta.N` build tracks beta, a plain tag tracks stable. Setting it + /// explicitly pins the channel, so an operator can move a nightly box back + /// onto stable without reinstalling. + #[schema(example = "stable")] + pub channel: Option, } impl Default for SelfUpdateSettings { fn default() -> Self { - Self { enabled: true } + Self { + enabled: true, + channel: None, + } } } diff --git a/crates/temps-core/src/lib.rs b/crates/temps-core/src/lib.rs index 097fd5075..8ff732e13 100644 --- a/crates/temps-core/src/lib.rs +++ b/crates/temps-core/src/lib.rs @@ -33,8 +33,9 @@ pub mod traces; pub mod update_status; pub use problemdetails::ProblemDetails; pub use self_update::{ - SelfUpdateAttempt, SelfUpdateBlocker, SelfUpdateCapability, SelfUpdateError, SelfUpdatePhase, - SelfUpdateStatus, SelfUpdater, StartedSelfUpdate, SupervisorKind, SELF_UPDATE_JOURNAL_FILE, + ReleaseCheckResult, SelfUpdateAttempt, SelfUpdateBlocker, SelfUpdateCapability, + SelfUpdateError, SelfUpdatePhase, SelfUpdatePolicy, SelfUpdateRestartMode, SelfUpdateStatus, + SelfUpdater, StartedSelfUpdate, SupervisorKind, SELF_UPDATE_JOURNAL_FILE, }; pub use update_status::{AvailableUpdate, UpdateStatusSlot, UPGRADE_DOCS_URL}; mod app_settings; diff --git a/crates/temps-core/src/self_update.rs b/crates/temps-core/src/self_update.rs index 4894688ae..344a1966f 100644 --- a/crates/temps-core/src/self_update.rs +++ b/crates/temps-core/src/self_update.rs @@ -15,6 +15,7 @@ //! capability is reported honestly up front, with the reason and the manual //! command to run instead, rather than discovering it after the process is gone. +use crate::AvailableUpdate; use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use utoipa::ToSchema; @@ -41,9 +42,17 @@ pub enum SupervisorKind { } impl SupervisorKind { - /// Can a process under this supervisor be expected to come back after exit? - pub fn restarts_on_exit(self) -> bool { - matches!(self, Self::Systemd | Self::Launchd) + /// How the new binary gets picked up under this supervisor. + /// + /// Only systemd and launchd are known to relaunch the process, so only they + /// get an automatic restart. Everything else installs and stays put: the + /// operator restarts on their own schedule, which is strictly better than + /// either refusing to install or exiting into an outage. + pub fn restart_mode(self) -> SelfUpdateRestartMode { + match self { + Self::Systemd | Self::Launchd => SelfUpdateRestartMode::Automatic, + Self::Container | Self::None => SelfUpdateRestartMode::Manual, + } } pub fn as_str(self) -> &'static str { @@ -68,10 +77,9 @@ pub enum SelfUpdateBlocker { /// Turned off in Settings (`self_update.enabled = false`). An admin can turn /// it back on in the UI. DisabledBySetting, - /// Running in a container: update the image tag instead. - Container, - /// Nothing would restart the process after it exits. - NoSupervisor, + /// This process does not manage the temps binary at all (e.g. the settings + /// API running inside the standalone proxy), so there is nothing to replace. + NotSupported, /// The binary (or its directory) is not writable by the server user. BinaryNotWritable, /// No release assets are published for this OS/arch. @@ -80,6 +88,28 @@ pub enum SelfUpdateBlocker { InProgress, } +/// What happens to the running process once the new binary is in place. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ToSchema)] +#[serde(rename_all = "snake_case")] +pub enum SelfUpdateRestartMode { + /// A supervisor will relaunch temps, so the update finishes by exiting. + /// Costs a few seconds of downtime and completes without further action. + Automatic, + /// Nothing would relaunch temps, so it installs the binary and keeps + /// running the OLD version until the operator restarts it themselves. + /// No downtime, but the update is not live until they do. + Manual, +} + +impl SelfUpdateRestartMode { + pub fn as_str(self) -> &'static str { + match self { + Self::Automatic => "automatic", + Self::Manual => "manual", + } + } +} + /// Where an in-flight update has got to. Polled by the console so a long /// download shows progress instead of an indefinite spinner. #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ToSchema, Default)] @@ -98,6 +128,9 @@ pub enum SelfUpdatePhase { Installing, /// Binary swapped; the process is shutting down so the supervisor restarts it. Restarting, + /// Binary swapped, but nothing will restart temps automatically — it is + /// still serving the old version until the operator restarts it. + PendingRestart, /// The attempt failed. The running binary was left untouched. Failed, } @@ -119,6 +152,7 @@ impl SelfUpdatePhase { Self::Verifying => "verifying", Self::Installing => "installing", Self::Restarting => "restarting", + Self::PendingRestart => "pending_restart", Self::Failed => "failed", } } @@ -133,6 +167,10 @@ pub enum SelfUpdateStatus { Pending, /// The process came back on the target version. Succeeded, + /// The new binary is on disk, but temps is still running the old one + /// because nothing restarts it automatically. Resolves to `Succeeded` on + /// the next boot; stays here (never fails) until the operator restarts. + InstalledPendingRestart, /// The attempt failed before the swap, or the process came back on the old /// version despite a completed swap. Failed, @@ -175,7 +213,20 @@ pub struct SelfUpdateCapability { /// Command to run by hand instead. Always present — the manual path works /// even when the API path is blocked, so the operator is never stuck. pub manual_command: String, + /// Version tag of the running binary, e.g. `v0.1.0-beta.55`. Always + /// present — the version page needs it whether or not an update exists. + pub current_version: String, + /// Channel this install actually tracks, after applying the configured + /// override or falling back to inference from `current_version`. + pub channel: String, + /// Whether `channel` came from settings (`true`) or was inferred from the + /// running version tag (`false`). The UI shows inference as the default + /// rather than as an explicit choice the operator made. + pub channel_is_pinned: bool, pub supervisor: SupervisorKind, + /// Whether applying an update also restarts temps, or only installs the + /// binary and leaves the restart to the operator. + pub restart_mode: SelfUpdateRestartMode, /// Absolute path of the binary that would be replaced. pub binary_path: String, /// Something true about this topology that the operator must know *before* @@ -198,7 +249,41 @@ pub struct StartedSelfUpdate { pub current_version: String, /// How long the console should expect to wait before the server answers /// again, so it can poll with a sensible timeout instead of guessing. + /// Meaningless when `restart_mode` is `manual` — nothing goes down. pub estimated_restart_secs: u64, + /// Echoed from the capability so the caller knows whether to expect a + /// restart at all, without racing a second capability fetch. + pub restart_mode: SelfUpdateRestartMode, +} + +/// Outcome of an operator-triggered release check. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema)] +pub struct ReleaseCheckResult { + /// Channel that was queried. + pub channel: String, + /// Version tag of the running binary. + pub current_version: String, + /// Newest release published on that channel, if any could be resolved. + pub latest_version: Option, + /// Release-notes page for `latest_version`. + pub release_url: Option, + /// True when `latest_version` is strictly newer than what is running. + /// False on a channel whose newest release is older — which is normal and + /// expected right after switching a nightly box onto stable. + pub update_available: bool, +} + +/// The database-backed half of the update policy. +/// +/// Passed in by the caller rather than read here: these live in the settings +/// table, which this trait deliberately knows nothing about. Bundled into one +/// struct so adding policy later doesn't churn every call site. +#[derive(Debug, Clone, Default, PartialEq, Eq)] +pub struct SelfUpdatePolicy { + /// `self_update.enabled` — the console's soft off switch. + pub enabled: bool, + /// `self_update.channel` — `None` means infer from the running version. + pub channel: Option, } #[derive(Debug, thiserror::Error)] @@ -227,17 +312,18 @@ impl SelfUpdateError { /// Registered as a service by `temps serve` and consumed by the settings API. /// Absent in hosts that cannot restart themselves meaningfully (e.g. the /// standalone proxy), in which case the endpoint reports "not supported here". +#[async_trait::async_trait] pub trait SelfUpdater: Send + Sync { - /// Report whether an update can be applied right now. - /// - /// `enabled_in_settings` is passed in rather than read here: the setting - /// lives in the database, which this trait deliberately knows nothing - /// about. The caller (which already loaded `AppSettings`) supplies it. - fn capability(&self, enabled_in_settings: bool) -> SelfUpdateCapability; + /// Report whether an update can be applied right now, plus the version and + /// channel information the console's version page renders. + fn capability(&self, policy: &SelfUpdatePolicy) -> SelfUpdateCapability; /// Begin an update. Returns as soon as the attempt is accepted — the - /// download, swap and restart continue in the background and are observable - /// through `capability().phase`, then through the journal after the restart. + /// download and swap continue in the background, observable through + /// `capability().phase`. Under `Automatic` restart mode the process then + /// exits and the outcome is read from the journal on the next boot; under + /// `Manual` it finishes at `PendingRestart` with temps still serving the + /// old binary. /// /// `target_version` pins a specific tag; `None` takes the newest release on /// this install's channel. @@ -245,8 +331,20 @@ pub trait SelfUpdater: Send + Sync { &self, target_version: Option, triggered_by_user_id: Option, - enabled_in_settings: bool, + policy: &SelfUpdatePolicy, ) -> Result; + + /// Query the release API right now instead of waiting for the background + /// notifier's next pass, and republish the shared update slot from the + /// result (including clearing it when nothing newer exists). + /// + /// `channel` is the configured override; `None` infers from the running + /// version. Errors are returned as operator-facing strings — a failed + /// check is a network problem to show, not a domain error to model. + async fn check_now(&self, channel: Option) -> Result; + + /// The update the last successful check found, if it is still current. + fn available_update(&self) -> Option; } #[cfg(test)] @@ -254,13 +352,25 @@ mod tests { use super::*; #[test] - fn test_only_real_supervisors_restart_on_exit() { - assert!(SupervisorKind::Systemd.restarts_on_exit()); - assert!(SupervisorKind::Launchd.restarts_on_exit()); - // A container restart returns to the image's binary, not the swapped - // one, so it must never count as "will come back updated". - assert!(!SupervisorKind::Container.restarts_on_exit()); - assert!(!SupervisorKind::None.restarts_on_exit()); + fn test_only_real_supervisors_restart_automatically() { + assert_eq!( + SupervisorKind::Systemd.restart_mode(), + SelfUpdateRestartMode::Automatic + ); + assert_eq!( + SupervisorKind::Launchd.restart_mode(), + SelfUpdateRestartMode::Automatic + ); + // Neither of these is known to relaunch temps, so the update must + // install and stop rather than exit into an outage. + assert_eq!( + SupervisorKind::Container.restart_mode(), + SelfUpdateRestartMode::Manual + ); + assert_eq!( + SupervisorKind::None.restart_mode(), + SelfUpdateRestartMode::Manual + ); } #[test] @@ -276,6 +386,9 @@ mod tests { // Restarting is deliberately NOT active: the swap is done and the // process is on its way out, so a second attempt has nothing to race. assert!(!SelfUpdatePhase::Restarting.is_active()); + // Likewise once installed — the binary is in place and the updater is + // free; only the operator's restart is outstanding. + assert!(!SelfUpdatePhase::PendingRestart.is_active()); assert!(!SelfUpdatePhase::Idle.is_active()); assert!(!SelfUpdatePhase::Failed.is_active()); } diff --git a/crates/temps-core/src/update_status.rs b/crates/temps-core/src/update_status.rs index f82685f7d..ef3b6b746 100644 --- a/crates/temps-core/src/update_status.rs +++ b/crates/temps-core/src/update_status.rs @@ -55,6 +55,20 @@ impl UpdateStatusSlot { *guard = Some(update); } + /// Drop any recorded notice. + /// + /// Used when a check finds nothing newer — otherwise switching from a + /// nightly install onto the stable channel would leave the old nightly + /// notice on screen forever, since stable is *older* and can never + /// overwrite it. + pub fn clear(&self) { + let mut guard = match self.inner.write() { + Ok(guard) => guard, + Err(poisoned) => poisoned.into_inner(), + }; + *guard = None; + } + /// The most recent notice, if any check has found a newer release. pub fn get(&self) -> Option { let guard = match self.inner.read() { @@ -92,6 +106,14 @@ mod tests { assert_eq!(slot.get(), Some(update)); } + #[test] + fn test_slot_clear_removes_a_stale_notice() { + let slot = UpdateStatusSlot::new(); + slot.set(notice("v0.2.0")); + slot.clear(); + assert_eq!(slot.get(), None); + } + #[test] fn test_slot_later_set_overwrites() { let slot = UpdateStatusSlot::new(); diff --git a/web/src/App.tsx b/web/src/App.tsx index 3f6847246..4ed90f329 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -267,6 +267,11 @@ const DockerRegistryPage = lazy(() => default: m.DockerRegistryPage, })) ) +const VersionPage = lazy(() => + import('./pages/settings/VersionPage').then((m) => ({ + default: m.VersionPage, + })) +) const SecurityPage = lazy(() => import('./pages/settings/SecurityPage').then((m) => ({ default: m.SecurityPage, @@ -591,6 +596,7 @@ const FullAppRoutes = () => { element={} /> {/* Security */} + } /> } /> = [ Pick & { @@ -14611,6 +14611,24 @@ export const getUpdateStatusOptions = (options?: Options) = queryKey: getUpdateStatusQueryKey(options) }); +/** + * Ask the release API for the newest version on this install's channel, now, + * instead of waiting for the background notifier's next pass. + */ +export const checkForUpdateMutation = (options?: Partial>): UseMutationOptions> => { + const mutationOptions: UseMutationOptions> = { + mutationFn: async (fnOptions) => { + const { data } = await checkForUpdate({ + ...options, + ...fnOptions, + throwOnError: true + }); + return data; + } + }; + return mutationOptions; +}; + export const listTeamsQueryKey = (options?: Options) => createQueryKey('listTeams', options); export const listTeamsOptions = (options?: Options) => queryOptions>({ diff --git a/web/src/api/client/index.ts b/web/src/api/client/index.ts index 6dcda3cbf..07fe24ab6 100644 --- a/web/src/api/client/index.ts +++ b/web/src/api/client/index.ts @@ -1,4 +1,4 @@ // This file is auto-generated by @hey-api/openapi-ts -export { acknowledgeAlarm, activateAiProvider, activateApiKey, activateConnection, activateProvider, addClusterMember, addContext, addEnvironmentDomain, addEvents, addManagedDomain, addSessionReplayEvents, addTeamMember, adminDrainNode, adminDrainStatus, adminGetNode, adminListNodeContainers, adminListNodes, adminRemoveNode, adminUndrainNode, applyHostnameMode, archiveConversation, archiveFlag, assignRole, attachScheduleServices, blobCopy, blobDelete, blobDisable, blobDownload, blobEnable, blobHead, blobList, blobPut, blobStatus, blobUpdate, cancel, cancelBackup, cancelDeployment, cancelDomainOrder, cancelPgUpgrade, cancelRun, cancelScheduleRun, changePasswordSelf, changeProjectSource, changeRequiredPassword, chatCompletions, checkAnalyticsHasEvents, checkCommitExists, checkDomainStatus, checkExplorerSupport, checkIpBlocked, checkProviderDeletionSafety, chunkUploadOptions, cleanupExpiredBackups, clearPreviewPassword, cliDeviceApprove, cliDeviceDeny, cliDeviceLookup, cliDevicePoll, cliDeviceStart, cliLogout, cmd, cmdKill, cmdLogs, confirmPendingAction, containerMetricsGetHistory, createAgent, createAlert, createAlertRule, createApiKey, createBackupSchedule, createBitbucketProvider, createCloudflareProvider, createConversation, createCustomDomain, createDashboard, createDeploymentToken, createDnsProvider, createDomain, createDsn, createEmailDomain, createEmailProvider, createEnvironment, createEnvironmentVariable, createFlag, createFunnel, createGenericProvider, createGiteaPatProvider, createGithubPatProvider, createGitlabOauthProvider, createGitlabPatProvider, createGitProvider, createGlobalMcp, createGlobalSkill, createIncident, createIpAccessControl, createMcp, createMonitor, createNotificationEmailProvider, createNotificationProvider, createOidcProvider, createOidcRoleMapping, createOrRecreateOrder, createPlan, createPr, createProject, createProjectFromTemplate, createProjectRelease, createProjectSecret, createProviderKey, createRelease, createRoute, createS3Source, createSandbox, createService, createSkill, createSlackProvider, createTeam, createUser, createWebhook, createWebhookProvider, deactivateApiKey, deactivateConnection, deactivateProvider, deleteAgent, deleteAlert, deleteAlertRule, deleteApiKey, deleteBackup, deleteBackupSchedule, deleteConnection, deleteCustomDomain, deleteDashboard, deleteDeploymentToken, deleteDnsProvider, deleteDomain, deleteEmailDomain, deleteEmailProvider, deleteEnvironment, deleteEnvironmentDomain, deleteEnvironmentVariable, deleteExternalImage, deleteFunnel, deleteGitProvider, deleteGlobalMcp, deleteGlobalSkill, deleteIpAccessControl, deleteMcp, deleteMonitor, deleteNotificationProvider, deleteOidcProvider, deleteOidcRoleMapping, deletePreferences, deleteProject, deleteProjectSecret, deleteProviderKey, deleteProviderSafely, deleteReleaseSourceFiles, deleteReleaseSourceMaps, deleteRoute, deleteS3Source, deleteScan, deleteSecret, deleteService, deleteSessionReplay, deleteSkill, deleteSourceMap, deleteStaticBundle, deleteTeam, deleteUser, deleteWebhook, deployFromImage, deployFromImageUpload, deployFromStatic, deployFromUploadedSource, deploymentMetricsGetLatest, deploymentMetricsGetRange, deploymentMetricsToggle, destroySandbox, detachScheduleService, detectPublicPresets, disableBackupSchedule, disableMfa, discoverWorkloads, domain, downloadGlobalSkillArchive, downloadObject, downloadSkillArchive, emailStatus, embeddings, enableBackupSchedule, enrichVisitor, exec, execDetached, executeDeploymentOperation, executeImport, extendTimeout, externalServiceEnablePgStatStatements, externalServiceMetricsByDatabase, externalServiceMetricsCreateAlertRule, externalServiceMetricsDeleteAlertRule, externalServiceMetricsGetAlertRules, externalServiceMetricsGetLatest, externalServiceMetricsGetRange, externalServiceMetricsStatus, externalServiceMetricsToggle, externalServiceMetricsUpdateAlertRule, externalServiceResetPgStatStatements, finalizeOrder, finalizeProjectRelease, findConversation, generateJoinToken, generatePresetDockerfile, getAccessInfo, getActiveVisitors, getActivityGraph, getAdminGate, getAgent, getAggregatedBuckets, getAiAgentBreakdown, getAiAgentPages, getAiAgentTimeline, getAiPageBreakdown, getAiStatusBreakdown, getAlert, getAlertRule, getAllRepositoriesByName, getAnalyticsActiveVisitors, getAnalyticsEventsCount, getAnalyticsSessionEvents, getAnalyticsVisitorSessions, getApiKey, getApiKeyPermissions, getAuditLog, getBackup, getBackupSchedule, getBranchesByRepositoryId, getBucketedIncidents, getBucketedStatus, getChallengeToken, getChatReadiness, getCliStatus, getClusterHealth, getClusterMember, getCmd, getContainerDetail, getContainerEnvironmentVariable, getContainerInfo, getContainerLogs, getContainerLogsById, getContainerMetrics, getConversation, getConversationDetail, getConversations, getCronById, getCronExecutions, getCrossProjectTraceSiblings, getCurrentMonitorStatus, getCurrentUser, getCustomDomain, getDashboard, getDashboardProjectsAnalytics, getDelivery, getDeployment, getDeploymentContainerLogContent, getDeploymentJobLogs, getDeploymentJobs, getDeploymentOperations, getDeploymentOperationStatus, getDeploymentToken, getDiskStatus, getDnsChanges, getDnsProvider, getDomain, getDomainByHost, getDomainById, getDomainByName, getDomainDnsRecords, getDomainOrder, getEmail, getEmailEvents, getEmailLinks, getEmailProvider, getEmailStats, getEmailTracking, getEmailTrackingStatus, getEntityInfo, getEnvironment, getEnvironmentCrons, getEnvironmentDomains, getEnvironments, getEnvironmentVariables, getEnvironmentVariableValue, getErrorDashboardStats, getErrorEvent, getErrorGroup, getErrorStats, getErrorTimeSeries, getEventDetail, getEventEntries, getEventsCount, getEventsTimeline, getEventTypeBreakdown, getEventVisitors, getExternalImage, getFile, getFlag, getFlagSnapshot, getFunnelMetrics, getGenaiTrace, getGeneralStats, getGitProvider, getGlobalEvents, getGlobalEventStats, getGlobalMcp, getGlobalSandboxStatus, getGlobalSkill, getGroupedPageMetrics, getHealth, getHourlyVisits, getHttpChallengeDebug, getImportStatus, getIncident, getIncidentUpdates, getIpAccessControl, getIpGeolocation, getJoinTokenStatus, getLastDeployment, getLatestScan, getLatestScansPerEnvironment, getLiveVisitorsList, getLogContext, getMcp, getMetricsOverTime, getMonitor, getNotificationProvider, getOnDemandCertStatus, getOrCreateDsn, getPageFlow, getPageHourlySessions, getPagePathDetail, getPagePaths, getPagePathsSparklines, getPagePathVisitors, getPendingAction, getPerformanceMetrics, getPgUpgrade, getPgUpgradeLogs, getPipelineStats, getPlatformInfo, getPostgresWalHealth, getPreferences, getPreviewGatewayLogs, getPreviewGatewaySettings, getPreviewGatewayStatus, getPricing, getPrivateIp, getProject, getProjectAlarmsSummary, getProjectBySlug, getProjectDeployments, getProjects, getProjectServiceEnvironmentVariables, getProjectSessionReplays, getProjectsHealth, getProjectsMonitorHealth, getProjectStatistics, getProjectTemplate, getPropertyBreakdown, getPropertyTimeline, getProviderConnections, getProviderMetadata, getProvidersMetadata, getProxyLogById, getProxyLogByRequestId, getProxyLogs, getPublicBranches, getPublicIp, getPublicRepository, getQuota, getRecentActivity, getRemoteExternalImage, getRepositoryBranches, getRepositoryById, getRepositoryByName, getRepositoryPresetByName, getRepositoryPresetLive, getRepositoryTags, getResolvedEnvironmentVariables, getResolvedEnvironmentVariableValue, getRestoreCapabilities, getRestoreRun, getRoute, getRun, getRunWithLogs, getS3Credentials, getS3Source, getSandbox, getSandboxStatus, getScan, getScanByDeployment, getScanVulnerabilities, getService, getServiceBySlug, getServiceEnvironmentVariable, getServiceEnvironmentVariables, getServiceHealthStatus, getServicePreviewEnvironmentVariableNames, getServicePreviewEnvironmentVariablesMasked, getServiceRuntime, getServiceStats, getServiceTypeParameters, getServiceTypes, getSessionDetails, getSessionEvents, getSessionLogs, getSessionReplay, getSessionReplayEvents, getSettings, getSkill, getSlowQueries, getStaticBundle, getStatusOverview, getTagsByRepositoryId, getTeam, getTimeBucketStats, getTodayStats, getTrace, getUnifiedTrace, getUniqueCounts, getUniqueEvents, getUpdateCapability, getUpdateStatus, getUptimeHistory, getUsageByProvider, getUsageRecent, getUsageSummary, getUsageTimeseries, getUsageTopModels, getVisitorByGuid, getVisitorById, getVisitorDetails, getVisitorFacets, getVisitorInfo, getVisitorJourney, getVisitors, getVisitorSessions, getVisitorStats, getWebhook, grantProjectAccess, handleGitProviderOauthCallback, hasAnalyticsEvents, hasErrorGroups, hasPerformanceMetrics, importExternalService, ingestLogs, ingestLogsByPath, ingestMetrics, ingestMetricsByPath, ingestSentryEnvelope, ingestSentryEvent, ingestTraces, ingestTracesByPath, initSessionReplay, inspectDropArchive, jobLogs, jobStatus, killJob, kvDel, kvDisable, kvEnable, kvExpire, kvGet, kvIncr, kvKeys, kvSet, kvStatus, kvTtl, kvUpdate, latestRunForSource, linkCustomDomainToCertificate, linkServiceToProject, listAgentRuns, listAgents, listAiProviders, listAlertRules, listAlerts, listAllConversations, listAllRuns, listApiKeys, listAuditLogs, listAvailableContainers, listBackupAlerts, listBackupChildren, listBackupSchedules, listBackupsForSchedule, listCommitsByRepositoryId, listConnections, listContainers, listContainersAtPath, listConversations, listCustomDomainsForProject, listDashboards, listDeliveries, listDeploymentContainerLogs, listDeploymentTokens, listDnsProviders, listDomains, listDsns, listEmailDomains, listEmailProviders, listEmails, listEnrollmentTokens, listEntities, listErrorEvents, listErrorGroups, listEvents, listEventTypes, listExternalImages, listExternalPlugins, listExternalServiceBackups, listFlags, listFunnels, listGitProviders, listGlobalMcps, listGlobalSkills, listIncidents, listInsights, listIpAccessControl, listJobs, listKnownAiAgents, listManagedDomains, listMcps, listMetricLabelKeys, listMetricLabelValues, listMetricNames, listModels, listMonitors, listNotificationProviders, listOidcProviders, listOidcProviderUsers, listOidcRoleMappings, listOnDemandCerts, listOrders, listPeers, listPendingActions, listPgUpgrades, listPresets, listProjectAccess, listProjectAlarms, listProjectScans, listProjectSecrets, listProjectServices, listProjectTemplates, listProjectTemplateTags, listProviderKeys, listProviderZones, listPublicProviders, listReleaseFiles, listReleases, listRemoteExternalImages, listRepositoriesByConnection, listRepositoriesByProvider, listRestoreRunsForService, listRootContainers, listRoutes, listS3Sources, listSandboxes, listScheduleRunJobs, listScheduleRuns, listScheduleServices, listSecrets, listServiceHealthStatuses, listServiceProjects, listServices, listServiceSchedules, listSkills, listSourceBackups, listSourceFiles, listSourceMaps, listSources, listStaticBundles, listSyncedRepositories, listTeamMembers, listTeamProjects, listTeams, listUsers, listWebhooks, login, logout, lookupDnsARecords, mintEnrollmentToken, mkdir, nodeHeartbeat, nodeMetricsGetRange, observabilityFullEvent, observabilityListEvents, oidcCallback, type Options, patchAdminGate, patchPreviewGatewaySettings, pauseDeployment, pauseSandbox, planRestore, postDnsAck, previewAlert, previewFunnelMetrics, previewHostnameMode, promoteClusterMember, promoteDeployment, provisionDomain, purgeProjectLogs, pushExternalImage, queryData, queryGenaiTraces, queryLogs, queryMetrics, queryTraces, queryTraceSummaries, readFile, reAnalyze, recordConsoleEvent, recordEventMetrics, recordFlagExposure, recordSpeedMetrics, refreshRouteTable, regenerateDsn, registerExternalImage, registerNode, reinstallGitlabWebhook, rejectPendingAction, reloadPlugins, removeClusterMember, removeManagedDomain, removeRole, removeTeamMember, renameConversation, renewDomain, requestPasswordReset, resetPassword, resizeSandbox, resolveAlarm, restartContainer, restartPreviewGateway, restartSandbox, restoreFlag, restoreUser, resumeDeployment, resumeSandbox, retryCluster, retryDelivery, retryPgUpgrade, retryRun, revealGlobalMcpConfig, revealMcpConfig, revealNotificationProviderConfig, revealServiceParameter, revenueCreateIntegration, revenueDeleteIntegration, revenueGlobalEvents, revenueImportInvoicesCsv, revenueImportSubscriptionsCsv, revenueListIntegrations, revenueListProviders, revenueMetricsCustomers, revenueMetricsGlobalMrr, revenueMetricsGlobalSummary, revenueMetricsMrr, revenueMetricsSummary, revenueRecentEvents, revenueRotateToken, revenueUpdateConfig, revenueUpdateSecret, revokeDsn, revokeEnrollmentToken, revokeJoinToken, revokeProjectAccess, rollbackPgUpgrade, rollbackToDeployment, rootfsGc, rootfsReport, rotateApiKey, rotateDeploymentToken, runBackupForSource, runConnectionHealthCheck, runExternalServiceBackup, runScheduleNow, sandboxCreatePreviewLink, saveAgentToken, saveAiProviderCredential, searchLogs, sendEmail, setDefaultS3Source, setFlagEnvironment, setPreviewPassword, setupDns, setupDnsChallenge, setupEmailTracking, setupMfa, sleepEnvironment, smokeTestAgent, sourceSandbox, startAnalysis, startContainer, startFix, startGitProviderOauth, startOidcLoginBySlug, startPgUpgrade, startRestore, startService, startUpdate, statPath, stopContainer, stopSandbox, stopService, streamContainerMetrics, streamEvents, streamRunEvents, syncRepositories, tailDeploymentJobLogs, tailLogs, teardownDeployment, teardownEnvironment, testNotificationProvider, testOidcProvider, testProvider, testProviderConnection, testProviderKeyById, testProviderKeyInline, testS3ConnectionPreview, testS3SourceConnection, trackClick, trackOpen, triggerAgent, triggerProjectPipeline, triggerScan, triggerServiceHealthCheck, triggerWeeklyDigest, unlinkServiceFromProject, updateAgent, updateAiProvider, updateAlert, updateAlertRule, updateApiKey, updateAutomaticDeploy, updateBackupSchedule, updateCloudflareProvider, updateConnectionToken, updateCustomDomain, updateDashboard, updateDeploymentToken, updateEmailProvider, updateEnvironmentSettings, updateEnvironmentSubdomain, updateEnvironmentVariable, updateErrorGroup, updateFlag, updateFunnel, updateGitProviderCredentials, updateGitSettings, updateGlobalMcp, updateGlobalSkill, updateIncidentStatus, updateIpAccessControl, updateManagedDomain, updateMcp, updateNotificationEmailProvider, updateNotificationProvider, updateOidcProvider, updatePreferences, updateProject, updateProjectDeploymentConfig, updateProjectSecret, updateProjectSettings, updateProvider, updateProviderKey, updateRoute, updateS3Source, updateSelf, updateService, updateServiceResources, updateSessionDuration, updateSettings, updateSkill, updateSlackProvider, updateSpeedMetrics, updateTeam, updateTeamMemberRole, updateUser, updateWebhook, updateWebhookProvider, upgradePreviewGateway, upgradeService, uploadGlobalSkill, uploadReleaseFile, uploadSkill, uploadSourceFile, uploadSourceMap, uploadStaticBundle, upsertSecret, validateConnection, validateEmail, verifyAndEnableMfa, verifyDomain, verifyEmail, verifyManagedDomain, verifyMfaChallenge, verifyStepUp, wakeEnvironment, webhookTrigger, workflowDryRun, writeFile, writeFiles } from './sdk.gen'; -export type { AcknowledgeAlarmData, AcknowledgeAlarmErrors, AcknowledgeAlarmResponses, AcmeOrderResponse, ActivateAiProviderData, ActivateAiProviderErrors, ActivateAiProviderResponse, ActivateAiProviderResponses, ActivateApiKeyData, ActivateApiKeyErrors, ActivateApiKeyResponse, ActivateApiKeyResponses, ActivateConnectionData, ActivateConnectionErrors, ActivateConnectionResponses, ActivateProviderData, ActivateProviderErrors, ActivateProviderResponse, ActivateProviderResponses, ActiveVisitor, ActiveVisitorsQuery, ActiveVisitorsResponse, ActivityDay, ActivityEvent, ActivityGraphQuery, ActivityGraphResponse, AddClusterMemberData, AddClusterMemberErrors, AddClusterMemberRequest, AddClusterMemberResponse, AddClusterMemberResponses, AddContextData, AddContextErrors, AddContextRequest, AddContextResponses, AddEnvironmentDomainData, AddEnvironmentDomainErrors, AddEnvironmentDomainRequest, AddEnvironmentDomainResponse, AddEnvironmentDomainResponses, AddEventsData, AddEventsError, AddEventsErrors, AddEventsRequest, AddEventsResponse, AddEventsResponse2, AddEventsResponses, AddManagedDomainApiRequest, AddManagedDomainData, AddManagedDomainErrors, AddManagedDomainResponse, AddManagedDomainResponses, AddSessionReplayEventsData, AddSessionReplayEventsError, AddSessionReplayEventsErrors, AddSessionReplayEventsResponse, AddSessionReplayEventsResponses, AddTeamMemberData, AddTeamMemberErrors, AddTeamMemberResponse, AddTeamMemberResponses, AdminDrainNodeData, AdminDrainNodeErrors, AdminDrainNodeResponse, AdminDrainNodeResponses, AdminDrainStatusData, AdminDrainStatusErrors, AdminDrainStatusResponse, AdminDrainStatusResponses, AdminGateResponse, AdminGateSource, AdminGetNodeData, AdminGetNodeErrors, AdminGetNodeResponse, AdminGetNodeResponses, AdminListNodeContainersData, AdminListNodeContainersErrors, AdminListNodeContainersResponse, AdminListNodeContainersResponses, AdminListNodesData, AdminListNodesErrors, AdminListNodesResponse, AdminListNodesResponses, AdminRemoveNodeData, AdminRemoveNodeErrors, AdminRemoveNodeResponse, AdminRemoveNodeResponses, AdminUndrainNodeData, AdminUndrainNodeErrors, AdminUndrainNodeResponse, AdminUndrainNodeResponses, AgentConfigResponse, AgentRunLogResponse, AgentRunResponse, AgentRunWithLogsResponse, AgentSandboxSettings, AgentSandboxSettingsMasked, AggregatedBucketItem, AggregatedBucketsQuery, AggregatedBucketsResponse, AggregationLevel, AggregationTemporality, AiAgentBreakdownResponse, AiAgentBreakdownRow, AiAgentDescriptor, AiAgentPageRow, AiAgentPagesResponse, AiAgentTimelineResponse, AiAgentTimelineRow, AiChatLimitsSettings, AiConfigSettings, AiPageBreakdownResponse, AiPageBreakdownRow, AiStatusBreakdownResponse, AiStatusBreakdownRow, AlarmListResponse, AlarmResponse, AlarmSummaryResponse, AlertRuleResponse, AllocEntry, AnalyticsSessionEventsResponse, AnnotatedSpan, AnomalyAlgorithm, AnomalyParams, AnomalyPreviewPointResponse, AnomalyPreviewRequest, AnomalyPreviewResponse, ApiKeyListResponse, ApiKeyResponse, ApplyHostnameModeData, ApplyHostnameModeErrors, ApplyHostnameModeRequest, ApplyHostnameModeResponse, ApplyHostnameModeResponses, AppSettings, AppSettingsResponse, ArchiveConversationData, ArchiveConversationErrors, ArchiveConversationResponse, ArchiveConversationResponses, ArchiveFlagData, ArchiveFlagErrors, ArchiveFlagResponse, ArchiveFlagResponse2, ArchiveFlagResponses, ArchiveMode, AssignRoleData, AssignRoleErrors, AssignRoleRequest, AssignRoleResponses, AttachScheduleServicesData, AttachScheduleServicesError, AttachScheduleServicesErrors, AttachScheduleServicesRequest, AttachScheduleServicesResponse, AttachScheduleServicesResponse2, AttachScheduleServicesResponses, AuditLogIpInfo, AuditLogResponse, AuditLogUserInfo, AuthFlavorDto, AuthResponse, AuthStatusResponse, AuthTokenResponse, AutofixerRunResponse, AutofixerRunWithLogsResponse, AutofixRunConfig, AutoWatchParams, AvailableContainerInfo, AvailablePermissions, BackupAlertListResponse, BackupAlertResponse, BackupResponse, BackupScheduleResponse, BitbucketAuthInput, BlobCopyData, BlobCopyError, BlobCopyErrors, BlobCopyResponse, BlobCopyResponses, BlobDeleteData, BlobDeleteError, BlobDeleteErrors, BlobDeleteResponse, BlobDeleteResponses, BlobDisableData, BlobDisableErrors, BlobDisableResponse, BlobDisableResponses, BlobDownloadData, BlobDownloadError, BlobDownloadErrors, BlobDownloadResponses, BlobEnableData, BlobEnableErrors, BlobEnableResponse, BlobEnableResponses, BlobHeadData, BlobHeadError, BlobHeadErrors, BlobHeadResponses, BlobListData, BlobListError, BlobListErrors, BlobListResponse, BlobListResponses, BlobPutData, BlobPutError, BlobPutErrors, BlobPutResponse, BlobPutResponses, BlobResponse, BlobStatusData, BlobStatusErrors, BlobStatusResponse, BlobStatusResponse2, BlobStatusResponses, BlobUpdateData, BlobUpdateErrors, BlobUpdateResponse, BlobUpdateResponses, BranchInfo, BranchListResponse, BrowserCount, BrowsersQuery, BuildConfiguration, BuildLimitsSettings, CancelBackupData, CancelBackupError, CancelBackupErrors, CancelBackupResponse, CancelBackupResponse2, CancelBackupResponses, CancelData, CancelDeploymentData, CancelDeploymentErrors, CancelDeploymentResponse, CancelDeploymentResponses, CancelDomainOrderData, CancelDomainOrderErrors, CancelDomainOrderResponse, CancelDomainOrderResponses, CancelErrors, CancelPgUpgradeData, CancelPgUpgradeErrors, CancelPgUpgradeResponse, CancelPgUpgradeResponses, CancelResponses, CancelRunData, CancelRunErrors, CancelRunResponse, CancelRunResponses, CancelScheduleRunData, CancelScheduleRunError, CancelScheduleRunErrors, CancelScheduleRunResponse, CancelScheduleRunResponses, CertStatusResponse, ChallengeConfig, ChallengeError, ChallengeValidationStatus, ChangePasswordRequest, ChangePasswordSelfData, ChangePasswordSelfErrors, ChangePasswordSelfResponse, ChangePasswordSelfResponses, ChangeProjectSourceData, ChangeProjectSourceErrors, ChangeProjectSourceRequest, ChangeProjectSourceResponse, ChangeProjectSourceResponses, ChangeRequiredPasswordData, ChangeRequiredPasswordErrors, ChangeRequiredPasswordResponse, ChangeRequiredPasswordResponses, ChatCompletionChoice, ChatCompletionRequest, ChatCompletionResponse, ChatCompletionsData, ChatCompletionsError, ChatCompletionsErrors, ChatCompletionsResponse, ChatCompletionsResponses, ChatMessage, ChatReadinessResponse, CheckAnalyticsHasEventsData, CheckAnalyticsHasEventsErrors, CheckAnalyticsHasEventsResponse, CheckAnalyticsHasEventsResponses, CheckCommitExistsData, CheckCommitExistsErrors, CheckCommitExistsResponse, CheckCommitExistsResponses, CheckDomainStatusData, CheckDomainStatusErrors, CheckDomainStatusResponse, CheckDomainStatusResponses, CheckExplorerSupportData, CheckExplorerSupportErrors, CheckExplorerSupportResponse, CheckExplorerSupportResponses, CheckIpBlockedData, CheckIpBlockedError, CheckIpBlockedErrors, CheckIpBlockedResponses, CheckProviderDeletionSafetyData, CheckProviderDeletionSafetyErrors, CheckProviderDeletionSafetyResponse, CheckProviderDeletionSafetyResponses, ChildBackupEntryResponse, ChildBackupListResponse, ChunkUploadOptionsData, ChunkUploadOptionsResponse, ChunkUploadOptionsResponses, CleanupExpiredBackupsData, CleanupExpiredBackupsError, CleanupExpiredBackupsErrors, CleanupExpiredBackupsRequest, CleanupExpiredBackupsResponse, CleanupExpiredBackupsResponses, ClearPreviewPasswordData, ClearPreviewPasswordErrors, ClearPreviewPasswordResponse, ClearPreviewPasswordResponses, CliDeviceApproveData, CliDeviceApproveErrors, CliDeviceApproveRequest, CliDeviceApproveResponse, CliDeviceApproveResponse2, CliDeviceApproveResponses, CliDeviceDenyData, CliDeviceDenyErrors, CliDeviceDenyResponse, CliDeviceDenyResponses, CliDeviceLookupData, CliDeviceLookupErrors, CliDeviceLookupResponse, CliDeviceLookupResponse2, CliDeviceLookupResponses, CliDevicePollData, CliDevicePollErrors, CliDevicePollRequest, CliDevicePollResponse, CliDevicePollResponse2, CliDevicePollResponses, CliDeviceStartData, CliDeviceStartErrors, CliDeviceStartRequest, CliDeviceStartResponse, CliDeviceStartResponse2, CliDeviceStartResponses, ClientOptions, CliLoginRequest, CliLogoutData, CliLogoutErrors, CliLogoutResponse, CliLogoutResponses, CloudflareConfig, CloudProvider, ClusterCapacity, ClusterDnsSettings, ClusterHealthReportResponse, ClusterMemberHealthResponse, ClusterMemberRequest, CmdBody, CmdData, CmdErrors, CmdInner, CmdKillBody, CmdKillData, CmdKillErrors, CmdKillResponse, CmdKillResponses, CmdLogsData, CmdLogsErrors, CmdLogsResponses, CmdResponse, CmdResponse2, CmdResponses, CommitExistsResponse, CommitInfo, CommitListResponse, Comparator, ComposePublicPort, ConfirmPendingActionData, ConfirmPendingActionErrors, ConfirmPendingActionResponse, ConfirmPendingActionResponses, ConnectionListQuery, ConnectionListResponse, ConnectionResponse, ConnectionTestResult, ConsoleEventPayload, ContainerActionResponse, ContainerDetailResponse, ContainerEnvironmentVariableValueResponse, ContainerInfoResponse, ContainerInventoryItem, ContainerListResponse, ContainerLogSettings, ContainerLogsQuery, ContainerMetricHistoryPoint, ContainerMetricsGetHistoryData, ContainerMetricsGetHistoryErrors, ContainerMetricsGetHistoryResponse, ContainerMetricsGetHistoryResponses, ContainerMetricsHistoryQuery, ContainerMetricsResponse, ContainerResponse, ContainerRuntimeInfo, ContainerStatsSample, ContentPart, ContextLine, ContextLogsRequest, ContextLogsResponse, ConversationDetailResponse, ConversationResponse, ConversationsQueryParams, ConversationSummary, CopyBlobRequest, CostAnalysis, CreateAgentData, CreateAgentErrors, CreateAgentResponse, CreateAgentResponses, CreateAlertData, CreateAlertError, CreateAlertErrors, CreateAlertResponse, CreateAlertResponses, CreateAlertRuleData, CreateAlertRuleErrors, CreateAlertRuleRequest, CreateAlertRuleResponse, CreateAlertRuleResponses, CreateApiKeyData, CreateApiKeyErrors, CreateApiKeyRequest, CreateApiKeyResponse, CreateApiKeyResponse2, CreateApiKeyResponses, CreateBackupScheduleData, CreateBackupScheduleError, CreateBackupScheduleErrors, CreateBackupScheduleRequest, CreateBackupScheduleResponse, CreateBackupScheduleResponses, CreateBitbucketProviderData, CreateBitbucketProviderErrors, CreateBitbucketProviderResponse, CreateBitbucketProviderResponses, CreateBitbucketRequest, CreateCloudflareProviderData, CreateCloudflareProviderErrors, CreateCloudflareProviderRequest, CreateCloudflareProviderResponse, CreateCloudflareProviderResponses, CreateConversationData, CreateConversationErrors, CreateConversationRequest, CreateConversationResponse, CreateConversationResponses, CreateCustomDomainData, CreateCustomDomainErrors, CreateCustomDomainResponse, CreateCustomDomainResponses, CreateDashboardData, CreateDashboardError, CreateDashboardErrors, CreateDashboardRequest, CreateDashboardResponse, CreateDashboardResponses, CreateDeploymentTokenData, CreateDeploymentTokenErrors, CreateDeploymentTokenRequest, CreateDeploymentTokenResponse, CreateDeploymentTokenResponse2, CreateDeploymentTokenResponses, CreateDnsProviderData, CreateDnsProviderErrors, CreateDnsProviderRequest, CreateDnsProviderResponse, CreateDnsProviderResponses, CreateDomainData, CreateDomainErrors, CreateDomainRequest, CreateDomainResponse, CreateDomainResponses, CreatedResource, CreateDsnData, CreateDsnErrors, CreateDsnRequest, CreateDsnResponse, CreateDsnResponses, CreateEmailDomainData, CreateEmailDomainErrors, CreateEmailDomainRequest, CreateEmailDomainResponse, CreateEmailDomainResponses, CreateEmailProviderData, CreateEmailProviderErrors, CreateEmailProviderRequest, CreateEmailProviderResponse, CreateEmailProviderResponses, CreateEnvironmentData, CreateEnvironmentErrors, CreateEnvironmentRequest, CreateEnvironmentResponse, CreateEnvironmentResponses, CreateEnvironmentVariableData, CreateEnvironmentVariableErrors, CreateEnvironmentVariableRequest, CreateEnvironmentVariableResponse, CreateEnvironmentVariableResponses, CreateExternalServiceRequest, CreateFlagData, CreateFlagErrors, CreateFlagRequest, CreateFlagResponse, CreateFlagResponses, CreateFunnelData, CreateFunnelErrors, CreateFunnelRequest, CreateFunnelResponse, CreateFunnelResponse2, CreateFunnelResponses, CreateFunnelStep, CreateGenericProviderData, CreateGenericProviderErrors, CreateGenericProviderResponse, CreateGenericProviderResponses, CreateGenericRequest, CreateGiteaPatProviderData, CreateGiteaPatProviderErrors, CreateGiteaPatProviderResponse, CreateGiteaPatProviderResponses, CreateGiteaPatRequest, CreateGithubPatProviderData, CreateGithubPatProviderErrors, CreateGithubPatProviderResponse, CreateGithubPatProviderResponses, CreateGitHubPatRequest, CreateGitlabOauthProviderData, CreateGitlabOauthProviderErrors, CreateGitlabOauthProviderResponse, CreateGitlabOauthProviderResponses, CreateGitLabOAuthRequest, CreateGitlabPatProviderData, CreateGitlabPatProviderErrors, CreateGitlabPatProviderResponse, CreateGitlabPatProviderResponses, CreateGitLabPatRequest, CreateGitProviderData, CreateGitProviderErrors, CreateGitProviderResponse, CreateGitProviderResponses, CreateGlobalMcpData, CreateGlobalMcpErrors, CreateGlobalMcpResponse, CreateGlobalMcpResponses, CreateGlobalSkillData, CreateGlobalSkillErrors, CreateGlobalSkillResponse, CreateGlobalSkillResponses, CreateIncidentData, CreateIncidentErrors, CreateIncidentRequest, CreateIncidentResponse, CreateIncidentResponses, CreateIntegrationBody, CreateIpAccessControlData, CreateIpAccessControlError, CreateIpAccessControlErrors, CreateIpAccessControlRequest, CreateIpAccessControlResponse, CreateIpAccessControlResponses, CreateMcpData, CreateMcpErrors, CreateMcpRequest, CreateMcpResponse, CreateMcpResponses, CreateMetricAlertRequest, CreateMonitorData, CreateMonitorErrors, CreateMonitorRequest, CreateMonitorResponse, CreateMonitorResponses, CreateNotificationEmailProviderData, CreateNotificationEmailProviderErrors, CreateNotificationEmailProviderRequest, CreateNotificationEmailProviderResponse, CreateNotificationEmailProviderResponses, CreateNotificationProviderData, CreateNotificationProviderErrors, CreateNotificationProviderResponse, CreateNotificationProviderResponses, CreateOidcProviderData, CreateOidcProviderErrors, CreateOidcProviderRequest, CreateOidcProviderResponse, CreateOidcProviderResponses, CreateOidcRoleMappingData, CreateOidcRoleMappingRequest, CreateOidcRoleMappingResponse, CreateOidcRoleMappingResponses, CreateOrRecreateOrderData, CreateOrRecreateOrderErrors, CreateOrRecreateOrderResponse, CreateOrRecreateOrderResponses, CreatePlanData, CreatePlanErrors, CreatePlanRequest, CreatePlanResponse, CreatePlanResponse2, CreatePlanResponses, CreatePrData, CreatePrErrors, CreateProjectAccessRequest, CreateProjectData, CreateProjectErrors, CreateProjectFromTemplateData, CreateProjectFromTemplateErrors, CreateProjectFromTemplateRequest, CreateProjectFromTemplateResponse, CreateProjectFromTemplateResponse2, CreateProjectFromTemplateResponses, CreateProjectReleaseData, CreateProjectReleaseErrors, CreateProjectReleaseResponse, CreateProjectReleaseResponses, CreateProjectRequest, CreateProjectResponse, CreateProjectResponses, CreateProjectSecretData, CreateProjectSecretErrors, CreateProjectSecretRequest, CreateProjectSecretResponse, CreateProjectSecretResponses, CreateProviderKeyData, CreateProviderKeyError, CreateProviderKeyErrors, CreateProviderKeyRequest, CreateProviderKeyResponse, CreateProviderKeyResponses, CreateProviderRequest, CreatePrResponse, CreatePrResponse2, CreatePrResponses, CreateReleaseData, CreateReleaseErrors, CreateReleaseResponse, CreateReleaseResponses, CreateRouteData, CreateRouteErrors, CreateRouteRequest, CreateRouteResponse, CreateRouteResponses, CreateS3SourceData, CreateS3SourceError, CreateS3SourceErrors, CreateS3SourceRequest, CreateS3SourceResponse, CreateS3SourceResponses, CreateSandboxBody, CreateSandboxData, CreateSandboxErrors, CreateSandboxResponse, CreateSandboxResponses, CreateServiceData, CreateServiceErrors, CreateServiceResponse, CreateServiceResponses, CreateSkillData, CreateSkillErrors, CreateSkillRequest, CreateSkillResponse, CreateSkillResponses, CreateSlackProviderData, CreateSlackProviderErrors, CreateSlackProviderRequest, CreateSlackProviderResponse, CreateSlackProviderResponses, CreateTeamData, CreateTeamErrors, CreateTeamMemberRequest, CreateTeamRequest, CreateTeamResponse, CreateTeamResponses, CreateUserData, CreateUserErrors, CreateUserRequest, CreateUserResponse, CreateUserResponses, CreateWebhookData, CreateWebhookErrors, CreateWebhookProviderData, CreateWebhookProviderErrors, CreateWebhookProviderRequest, CreateWebhookProviderResponse, CreateWebhookProviderResponses, CreateWebhookRequestBody, CreateWebhookResponse, CreateWebhookResponses, CronExecutionInfo, CronInfo, CrossProjectSiblingRef, CrossProjectTraceResponse, CurrentStatusResponse, CustomDomainRequest, CustomDomainResponse, CustomerMovementResponse, DashboardLayout, DashboardProjectsAnalyticsQuery, DashboardProjectsAnalyticsResponse, DashboardSection, DashboardTile, DatabaseMetricsResponse, DatabaseMetricsRow, DataImplication, DataImplicationSeverity, DeactivateApiKeyData, DeactivateApiKeyErrors, DeactivateApiKeyResponse, DeactivateApiKeyResponses, DeactivateConnectionData, DeactivateConnectionErrors, DeactivateConnectionResponses, DeactivateProviderData, DeactivateProviderErrors, DeactivateProviderResponses, DeleteAgentData, DeleteAgentErrors, DeleteAgentResponse, DeleteAgentResponses, DeleteAlertData, DeleteAlertError, DeleteAlertErrors, DeleteAlertResponse, DeleteAlertResponses, DeleteAlertRuleData, DeleteAlertRuleErrors, DeleteAlertRuleResponse, DeleteAlertRuleResponses, DeleteApiKeyData, DeleteApiKeyErrors, DeleteApiKeyResponse, DeleteApiKeyResponses, DeleteBackupData, DeleteBackupError, DeleteBackupErrors, DeleteBackupResponse, DeleteBackupResponses, DeleteBackupScheduleData, DeleteBackupScheduleError, DeleteBackupScheduleErrors, DeleteBackupScheduleResponse, DeleteBackupScheduleResponses, DeleteBlobRequest, DeleteBlobResponse, DeleteConnectionData, DeleteConnectionErrors, DeleteConnectionResponse, DeleteConnectionResponses, DeleteCustomDomainData, DeleteCustomDomainErrors, DeleteCustomDomainResponse, DeleteCustomDomainResponses, DeleteDashboardData, DeleteDashboardError, DeleteDashboardErrors, DeleteDashboardResponse, DeleteDashboardResponses, DeleteDeploymentTokenData, DeleteDeploymentTokenErrors, DeleteDeploymentTokenResponse, DeleteDeploymentTokenResponses, DeleteDnsProviderData, DeleteDnsProviderErrors, DeleteDnsProviderResponse, DeleteDnsProviderResponses, DeleteDomainData, DeleteDomainErrors, DeleteDomainResponse, DeleteDomainResponses, DeleteEmailDomainData, DeleteEmailDomainErrors, DeleteEmailDomainResponse, DeleteEmailDomainResponses, DeleteEmailProviderData, DeleteEmailProviderErrors, DeleteEmailProviderResponse, DeleteEmailProviderResponses, DeleteEnvironmentData, DeleteEnvironmentDomainData, DeleteEnvironmentDomainErrors, DeleteEnvironmentDomainResponse, DeleteEnvironmentDomainResponses, DeleteEnvironmentErrors, DeleteEnvironmentResponse, DeleteEnvironmentResponses, DeleteEnvironmentVariableData, DeleteEnvironmentVariableErrors, DeleteEnvironmentVariableResponse, DeleteEnvironmentVariableResponses, DeleteExternalImageData, DeleteExternalImageErrors, DeleteExternalImageResponse, DeleteExternalImageResponses, DeleteFunnelData, DeleteFunnelErrors, DeleteFunnelResponses, DeleteGitProviderData, DeleteGitProviderErrors, DeleteGitProviderResponse, DeleteGitProviderResponses, DeleteGlobalMcpData, DeleteGlobalMcpErrors, DeleteGlobalMcpResponse, DeleteGlobalMcpResponses, DeleteGlobalSkillData, DeleteGlobalSkillErrors, DeleteGlobalSkillResponse, DeleteGlobalSkillResponses, DeleteIpAccessControlData, DeleteIpAccessControlError, DeleteIpAccessControlErrors, DeleteIpAccessControlResponse, DeleteIpAccessControlResponses, DeleteMcpData, DeleteMcpErrors, DeleteMcpResponse, DeleteMcpResponses, DeleteMonitorData, DeleteMonitorErrors, DeleteMonitorResponse, DeleteMonitorResponses, DeleteNotificationProviderData, DeleteNotificationProviderErrors, DeleteNotificationProviderResponse, DeleteNotificationProviderResponses, DeleteOidcProviderData, DeleteOidcProviderResponse, DeleteOidcProviderResponses, DeleteOidcRoleMappingData, DeleteOidcRoleMappingResponse, DeleteOidcRoleMappingResponses, DeletePreferencesData, DeletePreferencesErrors, DeletePreferencesResponse, DeletePreferencesResponses, DeleteProjectData, DeleteProjectErrors, DeleteProjectResponse, DeleteProjectResponses, DeleteProjectSecretData, DeleteProjectSecretErrors, DeleteProjectSecretResponse, DeleteProjectSecretResponses, DeleteProviderKeyData, DeleteProviderKeyError, DeleteProviderKeyErrors, DeleteProviderKeyResponse, DeleteProviderKeyResponses, DeleteProviderSafelyData, DeleteProviderSafelyErrors, DeleteProviderSafelyResponse, DeleteProviderSafelyResponses, DeleteReleaseSourceFilesData, DeleteReleaseSourceFilesErrors, DeleteReleaseSourceFilesResponse, DeleteReleaseSourceFilesResponses, DeleteReleaseSourceMapsData, DeleteReleaseSourceMapsErrors, DeleteReleaseSourceMapsResponse, DeleteReleaseSourceMapsResponses, DeleteResponse, DeleteRouteData, DeleteRouteErrors, DeleteRouteResponse, DeleteRouteResponses, DeleteS3SourceData, DeleteS3SourceError, DeleteS3SourceErrors, DeleteS3SourceResponse, DeleteS3SourceResponses, DeleteScanData, DeleteScanError, DeleteScanErrors, DeleteScanResponse, DeleteScanResponses, DeleteSecretData, DeleteSecretErrors, DeleteSecretResponse, DeleteSecretResponses, DeleteServiceData, DeleteServiceErrors, DeleteServiceResponse, DeleteServiceResponses, DeleteSessionReplayData, DeleteSessionReplayError, DeleteSessionReplayErrors, DeleteSessionReplayResponses, DeleteSkillData, DeleteSkillErrors, DeleteSkillResponse, DeleteSkillResponses, DeleteSourceMapData, DeleteSourceMapErrors, DeleteSourceMapResponse, DeleteSourceMapResponses, DeleteStaticBundleData, DeleteStaticBundleErrors, DeleteStaticBundleResponse, DeleteStaticBundleResponses, DeleteTeamData, DeleteTeamErrors, DeleteTeamResponse, DeleteTeamResponses, DeleteUserData, DeleteUserErrors, DeleteUserResponse, DeleteUserResponses, DeleteWebhookData, DeleteWebhookErrors, DeleteWebhookResponse, DeleteWebhookResponses, DelRequest, DelResponse, DeployFromImageData, DeployFromImageErrors, DeployFromImageRequest, DeployFromImageResponse, DeployFromImageResponses, DeployFromImageUploadData, DeployFromImageUploadErrors, DeployFromImageUploadQuery, DeployFromImageUploadResponse, DeployFromImageUploadResponses, DeployFromStaticData, DeployFromStaticErrors, DeployFromStaticRequest, DeployFromStaticResponse, DeployFromStaticResponses, DeployFromUploadedSourceData, DeployFromUploadedSourceErrors, DeployFromUploadedSourceResponse, DeployFromUploadedSourceResponses, DeploymentConfig, DeploymentConfigSnapshot, DeploymentConfiguration, DeploymentContainerLogContentResponse, DeploymentContainerLogResponse, DeploymentContainerLogsListResponse, DeploymentEnvironmentResponse, DeploymentJobResponse, DeploymentJobsResponse, DeploymentListResponse, DeploymentMetadata, DeploymentMetricsGetLatestData, DeploymentMetricsGetLatestErrors, DeploymentMetricsGetLatestResponse, DeploymentMetricsGetLatestResponses, DeploymentMetricsGetRangeData, DeploymentMetricsGetRangeErrors, DeploymentMetricsGetRangeResponse, DeploymentMetricsGetRangeResponses, DeploymentMetricsToggleData, DeploymentMetricsToggleErrors, DeploymentMetricsToggleResponses, DeploymentResponse, DeploymentStateResponse, DeploymentStrategy, DeploymentTokenListResponse, DeploymentTokenResponse, DestroySandboxData, DestroySandboxErrors, DestroySandboxResponse, DestroySandboxResponses, DetachScheduleServiceData, DetachScheduleServiceError, DetachScheduleServiceErrors, DetachScheduleServiceResponse, DetachScheduleServiceResponses, DetectionConfig, DetectPublicPresetsData, DetectPublicPresetsErrors, DetectPublicPresetsResponse, DetectPublicPresetsResponses, DeviceCount, DigestSections, Direction, DisableBackupScheduleData, DisableBackupScheduleErrors, DisableBackupScheduleResponse, DisableBackupScheduleResponses, DisableBlobResponse, DisableKvResponse, DisableMfaData, DisableMfaErrors, DisableMfaRequest, DisableMfaResponse, DisableMfaResponses, DiscoverRequest, DiscoverResponse, DiscoverWorkloadsData, DiscoverWorkloadsErrors, DiscoverWorkloadsResponse, DiscoverWorkloadsResponses, DiskInfo, DiskSpaceAlert, DiskSpaceAlertSettings, DiskSpaceCheckResult, DnsAckRequest, DnsAckResponse, DnsChallengeRecordResult, DnsChangesResponse, DnsCompletionResponse, DnsLookupError, DnsLookupRequest, DnsLookupResponse, DnsProviderCredentials, DnsProviderResponse, DnsProviderSettings, DnsProviderSettingsMasked, DnsProviderType, DnsRecord, DnsRecordChange, DnsRecordContent, DnsRecordResponse, DnsRecordSetupResult, DnsRecordStatusResponse, DnsZone, DockerComposePresetConfig, DockerfilePresetConfig, DockerfileVariant, DockerRegistrySettings, DockerRegistrySettingsMasked, DomainAction, DomainChallengeResponse, DomainData, DomainEnvironmentResponse, DomainError, DomainErrors, DomainPlan, DomainResponse, DomainResponse2, DomainResponses, DownloadGlobalSkillArchiveData, DownloadGlobalSkillArchiveErrors, DownloadGlobalSkillArchiveResponse, DownloadGlobalSkillArchiveResponses, DownloadObjectData, DownloadObjectErrors, DownloadObjectResponse, DownloadObjectResponses, DownloadSkillArchiveData, DownloadSkillArchiveErrors, DownloadSkillArchiveResponse, DownloadSkillArchiveResponses, DrainNodeResponse, DrainStatusResponse, DropArchiveUpload, DropInspectionResponse, DropOffPoint, DropPresetCandidate, EmailConfig, EmailDomainResponse, EmailDomainWithDnsResponse, EmailProviderResponse, EmailProviderTypeRoute, EmailRequest, EmailResponse, EmailStatsResponse, EmailStatusData, EmailStatusErrors, EmailStatusResponse, EmailStatusResponse2, EmailStatusResponses, EmailTrackingResponse, EmailTrackingSetupResponse, EmailTrackingStatusResponse, EmbeddingData, EmbeddingInput, EmbeddingRequest, EmbeddingResponse, EmbeddingsData, EmbeddingsError, EmbeddingsErrors, EmbeddingsResponse, EmbeddingsResponses, EmbeddingUsage, EnableBackupScheduleData, EnableBackupScheduleErrors, EnableBackupScheduleResponse, EnableBackupScheduleResponses, EnableBlobRequest, EnableBlobResponse, EnableKvRequest, EnableKvResponse, EnablePgStatStatementsResponse, EndpointDto, EnqueuedJob, EnrichVisitorData, EnrichVisitorErrors, EnrichVisitorRequest, EnrichVisitorResponse, EnrichVisitorResponse2, EnrichVisitorResponses, EnrollmentTokenInfo, EnrollmentTokenListResponse, EntityInfoResponse, EntityResponse, EnvironmentConfiguration, EnvironmentDomainResponse, EnvironmentInfo, EnvironmentResponse, EnvironmentVariable, EnvironmentVariableInfo, EnvironmentVariableResponse, EnvironmentVariableValueResponse, EnvVarInput, EnvVarIntegrationInfo, EnvVarResponse, EnvVarTemplateResponse, ErrorDashboardStatsQuery, ErrorDashboardStatsResponse, ErrorEventResponse, ErrorGroupResponse, ErrorGroupStatsResponse, ErrorResponse, ErrorRow, ErrorTimeSeriesDataResponse, ErrorTimeSeriesQuery, EventActivityBucket, EventBreakdown, EventBrowserStats, EventCount, EventCountryStats, EventDetailQuery, EventDetailResponse, EventEntriesQuery, EventEntriesResponse, EventEntryInfo, EventKind, EventMetricsPayload, EventReferrerStats, EventsCountQuery, EventsResponse, EventTimeline, EventTimelineQuery, EventType, EventTypeBreakdown, EventTypeBreakdownQuery, EventTypeResponse, EventTypesResponse, EventVisitorInfo, EventVisitorsQuery, EventVisitorsResponse, ExecBody, ExecData, ExecDetachedData, ExecDetachedErrors, ExecDetachedResponse, ExecDetachedResponse2, ExecDetachedResponses, ExecErrors, ExecResponse, ExecResponse2, ExecResponses, ExecuteDeploymentOperationData, ExecuteDeploymentOperationErrors, ExecuteDeploymentOperationResponse, ExecuteDeploymentOperationResponses, ExecuteImportData, ExecuteImportErrors, ExecuteImportRequest, ExecuteImportResponse, ExecuteImportResponse2, ExecuteImportResponses, ExecuteOperationRequest, ExpireRequest, ExpireResponse, ExplorerSupportResponse, ExtendTimeoutBody, ExtendTimeoutData, ExtendTimeoutErrors, ExtendTimeoutResponse, ExtendTimeoutResponses, ExternalImageResponse, ExternalServiceBackupResponse, ExternalServiceDetails, ExternalServiceEnablePgStatStatementsData, ExternalServiceEnablePgStatStatementsErrors, ExternalServiceEnablePgStatStatementsResponse, ExternalServiceEnablePgStatStatementsResponses, ExternalServiceInfo, ExternalServiceMetricsByDatabaseData, ExternalServiceMetricsByDatabaseErrors, ExternalServiceMetricsByDatabaseResponse, ExternalServiceMetricsByDatabaseResponses, ExternalServiceMetricsCreateAlertRuleData, ExternalServiceMetricsCreateAlertRuleErrors, ExternalServiceMetricsCreateAlertRuleResponse, ExternalServiceMetricsCreateAlertRuleResponses, ExternalServiceMetricsDeleteAlertRuleData, ExternalServiceMetricsDeleteAlertRuleErrors, ExternalServiceMetricsDeleteAlertRuleResponse, ExternalServiceMetricsDeleteAlertRuleResponses, ExternalServiceMetricsGetAlertRulesData, ExternalServiceMetricsGetAlertRulesErrors, ExternalServiceMetricsGetAlertRulesResponse, ExternalServiceMetricsGetAlertRulesResponses, ExternalServiceMetricsGetLatestData, ExternalServiceMetricsGetLatestErrors, ExternalServiceMetricsGetLatestResponse, ExternalServiceMetricsGetLatestResponses, ExternalServiceMetricsGetRangeData, ExternalServiceMetricsGetRangeErrors, ExternalServiceMetricsGetRangeResponse, ExternalServiceMetricsGetRangeResponses, ExternalServiceMetricsStatusData, ExternalServiceMetricsStatusErrors, ExternalServiceMetricsStatusResponse, ExternalServiceMetricsStatusResponses, ExternalServiceMetricsToggleData, ExternalServiceMetricsToggleErrors, ExternalServiceMetricsToggleResponses, ExternalServiceMetricsUpdateAlertRuleData, ExternalServiceMetricsUpdateAlertRuleErrors, ExternalServiceMetricsUpdateAlertRuleResponse, ExternalServiceMetricsUpdateAlertRuleResponses, ExternalServiceResetPgStatStatementsData, ExternalServiceResetPgStatStatementsErrors, ExternalServiceResetPgStatStatementsResponse, ExternalServiceResetPgStatStatementsResponses, ExternalServiceSummary, FieldResponse, FinalizeOrderData, FinalizeOrderErrors, FinalizeOrderResponse, FinalizeOrderResponses, FinalizeProjectReleaseData, FinalizeProjectReleaseErrors, FinalizeProjectReleaseResponse, FinalizeProjectReleaseResponses, FindConversationData, FindConversationErrors, FindConversationResponse, FindConversationResponses, FiringSeriesEntry, FlagEnvironmentResponse, FlagListResponse, FlagResponse, FlagSnapshot, FlagSnapshotResponse, FlagValueType, ForecastAlgorithm, ForecastParams, FullError, FullEvent, FullRequest, FunnelMetricsResponse, FunnelResponse, GatewayStatus, GenAiEvent, GenAiSpanDetail, GenAiTraceDetailResponse, GenAiTraceSummariesResponse, GenAiTraceSummary, GeneralStatsQuery, GeneralStatsResponse, GenerateDockerfileRequest, GenerateDockerfileResponse, GenerateJoinTokenData, GenerateJoinTokenErrors, GenerateJoinTokenResponse, GenerateJoinTokenResponse2, GenerateJoinTokenResponses, GeneratePresetDockerfileData, GeneratePresetDockerfileErrors, GeneratePresetDockerfileResponse, GeneratePresetDockerfileResponses, GeoLocationResponse, GeoRestrictionsConfig, GetAccessInfoData, GetAccessInfoErrors, GetAccessInfoResponse, GetAccessInfoResponses, GetActiveVisitorsData, GetActiveVisitorsErrors, GetActiveVisitorsResponse, GetActiveVisitorsResponses, GetActivityGraphData, GetActivityGraphErrors, GetActivityGraphResponse, GetActivityGraphResponses, GetAdminGateData, GetAdminGateErrors, GetAdminGateResponse, GetAdminGateResponses, GetAgentData, GetAgentErrors, GetAgentResponse, GetAgentResponses, GetAggregatedBucketsData, GetAggregatedBucketsErrors, GetAggregatedBucketsResponse, GetAggregatedBucketsResponses, GetAiAgentBreakdownData, GetAiAgentBreakdownError, GetAiAgentBreakdownErrors, GetAiAgentBreakdownResponse, GetAiAgentBreakdownResponses, GetAiAgentPagesData, GetAiAgentPagesError, GetAiAgentPagesErrors, GetAiAgentPagesResponse, GetAiAgentPagesResponses, GetAiAgentTimelineData, GetAiAgentTimelineError, GetAiAgentTimelineErrors, GetAiAgentTimelineResponse, GetAiAgentTimelineResponses, GetAiPageBreakdownData, GetAiPageBreakdownError, GetAiPageBreakdownErrors, GetAiPageBreakdownResponse, GetAiPageBreakdownResponses, GetAiStatusBreakdownData, GetAiStatusBreakdownError, GetAiStatusBreakdownErrors, GetAiStatusBreakdownResponse, GetAiStatusBreakdownResponses, GetAlertData, GetAlertError, GetAlertErrors, GetAlertResponse, GetAlertResponses, GetAlertRuleData, GetAlertRuleErrors, GetAlertRuleResponse, GetAlertRuleResponses, GetAllRepositoriesByNameData, GetAllRepositoriesByNameErrors, GetAllRepositoriesByNameResponse, GetAllRepositoriesByNameResponses, GetAnalyticsActiveVisitorsData, GetAnalyticsActiveVisitorsErrors, GetAnalyticsActiveVisitorsResponse, GetAnalyticsActiveVisitorsResponses, GetAnalyticsEventsCountData, GetAnalyticsEventsCountErrors, GetAnalyticsEventsCountResponse, GetAnalyticsEventsCountResponses, GetAnalyticsSessionEventsData, GetAnalyticsSessionEventsErrors, GetAnalyticsSessionEventsResponse, GetAnalyticsSessionEventsResponses, GetAnalyticsVisitorSessionsData, GetAnalyticsVisitorSessionsErrors, GetAnalyticsVisitorSessionsResponse, GetAnalyticsVisitorSessionsResponses, GetApiKeyData, GetApiKeyErrors, GetApiKeyPermissionsData, GetApiKeyPermissionsErrors, GetApiKeyPermissionsResponse, GetApiKeyPermissionsResponses, GetApiKeyResponse, GetApiKeyResponses, GetAuditLogData, GetAuditLogErrors, GetAuditLogResponse, GetAuditLogResponses, GetBackupData, GetBackupError, GetBackupErrors, GetBackupResponse, GetBackupResponses, GetBackupScheduleData, GetBackupScheduleErrors, GetBackupScheduleResponse, GetBackupScheduleResponses, GetBranchesByRepositoryIdData, GetBranchesByRepositoryIdErrors, GetBranchesByRepositoryIdResponse, GetBranchesByRepositoryIdResponses, GetBucketedIncidentsData, GetBucketedIncidentsErrors, GetBucketedIncidentsResponse, GetBucketedIncidentsResponses, GetBucketedStatusData, GetBucketedStatusErrors, GetBucketedStatusResponse, GetBucketedStatusResponses, GetChallengeTokenData, GetChallengeTokenErrors, GetChallengeTokenResponse, GetChallengeTokenResponses, GetChatReadinessData, GetChatReadinessErrors, GetChatReadinessResponse, GetChatReadinessResponses, GetCliStatusData, GetCliStatusErrors, GetCliStatusResponses, GetClusterHealthData, GetClusterHealthErrors, GetClusterHealthResponse, GetClusterHealthResponses, GetClusterMemberData, GetClusterMemberErrors, GetClusterMemberResponse, GetClusterMemberResponses, GetCmdData, GetCmdErrors, GetCmdResponse, GetCmdResponses, GetContainerDetailData, GetContainerDetailErrors, GetContainerDetailResponse, GetContainerDetailResponses, GetContainerEnvironmentVariableData, GetContainerEnvironmentVariableErrors, GetContainerEnvironmentVariableResponse, GetContainerEnvironmentVariableResponses, GetContainerInfoData, GetContainerInfoErrors, GetContainerInfoResponse, GetContainerInfoResponses, GetContainerLogsByIdData, GetContainerLogsByIdErrors, GetContainerLogsData, GetContainerLogsErrors, GetContainerMetricsData, GetContainerMetricsErrors, GetContainerMetricsResponse, GetContainerMetricsResponses, GetConversationData, GetConversationDetailData, GetConversationDetailError, GetConversationDetailErrors, GetConversationDetailResponse, GetConversationDetailResponses, GetConversationErrors, GetConversationResponse, GetConversationResponses, GetConversationsData, GetConversationsError, GetConversationsErrors, GetConversationsResponse, GetConversationsResponses, GetCronByIdData, GetCronByIdErrors, GetCronByIdResponse, GetCronByIdResponses, GetCronExecutionsData, GetCronExecutionsErrors, GetCronExecutionsResponse, GetCronExecutionsResponses, GetCrossProjectTraceSiblingsData, GetCrossProjectTraceSiblingsError, GetCrossProjectTraceSiblingsErrors, GetCrossProjectTraceSiblingsResponse, GetCrossProjectTraceSiblingsResponses, GetCurrentMonitorStatusData, GetCurrentMonitorStatusErrors, GetCurrentMonitorStatusResponse, GetCurrentMonitorStatusResponses, GetCurrentUserData, GetCurrentUserErrors, GetCurrentUserResponse, GetCurrentUserResponses, GetCustomDomainData, GetCustomDomainErrors, GetCustomDomainResponse, GetCustomDomainResponses, GetDashboardData, GetDashboardError, GetDashboardErrors, GetDashboardProjectsAnalyticsData, GetDashboardProjectsAnalyticsErrors, GetDashboardProjectsAnalyticsResponse, GetDashboardProjectsAnalyticsResponses, GetDashboardResponse, GetDashboardResponses, GetDeliveryData, GetDeliveryErrors, GetDeliveryResponse, GetDeliveryResponses, GetDeploymentContainerLogContentData, GetDeploymentContainerLogContentErrors, GetDeploymentContainerLogContentResponse, GetDeploymentContainerLogContentResponses, GetDeploymentData, GetDeploymentErrors, GetDeploymentJobLogsData, GetDeploymentJobLogsErrors, GetDeploymentJobLogsResponse, GetDeploymentJobLogsResponses, GetDeploymentJobsData, GetDeploymentJobsErrors, GetDeploymentJobsResponse, GetDeploymentJobsResponses, GetDeploymentOperationsData, GetDeploymentOperationsErrors, GetDeploymentOperationsResponse, GetDeploymentOperationsResponses, GetDeploymentOperationStatusData, GetDeploymentOperationStatusErrors, GetDeploymentOperationStatusResponse, GetDeploymentOperationStatusResponses, GetDeploymentResponse, GetDeploymentResponses, GetDeploymentsParams, GetDeploymentTokenData, GetDeploymentTokenErrors, GetDeploymentTokenResponse, GetDeploymentTokenResponses, GetDiskStatusData, GetDiskStatusErrors, GetDiskStatusResponse, GetDiskStatusResponses, GetDnsChangesData, GetDnsChangesErrors, GetDnsChangesResponse, GetDnsChangesResponses, GetDnsProviderData, GetDnsProviderErrors, GetDnsProviderResponse, GetDnsProviderResponses, GetDomainByHostData, GetDomainByHostErrors, GetDomainByHostResponse, GetDomainByHostResponses, GetDomainByIdData, GetDomainByIdErrors, GetDomainByIdResponse, GetDomainByIdResponses, GetDomainByNameData, GetDomainByNameErrors, GetDomainByNameResponse, GetDomainByNameResponses, GetDomainData, GetDomainDnsRecordsData, GetDomainDnsRecordsErrors, GetDomainDnsRecordsResponse, GetDomainDnsRecordsResponses, GetDomainErrors, GetDomainOrderData, GetDomainOrderErrors, GetDomainOrderResponse, GetDomainOrderResponses, GetDomainResponse, GetDomainResponses, GetEmailData, GetEmailErrors, GetEmailEventsData, GetEmailEventsErrors, GetEmailEventsResponse, GetEmailEventsResponses, GetEmailLinksData, GetEmailLinksErrors, GetEmailLinksResponse, GetEmailLinksResponses, GetEmailProviderData, GetEmailProviderErrors, GetEmailProviderResponse, GetEmailProviderResponses, GetEmailResponse, GetEmailResponses, GetEmailStatsData, GetEmailStatsErrors, GetEmailStatsResponse, GetEmailStatsResponses, GetEmailTrackingData, GetEmailTrackingErrors, GetEmailTrackingResponse, GetEmailTrackingResponses, GetEmailTrackingStatusData, GetEmailTrackingStatusErrors, GetEmailTrackingStatusResponse, GetEmailTrackingStatusResponses, GetEntityInfoData, GetEntityInfoErrors, GetEntityInfoResponse, GetEntityInfoResponses, GetEnvironmentCronsData, GetEnvironmentCronsErrors, GetEnvironmentCronsResponse, GetEnvironmentCronsResponses, GetEnvironmentData, GetEnvironmentDomainsData, GetEnvironmentDomainsErrors, GetEnvironmentDomainsResponse, GetEnvironmentDomainsResponses, GetEnvironmentErrors, GetEnvironmentResponse, GetEnvironmentResponses, GetEnvironmentsData, GetEnvironmentsErrors, GetEnvironmentsResponse, GetEnvironmentsResponses, GetEnvironmentVariablesData, GetEnvironmentVariablesErrors, GetEnvironmentVariablesQuery, GetEnvironmentVariablesResponse, GetEnvironmentVariablesResponses, GetEnvironmentVariableValueData, GetEnvironmentVariableValueErrors, GetEnvironmentVariableValueResponse, GetEnvironmentVariableValueResponses, GetErrorDashboardStatsData, GetErrorDashboardStatsErrors, GetErrorDashboardStatsResponse, GetErrorDashboardStatsResponses, GetErrorEventData, GetErrorEventErrors, GetErrorEventResponse, GetErrorEventResponses, GetErrorGroupData, GetErrorGroupErrors, GetErrorGroupResponse, GetErrorGroupResponses, GetErrorStatsData, GetErrorStatsErrors, GetErrorStatsResponse, GetErrorStatsResponses, GetErrorTimeSeriesData, GetErrorTimeSeriesErrors, GetErrorTimeSeriesResponse, GetErrorTimeSeriesResponses, GetEventDetailData, GetEventDetailErrors, GetEventDetailResponse, GetEventDetailResponses, GetEventEntriesData, GetEventEntriesErrors, GetEventEntriesResponse, GetEventEntriesResponses, GetEventsCountData, GetEventsCountErrors, GetEventsCountResponse, GetEventsCountResponses, GetEventsTimelineData, GetEventsTimelineErrors, GetEventsTimelineResponse, GetEventsTimelineResponses, GetEventTypeBreakdownData, GetEventTypeBreakdownErrors, GetEventTypeBreakdownResponse, GetEventTypeBreakdownResponses, GetEventVisitorsData, GetEventVisitorsErrors, GetEventVisitorsResponse, GetEventVisitorsResponses, GetExternalImageData, GetExternalImageErrors, GetExternalImageResponse, GetExternalImageResponses, GetFileData, GetFileErrors, GetFileResponse, GetFileResponses, GetFlagData, GetFlagErrors, GetFlagResponse, GetFlagResponses, GetFlagSnapshotData, GetFlagSnapshotErrors, GetFlagSnapshotResponse, GetFlagSnapshotResponses, GetFunnelMetricsData, GetFunnelMetricsErrors, GetFunnelMetricsQuery, GetFunnelMetricsResponse, GetFunnelMetricsResponses, GetGenaiTraceData, GetGenaiTraceError, GetGenaiTraceErrors, GetGenaiTraceResponse, GetGenaiTraceResponses, GetGeneralStatsData, GetGeneralStatsErrors, GetGeneralStatsResponse, GetGeneralStatsResponses, GetGitProviderData, GetGitProviderErrors, GetGitProviderResponse, GetGitProviderResponses, GetGlobalEventsData, GetGlobalEventsErrors, GetGlobalEventsResponse, GetGlobalEventsResponses, GetGlobalEventStatsData, GetGlobalEventStatsErrors, GetGlobalEventStatsResponse, GetGlobalEventStatsResponses, GetGlobalMcpData, GetGlobalMcpErrors, GetGlobalMcpResponse, GetGlobalMcpResponses, GetGlobalSandboxStatusData, GetGlobalSandboxStatusErrors, GetGlobalSandboxStatusResponse, GetGlobalSandboxStatusResponses, GetGlobalSkillData, GetGlobalSkillErrors, GetGlobalSkillResponse, GetGlobalSkillResponses, GetGroupedPageMetricsData, GetGroupedPageMetricsError, GetGroupedPageMetricsErrors, GetGroupedPageMetricsResponse, GetGroupedPageMetricsResponses, GetHealthData, GetHealthError, GetHealthErrors, GetHealthResponse, GetHealthResponses, GetHourlyVisitsData, GetHourlyVisitsErrors, GetHourlyVisitsResponse, GetHourlyVisitsResponses, GetHttpChallengeDebugData, GetHttpChallengeDebugErrors, GetHttpChallengeDebugResponse, GetHttpChallengeDebugResponses, GetImportStatusData, GetImportStatusErrors, GetImportStatusResponse, GetImportStatusResponses, GetIncidentData, GetIncidentErrors, GetIncidentResponse, GetIncidentResponses, GetIncidentUpdatesData, GetIncidentUpdatesErrors, GetIncidentUpdatesResponse, GetIncidentUpdatesResponses, GetIpAccessControlData, GetIpAccessControlError, GetIpAccessControlErrors, GetIpAccessControlResponse, GetIpAccessControlResponses, GetIpGeolocationData, GetIpGeolocationError, GetIpGeolocationErrors, GetIpGeolocationResponse, GetIpGeolocationResponses, GetJoinTokenStatusData, GetJoinTokenStatusErrors, GetJoinTokenStatusResponse, GetJoinTokenStatusResponses, GetLastDeploymentData, GetLastDeploymentErrors, GetLastDeploymentResponse, GetLastDeploymentResponses, GetLatestScanData, GetLatestScanError, GetLatestScanErrors, GetLatestScanResponse, GetLatestScanResponses, GetLatestScansPerEnvironmentData, GetLatestScansPerEnvironmentError, GetLatestScansPerEnvironmentErrors, GetLatestScansPerEnvironmentResponse, GetLatestScansPerEnvironmentResponses, GetLiveVisitorsListData, GetLiveVisitorsListErrors, GetLiveVisitorsListResponse, GetLiveVisitorsListResponses, GetLogContextData, GetLogContextError, GetLogContextErrors, GetLogContextResponse, GetLogContextResponses, GetMcpData, GetMcpErrors, GetMcpResponse, GetMcpResponses, GetMetricsOverTimeData, GetMetricsOverTimeError, GetMetricsOverTimeErrors, GetMetricsOverTimeResponse, GetMetricsOverTimeResponses, GetMonitorData, GetMonitorErrors, GetMonitorResponse, GetMonitorResponses, GetNotificationProviderData, GetNotificationProviderErrors, GetNotificationProviderResponse, GetNotificationProviderResponses, GetOnDemandCertStatusData, GetOnDemandCertStatusErrors, GetOnDemandCertStatusResponse, GetOnDemandCertStatusResponses, GetOrCreateDsnData, GetOrCreateDsnErrors, GetOrCreateDsnRequest, GetOrCreateDsnResponse, GetOrCreateDsnResponses, GetPageFlowData, GetPageFlowErrors, GetPageFlowResponse, GetPageFlowResponses, GetPageHourlySessionsData, GetPageHourlySessionsErrors, GetPageHourlySessionsResponse, GetPageHourlySessionsResponses, GetPagePathDetailData, GetPagePathDetailErrors, GetPagePathDetailResponse, GetPagePathDetailResponses, GetPagePathsData, GetPagePathsErrors, GetPagePathsResponse, GetPagePathsResponses, GetPagePathsSparklinesData, GetPagePathsSparklinesErrors, GetPagePathsSparklinesResponse, GetPagePathsSparklinesResponses, GetPagePathVisitorsData, GetPagePathVisitorsErrors, GetPagePathVisitorsResponse, GetPagePathVisitorsResponses, GetPendingActionData, GetPendingActionErrors, GetPendingActionResponse, GetPendingActionResponses, GetPerformanceMetricsData, GetPerformanceMetricsError, GetPerformanceMetricsErrors, GetPerformanceMetricsResponse, GetPerformanceMetricsResponses, GetPgUpgradeData, GetPgUpgradeErrors, GetPgUpgradeLogsData, GetPgUpgradeLogsErrors, GetPgUpgradeLogsResponse, GetPgUpgradeLogsResponses, GetPgUpgradeResponse, GetPgUpgradeResponses, GetPipelineStatsData, GetPipelineStatsError, GetPipelineStatsErrors, GetPipelineStatsResponse, GetPipelineStatsResponses, GetPlatformInfoData, GetPlatformInfoErrors, GetPlatformInfoResponse, GetPlatformInfoResponses, GetPostgresWalHealthData, GetPostgresWalHealthErrors, GetPostgresWalHealthResponse, GetPostgresWalHealthResponses, GetPreferencesData, GetPreferencesErrors, GetPreferencesResponse, GetPreferencesResponses, GetPreviewGatewayLogsData, GetPreviewGatewayLogsResponse, GetPreviewGatewayLogsResponses, GetPreviewGatewaySettingsData, GetPreviewGatewaySettingsResponse, GetPreviewGatewaySettingsResponses, GetPreviewGatewayStatusData, GetPreviewGatewayStatusResponse, GetPreviewGatewayStatusResponses, GetPricingData, GetPricingError, GetPricingErrors, GetPricingResponse, GetPricingResponses, GetPrivateIpData, GetPrivateIpErrors, GetPrivateIpResponses, GetProjectAlarmsSummaryData, GetProjectAlarmsSummaryErrors, GetProjectAlarmsSummaryResponse, GetProjectAlarmsSummaryResponses, GetProjectBySlugData, GetProjectBySlugErrors, GetProjectBySlugResponse, GetProjectBySlugResponses, GetProjectData, GetProjectDeploymentsData, GetProjectDeploymentsErrors, GetProjectDeploymentsResponse, GetProjectDeploymentsResponses, GetProjectErrors, GetProjectResponse, GetProjectResponses, GetProjectsData, GetProjectSecretsQuery, GetProjectsErrors, GetProjectServiceEnvironmentVariablesData, GetProjectServiceEnvironmentVariablesErrors, GetProjectServiceEnvironmentVariablesResponse, GetProjectServiceEnvironmentVariablesResponses, GetProjectSessionReplaysData, GetProjectSessionReplaysError, GetProjectSessionReplaysErrors, GetProjectSessionReplaysQuery, GetProjectSessionReplaysResponse, GetProjectSessionReplaysResponse2, GetProjectSessionReplaysResponses, GetProjectsHealthData, GetProjectsHealthError, GetProjectsHealthErrors, GetProjectsHealthResponse, GetProjectsHealthResponses, GetProjectsMonitorHealthData, GetProjectsMonitorHealthErrors, GetProjectsMonitorHealthResponse, GetProjectsMonitorHealthResponses, GetProjectsResponse, GetProjectsResponses, GetProjectStatisticsData, GetProjectStatisticsErrors, GetProjectStatisticsResponse, GetProjectStatisticsResponses, GetProjectTemplateData, GetProjectTemplateErrors, GetProjectTemplateResponse, GetProjectTemplateResponses, GetPropertyBreakdownData, GetPropertyBreakdownErrors, GetPropertyBreakdownResponse, GetPropertyBreakdownResponses, GetPropertyTimelineData, GetPropertyTimelineErrors, GetPropertyTimelineResponse, GetPropertyTimelineResponses, GetProviderConnectionsData, GetProviderConnectionsErrors, GetProviderConnectionsResponse, GetProviderConnectionsResponses, GetProviderMetadataData, GetProviderMetadataErrors, GetProviderMetadataResponse, GetProviderMetadataResponses, GetProvidersMetadataData, GetProvidersMetadataErrors, GetProvidersMetadataResponse, GetProvidersMetadataResponses, GetProxyLogByIdData, GetProxyLogByIdError, GetProxyLogByIdErrors, GetProxyLogByIdResponse, GetProxyLogByIdResponses, GetProxyLogByRequestIdData, GetProxyLogByRequestIdError, GetProxyLogByRequestIdErrors, GetProxyLogByRequestIdResponse, GetProxyLogByRequestIdResponses, GetProxyLogsData, GetProxyLogsError, GetProxyLogsErrors, GetProxyLogsResponse, GetProxyLogsResponses, GetPublicBranchesData, GetPublicBranchesErrors, GetPublicBranchesResponse, GetPublicBranchesResponses, GetPublicIpData, GetPublicIpErrors, GetPublicIpResponses, GetPublicRepositoryData, GetPublicRepositoryErrors, GetPublicRepositoryResponse, GetPublicRepositoryResponses, GetQuotaData, GetQuotaError, GetQuotaErrors, GetQuotaResponse, GetQuotaResponses, GetRecentActivityData, GetRecentActivityErrors, GetRecentActivityResponse, GetRecentActivityResponses, GetRemoteExternalImageData, GetRemoteExternalImageErrors, GetRemoteExternalImageResponse, GetRemoteExternalImageResponses, GetRepositoryBranchesData, GetRepositoryBranchesErrors, GetRepositoryBranchesResponse, GetRepositoryBranchesResponses, GetRepositoryByIdData, GetRepositoryByIdErrors, GetRepositoryByIdResponse, GetRepositoryByIdResponses, GetRepositoryByNameData, GetRepositoryByNameErrors, GetRepositoryByNameResponse, GetRepositoryByNameResponses, GetRepositoryPresetByNameData, GetRepositoryPresetByNameErrors, GetRepositoryPresetByNameResponse, GetRepositoryPresetByNameResponses, GetRepositoryPresetLiveData, GetRepositoryPresetLiveErrors, GetRepositoryPresetLiveResponse, GetRepositoryPresetLiveResponses, GetRepositoryTagsData, GetRepositoryTagsErrors, GetRepositoryTagsResponse, GetRepositoryTagsResponses, GetRequest, GetResolvedEnvironmentVariablesData, GetResolvedEnvironmentVariablesErrors, GetResolvedEnvironmentVariablesResponse, GetResolvedEnvironmentVariablesResponses, GetResolvedEnvironmentVariableValueData, GetResolvedEnvironmentVariableValueErrors, GetResolvedEnvironmentVariableValueResponse, GetResolvedEnvironmentVariableValueResponses, GetResponse, GetRestoreCapabilitiesData, GetRestoreCapabilitiesError, GetRestoreCapabilitiesErrors, GetRestoreCapabilitiesResponse, GetRestoreCapabilitiesResponses, GetRestoreRunData, GetRestoreRunError, GetRestoreRunErrors, GetRestoreRunResponse, GetRestoreRunResponses, GetRouteData, GetRouteErrors, GetRouteResponse, GetRouteResponses, GetRunData, GetRunErrors, GetRunResponse, GetRunResponses, GetRunWithLogsData, GetRunWithLogsErrors, GetRunWithLogsResponse, GetRunWithLogsResponses, GetS3CredentialsData, GetS3CredentialsErrors, GetS3CredentialsResponse, GetS3CredentialsResponses, GetS3SourceData, GetS3SourceError, GetS3SourceErrors, GetS3SourceResponse, GetS3SourceResponses, GetSandboxData, GetSandboxErrors, GetSandboxResponse, GetSandboxResponses, GetSandboxStatusData, GetSandboxStatusErrors, GetSandboxStatusResponse, GetSandboxStatusResponses, GetScanByDeploymentData, GetScanByDeploymentError, GetScanByDeploymentErrors, GetScanByDeploymentResponse, GetScanByDeploymentResponses, GetScanData, GetScanError, GetScanErrors, GetScanResponse, GetScanResponses, GetScanVulnerabilitiesData, GetScanVulnerabilitiesError, GetScanVulnerabilitiesErrors, GetScanVulnerabilitiesResponse, GetScanVulnerabilitiesResponses, GetServiceBySlugData, GetServiceBySlugErrors, GetServiceBySlugResponse, GetServiceBySlugResponses, GetServiceData, GetServiceEnvironmentVariableData, GetServiceEnvironmentVariableErrors, GetServiceEnvironmentVariableResponse, GetServiceEnvironmentVariableResponses, GetServiceEnvironmentVariablesData, GetServiceEnvironmentVariablesErrors, GetServiceEnvironmentVariablesResponse, GetServiceEnvironmentVariablesResponses, GetServiceErrors, GetServiceHealthStatusData, GetServiceHealthStatusErrors, GetServiceHealthStatusResponse, GetServiceHealthStatusResponses, GetServicePreviewEnvironmentVariableNamesData, GetServicePreviewEnvironmentVariableNamesErrors, GetServicePreviewEnvironmentVariableNamesResponse, GetServicePreviewEnvironmentVariableNamesResponses, GetServicePreviewEnvironmentVariablesMaskedData, GetServicePreviewEnvironmentVariablesMaskedErrors, GetServicePreviewEnvironmentVariablesMaskedResponse, GetServicePreviewEnvironmentVariablesMaskedResponses, GetServiceResponse, GetServiceResponses, GetServiceRuntimeData, GetServiceRuntimeErrors, GetServiceRuntimeResponse, GetServiceRuntimeResponses, GetServiceStatsData, GetServiceStatsErrors, GetServiceStatsResponse, GetServiceStatsResponses, GetServiceTypeParametersData, GetServiceTypeParametersErrors, GetServiceTypeParametersResponses, GetServiceTypesData, GetServiceTypesErrors, GetServiceTypesResponse, GetServiceTypesResponses, GetSessionDetailsData, GetSessionDetailsErrors, GetSessionDetailsResponse, GetSessionDetailsResponses, GetSessionEventsData, GetSessionEventsErrors, GetSessionEventsResponse, GetSessionEventsResponses, GetSessionLogsData, GetSessionLogsErrors, GetSessionLogsResponse, GetSessionLogsResponses, GetSessionReplayData, GetSessionReplayError, GetSessionReplayErrors, GetSessionReplayEventsData, GetSessionReplayEventsError, GetSessionReplayEventsErrors, GetSessionReplayEventsResponse, GetSessionReplayEventsResponses, GetSessionReplayResponse, GetSessionReplayResponse2, GetSessionReplayResponses, GetSettingsData, GetSettingsErrors, GetSettingsResponse, GetSettingsResponses, GetSkillData, GetSkillErrors, GetSkillResponse, GetSkillResponses, GetSlowQueriesData, GetSlowQueriesErrors, GetSlowQueriesResponse, GetSlowQueriesResponses, GetStaticBundleData, GetStaticBundleErrors, GetStaticBundleResponse, GetStaticBundleResponses, GetStatusOverviewData, GetStatusOverviewErrors, GetStatusOverviewResponse, GetStatusOverviewResponses, GetTagsByRepositoryIdData, GetTagsByRepositoryIdErrors, GetTagsByRepositoryIdResponse, GetTagsByRepositoryIdResponses, GetTeamData, GetTeamErrors, GetTeamResponse, GetTeamResponses, GetTimeBucketStatsData, GetTimeBucketStatsError, GetTimeBucketStatsErrors, GetTimeBucketStatsResponse, GetTimeBucketStatsResponses, GetTodayStatsData, GetTodayStatsError, GetTodayStatsErrors, GetTodayStatsResponse, GetTodayStatsResponses, GetTraceData, GetTraceError, GetTraceErrors, GetTraceResponse, GetTraceResponses, GetUnifiedTraceData, GetUnifiedTraceError, GetUnifiedTraceErrors, GetUnifiedTraceResponse, GetUnifiedTraceResponses, GetUniqueCountsData, GetUniqueCountsErrors, GetUniqueCountsResponse, GetUniqueCountsResponses, GetUniqueEventsData, GetUniqueEventsErrors, GetUniqueEventsQuery, GetUniqueEventsResponse, GetUniqueEventsResponses, GetUpdateCapabilityData, GetUpdateCapabilityErrors, GetUpdateCapabilityResponse, GetUpdateCapabilityResponses, GetUpdateStatusData, GetUpdateStatusErrors, GetUpdateStatusResponse, GetUpdateStatusResponses, GetUptimeHistoryData, GetUptimeHistoryErrors, GetUptimeHistoryResponse, GetUptimeHistoryResponses, GetUsageByProviderData, GetUsageByProviderError, GetUsageByProviderErrors, GetUsageByProviderResponse, GetUsageByProviderResponses, GetUsageRecentData, GetUsageRecentError, GetUsageRecentErrors, GetUsageRecentResponse, GetUsageRecentResponses, GetUsageSummaryData, GetUsageSummaryError, GetUsageSummaryErrors, GetUsageSummaryResponse, GetUsageSummaryResponses, GetUsageTimeseriesData, GetUsageTimeseriesError, GetUsageTimeseriesErrors, GetUsageTimeseriesResponse, GetUsageTimeseriesResponses, GetUsageTopModelsData, GetUsageTopModelsError, GetUsageTopModelsErrors, GetUsageTopModelsResponse, GetUsageTopModelsResponses, GetVisitorByGuidData, GetVisitorByGuidErrors, GetVisitorByGuidResponse, GetVisitorByGuidResponses, GetVisitorByIdData, GetVisitorByIdErrors, GetVisitorByIdResponse, GetVisitorByIdResponses, GetVisitorDetailsData, GetVisitorDetailsErrors, GetVisitorDetailsResponse, GetVisitorDetailsResponses, GetVisitorFacetsData, GetVisitorFacetsErrors, GetVisitorFacetsResponse, GetVisitorFacetsResponses, GetVisitorInfoData, GetVisitorInfoErrors, GetVisitorInfoResponse, GetVisitorInfoResponses, GetVisitorJourneyData, GetVisitorJourneyErrors, GetVisitorJourneyResponse, GetVisitorJourneyResponses, GetVisitorsData, GetVisitorsErrors, GetVisitorSessionsData, GetVisitorSessionsError, GetVisitorSessionsErrors, GetVisitorSessionsQuery, GetVisitorSessionsResponse, GetVisitorSessionsResponse2, GetVisitorSessionsResponses, GetVisitorsResponse, GetVisitorsResponses, GetVisitorStatsData, GetVisitorStatsErrors, GetVisitorStatsResponse, GetVisitorStatsResponses, GetWebhookData, GetWebhookErrors, GetWebhookResponse, GetWebhookResponses, GitPushEvent, GitRefResponse, GitSourcePlan, GlobalConversationResponse, GlobalEventStatsResponse, GlobalMrrResponse, GlobalRecentEventResponse, GlobalRevenueSummaryResponse, GrantProjectAccessData, GrantProjectAccessErrors, GrantProjectAccessResponse, GrantProjectAccessResponses, GroupedPageMetric, GroupedPageMetricsQuery, GroupedPageMetricsResponse, HandleGitProviderOauthCallbackData, HandleGitProviderOauthCallbackErrors, HasAnalyticsEventsData, HasAnalyticsEventsErrors, HasAnalyticsEventsResponse, HasAnalyticsEventsResponse2, HasAnalyticsEventsResponses, HasErrorGroupsData, HasErrorGroupsErrors, HasErrorGroupsResponse, HasErrorGroupsResponse2, HasErrorGroupsResponses, HasEventsQuery, HasEventsResponse, HasMetricsQuery, HasMetricsResponse, HasPerformanceMetricsData, HasPerformanceMetricsError, HasPerformanceMetricsErrors, HasPerformanceMetricsResponse, HasPerformanceMetricsResponses, HealthCheckConfiguration, HealthCheckEntryResponse, HealthResponse, HealthStatus, HealthSummary, HeartbeatApiRequest, HeartbeatResponse, HierarchyLevel, HistogramSummary, HostnameChange, HostnamePreviewResponse, HourlyPageSessions, HourlyVisitsQuery, HttpChallengeDebugResponse, ImportCredentials, ImportExecutionStatus, ImportExternalServiceData, ImportExternalServiceErrors, ImportExternalServiceRequest, ImportExternalServiceResponse, ImportExternalServiceResponses, ImportOutcomeResponse, ImportPlan, ImportRowErrorResponse, ImportSelector, ImportSource, ImportSourceCapabilities, ImportSourceInfo, ImportStatusResponse, IncidentBucket, IncidentBucketedResponse, IncidentResponse, IncidentUpdateResponse, IncrRequest, IncrResponse, IngestLogsByPathData, IngestLogsByPathError, IngestLogsByPathErrors, IngestLogsByPathResponses, IngestLogsData, IngestLogsError, IngestLogsErrors, IngestLogsResponses, IngestMetricsByPathData, IngestMetricsByPathError, IngestMetricsByPathErrors, IngestMetricsByPathResponses, IngestMetricsData, IngestMetricsError, IngestMetricsErrors, IngestMetricsResponses, IngestSentryEnvelopeData, IngestSentryEnvelopeErrors, IngestSentryEnvelopeResponses, IngestSentryEventData, IngestSentryEventErrors, IngestSentryEventResponse, IngestSentryEventResponses, IngestTracesByPathData, IngestTracesByPathError, IngestTracesByPathErrors, IngestTracesByPathResponses, IngestTracesData, IngestTracesError, IngestTracesErrors, IngestTracesResponses, InitAuthResponse, InitSessionReplayData, InitSessionReplayError, InitSessionReplayErrors, InitSessionReplayResponse, InitSessionReplayResponses, Insight, InsightSeverity, InsightsResponse, InsightStatus, InspectDropArchiveData, InspectDropArchiveErrors, InspectDropArchiveResponse, InspectDropArchiveResponses, IntegrationResponse, IpAccessControlQuery, IpAccessControlResponse, JobLogsData, JobLogsErrors, JobLogsResponses, JobStatusData, JobStatusErrors, JobStatusResponse, JobStatusResponse2, JobStatusResponses, JobSummaryResponse, JoinTokenStatusResponse, JourneyEvent, JourneySession, KeysRequest, KeysResponse, KillJobBody, KillJobData, KillJobErrors, KillJobResponse, KillJobResponses, KnownAiAgentsResponse, KvDelData, KvDelErrors, KvDelResponse, KvDelResponses, KvDisableData, KvDisableErrors, KvDisableResponse, KvDisableResponses, KvEnableData, KvEnableErrors, KvEnableResponse, KvEnableResponses, KvExpireData, KvExpireErrors, KvExpireResponse, KvExpireResponses, KvGetData, KvGetErrors, KvGetResponse, KvGetResponses, KvIncrData, KvIncrErrors, KvIncrResponse, KvIncrResponses, KvKeysData, KvKeysErrors, KvKeysResponse, KvKeysResponses, KvSetData, KvSetErrors, KvSetResponse, KvSetResponses, KvStatusData, KvStatusErrors, KvStatusResponse, KvStatusResponse2, KvStatusResponses, KvTtlData, KvTtlErrors, KvTtlResponse, KvTtlResponses, KvUpdateData, KvUpdateErrors, KvUpdateResponse, KvUpdateResponses, LatestRunForSourceData, LatestRunForSourceErrors, LatestRunForSourceResponse, LatestRunForSourceResponses, LemonSqueezyConfig, LetsEncryptSettings, LineContext, LinkCustomDomainToCertificateData, LinkCustomDomainToCertificateErrors, LinkCustomDomainToCertificateResponse, LinkCustomDomainToCertificateResponses, LinkServiceRequest, LinkServiceToProjectData, LinkServiceToProjectErrors, LinkServiceToProjectResponse, LinkServiceToProjectResponses, ListAgentRunsData, ListAgentRunsErrors, ListAgentRunsResponse, ListAgentRunsResponses, ListAgentsData, ListAgentsErrors, ListAgentsResponse, ListAgentsResponse2, ListAgentsResponses, ListAiProvidersData, ListAiProvidersErrors, ListAiProvidersResponse, ListAiProvidersResponses, ListAlertRulesData, ListAlertRulesErrors, ListAlertRulesResponse, ListAlertRulesResponses, ListAlertsData, ListAlertsError, ListAlertsErrors, ListAlertsResponse, ListAlertsResponses, ListAllConversationsData, ListAllConversationsErrors, ListAllConversationsResponse, ListAllConversationsResponses, ListAllRunsData, ListAllRunsErrors, ListAllRunsResponse, ListAllRunsResponses, ListApiKeysData, ListApiKeysErrors, ListApiKeysQuery, ListApiKeysResponse, ListApiKeysResponses, ListAuditLogsData, ListAuditLogsErrors, ListAuditLogsQuery, ListAuditLogsResponse, ListAuditLogsResponses, ListAvailableContainersData, ListAvailableContainersErrors, ListAvailableContainersResponse, ListAvailableContainersResponses, ListBackupAlertsData, ListBackupAlertsError, ListBackupAlertsErrors, ListBackupAlertsResponse, ListBackupAlertsResponses, ListBackupChildrenData, ListBackupChildrenError, ListBackupChildrenErrors, ListBackupChildrenResponse, ListBackupChildrenResponses, ListBackupSchedulesData, ListBackupSchedulesError, ListBackupSchedulesErrors, ListBackupSchedulesResponse, ListBackupSchedulesResponses, ListBackupsForScheduleData, ListBackupsForScheduleErrors, ListBackupsForScheduleResponse, ListBackupsForScheduleResponses, ListBlobsQuery, ListBlobsResponse, ListCommitsByRepositoryIdData, ListCommitsByRepositoryIdErrors, ListCommitsByRepositoryIdResponse, ListCommitsByRepositoryIdResponses, ListConnectionsData, ListConnectionsErrors, ListConnectionsResponse, ListConnectionsResponses, ListContainersAtPathData, ListContainersAtPathErrors, ListContainersAtPathResponse, ListContainersAtPathResponses, ListContainersData, ListContainersErrors, ListContainersResponse, ListContainersResponses, ListConversationsData, ListConversationsErrors, ListConversationsResponse, ListConversationsResponses, ListCustomDomainsForProjectData, ListCustomDomainsForProjectErrors, ListCustomDomainsForProjectResponse, ListCustomDomainsForProjectResponses, ListCustomDomainsResponse, ListDashboardsData, ListDashboardsError, ListDashboardsErrors, ListDashboardsResponse, ListDashboardsResponses, ListDeliveriesData, ListDeliveriesErrors, ListDeliveriesResponse, ListDeliveriesResponses, ListDeploymentContainerLogsData, ListDeploymentContainerLogsErrors, ListDeploymentContainerLogsResponse, ListDeploymentContainerLogsResponses, ListDeploymentTokensData, ListDeploymentTokensErrors, ListDeploymentTokensQuery, ListDeploymentTokensResponse, ListDeploymentTokensResponses, ListDnsProvidersData, ListDnsProvidersErrors, ListDnsProvidersResponse, ListDnsProvidersResponses, ListDomainsData, ListDomainsErrors, ListDomainsResponse, ListDomainsResponse2, ListDomainsResponses, ListDsnsData, ListDsnsErrors, ListDsnsResponse, ListDsnsResponses, ListEmailDomainsData, ListEmailDomainsErrors, ListEmailDomainsResponse, ListEmailDomainsResponses, ListEmailProvidersData, ListEmailProvidersErrors, ListEmailProvidersResponse, ListEmailProvidersResponses, ListEmailsData, ListEmailsErrors, ListEmailsResponse, ListEmailsResponses, ListEnrollmentTokensData, ListEnrollmentTokensErrors, ListEnrollmentTokensResponse, ListEnrollmentTokensResponses, ListEntitiesData, ListEntitiesErrors, ListEntitiesQuery, ListEntitiesResponse, ListEntitiesResponses, ListErrorEventsData, ListErrorEventsErrors, ListErrorEventsQuery, ListErrorEventsResponse, ListErrorEventsResponses, ListErrorGroupsData, ListErrorGroupsErrors, ListErrorGroupsQuery, ListErrorGroupsResponse, ListErrorGroupsResponses, ListEventsData, ListEventsResponse, ListEventsResponses, ListEventTypesData, ListEventTypesResponse, ListEventTypesResponses, ListExternalImagesData, ListExternalImagesErrors, ListExternalImagesResponse, ListExternalImagesResponses, ListExternalPluginsData, ListExternalPluginsErrors, ListExternalPluginsResponse, ListExternalPluginsResponses, ListExternalServiceBackupsData, ListExternalServiceBackupsError, ListExternalServiceBackupsErrors, ListExternalServiceBackupsResponse, ListExternalServiceBackupsResponses, ListFlagsData, ListFlagsErrors, ListFlagsResponse, ListFlagsResponses, ListFunnelsData, ListFunnelsErrors, ListFunnelsResponse, ListFunnelsResponses, ListGitProvidersData, ListGitProvidersErrors, ListGitProvidersResponse, ListGitProvidersResponses, ListGlobalMcpsData, ListGlobalMcpsErrors, ListGlobalMcpsResponse, ListGlobalMcpsResponses, ListGlobalSkillsData, ListGlobalSkillsErrors, ListGlobalSkillsResponse, ListGlobalSkillsResponses, ListIncidentsData, ListIncidentsErrors, ListIncidentsResponses, ListInsightsData, ListInsightsError, ListInsightsErrors, ListInsightsResponse, ListInsightsResponses, ListIpAccessControlData, ListIpAccessControlError, ListIpAccessControlErrors, ListIpAccessControlResponse, ListIpAccessControlResponses, ListJobsData, ListJobsErrors, ListJobsResponse, ListJobsResponse2, ListJobsResponses, ListKnownAiAgentsData, ListKnownAiAgentsError, ListKnownAiAgentsErrors, ListKnownAiAgentsResponse, ListKnownAiAgentsResponses, ListManagedDomainsData, ListManagedDomainsErrors, ListManagedDomainsResponse, ListManagedDomainsResponses, ListMcpsData, ListMcpsErrors, ListMcpsResponse, ListMcpsResponse2, ListMcpsResponses, ListMetricLabelKeysData, ListMetricLabelKeysError, ListMetricLabelKeysErrors, ListMetricLabelKeysResponse, ListMetricLabelKeysResponses, ListMetricLabelValuesData, ListMetricLabelValuesError, ListMetricLabelValuesErrors, ListMetricLabelValuesResponse, ListMetricLabelValuesResponses, ListMetricNamesData, ListMetricNamesError, ListMetricNamesErrors, ListMetricNamesResponse, ListMetricNamesResponses, ListModelsData, ListModelsError, ListModelsErrors, ListModelsResponse, ListModelsResponses, ListMonitorsData, ListMonitorsErrors, ListMonitorsResponse, ListMonitorsResponses, ListNotificationProvidersData, ListNotificationProvidersErrors, ListNotificationProvidersResponse, ListNotificationProvidersResponses, ListOidcProvidersData, ListOidcProvidersResponse, ListOidcProvidersResponses, ListOidcProviderUsersData, ListOidcProviderUsersErrors, ListOidcProviderUsersResponse, ListOidcProviderUsersResponses, ListOidcRoleMappingsData, ListOidcRoleMappingsResponse, ListOidcRoleMappingsResponses, ListOnDemandCertsData, ListOnDemandCertsErrors, ListOnDemandCertsResponse, ListOnDemandCertsResponse2, ListOnDemandCertsResponses, ListOrdersData, ListOrdersErrors, ListOrdersResponse, ListOrdersResponse2, ListOrdersResponses, ListPeersData, ListPeersErrors, ListPeersResponse, ListPeersResponses, ListPendingActionsData, ListPendingActionsErrors, ListPendingActionsResponse, ListPendingActionsResponses, ListPgUpgradesData, ListPgUpgradesErrors, ListPgUpgradesResponse, ListPgUpgradesResponses, ListPresetsData, ListPresetsErrors, ListPresetsResponse, ListPresetsResponse2, ListPresetsResponses, ListProjectAccessData, ListProjectAccessErrors, ListProjectAccessResponse, ListProjectAccessResponses, ListProjectAlarmsData, ListProjectAlarmsErrors, ListProjectAlarmsResponse, ListProjectAlarmsResponses, ListProjectScansData, ListProjectScansError, ListProjectScansErrors, ListProjectScansResponse, ListProjectScansResponses, ListProjectSecretsData, ListProjectSecretsErrors, ListProjectSecretsResponse, ListProjectSecretsResponses, ListProjectServicesData, ListProjectServicesErrors, ListProjectServicesResponse, ListProjectServicesResponses, ListProjectTemplatesData, ListProjectTemplatesErrors, ListProjectTemplatesResponse, ListProjectTemplatesResponses, ListProjectTemplateTagsData, ListProjectTemplateTagsErrors, ListProjectTemplateTagsResponse, ListProjectTemplateTagsResponses, ListProviderKeysData, ListProviderKeysError, ListProviderKeysErrors, ListProviderKeysResponse, ListProviderKeysResponses, ListProviderZonesData, ListProviderZonesErrors, ListProviderZonesResponse, ListProviderZonesResponses, ListPublicProvidersData, ListPublicProvidersResponse, ListPublicProvidersResponses, ListReleaseFilesData, ListReleaseFilesErrors, ListReleaseFilesResponse, ListReleaseFilesResponses, ListReleasesData, ListReleasesErrors, ListReleasesResponse, ListReleasesResponses, ListRemoteExternalImagesData, ListRemoteExternalImagesErrors, ListRemoteExternalImagesResponse, ListRemoteExternalImagesResponses, ListRepositoriesByConnectionData, ListRepositoriesByConnectionErrors, ListRepositoriesByConnectionResponse, ListRepositoriesByConnectionResponses, ListRepositoriesByProviderData, ListRepositoriesByProviderErrors, ListRepositoriesByProviderResponse, ListRepositoriesByProviderResponses, ListRestoreRunsForServiceData, ListRestoreRunsForServiceResponse, ListRestoreRunsForServiceResponses, ListRootContainersData, ListRootContainersErrors, ListRootContainersResponse, ListRootContainersResponses, ListRoutesData, ListRoutesErrors, ListRoutesResponse, ListRoutesResponses, ListRunsResponse, ListS3SourcesData, ListS3SourcesError, ListS3SourcesErrors, ListS3SourcesResponse, ListS3SourcesResponses, ListSandboxesData, ListSandboxesResponse, ListSandboxesResponse2, ListSandboxesResponses, ListScansQuery, ListScheduleRunJobsData, ListScheduleRunJobsError, ListScheduleRunJobsErrors, ListScheduleRunJobsResponse, ListScheduleRunJobsResponses, ListScheduleRunsData, ListScheduleRunsError, ListScheduleRunsErrors, ListScheduleRunsResponse, ListScheduleRunsResponses, ListScheduleServicesData, ListScheduleServicesError, ListScheduleServicesErrors, ListScheduleServicesResponse, ListScheduleServicesResponses, ListSecretsData, ListSecretsErrors, ListSecretsResponse, ListSecretsResponse2, ListSecretsResponses, ListServiceHealthStatusesData, ListServiceHealthStatusesErrors, ListServiceHealthStatusesResponse, ListServiceHealthStatusesResponses, ListServiceProjectsData, ListServiceProjectsErrors, ListServiceProjectsResponse, ListServiceProjectsResponses, ListServiceSchedulesData, ListServiceSchedulesError, ListServiceSchedulesErrors, ListServiceSchedulesResponse, ListServiceSchedulesResponses, ListServicesData, ListServicesErrors, ListServicesResponse, ListServicesResponses, ListSkillsData, ListSkillsErrors, ListSkillsResponse, ListSkillsResponse2, ListSkillsResponses, ListSourceBackupsData, ListSourceBackupsError, ListSourceBackupsErrors, ListSourceBackupsResponse, ListSourceBackupsResponses, ListSourceFilesData, ListSourceFilesErrors, ListSourceFilesResponse, ListSourceFilesResponses, ListSourceMapsData, ListSourceMapsErrors, ListSourceMapsResponse, ListSourceMapsResponses, ListSourcesData, ListSourcesErrors, ListSourcesResponse, ListSourcesResponses, ListStaticBundlesData, ListStaticBundlesErrors, ListStaticBundlesResponse, ListStaticBundlesResponses, ListSyncedRepositoriesData, ListSyncedRepositoriesErrors, ListSyncedRepositoriesResponse, ListSyncedRepositoriesResponses, ListTagsResponse, ListTeamMembersData, ListTeamMembersErrors, ListTeamMembersResponse, ListTeamMembersResponses, ListTeamProjectsData, ListTeamProjectsErrors, ListTeamProjectsResponse, ListTeamProjectsResponses, ListTeamsData, ListTeamsErrors, ListTeamsResponse, ListTeamsResponses, ListTemplatesQuery, ListTemplatesResponse, ListUsersData, ListUsersErrors, ListUsersResponse, ListUsersResponses, ListVulnerabilitiesQuery, ListWebhooksData, ListWebhooksErrors, ListWebhooksResponse, ListWebhooksResponses, LiveVisitorInfo, LiveVisitorsListResponse, LocationCount, LocationGranularity, LocationInfo, LoginData, LoginErrors, LoginRequest, LoginResponse, LoginResponses, LogLevel, LogoutData, LogoutErrors, LogoutResponses, LogRecord, LogSearchLine, LogSeverity, LogSource, LogsQuery, LogsResponse, LogStream, LookupDnsARecordsData, LookupDnsARecordsError, LookupDnsARecordsErrors, LookupDnsARecordsResponse, LookupDnsARecordsResponses, ManagedDomainResponse, ManualAction, ManualActionTiming, McpDefinitionResponse, MessageContent, MessagePart, MessageResponse, MeteredMode, MetricAggregation, MetricBucket, MetricDataPoint, MetricsOverTimeResponse, MetricsQuery, MetricsRangeQuery, MetricsStatusResponse, MetricsStoreKind, MetricsSummaryResponse, MetricType, MfaRequiredResponse, MfaSetupResponse, MfaVerificationRequest, MigrationStep, MigrationSummary, MintEnrollmentTokenData, MintEnrollmentTokenErrors, MintEnrollmentTokenRequest, MintEnrollmentTokenResponse, MintEnrollmentTokenResponse2, MintEnrollmentTokenResponses, MiscResult, MkdirBody, MkdirData, MkdirErrors, MkdirResponse, MkdirResponses, ModelInfo, ModelListResponse, ModelPricing, ModelUsage, MonitoringSettings, MonitoringSettingsMasked, MonitorResponse, MonitorStatus, MrrBucketResponse, MultiNodeSettings, MultiNodeSettingsMasked, MxResult, NavEntry, NavSection, NetworkConfiguration, NetworkMode, NixpacksPresetConfig, NixpacksProvider, NodeContainerListResponse, NodeContainerResponse, NodeCostInfo, NodeHeartbeatData, NodeHeartbeatErrors, NodeHeartbeatResponse, NodeHeartbeatResponses, NodeInfoResponse, NodeListResponse, NodeMetricsGetRangeData, NodeMetricsGetRangeErrors, NodeMetricsGetRangeResponse, NodeMetricsGetRangeResponses, NotificationPreferencesResponse, NotificationProviderResponse, ObservabilityCompressionSettings, ObservabilityEvent, ObservabilityFullEventData, ObservabilityFullEventError, ObservabilityFullEventErrors, ObservabilityFullEventResponse, ObservabilityFullEventResponses, ObservabilityListEventsData, ObservabilityListEventsError, ObservabilityListEventsErrors, ObservabilityListEventsResponse, ObservabilityListEventsResponses, ObservabilityRetentionSettings, OidcCallbackData, OidcProviderResponse, OidcProvidersListResponse, OidcProviderSummary, OidcProviderUserResponse, OidcRoleMappingResponse, OidcTestConnectionResponse, OnDemandCertAttemptResponse, OnDemandCertRow, OnDemandTlsSettings, OpenAiError, OpenAiErrorResponse, OperatingSystemCount, OperationResultResponse, OperationResultsResponse, OtelDashboardResponse, OtelDashboardsResponse, OtelMetricAlertRuleResponse, OtelMetricAlertsResponse, OtelMetricLabelKeysResponse, OtelMetricLabelValuesResponse, OtelMetricNamesResponse, OtelMetricsResponse, OutlierAlgorithm, OutlierParams, OverprovisioningAssessment, OverprovisioningVerdict, PageActivityBucket, PageCountryStats, PageFlowEntry, PageFlowQuery, PageFlowResponse, PageHourlySessionsQuery, PageHourlySessionsResponse, PagePathDetailQuery, PagePathDetailResponse, PagePathInfo, PagePathSparkline, PagePathSparklinePoint, PagePathsQuery, PagePathsResponse, PagePathsSparklineQuery, PagePathsSparklineResponse, PagePathVisitorsQuery, PagePathVisitorsResponse, PageReferrerStats, PagesComparisonResponse, PageSessionComparison, PageSessionStats, PageSessionStatsQuery, PageTransition, PageVisit, PageVisitorSession, PaginatedEmailsResponse, PaginatedEntitiesResponse, PaginatedErrorEventsResponse, PaginatedErrorGroupsResponse, PaginatedEventsResponse, PaginatedExternalImagesResponse, PaginatedProjectList, PaginatedStaticBundlesResponse, Pagination, PaginationMeta, PaginationParams, PasswordProtectionConfig, PatchAdminGateData, PatchAdminGateErrors, PatchAdminGateResponse, PatchAdminGateResponses, PatchPreviewGatewaySettingsData, PatchPreviewGatewaySettingsResponse, PatchPreviewGatewaySettingsResponses, PatchSettingsRequest, PathVisitors, PathVisitorsAnalyticsQuery, PathVisitorsResponse, PauseDeploymentData, PauseDeploymentErrors, PauseDeploymentResponse, PauseDeploymentResponses, PauseSandboxData, PauseSandboxErrors, PauseSandboxResponse, PauseSandboxResponses, PeerEntry, PeerListResponse, PendingActionResponse, PerformanceMetricsQuery, PerformanceMetricsResponse, PermissionInfo, PgUpgradeLogResponse, PgUpgradeResponse, PipelineStats, PipelineStatsResponse, PlanComplexity, PlanMetadata, PlanRestoreData, PlanRestoreError, PlanRestoreErrors, PlanRestoreResponse, PlanRestoreResponses, PlanSourceBackup, PlanTarget, PlatformInfo, PluginManifest, PortMapping, PostDnsAckData, PostDnsAckErrors, PostDnsAckResponse, PostDnsAckResponses, PostgresWalHealth, PresetConfigSchema, PresetInfo, PresetResponse, PreviewAlertData, PreviewAlertError, PreviewAlertErrors, PreviewAlertResponse, PreviewAlertResponses, PreviewFunnelMetricsData, PreviewFunnelMetricsErrors, PreviewFunnelMetricsResponse, PreviewFunnelMetricsResponses, PreviewGatewaySettings, PreviewGatewaySettingsMasked, PreviewGatewaySettingsResponse, PreviewHostnameModeData, PreviewHostnameModeErrors, PreviewHostnameModeResponse, PreviewHostnameModeResponses, PreviewShareLinkBody, PreviewShareLinkResponse, PricingResponse, ProblemDetails, ProjectAccessResponse, ProjectConfiguration, ProjectDashboardAnalytics, ProjectDsnResponse, ProjectHealthSummary, ProjectInfo, ProjectMonitorHealth, ProjectPresetResponse, ProjectQuery, ProjectRef, ProjectResponse, ProjectSecretEnvironmentInfo, ProjectSecretResponse, ProjectServiceInfo, ProjectsHealthResponse, ProjectsMonitorHealthResponse, ProjectStatisticsResponse, ProjectStatsBreakdown, ProjectType, ProjectUsageInfoResponse, PromoteClusterMemberData, PromoteClusterMemberErrors, PromoteClusterMemberResponses, PromoteDeploymentData, PromoteDeploymentErrors, PromoteDeploymentRequest, PromoteDeploymentResponse, PromoteDeploymentResponses, PropertyBreakdownItem, PropertyBreakdownQuery, PropertyBreakdownResponse, PropertyColumn, PropertyTimelineItem, PropertyTimelineQuery, PropertyTimelineResponse, Protocol, ProviderCatalogDto, ProviderCatalogResponse, ProviderConfig, ProviderConfigMasked, ProviderDeletionCheckResponse, ProviderDescriptor, ProviderKeyResponse, ProviderMetadata, ProviderResponse, ProviderUsage, ProvisionDomainData, ProvisionDomainErrors, ProvisionDomainResponse, ProvisionDomainResponses, ProvisionResponse, ProxyLogResponse, ProxyLogsPaginatedResponse, PublicHostnameStrategy, PublicPresetResponse, PublicRepositoryInfo, PurgeLogsRequest, PurgeProjectLogsData, PurgeProjectLogsError, PurgeProjectLogsErrors, PurgeProjectLogsResponses, PushedExternalImageResponse, PushExternalImageData, PushExternalImageErrors, PushExternalImageResponse, PushExternalImageResponses, PushImageRequest, QueryDataData, QueryDataErrors, QueryDataRequest, QueryDataResponse, QueryDataResponse2, QueryDataResponses, QueryGenaiTracesData, QueryGenaiTracesError, QueryGenaiTracesErrors, QueryGenaiTracesResponse, QueryGenaiTracesResponses, QueryLogsData, QueryLogsError, QueryLogsErrors, QueryLogsResponse, QueryLogsResponses, QueryMetricsData, QueryMetricsError, QueryMetricsErrors, QueryMetricsResponse, QueryMetricsResponses, QueryTracesData, QueryTracesError, QueryTracesErrors, QueryTracesResponse, QueryTracesResponses, QueryTraceSummariesData, QueryTraceSummariesError, QueryTraceSummariesErrors, QueryTraceSummariesResponse, QueryTraceSummariesResponses, QuotaResponse, RateLimitConfig, RateLimitSettings, ReachabilityStatus, ReadFileData, ReadFileErrors, ReadFileResponse, ReadFileResponse2, ReadFileResponses, ReAnalyzeData, ReAnalyzeErrors, ReAnalyzeResponses, RecentActivityQuery, RecentActivityResponse, RecentEventResponse, RecentQueryParams, RecordConsoleEventData, RecordConsoleEventErrors, RecordConsoleEventResponses, RecordEventMetricsData, RecordEventMetricsErrors, RecordEventMetricsResponse, RecordEventMetricsResponses, RecordExposureRequest, RecordExposureResponse, RecordFlagExposureData, RecordFlagExposureErrors, RecordFlagExposureResponse, RecordFlagExposureResponses, RecordListResponse, RecordSpeedMetricsData, RecordSpeedMetricsError, RecordSpeedMetricsErrors, RecordSpeedMetricsResponse, RecordSpeedMetricsResponses, RecoveryTarget, ReferrerCount, ReferrersAnalyticsQuery, RefreshRouteTableData, RefreshRouteTableErrors, RefreshRouteTableResponse, RefreshRouteTableResponses, RegenerateDsnData, RegenerateDsnErrors, RegenerateDsnRequest, RegenerateDsnResponse, RegenerateDsnResponses, RegisterExternalImageData, RegisterExternalImageErrors, RegisterExternalImageResponse, RegisterExternalImageResponses, RegisterImageRequest, RegisterNodeApiRequest, RegisterNodeData, RegisterNodeErrors, RegisterNodeResponse, RegisterNodeResponse2, RegisterNodeResponses, RegisterRequest, ReinstallGitlabWebhookData, ReinstallGitlabWebhookErrors, ReinstallGitlabWebhookResponse, ReinstallGitlabWebhookResponses, ReinstallWebhookResponse, RejectPendingActionData, RejectPendingActionErrors, RejectPendingActionResponse, RejectPendingActionResponses, ReleaseListResponse, ReloadPluginsData, ReloadPluginsErrors, ReloadPluginsResponse, ReloadPluginsResponses, ReloadResponse, RemoteDeploymentResponse, RemoveClusterMemberData, RemoveClusterMemberErrors, RemoveClusterMemberResponse, RemoveClusterMemberResponses, RemoveManagedDomainData, RemoveManagedDomainErrors, RemoveManagedDomainResponse, RemoveManagedDomainResponses, RemoveNodeResponse, RemoveRoleData, RemoveRoleErrors, RemoveRoleResponse, RemoveRoleResponses, RemoveTeamMemberData, RemoveTeamMemberErrors, RemoveTeamMemberResponse, RemoveTeamMemberResponses, RenameConversationData, RenameConversationErrors, RenameConversationRequest, RenameConversationResponse, RenameConversationResponses, RenewDomainData, RenewDomainErrors, RenewDomainResponse, RenewDomainResponses, RepositoryListQuery, RepositoryListResponse, RepositoryPresetResponse, RepositoryResponse, RepositorySyncStartedResponse, RequestPasswordResetData, RequestPasswordResetErrors, RequestPasswordResetResponse, RequestPasswordResetResponses, RequestRow, RequiredPasswordChangeRequest, RequiredPasswordChangeResponse, ResetPasswordData, ResetPasswordErrors, ResetPasswordRequest, ResetPasswordResponse, ResetPasswordResponses, ResetPgStatStatementsRequest, ResetPgStatStatementsResponse, ResizeSandboxBody, ResizeSandboxData, ResizeSandboxErrors, ResizeSandboxResponse, ResizeSandboxResponses, ResolveAlarmData, ResolveAlarmErrors, ResolveAlarmResponses, ResolvedEnvVarResponse, ResolvedEnvVarSource, ResourceCounts, ResourceFootprint, ResourceInfo, ResourceLimitApplyResult, ResourceLimits, ResourceLimitsResponse, ResourceLimitsUpdateResponse, ResourcesBody, RestartContainerData, RestartContainerErrors, RestartContainerResponse, RestartContainerResponses, RestartPreviewGatewayData, RestartPreviewGatewayResponse, RestartPreviewGatewayResponses, RestartSandboxData, RestartSandboxErrors, RestartSandboxResponse, RestartSandboxResponses, RestoreCapabilities, RestoreCapabilitiesResponse, RestoreFlagData, RestoreFlagErrors, RestoreFlagResponse, RestoreFlagResponses, RestorePlan, RestoreRequestMode, RestoreRunView, RestoreUserData, RestoreUserErrors, RestoreUserResponse, RestoreUserResponses, ResumeDeploymentData, ResumeDeploymentErrors, ResumeDeploymentResponse, ResumeDeploymentResponses, ResumeSandboxData, ResumeSandboxErrors, ResumeSandboxResponse, ResumeSandboxResponses, RetentionCleanupFailure, RetentionCleanupReport, RetryClusterData, RetryClusterErrors, RetryClusterRequest, RetryClusterResponse, RetryClusterResponses, RetryDeliveryData, RetryDeliveryErrors, RetryDeliveryResponse, RetryDeliveryResponses, RetryPgUpgradeData, RetryPgUpgradeErrors, RetryPgUpgradeResponse, RetryPgUpgradeResponses, RetryRunData, RetryRunErrors, RetryRunResponse, RetryRunResponses, RevealGlobalMcpConfigData, RevealGlobalMcpConfigErrors, RevealGlobalMcpConfigResponse, RevealGlobalMcpConfigResponses, RevealMcpConfigData, RevealMcpConfigErrors, RevealMcpConfigResponse, RevealMcpConfigResponses, RevealNotificationProviderConfigData, RevealNotificationProviderConfigErrors, RevealNotificationProviderConfigResponse, RevealNotificationProviderConfigResponses, RevealServiceParameterData, RevealServiceParameterErrors, RevealServiceParameterResponse, RevealServiceParameterResponses, RevenueCreateIntegrationData, RevenueCreateIntegrationErrors, RevenueCreateIntegrationResponse, RevenueCreateIntegrationResponses, RevenueDeleteIntegrationData, RevenueDeleteIntegrationResponse, RevenueDeleteIntegrationResponses, RevenueGlobalEventsData, RevenueGlobalEventsResponse, RevenueGlobalEventsResponses, RevenueImportInvoicesCsvData, RevenueImportInvoicesCsvErrors, RevenueImportInvoicesCsvResponse, RevenueImportInvoicesCsvResponses, RevenueImportSubscriptionsCsvData, RevenueImportSubscriptionsCsvErrors, RevenueImportSubscriptionsCsvResponse, RevenueImportSubscriptionsCsvResponses, RevenueListIntegrationsData, RevenueListIntegrationsResponse, RevenueListIntegrationsResponses, RevenueListProvidersData, RevenueListProvidersResponse, RevenueListProvidersResponses, RevenueMetricsCustomersData, RevenueMetricsCustomersResponse, RevenueMetricsCustomersResponses, RevenueMetricsGlobalMrrData, RevenueMetricsGlobalMrrResponse, RevenueMetricsGlobalMrrResponses, RevenueMetricsGlobalSummaryData, RevenueMetricsGlobalSummaryResponse, RevenueMetricsGlobalSummaryResponses, RevenueMetricsMrrData, RevenueMetricsMrrResponse, RevenueMetricsMrrResponses, RevenueMetricsSummaryData, RevenueMetricsSummaryResponse, RevenueMetricsSummaryResponses, RevenueRecentEventsData, RevenueRecentEventsResponse, RevenueRecentEventsResponses, RevenueRotateTokenData, RevenueRotateTokenResponse, RevenueRotateTokenResponses, RevenueRow, RevenueUpdateConfigData, RevenueUpdateConfigErrors, RevenueUpdateConfigResponse, RevenueUpdateConfigResponses, RevenueUpdateSecretData, RevenueUpdateSecretErrors, RevenueUpdateSecretResponse, RevenueUpdateSecretResponses, RevokeDsnData, RevokeDsnErrors, RevokeDsnResponse, RevokeDsnResponses, RevokeEnrollmentTokenData, RevokeEnrollmentTokenErrors, RevokeEnrollmentTokenResponse, RevokeEnrollmentTokenResponses, RevokeJoinTokenData, RevokeJoinTokenErrors, RevokeJoinTokenResponse, RevokeJoinTokenResponses, RevokeProjectAccessData, RevokeProjectAccessErrors, RevokeProjectAccessResponse, RevokeProjectAccessResponses, RiskLevel, RoleInfo, RollbackPgUpgradeData, RollbackPgUpgradeErrors, RollbackPgUpgradeResponse, RollbackPgUpgradeResponses, RollbackToDeploymentData, RollbackToDeploymentErrors, RollbackToDeploymentResponse, RollbackToDeploymentResponses, RootfsCacheEntry, RootfsGcData, RootfsGcReport, RootfsGcResponses, RootfsReport, RootfsReportData, RootfsReportResponses, RootfsVmEntry, RotateApiKeyData, RotateApiKeyErrors, RotateApiKeyResponse, RotateApiKeyResponses, RotateDeploymentTokenData, RotateDeploymentTokenErrors, RotateDeploymentTokenResponse, RotateDeploymentTokenResponses, RouteRefreshResponse, RouteResponse, RouteRole, RouteUser, RouteUserWithRoles, RunBackupForSourceData, RunBackupForSourceError, RunBackupForSourceErrors, RunBackupForSourceResponse, RunBackupForSourceResponses, RunBackupRequest, RunConnectionHealthCheckData, RunConnectionHealthCheckErrors, RunConnectionHealthCheckResponse, RunConnectionHealthCheckResponses, RunExternalServiceBackupData, RunExternalServiceBackupError, RunExternalServiceBackupErrors, RunExternalServiceBackupRequest, RunExternalServiceBackupResponse, RunExternalServiceBackupResponses, RunScheduleNowData, RunScheduleNowError, RunScheduleNowErrors, RunScheduleNowResponse, RunScheduleNowResponses, S3ConnectionTestResponse, S3CredentialsResponse, S3SourceResponse, S3SourceResponseWritable, SandboxCreatePreviewLinkData, SandboxCreatePreviewLinkErrors, SandboxCreatePreviewLinkResponse, SandboxCreatePreviewLinkResponses, SandboxDomainResponse, SandboxEvent, SandboxEventsResponse, SandboxInner, SandboxResponse, SandboxRoute, SandboxStatusResponse, SaveAgentTokenData, SaveAgentTokenErrors, SaveAgentTokenRequest, SaveAgentTokenResponse, SaveAgentTokenResponse2, SaveAgentTokenResponses, SaveAiProviderCredentialData, SaveAiProviderCredentialErrors, SaveAiProviderCredentialResponse, SaveAiProviderCredentialResponses, SaveCredentialRequest, SaveCredentialResponse, ScalewayCredentialsRequest, ScanResponse, ScheduleRunEntry, ScheduleRunJobEntry, ScheduleRunListResponse, ScheduleRunResponse, ScheduleRunSummary, ScheduleRunSummaryList, ScreenshotSettings, SearchLogsData, SearchLogsError, SearchLogsErrors, SearchLogsRequest, SearchLogsResponse, SearchLogsResponse2, SearchLogsResponses, SearchMode, Seasonality, SecretResponse, SecurityConfig, SecurityHeadersConfig, SecurityHeadersSettings, SelfUpdateAttempt, SelfUpdateBlocker, SelfUpdatePhase, SelfUpdateSettings, SelfUpdateStatus, SendEmailData, SendEmailErrors, SendEmailRequestBody, SendEmailResponse, SendEmailResponseBody, SendEmailResponses, SendMessageRequest, SensitiveConfigValueResponse, SensitiveMcpConfigValueResponse, SensitiveValueResponse, SentryChunkUploadResponse, SentryCreateReleaseRequest, SentryEventRequest, SentryEventResponse, SentryReleaseFileResponse, SentryReleaseProjectRef, SentryReleaseResponse, SeriesStateEntry, ServiceAccessInfo, ServiceAction, ServiceAlertRuleResponse, ServiceBackupEntryResponse, ServiceBackupListResponse, ServiceCreateAlertRuleRequest, ServiceHealthResponse, ServiceHealthStatusBatchResponse, ServiceHealthStatusEntryResponse, ServiceMemberInfo, ServiceParameter, ServicePlan, ServiceResourceLimits, ServiceRuntimeReport, ServiceStatsReport, ServiceTypeInfo, ServiceTypeRoute, ServiceUpdateAlertRuleRequest, SesCredentialsRequest, SessionDetails, SessionDetailsQuery, SessionEvent, SessionEventDto, SessionEventsQuery, SessionEventsResponse, SessionLogsQuery, SessionLogsResponse, SessionReplayEventsRequest, SessionReplayInfoDto, SessionReplayInitRequest, SessionReplayInitResponse, SessionReplayWithEventsDto, SessionReplayWithVisitorDto, SessionRequestLog, SessionSummary, SetDefaultS3SourceData, SetDefaultS3SourceError, SetDefaultS3SourceErrors, SetDefaultS3SourceResponse, SetDefaultS3SourceResponses, SetFlagEnvironmentData, SetFlagEnvironmentErrors, SetFlagEnvironmentRequest, SetFlagEnvironmentResponse, SetFlagEnvironmentResponses, SetPreviewPasswordBody, SetPreviewPasswordData, SetPreviewPasswordErrors, SetPreviewPasswordResponse, SetPreviewPasswordResponse2, SetPreviewPasswordResponses, SetRequest, SetResponse, SettingsUpdateResponse, SetupDnsChallengeData, SetupDnsChallengeErrors, SetupDnsChallengeRequest, SetupDnsChallengeResponse, SetupDnsChallengeResponse2, SetupDnsChallengeResponses, SetupDnsData, SetupDnsErrors, SetupDnsRequest, SetupDnsResponse, SetupDnsResponse2, SetupDnsResponses, SetupEmailTrackingData, SetupEmailTrackingErrors, SetupEmailTrackingResponse, SetupEmailTrackingResponses, SetupMfaData, SetupMfaErrors, SetupMfaResponse, SetupMfaResponses, SiblingRef, SkillDefinitionResponse, SlackConfig, SleepEnvironmentData, SleepEnvironmentErrors, SleepEnvironmentResponse, SleepEnvironmentResponses, SlowQueriesResponse, SlowQueryRow, SmartFilter, SmokeTestAgentData, SmokeTestAgentErrors, SmokeTestAgentResponse, SmokeTestAgentResponses, SmokeTestResponse, SmtpCredentialsRequest, SmtpEncryptionRoute, SmtpResult, SourceArchiveUpload, SourceBackupEntry, SourceBackupIndexResponse, SourceBody, SourceFileListResponse, SourceFileResponse, SourceMapListResponse, SourceMapResponse, SourceSandboxData, SourceSandboxErrors, SourceSandboxResponse, SourceSandboxResponses, SourceType, SpanEvent, SpanKind, SpanRecord, SpanRow, SpanStatusCode, SpeedMetricsPayload, SpeedSegmentFilters, StaleSlot, StartAnalysisData, StartAnalysisErrors, StartAnalysisRequest, StartAnalysisResponse, StartAnalysisResponses, StartContainerData, StartContainerErrors, StartContainerResponse, StartContainerResponses, StartFixData, StartFixErrors, StartFixResponses, StartGitProviderOauthData, StartGitProviderOauthErrors, StartOidcLoginBySlugData, StartOidcLoginBySlugErrors, StartPgUpgradeData, StartPgUpgradeErrors, StartPgUpgradeRequest, StartPgUpgradeResponse, StartPgUpgradeResponses, StartRestoreData, StartRestoreError, StartRestoreErrors, StartRestoreRequest, StartRestoreResponse, StartRestoreResponses, StartServiceData, StartServiceErrors, StartServiceResponse, StartServiceResponses, StartUpdateData, StartUpdateError, StartUpdateErrors, StartUpdateRequest, StartUpdateResponse, StartUpdateResponse2, StartUpdateResponses, StaticBundleResponse, StaticParams, StaticPresetConfig, StatPathData, StatPathErrors, StatPathResponse, StatPathResponses, StatResponse, StatsFilters, StatusBucket, StatusBucketedResponse, StatusCodeCount, StatusCodesQuery, StatusPageOverview, StepConversionResponse, StepResourceType, StepResult, StepUpResponse, StopContainerData, StopContainerErrors, StopContainerResponse, StopContainerResponses, StopSandboxData, StopSandboxErrors, StopSandboxResponse, StopSandboxResponses, StopSequence, StopServiceData, StopServiceErrors, StopServiceResponse, StopServiceResponses, StorageQuota, StreamContainerMetricsData, StreamContainerMetricsErrors, StreamContainerMetricsResponses, StreamEventsData, StreamEventsErrors, StreamEventsResponses, StreamRunEventsData, StreamRunEventsErrors, StreamRunEventsResponses, StripeConfig, SupervisorKind, SyncedRepositoryListQuery, SyncRepositoriesData, SyncRepositoriesErrors, SyncRepositoriesResponse, SyncRepositoriesResponses, SyntaxResult, TagInfo, TagListResponse, TailDeploymentJobLogsData, TailDeploymentJobLogsErrors, TailLogsData, TailLogsError, TailLogsErrors, TailLogsRequest, TailLogsResponses, TargetRecommendation, TeamListResponse, TeamMemberResponse, TeamResponse, TeamRole, TeardownDeploymentData, TeardownDeploymentErrors, TeardownDeploymentResponse, TeardownDeploymentResponses, TeardownEnvironmentData, TeardownEnvironmentErrors, TeardownEnvironmentResponse, TeardownEnvironmentResponses, TemplateResponse, TestEmailRequest, TestEmailResponse, TestNotificationProviderData, TestNotificationProviderErrors, TestNotificationProviderResponse, TestNotificationProviderResponses, TestOidcProviderData, TestOidcProviderResponse, TestOidcProviderResponses, TestProviderConnectionData, TestProviderConnectionErrors, TestProviderConnectionResponse, TestProviderConnectionResponses, TestProviderData, TestProviderErrors, TestProviderKeyByIdData, TestProviderKeyByIdError, TestProviderKeyByIdErrors, TestProviderKeyByIdResponse, TestProviderKeyByIdResponses, TestProviderKeyInlineData, TestProviderKeyInlineError, TestProviderKeyInlineErrors, TestProviderKeyInlineResponse, TestProviderKeyInlineResponses, TestProviderKeyRequest, TestProviderKeyResponse, TestProviderResponse, TestProviderResponse2, TestProviderResponses, TestS3ConnectionPreviewData, TestS3ConnectionPreviewError, TestS3ConnectionPreviewErrors, TestS3ConnectionPreviewResponse, TestS3ConnectionPreviewResponses, TestS3SourceConnectionData, TestS3SourceConnectionError, TestS3SourceConnectionErrors, TestS3SourceConnectionResponse, TestS3SourceConnectionResponses, TimeBucketStats, TimeBucketStatsResponse, TimeseriesBucket, TimeseriesQueryParams, TlsMode, TodayStatsResponse, ToggleDeploymentMetricsRequest, ToggleServiceMetricsRequest, TokenRenewalRequest, ToolCallEvent, ToolInfo, ToolResultEvent, TopModelsQueryParams, TraceProjectRef, TracesResponse, TraceSummariesResponse, TraceSummary, TrackClickData, TrackClickErrors, TrackedLinkResponse, TrackingEventResponse, TrackOpenData, TrackOpenErrors, TrackOpenResponses, TriggerAgentData, TriggerAgentErrors, TriggerAgentRequest, TriggerAgentResponse, TriggerAgentResponses, TriggerDigestResponse, TriggerPipelinePayload, TriggerPipelineResponse, TriggerProjectPipelineData, TriggerProjectPipelineErrors, TriggerProjectPipelineResponse, TriggerProjectPipelineResponses, TriggerScanData, TriggerScanError, TriggerScanErrors, TriggerScanRequest, TriggerScanResponse, TriggerScanResponse2, TriggerScanResponses, TriggerServiceHealthCheckData, TriggerServiceHealthCheckErrors, TriggerServiceHealthCheckResponse, TriggerServiceHealthCheckResponses, TriggerWeeklyDigestData, TriggerWeeklyDigestErrors, TriggerWeeklyDigestResponse, TriggerWeeklyDigestResponses, TtlRequest, TtlResponse, TxtRecord, UiManifest, UiRoute, UndrainNodeResponse, UnifiedTrace, UniqueCountsQuery, UniqueCountsResponse, UnlinkServiceFromProjectData, UnlinkServiceFromProjectErrors, UnlinkServiceFromProjectResponse, UnlinkServiceFromProjectResponses, UnsupportedFeature, UpdateAdminGateRequest, UpdateAgentData, UpdateAgentErrors, UpdateAgentResponse, UpdateAgentResponses, UpdateAiProviderData, UpdateAiProviderErrors, UpdateAiProviderRequest, UpdateAiProviderResponse, UpdateAiProviderResponse2, UpdateAiProviderResponses, UpdateAlertData, UpdateAlertError, UpdateAlertErrors, UpdateAlertResponse, UpdateAlertResponses, UpdateAlertRuleData, UpdateAlertRuleErrors, UpdateAlertRuleRequest, UpdateAlertRuleResponse, UpdateAlertRuleResponses, UpdateApiKeyData, UpdateApiKeyErrors, UpdateApiKeyRequest, UpdateApiKeyResponse, UpdateApiKeyResponses, UpdateAutomaticDeployData, UpdateAutomaticDeployErrors, UpdateAutomaticDeployRequest, UpdateAutomaticDeployResponse, UpdateAutomaticDeployResponses, UpdateBackupScheduleData, UpdateBackupScheduleError, UpdateBackupScheduleErrors, UpdateBackupScheduleRequest, UpdateBackupScheduleResponse, UpdateBackupScheduleResponses, UpdateBlobRequest, UpdateBlobResponse, UpdateCapabilityResponse, UpdateCloudflareProviderData, UpdateCloudflareProviderErrors, UpdateCloudflareProviderRequest, UpdateCloudflareProviderResponse, UpdateCloudflareProviderResponses, UpdateConfigBody, UpdateConnectionTokenData, UpdateConnectionTokenErrors, UpdateConnectionTokenResponse, UpdateConnectionTokenResponses, UpdateCustomDomainData, UpdateCustomDomainErrors, UpdateCustomDomainRequest, UpdateCustomDomainResponse, UpdateCustomDomainResponses, UpdateDashboardData, UpdateDashboardError, UpdateDashboardErrors, UpdateDashboardRequest, UpdateDashboardResponse, UpdateDashboardResponses, UpdateDeploymentConfigRequest, UpdateDeploymentTokenData, UpdateDeploymentTokenErrors, UpdateDeploymentTokenRequest, UpdateDeploymentTokenResponse, UpdateDeploymentTokenResponses, UpdateDnsProviderRequest, UpdateEmailProviderData, UpdateEmailProviderErrors, UpdateEmailProviderRequest, UpdateEmailProviderResponse, UpdateEmailProviderResponses, UpdateEnvironmentSettingsData, UpdateEnvironmentSettingsErrors, UpdateEnvironmentSettingsRequest, UpdateEnvironmentSettingsResponse, UpdateEnvironmentSettingsResponses, UpdateEnvironmentSubdomainData, UpdateEnvironmentSubdomainErrors, UpdateEnvironmentSubdomainRequest, UpdateEnvironmentSubdomainResponse, UpdateEnvironmentSubdomainResponses, UpdateEnvironmentVariableData, UpdateEnvironmentVariableErrors, UpdateEnvironmentVariableRequest, UpdateEnvironmentVariableResponse, UpdateEnvironmentVariableResponses, UpdateErrorGroupData, UpdateErrorGroupErrors, UpdateErrorGroupRequest, UpdateErrorGroupResponses, UpdateExternalServiceRequest, UpdateFlagData, UpdateFlagErrors, UpdateFlagRequest, UpdateFlagResponse, UpdateFlagResponses, UpdateFunnelData, UpdateFunnelErrors, UpdateFunnelResponses, UpdateGitProviderCredentialsData, UpdateGitProviderCredentialsErrors, UpdateGitProviderCredentialsResponse, UpdateGitProviderCredentialsResponses, UpdateGitSettingsData, UpdateGitSettingsErrors, UpdateGitSettingsRequest, UpdateGitSettingsResponse, UpdateGitSettingsResponses, UpdateGlobalMcpData, UpdateGlobalMcpErrors, UpdateGlobalMcpResponse, UpdateGlobalMcpResponses, UpdateGlobalSkillData, UpdateGlobalSkillErrors, UpdateGlobalSkillResponse, UpdateGlobalSkillResponses, UpdateIncidentStatusData, UpdateIncidentStatusErrors, UpdateIncidentStatusRequest, UpdateIncidentStatusResponse, UpdateIncidentStatusResponses, UpdateIpAccessControlData, UpdateIpAccessControlError, UpdateIpAccessControlErrors, UpdateIpAccessControlRequest, UpdateIpAccessControlResponse, UpdateIpAccessControlResponses, UpdateKvRequest, UpdateKvResponse, UpdateManagedDomainApiRequest, UpdateManagedDomainData, UpdateManagedDomainErrors, UpdateManagedDomainResponse, UpdateManagedDomainResponses, UpdateMcpData, UpdateMcpErrors, UpdateMcpRequest, UpdateMcpResponse, UpdateMcpResponses, UpdateMemberRoleRequest, UpdateMetricAlertRequest, UpdateNotificationEmailProviderData, UpdateNotificationEmailProviderErrors, UpdateNotificationEmailProviderRequest, UpdateNotificationEmailProviderResponse, UpdateNotificationEmailProviderResponses, UpdateNotificationProviderData, UpdateNotificationProviderErrors, UpdateNotificationProviderResponse, UpdateNotificationProviderResponses, UpdateOidcProviderData, UpdateOidcProviderRequest, UpdateOidcProviderResponse, UpdateOidcProviderResponses, UpdatePreferencesData, UpdatePreferencesErrors, UpdatePreferencesRequest, UpdatePreferencesResponse, UpdatePreferencesResponses, UpdateProjectData, UpdateProjectDeploymentConfigData, UpdateProjectDeploymentConfigErrors, UpdateProjectDeploymentConfigResponse, UpdateProjectDeploymentConfigResponses, UpdateProjectErrors, UpdateProjectResponse, UpdateProjectResponses, UpdateProjectSecretData, UpdateProjectSecretErrors, UpdateProjectSecretRequest, UpdateProjectSecretResponse, UpdateProjectSecretResponses, UpdateProjectSettingsData, UpdateProjectSettingsErrors, UpdateProjectSettingsRequest, UpdateProjectSettingsResponse, UpdateProjectSettingsResponses, UpdateProviderCredentialsRequest, UpdateProviderData, UpdateProviderErrors, UpdateProviderKeyData, UpdateProviderKeyError, UpdateProviderKeyErrors, UpdateProviderKeyRequest, UpdateProviderKeyResponse, UpdateProviderKeyResponses, UpdateProviderRequest, UpdateProviderResponse, UpdateProviderResponses, UpdateRouteData, UpdateRouteErrors, UpdateRouteRequest, UpdateRouteResponse, UpdateRouteResponses, UpdateS3SourceData, UpdateS3SourceError, UpdateS3SourceErrors, UpdateS3SourceRequest, UpdateS3SourceResponse, UpdateS3SourceResponses, UpdateSecretBody, UpdateSelfData, UpdateSelfErrors, UpdateSelfRequest, UpdateSelfResponse, UpdateSelfResponses, UpdateServiceData, UpdateServiceErrors, UpdateServiceResourcesData, UpdateServiceResourcesErrors, UpdateServiceResourcesResponse, UpdateServiceResourcesResponses, UpdateServiceResponse, UpdateServiceResponses, UpdateSessionDurationData, UpdateSessionDurationError, UpdateSessionDurationErrors, UpdateSessionDurationRequest, UpdateSessionDurationResponse, UpdateSessionDurationResponse2, UpdateSessionDurationResponses, UpdateSettingsData, UpdateSettingsErrors, UpdateSettingsResponse, UpdateSettingsResponses, UpdateSkillData, UpdateSkillErrors, UpdateSkillRequest, UpdateSkillResponse, UpdateSkillResponses, UpdateSlackProviderData, UpdateSlackProviderErrors, UpdateSlackProviderRequest, UpdateSlackProviderResponse, UpdateSlackProviderResponses, UpdateSpeedMetricsData, UpdateSpeedMetricsError, UpdateSpeedMetricsErrors, UpdateSpeedMetricsPayload, UpdateSpeedMetricsResponse, UpdateSpeedMetricsResponses, UpdateStatusResponse, UpdateTeamData, UpdateTeamErrors, UpdateTeamMemberRoleData, UpdateTeamMemberRoleErrors, UpdateTeamMemberRoleResponse, UpdateTeamMemberRoleResponses, UpdateTeamRequest, UpdateTeamResponse, UpdateTeamResponses, UpdateTokenRequest, UpdateTokenResponse, UpdateUserData, UpdateUserErrors, UpdateUserRequest, UpdateUserResponse, UpdateUserResponses, UpdateWebhookData, UpdateWebhookErrors, UpdateWebhookProviderData, UpdateWebhookProviderErrors, UpdateWebhookProviderRequest, UpdateWebhookProviderResponse, UpdateWebhookProviderResponses, UpdateWebhookRequestBody, UpdateWebhookResponse, UpdateWebhookResponses, UpgradeExternalServiceRequest, UpgradePreviewGatewayData, UpgradePreviewGatewayResponse, UpgradePreviewGatewayResponses, UpgradeRequest, UpgradeServiceData, UpgradeServiceErrors, UpgradeServiceResponse, UpgradeServiceResponses, UploadGlobalSkillData, UploadGlobalSkillErrors, UploadGlobalSkillResponse, UploadGlobalSkillResponses, UploadReleaseFileData, UploadReleaseFileErrors, UploadReleaseFileResponse, UploadReleaseFileResponses, UploadSkillData, UploadSkillErrors, UploadSkillResponse, UploadSkillResponses, UploadSourceFileData, UploadSourceFileErrors, UploadSourceFileResponse, UploadSourceFileResponses, UploadSourceMapData, UploadSourceMapErrors, UploadSourceMapResponse, UploadSourceMapResponses, UploadStaticBundleData, UploadStaticBundleErrors, UploadStaticBundleResponse, UploadStaticBundleResponses, UpsertAgentRequest, UpsertSecretData, UpsertSecretErrors, UpsertSecretRequest, UpsertSecretResponse, UpsertSecretResponses, UptimeDataPoint, UptimeHistoryResponse, UsageFilter, UsageInfo, UsageLogEntry, UsageLogPage, UsageQueryParams, UsageSource, UsageSummary, UserResponse, ValidateConnectionData, ValidateConnectionErrors, ValidateConnectionResponse, ValidateConnectionResponses, ValidateEmailData, ValidateEmailErrors, ValidateEmailRequest, ValidateEmailResponse, ValidateEmailResponse2, ValidateEmailResponses, ValidationLevel, ValidationReport, ValidationResponse, ValidationResult, ValidationStatus, ValidationSummary, VerifyAndEnableMfaData, VerifyAndEnableMfaErrors, VerifyAndEnableMfaResponse, VerifyAndEnableMfaResponses, VerifyDomainData, VerifyDomainErrors, VerifyDomainResponse, VerifyDomainResponses, VerifyEmailData, VerifyEmailErrors, VerifyEmailResponse, VerifyEmailResponses, VerifyManagedDomainData, VerifyManagedDomainErrors, VerifyManagedDomainResponse, VerifyManagedDomainResponses, VerifyMfaChallengeData, VerifyMfaChallengeErrors, VerifyMfaChallengeResponse, VerifyMfaChallengeResponses, VerifyMfaRequest, VerifyStepUpData, VerifyStepUpErrors, VerifyStepUpRequest, VerifyStepUpResponse, VerifyStepUpResponses, ViewItem, ViewsOverTime, ViewsOverTimeQuery, VisitorDetails, VisitorFacets, VisitorFacetsQuery, VisitorFacetValue, VisitorInfo, VisitorJourneyQuery, VisitorJourneyResponse, VisitorLocationsQuery, VisitorRecord, VisitorSegmentFilters, VisitorSessionsQuery, VisitorSessionsResponse, VisitorsListQuery, VisitorsResponse, VisitorStats, VisitorWithGeolocation, VolumeMount, VolumeType, VulnerabilityResponse, WakeEnvironmentData, WakeEnvironmentErrors, WakeEnvironmentResponse, WakeEnvironmentResponses, WalWarning, WalWarningSeverity, WebhookConfig, WebhookDeliveryResponse, WebhookResponse, WebhookTriggerData, WebhookTriggerErrors, WebhookTriggerRequest, WebhookTriggerResponse, WebhookTriggerResponse2, WebhookTriggerResponses, WorkflowDryRunData, WorkflowDryRunErrors, WorkflowDryRunRequest, WorkflowDryRunResponse, WorkflowDryRunResponses, WorkloadDescriptor, WorkloadId, WorkloadStatus, WorkloadType, WriteFileBody, WriteFileData, WriteFileErrors, WriteFileResponse, WriteFileResponses, WriteFilesBody, WriteFilesData, WriteFilesErrors, WriteFilesResponse, WriteFilesResponse2, WriteFilesResponses, ZoneListResponse } from './types.gen'; +export { acknowledgeAlarm, activateAiProvider, activateApiKey, activateConnection, activateProvider, addClusterMember, addContext, addEnvironmentDomain, addEvents, addManagedDomain, addSessionReplayEvents, addTeamMember, adminDrainNode, adminDrainStatus, adminGetNode, adminListNodeContainers, adminListNodes, adminRemoveNode, adminUndrainNode, applyHostnameMode, archiveConversation, archiveFlag, assignRole, attachScheduleServices, blobCopy, blobDelete, blobDisable, blobDownload, blobEnable, blobHead, blobList, blobPut, blobStatus, blobUpdate, cancel, cancelBackup, cancelDeployment, cancelDomainOrder, cancelPgUpgrade, cancelRun, cancelScheduleRun, changePasswordSelf, changeProjectSource, changeRequiredPassword, chatCompletions, checkAnalyticsHasEvents, checkCommitExists, checkDomainStatus, checkExplorerSupport, checkForUpdate, checkIpBlocked, checkProviderDeletionSafety, chunkUploadOptions, cleanupExpiredBackups, clearPreviewPassword, cliDeviceApprove, cliDeviceDeny, cliDeviceLookup, cliDevicePoll, cliDeviceStart, cliLogout, cmd, cmdKill, cmdLogs, confirmPendingAction, containerMetricsGetHistory, createAgent, createAlert, createAlertRule, createApiKey, createBackupSchedule, createBitbucketProvider, createCloudflareProvider, createConversation, createCustomDomain, createDashboard, createDeploymentToken, createDnsProvider, createDomain, createDsn, createEmailDomain, createEmailProvider, createEnvironment, createEnvironmentVariable, createFlag, createFunnel, createGenericProvider, createGiteaPatProvider, createGithubPatProvider, createGitlabOauthProvider, createGitlabPatProvider, createGitProvider, createGlobalMcp, createGlobalSkill, createIncident, createIpAccessControl, createMcp, createMonitor, createNotificationEmailProvider, createNotificationProvider, createOidcProvider, createOidcRoleMapping, createOrRecreateOrder, createPlan, createPr, createProject, createProjectFromTemplate, createProjectRelease, createProjectSecret, createProviderKey, createRelease, createRoute, createS3Source, createSandbox, createService, createSkill, createSlackProvider, createTeam, createUser, createWebhook, createWebhookProvider, deactivateApiKey, deactivateConnection, deactivateProvider, deleteAgent, deleteAlert, deleteAlertRule, deleteApiKey, deleteBackup, deleteBackupSchedule, deleteConnection, deleteCustomDomain, deleteDashboard, deleteDeploymentToken, deleteDnsProvider, deleteDomain, deleteEmailDomain, deleteEmailProvider, deleteEnvironment, deleteEnvironmentDomain, deleteEnvironmentVariable, deleteExternalImage, deleteFunnel, deleteGitProvider, deleteGlobalMcp, deleteGlobalSkill, deleteIpAccessControl, deleteMcp, deleteMonitor, deleteNotificationProvider, deleteOidcProvider, deleteOidcRoleMapping, deletePreferences, deleteProject, deleteProjectSecret, deleteProviderKey, deleteProviderSafely, deleteReleaseSourceFiles, deleteReleaseSourceMaps, deleteRoute, deleteS3Source, deleteScan, deleteSecret, deleteService, deleteSessionReplay, deleteSkill, deleteSourceMap, deleteStaticBundle, deleteTeam, deleteUser, deleteWebhook, deployFromImage, deployFromImageUpload, deployFromStatic, deployFromUploadedSource, deploymentMetricsGetLatest, deploymentMetricsGetRange, deploymentMetricsToggle, destroySandbox, detachScheduleService, detectPublicPresets, disableBackupSchedule, disableMfa, discoverWorkloads, domain, downloadGlobalSkillArchive, downloadObject, downloadSkillArchive, emailStatus, embeddings, enableBackupSchedule, enrichVisitor, exec, execDetached, executeDeploymentOperation, executeImport, extendTimeout, externalServiceEnablePgStatStatements, externalServiceMetricsByDatabase, externalServiceMetricsCreateAlertRule, externalServiceMetricsDeleteAlertRule, externalServiceMetricsGetAlertRules, externalServiceMetricsGetLatest, externalServiceMetricsGetRange, externalServiceMetricsStatus, externalServiceMetricsToggle, externalServiceMetricsUpdateAlertRule, externalServiceResetPgStatStatements, finalizeOrder, finalizeProjectRelease, findConversation, generateJoinToken, generatePresetDockerfile, getAccessInfo, getActiveVisitors, getActivityGraph, getAdminGate, getAgent, getAggregatedBuckets, getAiAgentBreakdown, getAiAgentPages, getAiAgentTimeline, getAiPageBreakdown, getAiStatusBreakdown, getAlert, getAlertRule, getAllRepositoriesByName, getAnalyticsActiveVisitors, getAnalyticsEventsCount, getAnalyticsSessionEvents, getAnalyticsVisitorSessions, getApiKey, getApiKeyPermissions, getAuditLog, getBackup, getBackupSchedule, getBranchesByRepositoryId, getBucketedIncidents, getBucketedStatus, getChallengeToken, getChatReadiness, getCliStatus, getClusterHealth, getClusterMember, getCmd, getContainerDetail, getContainerEnvironmentVariable, getContainerInfo, getContainerLogs, getContainerLogsById, getContainerMetrics, getConversation, getConversationDetail, getConversations, getCronById, getCronExecutions, getCrossProjectTraceSiblings, getCurrentMonitorStatus, getCurrentUser, getCustomDomain, getDashboard, getDashboardProjectsAnalytics, getDelivery, getDeployment, getDeploymentContainerLogContent, getDeploymentJobLogs, getDeploymentJobs, getDeploymentOperations, getDeploymentOperationStatus, getDeploymentToken, getDiskStatus, getDnsChanges, getDnsProvider, getDomain, getDomainByHost, getDomainById, getDomainByName, getDomainDnsRecords, getDomainOrder, getEmail, getEmailEvents, getEmailLinks, getEmailProvider, getEmailStats, getEmailTracking, getEmailTrackingStatus, getEntityInfo, getEnvironment, getEnvironmentCrons, getEnvironmentDomains, getEnvironments, getEnvironmentVariables, getEnvironmentVariableValue, getErrorDashboardStats, getErrorEvent, getErrorGroup, getErrorStats, getErrorTimeSeries, getEventDetail, getEventEntries, getEventsCount, getEventsTimeline, getEventTypeBreakdown, getEventVisitors, getExternalImage, getFile, getFlag, getFlagSnapshot, getFunnelMetrics, getGenaiTrace, getGeneralStats, getGitProvider, getGlobalEvents, getGlobalEventStats, getGlobalMcp, getGlobalSandboxStatus, getGlobalSkill, getGroupedPageMetrics, getHealth, getHourlyVisits, getHttpChallengeDebug, getImportStatus, getIncident, getIncidentUpdates, getIpAccessControl, getIpGeolocation, getJoinTokenStatus, getLastDeployment, getLatestScan, getLatestScansPerEnvironment, getLiveVisitorsList, getLogContext, getMcp, getMetricsOverTime, getMonitor, getNotificationProvider, getOnDemandCertStatus, getOrCreateDsn, getPageFlow, getPageHourlySessions, getPagePathDetail, getPagePaths, getPagePathsSparklines, getPagePathVisitors, getPendingAction, getPerformanceMetrics, getPgUpgrade, getPgUpgradeLogs, getPipelineStats, getPlatformInfo, getPostgresWalHealth, getPreferences, getPreviewGatewayLogs, getPreviewGatewaySettings, getPreviewGatewayStatus, getPricing, getPrivateIp, getProject, getProjectAlarmsSummary, getProjectBySlug, getProjectDeployments, getProjects, getProjectServiceEnvironmentVariables, getProjectSessionReplays, getProjectsHealth, getProjectsMonitorHealth, getProjectStatistics, getProjectTemplate, getPropertyBreakdown, getPropertyTimeline, getProviderConnections, getProviderMetadata, getProvidersMetadata, getProxyLogById, getProxyLogByRequestId, getProxyLogs, getPublicBranches, getPublicIp, getPublicRepository, getQuota, getRecentActivity, getRemoteExternalImage, getRepositoryBranches, getRepositoryById, getRepositoryByName, getRepositoryPresetByName, getRepositoryPresetLive, getRepositoryTags, getResolvedEnvironmentVariables, getResolvedEnvironmentVariableValue, getRestoreCapabilities, getRestoreRun, getRoute, getRun, getRunWithLogs, getS3Credentials, getS3Source, getSandbox, getSandboxStatus, getScan, getScanByDeployment, getScanVulnerabilities, getService, getServiceBySlug, getServiceEnvironmentVariable, getServiceEnvironmentVariables, getServiceHealthStatus, getServicePreviewEnvironmentVariableNames, getServicePreviewEnvironmentVariablesMasked, getServiceRuntime, getServiceStats, getServiceTypeParameters, getServiceTypes, getSessionDetails, getSessionEvents, getSessionLogs, getSessionReplay, getSessionReplayEvents, getSettings, getSkill, getSlowQueries, getStaticBundle, getStatusOverview, getTagsByRepositoryId, getTeam, getTimeBucketStats, getTodayStats, getTrace, getUnifiedTrace, getUniqueCounts, getUniqueEvents, getUpdateCapability, getUpdateStatus, getUptimeHistory, getUsageByProvider, getUsageRecent, getUsageSummary, getUsageTimeseries, getUsageTopModels, getVisitorByGuid, getVisitorById, getVisitorDetails, getVisitorFacets, getVisitorInfo, getVisitorJourney, getVisitors, getVisitorSessions, getVisitorStats, getWebhook, grantProjectAccess, handleGitProviderOauthCallback, hasAnalyticsEvents, hasErrorGroups, hasPerformanceMetrics, importExternalService, ingestLogs, ingestLogsByPath, ingestMetrics, ingestMetricsByPath, ingestSentryEnvelope, ingestSentryEvent, ingestTraces, ingestTracesByPath, initSessionReplay, inspectDropArchive, jobLogs, jobStatus, killJob, kvDel, kvDisable, kvEnable, kvExpire, kvGet, kvIncr, kvKeys, kvSet, kvStatus, kvTtl, kvUpdate, latestRunForSource, linkCustomDomainToCertificate, linkServiceToProject, listAgentRuns, listAgents, listAiProviders, listAlertRules, listAlerts, listAllConversations, listAllRuns, listApiKeys, listAuditLogs, listAvailableContainers, listBackupAlerts, listBackupChildren, listBackupSchedules, listBackupsForSchedule, listCommitsByRepositoryId, listConnections, listContainers, listContainersAtPath, listConversations, listCustomDomainsForProject, listDashboards, listDeliveries, listDeploymentContainerLogs, listDeploymentTokens, listDnsProviders, listDomains, listDsns, listEmailDomains, listEmailProviders, listEmails, listEnrollmentTokens, listEntities, listErrorEvents, listErrorGroups, listEvents, listEventTypes, listExternalImages, listExternalPlugins, listExternalServiceBackups, listFlags, listFunnels, listGitProviders, listGlobalMcps, listGlobalSkills, listIncidents, listInsights, listIpAccessControl, listJobs, listKnownAiAgents, listManagedDomains, listMcps, listMetricLabelKeys, listMetricLabelValues, listMetricNames, listModels, listMonitors, listNotificationProviders, listOidcProviders, listOidcProviderUsers, listOidcRoleMappings, listOnDemandCerts, listOrders, listPeers, listPendingActions, listPgUpgrades, listPresets, listProjectAccess, listProjectAlarms, listProjectScans, listProjectSecrets, listProjectServices, listProjectTemplates, listProjectTemplateTags, listProviderKeys, listProviderZones, listPublicProviders, listReleaseFiles, listReleases, listRemoteExternalImages, listRepositoriesByConnection, listRepositoriesByProvider, listRestoreRunsForService, listRootContainers, listRoutes, listS3Sources, listSandboxes, listScheduleRunJobs, listScheduleRuns, listScheduleServices, listSecrets, listServiceHealthStatuses, listServiceProjects, listServices, listServiceSchedules, listSkills, listSourceBackups, listSourceFiles, listSourceMaps, listSources, listStaticBundles, listSyncedRepositories, listTeamMembers, listTeamProjects, listTeams, listUsers, listWebhooks, login, logout, lookupDnsARecords, mintEnrollmentToken, mkdir, nodeHeartbeat, nodeMetricsGetRange, observabilityFullEvent, observabilityListEvents, oidcCallback, type Options, patchAdminGate, patchPreviewGatewaySettings, pauseDeployment, pauseSandbox, planRestore, postDnsAck, previewAlert, previewFunnelMetrics, previewHostnameMode, promoteClusterMember, promoteDeployment, provisionDomain, purgeProjectLogs, pushExternalImage, queryData, queryGenaiTraces, queryLogs, queryMetrics, queryTraces, queryTraceSummaries, readFile, reAnalyze, recordConsoleEvent, recordEventMetrics, recordFlagExposure, recordSpeedMetrics, refreshRouteTable, regenerateDsn, registerExternalImage, registerNode, reinstallGitlabWebhook, rejectPendingAction, reloadPlugins, removeClusterMember, removeManagedDomain, removeRole, removeTeamMember, renameConversation, renewDomain, requestPasswordReset, resetPassword, resizeSandbox, resolveAlarm, restartContainer, restartPreviewGateway, restartSandbox, restoreFlag, restoreUser, resumeDeployment, resumeSandbox, retryCluster, retryDelivery, retryPgUpgrade, retryRun, revealGlobalMcpConfig, revealMcpConfig, revealNotificationProviderConfig, revealServiceParameter, revenueCreateIntegration, revenueDeleteIntegration, revenueGlobalEvents, revenueImportInvoicesCsv, revenueImportSubscriptionsCsv, revenueListIntegrations, revenueListProviders, revenueMetricsCustomers, revenueMetricsGlobalMrr, revenueMetricsGlobalSummary, revenueMetricsMrr, revenueMetricsSummary, revenueRecentEvents, revenueRotateToken, revenueUpdateConfig, revenueUpdateSecret, revokeDsn, revokeEnrollmentToken, revokeJoinToken, revokeProjectAccess, rollbackPgUpgrade, rollbackToDeployment, rootfsGc, rootfsReport, rotateApiKey, rotateDeploymentToken, runBackupForSource, runConnectionHealthCheck, runExternalServiceBackup, runScheduleNow, sandboxCreatePreviewLink, saveAgentToken, saveAiProviderCredential, searchLogs, sendEmail, setDefaultS3Source, setFlagEnvironment, setPreviewPassword, setupDns, setupDnsChallenge, setupEmailTracking, setupMfa, sleepEnvironment, smokeTestAgent, sourceSandbox, startAnalysis, startContainer, startFix, startGitProviderOauth, startOidcLoginBySlug, startPgUpgrade, startRestore, startService, startUpdate, statPath, stopContainer, stopSandbox, stopService, streamContainerMetrics, streamEvents, streamRunEvents, syncRepositories, tailDeploymentJobLogs, tailLogs, teardownDeployment, teardownEnvironment, testNotificationProvider, testOidcProvider, testProvider, testProviderConnection, testProviderKeyById, testProviderKeyInline, testS3ConnectionPreview, testS3SourceConnection, trackClick, trackOpen, triggerAgent, triggerProjectPipeline, triggerScan, triggerServiceHealthCheck, triggerWeeklyDigest, unlinkServiceFromProject, updateAgent, updateAiProvider, updateAlert, updateAlertRule, updateApiKey, updateAutomaticDeploy, updateBackupSchedule, updateCloudflareProvider, updateConnectionToken, updateCustomDomain, updateDashboard, updateDeploymentToken, updateEmailProvider, updateEnvironmentSettings, updateEnvironmentSubdomain, updateEnvironmentVariable, updateErrorGroup, updateFlag, updateFunnel, updateGitProviderCredentials, updateGitSettings, updateGlobalMcp, updateGlobalSkill, updateIncidentStatus, updateIpAccessControl, updateManagedDomain, updateMcp, updateNotificationEmailProvider, updateNotificationProvider, updateOidcProvider, updatePreferences, updateProject, updateProjectDeploymentConfig, updateProjectSecret, updateProjectSettings, updateProvider, updateProviderKey, updateRoute, updateS3Source, updateSelf, updateService, updateServiceResources, updateSessionDuration, updateSettings, updateSkill, updateSlackProvider, updateSpeedMetrics, updateTeam, updateTeamMemberRole, updateUser, updateWebhook, updateWebhookProvider, upgradePreviewGateway, upgradeService, uploadGlobalSkill, uploadReleaseFile, uploadSkill, uploadSourceFile, uploadSourceMap, uploadStaticBundle, upsertSecret, validateConnection, validateEmail, verifyAndEnableMfa, verifyDomain, verifyEmail, verifyManagedDomain, verifyMfaChallenge, verifyStepUp, wakeEnvironment, webhookTrigger, workflowDryRun, writeFile, writeFiles } from './sdk.gen'; +export type { AcknowledgeAlarmData, AcknowledgeAlarmErrors, AcknowledgeAlarmResponses, AcmeOrderResponse, ActivateAiProviderData, ActivateAiProviderErrors, ActivateAiProviderResponse, ActivateAiProviderResponses, ActivateApiKeyData, ActivateApiKeyErrors, ActivateApiKeyResponse, ActivateApiKeyResponses, ActivateConnectionData, ActivateConnectionErrors, ActivateConnectionResponses, ActivateProviderData, ActivateProviderErrors, ActivateProviderResponse, ActivateProviderResponses, ActiveVisitor, ActiveVisitorsQuery, ActiveVisitorsResponse, ActivityDay, ActivityEvent, ActivityGraphQuery, ActivityGraphResponse, AddClusterMemberData, AddClusterMemberErrors, AddClusterMemberRequest, AddClusterMemberResponse, AddClusterMemberResponses, AddContextData, AddContextErrors, AddContextRequest, AddContextResponses, AddEnvironmentDomainData, AddEnvironmentDomainErrors, AddEnvironmentDomainRequest, AddEnvironmentDomainResponse, AddEnvironmentDomainResponses, AddEventsData, AddEventsError, AddEventsErrors, AddEventsRequest, AddEventsResponse, AddEventsResponse2, AddEventsResponses, AddManagedDomainApiRequest, AddManagedDomainData, AddManagedDomainErrors, AddManagedDomainResponse, AddManagedDomainResponses, AddSessionReplayEventsData, AddSessionReplayEventsError, AddSessionReplayEventsErrors, AddSessionReplayEventsResponse, AddSessionReplayEventsResponses, AddTeamMemberData, AddTeamMemberErrors, AddTeamMemberResponse, AddTeamMemberResponses, AdminDrainNodeData, AdminDrainNodeErrors, AdminDrainNodeResponse, AdminDrainNodeResponses, AdminDrainStatusData, AdminDrainStatusErrors, AdminDrainStatusResponse, AdminDrainStatusResponses, AdminGateResponse, AdminGateSource, AdminGetNodeData, AdminGetNodeErrors, AdminGetNodeResponse, AdminGetNodeResponses, AdminListNodeContainersData, AdminListNodeContainersErrors, AdminListNodeContainersResponse, AdminListNodeContainersResponses, AdminListNodesData, AdminListNodesErrors, AdminListNodesResponse, AdminListNodesResponses, AdminRemoveNodeData, AdminRemoveNodeErrors, AdminRemoveNodeResponse, AdminRemoveNodeResponses, AdminUndrainNodeData, AdminUndrainNodeErrors, AdminUndrainNodeResponse, AdminUndrainNodeResponses, AgentConfigResponse, AgentRunLogResponse, AgentRunResponse, AgentRunWithLogsResponse, AgentSandboxSettings, AgentSandboxSettingsMasked, AggregatedBucketItem, AggregatedBucketsQuery, AggregatedBucketsResponse, AggregationLevel, AggregationTemporality, AiAgentBreakdownResponse, AiAgentBreakdownRow, AiAgentDescriptor, AiAgentPageRow, AiAgentPagesResponse, AiAgentTimelineResponse, AiAgentTimelineRow, AiChatLimitsSettings, AiConfigSettings, AiPageBreakdownResponse, AiPageBreakdownRow, AiStatusBreakdownResponse, AiStatusBreakdownRow, AlarmListResponse, AlarmResponse, AlarmSummaryResponse, AlertRuleResponse, AllocEntry, AnalyticsSessionEventsResponse, AnnotatedSpan, AnomalyAlgorithm, AnomalyParams, AnomalyPreviewPointResponse, AnomalyPreviewRequest, AnomalyPreviewResponse, ApiKeyListResponse, ApiKeyResponse, ApplyHostnameModeData, ApplyHostnameModeErrors, ApplyHostnameModeRequest, ApplyHostnameModeResponse, ApplyHostnameModeResponses, AppSettings, AppSettingsResponse, ArchiveConversationData, ArchiveConversationErrors, ArchiveConversationResponse, ArchiveConversationResponses, ArchiveFlagData, ArchiveFlagErrors, ArchiveFlagResponse, ArchiveFlagResponse2, ArchiveFlagResponses, ArchiveMode, AssignRoleData, AssignRoleErrors, AssignRoleRequest, AssignRoleResponses, AttachScheduleServicesData, AttachScheduleServicesError, AttachScheduleServicesErrors, AttachScheduleServicesRequest, AttachScheduleServicesResponse, AttachScheduleServicesResponse2, AttachScheduleServicesResponses, AuditLogIpInfo, AuditLogResponse, AuditLogUserInfo, AuthFlavorDto, AuthResponse, AuthStatusResponse, AuthTokenResponse, AutofixerRunResponse, AutofixerRunWithLogsResponse, AutofixRunConfig, AutoWatchParams, AvailableContainerInfo, AvailablePermissions, BackupAlertListResponse, BackupAlertResponse, BackupResponse, BackupScheduleResponse, BitbucketAuthInput, BlobCopyData, BlobCopyError, BlobCopyErrors, BlobCopyResponse, BlobCopyResponses, BlobDeleteData, BlobDeleteError, BlobDeleteErrors, BlobDeleteResponse, BlobDeleteResponses, BlobDisableData, BlobDisableErrors, BlobDisableResponse, BlobDisableResponses, BlobDownloadData, BlobDownloadError, BlobDownloadErrors, BlobDownloadResponses, BlobEnableData, BlobEnableErrors, BlobEnableResponse, BlobEnableResponses, BlobHeadData, BlobHeadError, BlobHeadErrors, BlobHeadResponses, BlobListData, BlobListError, BlobListErrors, BlobListResponse, BlobListResponses, BlobPutData, BlobPutError, BlobPutErrors, BlobPutResponse, BlobPutResponses, BlobResponse, BlobStatusData, BlobStatusErrors, BlobStatusResponse, BlobStatusResponse2, BlobStatusResponses, BlobUpdateData, BlobUpdateErrors, BlobUpdateResponse, BlobUpdateResponses, BranchInfo, BranchListResponse, BrowserCount, BrowsersQuery, BuildConfiguration, BuildLimitsSettings, CancelBackupData, CancelBackupError, CancelBackupErrors, CancelBackupResponse, CancelBackupResponse2, CancelBackupResponses, CancelData, CancelDeploymentData, CancelDeploymentErrors, CancelDeploymentResponse, CancelDeploymentResponses, CancelDomainOrderData, CancelDomainOrderErrors, CancelDomainOrderResponse, CancelDomainOrderResponses, CancelErrors, CancelPgUpgradeData, CancelPgUpgradeErrors, CancelPgUpgradeResponse, CancelPgUpgradeResponses, CancelResponses, CancelRunData, CancelRunErrors, CancelRunResponse, CancelRunResponses, CancelScheduleRunData, CancelScheduleRunError, CancelScheduleRunErrors, CancelScheduleRunResponse, CancelScheduleRunResponses, CertStatusResponse, ChallengeConfig, ChallengeError, ChallengeValidationStatus, ChangePasswordRequest, ChangePasswordSelfData, ChangePasswordSelfErrors, ChangePasswordSelfResponse, ChangePasswordSelfResponses, ChangeProjectSourceData, ChangeProjectSourceErrors, ChangeProjectSourceRequest, ChangeProjectSourceResponse, ChangeProjectSourceResponses, ChangeRequiredPasswordData, ChangeRequiredPasswordErrors, ChangeRequiredPasswordResponse, ChangeRequiredPasswordResponses, ChatCompletionChoice, ChatCompletionRequest, ChatCompletionResponse, ChatCompletionsData, ChatCompletionsError, ChatCompletionsErrors, ChatCompletionsResponse, ChatCompletionsResponses, ChatMessage, ChatReadinessResponse, CheckAnalyticsHasEventsData, CheckAnalyticsHasEventsErrors, CheckAnalyticsHasEventsResponse, CheckAnalyticsHasEventsResponses, CheckCommitExistsData, CheckCommitExistsErrors, CheckCommitExistsResponse, CheckCommitExistsResponses, CheckDomainStatusData, CheckDomainStatusErrors, CheckDomainStatusResponse, CheckDomainStatusResponses, CheckExplorerSupportData, CheckExplorerSupportErrors, CheckExplorerSupportResponse, CheckExplorerSupportResponses, CheckForUpdateData, CheckForUpdateError, CheckForUpdateErrors, CheckForUpdateResponse, CheckForUpdateResponses, CheckIpBlockedData, CheckIpBlockedError, CheckIpBlockedErrors, CheckIpBlockedResponses, CheckProviderDeletionSafetyData, CheckProviderDeletionSafetyErrors, CheckProviderDeletionSafetyResponse, CheckProviderDeletionSafetyResponses, ChildBackupEntryResponse, ChildBackupListResponse, ChunkUploadOptionsData, ChunkUploadOptionsResponse, ChunkUploadOptionsResponses, CleanupExpiredBackupsData, CleanupExpiredBackupsError, CleanupExpiredBackupsErrors, CleanupExpiredBackupsRequest, CleanupExpiredBackupsResponse, CleanupExpiredBackupsResponses, ClearPreviewPasswordData, ClearPreviewPasswordErrors, ClearPreviewPasswordResponse, ClearPreviewPasswordResponses, CliDeviceApproveData, CliDeviceApproveErrors, CliDeviceApproveRequest, CliDeviceApproveResponse, CliDeviceApproveResponse2, CliDeviceApproveResponses, CliDeviceDenyData, CliDeviceDenyErrors, CliDeviceDenyResponse, CliDeviceDenyResponses, CliDeviceLookupData, CliDeviceLookupErrors, CliDeviceLookupResponse, CliDeviceLookupResponse2, CliDeviceLookupResponses, CliDevicePollData, CliDevicePollErrors, CliDevicePollRequest, CliDevicePollResponse, CliDevicePollResponse2, CliDevicePollResponses, CliDeviceStartData, CliDeviceStartErrors, CliDeviceStartRequest, CliDeviceStartResponse, CliDeviceStartResponse2, CliDeviceStartResponses, ClientOptions, CliLoginRequest, CliLogoutData, CliLogoutErrors, CliLogoutResponse, CliLogoutResponses, CloudflareConfig, CloudProvider, ClusterCapacity, ClusterDnsSettings, ClusterHealthReportResponse, ClusterMemberHealthResponse, ClusterMemberRequest, CmdBody, CmdData, CmdErrors, CmdInner, CmdKillBody, CmdKillData, CmdKillErrors, CmdKillResponse, CmdKillResponses, CmdLogsData, CmdLogsErrors, CmdLogsResponses, CmdResponse, CmdResponse2, CmdResponses, CommitExistsResponse, CommitInfo, CommitListResponse, Comparator, ComposePublicPort, ConfirmPendingActionData, ConfirmPendingActionErrors, ConfirmPendingActionResponse, ConfirmPendingActionResponses, ConnectionListQuery, ConnectionListResponse, ConnectionResponse, ConnectionTestResult, ConsoleEventPayload, ContainerActionResponse, ContainerDetailResponse, ContainerEnvironmentVariableValueResponse, ContainerInfoResponse, ContainerInventoryItem, ContainerListResponse, ContainerLogSettings, ContainerLogsQuery, ContainerMetricHistoryPoint, ContainerMetricsGetHistoryData, ContainerMetricsGetHistoryErrors, ContainerMetricsGetHistoryResponse, ContainerMetricsGetHistoryResponses, ContainerMetricsHistoryQuery, ContainerMetricsResponse, ContainerResponse, ContainerRuntimeInfo, ContainerStatsSample, ContentPart, ContextLine, ContextLogsRequest, ContextLogsResponse, ConversationDetailResponse, ConversationResponse, ConversationsQueryParams, ConversationSummary, CopyBlobRequest, CostAnalysis, CreateAgentData, CreateAgentErrors, CreateAgentResponse, CreateAgentResponses, CreateAlertData, CreateAlertError, CreateAlertErrors, CreateAlertResponse, CreateAlertResponses, CreateAlertRuleData, CreateAlertRuleErrors, CreateAlertRuleRequest, CreateAlertRuleResponse, CreateAlertRuleResponses, CreateApiKeyData, CreateApiKeyErrors, CreateApiKeyRequest, CreateApiKeyResponse, CreateApiKeyResponse2, CreateApiKeyResponses, CreateBackupScheduleData, CreateBackupScheduleError, CreateBackupScheduleErrors, CreateBackupScheduleRequest, CreateBackupScheduleResponse, CreateBackupScheduleResponses, CreateBitbucketProviderData, CreateBitbucketProviderErrors, CreateBitbucketProviderResponse, CreateBitbucketProviderResponses, CreateBitbucketRequest, CreateCloudflareProviderData, CreateCloudflareProviderErrors, CreateCloudflareProviderRequest, CreateCloudflareProviderResponse, CreateCloudflareProviderResponses, CreateConversationData, CreateConversationErrors, CreateConversationRequest, CreateConversationResponse, CreateConversationResponses, CreateCustomDomainData, CreateCustomDomainErrors, CreateCustomDomainResponse, CreateCustomDomainResponses, CreateDashboardData, CreateDashboardError, CreateDashboardErrors, CreateDashboardRequest, CreateDashboardResponse, CreateDashboardResponses, CreateDeploymentTokenData, CreateDeploymentTokenErrors, CreateDeploymentTokenRequest, CreateDeploymentTokenResponse, CreateDeploymentTokenResponse2, CreateDeploymentTokenResponses, CreateDnsProviderData, CreateDnsProviderErrors, CreateDnsProviderRequest, CreateDnsProviderResponse, CreateDnsProviderResponses, CreateDomainData, CreateDomainErrors, CreateDomainRequest, CreateDomainResponse, CreateDomainResponses, CreatedResource, CreateDsnData, CreateDsnErrors, CreateDsnRequest, CreateDsnResponse, CreateDsnResponses, CreateEmailDomainData, CreateEmailDomainErrors, CreateEmailDomainRequest, CreateEmailDomainResponse, CreateEmailDomainResponses, CreateEmailProviderData, CreateEmailProviderErrors, CreateEmailProviderRequest, CreateEmailProviderResponse, CreateEmailProviderResponses, CreateEnvironmentData, CreateEnvironmentErrors, CreateEnvironmentRequest, CreateEnvironmentResponse, CreateEnvironmentResponses, CreateEnvironmentVariableData, CreateEnvironmentVariableErrors, CreateEnvironmentVariableRequest, CreateEnvironmentVariableResponse, CreateEnvironmentVariableResponses, CreateExternalServiceRequest, CreateFlagData, CreateFlagErrors, CreateFlagRequest, CreateFlagResponse, CreateFlagResponses, CreateFunnelData, CreateFunnelErrors, CreateFunnelRequest, CreateFunnelResponse, CreateFunnelResponse2, CreateFunnelResponses, CreateFunnelStep, CreateGenericProviderData, CreateGenericProviderErrors, CreateGenericProviderResponse, CreateGenericProviderResponses, CreateGenericRequest, CreateGiteaPatProviderData, CreateGiteaPatProviderErrors, CreateGiteaPatProviderResponse, CreateGiteaPatProviderResponses, CreateGiteaPatRequest, CreateGithubPatProviderData, CreateGithubPatProviderErrors, CreateGithubPatProviderResponse, CreateGithubPatProviderResponses, CreateGitHubPatRequest, CreateGitlabOauthProviderData, CreateGitlabOauthProviderErrors, CreateGitlabOauthProviderResponse, CreateGitlabOauthProviderResponses, CreateGitLabOAuthRequest, CreateGitlabPatProviderData, CreateGitlabPatProviderErrors, CreateGitlabPatProviderResponse, CreateGitlabPatProviderResponses, CreateGitLabPatRequest, CreateGitProviderData, CreateGitProviderErrors, CreateGitProviderResponse, CreateGitProviderResponses, CreateGlobalMcpData, CreateGlobalMcpErrors, CreateGlobalMcpResponse, CreateGlobalMcpResponses, CreateGlobalSkillData, CreateGlobalSkillErrors, CreateGlobalSkillResponse, CreateGlobalSkillResponses, CreateIncidentData, CreateIncidentErrors, CreateIncidentRequest, CreateIncidentResponse, CreateIncidentResponses, CreateIntegrationBody, CreateIpAccessControlData, CreateIpAccessControlError, CreateIpAccessControlErrors, CreateIpAccessControlRequest, CreateIpAccessControlResponse, CreateIpAccessControlResponses, CreateMcpData, CreateMcpErrors, CreateMcpRequest, CreateMcpResponse, CreateMcpResponses, CreateMetricAlertRequest, CreateMonitorData, CreateMonitorErrors, CreateMonitorRequest, CreateMonitorResponse, CreateMonitorResponses, CreateNotificationEmailProviderData, CreateNotificationEmailProviderErrors, CreateNotificationEmailProviderRequest, CreateNotificationEmailProviderResponse, CreateNotificationEmailProviderResponses, CreateNotificationProviderData, CreateNotificationProviderErrors, CreateNotificationProviderResponse, CreateNotificationProviderResponses, CreateOidcProviderData, CreateOidcProviderErrors, CreateOidcProviderRequest, CreateOidcProviderResponse, CreateOidcProviderResponses, CreateOidcRoleMappingData, CreateOidcRoleMappingRequest, CreateOidcRoleMappingResponse, CreateOidcRoleMappingResponses, CreateOrRecreateOrderData, CreateOrRecreateOrderErrors, CreateOrRecreateOrderResponse, CreateOrRecreateOrderResponses, CreatePlanData, CreatePlanErrors, CreatePlanRequest, CreatePlanResponse, CreatePlanResponse2, CreatePlanResponses, CreatePrData, CreatePrErrors, CreateProjectAccessRequest, CreateProjectData, CreateProjectErrors, CreateProjectFromTemplateData, CreateProjectFromTemplateErrors, CreateProjectFromTemplateRequest, CreateProjectFromTemplateResponse, CreateProjectFromTemplateResponse2, CreateProjectFromTemplateResponses, CreateProjectReleaseData, CreateProjectReleaseErrors, CreateProjectReleaseResponse, CreateProjectReleaseResponses, CreateProjectRequest, CreateProjectResponse, CreateProjectResponses, CreateProjectSecretData, CreateProjectSecretErrors, CreateProjectSecretRequest, CreateProjectSecretResponse, CreateProjectSecretResponses, CreateProviderKeyData, CreateProviderKeyError, CreateProviderKeyErrors, CreateProviderKeyRequest, CreateProviderKeyResponse, CreateProviderKeyResponses, CreateProviderRequest, CreatePrResponse, CreatePrResponse2, CreatePrResponses, CreateReleaseData, CreateReleaseErrors, CreateReleaseResponse, CreateReleaseResponses, CreateRouteData, CreateRouteErrors, CreateRouteRequest, CreateRouteResponse, CreateRouteResponses, CreateS3SourceData, CreateS3SourceError, CreateS3SourceErrors, CreateS3SourceRequest, CreateS3SourceResponse, CreateS3SourceResponses, CreateSandboxBody, CreateSandboxData, CreateSandboxErrors, CreateSandboxResponse, CreateSandboxResponses, CreateServiceData, CreateServiceErrors, CreateServiceResponse, CreateServiceResponses, CreateSkillData, CreateSkillErrors, CreateSkillRequest, CreateSkillResponse, CreateSkillResponses, CreateSlackProviderData, CreateSlackProviderErrors, CreateSlackProviderRequest, CreateSlackProviderResponse, CreateSlackProviderResponses, CreateTeamData, CreateTeamErrors, CreateTeamMemberRequest, CreateTeamRequest, CreateTeamResponse, CreateTeamResponses, CreateUserData, CreateUserErrors, CreateUserRequest, CreateUserResponse, CreateUserResponses, CreateWebhookData, CreateWebhookErrors, CreateWebhookProviderData, CreateWebhookProviderErrors, CreateWebhookProviderRequest, CreateWebhookProviderResponse, CreateWebhookProviderResponses, CreateWebhookRequestBody, CreateWebhookResponse, CreateWebhookResponses, CronExecutionInfo, CronInfo, CrossProjectSiblingRef, CrossProjectTraceResponse, CurrentStatusResponse, CustomDomainRequest, CustomDomainResponse, CustomerMovementResponse, DashboardLayout, DashboardProjectsAnalyticsQuery, DashboardProjectsAnalyticsResponse, DashboardSection, DashboardTile, DatabaseMetricsResponse, DatabaseMetricsRow, DataImplication, DataImplicationSeverity, DeactivateApiKeyData, DeactivateApiKeyErrors, DeactivateApiKeyResponse, DeactivateApiKeyResponses, DeactivateConnectionData, DeactivateConnectionErrors, DeactivateConnectionResponses, DeactivateProviderData, DeactivateProviderErrors, DeactivateProviderResponses, DeleteAgentData, DeleteAgentErrors, DeleteAgentResponse, DeleteAgentResponses, DeleteAlertData, DeleteAlertError, DeleteAlertErrors, DeleteAlertResponse, DeleteAlertResponses, DeleteAlertRuleData, DeleteAlertRuleErrors, DeleteAlertRuleResponse, DeleteAlertRuleResponses, DeleteApiKeyData, DeleteApiKeyErrors, DeleteApiKeyResponse, DeleteApiKeyResponses, DeleteBackupData, DeleteBackupError, DeleteBackupErrors, DeleteBackupResponse, DeleteBackupResponses, DeleteBackupScheduleData, DeleteBackupScheduleError, DeleteBackupScheduleErrors, DeleteBackupScheduleResponse, DeleteBackupScheduleResponses, DeleteBlobRequest, DeleteBlobResponse, DeleteConnectionData, DeleteConnectionErrors, DeleteConnectionResponse, DeleteConnectionResponses, DeleteCustomDomainData, DeleteCustomDomainErrors, DeleteCustomDomainResponse, DeleteCustomDomainResponses, DeleteDashboardData, DeleteDashboardError, DeleteDashboardErrors, DeleteDashboardResponse, DeleteDashboardResponses, DeleteDeploymentTokenData, DeleteDeploymentTokenErrors, DeleteDeploymentTokenResponse, DeleteDeploymentTokenResponses, DeleteDnsProviderData, DeleteDnsProviderErrors, DeleteDnsProviderResponse, DeleteDnsProviderResponses, DeleteDomainData, DeleteDomainErrors, DeleteDomainResponse, DeleteDomainResponses, DeleteEmailDomainData, DeleteEmailDomainErrors, DeleteEmailDomainResponse, DeleteEmailDomainResponses, DeleteEmailProviderData, DeleteEmailProviderErrors, DeleteEmailProviderResponse, DeleteEmailProviderResponses, DeleteEnvironmentData, DeleteEnvironmentDomainData, DeleteEnvironmentDomainErrors, DeleteEnvironmentDomainResponse, DeleteEnvironmentDomainResponses, DeleteEnvironmentErrors, DeleteEnvironmentResponse, DeleteEnvironmentResponses, DeleteEnvironmentVariableData, DeleteEnvironmentVariableErrors, DeleteEnvironmentVariableResponse, DeleteEnvironmentVariableResponses, DeleteExternalImageData, DeleteExternalImageErrors, DeleteExternalImageResponse, DeleteExternalImageResponses, DeleteFunnelData, DeleteFunnelErrors, DeleteFunnelResponses, DeleteGitProviderData, DeleteGitProviderErrors, DeleteGitProviderResponse, DeleteGitProviderResponses, DeleteGlobalMcpData, DeleteGlobalMcpErrors, DeleteGlobalMcpResponse, DeleteGlobalMcpResponses, DeleteGlobalSkillData, DeleteGlobalSkillErrors, DeleteGlobalSkillResponse, DeleteGlobalSkillResponses, DeleteIpAccessControlData, DeleteIpAccessControlError, DeleteIpAccessControlErrors, DeleteIpAccessControlResponse, DeleteIpAccessControlResponses, DeleteMcpData, DeleteMcpErrors, DeleteMcpResponse, DeleteMcpResponses, DeleteMonitorData, DeleteMonitorErrors, DeleteMonitorResponse, DeleteMonitorResponses, DeleteNotificationProviderData, DeleteNotificationProviderErrors, DeleteNotificationProviderResponse, DeleteNotificationProviderResponses, DeleteOidcProviderData, DeleteOidcProviderResponse, DeleteOidcProviderResponses, DeleteOidcRoleMappingData, DeleteOidcRoleMappingResponse, DeleteOidcRoleMappingResponses, DeletePreferencesData, DeletePreferencesErrors, DeletePreferencesResponse, DeletePreferencesResponses, DeleteProjectData, DeleteProjectErrors, DeleteProjectResponse, DeleteProjectResponses, DeleteProjectSecretData, DeleteProjectSecretErrors, DeleteProjectSecretResponse, DeleteProjectSecretResponses, DeleteProviderKeyData, DeleteProviderKeyError, DeleteProviderKeyErrors, DeleteProviderKeyResponse, DeleteProviderKeyResponses, DeleteProviderSafelyData, DeleteProviderSafelyErrors, DeleteProviderSafelyResponse, DeleteProviderSafelyResponses, DeleteReleaseSourceFilesData, DeleteReleaseSourceFilesErrors, DeleteReleaseSourceFilesResponse, DeleteReleaseSourceFilesResponses, DeleteReleaseSourceMapsData, DeleteReleaseSourceMapsErrors, DeleteReleaseSourceMapsResponse, DeleteReleaseSourceMapsResponses, DeleteResponse, DeleteRouteData, DeleteRouteErrors, DeleteRouteResponse, DeleteRouteResponses, DeleteS3SourceData, DeleteS3SourceError, DeleteS3SourceErrors, DeleteS3SourceResponse, DeleteS3SourceResponses, DeleteScanData, DeleteScanError, DeleteScanErrors, DeleteScanResponse, DeleteScanResponses, DeleteSecretData, DeleteSecretErrors, DeleteSecretResponse, DeleteSecretResponses, DeleteServiceData, DeleteServiceErrors, DeleteServiceResponse, DeleteServiceResponses, DeleteSessionReplayData, DeleteSessionReplayError, DeleteSessionReplayErrors, DeleteSessionReplayResponses, DeleteSkillData, DeleteSkillErrors, DeleteSkillResponse, DeleteSkillResponses, DeleteSourceMapData, DeleteSourceMapErrors, DeleteSourceMapResponse, DeleteSourceMapResponses, DeleteStaticBundleData, DeleteStaticBundleErrors, DeleteStaticBundleResponse, DeleteStaticBundleResponses, DeleteTeamData, DeleteTeamErrors, DeleteTeamResponse, DeleteTeamResponses, DeleteUserData, DeleteUserErrors, DeleteUserResponse, DeleteUserResponses, DeleteWebhookData, DeleteWebhookErrors, DeleteWebhookResponse, DeleteWebhookResponses, DelRequest, DelResponse, DeployFromImageData, DeployFromImageErrors, DeployFromImageRequest, DeployFromImageResponse, DeployFromImageResponses, DeployFromImageUploadData, DeployFromImageUploadErrors, DeployFromImageUploadQuery, DeployFromImageUploadResponse, DeployFromImageUploadResponses, DeployFromStaticData, DeployFromStaticErrors, DeployFromStaticRequest, DeployFromStaticResponse, DeployFromStaticResponses, DeployFromUploadedSourceData, DeployFromUploadedSourceErrors, DeployFromUploadedSourceResponse, DeployFromUploadedSourceResponses, DeploymentConfig, DeploymentConfigSnapshot, DeploymentConfiguration, DeploymentContainerLogContentResponse, DeploymentContainerLogResponse, DeploymentContainerLogsListResponse, DeploymentEnvironmentResponse, DeploymentJobResponse, DeploymentJobsResponse, DeploymentListResponse, DeploymentMetadata, DeploymentMetricsGetLatestData, DeploymentMetricsGetLatestErrors, DeploymentMetricsGetLatestResponse, DeploymentMetricsGetLatestResponses, DeploymentMetricsGetRangeData, DeploymentMetricsGetRangeErrors, DeploymentMetricsGetRangeResponse, DeploymentMetricsGetRangeResponses, DeploymentMetricsToggleData, DeploymentMetricsToggleErrors, DeploymentMetricsToggleResponses, DeploymentResponse, DeploymentStateResponse, DeploymentStrategy, DeploymentTokenListResponse, DeploymentTokenResponse, DestroySandboxData, DestroySandboxErrors, DestroySandboxResponse, DestroySandboxResponses, DetachScheduleServiceData, DetachScheduleServiceError, DetachScheduleServiceErrors, DetachScheduleServiceResponse, DetachScheduleServiceResponses, DetectionConfig, DetectPublicPresetsData, DetectPublicPresetsErrors, DetectPublicPresetsResponse, DetectPublicPresetsResponses, DeviceCount, DigestSections, Direction, DisableBackupScheduleData, DisableBackupScheduleErrors, DisableBackupScheduleResponse, DisableBackupScheduleResponses, DisableBlobResponse, DisableKvResponse, DisableMfaData, DisableMfaErrors, DisableMfaRequest, DisableMfaResponse, DisableMfaResponses, DiscoverRequest, DiscoverResponse, DiscoverWorkloadsData, DiscoverWorkloadsErrors, DiscoverWorkloadsResponse, DiscoverWorkloadsResponses, DiskInfo, DiskSpaceAlert, DiskSpaceAlertSettings, DiskSpaceCheckResult, DnsAckRequest, DnsAckResponse, DnsChallengeRecordResult, DnsChangesResponse, DnsCompletionResponse, DnsLookupError, DnsLookupRequest, DnsLookupResponse, DnsProviderCredentials, DnsProviderResponse, DnsProviderSettings, DnsProviderSettingsMasked, DnsProviderType, DnsRecord, DnsRecordChange, DnsRecordContent, DnsRecordResponse, DnsRecordSetupResult, DnsRecordStatusResponse, DnsZone, DockerComposePresetConfig, DockerfilePresetConfig, DockerfileVariant, DockerRegistrySettings, DockerRegistrySettingsMasked, DomainAction, DomainChallengeResponse, DomainData, DomainEnvironmentResponse, DomainError, DomainErrors, DomainPlan, DomainResponse, DomainResponse2, DomainResponses, DownloadGlobalSkillArchiveData, DownloadGlobalSkillArchiveErrors, DownloadGlobalSkillArchiveResponse, DownloadGlobalSkillArchiveResponses, DownloadObjectData, DownloadObjectErrors, DownloadObjectResponse, DownloadObjectResponses, DownloadSkillArchiveData, DownloadSkillArchiveErrors, DownloadSkillArchiveResponse, DownloadSkillArchiveResponses, DrainNodeResponse, DrainStatusResponse, DropArchiveUpload, DropInspectionResponse, DropOffPoint, DropPresetCandidate, EmailConfig, EmailDomainResponse, EmailDomainWithDnsResponse, EmailProviderResponse, EmailProviderTypeRoute, EmailRequest, EmailResponse, EmailStatsResponse, EmailStatusData, EmailStatusErrors, EmailStatusResponse, EmailStatusResponse2, EmailStatusResponses, EmailTrackingResponse, EmailTrackingSetupResponse, EmailTrackingStatusResponse, EmbeddingData, EmbeddingInput, EmbeddingRequest, EmbeddingResponse, EmbeddingsData, EmbeddingsError, EmbeddingsErrors, EmbeddingsResponse, EmbeddingsResponses, EmbeddingUsage, EnableBackupScheduleData, EnableBackupScheduleErrors, EnableBackupScheduleResponse, EnableBackupScheduleResponses, EnableBlobRequest, EnableBlobResponse, EnableKvRequest, EnableKvResponse, EnablePgStatStatementsResponse, EndpointDto, EnqueuedJob, EnrichVisitorData, EnrichVisitorErrors, EnrichVisitorRequest, EnrichVisitorResponse, EnrichVisitorResponse2, EnrichVisitorResponses, EnrollmentTokenInfo, EnrollmentTokenListResponse, EntityInfoResponse, EntityResponse, EnvironmentConfiguration, EnvironmentDomainResponse, EnvironmentInfo, EnvironmentResponse, EnvironmentVariable, EnvironmentVariableInfo, EnvironmentVariableResponse, EnvironmentVariableValueResponse, EnvVarInput, EnvVarIntegrationInfo, EnvVarResponse, EnvVarTemplateResponse, ErrorDashboardStatsQuery, ErrorDashboardStatsResponse, ErrorEventResponse, ErrorGroupResponse, ErrorGroupStatsResponse, ErrorResponse, ErrorRow, ErrorTimeSeriesDataResponse, ErrorTimeSeriesQuery, EventActivityBucket, EventBreakdown, EventBrowserStats, EventCount, EventCountryStats, EventDetailQuery, EventDetailResponse, EventEntriesQuery, EventEntriesResponse, EventEntryInfo, EventKind, EventMetricsPayload, EventReferrerStats, EventsCountQuery, EventsResponse, EventTimeline, EventTimelineQuery, EventType, EventTypeBreakdown, EventTypeBreakdownQuery, EventTypeResponse, EventTypesResponse, EventVisitorInfo, EventVisitorsQuery, EventVisitorsResponse, ExecBody, ExecData, ExecDetachedData, ExecDetachedErrors, ExecDetachedResponse, ExecDetachedResponse2, ExecDetachedResponses, ExecErrors, ExecResponse, ExecResponse2, ExecResponses, ExecuteDeploymentOperationData, ExecuteDeploymentOperationErrors, ExecuteDeploymentOperationResponse, ExecuteDeploymentOperationResponses, ExecuteImportData, ExecuteImportErrors, ExecuteImportRequest, ExecuteImportResponse, ExecuteImportResponse2, ExecuteImportResponses, ExecuteOperationRequest, ExpireRequest, ExpireResponse, ExplorerSupportResponse, ExtendTimeoutBody, ExtendTimeoutData, ExtendTimeoutErrors, ExtendTimeoutResponse, ExtendTimeoutResponses, ExternalImageResponse, ExternalServiceBackupResponse, ExternalServiceDetails, ExternalServiceEnablePgStatStatementsData, ExternalServiceEnablePgStatStatementsErrors, ExternalServiceEnablePgStatStatementsResponse, ExternalServiceEnablePgStatStatementsResponses, ExternalServiceInfo, ExternalServiceMetricsByDatabaseData, ExternalServiceMetricsByDatabaseErrors, ExternalServiceMetricsByDatabaseResponse, ExternalServiceMetricsByDatabaseResponses, ExternalServiceMetricsCreateAlertRuleData, ExternalServiceMetricsCreateAlertRuleErrors, ExternalServiceMetricsCreateAlertRuleResponse, ExternalServiceMetricsCreateAlertRuleResponses, ExternalServiceMetricsDeleteAlertRuleData, ExternalServiceMetricsDeleteAlertRuleErrors, ExternalServiceMetricsDeleteAlertRuleResponse, ExternalServiceMetricsDeleteAlertRuleResponses, ExternalServiceMetricsGetAlertRulesData, ExternalServiceMetricsGetAlertRulesErrors, ExternalServiceMetricsGetAlertRulesResponse, ExternalServiceMetricsGetAlertRulesResponses, ExternalServiceMetricsGetLatestData, ExternalServiceMetricsGetLatestErrors, ExternalServiceMetricsGetLatestResponse, ExternalServiceMetricsGetLatestResponses, ExternalServiceMetricsGetRangeData, ExternalServiceMetricsGetRangeErrors, ExternalServiceMetricsGetRangeResponse, ExternalServiceMetricsGetRangeResponses, ExternalServiceMetricsStatusData, ExternalServiceMetricsStatusErrors, ExternalServiceMetricsStatusResponse, ExternalServiceMetricsStatusResponses, ExternalServiceMetricsToggleData, ExternalServiceMetricsToggleErrors, ExternalServiceMetricsToggleResponses, ExternalServiceMetricsUpdateAlertRuleData, ExternalServiceMetricsUpdateAlertRuleErrors, ExternalServiceMetricsUpdateAlertRuleResponse, ExternalServiceMetricsUpdateAlertRuleResponses, ExternalServiceResetPgStatStatementsData, ExternalServiceResetPgStatStatementsErrors, ExternalServiceResetPgStatStatementsResponse, ExternalServiceResetPgStatStatementsResponses, ExternalServiceSummary, FieldResponse, FinalizeOrderData, FinalizeOrderErrors, FinalizeOrderResponse, FinalizeOrderResponses, FinalizeProjectReleaseData, FinalizeProjectReleaseErrors, FinalizeProjectReleaseResponse, FinalizeProjectReleaseResponses, FindConversationData, FindConversationErrors, FindConversationResponse, FindConversationResponses, FiringSeriesEntry, FlagEnvironmentResponse, FlagListResponse, FlagResponse, FlagSnapshot, FlagSnapshotResponse, FlagValueType, ForecastAlgorithm, ForecastParams, FullError, FullEvent, FullRequest, FunnelMetricsResponse, FunnelResponse, GatewayStatus, GenAiEvent, GenAiSpanDetail, GenAiTraceDetailResponse, GenAiTraceSummariesResponse, GenAiTraceSummary, GeneralStatsQuery, GeneralStatsResponse, GenerateDockerfileRequest, GenerateDockerfileResponse, GenerateJoinTokenData, GenerateJoinTokenErrors, GenerateJoinTokenResponse, GenerateJoinTokenResponse2, GenerateJoinTokenResponses, GeneratePresetDockerfileData, GeneratePresetDockerfileErrors, GeneratePresetDockerfileResponse, GeneratePresetDockerfileResponses, GeoLocationResponse, GeoRestrictionsConfig, GetAccessInfoData, GetAccessInfoErrors, GetAccessInfoResponse, GetAccessInfoResponses, GetActiveVisitorsData, GetActiveVisitorsErrors, GetActiveVisitorsResponse, GetActiveVisitorsResponses, GetActivityGraphData, GetActivityGraphErrors, GetActivityGraphResponse, GetActivityGraphResponses, GetAdminGateData, GetAdminGateErrors, GetAdminGateResponse, GetAdminGateResponses, GetAgentData, GetAgentErrors, GetAgentResponse, GetAgentResponses, GetAggregatedBucketsData, GetAggregatedBucketsErrors, GetAggregatedBucketsResponse, GetAggregatedBucketsResponses, GetAiAgentBreakdownData, GetAiAgentBreakdownError, GetAiAgentBreakdownErrors, GetAiAgentBreakdownResponse, GetAiAgentBreakdownResponses, GetAiAgentPagesData, GetAiAgentPagesError, GetAiAgentPagesErrors, GetAiAgentPagesResponse, GetAiAgentPagesResponses, GetAiAgentTimelineData, GetAiAgentTimelineError, GetAiAgentTimelineErrors, GetAiAgentTimelineResponse, GetAiAgentTimelineResponses, GetAiPageBreakdownData, GetAiPageBreakdownError, GetAiPageBreakdownErrors, GetAiPageBreakdownResponse, GetAiPageBreakdownResponses, GetAiStatusBreakdownData, GetAiStatusBreakdownError, GetAiStatusBreakdownErrors, GetAiStatusBreakdownResponse, GetAiStatusBreakdownResponses, GetAlertData, GetAlertError, GetAlertErrors, GetAlertResponse, GetAlertResponses, GetAlertRuleData, GetAlertRuleErrors, GetAlertRuleResponse, GetAlertRuleResponses, GetAllRepositoriesByNameData, GetAllRepositoriesByNameErrors, GetAllRepositoriesByNameResponse, GetAllRepositoriesByNameResponses, GetAnalyticsActiveVisitorsData, GetAnalyticsActiveVisitorsErrors, GetAnalyticsActiveVisitorsResponse, GetAnalyticsActiveVisitorsResponses, GetAnalyticsEventsCountData, GetAnalyticsEventsCountErrors, GetAnalyticsEventsCountResponse, GetAnalyticsEventsCountResponses, GetAnalyticsSessionEventsData, GetAnalyticsSessionEventsErrors, GetAnalyticsSessionEventsResponse, GetAnalyticsSessionEventsResponses, GetAnalyticsVisitorSessionsData, GetAnalyticsVisitorSessionsErrors, GetAnalyticsVisitorSessionsResponse, GetAnalyticsVisitorSessionsResponses, GetApiKeyData, GetApiKeyErrors, GetApiKeyPermissionsData, GetApiKeyPermissionsErrors, GetApiKeyPermissionsResponse, GetApiKeyPermissionsResponses, GetApiKeyResponse, GetApiKeyResponses, GetAuditLogData, GetAuditLogErrors, GetAuditLogResponse, GetAuditLogResponses, GetBackupData, GetBackupError, GetBackupErrors, GetBackupResponse, GetBackupResponses, GetBackupScheduleData, GetBackupScheduleErrors, GetBackupScheduleResponse, GetBackupScheduleResponses, GetBranchesByRepositoryIdData, GetBranchesByRepositoryIdErrors, GetBranchesByRepositoryIdResponse, GetBranchesByRepositoryIdResponses, GetBucketedIncidentsData, GetBucketedIncidentsErrors, GetBucketedIncidentsResponse, GetBucketedIncidentsResponses, GetBucketedStatusData, GetBucketedStatusErrors, GetBucketedStatusResponse, GetBucketedStatusResponses, GetChallengeTokenData, GetChallengeTokenErrors, GetChallengeTokenResponse, GetChallengeTokenResponses, GetChatReadinessData, GetChatReadinessErrors, GetChatReadinessResponse, GetChatReadinessResponses, GetCliStatusData, GetCliStatusErrors, GetCliStatusResponses, GetClusterHealthData, GetClusterHealthErrors, GetClusterHealthResponse, GetClusterHealthResponses, GetClusterMemberData, GetClusterMemberErrors, GetClusterMemberResponse, GetClusterMemberResponses, GetCmdData, GetCmdErrors, GetCmdResponse, GetCmdResponses, GetContainerDetailData, GetContainerDetailErrors, GetContainerDetailResponse, GetContainerDetailResponses, GetContainerEnvironmentVariableData, GetContainerEnvironmentVariableErrors, GetContainerEnvironmentVariableResponse, GetContainerEnvironmentVariableResponses, GetContainerInfoData, GetContainerInfoErrors, GetContainerInfoResponse, GetContainerInfoResponses, GetContainerLogsByIdData, GetContainerLogsByIdErrors, GetContainerLogsData, GetContainerLogsErrors, GetContainerMetricsData, GetContainerMetricsErrors, GetContainerMetricsResponse, GetContainerMetricsResponses, GetConversationData, GetConversationDetailData, GetConversationDetailError, GetConversationDetailErrors, GetConversationDetailResponse, GetConversationDetailResponses, GetConversationErrors, GetConversationResponse, GetConversationResponses, GetConversationsData, GetConversationsError, GetConversationsErrors, GetConversationsResponse, GetConversationsResponses, GetCronByIdData, GetCronByIdErrors, GetCronByIdResponse, GetCronByIdResponses, GetCronExecutionsData, GetCronExecutionsErrors, GetCronExecutionsResponse, GetCronExecutionsResponses, GetCrossProjectTraceSiblingsData, GetCrossProjectTraceSiblingsError, GetCrossProjectTraceSiblingsErrors, GetCrossProjectTraceSiblingsResponse, GetCrossProjectTraceSiblingsResponses, GetCurrentMonitorStatusData, GetCurrentMonitorStatusErrors, GetCurrentMonitorStatusResponse, GetCurrentMonitorStatusResponses, GetCurrentUserData, GetCurrentUserErrors, GetCurrentUserResponse, GetCurrentUserResponses, GetCustomDomainData, GetCustomDomainErrors, GetCustomDomainResponse, GetCustomDomainResponses, GetDashboardData, GetDashboardError, GetDashboardErrors, GetDashboardProjectsAnalyticsData, GetDashboardProjectsAnalyticsErrors, GetDashboardProjectsAnalyticsResponse, GetDashboardProjectsAnalyticsResponses, GetDashboardResponse, GetDashboardResponses, GetDeliveryData, GetDeliveryErrors, GetDeliveryResponse, GetDeliveryResponses, GetDeploymentContainerLogContentData, GetDeploymentContainerLogContentErrors, GetDeploymentContainerLogContentResponse, GetDeploymentContainerLogContentResponses, GetDeploymentData, GetDeploymentErrors, GetDeploymentJobLogsData, GetDeploymentJobLogsErrors, GetDeploymentJobLogsResponse, GetDeploymentJobLogsResponses, GetDeploymentJobsData, GetDeploymentJobsErrors, GetDeploymentJobsResponse, GetDeploymentJobsResponses, GetDeploymentOperationsData, GetDeploymentOperationsErrors, GetDeploymentOperationsResponse, GetDeploymentOperationsResponses, GetDeploymentOperationStatusData, GetDeploymentOperationStatusErrors, GetDeploymentOperationStatusResponse, GetDeploymentOperationStatusResponses, GetDeploymentResponse, GetDeploymentResponses, GetDeploymentsParams, GetDeploymentTokenData, GetDeploymentTokenErrors, GetDeploymentTokenResponse, GetDeploymentTokenResponses, GetDiskStatusData, GetDiskStatusErrors, GetDiskStatusResponse, GetDiskStatusResponses, GetDnsChangesData, GetDnsChangesErrors, GetDnsChangesResponse, GetDnsChangesResponses, GetDnsProviderData, GetDnsProviderErrors, GetDnsProviderResponse, GetDnsProviderResponses, GetDomainByHostData, GetDomainByHostErrors, GetDomainByHostResponse, GetDomainByHostResponses, GetDomainByIdData, GetDomainByIdErrors, GetDomainByIdResponse, GetDomainByIdResponses, GetDomainByNameData, GetDomainByNameErrors, GetDomainByNameResponse, GetDomainByNameResponses, GetDomainData, GetDomainDnsRecordsData, GetDomainDnsRecordsErrors, GetDomainDnsRecordsResponse, GetDomainDnsRecordsResponses, GetDomainErrors, GetDomainOrderData, GetDomainOrderErrors, GetDomainOrderResponse, GetDomainOrderResponses, GetDomainResponse, GetDomainResponses, GetEmailData, GetEmailErrors, GetEmailEventsData, GetEmailEventsErrors, GetEmailEventsResponse, GetEmailEventsResponses, GetEmailLinksData, GetEmailLinksErrors, GetEmailLinksResponse, GetEmailLinksResponses, GetEmailProviderData, GetEmailProviderErrors, GetEmailProviderResponse, GetEmailProviderResponses, GetEmailResponse, GetEmailResponses, GetEmailStatsData, GetEmailStatsErrors, GetEmailStatsResponse, GetEmailStatsResponses, GetEmailTrackingData, GetEmailTrackingErrors, GetEmailTrackingResponse, GetEmailTrackingResponses, GetEmailTrackingStatusData, GetEmailTrackingStatusErrors, GetEmailTrackingStatusResponse, GetEmailTrackingStatusResponses, GetEntityInfoData, GetEntityInfoErrors, GetEntityInfoResponse, GetEntityInfoResponses, GetEnvironmentCronsData, GetEnvironmentCronsErrors, GetEnvironmentCronsResponse, GetEnvironmentCronsResponses, GetEnvironmentData, GetEnvironmentDomainsData, GetEnvironmentDomainsErrors, GetEnvironmentDomainsResponse, GetEnvironmentDomainsResponses, GetEnvironmentErrors, GetEnvironmentResponse, GetEnvironmentResponses, GetEnvironmentsData, GetEnvironmentsErrors, GetEnvironmentsResponse, GetEnvironmentsResponses, GetEnvironmentVariablesData, GetEnvironmentVariablesErrors, GetEnvironmentVariablesQuery, GetEnvironmentVariablesResponse, GetEnvironmentVariablesResponses, GetEnvironmentVariableValueData, GetEnvironmentVariableValueErrors, GetEnvironmentVariableValueResponse, GetEnvironmentVariableValueResponses, GetErrorDashboardStatsData, GetErrorDashboardStatsErrors, GetErrorDashboardStatsResponse, GetErrorDashboardStatsResponses, GetErrorEventData, GetErrorEventErrors, GetErrorEventResponse, GetErrorEventResponses, GetErrorGroupData, GetErrorGroupErrors, GetErrorGroupResponse, GetErrorGroupResponses, GetErrorStatsData, GetErrorStatsErrors, GetErrorStatsResponse, GetErrorStatsResponses, GetErrorTimeSeriesData, GetErrorTimeSeriesErrors, GetErrorTimeSeriesResponse, GetErrorTimeSeriesResponses, GetEventDetailData, GetEventDetailErrors, GetEventDetailResponse, GetEventDetailResponses, GetEventEntriesData, GetEventEntriesErrors, GetEventEntriesResponse, GetEventEntriesResponses, GetEventsCountData, GetEventsCountErrors, GetEventsCountResponse, GetEventsCountResponses, GetEventsTimelineData, GetEventsTimelineErrors, GetEventsTimelineResponse, GetEventsTimelineResponses, GetEventTypeBreakdownData, GetEventTypeBreakdownErrors, GetEventTypeBreakdownResponse, GetEventTypeBreakdownResponses, GetEventVisitorsData, GetEventVisitorsErrors, GetEventVisitorsResponse, GetEventVisitorsResponses, GetExternalImageData, GetExternalImageErrors, GetExternalImageResponse, GetExternalImageResponses, GetFileData, GetFileErrors, GetFileResponse, GetFileResponses, GetFlagData, GetFlagErrors, GetFlagResponse, GetFlagResponses, GetFlagSnapshotData, GetFlagSnapshotErrors, GetFlagSnapshotResponse, GetFlagSnapshotResponses, GetFunnelMetricsData, GetFunnelMetricsErrors, GetFunnelMetricsQuery, GetFunnelMetricsResponse, GetFunnelMetricsResponses, GetGenaiTraceData, GetGenaiTraceError, GetGenaiTraceErrors, GetGenaiTraceResponse, GetGenaiTraceResponses, GetGeneralStatsData, GetGeneralStatsErrors, GetGeneralStatsResponse, GetGeneralStatsResponses, GetGitProviderData, GetGitProviderErrors, GetGitProviderResponse, GetGitProviderResponses, GetGlobalEventsData, GetGlobalEventsErrors, GetGlobalEventsResponse, GetGlobalEventsResponses, GetGlobalEventStatsData, GetGlobalEventStatsErrors, GetGlobalEventStatsResponse, GetGlobalEventStatsResponses, GetGlobalMcpData, GetGlobalMcpErrors, GetGlobalMcpResponse, GetGlobalMcpResponses, GetGlobalSandboxStatusData, GetGlobalSandboxStatusErrors, GetGlobalSandboxStatusResponse, GetGlobalSandboxStatusResponses, GetGlobalSkillData, GetGlobalSkillErrors, GetGlobalSkillResponse, GetGlobalSkillResponses, GetGroupedPageMetricsData, GetGroupedPageMetricsError, GetGroupedPageMetricsErrors, GetGroupedPageMetricsResponse, GetGroupedPageMetricsResponses, GetHealthData, GetHealthError, GetHealthErrors, GetHealthResponse, GetHealthResponses, GetHourlyVisitsData, GetHourlyVisitsErrors, GetHourlyVisitsResponse, GetHourlyVisitsResponses, GetHttpChallengeDebugData, GetHttpChallengeDebugErrors, GetHttpChallengeDebugResponse, GetHttpChallengeDebugResponses, GetImportStatusData, GetImportStatusErrors, GetImportStatusResponse, GetImportStatusResponses, GetIncidentData, GetIncidentErrors, GetIncidentResponse, GetIncidentResponses, GetIncidentUpdatesData, GetIncidentUpdatesErrors, GetIncidentUpdatesResponse, GetIncidentUpdatesResponses, GetIpAccessControlData, GetIpAccessControlError, GetIpAccessControlErrors, GetIpAccessControlResponse, GetIpAccessControlResponses, GetIpGeolocationData, GetIpGeolocationError, GetIpGeolocationErrors, GetIpGeolocationResponse, GetIpGeolocationResponses, GetJoinTokenStatusData, GetJoinTokenStatusErrors, GetJoinTokenStatusResponse, GetJoinTokenStatusResponses, GetLastDeploymentData, GetLastDeploymentErrors, GetLastDeploymentResponse, GetLastDeploymentResponses, GetLatestScanData, GetLatestScanError, GetLatestScanErrors, GetLatestScanResponse, GetLatestScanResponses, GetLatestScansPerEnvironmentData, GetLatestScansPerEnvironmentError, GetLatestScansPerEnvironmentErrors, GetLatestScansPerEnvironmentResponse, GetLatestScansPerEnvironmentResponses, GetLiveVisitorsListData, GetLiveVisitorsListErrors, GetLiveVisitorsListResponse, GetLiveVisitorsListResponses, GetLogContextData, GetLogContextError, GetLogContextErrors, GetLogContextResponse, GetLogContextResponses, GetMcpData, GetMcpErrors, GetMcpResponse, GetMcpResponses, GetMetricsOverTimeData, GetMetricsOverTimeError, GetMetricsOverTimeErrors, GetMetricsOverTimeResponse, GetMetricsOverTimeResponses, GetMonitorData, GetMonitorErrors, GetMonitorResponse, GetMonitorResponses, GetNotificationProviderData, GetNotificationProviderErrors, GetNotificationProviderResponse, GetNotificationProviderResponses, GetOnDemandCertStatusData, GetOnDemandCertStatusErrors, GetOnDemandCertStatusResponse, GetOnDemandCertStatusResponses, GetOrCreateDsnData, GetOrCreateDsnErrors, GetOrCreateDsnRequest, GetOrCreateDsnResponse, GetOrCreateDsnResponses, GetPageFlowData, GetPageFlowErrors, GetPageFlowResponse, GetPageFlowResponses, GetPageHourlySessionsData, GetPageHourlySessionsErrors, GetPageHourlySessionsResponse, GetPageHourlySessionsResponses, GetPagePathDetailData, GetPagePathDetailErrors, GetPagePathDetailResponse, GetPagePathDetailResponses, GetPagePathsData, GetPagePathsErrors, GetPagePathsResponse, GetPagePathsResponses, GetPagePathsSparklinesData, GetPagePathsSparklinesErrors, GetPagePathsSparklinesResponse, GetPagePathsSparklinesResponses, GetPagePathVisitorsData, GetPagePathVisitorsErrors, GetPagePathVisitorsResponse, GetPagePathVisitorsResponses, GetPendingActionData, GetPendingActionErrors, GetPendingActionResponse, GetPendingActionResponses, GetPerformanceMetricsData, GetPerformanceMetricsError, GetPerformanceMetricsErrors, GetPerformanceMetricsResponse, GetPerformanceMetricsResponses, GetPgUpgradeData, GetPgUpgradeErrors, GetPgUpgradeLogsData, GetPgUpgradeLogsErrors, GetPgUpgradeLogsResponse, GetPgUpgradeLogsResponses, GetPgUpgradeResponse, GetPgUpgradeResponses, GetPipelineStatsData, GetPipelineStatsError, GetPipelineStatsErrors, GetPipelineStatsResponse, GetPipelineStatsResponses, GetPlatformInfoData, GetPlatformInfoErrors, GetPlatformInfoResponse, GetPlatformInfoResponses, GetPostgresWalHealthData, GetPostgresWalHealthErrors, GetPostgresWalHealthResponse, GetPostgresWalHealthResponses, GetPreferencesData, GetPreferencesErrors, GetPreferencesResponse, GetPreferencesResponses, GetPreviewGatewayLogsData, GetPreviewGatewayLogsResponse, GetPreviewGatewayLogsResponses, GetPreviewGatewaySettingsData, GetPreviewGatewaySettingsResponse, GetPreviewGatewaySettingsResponses, GetPreviewGatewayStatusData, GetPreviewGatewayStatusResponse, GetPreviewGatewayStatusResponses, GetPricingData, GetPricingError, GetPricingErrors, GetPricingResponse, GetPricingResponses, GetPrivateIpData, GetPrivateIpErrors, GetPrivateIpResponses, GetProjectAlarmsSummaryData, GetProjectAlarmsSummaryErrors, GetProjectAlarmsSummaryResponse, GetProjectAlarmsSummaryResponses, GetProjectBySlugData, GetProjectBySlugErrors, GetProjectBySlugResponse, GetProjectBySlugResponses, GetProjectData, GetProjectDeploymentsData, GetProjectDeploymentsErrors, GetProjectDeploymentsResponse, GetProjectDeploymentsResponses, GetProjectErrors, GetProjectResponse, GetProjectResponses, GetProjectsData, GetProjectSecretsQuery, GetProjectsErrors, GetProjectServiceEnvironmentVariablesData, GetProjectServiceEnvironmentVariablesErrors, GetProjectServiceEnvironmentVariablesResponse, GetProjectServiceEnvironmentVariablesResponses, GetProjectSessionReplaysData, GetProjectSessionReplaysError, GetProjectSessionReplaysErrors, GetProjectSessionReplaysQuery, GetProjectSessionReplaysResponse, GetProjectSessionReplaysResponse2, GetProjectSessionReplaysResponses, GetProjectsHealthData, GetProjectsHealthError, GetProjectsHealthErrors, GetProjectsHealthResponse, GetProjectsHealthResponses, GetProjectsMonitorHealthData, GetProjectsMonitorHealthErrors, GetProjectsMonitorHealthResponse, GetProjectsMonitorHealthResponses, GetProjectsResponse, GetProjectsResponses, GetProjectStatisticsData, GetProjectStatisticsErrors, GetProjectStatisticsResponse, GetProjectStatisticsResponses, GetProjectTemplateData, GetProjectTemplateErrors, GetProjectTemplateResponse, GetProjectTemplateResponses, GetPropertyBreakdownData, GetPropertyBreakdownErrors, GetPropertyBreakdownResponse, GetPropertyBreakdownResponses, GetPropertyTimelineData, GetPropertyTimelineErrors, GetPropertyTimelineResponse, GetPropertyTimelineResponses, GetProviderConnectionsData, GetProviderConnectionsErrors, GetProviderConnectionsResponse, GetProviderConnectionsResponses, GetProviderMetadataData, GetProviderMetadataErrors, GetProviderMetadataResponse, GetProviderMetadataResponses, GetProvidersMetadataData, GetProvidersMetadataErrors, GetProvidersMetadataResponse, GetProvidersMetadataResponses, GetProxyLogByIdData, GetProxyLogByIdError, GetProxyLogByIdErrors, GetProxyLogByIdResponse, GetProxyLogByIdResponses, GetProxyLogByRequestIdData, GetProxyLogByRequestIdError, GetProxyLogByRequestIdErrors, GetProxyLogByRequestIdResponse, GetProxyLogByRequestIdResponses, GetProxyLogsData, GetProxyLogsError, GetProxyLogsErrors, GetProxyLogsResponse, GetProxyLogsResponses, GetPublicBranchesData, GetPublicBranchesErrors, GetPublicBranchesResponse, GetPublicBranchesResponses, GetPublicIpData, GetPublicIpErrors, GetPublicIpResponses, GetPublicRepositoryData, GetPublicRepositoryErrors, GetPublicRepositoryResponse, GetPublicRepositoryResponses, GetQuotaData, GetQuotaError, GetQuotaErrors, GetQuotaResponse, GetQuotaResponses, GetRecentActivityData, GetRecentActivityErrors, GetRecentActivityResponse, GetRecentActivityResponses, GetRemoteExternalImageData, GetRemoteExternalImageErrors, GetRemoteExternalImageResponse, GetRemoteExternalImageResponses, GetRepositoryBranchesData, GetRepositoryBranchesErrors, GetRepositoryBranchesResponse, GetRepositoryBranchesResponses, GetRepositoryByIdData, GetRepositoryByIdErrors, GetRepositoryByIdResponse, GetRepositoryByIdResponses, GetRepositoryByNameData, GetRepositoryByNameErrors, GetRepositoryByNameResponse, GetRepositoryByNameResponses, GetRepositoryPresetByNameData, GetRepositoryPresetByNameErrors, GetRepositoryPresetByNameResponse, GetRepositoryPresetByNameResponses, GetRepositoryPresetLiveData, GetRepositoryPresetLiveErrors, GetRepositoryPresetLiveResponse, GetRepositoryPresetLiveResponses, GetRepositoryTagsData, GetRepositoryTagsErrors, GetRepositoryTagsResponse, GetRepositoryTagsResponses, GetRequest, GetResolvedEnvironmentVariablesData, GetResolvedEnvironmentVariablesErrors, GetResolvedEnvironmentVariablesResponse, GetResolvedEnvironmentVariablesResponses, GetResolvedEnvironmentVariableValueData, GetResolvedEnvironmentVariableValueErrors, GetResolvedEnvironmentVariableValueResponse, GetResolvedEnvironmentVariableValueResponses, GetResponse, GetRestoreCapabilitiesData, GetRestoreCapabilitiesError, GetRestoreCapabilitiesErrors, GetRestoreCapabilitiesResponse, GetRestoreCapabilitiesResponses, GetRestoreRunData, GetRestoreRunError, GetRestoreRunErrors, GetRestoreRunResponse, GetRestoreRunResponses, GetRouteData, GetRouteErrors, GetRouteResponse, GetRouteResponses, GetRunData, GetRunErrors, GetRunResponse, GetRunResponses, GetRunWithLogsData, GetRunWithLogsErrors, GetRunWithLogsResponse, GetRunWithLogsResponses, GetS3CredentialsData, GetS3CredentialsErrors, GetS3CredentialsResponse, GetS3CredentialsResponses, GetS3SourceData, GetS3SourceError, GetS3SourceErrors, GetS3SourceResponse, GetS3SourceResponses, GetSandboxData, GetSandboxErrors, GetSandboxResponse, GetSandboxResponses, GetSandboxStatusData, GetSandboxStatusErrors, GetSandboxStatusResponse, GetSandboxStatusResponses, GetScanByDeploymentData, GetScanByDeploymentError, GetScanByDeploymentErrors, GetScanByDeploymentResponse, GetScanByDeploymentResponses, GetScanData, GetScanError, GetScanErrors, GetScanResponse, GetScanResponses, GetScanVulnerabilitiesData, GetScanVulnerabilitiesError, GetScanVulnerabilitiesErrors, GetScanVulnerabilitiesResponse, GetScanVulnerabilitiesResponses, GetServiceBySlugData, GetServiceBySlugErrors, GetServiceBySlugResponse, GetServiceBySlugResponses, GetServiceData, GetServiceEnvironmentVariableData, GetServiceEnvironmentVariableErrors, GetServiceEnvironmentVariableResponse, GetServiceEnvironmentVariableResponses, GetServiceEnvironmentVariablesData, GetServiceEnvironmentVariablesErrors, GetServiceEnvironmentVariablesResponse, GetServiceEnvironmentVariablesResponses, GetServiceErrors, GetServiceHealthStatusData, GetServiceHealthStatusErrors, GetServiceHealthStatusResponse, GetServiceHealthStatusResponses, GetServicePreviewEnvironmentVariableNamesData, GetServicePreviewEnvironmentVariableNamesErrors, GetServicePreviewEnvironmentVariableNamesResponse, GetServicePreviewEnvironmentVariableNamesResponses, GetServicePreviewEnvironmentVariablesMaskedData, GetServicePreviewEnvironmentVariablesMaskedErrors, GetServicePreviewEnvironmentVariablesMaskedResponse, GetServicePreviewEnvironmentVariablesMaskedResponses, GetServiceResponse, GetServiceResponses, GetServiceRuntimeData, GetServiceRuntimeErrors, GetServiceRuntimeResponse, GetServiceRuntimeResponses, GetServiceStatsData, GetServiceStatsErrors, GetServiceStatsResponse, GetServiceStatsResponses, GetServiceTypeParametersData, GetServiceTypeParametersErrors, GetServiceTypeParametersResponses, GetServiceTypesData, GetServiceTypesErrors, GetServiceTypesResponse, GetServiceTypesResponses, GetSessionDetailsData, GetSessionDetailsErrors, GetSessionDetailsResponse, GetSessionDetailsResponses, GetSessionEventsData, GetSessionEventsErrors, GetSessionEventsResponse, GetSessionEventsResponses, GetSessionLogsData, GetSessionLogsErrors, GetSessionLogsResponse, GetSessionLogsResponses, GetSessionReplayData, GetSessionReplayError, GetSessionReplayErrors, GetSessionReplayEventsData, GetSessionReplayEventsError, GetSessionReplayEventsErrors, GetSessionReplayEventsResponse, GetSessionReplayEventsResponses, GetSessionReplayResponse, GetSessionReplayResponse2, GetSessionReplayResponses, GetSettingsData, GetSettingsErrors, GetSettingsResponse, GetSettingsResponses, GetSkillData, GetSkillErrors, GetSkillResponse, GetSkillResponses, GetSlowQueriesData, GetSlowQueriesErrors, GetSlowQueriesResponse, GetSlowQueriesResponses, GetStaticBundleData, GetStaticBundleErrors, GetStaticBundleResponse, GetStaticBundleResponses, GetStatusOverviewData, GetStatusOverviewErrors, GetStatusOverviewResponse, GetStatusOverviewResponses, GetTagsByRepositoryIdData, GetTagsByRepositoryIdErrors, GetTagsByRepositoryIdResponse, GetTagsByRepositoryIdResponses, GetTeamData, GetTeamErrors, GetTeamResponse, GetTeamResponses, GetTimeBucketStatsData, GetTimeBucketStatsError, GetTimeBucketStatsErrors, GetTimeBucketStatsResponse, GetTimeBucketStatsResponses, GetTodayStatsData, GetTodayStatsError, GetTodayStatsErrors, GetTodayStatsResponse, GetTodayStatsResponses, GetTraceData, GetTraceError, GetTraceErrors, GetTraceResponse, GetTraceResponses, GetUnifiedTraceData, GetUnifiedTraceError, GetUnifiedTraceErrors, GetUnifiedTraceResponse, GetUnifiedTraceResponses, GetUniqueCountsData, GetUniqueCountsErrors, GetUniqueCountsResponse, GetUniqueCountsResponses, GetUniqueEventsData, GetUniqueEventsErrors, GetUniqueEventsQuery, GetUniqueEventsResponse, GetUniqueEventsResponses, GetUpdateCapabilityData, GetUpdateCapabilityErrors, GetUpdateCapabilityResponse, GetUpdateCapabilityResponses, GetUpdateStatusData, GetUpdateStatusErrors, GetUpdateStatusResponse, GetUpdateStatusResponses, GetUptimeHistoryData, GetUptimeHistoryErrors, GetUptimeHistoryResponse, GetUptimeHistoryResponses, GetUsageByProviderData, GetUsageByProviderError, GetUsageByProviderErrors, GetUsageByProviderResponse, GetUsageByProviderResponses, GetUsageRecentData, GetUsageRecentError, GetUsageRecentErrors, GetUsageRecentResponse, GetUsageRecentResponses, GetUsageSummaryData, GetUsageSummaryError, GetUsageSummaryErrors, GetUsageSummaryResponse, GetUsageSummaryResponses, GetUsageTimeseriesData, GetUsageTimeseriesError, GetUsageTimeseriesErrors, GetUsageTimeseriesResponse, GetUsageTimeseriesResponses, GetUsageTopModelsData, GetUsageTopModelsError, GetUsageTopModelsErrors, GetUsageTopModelsResponse, GetUsageTopModelsResponses, GetVisitorByGuidData, GetVisitorByGuidErrors, GetVisitorByGuidResponse, GetVisitorByGuidResponses, GetVisitorByIdData, GetVisitorByIdErrors, GetVisitorByIdResponse, GetVisitorByIdResponses, GetVisitorDetailsData, GetVisitorDetailsErrors, GetVisitorDetailsResponse, GetVisitorDetailsResponses, GetVisitorFacetsData, GetVisitorFacetsErrors, GetVisitorFacetsResponse, GetVisitorFacetsResponses, GetVisitorInfoData, GetVisitorInfoErrors, GetVisitorInfoResponse, GetVisitorInfoResponses, GetVisitorJourneyData, GetVisitorJourneyErrors, GetVisitorJourneyResponse, GetVisitorJourneyResponses, GetVisitorsData, GetVisitorsErrors, GetVisitorSessionsData, GetVisitorSessionsError, GetVisitorSessionsErrors, GetVisitorSessionsQuery, GetVisitorSessionsResponse, GetVisitorSessionsResponse2, GetVisitorSessionsResponses, GetVisitorsResponse, GetVisitorsResponses, GetVisitorStatsData, GetVisitorStatsErrors, GetVisitorStatsResponse, GetVisitorStatsResponses, GetWebhookData, GetWebhookErrors, GetWebhookResponse, GetWebhookResponses, GitPushEvent, GitRefResponse, GitSourcePlan, GlobalConversationResponse, GlobalEventStatsResponse, GlobalMrrResponse, GlobalRecentEventResponse, GlobalRevenueSummaryResponse, GrantProjectAccessData, GrantProjectAccessErrors, GrantProjectAccessResponse, GrantProjectAccessResponses, GroupedPageMetric, GroupedPageMetricsQuery, GroupedPageMetricsResponse, HandleGitProviderOauthCallbackData, HandleGitProviderOauthCallbackErrors, HasAnalyticsEventsData, HasAnalyticsEventsErrors, HasAnalyticsEventsResponse, HasAnalyticsEventsResponse2, HasAnalyticsEventsResponses, HasErrorGroupsData, HasErrorGroupsErrors, HasErrorGroupsResponse, HasErrorGroupsResponse2, HasErrorGroupsResponses, HasEventsQuery, HasEventsResponse, HasMetricsQuery, HasMetricsResponse, HasPerformanceMetricsData, HasPerformanceMetricsError, HasPerformanceMetricsErrors, HasPerformanceMetricsResponse, HasPerformanceMetricsResponses, HealthCheckConfiguration, HealthCheckEntryResponse, HealthResponse, HealthStatus, HealthSummary, HeartbeatApiRequest, HeartbeatResponse, HierarchyLevel, HistogramSummary, HostnameChange, HostnamePreviewResponse, HourlyPageSessions, HourlyVisitsQuery, HttpChallengeDebugResponse, ImportCredentials, ImportExecutionStatus, ImportExternalServiceData, ImportExternalServiceErrors, ImportExternalServiceRequest, ImportExternalServiceResponse, ImportExternalServiceResponses, ImportOutcomeResponse, ImportPlan, ImportRowErrorResponse, ImportSelector, ImportSource, ImportSourceCapabilities, ImportSourceInfo, ImportStatusResponse, IncidentBucket, IncidentBucketedResponse, IncidentResponse, IncidentUpdateResponse, IncrRequest, IncrResponse, IngestLogsByPathData, IngestLogsByPathError, IngestLogsByPathErrors, IngestLogsByPathResponses, IngestLogsData, IngestLogsError, IngestLogsErrors, IngestLogsResponses, IngestMetricsByPathData, IngestMetricsByPathError, IngestMetricsByPathErrors, IngestMetricsByPathResponses, IngestMetricsData, IngestMetricsError, IngestMetricsErrors, IngestMetricsResponses, IngestSentryEnvelopeData, IngestSentryEnvelopeErrors, IngestSentryEnvelopeResponses, IngestSentryEventData, IngestSentryEventErrors, IngestSentryEventResponse, IngestSentryEventResponses, IngestTracesByPathData, IngestTracesByPathError, IngestTracesByPathErrors, IngestTracesByPathResponses, IngestTracesData, IngestTracesError, IngestTracesErrors, IngestTracesResponses, InitAuthResponse, InitSessionReplayData, InitSessionReplayError, InitSessionReplayErrors, InitSessionReplayResponse, InitSessionReplayResponses, Insight, InsightSeverity, InsightsResponse, InsightStatus, InspectDropArchiveData, InspectDropArchiveErrors, InspectDropArchiveResponse, InspectDropArchiveResponses, IntegrationResponse, IpAccessControlQuery, IpAccessControlResponse, JobLogsData, JobLogsErrors, JobLogsResponses, JobStatusData, JobStatusErrors, JobStatusResponse, JobStatusResponse2, JobStatusResponses, JobSummaryResponse, JoinTokenStatusResponse, JourneyEvent, JourneySession, KeysRequest, KeysResponse, KillJobBody, KillJobData, KillJobErrors, KillJobResponse, KillJobResponses, KnownAiAgentsResponse, KvDelData, KvDelErrors, KvDelResponse, KvDelResponses, KvDisableData, KvDisableErrors, KvDisableResponse, KvDisableResponses, KvEnableData, KvEnableErrors, KvEnableResponse, KvEnableResponses, KvExpireData, KvExpireErrors, KvExpireResponse, KvExpireResponses, KvGetData, KvGetErrors, KvGetResponse, KvGetResponses, KvIncrData, KvIncrErrors, KvIncrResponse, KvIncrResponses, KvKeysData, KvKeysErrors, KvKeysResponse, KvKeysResponses, KvSetData, KvSetErrors, KvSetResponse, KvSetResponses, KvStatusData, KvStatusErrors, KvStatusResponse, KvStatusResponse2, KvStatusResponses, KvTtlData, KvTtlErrors, KvTtlResponse, KvTtlResponses, KvUpdateData, KvUpdateErrors, KvUpdateResponse, KvUpdateResponses, LatestRunForSourceData, LatestRunForSourceErrors, LatestRunForSourceResponse, LatestRunForSourceResponses, LemonSqueezyConfig, LetsEncryptSettings, LineContext, LinkCustomDomainToCertificateData, LinkCustomDomainToCertificateErrors, LinkCustomDomainToCertificateResponse, LinkCustomDomainToCertificateResponses, LinkServiceRequest, LinkServiceToProjectData, LinkServiceToProjectErrors, LinkServiceToProjectResponse, LinkServiceToProjectResponses, ListAgentRunsData, ListAgentRunsErrors, ListAgentRunsResponse, ListAgentRunsResponses, ListAgentsData, ListAgentsErrors, ListAgentsResponse, ListAgentsResponse2, ListAgentsResponses, ListAiProvidersData, ListAiProvidersErrors, ListAiProvidersResponse, ListAiProvidersResponses, ListAlertRulesData, ListAlertRulesErrors, ListAlertRulesResponse, ListAlertRulesResponses, ListAlertsData, ListAlertsError, ListAlertsErrors, ListAlertsResponse, ListAlertsResponses, ListAllConversationsData, ListAllConversationsErrors, ListAllConversationsResponse, ListAllConversationsResponses, ListAllRunsData, ListAllRunsErrors, ListAllRunsResponse, ListAllRunsResponses, ListApiKeysData, ListApiKeysErrors, ListApiKeysQuery, ListApiKeysResponse, ListApiKeysResponses, ListAuditLogsData, ListAuditLogsErrors, ListAuditLogsQuery, ListAuditLogsResponse, ListAuditLogsResponses, ListAvailableContainersData, ListAvailableContainersErrors, ListAvailableContainersResponse, ListAvailableContainersResponses, ListBackupAlertsData, ListBackupAlertsError, ListBackupAlertsErrors, ListBackupAlertsResponse, ListBackupAlertsResponses, ListBackupChildrenData, ListBackupChildrenError, ListBackupChildrenErrors, ListBackupChildrenResponse, ListBackupChildrenResponses, ListBackupSchedulesData, ListBackupSchedulesError, ListBackupSchedulesErrors, ListBackupSchedulesResponse, ListBackupSchedulesResponses, ListBackupsForScheduleData, ListBackupsForScheduleErrors, ListBackupsForScheduleResponse, ListBackupsForScheduleResponses, ListBlobsQuery, ListBlobsResponse, ListCommitsByRepositoryIdData, ListCommitsByRepositoryIdErrors, ListCommitsByRepositoryIdResponse, ListCommitsByRepositoryIdResponses, ListConnectionsData, ListConnectionsErrors, ListConnectionsResponse, ListConnectionsResponses, ListContainersAtPathData, ListContainersAtPathErrors, ListContainersAtPathResponse, ListContainersAtPathResponses, ListContainersData, ListContainersErrors, ListContainersResponse, ListContainersResponses, ListConversationsData, ListConversationsErrors, ListConversationsResponse, ListConversationsResponses, ListCustomDomainsForProjectData, ListCustomDomainsForProjectErrors, ListCustomDomainsForProjectResponse, ListCustomDomainsForProjectResponses, ListCustomDomainsResponse, ListDashboardsData, ListDashboardsError, ListDashboardsErrors, ListDashboardsResponse, ListDashboardsResponses, ListDeliveriesData, ListDeliveriesErrors, ListDeliveriesResponse, ListDeliveriesResponses, ListDeploymentContainerLogsData, ListDeploymentContainerLogsErrors, ListDeploymentContainerLogsResponse, ListDeploymentContainerLogsResponses, ListDeploymentTokensData, ListDeploymentTokensErrors, ListDeploymentTokensQuery, ListDeploymentTokensResponse, ListDeploymentTokensResponses, ListDnsProvidersData, ListDnsProvidersErrors, ListDnsProvidersResponse, ListDnsProvidersResponses, ListDomainsData, ListDomainsErrors, ListDomainsResponse, ListDomainsResponse2, ListDomainsResponses, ListDsnsData, ListDsnsErrors, ListDsnsResponse, ListDsnsResponses, ListEmailDomainsData, ListEmailDomainsErrors, ListEmailDomainsResponse, ListEmailDomainsResponses, ListEmailProvidersData, ListEmailProvidersErrors, ListEmailProvidersResponse, ListEmailProvidersResponses, ListEmailsData, ListEmailsErrors, ListEmailsResponse, ListEmailsResponses, ListEnrollmentTokensData, ListEnrollmentTokensErrors, ListEnrollmentTokensResponse, ListEnrollmentTokensResponses, ListEntitiesData, ListEntitiesErrors, ListEntitiesQuery, ListEntitiesResponse, ListEntitiesResponses, ListErrorEventsData, ListErrorEventsErrors, ListErrorEventsQuery, ListErrorEventsResponse, ListErrorEventsResponses, ListErrorGroupsData, ListErrorGroupsErrors, ListErrorGroupsQuery, ListErrorGroupsResponse, ListErrorGroupsResponses, ListEventsData, ListEventsResponse, ListEventsResponses, ListEventTypesData, ListEventTypesResponse, ListEventTypesResponses, ListExternalImagesData, ListExternalImagesErrors, ListExternalImagesResponse, ListExternalImagesResponses, ListExternalPluginsData, ListExternalPluginsErrors, ListExternalPluginsResponse, ListExternalPluginsResponses, ListExternalServiceBackupsData, ListExternalServiceBackupsError, ListExternalServiceBackupsErrors, ListExternalServiceBackupsResponse, ListExternalServiceBackupsResponses, ListFlagsData, ListFlagsErrors, ListFlagsResponse, ListFlagsResponses, ListFunnelsData, ListFunnelsErrors, ListFunnelsResponse, ListFunnelsResponses, ListGitProvidersData, ListGitProvidersErrors, ListGitProvidersResponse, ListGitProvidersResponses, ListGlobalMcpsData, ListGlobalMcpsErrors, ListGlobalMcpsResponse, ListGlobalMcpsResponses, ListGlobalSkillsData, ListGlobalSkillsErrors, ListGlobalSkillsResponse, ListGlobalSkillsResponses, ListIncidentsData, ListIncidentsErrors, ListIncidentsResponses, ListInsightsData, ListInsightsError, ListInsightsErrors, ListInsightsResponse, ListInsightsResponses, ListIpAccessControlData, ListIpAccessControlError, ListIpAccessControlErrors, ListIpAccessControlResponse, ListIpAccessControlResponses, ListJobsData, ListJobsErrors, ListJobsResponse, ListJobsResponse2, ListJobsResponses, ListKnownAiAgentsData, ListKnownAiAgentsError, ListKnownAiAgentsErrors, ListKnownAiAgentsResponse, ListKnownAiAgentsResponses, ListManagedDomainsData, ListManagedDomainsErrors, ListManagedDomainsResponse, ListManagedDomainsResponses, ListMcpsData, ListMcpsErrors, ListMcpsResponse, ListMcpsResponse2, ListMcpsResponses, ListMetricLabelKeysData, ListMetricLabelKeysError, ListMetricLabelKeysErrors, ListMetricLabelKeysResponse, ListMetricLabelKeysResponses, ListMetricLabelValuesData, ListMetricLabelValuesError, ListMetricLabelValuesErrors, ListMetricLabelValuesResponse, ListMetricLabelValuesResponses, ListMetricNamesData, ListMetricNamesError, ListMetricNamesErrors, ListMetricNamesResponse, ListMetricNamesResponses, ListModelsData, ListModelsError, ListModelsErrors, ListModelsResponse, ListModelsResponses, ListMonitorsData, ListMonitorsErrors, ListMonitorsResponse, ListMonitorsResponses, ListNotificationProvidersData, ListNotificationProvidersErrors, ListNotificationProvidersResponse, ListNotificationProvidersResponses, ListOidcProvidersData, ListOidcProvidersResponse, ListOidcProvidersResponses, ListOidcProviderUsersData, ListOidcProviderUsersErrors, ListOidcProviderUsersResponse, ListOidcProviderUsersResponses, ListOidcRoleMappingsData, ListOidcRoleMappingsResponse, ListOidcRoleMappingsResponses, ListOnDemandCertsData, ListOnDemandCertsErrors, ListOnDemandCertsResponse, ListOnDemandCertsResponse2, ListOnDemandCertsResponses, ListOrdersData, ListOrdersErrors, ListOrdersResponse, ListOrdersResponse2, ListOrdersResponses, ListPeersData, ListPeersErrors, ListPeersResponse, ListPeersResponses, ListPendingActionsData, ListPendingActionsErrors, ListPendingActionsResponse, ListPendingActionsResponses, ListPgUpgradesData, ListPgUpgradesErrors, ListPgUpgradesResponse, ListPgUpgradesResponses, ListPresetsData, ListPresetsErrors, ListPresetsResponse, ListPresetsResponse2, ListPresetsResponses, ListProjectAccessData, ListProjectAccessErrors, ListProjectAccessResponse, ListProjectAccessResponses, ListProjectAlarmsData, ListProjectAlarmsErrors, ListProjectAlarmsResponse, ListProjectAlarmsResponses, ListProjectScansData, ListProjectScansError, ListProjectScansErrors, ListProjectScansResponse, ListProjectScansResponses, ListProjectSecretsData, ListProjectSecretsErrors, ListProjectSecretsResponse, ListProjectSecretsResponses, ListProjectServicesData, ListProjectServicesErrors, ListProjectServicesResponse, ListProjectServicesResponses, ListProjectTemplatesData, ListProjectTemplatesErrors, ListProjectTemplatesResponse, ListProjectTemplatesResponses, ListProjectTemplateTagsData, ListProjectTemplateTagsErrors, ListProjectTemplateTagsResponse, ListProjectTemplateTagsResponses, ListProviderKeysData, ListProviderKeysError, ListProviderKeysErrors, ListProviderKeysResponse, ListProviderKeysResponses, ListProviderZonesData, ListProviderZonesErrors, ListProviderZonesResponse, ListProviderZonesResponses, ListPublicProvidersData, ListPublicProvidersResponse, ListPublicProvidersResponses, ListReleaseFilesData, ListReleaseFilesErrors, ListReleaseFilesResponse, ListReleaseFilesResponses, ListReleasesData, ListReleasesErrors, ListReleasesResponse, ListReleasesResponses, ListRemoteExternalImagesData, ListRemoteExternalImagesErrors, ListRemoteExternalImagesResponse, ListRemoteExternalImagesResponses, ListRepositoriesByConnectionData, ListRepositoriesByConnectionErrors, ListRepositoriesByConnectionResponse, ListRepositoriesByConnectionResponses, ListRepositoriesByProviderData, ListRepositoriesByProviderErrors, ListRepositoriesByProviderResponse, ListRepositoriesByProviderResponses, ListRestoreRunsForServiceData, ListRestoreRunsForServiceResponse, ListRestoreRunsForServiceResponses, ListRootContainersData, ListRootContainersErrors, ListRootContainersResponse, ListRootContainersResponses, ListRoutesData, ListRoutesErrors, ListRoutesResponse, ListRoutesResponses, ListRunsResponse, ListS3SourcesData, ListS3SourcesError, ListS3SourcesErrors, ListS3SourcesResponse, ListS3SourcesResponses, ListSandboxesData, ListSandboxesResponse, ListSandboxesResponse2, ListSandboxesResponses, ListScansQuery, ListScheduleRunJobsData, ListScheduleRunJobsError, ListScheduleRunJobsErrors, ListScheduleRunJobsResponse, ListScheduleRunJobsResponses, ListScheduleRunsData, ListScheduleRunsError, ListScheduleRunsErrors, ListScheduleRunsResponse, ListScheduleRunsResponses, ListScheduleServicesData, ListScheduleServicesError, ListScheduleServicesErrors, ListScheduleServicesResponse, ListScheduleServicesResponses, ListSecretsData, ListSecretsErrors, ListSecretsResponse, ListSecretsResponse2, ListSecretsResponses, ListServiceHealthStatusesData, ListServiceHealthStatusesErrors, ListServiceHealthStatusesResponse, ListServiceHealthStatusesResponses, ListServiceProjectsData, ListServiceProjectsErrors, ListServiceProjectsResponse, ListServiceProjectsResponses, ListServiceSchedulesData, ListServiceSchedulesError, ListServiceSchedulesErrors, ListServiceSchedulesResponse, ListServiceSchedulesResponses, ListServicesData, ListServicesErrors, ListServicesResponse, ListServicesResponses, ListSkillsData, ListSkillsErrors, ListSkillsResponse, ListSkillsResponse2, ListSkillsResponses, ListSourceBackupsData, ListSourceBackupsError, ListSourceBackupsErrors, ListSourceBackupsResponse, ListSourceBackupsResponses, ListSourceFilesData, ListSourceFilesErrors, ListSourceFilesResponse, ListSourceFilesResponses, ListSourceMapsData, ListSourceMapsErrors, ListSourceMapsResponse, ListSourceMapsResponses, ListSourcesData, ListSourcesErrors, ListSourcesResponse, ListSourcesResponses, ListStaticBundlesData, ListStaticBundlesErrors, ListStaticBundlesResponse, ListStaticBundlesResponses, ListSyncedRepositoriesData, ListSyncedRepositoriesErrors, ListSyncedRepositoriesResponse, ListSyncedRepositoriesResponses, ListTagsResponse, ListTeamMembersData, ListTeamMembersErrors, ListTeamMembersResponse, ListTeamMembersResponses, ListTeamProjectsData, ListTeamProjectsErrors, ListTeamProjectsResponse, ListTeamProjectsResponses, ListTeamsData, ListTeamsErrors, ListTeamsResponse, ListTeamsResponses, ListTemplatesQuery, ListTemplatesResponse, ListUsersData, ListUsersErrors, ListUsersResponse, ListUsersResponses, ListVulnerabilitiesQuery, ListWebhooksData, ListWebhooksErrors, ListWebhooksResponse, ListWebhooksResponses, LiveVisitorInfo, LiveVisitorsListResponse, LocationCount, LocationGranularity, LocationInfo, LoginData, LoginErrors, LoginRequest, LoginResponse, LoginResponses, LogLevel, LogoutData, LogoutErrors, LogoutResponses, LogRecord, LogSearchLine, LogSeverity, LogSource, LogsQuery, LogsResponse, LogStream, LookupDnsARecordsData, LookupDnsARecordsError, LookupDnsARecordsErrors, LookupDnsARecordsResponse, LookupDnsARecordsResponses, ManagedDomainResponse, ManualAction, ManualActionTiming, McpDefinitionResponse, MessageContent, MessagePart, MessageResponse, MeteredMode, MetricAggregation, MetricBucket, MetricDataPoint, MetricsOverTimeResponse, MetricsQuery, MetricsRangeQuery, MetricsStatusResponse, MetricsStoreKind, MetricsSummaryResponse, MetricType, MfaRequiredResponse, MfaSetupResponse, MfaVerificationRequest, MigrationStep, MigrationSummary, MintEnrollmentTokenData, MintEnrollmentTokenErrors, MintEnrollmentTokenRequest, MintEnrollmentTokenResponse, MintEnrollmentTokenResponse2, MintEnrollmentTokenResponses, MiscResult, MkdirBody, MkdirData, MkdirErrors, MkdirResponse, MkdirResponses, ModelInfo, ModelListResponse, ModelPricing, ModelUsage, MonitoringSettings, MonitoringSettingsMasked, MonitorResponse, MonitorStatus, MrrBucketResponse, MultiNodeSettings, MultiNodeSettingsMasked, MxResult, NavEntry, NavSection, NetworkConfiguration, NetworkMode, NixpacksPresetConfig, NixpacksProvider, NodeContainerListResponse, NodeContainerResponse, NodeCostInfo, NodeHeartbeatData, NodeHeartbeatErrors, NodeHeartbeatResponse, NodeHeartbeatResponses, NodeInfoResponse, NodeListResponse, NodeMetricsGetRangeData, NodeMetricsGetRangeErrors, NodeMetricsGetRangeResponse, NodeMetricsGetRangeResponses, NotificationPreferencesResponse, NotificationProviderResponse, ObservabilityCompressionSettings, ObservabilityEvent, ObservabilityFullEventData, ObservabilityFullEventError, ObservabilityFullEventErrors, ObservabilityFullEventResponse, ObservabilityFullEventResponses, ObservabilityListEventsData, ObservabilityListEventsError, ObservabilityListEventsErrors, ObservabilityListEventsResponse, ObservabilityListEventsResponses, ObservabilityRetentionSettings, OidcCallbackData, OidcProviderResponse, OidcProvidersListResponse, OidcProviderSummary, OidcProviderUserResponse, OidcRoleMappingResponse, OidcTestConnectionResponse, OnDemandCertAttemptResponse, OnDemandCertRow, OnDemandTlsSettings, OpenAiError, OpenAiErrorResponse, OperatingSystemCount, OperationResultResponse, OperationResultsResponse, OtelDashboardResponse, OtelDashboardsResponse, OtelMetricAlertRuleResponse, OtelMetricAlertsResponse, OtelMetricLabelKeysResponse, OtelMetricLabelValuesResponse, OtelMetricNamesResponse, OtelMetricsResponse, OutlierAlgorithm, OutlierParams, OverprovisioningAssessment, OverprovisioningVerdict, PageActivityBucket, PageCountryStats, PageFlowEntry, PageFlowQuery, PageFlowResponse, PageHourlySessionsQuery, PageHourlySessionsResponse, PagePathDetailQuery, PagePathDetailResponse, PagePathInfo, PagePathSparkline, PagePathSparklinePoint, PagePathsQuery, PagePathsResponse, PagePathsSparklineQuery, PagePathsSparklineResponse, PagePathVisitorsQuery, PagePathVisitorsResponse, PageReferrerStats, PagesComparisonResponse, PageSessionComparison, PageSessionStats, PageSessionStatsQuery, PageTransition, PageVisit, PageVisitorSession, PaginatedEmailsResponse, PaginatedEntitiesResponse, PaginatedErrorEventsResponse, PaginatedErrorGroupsResponse, PaginatedEventsResponse, PaginatedExternalImagesResponse, PaginatedProjectList, PaginatedStaticBundlesResponse, Pagination, PaginationMeta, PaginationParams, PasswordProtectionConfig, PatchAdminGateData, PatchAdminGateErrors, PatchAdminGateResponse, PatchAdminGateResponses, PatchPreviewGatewaySettingsData, PatchPreviewGatewaySettingsResponse, PatchPreviewGatewaySettingsResponses, PatchSettingsRequest, PathVisitors, PathVisitorsAnalyticsQuery, PathVisitorsResponse, PauseDeploymentData, PauseDeploymentErrors, PauseDeploymentResponse, PauseDeploymentResponses, PauseSandboxData, PauseSandboxErrors, PauseSandboxResponse, PauseSandboxResponses, PeerEntry, PeerListResponse, PendingActionResponse, PerformanceMetricsQuery, PerformanceMetricsResponse, PermissionInfo, PgUpgradeLogResponse, PgUpgradeResponse, PipelineStats, PipelineStatsResponse, PlanComplexity, PlanMetadata, PlanRestoreData, PlanRestoreError, PlanRestoreErrors, PlanRestoreResponse, PlanRestoreResponses, PlanSourceBackup, PlanTarget, PlatformInfo, PluginManifest, PortMapping, PostDnsAckData, PostDnsAckErrors, PostDnsAckResponse, PostDnsAckResponses, PostgresWalHealth, PresetConfigSchema, PresetInfo, PresetResponse, PreviewAlertData, PreviewAlertError, PreviewAlertErrors, PreviewAlertResponse, PreviewAlertResponses, PreviewFunnelMetricsData, PreviewFunnelMetricsErrors, PreviewFunnelMetricsResponse, PreviewFunnelMetricsResponses, PreviewGatewaySettings, PreviewGatewaySettingsMasked, PreviewGatewaySettingsResponse, PreviewHostnameModeData, PreviewHostnameModeErrors, PreviewHostnameModeResponse, PreviewHostnameModeResponses, PreviewShareLinkBody, PreviewShareLinkResponse, PricingResponse, ProblemDetails, ProjectAccessResponse, ProjectConfiguration, ProjectDashboardAnalytics, ProjectDsnResponse, ProjectHealthSummary, ProjectInfo, ProjectMonitorHealth, ProjectPresetResponse, ProjectQuery, ProjectRef, ProjectResponse, ProjectSecretEnvironmentInfo, ProjectSecretResponse, ProjectServiceInfo, ProjectsHealthResponse, ProjectsMonitorHealthResponse, ProjectStatisticsResponse, ProjectStatsBreakdown, ProjectType, ProjectUsageInfoResponse, PromoteClusterMemberData, PromoteClusterMemberErrors, PromoteClusterMemberResponses, PromoteDeploymentData, PromoteDeploymentErrors, PromoteDeploymentRequest, PromoteDeploymentResponse, PromoteDeploymentResponses, PropertyBreakdownItem, PropertyBreakdownQuery, PropertyBreakdownResponse, PropertyColumn, PropertyTimelineItem, PropertyTimelineQuery, PropertyTimelineResponse, Protocol, ProviderCatalogDto, ProviderCatalogResponse, ProviderConfig, ProviderConfigMasked, ProviderDeletionCheckResponse, ProviderDescriptor, ProviderKeyResponse, ProviderMetadata, ProviderResponse, ProviderUsage, ProvisionDomainData, ProvisionDomainErrors, ProvisionDomainResponse, ProvisionDomainResponses, ProvisionResponse, ProxyLogResponse, ProxyLogsPaginatedResponse, PublicHostnameStrategy, PublicPresetResponse, PublicRepositoryInfo, PurgeLogsRequest, PurgeProjectLogsData, PurgeProjectLogsError, PurgeProjectLogsErrors, PurgeProjectLogsResponses, PushedExternalImageResponse, PushExternalImageData, PushExternalImageErrors, PushExternalImageResponse, PushExternalImageResponses, PushImageRequest, QueryDataData, QueryDataErrors, QueryDataRequest, QueryDataResponse, QueryDataResponse2, QueryDataResponses, QueryGenaiTracesData, QueryGenaiTracesError, QueryGenaiTracesErrors, QueryGenaiTracesResponse, QueryGenaiTracesResponses, QueryLogsData, QueryLogsError, QueryLogsErrors, QueryLogsResponse, QueryLogsResponses, QueryMetricsData, QueryMetricsError, QueryMetricsErrors, QueryMetricsResponse, QueryMetricsResponses, QueryTracesData, QueryTracesError, QueryTracesErrors, QueryTracesResponse, QueryTracesResponses, QueryTraceSummariesData, QueryTraceSummariesError, QueryTraceSummariesErrors, QueryTraceSummariesResponse, QueryTraceSummariesResponses, QuotaResponse, RateLimitConfig, RateLimitSettings, ReachabilityStatus, ReadFileData, ReadFileErrors, ReadFileResponse, ReadFileResponse2, ReadFileResponses, ReAnalyzeData, ReAnalyzeErrors, ReAnalyzeResponses, RecentActivityQuery, RecentActivityResponse, RecentEventResponse, RecentQueryParams, RecordConsoleEventData, RecordConsoleEventErrors, RecordConsoleEventResponses, RecordEventMetricsData, RecordEventMetricsErrors, RecordEventMetricsResponse, RecordEventMetricsResponses, RecordExposureRequest, RecordExposureResponse, RecordFlagExposureData, RecordFlagExposureErrors, RecordFlagExposureResponse, RecordFlagExposureResponses, RecordListResponse, RecordSpeedMetricsData, RecordSpeedMetricsError, RecordSpeedMetricsErrors, RecordSpeedMetricsResponse, RecordSpeedMetricsResponses, RecoveryTarget, ReferrerCount, ReferrersAnalyticsQuery, RefreshRouteTableData, RefreshRouteTableErrors, RefreshRouteTableResponse, RefreshRouteTableResponses, RegenerateDsnData, RegenerateDsnErrors, RegenerateDsnRequest, RegenerateDsnResponse, RegenerateDsnResponses, RegisterExternalImageData, RegisterExternalImageErrors, RegisterExternalImageResponse, RegisterExternalImageResponses, RegisterImageRequest, RegisterNodeApiRequest, RegisterNodeData, RegisterNodeErrors, RegisterNodeResponse, RegisterNodeResponse2, RegisterNodeResponses, RegisterRequest, ReinstallGitlabWebhookData, ReinstallGitlabWebhookErrors, ReinstallGitlabWebhookResponse, ReinstallGitlabWebhookResponses, ReinstallWebhookResponse, RejectPendingActionData, RejectPendingActionErrors, RejectPendingActionResponse, RejectPendingActionResponses, ReleaseCheckResult, ReleaseListResponse, ReloadPluginsData, ReloadPluginsErrors, ReloadPluginsResponse, ReloadPluginsResponses, ReloadResponse, RemoteDeploymentResponse, RemoveClusterMemberData, RemoveClusterMemberErrors, RemoveClusterMemberResponse, RemoveClusterMemberResponses, RemoveManagedDomainData, RemoveManagedDomainErrors, RemoveManagedDomainResponse, RemoveManagedDomainResponses, RemoveNodeResponse, RemoveRoleData, RemoveRoleErrors, RemoveRoleResponse, RemoveRoleResponses, RemoveTeamMemberData, RemoveTeamMemberErrors, RemoveTeamMemberResponse, RemoveTeamMemberResponses, RenameConversationData, RenameConversationErrors, RenameConversationRequest, RenameConversationResponse, RenameConversationResponses, RenewDomainData, RenewDomainErrors, RenewDomainResponse, RenewDomainResponses, RepositoryListQuery, RepositoryListResponse, RepositoryPresetResponse, RepositoryResponse, RepositorySyncStartedResponse, RequestPasswordResetData, RequestPasswordResetErrors, RequestPasswordResetResponse, RequestPasswordResetResponses, RequestRow, RequiredPasswordChangeRequest, RequiredPasswordChangeResponse, ResetPasswordData, ResetPasswordErrors, ResetPasswordRequest, ResetPasswordResponse, ResetPasswordResponses, ResetPgStatStatementsRequest, ResetPgStatStatementsResponse, ResizeSandboxBody, ResizeSandboxData, ResizeSandboxErrors, ResizeSandboxResponse, ResizeSandboxResponses, ResolveAlarmData, ResolveAlarmErrors, ResolveAlarmResponses, ResolvedEnvVarResponse, ResolvedEnvVarSource, ResourceCounts, ResourceFootprint, ResourceInfo, ResourceLimitApplyResult, ResourceLimits, ResourceLimitsResponse, ResourceLimitsUpdateResponse, ResourcesBody, RestartContainerData, RestartContainerErrors, RestartContainerResponse, RestartContainerResponses, RestartPreviewGatewayData, RestartPreviewGatewayResponse, RestartPreviewGatewayResponses, RestartSandboxData, RestartSandboxErrors, RestartSandboxResponse, RestartSandboxResponses, RestoreCapabilities, RestoreCapabilitiesResponse, RestoreFlagData, RestoreFlagErrors, RestoreFlagResponse, RestoreFlagResponses, RestorePlan, RestoreRequestMode, RestoreRunView, RestoreUserData, RestoreUserErrors, RestoreUserResponse, RestoreUserResponses, ResumeDeploymentData, ResumeDeploymentErrors, ResumeDeploymentResponse, ResumeDeploymentResponses, ResumeSandboxData, ResumeSandboxErrors, ResumeSandboxResponse, ResumeSandboxResponses, RetentionCleanupFailure, RetentionCleanupReport, RetryClusterData, RetryClusterErrors, RetryClusterRequest, RetryClusterResponse, RetryClusterResponses, RetryDeliveryData, RetryDeliveryErrors, RetryDeliveryResponse, RetryDeliveryResponses, RetryPgUpgradeData, RetryPgUpgradeErrors, RetryPgUpgradeResponse, RetryPgUpgradeResponses, RetryRunData, RetryRunErrors, RetryRunResponse, RetryRunResponses, RevealGlobalMcpConfigData, RevealGlobalMcpConfigErrors, RevealGlobalMcpConfigResponse, RevealGlobalMcpConfigResponses, RevealMcpConfigData, RevealMcpConfigErrors, RevealMcpConfigResponse, RevealMcpConfigResponses, RevealNotificationProviderConfigData, RevealNotificationProviderConfigErrors, RevealNotificationProviderConfigResponse, RevealNotificationProviderConfigResponses, RevealServiceParameterData, RevealServiceParameterErrors, RevealServiceParameterResponse, RevealServiceParameterResponses, RevenueCreateIntegrationData, RevenueCreateIntegrationErrors, RevenueCreateIntegrationResponse, RevenueCreateIntegrationResponses, RevenueDeleteIntegrationData, RevenueDeleteIntegrationResponse, RevenueDeleteIntegrationResponses, RevenueGlobalEventsData, RevenueGlobalEventsResponse, RevenueGlobalEventsResponses, RevenueImportInvoicesCsvData, RevenueImportInvoicesCsvErrors, RevenueImportInvoicesCsvResponse, RevenueImportInvoicesCsvResponses, RevenueImportSubscriptionsCsvData, RevenueImportSubscriptionsCsvErrors, RevenueImportSubscriptionsCsvResponse, RevenueImportSubscriptionsCsvResponses, RevenueListIntegrationsData, RevenueListIntegrationsResponse, RevenueListIntegrationsResponses, RevenueListProvidersData, RevenueListProvidersResponse, RevenueListProvidersResponses, RevenueMetricsCustomersData, RevenueMetricsCustomersResponse, RevenueMetricsCustomersResponses, RevenueMetricsGlobalMrrData, RevenueMetricsGlobalMrrResponse, RevenueMetricsGlobalMrrResponses, RevenueMetricsGlobalSummaryData, RevenueMetricsGlobalSummaryResponse, RevenueMetricsGlobalSummaryResponses, RevenueMetricsMrrData, RevenueMetricsMrrResponse, RevenueMetricsMrrResponses, RevenueMetricsSummaryData, RevenueMetricsSummaryResponse, RevenueMetricsSummaryResponses, RevenueRecentEventsData, RevenueRecentEventsResponse, RevenueRecentEventsResponses, RevenueRotateTokenData, RevenueRotateTokenResponse, RevenueRotateTokenResponses, RevenueRow, RevenueUpdateConfigData, RevenueUpdateConfigErrors, RevenueUpdateConfigResponse, RevenueUpdateConfigResponses, RevenueUpdateSecretData, RevenueUpdateSecretErrors, RevenueUpdateSecretResponse, RevenueUpdateSecretResponses, RevokeDsnData, RevokeDsnErrors, RevokeDsnResponse, RevokeDsnResponses, RevokeEnrollmentTokenData, RevokeEnrollmentTokenErrors, RevokeEnrollmentTokenResponse, RevokeEnrollmentTokenResponses, RevokeJoinTokenData, RevokeJoinTokenErrors, RevokeJoinTokenResponse, RevokeJoinTokenResponses, RevokeProjectAccessData, RevokeProjectAccessErrors, RevokeProjectAccessResponse, RevokeProjectAccessResponses, RiskLevel, RoleInfo, RollbackPgUpgradeData, RollbackPgUpgradeErrors, RollbackPgUpgradeResponse, RollbackPgUpgradeResponses, RollbackToDeploymentData, RollbackToDeploymentErrors, RollbackToDeploymentResponse, RollbackToDeploymentResponses, RootfsCacheEntry, RootfsGcData, RootfsGcReport, RootfsGcResponses, RootfsReport, RootfsReportData, RootfsReportResponses, RootfsVmEntry, RotateApiKeyData, RotateApiKeyErrors, RotateApiKeyResponse, RotateApiKeyResponses, RotateDeploymentTokenData, RotateDeploymentTokenErrors, RotateDeploymentTokenResponse, RotateDeploymentTokenResponses, RouteRefreshResponse, RouteResponse, RouteRole, RouteUser, RouteUserWithRoles, RunBackupForSourceData, RunBackupForSourceError, RunBackupForSourceErrors, RunBackupForSourceResponse, RunBackupForSourceResponses, RunBackupRequest, RunConnectionHealthCheckData, RunConnectionHealthCheckErrors, RunConnectionHealthCheckResponse, RunConnectionHealthCheckResponses, RunExternalServiceBackupData, RunExternalServiceBackupError, RunExternalServiceBackupErrors, RunExternalServiceBackupRequest, RunExternalServiceBackupResponse, RunExternalServiceBackupResponses, RunScheduleNowData, RunScheduleNowError, RunScheduleNowErrors, RunScheduleNowResponse, RunScheduleNowResponses, S3ConnectionTestResponse, S3CredentialsResponse, S3SourceResponse, S3SourceResponseWritable, SandboxCreatePreviewLinkData, SandboxCreatePreviewLinkErrors, SandboxCreatePreviewLinkResponse, SandboxCreatePreviewLinkResponses, SandboxDomainResponse, SandboxEvent, SandboxEventsResponse, SandboxInner, SandboxResponse, SandboxRoute, SandboxStatusResponse, SaveAgentTokenData, SaveAgentTokenErrors, SaveAgentTokenRequest, SaveAgentTokenResponse, SaveAgentTokenResponse2, SaveAgentTokenResponses, SaveAiProviderCredentialData, SaveAiProviderCredentialErrors, SaveAiProviderCredentialResponse, SaveAiProviderCredentialResponses, SaveCredentialRequest, SaveCredentialResponse, ScalewayCredentialsRequest, ScanResponse, ScheduleRunEntry, ScheduleRunJobEntry, ScheduleRunListResponse, ScheduleRunResponse, ScheduleRunSummary, ScheduleRunSummaryList, ScreenshotSettings, SearchLogsData, SearchLogsError, SearchLogsErrors, SearchLogsRequest, SearchLogsResponse, SearchLogsResponse2, SearchLogsResponses, SearchMode, Seasonality, SecretResponse, SecurityConfig, SecurityHeadersConfig, SecurityHeadersSettings, SelfUpdateAttempt, SelfUpdateBlocker, SelfUpdatePhase, SelfUpdateRestartMode, SelfUpdateSettings, SelfUpdateStatus, SendEmailData, SendEmailErrors, SendEmailRequestBody, SendEmailResponse, SendEmailResponseBody, SendEmailResponses, SendMessageRequest, SensitiveConfigValueResponse, SensitiveMcpConfigValueResponse, SensitiveValueResponse, SentryChunkUploadResponse, SentryCreateReleaseRequest, SentryEventRequest, SentryEventResponse, SentryReleaseFileResponse, SentryReleaseProjectRef, SentryReleaseResponse, SeriesStateEntry, ServiceAccessInfo, ServiceAction, ServiceAlertRuleResponse, ServiceBackupEntryResponse, ServiceBackupListResponse, ServiceCreateAlertRuleRequest, ServiceHealthResponse, ServiceHealthStatusBatchResponse, ServiceHealthStatusEntryResponse, ServiceMemberInfo, ServiceParameter, ServicePlan, ServiceResourceLimits, ServiceRuntimeReport, ServiceStatsReport, ServiceTypeInfo, ServiceTypeRoute, ServiceUpdateAlertRuleRequest, SesCredentialsRequest, SessionDetails, SessionDetailsQuery, SessionEvent, SessionEventDto, SessionEventsQuery, SessionEventsResponse, SessionLogsQuery, SessionLogsResponse, SessionReplayEventsRequest, SessionReplayInfoDto, SessionReplayInitRequest, SessionReplayInitResponse, SessionReplayWithEventsDto, SessionReplayWithVisitorDto, SessionRequestLog, SessionSummary, SetDefaultS3SourceData, SetDefaultS3SourceError, SetDefaultS3SourceErrors, SetDefaultS3SourceResponse, SetDefaultS3SourceResponses, SetFlagEnvironmentData, SetFlagEnvironmentErrors, SetFlagEnvironmentRequest, SetFlagEnvironmentResponse, SetFlagEnvironmentResponses, SetPreviewPasswordBody, SetPreviewPasswordData, SetPreviewPasswordErrors, SetPreviewPasswordResponse, SetPreviewPasswordResponse2, SetPreviewPasswordResponses, SetRequest, SetResponse, SettingsUpdateResponse, SetupDnsChallengeData, SetupDnsChallengeErrors, SetupDnsChallengeRequest, SetupDnsChallengeResponse, SetupDnsChallengeResponse2, SetupDnsChallengeResponses, SetupDnsData, SetupDnsErrors, SetupDnsRequest, SetupDnsResponse, SetupDnsResponse2, SetupDnsResponses, SetupEmailTrackingData, SetupEmailTrackingErrors, SetupEmailTrackingResponse, SetupEmailTrackingResponses, SetupMfaData, SetupMfaErrors, SetupMfaResponse, SetupMfaResponses, SiblingRef, SkillDefinitionResponse, SlackConfig, SleepEnvironmentData, SleepEnvironmentErrors, SleepEnvironmentResponse, SleepEnvironmentResponses, SlowQueriesResponse, SlowQueryRow, SmartFilter, SmokeTestAgentData, SmokeTestAgentErrors, SmokeTestAgentResponse, SmokeTestAgentResponses, SmokeTestResponse, SmtpCredentialsRequest, SmtpEncryptionRoute, SmtpResult, SourceArchiveUpload, SourceBackupEntry, SourceBackupIndexResponse, SourceBody, SourceFileListResponse, SourceFileResponse, SourceMapListResponse, SourceMapResponse, SourceSandboxData, SourceSandboxErrors, SourceSandboxResponse, SourceSandboxResponses, SourceType, SpanEvent, SpanKind, SpanRecord, SpanRow, SpanStatusCode, SpeedMetricsPayload, SpeedSegmentFilters, StaleSlot, StartAnalysisData, StartAnalysisErrors, StartAnalysisRequest, StartAnalysisResponse, StartAnalysisResponses, StartContainerData, StartContainerErrors, StartContainerResponse, StartContainerResponses, StartFixData, StartFixErrors, StartFixResponses, StartGitProviderOauthData, StartGitProviderOauthErrors, StartOidcLoginBySlugData, StartOidcLoginBySlugErrors, StartPgUpgradeData, StartPgUpgradeErrors, StartPgUpgradeRequest, StartPgUpgradeResponse, StartPgUpgradeResponses, StartRestoreData, StartRestoreError, StartRestoreErrors, StartRestoreRequest, StartRestoreResponse, StartRestoreResponses, StartServiceData, StartServiceErrors, StartServiceResponse, StartServiceResponses, StartUpdateData, StartUpdateError, StartUpdateErrors, StartUpdateRequest, StartUpdateResponse, StartUpdateResponse2, StartUpdateResponses, StaticBundleResponse, StaticParams, StaticPresetConfig, StatPathData, StatPathErrors, StatPathResponse, StatPathResponses, StatResponse, StatsFilters, StatusBucket, StatusBucketedResponse, StatusCodeCount, StatusCodesQuery, StatusPageOverview, StepConversionResponse, StepResourceType, StepResult, StepUpResponse, StopContainerData, StopContainerErrors, StopContainerResponse, StopContainerResponses, StopSandboxData, StopSandboxErrors, StopSandboxResponse, StopSandboxResponses, StopSequence, StopServiceData, StopServiceErrors, StopServiceResponse, StopServiceResponses, StorageQuota, StreamContainerMetricsData, StreamContainerMetricsErrors, StreamContainerMetricsResponses, StreamEventsData, StreamEventsErrors, StreamEventsResponses, StreamRunEventsData, StreamRunEventsErrors, StreamRunEventsResponses, StripeConfig, SupervisorKind, SyncedRepositoryListQuery, SyncRepositoriesData, SyncRepositoriesErrors, SyncRepositoriesResponse, SyncRepositoriesResponses, SyntaxResult, TagInfo, TagListResponse, TailDeploymentJobLogsData, TailDeploymentJobLogsErrors, TailLogsData, TailLogsError, TailLogsErrors, TailLogsRequest, TailLogsResponses, TargetRecommendation, TeamListResponse, TeamMemberResponse, TeamResponse, TeamRole, TeardownDeploymentData, TeardownDeploymentErrors, TeardownDeploymentResponse, TeardownDeploymentResponses, TeardownEnvironmentData, TeardownEnvironmentErrors, TeardownEnvironmentResponse, TeardownEnvironmentResponses, TemplateResponse, TestEmailRequest, TestEmailResponse, TestNotificationProviderData, TestNotificationProviderErrors, TestNotificationProviderResponse, TestNotificationProviderResponses, TestOidcProviderData, TestOidcProviderResponse, TestOidcProviderResponses, TestProviderConnectionData, TestProviderConnectionErrors, TestProviderConnectionResponse, TestProviderConnectionResponses, TestProviderData, TestProviderErrors, TestProviderKeyByIdData, TestProviderKeyByIdError, TestProviderKeyByIdErrors, TestProviderKeyByIdResponse, TestProviderKeyByIdResponses, TestProviderKeyInlineData, TestProviderKeyInlineError, TestProviderKeyInlineErrors, TestProviderKeyInlineResponse, TestProviderKeyInlineResponses, TestProviderKeyRequest, TestProviderKeyResponse, TestProviderResponse, TestProviderResponse2, TestProviderResponses, TestS3ConnectionPreviewData, TestS3ConnectionPreviewError, TestS3ConnectionPreviewErrors, TestS3ConnectionPreviewResponse, TestS3ConnectionPreviewResponses, TestS3SourceConnectionData, TestS3SourceConnectionError, TestS3SourceConnectionErrors, TestS3SourceConnectionResponse, TestS3SourceConnectionResponses, TimeBucketStats, TimeBucketStatsResponse, TimeseriesBucket, TimeseriesQueryParams, TlsMode, TodayStatsResponse, ToggleDeploymentMetricsRequest, ToggleServiceMetricsRequest, TokenRenewalRequest, ToolCallEvent, ToolInfo, ToolResultEvent, TopModelsQueryParams, TraceProjectRef, TracesResponse, TraceSummariesResponse, TraceSummary, TrackClickData, TrackClickErrors, TrackedLinkResponse, TrackingEventResponse, TrackOpenData, TrackOpenErrors, TrackOpenResponses, TriggerAgentData, TriggerAgentErrors, TriggerAgentRequest, TriggerAgentResponse, TriggerAgentResponses, TriggerDigestResponse, TriggerPipelinePayload, TriggerPipelineResponse, TriggerProjectPipelineData, TriggerProjectPipelineErrors, TriggerProjectPipelineResponse, TriggerProjectPipelineResponses, TriggerScanData, TriggerScanError, TriggerScanErrors, TriggerScanRequest, TriggerScanResponse, TriggerScanResponse2, TriggerScanResponses, TriggerServiceHealthCheckData, TriggerServiceHealthCheckErrors, TriggerServiceHealthCheckResponse, TriggerServiceHealthCheckResponses, TriggerWeeklyDigestData, TriggerWeeklyDigestErrors, TriggerWeeklyDigestResponse, TriggerWeeklyDigestResponses, TtlRequest, TtlResponse, TxtRecord, UiManifest, UiRoute, UndrainNodeResponse, UnifiedTrace, UniqueCountsQuery, UniqueCountsResponse, UnlinkServiceFromProjectData, UnlinkServiceFromProjectErrors, UnlinkServiceFromProjectResponse, UnlinkServiceFromProjectResponses, UnsupportedFeature, UpdateAdminGateRequest, UpdateAgentData, UpdateAgentErrors, UpdateAgentResponse, UpdateAgentResponses, UpdateAiProviderData, UpdateAiProviderErrors, UpdateAiProviderRequest, UpdateAiProviderResponse, UpdateAiProviderResponse2, UpdateAiProviderResponses, UpdateAlertData, UpdateAlertError, UpdateAlertErrors, UpdateAlertResponse, UpdateAlertResponses, UpdateAlertRuleData, UpdateAlertRuleErrors, UpdateAlertRuleRequest, UpdateAlertRuleResponse, UpdateAlertRuleResponses, UpdateApiKeyData, UpdateApiKeyErrors, UpdateApiKeyRequest, UpdateApiKeyResponse, UpdateApiKeyResponses, UpdateAutomaticDeployData, UpdateAutomaticDeployErrors, UpdateAutomaticDeployRequest, UpdateAutomaticDeployResponse, UpdateAutomaticDeployResponses, UpdateBackupScheduleData, UpdateBackupScheduleError, UpdateBackupScheduleErrors, UpdateBackupScheduleRequest, UpdateBackupScheduleResponse, UpdateBackupScheduleResponses, UpdateBlobRequest, UpdateBlobResponse, UpdateCapabilityResponse, UpdateCloudflareProviderData, UpdateCloudflareProviderErrors, UpdateCloudflareProviderRequest, UpdateCloudflareProviderResponse, UpdateCloudflareProviderResponses, UpdateConfigBody, UpdateConnectionTokenData, UpdateConnectionTokenErrors, UpdateConnectionTokenResponse, UpdateConnectionTokenResponses, UpdateCustomDomainData, UpdateCustomDomainErrors, UpdateCustomDomainRequest, UpdateCustomDomainResponse, UpdateCustomDomainResponses, UpdateDashboardData, UpdateDashboardError, UpdateDashboardErrors, UpdateDashboardRequest, UpdateDashboardResponse, UpdateDashboardResponses, UpdateDeploymentConfigRequest, UpdateDeploymentTokenData, UpdateDeploymentTokenErrors, UpdateDeploymentTokenRequest, UpdateDeploymentTokenResponse, UpdateDeploymentTokenResponses, UpdateDnsProviderRequest, UpdateEmailProviderData, UpdateEmailProviderErrors, UpdateEmailProviderRequest, UpdateEmailProviderResponse, UpdateEmailProviderResponses, UpdateEnvironmentSettingsData, UpdateEnvironmentSettingsErrors, UpdateEnvironmentSettingsRequest, UpdateEnvironmentSettingsResponse, UpdateEnvironmentSettingsResponses, UpdateEnvironmentSubdomainData, UpdateEnvironmentSubdomainErrors, UpdateEnvironmentSubdomainRequest, UpdateEnvironmentSubdomainResponse, UpdateEnvironmentSubdomainResponses, UpdateEnvironmentVariableData, UpdateEnvironmentVariableErrors, UpdateEnvironmentVariableRequest, UpdateEnvironmentVariableResponse, UpdateEnvironmentVariableResponses, UpdateErrorGroupData, UpdateErrorGroupErrors, UpdateErrorGroupRequest, UpdateErrorGroupResponses, UpdateExternalServiceRequest, UpdateFlagData, UpdateFlagErrors, UpdateFlagRequest, UpdateFlagResponse, UpdateFlagResponses, UpdateFunnelData, UpdateFunnelErrors, UpdateFunnelResponses, UpdateGitProviderCredentialsData, UpdateGitProviderCredentialsErrors, UpdateGitProviderCredentialsResponse, UpdateGitProviderCredentialsResponses, UpdateGitSettingsData, UpdateGitSettingsErrors, UpdateGitSettingsRequest, UpdateGitSettingsResponse, UpdateGitSettingsResponses, UpdateGlobalMcpData, UpdateGlobalMcpErrors, UpdateGlobalMcpResponse, UpdateGlobalMcpResponses, UpdateGlobalSkillData, UpdateGlobalSkillErrors, UpdateGlobalSkillResponse, UpdateGlobalSkillResponses, UpdateIncidentStatusData, UpdateIncidentStatusErrors, UpdateIncidentStatusRequest, UpdateIncidentStatusResponse, UpdateIncidentStatusResponses, UpdateIpAccessControlData, UpdateIpAccessControlError, UpdateIpAccessControlErrors, UpdateIpAccessControlRequest, UpdateIpAccessControlResponse, UpdateIpAccessControlResponses, UpdateKvRequest, UpdateKvResponse, UpdateManagedDomainApiRequest, UpdateManagedDomainData, UpdateManagedDomainErrors, UpdateManagedDomainResponse, UpdateManagedDomainResponses, UpdateMcpData, UpdateMcpErrors, UpdateMcpRequest, UpdateMcpResponse, UpdateMcpResponses, UpdateMemberRoleRequest, UpdateMetricAlertRequest, UpdateNotificationEmailProviderData, UpdateNotificationEmailProviderErrors, UpdateNotificationEmailProviderRequest, UpdateNotificationEmailProviderResponse, UpdateNotificationEmailProviderResponses, UpdateNotificationProviderData, UpdateNotificationProviderErrors, UpdateNotificationProviderResponse, UpdateNotificationProviderResponses, UpdateOidcProviderData, UpdateOidcProviderRequest, UpdateOidcProviderResponse, UpdateOidcProviderResponses, UpdatePreferencesData, UpdatePreferencesErrors, UpdatePreferencesRequest, UpdatePreferencesResponse, UpdatePreferencesResponses, UpdateProjectData, UpdateProjectDeploymentConfigData, UpdateProjectDeploymentConfigErrors, UpdateProjectDeploymentConfigResponse, UpdateProjectDeploymentConfigResponses, UpdateProjectErrors, UpdateProjectResponse, UpdateProjectResponses, UpdateProjectSecretData, UpdateProjectSecretErrors, UpdateProjectSecretRequest, UpdateProjectSecretResponse, UpdateProjectSecretResponses, UpdateProjectSettingsData, UpdateProjectSettingsErrors, UpdateProjectSettingsRequest, UpdateProjectSettingsResponse, UpdateProjectSettingsResponses, UpdateProviderCredentialsRequest, UpdateProviderData, UpdateProviderErrors, UpdateProviderKeyData, UpdateProviderKeyError, UpdateProviderKeyErrors, UpdateProviderKeyRequest, UpdateProviderKeyResponse, UpdateProviderKeyResponses, UpdateProviderRequest, UpdateProviderResponse, UpdateProviderResponses, UpdateRouteData, UpdateRouteErrors, UpdateRouteRequest, UpdateRouteResponse, UpdateRouteResponses, UpdateS3SourceData, UpdateS3SourceError, UpdateS3SourceErrors, UpdateS3SourceRequest, UpdateS3SourceResponse, UpdateS3SourceResponses, UpdateSecretBody, UpdateSelfData, UpdateSelfErrors, UpdateSelfRequest, UpdateSelfResponse, UpdateSelfResponses, UpdateServiceData, UpdateServiceErrors, UpdateServiceResourcesData, UpdateServiceResourcesErrors, UpdateServiceResourcesResponse, UpdateServiceResourcesResponses, UpdateServiceResponse, UpdateServiceResponses, UpdateSessionDurationData, UpdateSessionDurationError, UpdateSessionDurationErrors, UpdateSessionDurationRequest, UpdateSessionDurationResponse, UpdateSessionDurationResponse2, UpdateSessionDurationResponses, UpdateSettingsData, UpdateSettingsErrors, UpdateSettingsResponse, UpdateSettingsResponses, UpdateSkillData, UpdateSkillErrors, UpdateSkillRequest, UpdateSkillResponse, UpdateSkillResponses, UpdateSlackProviderData, UpdateSlackProviderErrors, UpdateSlackProviderRequest, UpdateSlackProviderResponse, UpdateSlackProviderResponses, UpdateSpeedMetricsData, UpdateSpeedMetricsError, UpdateSpeedMetricsErrors, UpdateSpeedMetricsPayload, UpdateSpeedMetricsResponse, UpdateSpeedMetricsResponses, UpdateStatusResponse, UpdateTeamData, UpdateTeamErrors, UpdateTeamMemberRoleData, UpdateTeamMemberRoleErrors, UpdateTeamMemberRoleResponse, UpdateTeamMemberRoleResponses, UpdateTeamRequest, UpdateTeamResponse, UpdateTeamResponses, UpdateTokenRequest, UpdateTokenResponse, UpdateUserData, UpdateUserErrors, UpdateUserRequest, UpdateUserResponse, UpdateUserResponses, UpdateWebhookData, UpdateWebhookErrors, UpdateWebhookProviderData, UpdateWebhookProviderErrors, UpdateWebhookProviderRequest, UpdateWebhookProviderResponse, UpdateWebhookProviderResponses, UpdateWebhookRequestBody, UpdateWebhookResponse, UpdateWebhookResponses, UpgradeExternalServiceRequest, UpgradePreviewGatewayData, UpgradePreviewGatewayResponse, UpgradePreviewGatewayResponses, UpgradeRequest, UpgradeServiceData, UpgradeServiceErrors, UpgradeServiceResponse, UpgradeServiceResponses, UploadGlobalSkillData, UploadGlobalSkillErrors, UploadGlobalSkillResponse, UploadGlobalSkillResponses, UploadReleaseFileData, UploadReleaseFileErrors, UploadReleaseFileResponse, UploadReleaseFileResponses, UploadSkillData, UploadSkillErrors, UploadSkillResponse, UploadSkillResponses, UploadSourceFileData, UploadSourceFileErrors, UploadSourceFileResponse, UploadSourceFileResponses, UploadSourceMapData, UploadSourceMapErrors, UploadSourceMapResponse, UploadSourceMapResponses, UploadStaticBundleData, UploadStaticBundleErrors, UploadStaticBundleResponse, UploadStaticBundleResponses, UpsertAgentRequest, UpsertSecretData, UpsertSecretErrors, UpsertSecretRequest, UpsertSecretResponse, UpsertSecretResponses, UptimeDataPoint, UptimeHistoryResponse, UsageFilter, UsageInfo, UsageLogEntry, UsageLogPage, UsageQueryParams, UsageSource, UsageSummary, UserResponse, ValidateConnectionData, ValidateConnectionErrors, ValidateConnectionResponse, ValidateConnectionResponses, ValidateEmailData, ValidateEmailErrors, ValidateEmailRequest, ValidateEmailResponse, ValidateEmailResponse2, ValidateEmailResponses, ValidationLevel, ValidationReport, ValidationResponse, ValidationResult, ValidationStatus, ValidationSummary, VerifyAndEnableMfaData, VerifyAndEnableMfaErrors, VerifyAndEnableMfaResponse, VerifyAndEnableMfaResponses, VerifyDomainData, VerifyDomainErrors, VerifyDomainResponse, VerifyDomainResponses, VerifyEmailData, VerifyEmailErrors, VerifyEmailResponse, VerifyEmailResponses, VerifyManagedDomainData, VerifyManagedDomainErrors, VerifyManagedDomainResponse, VerifyManagedDomainResponses, VerifyMfaChallengeData, VerifyMfaChallengeErrors, VerifyMfaChallengeResponse, VerifyMfaChallengeResponses, VerifyMfaRequest, VerifyStepUpData, VerifyStepUpErrors, VerifyStepUpRequest, VerifyStepUpResponse, VerifyStepUpResponses, ViewItem, ViewsOverTime, ViewsOverTimeQuery, VisitorDetails, VisitorFacets, VisitorFacetsQuery, VisitorFacetValue, VisitorInfo, VisitorJourneyQuery, VisitorJourneyResponse, VisitorLocationsQuery, VisitorRecord, VisitorSegmentFilters, VisitorSessionsQuery, VisitorSessionsResponse, VisitorsListQuery, VisitorsResponse, VisitorStats, VisitorWithGeolocation, VolumeMount, VolumeType, VulnerabilityResponse, WakeEnvironmentData, WakeEnvironmentErrors, WakeEnvironmentResponse, WakeEnvironmentResponses, WalWarning, WalWarningSeverity, WebhookConfig, WebhookDeliveryResponse, WebhookResponse, WebhookTriggerData, WebhookTriggerErrors, WebhookTriggerRequest, WebhookTriggerResponse, WebhookTriggerResponse2, WebhookTriggerResponses, WorkflowDryRunData, WorkflowDryRunErrors, WorkflowDryRunRequest, WorkflowDryRunResponse, WorkflowDryRunResponses, WorkloadDescriptor, WorkloadId, WorkloadStatus, WorkloadType, WriteFileBody, WriteFileData, WriteFileErrors, WriteFileResponse, WriteFileResponses, WriteFilesBody, WriteFilesData, WriteFilesErrors, WriteFilesResponse, WriteFilesResponse2, WriteFilesResponses, ZoneListResponse } from './types.gen'; diff --git a/web/src/api/client/sdk.gen.ts b/web/src/api/client/sdk.gen.ts index fb3fedb57..95fd4ba7f 100644 --- a/web/src/api/client/sdk.gen.ts +++ b/web/src/api/client/sdk.gen.ts @@ -2,7 +2,7 @@ import { type Client, type ClientMeta, formDataBodySerializer, type Options as Options2, type RequestResult, type ServerSentEventsResult, type TDataShape } from './client'; import { client } from './client.gen'; -import type { AcknowledgeAlarmData, AcknowledgeAlarmErrors, AcknowledgeAlarmResponses, ActivateAiProviderData, ActivateAiProviderErrors, ActivateAiProviderResponses, ActivateApiKeyData, ActivateApiKeyErrors, ActivateApiKeyResponses, ActivateConnectionData, ActivateConnectionErrors, ActivateConnectionResponses, ActivateProviderData, ActivateProviderErrors, ActivateProviderResponses, AddClusterMemberData, AddClusterMemberErrors, AddClusterMemberResponses, AddContextData, AddContextErrors, AddContextResponses, AddEnvironmentDomainData, AddEnvironmentDomainErrors, AddEnvironmentDomainResponses, AddEventsData, AddEventsErrors, AddEventsResponses, AddManagedDomainData, AddManagedDomainErrors, AddManagedDomainResponses, AddSessionReplayEventsData, AddSessionReplayEventsErrors, AddSessionReplayEventsResponses, AddTeamMemberData, AddTeamMemberErrors, AddTeamMemberResponses, AdminDrainNodeData, AdminDrainNodeErrors, AdminDrainNodeResponses, AdminDrainStatusData, AdminDrainStatusErrors, AdminDrainStatusResponses, AdminGetNodeData, AdminGetNodeErrors, AdminGetNodeResponses, AdminListNodeContainersData, AdminListNodeContainersErrors, AdminListNodeContainersResponses, AdminListNodesData, AdminListNodesErrors, AdminListNodesResponses, AdminRemoveNodeData, AdminRemoveNodeErrors, AdminRemoveNodeResponses, AdminUndrainNodeData, AdminUndrainNodeErrors, AdminUndrainNodeResponses, ApplyHostnameModeData, ApplyHostnameModeErrors, ApplyHostnameModeResponses, ArchiveConversationData, ArchiveConversationErrors, ArchiveConversationResponses, ArchiveFlagData, ArchiveFlagErrors, ArchiveFlagResponses, AssignRoleData, AssignRoleErrors, AssignRoleResponses, AttachScheduleServicesData, AttachScheduleServicesErrors, AttachScheduleServicesResponses, BlobCopyData, BlobCopyErrors, BlobCopyResponses, BlobDeleteData, BlobDeleteErrors, BlobDeleteResponses, BlobDisableData, BlobDisableErrors, BlobDisableResponses, BlobDownloadData, BlobDownloadErrors, BlobDownloadResponses, BlobEnableData, BlobEnableErrors, BlobEnableResponses, BlobHeadData, BlobHeadErrors, BlobHeadResponses, BlobListData, BlobListErrors, BlobListResponses, BlobPutData, BlobPutErrors, BlobPutResponses, BlobStatusData, BlobStatusErrors, BlobStatusResponses, BlobUpdateData, BlobUpdateErrors, BlobUpdateResponses, CancelBackupData, CancelBackupErrors, CancelBackupResponses, CancelData, CancelDeploymentData, CancelDeploymentErrors, CancelDeploymentResponses, CancelDomainOrderData, CancelDomainOrderErrors, CancelDomainOrderResponses, CancelErrors, CancelPgUpgradeData, CancelPgUpgradeErrors, CancelPgUpgradeResponses, CancelResponses, CancelRunData, CancelRunErrors, CancelRunResponses, CancelScheduleRunData, CancelScheduleRunErrors, CancelScheduleRunResponses, ChangePasswordSelfData, ChangePasswordSelfErrors, ChangePasswordSelfResponses, ChangeProjectSourceData, ChangeProjectSourceErrors, ChangeProjectSourceResponses, ChangeRequiredPasswordData, ChangeRequiredPasswordErrors, ChangeRequiredPasswordResponses, ChatCompletionsData, ChatCompletionsErrors, ChatCompletionsResponses, CheckAnalyticsHasEventsData, CheckAnalyticsHasEventsErrors, CheckAnalyticsHasEventsResponses, CheckCommitExistsData, CheckCommitExistsErrors, CheckCommitExistsResponses, CheckDomainStatusData, CheckDomainStatusErrors, CheckDomainStatusResponses, CheckExplorerSupportData, CheckExplorerSupportErrors, CheckExplorerSupportResponses, CheckIpBlockedData, CheckIpBlockedErrors, CheckIpBlockedResponses, CheckProviderDeletionSafetyData, CheckProviderDeletionSafetyErrors, CheckProviderDeletionSafetyResponses, ChunkUploadOptionsData, ChunkUploadOptionsResponses, CleanupExpiredBackupsData, CleanupExpiredBackupsErrors, CleanupExpiredBackupsResponses, ClearPreviewPasswordData, ClearPreviewPasswordErrors, ClearPreviewPasswordResponses, CliDeviceApproveData, CliDeviceApproveErrors, CliDeviceApproveResponses, CliDeviceDenyData, CliDeviceDenyErrors, CliDeviceDenyResponses, CliDeviceLookupData, CliDeviceLookupErrors, CliDeviceLookupResponses, CliDevicePollData, CliDevicePollErrors, CliDevicePollResponses, CliDeviceStartData, CliDeviceStartErrors, CliDeviceStartResponses, CliLogoutData, CliLogoutErrors, CliLogoutResponses, CmdData, CmdErrors, CmdKillData, CmdKillErrors, CmdKillResponses, CmdLogsData, CmdLogsErrors, CmdLogsResponses, CmdResponses, ConfirmPendingActionData, ConfirmPendingActionErrors, ConfirmPendingActionResponses, ContainerMetricsGetHistoryData, ContainerMetricsGetHistoryErrors, ContainerMetricsGetHistoryResponses, CreateAgentData, CreateAgentErrors, CreateAgentResponses, CreateAlertData, CreateAlertErrors, CreateAlertResponses, CreateAlertRuleData, CreateAlertRuleErrors, CreateAlertRuleResponses, CreateApiKeyData, CreateApiKeyErrors, CreateApiKeyResponses, CreateBackupScheduleData, CreateBackupScheduleErrors, CreateBackupScheduleResponses, CreateBitbucketProviderData, CreateBitbucketProviderErrors, CreateBitbucketProviderResponses, CreateCloudflareProviderData, CreateCloudflareProviderErrors, CreateCloudflareProviderResponses, CreateConversationData, CreateConversationErrors, CreateConversationResponses, CreateCustomDomainData, CreateCustomDomainErrors, CreateCustomDomainResponses, CreateDashboardData, CreateDashboardErrors, CreateDashboardResponses, CreateDeploymentTokenData, CreateDeploymentTokenErrors, CreateDeploymentTokenResponses, CreateDnsProviderData, CreateDnsProviderErrors, CreateDnsProviderResponses, CreateDomainData, CreateDomainErrors, CreateDomainResponses, CreateDsnData, CreateDsnErrors, CreateDsnResponses, CreateEmailDomainData, CreateEmailDomainErrors, CreateEmailDomainResponses, CreateEmailProviderData, CreateEmailProviderErrors, CreateEmailProviderResponses, CreateEnvironmentData, CreateEnvironmentErrors, CreateEnvironmentResponses, CreateEnvironmentVariableData, CreateEnvironmentVariableErrors, CreateEnvironmentVariableResponses, CreateFlagData, CreateFlagErrors, CreateFlagResponses, CreateFunnelData, CreateFunnelErrors, CreateFunnelResponses, CreateGenericProviderData, CreateGenericProviderErrors, CreateGenericProviderResponses, CreateGiteaPatProviderData, CreateGiteaPatProviderErrors, CreateGiteaPatProviderResponses, CreateGithubPatProviderData, CreateGithubPatProviderErrors, CreateGithubPatProviderResponses, CreateGitlabOauthProviderData, CreateGitlabOauthProviderErrors, CreateGitlabOauthProviderResponses, CreateGitlabPatProviderData, CreateGitlabPatProviderErrors, CreateGitlabPatProviderResponses, CreateGitProviderData, CreateGitProviderErrors, CreateGitProviderResponses, CreateGlobalMcpData, CreateGlobalMcpErrors, CreateGlobalMcpResponses, CreateGlobalSkillData, CreateGlobalSkillErrors, CreateGlobalSkillResponses, CreateIncidentData, CreateIncidentErrors, CreateIncidentResponses, CreateIpAccessControlData, CreateIpAccessControlErrors, CreateIpAccessControlResponses, CreateMcpData, CreateMcpErrors, CreateMcpResponses, CreateMonitorData, CreateMonitorErrors, CreateMonitorResponses, CreateNotificationEmailProviderData, CreateNotificationEmailProviderErrors, CreateNotificationEmailProviderResponses, CreateNotificationProviderData, CreateNotificationProviderErrors, CreateNotificationProviderResponses, CreateOidcProviderData, CreateOidcProviderErrors, CreateOidcProviderResponses, CreateOidcRoleMappingData, CreateOidcRoleMappingResponses, CreateOrRecreateOrderData, CreateOrRecreateOrderErrors, CreateOrRecreateOrderResponses, CreatePlanData, CreatePlanErrors, CreatePlanResponses, CreatePrData, CreatePrErrors, CreateProjectData, CreateProjectErrors, CreateProjectFromTemplateData, CreateProjectFromTemplateErrors, CreateProjectFromTemplateResponses, CreateProjectReleaseData, CreateProjectReleaseErrors, CreateProjectReleaseResponses, CreateProjectResponses, CreateProjectSecretData, CreateProjectSecretErrors, CreateProjectSecretResponses, CreateProviderKeyData, CreateProviderKeyErrors, CreateProviderKeyResponses, CreatePrResponses, CreateReleaseData, CreateReleaseErrors, CreateReleaseResponses, CreateRouteData, CreateRouteErrors, CreateRouteResponses, CreateS3SourceData, CreateS3SourceErrors, CreateS3SourceResponses, CreateSandboxData, CreateSandboxErrors, CreateSandboxResponses, CreateServiceData, CreateServiceErrors, CreateServiceResponses, CreateSkillData, CreateSkillErrors, CreateSkillResponses, CreateSlackProviderData, CreateSlackProviderErrors, CreateSlackProviderResponses, CreateTeamData, CreateTeamErrors, CreateTeamResponses, CreateUserData, CreateUserErrors, CreateUserResponses, CreateWebhookData, CreateWebhookErrors, CreateWebhookProviderData, CreateWebhookProviderErrors, CreateWebhookProviderResponses, CreateWebhookResponses, DeactivateApiKeyData, DeactivateApiKeyErrors, DeactivateApiKeyResponses, DeactivateConnectionData, DeactivateConnectionErrors, DeactivateConnectionResponses, DeactivateProviderData, DeactivateProviderErrors, DeactivateProviderResponses, DeleteAgentData, DeleteAgentErrors, DeleteAgentResponses, DeleteAlertData, DeleteAlertErrors, DeleteAlertResponses, DeleteAlertRuleData, DeleteAlertRuleErrors, DeleteAlertRuleResponses, DeleteApiKeyData, DeleteApiKeyErrors, DeleteApiKeyResponses, DeleteBackupData, DeleteBackupErrors, DeleteBackupResponses, DeleteBackupScheduleData, DeleteBackupScheduleErrors, DeleteBackupScheduleResponses, DeleteConnectionData, DeleteConnectionErrors, DeleteConnectionResponses, DeleteCustomDomainData, DeleteCustomDomainErrors, DeleteCustomDomainResponses, DeleteDashboardData, DeleteDashboardErrors, DeleteDashboardResponses, DeleteDeploymentTokenData, DeleteDeploymentTokenErrors, DeleteDeploymentTokenResponses, DeleteDnsProviderData, DeleteDnsProviderErrors, DeleteDnsProviderResponses, DeleteDomainData, DeleteDomainErrors, DeleteDomainResponses, DeleteEmailDomainData, DeleteEmailDomainErrors, DeleteEmailDomainResponses, DeleteEmailProviderData, DeleteEmailProviderErrors, DeleteEmailProviderResponses, DeleteEnvironmentData, DeleteEnvironmentDomainData, DeleteEnvironmentDomainErrors, DeleteEnvironmentDomainResponses, DeleteEnvironmentErrors, DeleteEnvironmentResponses, DeleteEnvironmentVariableData, DeleteEnvironmentVariableErrors, DeleteEnvironmentVariableResponses, DeleteExternalImageData, DeleteExternalImageErrors, DeleteExternalImageResponses, DeleteFunnelData, DeleteFunnelErrors, DeleteFunnelResponses, DeleteGitProviderData, DeleteGitProviderErrors, DeleteGitProviderResponses, DeleteGlobalMcpData, DeleteGlobalMcpErrors, DeleteGlobalMcpResponses, DeleteGlobalSkillData, DeleteGlobalSkillErrors, DeleteGlobalSkillResponses, DeleteIpAccessControlData, DeleteIpAccessControlErrors, DeleteIpAccessControlResponses, DeleteMcpData, DeleteMcpErrors, DeleteMcpResponses, DeleteMonitorData, DeleteMonitorErrors, DeleteMonitorResponses, DeleteNotificationProviderData, DeleteNotificationProviderErrors, DeleteNotificationProviderResponses, DeleteOidcProviderData, DeleteOidcProviderResponses, DeleteOidcRoleMappingData, DeleteOidcRoleMappingResponses, DeletePreferencesData, DeletePreferencesErrors, DeletePreferencesResponses, DeleteProjectData, DeleteProjectErrors, DeleteProjectResponses, DeleteProjectSecretData, DeleteProjectSecretErrors, DeleteProjectSecretResponses, DeleteProviderKeyData, DeleteProviderKeyErrors, DeleteProviderKeyResponses, DeleteProviderSafelyData, DeleteProviderSafelyErrors, DeleteProviderSafelyResponses, DeleteReleaseSourceFilesData, DeleteReleaseSourceFilesErrors, DeleteReleaseSourceFilesResponses, DeleteReleaseSourceMapsData, DeleteReleaseSourceMapsErrors, DeleteReleaseSourceMapsResponses, DeleteRouteData, DeleteRouteErrors, DeleteRouteResponses, DeleteS3SourceData, DeleteS3SourceErrors, DeleteS3SourceResponses, DeleteScanData, DeleteScanErrors, DeleteScanResponses, DeleteSecretData, DeleteSecretErrors, DeleteSecretResponses, DeleteServiceData, DeleteServiceErrors, DeleteServiceResponses, DeleteSessionReplayData, DeleteSessionReplayErrors, DeleteSessionReplayResponses, DeleteSkillData, DeleteSkillErrors, DeleteSkillResponses, DeleteSourceMapData, DeleteSourceMapErrors, DeleteSourceMapResponses, DeleteStaticBundleData, DeleteStaticBundleErrors, DeleteStaticBundleResponses, DeleteTeamData, DeleteTeamErrors, DeleteTeamResponses, DeleteUserData, DeleteUserErrors, DeleteUserResponses, DeleteWebhookData, DeleteWebhookErrors, DeleteWebhookResponses, DeployFromImageData, DeployFromImageErrors, DeployFromImageResponses, DeployFromImageUploadData, DeployFromImageUploadErrors, DeployFromImageUploadResponses, DeployFromStaticData, DeployFromStaticErrors, DeployFromStaticResponses, DeployFromUploadedSourceData, DeployFromUploadedSourceErrors, DeployFromUploadedSourceResponses, DeploymentMetricsGetLatestData, DeploymentMetricsGetLatestErrors, DeploymentMetricsGetLatestResponses, DeploymentMetricsGetRangeData, DeploymentMetricsGetRangeErrors, DeploymentMetricsGetRangeResponses, DeploymentMetricsToggleData, DeploymentMetricsToggleErrors, DeploymentMetricsToggleResponses, DestroySandboxData, DestroySandboxErrors, DestroySandboxResponses, DetachScheduleServiceData, DetachScheduleServiceErrors, DetachScheduleServiceResponses, DetectPublicPresetsData, DetectPublicPresetsErrors, DetectPublicPresetsResponses, DisableBackupScheduleData, DisableBackupScheduleErrors, DisableBackupScheduleResponses, DisableMfaData, DisableMfaErrors, DisableMfaResponses, DiscoverWorkloadsData, DiscoverWorkloadsErrors, DiscoverWorkloadsResponses, DomainData, DomainErrors, DomainResponses, DownloadGlobalSkillArchiveData, DownloadGlobalSkillArchiveErrors, DownloadGlobalSkillArchiveResponses, DownloadObjectData, DownloadObjectErrors, DownloadObjectResponses, DownloadSkillArchiveData, DownloadSkillArchiveErrors, DownloadSkillArchiveResponses, EmailStatusData, EmailStatusErrors, EmailStatusResponses, EmbeddingsData, EmbeddingsErrors, EmbeddingsResponses, EnableBackupScheduleData, EnableBackupScheduleErrors, EnableBackupScheduleResponses, EnrichVisitorData, EnrichVisitorErrors, EnrichVisitorResponses, ExecData, ExecDetachedData, ExecDetachedErrors, ExecDetachedResponses, ExecErrors, ExecResponses, ExecuteDeploymentOperationData, ExecuteDeploymentOperationErrors, ExecuteDeploymentOperationResponses, ExecuteImportData, ExecuteImportErrors, ExecuteImportResponses, ExtendTimeoutData, ExtendTimeoutErrors, ExtendTimeoutResponses, ExternalServiceEnablePgStatStatementsData, ExternalServiceEnablePgStatStatementsErrors, ExternalServiceEnablePgStatStatementsResponses, ExternalServiceMetricsByDatabaseData, ExternalServiceMetricsByDatabaseErrors, ExternalServiceMetricsByDatabaseResponses, ExternalServiceMetricsCreateAlertRuleData, ExternalServiceMetricsCreateAlertRuleErrors, ExternalServiceMetricsCreateAlertRuleResponses, ExternalServiceMetricsDeleteAlertRuleData, ExternalServiceMetricsDeleteAlertRuleErrors, ExternalServiceMetricsDeleteAlertRuleResponses, ExternalServiceMetricsGetAlertRulesData, ExternalServiceMetricsGetAlertRulesErrors, ExternalServiceMetricsGetAlertRulesResponses, ExternalServiceMetricsGetLatestData, ExternalServiceMetricsGetLatestErrors, ExternalServiceMetricsGetLatestResponses, ExternalServiceMetricsGetRangeData, ExternalServiceMetricsGetRangeErrors, ExternalServiceMetricsGetRangeResponses, ExternalServiceMetricsStatusData, ExternalServiceMetricsStatusErrors, ExternalServiceMetricsStatusResponses, ExternalServiceMetricsToggleData, ExternalServiceMetricsToggleErrors, ExternalServiceMetricsToggleResponses, ExternalServiceMetricsUpdateAlertRuleData, ExternalServiceMetricsUpdateAlertRuleErrors, ExternalServiceMetricsUpdateAlertRuleResponses, ExternalServiceResetPgStatStatementsData, ExternalServiceResetPgStatStatementsErrors, ExternalServiceResetPgStatStatementsResponses, FinalizeOrderData, FinalizeOrderErrors, FinalizeOrderResponses, FinalizeProjectReleaseData, FinalizeProjectReleaseErrors, FinalizeProjectReleaseResponses, FindConversationData, FindConversationErrors, FindConversationResponses, GenerateJoinTokenData, GenerateJoinTokenErrors, GenerateJoinTokenResponses, GeneratePresetDockerfileData, GeneratePresetDockerfileErrors, GeneratePresetDockerfileResponses, GetAccessInfoData, GetAccessInfoErrors, GetAccessInfoResponses, GetActiveVisitorsData, GetActiveVisitorsErrors, GetActiveVisitorsResponses, GetActivityGraphData, GetActivityGraphErrors, GetActivityGraphResponses, GetAdminGateData, GetAdminGateErrors, GetAdminGateResponses, GetAgentData, GetAgentErrors, GetAgentResponses, GetAggregatedBucketsData, GetAggregatedBucketsErrors, GetAggregatedBucketsResponses, GetAiAgentBreakdownData, GetAiAgentBreakdownErrors, GetAiAgentBreakdownResponses, GetAiAgentPagesData, GetAiAgentPagesErrors, GetAiAgentPagesResponses, GetAiAgentTimelineData, GetAiAgentTimelineErrors, GetAiAgentTimelineResponses, GetAiPageBreakdownData, GetAiPageBreakdownErrors, GetAiPageBreakdownResponses, GetAiStatusBreakdownData, GetAiStatusBreakdownErrors, GetAiStatusBreakdownResponses, GetAlertData, GetAlertErrors, GetAlertResponses, GetAlertRuleData, GetAlertRuleErrors, GetAlertRuleResponses, GetAllRepositoriesByNameData, GetAllRepositoriesByNameErrors, GetAllRepositoriesByNameResponses, GetAnalyticsActiveVisitorsData, GetAnalyticsActiveVisitorsErrors, GetAnalyticsActiveVisitorsResponses, GetAnalyticsEventsCountData, GetAnalyticsEventsCountErrors, GetAnalyticsEventsCountResponses, GetAnalyticsSessionEventsData, GetAnalyticsSessionEventsErrors, GetAnalyticsSessionEventsResponses, GetAnalyticsVisitorSessionsData, GetAnalyticsVisitorSessionsErrors, GetAnalyticsVisitorSessionsResponses, GetApiKeyData, GetApiKeyErrors, GetApiKeyPermissionsData, GetApiKeyPermissionsErrors, GetApiKeyPermissionsResponses, GetApiKeyResponses, GetAuditLogData, GetAuditLogErrors, GetAuditLogResponses, GetBackupData, GetBackupErrors, GetBackupResponses, GetBackupScheduleData, GetBackupScheduleErrors, GetBackupScheduleResponses, GetBranchesByRepositoryIdData, GetBranchesByRepositoryIdErrors, GetBranchesByRepositoryIdResponses, GetBucketedIncidentsData, GetBucketedIncidentsErrors, GetBucketedIncidentsResponses, GetBucketedStatusData, GetBucketedStatusErrors, GetBucketedStatusResponses, GetChallengeTokenData, GetChallengeTokenErrors, GetChallengeTokenResponses, GetChatReadinessData, GetChatReadinessErrors, GetChatReadinessResponses, GetCliStatusData, GetCliStatusErrors, GetCliStatusResponses, GetClusterHealthData, GetClusterHealthErrors, GetClusterHealthResponses, GetClusterMemberData, GetClusterMemberErrors, GetClusterMemberResponses, GetCmdData, GetCmdErrors, GetCmdResponses, GetContainerDetailData, GetContainerDetailErrors, GetContainerDetailResponses, GetContainerEnvironmentVariableData, GetContainerEnvironmentVariableErrors, GetContainerEnvironmentVariableResponses, GetContainerInfoData, GetContainerInfoErrors, GetContainerInfoResponses, GetContainerLogsByIdData, GetContainerLogsByIdErrors, GetContainerLogsData, GetContainerLogsErrors, GetContainerMetricsData, GetContainerMetricsErrors, GetContainerMetricsResponses, GetConversationData, GetConversationDetailData, GetConversationDetailErrors, GetConversationDetailResponses, GetConversationErrors, GetConversationResponses, GetConversationsData, GetConversationsErrors, GetConversationsResponses, GetCronByIdData, GetCronByIdErrors, GetCronByIdResponses, GetCronExecutionsData, GetCronExecutionsErrors, GetCronExecutionsResponses, GetCrossProjectTraceSiblingsData, GetCrossProjectTraceSiblingsErrors, GetCrossProjectTraceSiblingsResponses, GetCurrentMonitorStatusData, GetCurrentMonitorStatusErrors, GetCurrentMonitorStatusResponses, GetCurrentUserData, GetCurrentUserErrors, GetCurrentUserResponses, GetCustomDomainData, GetCustomDomainErrors, GetCustomDomainResponses, GetDashboardData, GetDashboardErrors, GetDashboardProjectsAnalyticsData, GetDashboardProjectsAnalyticsErrors, GetDashboardProjectsAnalyticsResponses, GetDashboardResponses, GetDeliveryData, GetDeliveryErrors, GetDeliveryResponses, GetDeploymentContainerLogContentData, GetDeploymentContainerLogContentErrors, GetDeploymentContainerLogContentResponses, GetDeploymentData, GetDeploymentErrors, GetDeploymentJobLogsData, GetDeploymentJobLogsErrors, GetDeploymentJobLogsResponses, GetDeploymentJobsData, GetDeploymentJobsErrors, GetDeploymentJobsResponses, GetDeploymentOperationsData, GetDeploymentOperationsErrors, GetDeploymentOperationsResponses, GetDeploymentOperationStatusData, GetDeploymentOperationStatusErrors, GetDeploymentOperationStatusResponses, GetDeploymentResponses, GetDeploymentTokenData, GetDeploymentTokenErrors, GetDeploymentTokenResponses, GetDiskStatusData, GetDiskStatusErrors, GetDiskStatusResponses, GetDnsChangesData, GetDnsChangesErrors, GetDnsChangesResponses, GetDnsProviderData, GetDnsProviderErrors, GetDnsProviderResponses, GetDomainByHostData, GetDomainByHostErrors, GetDomainByHostResponses, GetDomainByIdData, GetDomainByIdErrors, GetDomainByIdResponses, GetDomainByNameData, GetDomainByNameErrors, GetDomainByNameResponses, GetDomainData, GetDomainDnsRecordsData, GetDomainDnsRecordsErrors, GetDomainDnsRecordsResponses, GetDomainErrors, GetDomainOrderData, GetDomainOrderErrors, GetDomainOrderResponses, GetDomainResponses, GetEmailData, GetEmailErrors, GetEmailEventsData, GetEmailEventsErrors, GetEmailEventsResponses, GetEmailLinksData, GetEmailLinksErrors, GetEmailLinksResponses, GetEmailProviderData, GetEmailProviderErrors, GetEmailProviderResponses, GetEmailResponses, GetEmailStatsData, GetEmailStatsErrors, GetEmailStatsResponses, GetEmailTrackingData, GetEmailTrackingErrors, GetEmailTrackingResponses, GetEmailTrackingStatusData, GetEmailTrackingStatusErrors, GetEmailTrackingStatusResponses, GetEntityInfoData, GetEntityInfoErrors, GetEntityInfoResponses, GetEnvironmentCronsData, GetEnvironmentCronsErrors, GetEnvironmentCronsResponses, GetEnvironmentData, GetEnvironmentDomainsData, GetEnvironmentDomainsErrors, GetEnvironmentDomainsResponses, GetEnvironmentErrors, GetEnvironmentResponses, GetEnvironmentsData, GetEnvironmentsErrors, GetEnvironmentsResponses, GetEnvironmentVariablesData, GetEnvironmentVariablesErrors, GetEnvironmentVariablesResponses, GetEnvironmentVariableValueData, GetEnvironmentVariableValueErrors, GetEnvironmentVariableValueResponses, GetErrorDashboardStatsData, GetErrorDashboardStatsErrors, GetErrorDashboardStatsResponses, GetErrorEventData, GetErrorEventErrors, GetErrorEventResponses, GetErrorGroupData, GetErrorGroupErrors, GetErrorGroupResponses, GetErrorStatsData, GetErrorStatsErrors, GetErrorStatsResponses, GetErrorTimeSeriesData, GetErrorTimeSeriesErrors, GetErrorTimeSeriesResponses, GetEventDetailData, GetEventDetailErrors, GetEventDetailResponses, GetEventEntriesData, GetEventEntriesErrors, GetEventEntriesResponses, GetEventsCountData, GetEventsCountErrors, GetEventsCountResponses, GetEventsTimelineData, GetEventsTimelineErrors, GetEventsTimelineResponses, GetEventTypeBreakdownData, GetEventTypeBreakdownErrors, GetEventTypeBreakdownResponses, GetEventVisitorsData, GetEventVisitorsErrors, GetEventVisitorsResponses, GetExternalImageData, GetExternalImageErrors, GetExternalImageResponses, GetFileData, GetFileErrors, GetFileResponses, GetFlagData, GetFlagErrors, GetFlagResponses, GetFlagSnapshotData, GetFlagSnapshotErrors, GetFlagSnapshotResponses, GetFunnelMetricsData, GetFunnelMetricsErrors, GetFunnelMetricsResponses, GetGenaiTraceData, GetGenaiTraceErrors, GetGenaiTraceResponses, GetGeneralStatsData, GetGeneralStatsErrors, GetGeneralStatsResponses, GetGitProviderData, GetGitProviderErrors, GetGitProviderResponses, GetGlobalEventsData, GetGlobalEventsErrors, GetGlobalEventsResponses, GetGlobalEventStatsData, GetGlobalEventStatsErrors, GetGlobalEventStatsResponses, GetGlobalMcpData, GetGlobalMcpErrors, GetGlobalMcpResponses, GetGlobalSandboxStatusData, GetGlobalSandboxStatusErrors, GetGlobalSandboxStatusResponses, GetGlobalSkillData, GetGlobalSkillErrors, GetGlobalSkillResponses, GetGroupedPageMetricsData, GetGroupedPageMetricsErrors, GetGroupedPageMetricsResponses, GetHealthData, GetHealthErrors, GetHealthResponses, GetHourlyVisitsData, GetHourlyVisitsErrors, GetHourlyVisitsResponses, GetHttpChallengeDebugData, GetHttpChallengeDebugErrors, GetHttpChallengeDebugResponses, GetImportStatusData, GetImportStatusErrors, GetImportStatusResponses, GetIncidentData, GetIncidentErrors, GetIncidentResponses, GetIncidentUpdatesData, GetIncidentUpdatesErrors, GetIncidentUpdatesResponses, GetIpAccessControlData, GetIpAccessControlErrors, GetIpAccessControlResponses, GetIpGeolocationData, GetIpGeolocationErrors, GetIpGeolocationResponses, GetJoinTokenStatusData, GetJoinTokenStatusErrors, GetJoinTokenStatusResponses, GetLastDeploymentData, GetLastDeploymentErrors, GetLastDeploymentResponses, GetLatestScanData, GetLatestScanErrors, GetLatestScanResponses, GetLatestScansPerEnvironmentData, GetLatestScansPerEnvironmentErrors, GetLatestScansPerEnvironmentResponses, GetLiveVisitorsListData, GetLiveVisitorsListErrors, GetLiveVisitorsListResponses, GetLogContextData, GetLogContextErrors, GetLogContextResponses, GetMcpData, GetMcpErrors, GetMcpResponses, GetMetricsOverTimeData, GetMetricsOverTimeErrors, GetMetricsOverTimeResponses, GetMonitorData, GetMonitorErrors, GetMonitorResponses, GetNotificationProviderData, GetNotificationProviderErrors, GetNotificationProviderResponses, GetOnDemandCertStatusData, GetOnDemandCertStatusErrors, GetOnDemandCertStatusResponses, GetOrCreateDsnData, GetOrCreateDsnErrors, GetOrCreateDsnResponses, GetPageFlowData, GetPageFlowErrors, GetPageFlowResponses, GetPageHourlySessionsData, GetPageHourlySessionsErrors, GetPageHourlySessionsResponses, GetPagePathDetailData, GetPagePathDetailErrors, GetPagePathDetailResponses, GetPagePathsData, GetPagePathsErrors, GetPagePathsResponses, GetPagePathsSparklinesData, GetPagePathsSparklinesErrors, GetPagePathsSparklinesResponses, GetPagePathVisitorsData, GetPagePathVisitorsErrors, GetPagePathVisitorsResponses, GetPendingActionData, GetPendingActionErrors, GetPendingActionResponses, GetPerformanceMetricsData, GetPerformanceMetricsErrors, GetPerformanceMetricsResponses, GetPgUpgradeData, GetPgUpgradeErrors, GetPgUpgradeLogsData, GetPgUpgradeLogsErrors, GetPgUpgradeLogsResponses, GetPgUpgradeResponses, GetPipelineStatsData, GetPipelineStatsErrors, GetPipelineStatsResponses, GetPlatformInfoData, GetPlatformInfoErrors, GetPlatformInfoResponses, GetPostgresWalHealthData, GetPostgresWalHealthErrors, GetPostgresWalHealthResponses, GetPreferencesData, GetPreferencesErrors, GetPreferencesResponses, GetPreviewGatewayLogsData, GetPreviewGatewayLogsResponses, GetPreviewGatewaySettingsData, GetPreviewGatewaySettingsResponses, GetPreviewGatewayStatusData, GetPreviewGatewayStatusResponses, GetPricingData, GetPricingErrors, GetPricingResponses, GetPrivateIpData, GetPrivateIpErrors, GetPrivateIpResponses, GetProjectAlarmsSummaryData, GetProjectAlarmsSummaryErrors, GetProjectAlarmsSummaryResponses, GetProjectBySlugData, GetProjectBySlugErrors, GetProjectBySlugResponses, GetProjectData, GetProjectDeploymentsData, GetProjectDeploymentsErrors, GetProjectDeploymentsResponses, GetProjectErrors, GetProjectResponses, GetProjectsData, GetProjectsErrors, GetProjectServiceEnvironmentVariablesData, GetProjectServiceEnvironmentVariablesErrors, GetProjectServiceEnvironmentVariablesResponses, GetProjectSessionReplaysData, GetProjectSessionReplaysErrors, GetProjectSessionReplaysResponses, GetProjectsHealthData, GetProjectsHealthErrors, GetProjectsHealthResponses, GetProjectsMonitorHealthData, GetProjectsMonitorHealthErrors, GetProjectsMonitorHealthResponses, GetProjectsResponses, GetProjectStatisticsData, GetProjectStatisticsErrors, GetProjectStatisticsResponses, GetProjectTemplateData, GetProjectTemplateErrors, GetProjectTemplateResponses, GetPropertyBreakdownData, GetPropertyBreakdownErrors, GetPropertyBreakdownResponses, GetPropertyTimelineData, GetPropertyTimelineErrors, GetPropertyTimelineResponses, GetProviderConnectionsData, GetProviderConnectionsErrors, GetProviderConnectionsResponses, GetProviderMetadataData, GetProviderMetadataErrors, GetProviderMetadataResponses, GetProvidersMetadataData, GetProvidersMetadataErrors, GetProvidersMetadataResponses, GetProxyLogByIdData, GetProxyLogByIdErrors, GetProxyLogByIdResponses, GetProxyLogByRequestIdData, GetProxyLogByRequestIdErrors, GetProxyLogByRequestIdResponses, GetProxyLogsData, GetProxyLogsErrors, GetProxyLogsResponses, GetPublicBranchesData, GetPublicBranchesErrors, GetPublicBranchesResponses, GetPublicIpData, GetPublicIpErrors, GetPublicIpResponses, GetPublicRepositoryData, GetPublicRepositoryErrors, GetPublicRepositoryResponses, GetQuotaData, GetQuotaErrors, GetQuotaResponses, GetRecentActivityData, GetRecentActivityErrors, GetRecentActivityResponses, GetRemoteExternalImageData, GetRemoteExternalImageErrors, GetRemoteExternalImageResponses, GetRepositoryBranchesData, GetRepositoryBranchesErrors, GetRepositoryBranchesResponses, GetRepositoryByIdData, GetRepositoryByIdErrors, GetRepositoryByIdResponses, GetRepositoryByNameData, GetRepositoryByNameErrors, GetRepositoryByNameResponses, GetRepositoryPresetByNameData, GetRepositoryPresetByNameErrors, GetRepositoryPresetByNameResponses, GetRepositoryPresetLiveData, GetRepositoryPresetLiveErrors, GetRepositoryPresetLiveResponses, GetRepositoryTagsData, GetRepositoryTagsErrors, GetRepositoryTagsResponses, GetResolvedEnvironmentVariablesData, GetResolvedEnvironmentVariablesErrors, GetResolvedEnvironmentVariablesResponses, GetResolvedEnvironmentVariableValueData, GetResolvedEnvironmentVariableValueErrors, GetResolvedEnvironmentVariableValueResponses, GetRestoreCapabilitiesData, GetRestoreCapabilitiesErrors, GetRestoreCapabilitiesResponses, GetRestoreRunData, GetRestoreRunErrors, GetRestoreRunResponses, GetRouteData, GetRouteErrors, GetRouteResponses, GetRunData, GetRunErrors, GetRunResponses, GetRunWithLogsData, GetRunWithLogsErrors, GetRunWithLogsResponses, GetS3CredentialsData, GetS3CredentialsErrors, GetS3CredentialsResponses, GetS3SourceData, GetS3SourceErrors, GetS3SourceResponses, GetSandboxData, GetSandboxErrors, GetSandboxResponses, GetSandboxStatusData, GetSandboxStatusErrors, GetSandboxStatusResponses, GetScanByDeploymentData, GetScanByDeploymentErrors, GetScanByDeploymentResponses, GetScanData, GetScanErrors, GetScanResponses, GetScanVulnerabilitiesData, GetScanVulnerabilitiesErrors, GetScanVulnerabilitiesResponses, GetServiceBySlugData, GetServiceBySlugErrors, GetServiceBySlugResponses, GetServiceData, GetServiceEnvironmentVariableData, GetServiceEnvironmentVariableErrors, GetServiceEnvironmentVariableResponses, GetServiceEnvironmentVariablesData, GetServiceEnvironmentVariablesErrors, GetServiceEnvironmentVariablesResponses, GetServiceErrors, GetServiceHealthStatusData, GetServiceHealthStatusErrors, GetServiceHealthStatusResponses, GetServicePreviewEnvironmentVariableNamesData, GetServicePreviewEnvironmentVariableNamesErrors, GetServicePreviewEnvironmentVariableNamesResponses, GetServicePreviewEnvironmentVariablesMaskedData, GetServicePreviewEnvironmentVariablesMaskedErrors, GetServicePreviewEnvironmentVariablesMaskedResponses, GetServiceResponses, GetServiceRuntimeData, GetServiceRuntimeErrors, GetServiceRuntimeResponses, GetServiceStatsData, GetServiceStatsErrors, GetServiceStatsResponses, GetServiceTypeParametersData, GetServiceTypeParametersErrors, GetServiceTypeParametersResponses, GetServiceTypesData, GetServiceTypesErrors, GetServiceTypesResponses, GetSessionDetailsData, GetSessionDetailsErrors, GetSessionDetailsResponses, GetSessionEventsData, GetSessionEventsErrors, GetSessionEventsResponses, GetSessionLogsData, GetSessionLogsErrors, GetSessionLogsResponses, GetSessionReplayData, GetSessionReplayErrors, GetSessionReplayEventsData, GetSessionReplayEventsErrors, GetSessionReplayEventsResponses, GetSessionReplayResponses, GetSettingsData, GetSettingsErrors, GetSettingsResponses, GetSkillData, GetSkillErrors, GetSkillResponses, GetSlowQueriesData, GetSlowQueriesErrors, GetSlowQueriesResponses, GetStaticBundleData, GetStaticBundleErrors, GetStaticBundleResponses, GetStatusOverviewData, GetStatusOverviewErrors, GetStatusOverviewResponses, GetTagsByRepositoryIdData, GetTagsByRepositoryIdErrors, GetTagsByRepositoryIdResponses, GetTeamData, GetTeamErrors, GetTeamResponses, GetTimeBucketStatsData, GetTimeBucketStatsErrors, GetTimeBucketStatsResponses, GetTodayStatsData, GetTodayStatsErrors, GetTodayStatsResponses, GetTraceData, GetTraceErrors, GetTraceResponses, GetUnifiedTraceData, GetUnifiedTraceErrors, GetUnifiedTraceResponses, GetUniqueCountsData, GetUniqueCountsErrors, GetUniqueCountsResponses, GetUniqueEventsData, GetUniqueEventsErrors, GetUniqueEventsResponses, GetUpdateCapabilityData, GetUpdateCapabilityErrors, GetUpdateCapabilityResponses, GetUpdateStatusData, GetUpdateStatusErrors, GetUpdateStatusResponses, GetUptimeHistoryData, GetUptimeHistoryErrors, GetUptimeHistoryResponses, GetUsageByProviderData, GetUsageByProviderErrors, GetUsageByProviderResponses, GetUsageRecentData, GetUsageRecentErrors, GetUsageRecentResponses, GetUsageSummaryData, GetUsageSummaryErrors, GetUsageSummaryResponses, GetUsageTimeseriesData, GetUsageTimeseriesErrors, GetUsageTimeseriesResponses, GetUsageTopModelsData, GetUsageTopModelsErrors, GetUsageTopModelsResponses, GetVisitorByGuidData, GetVisitorByGuidErrors, GetVisitorByGuidResponses, GetVisitorByIdData, GetVisitorByIdErrors, GetVisitorByIdResponses, GetVisitorDetailsData, GetVisitorDetailsErrors, GetVisitorDetailsResponses, GetVisitorFacetsData, GetVisitorFacetsErrors, GetVisitorFacetsResponses, GetVisitorInfoData, GetVisitorInfoErrors, GetVisitorInfoResponses, GetVisitorJourneyData, GetVisitorJourneyErrors, GetVisitorJourneyResponses, GetVisitorsData, GetVisitorsErrors, GetVisitorSessionsData, GetVisitorSessionsErrors, GetVisitorSessionsResponses, GetVisitorsResponses, GetVisitorStatsData, GetVisitorStatsErrors, GetVisitorStatsResponses, GetWebhookData, GetWebhookErrors, GetWebhookResponses, GrantProjectAccessData, GrantProjectAccessErrors, GrantProjectAccessResponses, HandleGitProviderOauthCallbackData, HandleGitProviderOauthCallbackErrors, HasAnalyticsEventsData, HasAnalyticsEventsErrors, HasAnalyticsEventsResponses, HasErrorGroupsData, HasErrorGroupsErrors, HasErrorGroupsResponses, HasPerformanceMetricsData, HasPerformanceMetricsErrors, HasPerformanceMetricsResponses, ImportExternalServiceData, ImportExternalServiceErrors, ImportExternalServiceResponses, IngestLogsByPathData, IngestLogsByPathErrors, IngestLogsByPathResponses, IngestLogsData, IngestLogsErrors, IngestLogsResponses, IngestMetricsByPathData, IngestMetricsByPathErrors, IngestMetricsByPathResponses, IngestMetricsData, IngestMetricsErrors, IngestMetricsResponses, IngestSentryEnvelopeData, IngestSentryEnvelopeErrors, IngestSentryEnvelopeResponses, IngestSentryEventData, IngestSentryEventErrors, IngestSentryEventResponses, IngestTracesByPathData, IngestTracesByPathErrors, IngestTracesByPathResponses, IngestTracesData, IngestTracesErrors, IngestTracesResponses, InitSessionReplayData, InitSessionReplayErrors, InitSessionReplayResponses, InspectDropArchiveData, InspectDropArchiveErrors, InspectDropArchiveResponses, JobLogsData, JobLogsErrors, JobLogsResponses, JobStatusData, JobStatusErrors, JobStatusResponses, KillJobData, KillJobErrors, KillJobResponses, KvDelData, KvDelErrors, KvDelResponses, KvDisableData, KvDisableErrors, KvDisableResponses, KvEnableData, KvEnableErrors, KvEnableResponses, KvExpireData, KvExpireErrors, KvExpireResponses, KvGetData, KvGetErrors, KvGetResponses, KvIncrData, KvIncrErrors, KvIncrResponses, KvKeysData, KvKeysErrors, KvKeysResponses, KvSetData, KvSetErrors, KvSetResponses, KvStatusData, KvStatusErrors, KvStatusResponses, KvTtlData, KvTtlErrors, KvTtlResponses, KvUpdateData, KvUpdateErrors, KvUpdateResponses, LatestRunForSourceData, LatestRunForSourceErrors, LatestRunForSourceResponses, LinkCustomDomainToCertificateData, LinkCustomDomainToCertificateErrors, LinkCustomDomainToCertificateResponses, LinkServiceToProjectData, LinkServiceToProjectErrors, LinkServiceToProjectResponses, ListAgentRunsData, ListAgentRunsErrors, ListAgentRunsResponses, ListAgentsData, ListAgentsErrors, ListAgentsResponses, ListAiProvidersData, ListAiProvidersErrors, ListAiProvidersResponses, ListAlertRulesData, ListAlertRulesErrors, ListAlertRulesResponses, ListAlertsData, ListAlertsErrors, ListAlertsResponses, ListAllConversationsData, ListAllConversationsErrors, ListAllConversationsResponses, ListAllRunsData, ListAllRunsErrors, ListAllRunsResponses, ListApiKeysData, ListApiKeysErrors, ListApiKeysResponses, ListAuditLogsData, ListAuditLogsErrors, ListAuditLogsResponses, ListAvailableContainersData, ListAvailableContainersErrors, ListAvailableContainersResponses, ListBackupAlertsData, ListBackupAlertsErrors, ListBackupAlertsResponses, ListBackupChildrenData, ListBackupChildrenErrors, ListBackupChildrenResponses, ListBackupSchedulesData, ListBackupSchedulesErrors, ListBackupSchedulesResponses, ListBackupsForScheduleData, ListBackupsForScheduleErrors, ListBackupsForScheduleResponses, ListCommitsByRepositoryIdData, ListCommitsByRepositoryIdErrors, ListCommitsByRepositoryIdResponses, ListConnectionsData, ListConnectionsErrors, ListConnectionsResponses, ListContainersAtPathData, ListContainersAtPathErrors, ListContainersAtPathResponses, ListContainersData, ListContainersErrors, ListContainersResponses, ListConversationsData, ListConversationsErrors, ListConversationsResponses, ListCustomDomainsForProjectData, ListCustomDomainsForProjectErrors, ListCustomDomainsForProjectResponses, ListDashboardsData, ListDashboardsErrors, ListDashboardsResponses, ListDeliveriesData, ListDeliveriesErrors, ListDeliveriesResponses, ListDeploymentContainerLogsData, ListDeploymentContainerLogsErrors, ListDeploymentContainerLogsResponses, ListDeploymentTokensData, ListDeploymentTokensErrors, ListDeploymentTokensResponses, ListDnsProvidersData, ListDnsProvidersErrors, ListDnsProvidersResponses, ListDomainsData, ListDomainsErrors, ListDomainsResponses, ListDsnsData, ListDsnsErrors, ListDsnsResponses, ListEmailDomainsData, ListEmailDomainsErrors, ListEmailDomainsResponses, ListEmailProvidersData, ListEmailProvidersErrors, ListEmailProvidersResponses, ListEmailsData, ListEmailsErrors, ListEmailsResponses, ListEnrollmentTokensData, ListEnrollmentTokensErrors, ListEnrollmentTokensResponses, ListEntitiesData, ListEntitiesErrors, ListEntitiesResponses, ListErrorEventsData, ListErrorEventsErrors, ListErrorEventsResponses, ListErrorGroupsData, ListErrorGroupsErrors, ListErrorGroupsResponses, ListEventsData, ListEventsResponses, ListEventTypesData, ListEventTypesResponses, ListExternalImagesData, ListExternalImagesErrors, ListExternalImagesResponses, ListExternalPluginsData, ListExternalPluginsErrors, ListExternalPluginsResponses, ListExternalServiceBackupsData, ListExternalServiceBackupsErrors, ListExternalServiceBackupsResponses, ListFlagsData, ListFlagsErrors, ListFlagsResponses, ListFunnelsData, ListFunnelsErrors, ListFunnelsResponses, ListGitProvidersData, ListGitProvidersErrors, ListGitProvidersResponses, ListGlobalMcpsData, ListGlobalMcpsErrors, ListGlobalMcpsResponses, ListGlobalSkillsData, ListGlobalSkillsErrors, ListGlobalSkillsResponses, ListIncidentsData, ListIncidentsErrors, ListIncidentsResponses, ListInsightsData, ListInsightsErrors, ListInsightsResponses, ListIpAccessControlData, ListIpAccessControlErrors, ListIpAccessControlResponses, ListJobsData, ListJobsErrors, ListJobsResponses, ListKnownAiAgentsData, ListKnownAiAgentsErrors, ListKnownAiAgentsResponses, ListManagedDomainsData, ListManagedDomainsErrors, ListManagedDomainsResponses, ListMcpsData, ListMcpsErrors, ListMcpsResponses, ListMetricLabelKeysData, ListMetricLabelKeysErrors, ListMetricLabelKeysResponses, ListMetricLabelValuesData, ListMetricLabelValuesErrors, ListMetricLabelValuesResponses, ListMetricNamesData, ListMetricNamesErrors, ListMetricNamesResponses, ListModelsData, ListModelsErrors, ListModelsResponses, ListMonitorsData, ListMonitorsErrors, ListMonitorsResponses, ListNotificationProvidersData, ListNotificationProvidersErrors, ListNotificationProvidersResponses, ListOidcProvidersData, ListOidcProvidersResponses, ListOidcProviderUsersData, ListOidcProviderUsersErrors, ListOidcProviderUsersResponses, ListOidcRoleMappingsData, ListOidcRoleMappingsResponses, ListOnDemandCertsData, ListOnDemandCertsErrors, ListOnDemandCertsResponses, ListOrdersData, ListOrdersErrors, ListOrdersResponses, ListPeersData, ListPeersErrors, ListPeersResponses, ListPendingActionsData, ListPendingActionsErrors, ListPendingActionsResponses, ListPgUpgradesData, ListPgUpgradesErrors, ListPgUpgradesResponses, ListPresetsData, ListPresetsErrors, ListPresetsResponses, ListProjectAccessData, ListProjectAccessErrors, ListProjectAccessResponses, ListProjectAlarmsData, ListProjectAlarmsErrors, ListProjectAlarmsResponses, ListProjectScansData, ListProjectScansErrors, ListProjectScansResponses, ListProjectSecretsData, ListProjectSecretsErrors, ListProjectSecretsResponses, ListProjectServicesData, ListProjectServicesErrors, ListProjectServicesResponses, ListProjectTemplatesData, ListProjectTemplatesErrors, ListProjectTemplatesResponses, ListProjectTemplateTagsData, ListProjectTemplateTagsErrors, ListProjectTemplateTagsResponses, ListProviderKeysData, ListProviderKeysErrors, ListProviderKeysResponses, ListProviderZonesData, ListProviderZonesErrors, ListProviderZonesResponses, ListPublicProvidersData, ListPublicProvidersResponses, ListReleaseFilesData, ListReleaseFilesErrors, ListReleaseFilesResponses, ListReleasesData, ListReleasesErrors, ListReleasesResponses, ListRemoteExternalImagesData, ListRemoteExternalImagesErrors, ListRemoteExternalImagesResponses, ListRepositoriesByConnectionData, ListRepositoriesByConnectionErrors, ListRepositoriesByConnectionResponses, ListRepositoriesByProviderData, ListRepositoriesByProviderErrors, ListRepositoriesByProviderResponses, ListRestoreRunsForServiceData, ListRestoreRunsForServiceResponses, ListRootContainersData, ListRootContainersErrors, ListRootContainersResponses, ListRoutesData, ListRoutesErrors, ListRoutesResponses, ListS3SourcesData, ListS3SourcesErrors, ListS3SourcesResponses, ListSandboxesData, ListSandboxesResponses, ListScheduleRunJobsData, ListScheduleRunJobsErrors, ListScheduleRunJobsResponses, ListScheduleRunsData, ListScheduleRunsErrors, ListScheduleRunsResponses, ListScheduleServicesData, ListScheduleServicesErrors, ListScheduleServicesResponses, ListSecretsData, ListSecretsErrors, ListSecretsResponses, ListServiceHealthStatusesData, ListServiceHealthStatusesErrors, ListServiceHealthStatusesResponses, ListServiceProjectsData, ListServiceProjectsErrors, ListServiceProjectsResponses, ListServiceSchedulesData, ListServiceSchedulesErrors, ListServiceSchedulesResponses, ListServicesData, ListServicesErrors, ListServicesResponses, ListSkillsData, ListSkillsErrors, ListSkillsResponses, ListSourceBackupsData, ListSourceBackupsErrors, ListSourceBackupsResponses, ListSourceFilesData, ListSourceFilesErrors, ListSourceFilesResponses, ListSourceMapsData, ListSourceMapsErrors, ListSourceMapsResponses, ListSourcesData, ListSourcesErrors, ListSourcesResponses, ListStaticBundlesData, ListStaticBundlesErrors, ListStaticBundlesResponses, ListSyncedRepositoriesData, ListSyncedRepositoriesErrors, ListSyncedRepositoriesResponses, ListTeamMembersData, ListTeamMembersErrors, ListTeamMembersResponses, ListTeamProjectsData, ListTeamProjectsErrors, ListTeamProjectsResponses, ListTeamsData, ListTeamsErrors, ListTeamsResponses, ListUsersData, ListUsersErrors, ListUsersResponses, ListWebhooksData, ListWebhooksErrors, ListWebhooksResponses, LoginData, LoginErrors, LoginResponses, LogoutData, LogoutErrors, LogoutResponses, LookupDnsARecordsData, LookupDnsARecordsErrors, LookupDnsARecordsResponses, MintEnrollmentTokenData, MintEnrollmentTokenErrors, MintEnrollmentTokenResponses, MkdirData, MkdirErrors, MkdirResponses, NodeHeartbeatData, NodeHeartbeatErrors, NodeHeartbeatResponses, NodeMetricsGetRangeData, NodeMetricsGetRangeErrors, NodeMetricsGetRangeResponses, ObservabilityFullEventData, ObservabilityFullEventErrors, ObservabilityFullEventResponses, ObservabilityListEventsData, ObservabilityListEventsErrors, ObservabilityListEventsResponses, OidcCallbackData, PatchAdminGateData, PatchAdminGateErrors, PatchAdminGateResponses, PatchPreviewGatewaySettingsData, PatchPreviewGatewaySettingsResponses, PauseDeploymentData, PauseDeploymentErrors, PauseDeploymentResponses, PauseSandboxData, PauseSandboxErrors, PauseSandboxResponses, PlanRestoreData, PlanRestoreErrors, PlanRestoreResponses, PostDnsAckData, PostDnsAckErrors, PostDnsAckResponses, PreviewAlertData, PreviewAlertErrors, PreviewAlertResponses, PreviewFunnelMetricsData, PreviewFunnelMetricsErrors, PreviewFunnelMetricsResponses, PreviewHostnameModeData, PreviewHostnameModeErrors, PreviewHostnameModeResponses, PromoteClusterMemberData, PromoteClusterMemberErrors, PromoteClusterMemberResponses, PromoteDeploymentData, PromoteDeploymentErrors, PromoteDeploymentResponses, ProvisionDomainData, ProvisionDomainErrors, ProvisionDomainResponses, PurgeProjectLogsData, PurgeProjectLogsErrors, PurgeProjectLogsResponses, PushExternalImageData, PushExternalImageErrors, PushExternalImageResponses, QueryDataData, QueryDataErrors, QueryDataResponses, QueryGenaiTracesData, QueryGenaiTracesErrors, QueryGenaiTracesResponses, QueryLogsData, QueryLogsErrors, QueryLogsResponses, QueryMetricsData, QueryMetricsErrors, QueryMetricsResponses, QueryTracesData, QueryTracesErrors, QueryTracesResponses, QueryTraceSummariesData, QueryTraceSummariesErrors, QueryTraceSummariesResponses, ReadFileData, ReadFileErrors, ReadFileResponses, ReAnalyzeData, ReAnalyzeErrors, ReAnalyzeResponses, RecordConsoleEventData, RecordConsoleEventErrors, RecordConsoleEventResponses, RecordEventMetricsData, RecordEventMetricsErrors, RecordEventMetricsResponses, RecordFlagExposureData, RecordFlagExposureErrors, RecordFlagExposureResponses, RecordSpeedMetricsData, RecordSpeedMetricsErrors, RecordSpeedMetricsResponses, RefreshRouteTableData, RefreshRouteTableErrors, RefreshRouteTableResponses, RegenerateDsnData, RegenerateDsnErrors, RegenerateDsnResponses, RegisterExternalImageData, RegisterExternalImageErrors, RegisterExternalImageResponses, RegisterNodeData, RegisterNodeErrors, RegisterNodeResponses, ReinstallGitlabWebhookData, ReinstallGitlabWebhookErrors, ReinstallGitlabWebhookResponses, RejectPendingActionData, RejectPendingActionErrors, RejectPendingActionResponses, ReloadPluginsData, ReloadPluginsErrors, ReloadPluginsResponses, RemoveClusterMemberData, RemoveClusterMemberErrors, RemoveClusterMemberResponses, RemoveManagedDomainData, RemoveManagedDomainErrors, RemoveManagedDomainResponses, RemoveRoleData, RemoveRoleErrors, RemoveRoleResponses, RemoveTeamMemberData, RemoveTeamMemberErrors, RemoveTeamMemberResponses, RenameConversationData, RenameConversationErrors, RenameConversationResponses, RenewDomainData, RenewDomainErrors, RenewDomainResponses, RequestPasswordResetData, RequestPasswordResetErrors, RequestPasswordResetResponses, ResetPasswordData, ResetPasswordErrors, ResetPasswordResponses, ResizeSandboxData, ResizeSandboxErrors, ResizeSandboxResponses, ResolveAlarmData, ResolveAlarmErrors, ResolveAlarmResponses, RestartContainerData, RestartContainerErrors, RestartContainerResponses, RestartPreviewGatewayData, RestartPreviewGatewayResponses, RestartSandboxData, RestartSandboxErrors, RestartSandboxResponses, RestoreFlagData, RestoreFlagErrors, RestoreFlagResponses, RestoreUserData, RestoreUserErrors, RestoreUserResponses, ResumeDeploymentData, ResumeDeploymentErrors, ResumeDeploymentResponses, ResumeSandboxData, ResumeSandboxErrors, ResumeSandboxResponses, RetryClusterData, RetryClusterErrors, RetryClusterResponses, RetryDeliveryData, RetryDeliveryErrors, RetryDeliveryResponses, RetryPgUpgradeData, RetryPgUpgradeErrors, RetryPgUpgradeResponses, RetryRunData, RetryRunErrors, RetryRunResponses, RevealGlobalMcpConfigData, RevealGlobalMcpConfigErrors, RevealGlobalMcpConfigResponses, RevealMcpConfigData, RevealMcpConfigErrors, RevealMcpConfigResponses, RevealNotificationProviderConfigData, RevealNotificationProviderConfigErrors, RevealNotificationProviderConfigResponses, RevealServiceParameterData, RevealServiceParameterErrors, RevealServiceParameterResponses, RevenueCreateIntegrationData, RevenueCreateIntegrationErrors, RevenueCreateIntegrationResponses, RevenueDeleteIntegrationData, RevenueDeleteIntegrationResponses, RevenueGlobalEventsData, RevenueGlobalEventsResponses, RevenueImportInvoicesCsvData, RevenueImportInvoicesCsvErrors, RevenueImportInvoicesCsvResponses, RevenueImportSubscriptionsCsvData, RevenueImportSubscriptionsCsvErrors, RevenueImportSubscriptionsCsvResponses, RevenueListIntegrationsData, RevenueListIntegrationsResponses, RevenueListProvidersData, RevenueListProvidersResponses, RevenueMetricsCustomersData, RevenueMetricsCustomersResponses, RevenueMetricsGlobalMrrData, RevenueMetricsGlobalMrrResponses, RevenueMetricsGlobalSummaryData, RevenueMetricsGlobalSummaryResponses, RevenueMetricsMrrData, RevenueMetricsMrrResponses, RevenueMetricsSummaryData, RevenueMetricsSummaryResponses, RevenueRecentEventsData, RevenueRecentEventsResponses, RevenueRotateTokenData, RevenueRotateTokenResponses, RevenueUpdateConfigData, RevenueUpdateConfigErrors, RevenueUpdateConfigResponses, RevenueUpdateSecretData, RevenueUpdateSecretErrors, RevenueUpdateSecretResponses, RevokeDsnData, RevokeDsnErrors, RevokeDsnResponses, RevokeEnrollmentTokenData, RevokeEnrollmentTokenErrors, RevokeEnrollmentTokenResponses, RevokeJoinTokenData, RevokeJoinTokenErrors, RevokeJoinTokenResponses, RevokeProjectAccessData, RevokeProjectAccessErrors, RevokeProjectAccessResponses, RollbackPgUpgradeData, RollbackPgUpgradeErrors, RollbackPgUpgradeResponses, RollbackToDeploymentData, RollbackToDeploymentErrors, RollbackToDeploymentResponses, RootfsGcData, RootfsGcResponses, RootfsReportData, RootfsReportResponses, RotateApiKeyData, RotateApiKeyErrors, RotateApiKeyResponses, RotateDeploymentTokenData, RotateDeploymentTokenErrors, RotateDeploymentTokenResponses, RunBackupForSourceData, RunBackupForSourceErrors, RunBackupForSourceResponses, RunConnectionHealthCheckData, RunConnectionHealthCheckErrors, RunConnectionHealthCheckResponses, RunExternalServiceBackupData, RunExternalServiceBackupErrors, RunExternalServiceBackupResponses, RunScheduleNowData, RunScheduleNowErrors, RunScheduleNowResponses, SandboxCreatePreviewLinkData, SandboxCreatePreviewLinkErrors, SandboxCreatePreviewLinkResponses, SaveAgentTokenData, SaveAgentTokenErrors, SaveAgentTokenResponses, SaveAiProviderCredentialData, SaveAiProviderCredentialErrors, SaveAiProviderCredentialResponses, SearchLogsData, SearchLogsErrors, SearchLogsResponses, SendEmailData, SendEmailErrors, SendEmailResponses, SetDefaultS3SourceData, SetDefaultS3SourceErrors, SetDefaultS3SourceResponses, SetFlagEnvironmentData, SetFlagEnvironmentErrors, SetFlagEnvironmentResponses, SetPreviewPasswordData, SetPreviewPasswordErrors, SetPreviewPasswordResponses, SetupDnsChallengeData, SetupDnsChallengeErrors, SetupDnsChallengeResponses, SetupDnsData, SetupDnsErrors, SetupDnsResponses, SetupEmailTrackingData, SetupEmailTrackingErrors, SetupEmailTrackingResponses, SetupMfaData, SetupMfaErrors, SetupMfaResponses, SleepEnvironmentData, SleepEnvironmentErrors, SleepEnvironmentResponses, SmokeTestAgentData, SmokeTestAgentErrors, SmokeTestAgentResponses, SourceSandboxData, SourceSandboxErrors, SourceSandboxResponses, StartAnalysisData, StartAnalysisErrors, StartAnalysisResponses, StartContainerData, StartContainerErrors, StartContainerResponses, StartFixData, StartFixErrors, StartFixResponses, StartGitProviderOauthData, StartGitProviderOauthErrors, StartOidcLoginBySlugData, StartOidcLoginBySlugErrors, StartPgUpgradeData, StartPgUpgradeErrors, StartPgUpgradeResponses, StartRestoreData, StartRestoreErrors, StartRestoreResponses, StartServiceData, StartServiceErrors, StartServiceResponses, StartUpdateData, StartUpdateErrors, StartUpdateResponses, StatPathData, StatPathErrors, StatPathResponses, StopContainerData, StopContainerErrors, StopContainerResponses, StopSandboxData, StopSandboxErrors, StopSandboxResponses, StopServiceData, StopServiceErrors, StopServiceResponses, StreamContainerMetricsData, StreamContainerMetricsErrors, StreamContainerMetricsResponses, StreamEventsData, StreamEventsErrors, StreamEventsResponses, StreamRunEventsData, StreamRunEventsErrors, StreamRunEventsResponses, SyncRepositoriesData, SyncRepositoriesErrors, SyncRepositoriesResponses, TailDeploymentJobLogsData, TailDeploymentJobLogsErrors, TailLogsData, TailLogsErrors, TailLogsResponses, TeardownDeploymentData, TeardownDeploymentErrors, TeardownDeploymentResponses, TeardownEnvironmentData, TeardownEnvironmentErrors, TeardownEnvironmentResponses, TestNotificationProviderData, TestNotificationProviderErrors, TestNotificationProviderResponses, TestOidcProviderData, TestOidcProviderResponses, TestProviderConnectionData, TestProviderConnectionErrors, TestProviderConnectionResponses, TestProviderData, TestProviderErrors, TestProviderKeyByIdData, TestProviderKeyByIdErrors, TestProviderKeyByIdResponses, TestProviderKeyInlineData, TestProviderKeyInlineErrors, TestProviderKeyInlineResponses, TestProviderResponses, TestS3ConnectionPreviewData, TestS3ConnectionPreviewErrors, TestS3ConnectionPreviewResponses, TestS3SourceConnectionData, TestS3SourceConnectionErrors, TestS3SourceConnectionResponses, TrackClickData, TrackClickErrors, TrackOpenData, TrackOpenErrors, TrackOpenResponses, TriggerAgentData, TriggerAgentErrors, TriggerAgentResponses, TriggerProjectPipelineData, TriggerProjectPipelineErrors, TriggerProjectPipelineResponses, TriggerScanData, TriggerScanErrors, TriggerScanResponses, TriggerServiceHealthCheckData, TriggerServiceHealthCheckErrors, TriggerServiceHealthCheckResponses, TriggerWeeklyDigestData, TriggerWeeklyDigestErrors, TriggerWeeklyDigestResponses, UnlinkServiceFromProjectData, UnlinkServiceFromProjectErrors, UnlinkServiceFromProjectResponses, UpdateAgentData, UpdateAgentErrors, UpdateAgentResponses, UpdateAiProviderData, UpdateAiProviderErrors, UpdateAiProviderResponses, UpdateAlertData, UpdateAlertErrors, UpdateAlertResponses, UpdateAlertRuleData, UpdateAlertRuleErrors, UpdateAlertRuleResponses, UpdateApiKeyData, UpdateApiKeyErrors, UpdateApiKeyResponses, UpdateAutomaticDeployData, UpdateAutomaticDeployErrors, UpdateAutomaticDeployResponses, UpdateBackupScheduleData, UpdateBackupScheduleErrors, UpdateBackupScheduleResponses, UpdateCloudflareProviderData, UpdateCloudflareProviderErrors, UpdateCloudflareProviderResponses, UpdateConnectionTokenData, UpdateConnectionTokenErrors, UpdateConnectionTokenResponses, UpdateCustomDomainData, UpdateCustomDomainErrors, UpdateCustomDomainResponses, UpdateDashboardData, UpdateDashboardErrors, UpdateDashboardResponses, UpdateDeploymentTokenData, UpdateDeploymentTokenErrors, UpdateDeploymentTokenResponses, UpdateEmailProviderData, UpdateEmailProviderErrors, UpdateEmailProviderResponses, UpdateEnvironmentSettingsData, UpdateEnvironmentSettingsErrors, UpdateEnvironmentSettingsResponses, UpdateEnvironmentSubdomainData, UpdateEnvironmentSubdomainErrors, UpdateEnvironmentSubdomainResponses, UpdateEnvironmentVariableData, UpdateEnvironmentVariableErrors, UpdateEnvironmentVariableResponses, UpdateErrorGroupData, UpdateErrorGroupErrors, UpdateErrorGroupResponses, UpdateFlagData, UpdateFlagErrors, UpdateFlagResponses, UpdateFunnelData, UpdateFunnelErrors, UpdateFunnelResponses, UpdateGitProviderCredentialsData, UpdateGitProviderCredentialsErrors, UpdateGitProviderCredentialsResponses, UpdateGitSettingsData, UpdateGitSettingsErrors, UpdateGitSettingsResponses, UpdateGlobalMcpData, UpdateGlobalMcpErrors, UpdateGlobalMcpResponses, UpdateGlobalSkillData, UpdateGlobalSkillErrors, UpdateGlobalSkillResponses, UpdateIncidentStatusData, UpdateIncidentStatusErrors, UpdateIncidentStatusResponses, UpdateIpAccessControlData, UpdateIpAccessControlErrors, UpdateIpAccessControlResponses, UpdateManagedDomainData, UpdateManagedDomainErrors, UpdateManagedDomainResponses, UpdateMcpData, UpdateMcpErrors, UpdateMcpResponses, UpdateNotificationEmailProviderData, UpdateNotificationEmailProviderErrors, UpdateNotificationEmailProviderResponses, UpdateNotificationProviderData, UpdateNotificationProviderErrors, UpdateNotificationProviderResponses, UpdateOidcProviderData, UpdateOidcProviderResponses, UpdatePreferencesData, UpdatePreferencesErrors, UpdatePreferencesResponses, UpdateProjectData, UpdateProjectDeploymentConfigData, UpdateProjectDeploymentConfigErrors, UpdateProjectDeploymentConfigResponses, UpdateProjectErrors, UpdateProjectResponses, UpdateProjectSecretData, UpdateProjectSecretErrors, UpdateProjectSecretResponses, UpdateProjectSettingsData, UpdateProjectSettingsErrors, UpdateProjectSettingsResponses, UpdateProviderData, UpdateProviderErrors, UpdateProviderKeyData, UpdateProviderKeyErrors, UpdateProviderKeyResponses, UpdateProviderResponses, UpdateRouteData, UpdateRouteErrors, UpdateRouteResponses, UpdateS3SourceData, UpdateS3SourceErrors, UpdateS3SourceResponses, UpdateSelfData, UpdateSelfErrors, UpdateSelfResponses, UpdateServiceData, UpdateServiceErrors, UpdateServiceResourcesData, UpdateServiceResourcesErrors, UpdateServiceResourcesResponses, UpdateServiceResponses, UpdateSessionDurationData, UpdateSessionDurationErrors, UpdateSessionDurationResponses, UpdateSettingsData, UpdateSettingsErrors, UpdateSettingsResponses, UpdateSkillData, UpdateSkillErrors, UpdateSkillResponses, UpdateSlackProviderData, UpdateSlackProviderErrors, UpdateSlackProviderResponses, UpdateSpeedMetricsData, UpdateSpeedMetricsErrors, UpdateSpeedMetricsResponses, UpdateTeamData, UpdateTeamErrors, UpdateTeamMemberRoleData, UpdateTeamMemberRoleErrors, UpdateTeamMemberRoleResponses, UpdateTeamResponses, UpdateUserData, UpdateUserErrors, UpdateUserResponses, UpdateWebhookData, UpdateWebhookErrors, UpdateWebhookProviderData, UpdateWebhookProviderErrors, UpdateWebhookProviderResponses, UpdateWebhookResponses, UpgradePreviewGatewayData, UpgradePreviewGatewayResponses, UpgradeServiceData, UpgradeServiceErrors, UpgradeServiceResponses, UploadGlobalSkillData, UploadGlobalSkillErrors, UploadGlobalSkillResponses, UploadReleaseFileData, UploadReleaseFileErrors, UploadReleaseFileResponses, UploadSkillData, UploadSkillErrors, UploadSkillResponses, UploadSourceFileData, UploadSourceFileErrors, UploadSourceFileResponses, UploadSourceMapData, UploadSourceMapErrors, UploadSourceMapResponses, UploadStaticBundleData, UploadStaticBundleErrors, UploadStaticBundleResponses, UpsertSecretData, UpsertSecretErrors, UpsertSecretResponses, ValidateConnectionData, ValidateConnectionErrors, ValidateConnectionResponses, ValidateEmailData, ValidateEmailErrors, ValidateEmailResponses, VerifyAndEnableMfaData, VerifyAndEnableMfaErrors, VerifyAndEnableMfaResponses, VerifyDomainData, VerifyDomainErrors, VerifyDomainResponses, VerifyEmailData, VerifyEmailErrors, VerifyEmailResponses, VerifyManagedDomainData, VerifyManagedDomainErrors, VerifyManagedDomainResponses, VerifyMfaChallengeData, VerifyMfaChallengeErrors, VerifyMfaChallengeResponses, VerifyStepUpData, VerifyStepUpErrors, VerifyStepUpResponses, WakeEnvironmentData, WakeEnvironmentErrors, WakeEnvironmentResponses, WebhookTriggerData, WebhookTriggerErrors, WebhookTriggerResponses, WorkflowDryRunData, WorkflowDryRunErrors, WorkflowDryRunResponses, WriteFileData, WriteFileErrors, WriteFileResponses, WriteFilesData, WriteFilesErrors, WriteFilesResponses } from './types.gen'; +import type { AcknowledgeAlarmData, AcknowledgeAlarmErrors, AcknowledgeAlarmResponses, ActivateAiProviderData, ActivateAiProviderErrors, ActivateAiProviderResponses, ActivateApiKeyData, ActivateApiKeyErrors, ActivateApiKeyResponses, ActivateConnectionData, ActivateConnectionErrors, ActivateConnectionResponses, ActivateProviderData, ActivateProviderErrors, ActivateProviderResponses, AddClusterMemberData, AddClusterMemberErrors, AddClusterMemberResponses, AddContextData, AddContextErrors, AddContextResponses, AddEnvironmentDomainData, AddEnvironmentDomainErrors, AddEnvironmentDomainResponses, AddEventsData, AddEventsErrors, AddEventsResponses, AddManagedDomainData, AddManagedDomainErrors, AddManagedDomainResponses, AddSessionReplayEventsData, AddSessionReplayEventsErrors, AddSessionReplayEventsResponses, AddTeamMemberData, AddTeamMemberErrors, AddTeamMemberResponses, AdminDrainNodeData, AdminDrainNodeErrors, AdminDrainNodeResponses, AdminDrainStatusData, AdminDrainStatusErrors, AdminDrainStatusResponses, AdminGetNodeData, AdminGetNodeErrors, AdminGetNodeResponses, AdminListNodeContainersData, AdminListNodeContainersErrors, AdminListNodeContainersResponses, AdminListNodesData, AdminListNodesErrors, AdminListNodesResponses, AdminRemoveNodeData, AdminRemoveNodeErrors, AdminRemoveNodeResponses, AdminUndrainNodeData, AdminUndrainNodeErrors, AdminUndrainNodeResponses, ApplyHostnameModeData, ApplyHostnameModeErrors, ApplyHostnameModeResponses, ArchiveConversationData, ArchiveConversationErrors, ArchiveConversationResponses, ArchiveFlagData, ArchiveFlagErrors, ArchiveFlagResponses, AssignRoleData, AssignRoleErrors, AssignRoleResponses, AttachScheduleServicesData, AttachScheduleServicesErrors, AttachScheduleServicesResponses, BlobCopyData, BlobCopyErrors, BlobCopyResponses, BlobDeleteData, BlobDeleteErrors, BlobDeleteResponses, BlobDisableData, BlobDisableErrors, BlobDisableResponses, BlobDownloadData, BlobDownloadErrors, BlobDownloadResponses, BlobEnableData, BlobEnableErrors, BlobEnableResponses, BlobHeadData, BlobHeadErrors, BlobHeadResponses, BlobListData, BlobListErrors, BlobListResponses, BlobPutData, BlobPutErrors, BlobPutResponses, BlobStatusData, BlobStatusErrors, BlobStatusResponses, BlobUpdateData, BlobUpdateErrors, BlobUpdateResponses, CancelBackupData, CancelBackupErrors, CancelBackupResponses, CancelData, CancelDeploymentData, CancelDeploymentErrors, CancelDeploymentResponses, CancelDomainOrderData, CancelDomainOrderErrors, CancelDomainOrderResponses, CancelErrors, CancelPgUpgradeData, CancelPgUpgradeErrors, CancelPgUpgradeResponses, CancelResponses, CancelRunData, CancelRunErrors, CancelRunResponses, CancelScheduleRunData, CancelScheduleRunErrors, CancelScheduleRunResponses, ChangePasswordSelfData, ChangePasswordSelfErrors, ChangePasswordSelfResponses, ChangeProjectSourceData, ChangeProjectSourceErrors, ChangeProjectSourceResponses, ChangeRequiredPasswordData, ChangeRequiredPasswordErrors, ChangeRequiredPasswordResponses, ChatCompletionsData, ChatCompletionsErrors, ChatCompletionsResponses, CheckAnalyticsHasEventsData, CheckAnalyticsHasEventsErrors, CheckAnalyticsHasEventsResponses, CheckCommitExistsData, CheckCommitExistsErrors, CheckCommitExistsResponses, CheckDomainStatusData, CheckDomainStatusErrors, CheckDomainStatusResponses, CheckExplorerSupportData, CheckExplorerSupportErrors, CheckExplorerSupportResponses, CheckForUpdateData, CheckForUpdateErrors, CheckForUpdateResponses, CheckIpBlockedData, CheckIpBlockedErrors, CheckIpBlockedResponses, CheckProviderDeletionSafetyData, CheckProviderDeletionSafetyErrors, CheckProviderDeletionSafetyResponses, ChunkUploadOptionsData, ChunkUploadOptionsResponses, CleanupExpiredBackupsData, CleanupExpiredBackupsErrors, CleanupExpiredBackupsResponses, ClearPreviewPasswordData, ClearPreviewPasswordErrors, ClearPreviewPasswordResponses, CliDeviceApproveData, CliDeviceApproveErrors, CliDeviceApproveResponses, CliDeviceDenyData, CliDeviceDenyErrors, CliDeviceDenyResponses, CliDeviceLookupData, CliDeviceLookupErrors, CliDeviceLookupResponses, CliDevicePollData, CliDevicePollErrors, CliDevicePollResponses, CliDeviceStartData, CliDeviceStartErrors, CliDeviceStartResponses, CliLogoutData, CliLogoutErrors, CliLogoutResponses, CmdData, CmdErrors, CmdKillData, CmdKillErrors, CmdKillResponses, CmdLogsData, CmdLogsErrors, CmdLogsResponses, CmdResponses, ConfirmPendingActionData, ConfirmPendingActionErrors, ConfirmPendingActionResponses, ContainerMetricsGetHistoryData, ContainerMetricsGetHistoryErrors, ContainerMetricsGetHistoryResponses, CreateAgentData, CreateAgentErrors, CreateAgentResponses, CreateAlertData, CreateAlertErrors, CreateAlertResponses, CreateAlertRuleData, CreateAlertRuleErrors, CreateAlertRuleResponses, CreateApiKeyData, CreateApiKeyErrors, CreateApiKeyResponses, CreateBackupScheduleData, CreateBackupScheduleErrors, CreateBackupScheduleResponses, CreateBitbucketProviderData, CreateBitbucketProviderErrors, CreateBitbucketProviderResponses, CreateCloudflareProviderData, CreateCloudflareProviderErrors, CreateCloudflareProviderResponses, CreateConversationData, CreateConversationErrors, CreateConversationResponses, CreateCustomDomainData, CreateCustomDomainErrors, CreateCustomDomainResponses, CreateDashboardData, CreateDashboardErrors, CreateDashboardResponses, CreateDeploymentTokenData, CreateDeploymentTokenErrors, CreateDeploymentTokenResponses, CreateDnsProviderData, CreateDnsProviderErrors, CreateDnsProviderResponses, CreateDomainData, CreateDomainErrors, CreateDomainResponses, CreateDsnData, CreateDsnErrors, CreateDsnResponses, CreateEmailDomainData, CreateEmailDomainErrors, CreateEmailDomainResponses, CreateEmailProviderData, CreateEmailProviderErrors, CreateEmailProviderResponses, CreateEnvironmentData, CreateEnvironmentErrors, CreateEnvironmentResponses, CreateEnvironmentVariableData, CreateEnvironmentVariableErrors, CreateEnvironmentVariableResponses, CreateFlagData, CreateFlagErrors, CreateFlagResponses, CreateFunnelData, CreateFunnelErrors, CreateFunnelResponses, CreateGenericProviderData, CreateGenericProviderErrors, CreateGenericProviderResponses, CreateGiteaPatProviderData, CreateGiteaPatProviderErrors, CreateGiteaPatProviderResponses, CreateGithubPatProviderData, CreateGithubPatProviderErrors, CreateGithubPatProviderResponses, CreateGitlabOauthProviderData, CreateGitlabOauthProviderErrors, CreateGitlabOauthProviderResponses, CreateGitlabPatProviderData, CreateGitlabPatProviderErrors, CreateGitlabPatProviderResponses, CreateGitProviderData, CreateGitProviderErrors, CreateGitProviderResponses, CreateGlobalMcpData, CreateGlobalMcpErrors, CreateGlobalMcpResponses, CreateGlobalSkillData, CreateGlobalSkillErrors, CreateGlobalSkillResponses, CreateIncidentData, CreateIncidentErrors, CreateIncidentResponses, CreateIpAccessControlData, CreateIpAccessControlErrors, CreateIpAccessControlResponses, CreateMcpData, CreateMcpErrors, CreateMcpResponses, CreateMonitorData, CreateMonitorErrors, CreateMonitorResponses, CreateNotificationEmailProviderData, CreateNotificationEmailProviderErrors, CreateNotificationEmailProviderResponses, CreateNotificationProviderData, CreateNotificationProviderErrors, CreateNotificationProviderResponses, CreateOidcProviderData, CreateOidcProviderErrors, CreateOidcProviderResponses, CreateOidcRoleMappingData, CreateOidcRoleMappingResponses, CreateOrRecreateOrderData, CreateOrRecreateOrderErrors, CreateOrRecreateOrderResponses, CreatePlanData, CreatePlanErrors, CreatePlanResponses, CreatePrData, CreatePrErrors, CreateProjectData, CreateProjectErrors, CreateProjectFromTemplateData, CreateProjectFromTemplateErrors, CreateProjectFromTemplateResponses, CreateProjectReleaseData, CreateProjectReleaseErrors, CreateProjectReleaseResponses, CreateProjectResponses, CreateProjectSecretData, CreateProjectSecretErrors, CreateProjectSecretResponses, CreateProviderKeyData, CreateProviderKeyErrors, CreateProviderKeyResponses, CreatePrResponses, CreateReleaseData, CreateReleaseErrors, CreateReleaseResponses, CreateRouteData, CreateRouteErrors, CreateRouteResponses, CreateS3SourceData, CreateS3SourceErrors, CreateS3SourceResponses, CreateSandboxData, CreateSandboxErrors, CreateSandboxResponses, CreateServiceData, CreateServiceErrors, CreateServiceResponses, CreateSkillData, CreateSkillErrors, CreateSkillResponses, CreateSlackProviderData, CreateSlackProviderErrors, CreateSlackProviderResponses, CreateTeamData, CreateTeamErrors, CreateTeamResponses, CreateUserData, CreateUserErrors, CreateUserResponses, CreateWebhookData, CreateWebhookErrors, CreateWebhookProviderData, CreateWebhookProviderErrors, CreateWebhookProviderResponses, CreateWebhookResponses, DeactivateApiKeyData, DeactivateApiKeyErrors, DeactivateApiKeyResponses, DeactivateConnectionData, DeactivateConnectionErrors, DeactivateConnectionResponses, DeactivateProviderData, DeactivateProviderErrors, DeactivateProviderResponses, DeleteAgentData, DeleteAgentErrors, DeleteAgentResponses, DeleteAlertData, DeleteAlertErrors, DeleteAlertResponses, DeleteAlertRuleData, DeleteAlertRuleErrors, DeleteAlertRuleResponses, DeleteApiKeyData, DeleteApiKeyErrors, DeleteApiKeyResponses, DeleteBackupData, DeleteBackupErrors, DeleteBackupResponses, DeleteBackupScheduleData, DeleteBackupScheduleErrors, DeleteBackupScheduleResponses, DeleteConnectionData, DeleteConnectionErrors, DeleteConnectionResponses, DeleteCustomDomainData, DeleteCustomDomainErrors, DeleteCustomDomainResponses, DeleteDashboardData, DeleteDashboardErrors, DeleteDashboardResponses, DeleteDeploymentTokenData, DeleteDeploymentTokenErrors, DeleteDeploymentTokenResponses, DeleteDnsProviderData, DeleteDnsProviderErrors, DeleteDnsProviderResponses, DeleteDomainData, DeleteDomainErrors, DeleteDomainResponses, DeleteEmailDomainData, DeleteEmailDomainErrors, DeleteEmailDomainResponses, DeleteEmailProviderData, DeleteEmailProviderErrors, DeleteEmailProviderResponses, DeleteEnvironmentData, DeleteEnvironmentDomainData, DeleteEnvironmentDomainErrors, DeleteEnvironmentDomainResponses, DeleteEnvironmentErrors, DeleteEnvironmentResponses, DeleteEnvironmentVariableData, DeleteEnvironmentVariableErrors, DeleteEnvironmentVariableResponses, DeleteExternalImageData, DeleteExternalImageErrors, DeleteExternalImageResponses, DeleteFunnelData, DeleteFunnelErrors, DeleteFunnelResponses, DeleteGitProviderData, DeleteGitProviderErrors, DeleteGitProviderResponses, DeleteGlobalMcpData, DeleteGlobalMcpErrors, DeleteGlobalMcpResponses, DeleteGlobalSkillData, DeleteGlobalSkillErrors, DeleteGlobalSkillResponses, DeleteIpAccessControlData, DeleteIpAccessControlErrors, DeleteIpAccessControlResponses, DeleteMcpData, DeleteMcpErrors, DeleteMcpResponses, DeleteMonitorData, DeleteMonitorErrors, DeleteMonitorResponses, DeleteNotificationProviderData, DeleteNotificationProviderErrors, DeleteNotificationProviderResponses, DeleteOidcProviderData, DeleteOidcProviderResponses, DeleteOidcRoleMappingData, DeleteOidcRoleMappingResponses, DeletePreferencesData, DeletePreferencesErrors, DeletePreferencesResponses, DeleteProjectData, DeleteProjectErrors, DeleteProjectResponses, DeleteProjectSecretData, DeleteProjectSecretErrors, DeleteProjectSecretResponses, DeleteProviderKeyData, DeleteProviderKeyErrors, DeleteProviderKeyResponses, DeleteProviderSafelyData, DeleteProviderSafelyErrors, DeleteProviderSafelyResponses, DeleteReleaseSourceFilesData, DeleteReleaseSourceFilesErrors, DeleteReleaseSourceFilesResponses, DeleteReleaseSourceMapsData, DeleteReleaseSourceMapsErrors, DeleteReleaseSourceMapsResponses, DeleteRouteData, DeleteRouteErrors, DeleteRouteResponses, DeleteS3SourceData, DeleteS3SourceErrors, DeleteS3SourceResponses, DeleteScanData, DeleteScanErrors, DeleteScanResponses, DeleteSecretData, DeleteSecretErrors, DeleteSecretResponses, DeleteServiceData, DeleteServiceErrors, DeleteServiceResponses, DeleteSessionReplayData, DeleteSessionReplayErrors, DeleteSessionReplayResponses, DeleteSkillData, DeleteSkillErrors, DeleteSkillResponses, DeleteSourceMapData, DeleteSourceMapErrors, DeleteSourceMapResponses, DeleteStaticBundleData, DeleteStaticBundleErrors, DeleteStaticBundleResponses, DeleteTeamData, DeleteTeamErrors, DeleteTeamResponses, DeleteUserData, DeleteUserErrors, DeleteUserResponses, DeleteWebhookData, DeleteWebhookErrors, DeleteWebhookResponses, DeployFromImageData, DeployFromImageErrors, DeployFromImageResponses, DeployFromImageUploadData, DeployFromImageUploadErrors, DeployFromImageUploadResponses, DeployFromStaticData, DeployFromStaticErrors, DeployFromStaticResponses, DeployFromUploadedSourceData, DeployFromUploadedSourceErrors, DeployFromUploadedSourceResponses, DeploymentMetricsGetLatestData, DeploymentMetricsGetLatestErrors, DeploymentMetricsGetLatestResponses, DeploymentMetricsGetRangeData, DeploymentMetricsGetRangeErrors, DeploymentMetricsGetRangeResponses, DeploymentMetricsToggleData, DeploymentMetricsToggleErrors, DeploymentMetricsToggleResponses, DestroySandboxData, DestroySandboxErrors, DestroySandboxResponses, DetachScheduleServiceData, DetachScheduleServiceErrors, DetachScheduleServiceResponses, DetectPublicPresetsData, DetectPublicPresetsErrors, DetectPublicPresetsResponses, DisableBackupScheduleData, DisableBackupScheduleErrors, DisableBackupScheduleResponses, DisableMfaData, DisableMfaErrors, DisableMfaResponses, DiscoverWorkloadsData, DiscoverWorkloadsErrors, DiscoverWorkloadsResponses, DomainData, DomainErrors, DomainResponses, DownloadGlobalSkillArchiveData, DownloadGlobalSkillArchiveErrors, DownloadGlobalSkillArchiveResponses, DownloadObjectData, DownloadObjectErrors, DownloadObjectResponses, DownloadSkillArchiveData, DownloadSkillArchiveErrors, DownloadSkillArchiveResponses, EmailStatusData, EmailStatusErrors, EmailStatusResponses, EmbeddingsData, EmbeddingsErrors, EmbeddingsResponses, EnableBackupScheduleData, EnableBackupScheduleErrors, EnableBackupScheduleResponses, EnrichVisitorData, EnrichVisitorErrors, EnrichVisitorResponses, ExecData, ExecDetachedData, ExecDetachedErrors, ExecDetachedResponses, ExecErrors, ExecResponses, ExecuteDeploymentOperationData, ExecuteDeploymentOperationErrors, ExecuteDeploymentOperationResponses, ExecuteImportData, ExecuteImportErrors, ExecuteImportResponses, ExtendTimeoutData, ExtendTimeoutErrors, ExtendTimeoutResponses, ExternalServiceEnablePgStatStatementsData, ExternalServiceEnablePgStatStatementsErrors, ExternalServiceEnablePgStatStatementsResponses, ExternalServiceMetricsByDatabaseData, ExternalServiceMetricsByDatabaseErrors, ExternalServiceMetricsByDatabaseResponses, ExternalServiceMetricsCreateAlertRuleData, ExternalServiceMetricsCreateAlertRuleErrors, ExternalServiceMetricsCreateAlertRuleResponses, ExternalServiceMetricsDeleteAlertRuleData, ExternalServiceMetricsDeleteAlertRuleErrors, ExternalServiceMetricsDeleteAlertRuleResponses, ExternalServiceMetricsGetAlertRulesData, ExternalServiceMetricsGetAlertRulesErrors, ExternalServiceMetricsGetAlertRulesResponses, ExternalServiceMetricsGetLatestData, ExternalServiceMetricsGetLatestErrors, ExternalServiceMetricsGetLatestResponses, ExternalServiceMetricsGetRangeData, ExternalServiceMetricsGetRangeErrors, ExternalServiceMetricsGetRangeResponses, ExternalServiceMetricsStatusData, ExternalServiceMetricsStatusErrors, ExternalServiceMetricsStatusResponses, ExternalServiceMetricsToggleData, ExternalServiceMetricsToggleErrors, ExternalServiceMetricsToggleResponses, ExternalServiceMetricsUpdateAlertRuleData, ExternalServiceMetricsUpdateAlertRuleErrors, ExternalServiceMetricsUpdateAlertRuleResponses, ExternalServiceResetPgStatStatementsData, ExternalServiceResetPgStatStatementsErrors, ExternalServiceResetPgStatStatementsResponses, FinalizeOrderData, FinalizeOrderErrors, FinalizeOrderResponses, FinalizeProjectReleaseData, FinalizeProjectReleaseErrors, FinalizeProjectReleaseResponses, FindConversationData, FindConversationErrors, FindConversationResponses, GenerateJoinTokenData, GenerateJoinTokenErrors, GenerateJoinTokenResponses, GeneratePresetDockerfileData, GeneratePresetDockerfileErrors, GeneratePresetDockerfileResponses, GetAccessInfoData, GetAccessInfoErrors, GetAccessInfoResponses, GetActiveVisitorsData, GetActiveVisitorsErrors, GetActiveVisitorsResponses, GetActivityGraphData, GetActivityGraphErrors, GetActivityGraphResponses, GetAdminGateData, GetAdminGateErrors, GetAdminGateResponses, GetAgentData, GetAgentErrors, GetAgentResponses, GetAggregatedBucketsData, GetAggregatedBucketsErrors, GetAggregatedBucketsResponses, GetAiAgentBreakdownData, GetAiAgentBreakdownErrors, GetAiAgentBreakdownResponses, GetAiAgentPagesData, GetAiAgentPagesErrors, GetAiAgentPagesResponses, GetAiAgentTimelineData, GetAiAgentTimelineErrors, GetAiAgentTimelineResponses, GetAiPageBreakdownData, GetAiPageBreakdownErrors, GetAiPageBreakdownResponses, GetAiStatusBreakdownData, GetAiStatusBreakdownErrors, GetAiStatusBreakdownResponses, GetAlertData, GetAlertErrors, GetAlertResponses, GetAlertRuleData, GetAlertRuleErrors, GetAlertRuleResponses, GetAllRepositoriesByNameData, GetAllRepositoriesByNameErrors, GetAllRepositoriesByNameResponses, GetAnalyticsActiveVisitorsData, GetAnalyticsActiveVisitorsErrors, GetAnalyticsActiveVisitorsResponses, GetAnalyticsEventsCountData, GetAnalyticsEventsCountErrors, GetAnalyticsEventsCountResponses, GetAnalyticsSessionEventsData, GetAnalyticsSessionEventsErrors, GetAnalyticsSessionEventsResponses, GetAnalyticsVisitorSessionsData, GetAnalyticsVisitorSessionsErrors, GetAnalyticsVisitorSessionsResponses, GetApiKeyData, GetApiKeyErrors, GetApiKeyPermissionsData, GetApiKeyPermissionsErrors, GetApiKeyPermissionsResponses, GetApiKeyResponses, GetAuditLogData, GetAuditLogErrors, GetAuditLogResponses, GetBackupData, GetBackupErrors, GetBackupResponses, GetBackupScheduleData, GetBackupScheduleErrors, GetBackupScheduleResponses, GetBranchesByRepositoryIdData, GetBranchesByRepositoryIdErrors, GetBranchesByRepositoryIdResponses, GetBucketedIncidentsData, GetBucketedIncidentsErrors, GetBucketedIncidentsResponses, GetBucketedStatusData, GetBucketedStatusErrors, GetBucketedStatusResponses, GetChallengeTokenData, GetChallengeTokenErrors, GetChallengeTokenResponses, GetChatReadinessData, GetChatReadinessErrors, GetChatReadinessResponses, GetCliStatusData, GetCliStatusErrors, GetCliStatusResponses, GetClusterHealthData, GetClusterHealthErrors, GetClusterHealthResponses, GetClusterMemberData, GetClusterMemberErrors, GetClusterMemberResponses, GetCmdData, GetCmdErrors, GetCmdResponses, GetContainerDetailData, GetContainerDetailErrors, GetContainerDetailResponses, GetContainerEnvironmentVariableData, GetContainerEnvironmentVariableErrors, GetContainerEnvironmentVariableResponses, GetContainerInfoData, GetContainerInfoErrors, GetContainerInfoResponses, GetContainerLogsByIdData, GetContainerLogsByIdErrors, GetContainerLogsData, GetContainerLogsErrors, GetContainerMetricsData, GetContainerMetricsErrors, GetContainerMetricsResponses, GetConversationData, GetConversationDetailData, GetConversationDetailErrors, GetConversationDetailResponses, GetConversationErrors, GetConversationResponses, GetConversationsData, GetConversationsErrors, GetConversationsResponses, GetCronByIdData, GetCronByIdErrors, GetCronByIdResponses, GetCronExecutionsData, GetCronExecutionsErrors, GetCronExecutionsResponses, GetCrossProjectTraceSiblingsData, GetCrossProjectTraceSiblingsErrors, GetCrossProjectTraceSiblingsResponses, GetCurrentMonitorStatusData, GetCurrentMonitorStatusErrors, GetCurrentMonitorStatusResponses, GetCurrentUserData, GetCurrentUserErrors, GetCurrentUserResponses, GetCustomDomainData, GetCustomDomainErrors, GetCustomDomainResponses, GetDashboardData, GetDashboardErrors, GetDashboardProjectsAnalyticsData, GetDashboardProjectsAnalyticsErrors, GetDashboardProjectsAnalyticsResponses, GetDashboardResponses, GetDeliveryData, GetDeliveryErrors, GetDeliveryResponses, GetDeploymentContainerLogContentData, GetDeploymentContainerLogContentErrors, GetDeploymentContainerLogContentResponses, GetDeploymentData, GetDeploymentErrors, GetDeploymentJobLogsData, GetDeploymentJobLogsErrors, GetDeploymentJobLogsResponses, GetDeploymentJobsData, GetDeploymentJobsErrors, GetDeploymentJobsResponses, GetDeploymentOperationsData, GetDeploymentOperationsErrors, GetDeploymentOperationsResponses, GetDeploymentOperationStatusData, GetDeploymentOperationStatusErrors, GetDeploymentOperationStatusResponses, GetDeploymentResponses, GetDeploymentTokenData, GetDeploymentTokenErrors, GetDeploymentTokenResponses, GetDiskStatusData, GetDiskStatusErrors, GetDiskStatusResponses, GetDnsChangesData, GetDnsChangesErrors, GetDnsChangesResponses, GetDnsProviderData, GetDnsProviderErrors, GetDnsProviderResponses, GetDomainByHostData, GetDomainByHostErrors, GetDomainByHostResponses, GetDomainByIdData, GetDomainByIdErrors, GetDomainByIdResponses, GetDomainByNameData, GetDomainByNameErrors, GetDomainByNameResponses, GetDomainData, GetDomainDnsRecordsData, GetDomainDnsRecordsErrors, GetDomainDnsRecordsResponses, GetDomainErrors, GetDomainOrderData, GetDomainOrderErrors, GetDomainOrderResponses, GetDomainResponses, GetEmailData, GetEmailErrors, GetEmailEventsData, GetEmailEventsErrors, GetEmailEventsResponses, GetEmailLinksData, GetEmailLinksErrors, GetEmailLinksResponses, GetEmailProviderData, GetEmailProviderErrors, GetEmailProviderResponses, GetEmailResponses, GetEmailStatsData, GetEmailStatsErrors, GetEmailStatsResponses, GetEmailTrackingData, GetEmailTrackingErrors, GetEmailTrackingResponses, GetEmailTrackingStatusData, GetEmailTrackingStatusErrors, GetEmailTrackingStatusResponses, GetEntityInfoData, GetEntityInfoErrors, GetEntityInfoResponses, GetEnvironmentCronsData, GetEnvironmentCronsErrors, GetEnvironmentCronsResponses, GetEnvironmentData, GetEnvironmentDomainsData, GetEnvironmentDomainsErrors, GetEnvironmentDomainsResponses, GetEnvironmentErrors, GetEnvironmentResponses, GetEnvironmentsData, GetEnvironmentsErrors, GetEnvironmentsResponses, GetEnvironmentVariablesData, GetEnvironmentVariablesErrors, GetEnvironmentVariablesResponses, GetEnvironmentVariableValueData, GetEnvironmentVariableValueErrors, GetEnvironmentVariableValueResponses, GetErrorDashboardStatsData, GetErrorDashboardStatsErrors, GetErrorDashboardStatsResponses, GetErrorEventData, GetErrorEventErrors, GetErrorEventResponses, GetErrorGroupData, GetErrorGroupErrors, GetErrorGroupResponses, GetErrorStatsData, GetErrorStatsErrors, GetErrorStatsResponses, GetErrorTimeSeriesData, GetErrorTimeSeriesErrors, GetErrorTimeSeriesResponses, GetEventDetailData, GetEventDetailErrors, GetEventDetailResponses, GetEventEntriesData, GetEventEntriesErrors, GetEventEntriesResponses, GetEventsCountData, GetEventsCountErrors, GetEventsCountResponses, GetEventsTimelineData, GetEventsTimelineErrors, GetEventsTimelineResponses, GetEventTypeBreakdownData, GetEventTypeBreakdownErrors, GetEventTypeBreakdownResponses, GetEventVisitorsData, GetEventVisitorsErrors, GetEventVisitorsResponses, GetExternalImageData, GetExternalImageErrors, GetExternalImageResponses, GetFileData, GetFileErrors, GetFileResponses, GetFlagData, GetFlagErrors, GetFlagResponses, GetFlagSnapshotData, GetFlagSnapshotErrors, GetFlagSnapshotResponses, GetFunnelMetricsData, GetFunnelMetricsErrors, GetFunnelMetricsResponses, GetGenaiTraceData, GetGenaiTraceErrors, GetGenaiTraceResponses, GetGeneralStatsData, GetGeneralStatsErrors, GetGeneralStatsResponses, GetGitProviderData, GetGitProviderErrors, GetGitProviderResponses, GetGlobalEventsData, GetGlobalEventsErrors, GetGlobalEventsResponses, GetGlobalEventStatsData, GetGlobalEventStatsErrors, GetGlobalEventStatsResponses, GetGlobalMcpData, GetGlobalMcpErrors, GetGlobalMcpResponses, GetGlobalSandboxStatusData, GetGlobalSandboxStatusErrors, GetGlobalSandboxStatusResponses, GetGlobalSkillData, GetGlobalSkillErrors, GetGlobalSkillResponses, GetGroupedPageMetricsData, GetGroupedPageMetricsErrors, GetGroupedPageMetricsResponses, GetHealthData, GetHealthErrors, GetHealthResponses, GetHourlyVisitsData, GetHourlyVisitsErrors, GetHourlyVisitsResponses, GetHttpChallengeDebugData, GetHttpChallengeDebugErrors, GetHttpChallengeDebugResponses, GetImportStatusData, GetImportStatusErrors, GetImportStatusResponses, GetIncidentData, GetIncidentErrors, GetIncidentResponses, GetIncidentUpdatesData, GetIncidentUpdatesErrors, GetIncidentUpdatesResponses, GetIpAccessControlData, GetIpAccessControlErrors, GetIpAccessControlResponses, GetIpGeolocationData, GetIpGeolocationErrors, GetIpGeolocationResponses, GetJoinTokenStatusData, GetJoinTokenStatusErrors, GetJoinTokenStatusResponses, GetLastDeploymentData, GetLastDeploymentErrors, GetLastDeploymentResponses, GetLatestScanData, GetLatestScanErrors, GetLatestScanResponses, GetLatestScansPerEnvironmentData, GetLatestScansPerEnvironmentErrors, GetLatestScansPerEnvironmentResponses, GetLiveVisitorsListData, GetLiveVisitorsListErrors, GetLiveVisitorsListResponses, GetLogContextData, GetLogContextErrors, GetLogContextResponses, GetMcpData, GetMcpErrors, GetMcpResponses, GetMetricsOverTimeData, GetMetricsOverTimeErrors, GetMetricsOverTimeResponses, GetMonitorData, GetMonitorErrors, GetMonitorResponses, GetNotificationProviderData, GetNotificationProviderErrors, GetNotificationProviderResponses, GetOnDemandCertStatusData, GetOnDemandCertStatusErrors, GetOnDemandCertStatusResponses, GetOrCreateDsnData, GetOrCreateDsnErrors, GetOrCreateDsnResponses, GetPageFlowData, GetPageFlowErrors, GetPageFlowResponses, GetPageHourlySessionsData, GetPageHourlySessionsErrors, GetPageHourlySessionsResponses, GetPagePathDetailData, GetPagePathDetailErrors, GetPagePathDetailResponses, GetPagePathsData, GetPagePathsErrors, GetPagePathsResponses, GetPagePathsSparklinesData, GetPagePathsSparklinesErrors, GetPagePathsSparklinesResponses, GetPagePathVisitorsData, GetPagePathVisitorsErrors, GetPagePathVisitorsResponses, GetPendingActionData, GetPendingActionErrors, GetPendingActionResponses, GetPerformanceMetricsData, GetPerformanceMetricsErrors, GetPerformanceMetricsResponses, GetPgUpgradeData, GetPgUpgradeErrors, GetPgUpgradeLogsData, GetPgUpgradeLogsErrors, GetPgUpgradeLogsResponses, GetPgUpgradeResponses, GetPipelineStatsData, GetPipelineStatsErrors, GetPipelineStatsResponses, GetPlatformInfoData, GetPlatformInfoErrors, GetPlatformInfoResponses, GetPostgresWalHealthData, GetPostgresWalHealthErrors, GetPostgresWalHealthResponses, GetPreferencesData, GetPreferencesErrors, GetPreferencesResponses, GetPreviewGatewayLogsData, GetPreviewGatewayLogsResponses, GetPreviewGatewaySettingsData, GetPreviewGatewaySettingsResponses, GetPreviewGatewayStatusData, GetPreviewGatewayStatusResponses, GetPricingData, GetPricingErrors, GetPricingResponses, GetPrivateIpData, GetPrivateIpErrors, GetPrivateIpResponses, GetProjectAlarmsSummaryData, GetProjectAlarmsSummaryErrors, GetProjectAlarmsSummaryResponses, GetProjectBySlugData, GetProjectBySlugErrors, GetProjectBySlugResponses, GetProjectData, GetProjectDeploymentsData, GetProjectDeploymentsErrors, GetProjectDeploymentsResponses, GetProjectErrors, GetProjectResponses, GetProjectsData, GetProjectsErrors, GetProjectServiceEnvironmentVariablesData, GetProjectServiceEnvironmentVariablesErrors, GetProjectServiceEnvironmentVariablesResponses, GetProjectSessionReplaysData, GetProjectSessionReplaysErrors, GetProjectSessionReplaysResponses, GetProjectsHealthData, GetProjectsHealthErrors, GetProjectsHealthResponses, GetProjectsMonitorHealthData, GetProjectsMonitorHealthErrors, GetProjectsMonitorHealthResponses, GetProjectsResponses, GetProjectStatisticsData, GetProjectStatisticsErrors, GetProjectStatisticsResponses, GetProjectTemplateData, GetProjectTemplateErrors, GetProjectTemplateResponses, GetPropertyBreakdownData, GetPropertyBreakdownErrors, GetPropertyBreakdownResponses, GetPropertyTimelineData, GetPropertyTimelineErrors, GetPropertyTimelineResponses, GetProviderConnectionsData, GetProviderConnectionsErrors, GetProviderConnectionsResponses, GetProviderMetadataData, GetProviderMetadataErrors, GetProviderMetadataResponses, GetProvidersMetadataData, GetProvidersMetadataErrors, GetProvidersMetadataResponses, GetProxyLogByIdData, GetProxyLogByIdErrors, GetProxyLogByIdResponses, GetProxyLogByRequestIdData, GetProxyLogByRequestIdErrors, GetProxyLogByRequestIdResponses, GetProxyLogsData, GetProxyLogsErrors, GetProxyLogsResponses, GetPublicBranchesData, GetPublicBranchesErrors, GetPublicBranchesResponses, GetPublicIpData, GetPublicIpErrors, GetPublicIpResponses, GetPublicRepositoryData, GetPublicRepositoryErrors, GetPublicRepositoryResponses, GetQuotaData, GetQuotaErrors, GetQuotaResponses, GetRecentActivityData, GetRecentActivityErrors, GetRecentActivityResponses, GetRemoteExternalImageData, GetRemoteExternalImageErrors, GetRemoteExternalImageResponses, GetRepositoryBranchesData, GetRepositoryBranchesErrors, GetRepositoryBranchesResponses, GetRepositoryByIdData, GetRepositoryByIdErrors, GetRepositoryByIdResponses, GetRepositoryByNameData, GetRepositoryByNameErrors, GetRepositoryByNameResponses, GetRepositoryPresetByNameData, GetRepositoryPresetByNameErrors, GetRepositoryPresetByNameResponses, GetRepositoryPresetLiveData, GetRepositoryPresetLiveErrors, GetRepositoryPresetLiveResponses, GetRepositoryTagsData, GetRepositoryTagsErrors, GetRepositoryTagsResponses, GetResolvedEnvironmentVariablesData, GetResolvedEnvironmentVariablesErrors, GetResolvedEnvironmentVariablesResponses, GetResolvedEnvironmentVariableValueData, GetResolvedEnvironmentVariableValueErrors, GetResolvedEnvironmentVariableValueResponses, GetRestoreCapabilitiesData, GetRestoreCapabilitiesErrors, GetRestoreCapabilitiesResponses, GetRestoreRunData, GetRestoreRunErrors, GetRestoreRunResponses, GetRouteData, GetRouteErrors, GetRouteResponses, GetRunData, GetRunErrors, GetRunResponses, GetRunWithLogsData, GetRunWithLogsErrors, GetRunWithLogsResponses, GetS3CredentialsData, GetS3CredentialsErrors, GetS3CredentialsResponses, GetS3SourceData, GetS3SourceErrors, GetS3SourceResponses, GetSandboxData, GetSandboxErrors, GetSandboxResponses, GetSandboxStatusData, GetSandboxStatusErrors, GetSandboxStatusResponses, GetScanByDeploymentData, GetScanByDeploymentErrors, GetScanByDeploymentResponses, GetScanData, GetScanErrors, GetScanResponses, GetScanVulnerabilitiesData, GetScanVulnerabilitiesErrors, GetScanVulnerabilitiesResponses, GetServiceBySlugData, GetServiceBySlugErrors, GetServiceBySlugResponses, GetServiceData, GetServiceEnvironmentVariableData, GetServiceEnvironmentVariableErrors, GetServiceEnvironmentVariableResponses, GetServiceEnvironmentVariablesData, GetServiceEnvironmentVariablesErrors, GetServiceEnvironmentVariablesResponses, GetServiceErrors, GetServiceHealthStatusData, GetServiceHealthStatusErrors, GetServiceHealthStatusResponses, GetServicePreviewEnvironmentVariableNamesData, GetServicePreviewEnvironmentVariableNamesErrors, GetServicePreviewEnvironmentVariableNamesResponses, GetServicePreviewEnvironmentVariablesMaskedData, GetServicePreviewEnvironmentVariablesMaskedErrors, GetServicePreviewEnvironmentVariablesMaskedResponses, GetServiceResponses, GetServiceRuntimeData, GetServiceRuntimeErrors, GetServiceRuntimeResponses, GetServiceStatsData, GetServiceStatsErrors, GetServiceStatsResponses, GetServiceTypeParametersData, GetServiceTypeParametersErrors, GetServiceTypeParametersResponses, GetServiceTypesData, GetServiceTypesErrors, GetServiceTypesResponses, GetSessionDetailsData, GetSessionDetailsErrors, GetSessionDetailsResponses, GetSessionEventsData, GetSessionEventsErrors, GetSessionEventsResponses, GetSessionLogsData, GetSessionLogsErrors, GetSessionLogsResponses, GetSessionReplayData, GetSessionReplayErrors, GetSessionReplayEventsData, GetSessionReplayEventsErrors, GetSessionReplayEventsResponses, GetSessionReplayResponses, GetSettingsData, GetSettingsErrors, GetSettingsResponses, GetSkillData, GetSkillErrors, GetSkillResponses, GetSlowQueriesData, GetSlowQueriesErrors, GetSlowQueriesResponses, GetStaticBundleData, GetStaticBundleErrors, GetStaticBundleResponses, GetStatusOverviewData, GetStatusOverviewErrors, GetStatusOverviewResponses, GetTagsByRepositoryIdData, GetTagsByRepositoryIdErrors, GetTagsByRepositoryIdResponses, GetTeamData, GetTeamErrors, GetTeamResponses, GetTimeBucketStatsData, GetTimeBucketStatsErrors, GetTimeBucketStatsResponses, GetTodayStatsData, GetTodayStatsErrors, GetTodayStatsResponses, GetTraceData, GetTraceErrors, GetTraceResponses, GetUnifiedTraceData, GetUnifiedTraceErrors, GetUnifiedTraceResponses, GetUniqueCountsData, GetUniqueCountsErrors, GetUniqueCountsResponses, GetUniqueEventsData, GetUniqueEventsErrors, GetUniqueEventsResponses, GetUpdateCapabilityData, GetUpdateCapabilityErrors, GetUpdateCapabilityResponses, GetUpdateStatusData, GetUpdateStatusErrors, GetUpdateStatusResponses, GetUptimeHistoryData, GetUptimeHistoryErrors, GetUptimeHistoryResponses, GetUsageByProviderData, GetUsageByProviderErrors, GetUsageByProviderResponses, GetUsageRecentData, GetUsageRecentErrors, GetUsageRecentResponses, GetUsageSummaryData, GetUsageSummaryErrors, GetUsageSummaryResponses, GetUsageTimeseriesData, GetUsageTimeseriesErrors, GetUsageTimeseriesResponses, GetUsageTopModelsData, GetUsageTopModelsErrors, GetUsageTopModelsResponses, GetVisitorByGuidData, GetVisitorByGuidErrors, GetVisitorByGuidResponses, GetVisitorByIdData, GetVisitorByIdErrors, GetVisitorByIdResponses, GetVisitorDetailsData, GetVisitorDetailsErrors, GetVisitorDetailsResponses, GetVisitorFacetsData, GetVisitorFacetsErrors, GetVisitorFacetsResponses, GetVisitorInfoData, GetVisitorInfoErrors, GetVisitorInfoResponses, GetVisitorJourneyData, GetVisitorJourneyErrors, GetVisitorJourneyResponses, GetVisitorsData, GetVisitorsErrors, GetVisitorSessionsData, GetVisitorSessionsErrors, GetVisitorSessionsResponses, GetVisitorsResponses, GetVisitorStatsData, GetVisitorStatsErrors, GetVisitorStatsResponses, GetWebhookData, GetWebhookErrors, GetWebhookResponses, GrantProjectAccessData, GrantProjectAccessErrors, GrantProjectAccessResponses, HandleGitProviderOauthCallbackData, HandleGitProviderOauthCallbackErrors, HasAnalyticsEventsData, HasAnalyticsEventsErrors, HasAnalyticsEventsResponses, HasErrorGroupsData, HasErrorGroupsErrors, HasErrorGroupsResponses, HasPerformanceMetricsData, HasPerformanceMetricsErrors, HasPerformanceMetricsResponses, ImportExternalServiceData, ImportExternalServiceErrors, ImportExternalServiceResponses, IngestLogsByPathData, IngestLogsByPathErrors, IngestLogsByPathResponses, IngestLogsData, IngestLogsErrors, IngestLogsResponses, IngestMetricsByPathData, IngestMetricsByPathErrors, IngestMetricsByPathResponses, IngestMetricsData, IngestMetricsErrors, IngestMetricsResponses, IngestSentryEnvelopeData, IngestSentryEnvelopeErrors, IngestSentryEnvelopeResponses, IngestSentryEventData, IngestSentryEventErrors, IngestSentryEventResponses, IngestTracesByPathData, IngestTracesByPathErrors, IngestTracesByPathResponses, IngestTracesData, IngestTracesErrors, IngestTracesResponses, InitSessionReplayData, InitSessionReplayErrors, InitSessionReplayResponses, InspectDropArchiveData, InspectDropArchiveErrors, InspectDropArchiveResponses, JobLogsData, JobLogsErrors, JobLogsResponses, JobStatusData, JobStatusErrors, JobStatusResponses, KillJobData, KillJobErrors, KillJobResponses, KvDelData, KvDelErrors, KvDelResponses, KvDisableData, KvDisableErrors, KvDisableResponses, KvEnableData, KvEnableErrors, KvEnableResponses, KvExpireData, KvExpireErrors, KvExpireResponses, KvGetData, KvGetErrors, KvGetResponses, KvIncrData, KvIncrErrors, KvIncrResponses, KvKeysData, KvKeysErrors, KvKeysResponses, KvSetData, KvSetErrors, KvSetResponses, KvStatusData, KvStatusErrors, KvStatusResponses, KvTtlData, KvTtlErrors, KvTtlResponses, KvUpdateData, KvUpdateErrors, KvUpdateResponses, LatestRunForSourceData, LatestRunForSourceErrors, LatestRunForSourceResponses, LinkCustomDomainToCertificateData, LinkCustomDomainToCertificateErrors, LinkCustomDomainToCertificateResponses, LinkServiceToProjectData, LinkServiceToProjectErrors, LinkServiceToProjectResponses, ListAgentRunsData, ListAgentRunsErrors, ListAgentRunsResponses, ListAgentsData, ListAgentsErrors, ListAgentsResponses, ListAiProvidersData, ListAiProvidersErrors, ListAiProvidersResponses, ListAlertRulesData, ListAlertRulesErrors, ListAlertRulesResponses, ListAlertsData, ListAlertsErrors, ListAlertsResponses, ListAllConversationsData, ListAllConversationsErrors, ListAllConversationsResponses, ListAllRunsData, ListAllRunsErrors, ListAllRunsResponses, ListApiKeysData, ListApiKeysErrors, ListApiKeysResponses, ListAuditLogsData, ListAuditLogsErrors, ListAuditLogsResponses, ListAvailableContainersData, ListAvailableContainersErrors, ListAvailableContainersResponses, ListBackupAlertsData, ListBackupAlertsErrors, ListBackupAlertsResponses, ListBackupChildrenData, ListBackupChildrenErrors, ListBackupChildrenResponses, ListBackupSchedulesData, ListBackupSchedulesErrors, ListBackupSchedulesResponses, ListBackupsForScheduleData, ListBackupsForScheduleErrors, ListBackupsForScheduleResponses, ListCommitsByRepositoryIdData, ListCommitsByRepositoryIdErrors, ListCommitsByRepositoryIdResponses, ListConnectionsData, ListConnectionsErrors, ListConnectionsResponses, ListContainersAtPathData, ListContainersAtPathErrors, ListContainersAtPathResponses, ListContainersData, ListContainersErrors, ListContainersResponses, ListConversationsData, ListConversationsErrors, ListConversationsResponses, ListCustomDomainsForProjectData, ListCustomDomainsForProjectErrors, ListCustomDomainsForProjectResponses, ListDashboardsData, ListDashboardsErrors, ListDashboardsResponses, ListDeliveriesData, ListDeliveriesErrors, ListDeliveriesResponses, ListDeploymentContainerLogsData, ListDeploymentContainerLogsErrors, ListDeploymentContainerLogsResponses, ListDeploymentTokensData, ListDeploymentTokensErrors, ListDeploymentTokensResponses, ListDnsProvidersData, ListDnsProvidersErrors, ListDnsProvidersResponses, ListDomainsData, ListDomainsErrors, ListDomainsResponses, ListDsnsData, ListDsnsErrors, ListDsnsResponses, ListEmailDomainsData, ListEmailDomainsErrors, ListEmailDomainsResponses, ListEmailProvidersData, ListEmailProvidersErrors, ListEmailProvidersResponses, ListEmailsData, ListEmailsErrors, ListEmailsResponses, ListEnrollmentTokensData, ListEnrollmentTokensErrors, ListEnrollmentTokensResponses, ListEntitiesData, ListEntitiesErrors, ListEntitiesResponses, ListErrorEventsData, ListErrorEventsErrors, ListErrorEventsResponses, ListErrorGroupsData, ListErrorGroupsErrors, ListErrorGroupsResponses, ListEventsData, ListEventsResponses, ListEventTypesData, ListEventTypesResponses, ListExternalImagesData, ListExternalImagesErrors, ListExternalImagesResponses, ListExternalPluginsData, ListExternalPluginsErrors, ListExternalPluginsResponses, ListExternalServiceBackupsData, ListExternalServiceBackupsErrors, ListExternalServiceBackupsResponses, ListFlagsData, ListFlagsErrors, ListFlagsResponses, ListFunnelsData, ListFunnelsErrors, ListFunnelsResponses, ListGitProvidersData, ListGitProvidersErrors, ListGitProvidersResponses, ListGlobalMcpsData, ListGlobalMcpsErrors, ListGlobalMcpsResponses, ListGlobalSkillsData, ListGlobalSkillsErrors, ListGlobalSkillsResponses, ListIncidentsData, ListIncidentsErrors, ListIncidentsResponses, ListInsightsData, ListInsightsErrors, ListInsightsResponses, ListIpAccessControlData, ListIpAccessControlErrors, ListIpAccessControlResponses, ListJobsData, ListJobsErrors, ListJobsResponses, ListKnownAiAgentsData, ListKnownAiAgentsErrors, ListKnownAiAgentsResponses, ListManagedDomainsData, ListManagedDomainsErrors, ListManagedDomainsResponses, ListMcpsData, ListMcpsErrors, ListMcpsResponses, ListMetricLabelKeysData, ListMetricLabelKeysErrors, ListMetricLabelKeysResponses, ListMetricLabelValuesData, ListMetricLabelValuesErrors, ListMetricLabelValuesResponses, ListMetricNamesData, ListMetricNamesErrors, ListMetricNamesResponses, ListModelsData, ListModelsErrors, ListModelsResponses, ListMonitorsData, ListMonitorsErrors, ListMonitorsResponses, ListNotificationProvidersData, ListNotificationProvidersErrors, ListNotificationProvidersResponses, ListOidcProvidersData, ListOidcProvidersResponses, ListOidcProviderUsersData, ListOidcProviderUsersErrors, ListOidcProviderUsersResponses, ListOidcRoleMappingsData, ListOidcRoleMappingsResponses, ListOnDemandCertsData, ListOnDemandCertsErrors, ListOnDemandCertsResponses, ListOrdersData, ListOrdersErrors, ListOrdersResponses, ListPeersData, ListPeersErrors, ListPeersResponses, ListPendingActionsData, ListPendingActionsErrors, ListPendingActionsResponses, ListPgUpgradesData, ListPgUpgradesErrors, ListPgUpgradesResponses, ListPresetsData, ListPresetsErrors, ListPresetsResponses, ListProjectAccessData, ListProjectAccessErrors, ListProjectAccessResponses, ListProjectAlarmsData, ListProjectAlarmsErrors, ListProjectAlarmsResponses, ListProjectScansData, ListProjectScansErrors, ListProjectScansResponses, ListProjectSecretsData, ListProjectSecretsErrors, ListProjectSecretsResponses, ListProjectServicesData, ListProjectServicesErrors, ListProjectServicesResponses, ListProjectTemplatesData, ListProjectTemplatesErrors, ListProjectTemplatesResponses, ListProjectTemplateTagsData, ListProjectTemplateTagsErrors, ListProjectTemplateTagsResponses, ListProviderKeysData, ListProviderKeysErrors, ListProviderKeysResponses, ListProviderZonesData, ListProviderZonesErrors, ListProviderZonesResponses, ListPublicProvidersData, ListPublicProvidersResponses, ListReleaseFilesData, ListReleaseFilesErrors, ListReleaseFilesResponses, ListReleasesData, ListReleasesErrors, ListReleasesResponses, ListRemoteExternalImagesData, ListRemoteExternalImagesErrors, ListRemoteExternalImagesResponses, ListRepositoriesByConnectionData, ListRepositoriesByConnectionErrors, ListRepositoriesByConnectionResponses, ListRepositoriesByProviderData, ListRepositoriesByProviderErrors, ListRepositoriesByProviderResponses, ListRestoreRunsForServiceData, ListRestoreRunsForServiceResponses, ListRootContainersData, ListRootContainersErrors, ListRootContainersResponses, ListRoutesData, ListRoutesErrors, ListRoutesResponses, ListS3SourcesData, ListS3SourcesErrors, ListS3SourcesResponses, ListSandboxesData, ListSandboxesResponses, ListScheduleRunJobsData, ListScheduleRunJobsErrors, ListScheduleRunJobsResponses, ListScheduleRunsData, ListScheduleRunsErrors, ListScheduleRunsResponses, ListScheduleServicesData, ListScheduleServicesErrors, ListScheduleServicesResponses, ListSecretsData, ListSecretsErrors, ListSecretsResponses, ListServiceHealthStatusesData, ListServiceHealthStatusesErrors, ListServiceHealthStatusesResponses, ListServiceProjectsData, ListServiceProjectsErrors, ListServiceProjectsResponses, ListServiceSchedulesData, ListServiceSchedulesErrors, ListServiceSchedulesResponses, ListServicesData, ListServicesErrors, ListServicesResponses, ListSkillsData, ListSkillsErrors, ListSkillsResponses, ListSourceBackupsData, ListSourceBackupsErrors, ListSourceBackupsResponses, ListSourceFilesData, ListSourceFilesErrors, ListSourceFilesResponses, ListSourceMapsData, ListSourceMapsErrors, ListSourceMapsResponses, ListSourcesData, ListSourcesErrors, ListSourcesResponses, ListStaticBundlesData, ListStaticBundlesErrors, ListStaticBundlesResponses, ListSyncedRepositoriesData, ListSyncedRepositoriesErrors, ListSyncedRepositoriesResponses, ListTeamMembersData, ListTeamMembersErrors, ListTeamMembersResponses, ListTeamProjectsData, ListTeamProjectsErrors, ListTeamProjectsResponses, ListTeamsData, ListTeamsErrors, ListTeamsResponses, ListUsersData, ListUsersErrors, ListUsersResponses, ListWebhooksData, ListWebhooksErrors, ListWebhooksResponses, LoginData, LoginErrors, LoginResponses, LogoutData, LogoutErrors, LogoutResponses, LookupDnsARecordsData, LookupDnsARecordsErrors, LookupDnsARecordsResponses, MintEnrollmentTokenData, MintEnrollmentTokenErrors, MintEnrollmentTokenResponses, MkdirData, MkdirErrors, MkdirResponses, NodeHeartbeatData, NodeHeartbeatErrors, NodeHeartbeatResponses, NodeMetricsGetRangeData, NodeMetricsGetRangeErrors, NodeMetricsGetRangeResponses, ObservabilityFullEventData, ObservabilityFullEventErrors, ObservabilityFullEventResponses, ObservabilityListEventsData, ObservabilityListEventsErrors, ObservabilityListEventsResponses, OidcCallbackData, PatchAdminGateData, PatchAdminGateErrors, PatchAdminGateResponses, PatchPreviewGatewaySettingsData, PatchPreviewGatewaySettingsResponses, PauseDeploymentData, PauseDeploymentErrors, PauseDeploymentResponses, PauseSandboxData, PauseSandboxErrors, PauseSandboxResponses, PlanRestoreData, PlanRestoreErrors, PlanRestoreResponses, PostDnsAckData, PostDnsAckErrors, PostDnsAckResponses, PreviewAlertData, PreviewAlertErrors, PreviewAlertResponses, PreviewFunnelMetricsData, PreviewFunnelMetricsErrors, PreviewFunnelMetricsResponses, PreviewHostnameModeData, PreviewHostnameModeErrors, PreviewHostnameModeResponses, PromoteClusterMemberData, PromoteClusterMemberErrors, PromoteClusterMemberResponses, PromoteDeploymentData, PromoteDeploymentErrors, PromoteDeploymentResponses, ProvisionDomainData, ProvisionDomainErrors, ProvisionDomainResponses, PurgeProjectLogsData, PurgeProjectLogsErrors, PurgeProjectLogsResponses, PushExternalImageData, PushExternalImageErrors, PushExternalImageResponses, QueryDataData, QueryDataErrors, QueryDataResponses, QueryGenaiTracesData, QueryGenaiTracesErrors, QueryGenaiTracesResponses, QueryLogsData, QueryLogsErrors, QueryLogsResponses, QueryMetricsData, QueryMetricsErrors, QueryMetricsResponses, QueryTracesData, QueryTracesErrors, QueryTracesResponses, QueryTraceSummariesData, QueryTraceSummariesErrors, QueryTraceSummariesResponses, ReadFileData, ReadFileErrors, ReadFileResponses, ReAnalyzeData, ReAnalyzeErrors, ReAnalyzeResponses, RecordConsoleEventData, RecordConsoleEventErrors, RecordConsoleEventResponses, RecordEventMetricsData, RecordEventMetricsErrors, RecordEventMetricsResponses, RecordFlagExposureData, RecordFlagExposureErrors, RecordFlagExposureResponses, RecordSpeedMetricsData, RecordSpeedMetricsErrors, RecordSpeedMetricsResponses, RefreshRouteTableData, RefreshRouteTableErrors, RefreshRouteTableResponses, RegenerateDsnData, RegenerateDsnErrors, RegenerateDsnResponses, RegisterExternalImageData, RegisterExternalImageErrors, RegisterExternalImageResponses, RegisterNodeData, RegisterNodeErrors, RegisterNodeResponses, ReinstallGitlabWebhookData, ReinstallGitlabWebhookErrors, ReinstallGitlabWebhookResponses, RejectPendingActionData, RejectPendingActionErrors, RejectPendingActionResponses, ReloadPluginsData, ReloadPluginsErrors, ReloadPluginsResponses, RemoveClusterMemberData, RemoveClusterMemberErrors, RemoveClusterMemberResponses, RemoveManagedDomainData, RemoveManagedDomainErrors, RemoveManagedDomainResponses, RemoveRoleData, RemoveRoleErrors, RemoveRoleResponses, RemoveTeamMemberData, RemoveTeamMemberErrors, RemoveTeamMemberResponses, RenameConversationData, RenameConversationErrors, RenameConversationResponses, RenewDomainData, RenewDomainErrors, RenewDomainResponses, RequestPasswordResetData, RequestPasswordResetErrors, RequestPasswordResetResponses, ResetPasswordData, ResetPasswordErrors, ResetPasswordResponses, ResizeSandboxData, ResizeSandboxErrors, ResizeSandboxResponses, ResolveAlarmData, ResolveAlarmErrors, ResolveAlarmResponses, RestartContainerData, RestartContainerErrors, RestartContainerResponses, RestartPreviewGatewayData, RestartPreviewGatewayResponses, RestartSandboxData, RestartSandboxErrors, RestartSandboxResponses, RestoreFlagData, RestoreFlagErrors, RestoreFlagResponses, RestoreUserData, RestoreUserErrors, RestoreUserResponses, ResumeDeploymentData, ResumeDeploymentErrors, ResumeDeploymentResponses, ResumeSandboxData, ResumeSandboxErrors, ResumeSandboxResponses, RetryClusterData, RetryClusterErrors, RetryClusterResponses, RetryDeliveryData, RetryDeliveryErrors, RetryDeliveryResponses, RetryPgUpgradeData, RetryPgUpgradeErrors, RetryPgUpgradeResponses, RetryRunData, RetryRunErrors, RetryRunResponses, RevealGlobalMcpConfigData, RevealGlobalMcpConfigErrors, RevealGlobalMcpConfigResponses, RevealMcpConfigData, RevealMcpConfigErrors, RevealMcpConfigResponses, RevealNotificationProviderConfigData, RevealNotificationProviderConfigErrors, RevealNotificationProviderConfigResponses, RevealServiceParameterData, RevealServiceParameterErrors, RevealServiceParameterResponses, RevenueCreateIntegrationData, RevenueCreateIntegrationErrors, RevenueCreateIntegrationResponses, RevenueDeleteIntegrationData, RevenueDeleteIntegrationResponses, RevenueGlobalEventsData, RevenueGlobalEventsResponses, RevenueImportInvoicesCsvData, RevenueImportInvoicesCsvErrors, RevenueImportInvoicesCsvResponses, RevenueImportSubscriptionsCsvData, RevenueImportSubscriptionsCsvErrors, RevenueImportSubscriptionsCsvResponses, RevenueListIntegrationsData, RevenueListIntegrationsResponses, RevenueListProvidersData, RevenueListProvidersResponses, RevenueMetricsCustomersData, RevenueMetricsCustomersResponses, RevenueMetricsGlobalMrrData, RevenueMetricsGlobalMrrResponses, RevenueMetricsGlobalSummaryData, RevenueMetricsGlobalSummaryResponses, RevenueMetricsMrrData, RevenueMetricsMrrResponses, RevenueMetricsSummaryData, RevenueMetricsSummaryResponses, RevenueRecentEventsData, RevenueRecentEventsResponses, RevenueRotateTokenData, RevenueRotateTokenResponses, RevenueUpdateConfigData, RevenueUpdateConfigErrors, RevenueUpdateConfigResponses, RevenueUpdateSecretData, RevenueUpdateSecretErrors, RevenueUpdateSecretResponses, RevokeDsnData, RevokeDsnErrors, RevokeDsnResponses, RevokeEnrollmentTokenData, RevokeEnrollmentTokenErrors, RevokeEnrollmentTokenResponses, RevokeJoinTokenData, RevokeJoinTokenErrors, RevokeJoinTokenResponses, RevokeProjectAccessData, RevokeProjectAccessErrors, RevokeProjectAccessResponses, RollbackPgUpgradeData, RollbackPgUpgradeErrors, RollbackPgUpgradeResponses, RollbackToDeploymentData, RollbackToDeploymentErrors, RollbackToDeploymentResponses, RootfsGcData, RootfsGcResponses, RootfsReportData, RootfsReportResponses, RotateApiKeyData, RotateApiKeyErrors, RotateApiKeyResponses, RotateDeploymentTokenData, RotateDeploymentTokenErrors, RotateDeploymentTokenResponses, RunBackupForSourceData, RunBackupForSourceErrors, RunBackupForSourceResponses, RunConnectionHealthCheckData, RunConnectionHealthCheckErrors, RunConnectionHealthCheckResponses, RunExternalServiceBackupData, RunExternalServiceBackupErrors, RunExternalServiceBackupResponses, RunScheduleNowData, RunScheduleNowErrors, RunScheduleNowResponses, SandboxCreatePreviewLinkData, SandboxCreatePreviewLinkErrors, SandboxCreatePreviewLinkResponses, SaveAgentTokenData, SaveAgentTokenErrors, SaveAgentTokenResponses, SaveAiProviderCredentialData, SaveAiProviderCredentialErrors, SaveAiProviderCredentialResponses, SearchLogsData, SearchLogsErrors, SearchLogsResponses, SendEmailData, SendEmailErrors, SendEmailResponses, SetDefaultS3SourceData, SetDefaultS3SourceErrors, SetDefaultS3SourceResponses, SetFlagEnvironmentData, SetFlagEnvironmentErrors, SetFlagEnvironmentResponses, SetPreviewPasswordData, SetPreviewPasswordErrors, SetPreviewPasswordResponses, SetupDnsChallengeData, SetupDnsChallengeErrors, SetupDnsChallengeResponses, SetupDnsData, SetupDnsErrors, SetupDnsResponses, SetupEmailTrackingData, SetupEmailTrackingErrors, SetupEmailTrackingResponses, SetupMfaData, SetupMfaErrors, SetupMfaResponses, SleepEnvironmentData, SleepEnvironmentErrors, SleepEnvironmentResponses, SmokeTestAgentData, SmokeTestAgentErrors, SmokeTestAgentResponses, SourceSandboxData, SourceSandboxErrors, SourceSandboxResponses, StartAnalysisData, StartAnalysisErrors, StartAnalysisResponses, StartContainerData, StartContainerErrors, StartContainerResponses, StartFixData, StartFixErrors, StartFixResponses, StartGitProviderOauthData, StartGitProviderOauthErrors, StartOidcLoginBySlugData, StartOidcLoginBySlugErrors, StartPgUpgradeData, StartPgUpgradeErrors, StartPgUpgradeResponses, StartRestoreData, StartRestoreErrors, StartRestoreResponses, StartServiceData, StartServiceErrors, StartServiceResponses, StartUpdateData, StartUpdateErrors, StartUpdateResponses, StatPathData, StatPathErrors, StatPathResponses, StopContainerData, StopContainerErrors, StopContainerResponses, StopSandboxData, StopSandboxErrors, StopSandboxResponses, StopServiceData, StopServiceErrors, StopServiceResponses, StreamContainerMetricsData, StreamContainerMetricsErrors, StreamContainerMetricsResponses, StreamEventsData, StreamEventsErrors, StreamEventsResponses, StreamRunEventsData, StreamRunEventsErrors, StreamRunEventsResponses, SyncRepositoriesData, SyncRepositoriesErrors, SyncRepositoriesResponses, TailDeploymentJobLogsData, TailDeploymentJobLogsErrors, TailLogsData, TailLogsErrors, TailLogsResponses, TeardownDeploymentData, TeardownDeploymentErrors, TeardownDeploymentResponses, TeardownEnvironmentData, TeardownEnvironmentErrors, TeardownEnvironmentResponses, TestNotificationProviderData, TestNotificationProviderErrors, TestNotificationProviderResponses, TestOidcProviderData, TestOidcProviderResponses, TestProviderConnectionData, TestProviderConnectionErrors, TestProviderConnectionResponses, TestProviderData, TestProviderErrors, TestProviderKeyByIdData, TestProviderKeyByIdErrors, TestProviderKeyByIdResponses, TestProviderKeyInlineData, TestProviderKeyInlineErrors, TestProviderKeyInlineResponses, TestProviderResponses, TestS3ConnectionPreviewData, TestS3ConnectionPreviewErrors, TestS3ConnectionPreviewResponses, TestS3SourceConnectionData, TestS3SourceConnectionErrors, TestS3SourceConnectionResponses, TrackClickData, TrackClickErrors, TrackOpenData, TrackOpenErrors, TrackOpenResponses, TriggerAgentData, TriggerAgentErrors, TriggerAgentResponses, TriggerProjectPipelineData, TriggerProjectPipelineErrors, TriggerProjectPipelineResponses, TriggerScanData, TriggerScanErrors, TriggerScanResponses, TriggerServiceHealthCheckData, TriggerServiceHealthCheckErrors, TriggerServiceHealthCheckResponses, TriggerWeeklyDigestData, TriggerWeeklyDigestErrors, TriggerWeeklyDigestResponses, UnlinkServiceFromProjectData, UnlinkServiceFromProjectErrors, UnlinkServiceFromProjectResponses, UpdateAgentData, UpdateAgentErrors, UpdateAgentResponses, UpdateAiProviderData, UpdateAiProviderErrors, UpdateAiProviderResponses, UpdateAlertData, UpdateAlertErrors, UpdateAlertResponses, UpdateAlertRuleData, UpdateAlertRuleErrors, UpdateAlertRuleResponses, UpdateApiKeyData, UpdateApiKeyErrors, UpdateApiKeyResponses, UpdateAutomaticDeployData, UpdateAutomaticDeployErrors, UpdateAutomaticDeployResponses, UpdateBackupScheduleData, UpdateBackupScheduleErrors, UpdateBackupScheduleResponses, UpdateCloudflareProviderData, UpdateCloudflareProviderErrors, UpdateCloudflareProviderResponses, UpdateConnectionTokenData, UpdateConnectionTokenErrors, UpdateConnectionTokenResponses, UpdateCustomDomainData, UpdateCustomDomainErrors, UpdateCustomDomainResponses, UpdateDashboardData, UpdateDashboardErrors, UpdateDashboardResponses, UpdateDeploymentTokenData, UpdateDeploymentTokenErrors, UpdateDeploymentTokenResponses, UpdateEmailProviderData, UpdateEmailProviderErrors, UpdateEmailProviderResponses, UpdateEnvironmentSettingsData, UpdateEnvironmentSettingsErrors, UpdateEnvironmentSettingsResponses, UpdateEnvironmentSubdomainData, UpdateEnvironmentSubdomainErrors, UpdateEnvironmentSubdomainResponses, UpdateEnvironmentVariableData, UpdateEnvironmentVariableErrors, UpdateEnvironmentVariableResponses, UpdateErrorGroupData, UpdateErrorGroupErrors, UpdateErrorGroupResponses, UpdateFlagData, UpdateFlagErrors, UpdateFlagResponses, UpdateFunnelData, UpdateFunnelErrors, UpdateFunnelResponses, UpdateGitProviderCredentialsData, UpdateGitProviderCredentialsErrors, UpdateGitProviderCredentialsResponses, UpdateGitSettingsData, UpdateGitSettingsErrors, UpdateGitSettingsResponses, UpdateGlobalMcpData, UpdateGlobalMcpErrors, UpdateGlobalMcpResponses, UpdateGlobalSkillData, UpdateGlobalSkillErrors, UpdateGlobalSkillResponses, UpdateIncidentStatusData, UpdateIncidentStatusErrors, UpdateIncidentStatusResponses, UpdateIpAccessControlData, UpdateIpAccessControlErrors, UpdateIpAccessControlResponses, UpdateManagedDomainData, UpdateManagedDomainErrors, UpdateManagedDomainResponses, UpdateMcpData, UpdateMcpErrors, UpdateMcpResponses, UpdateNotificationEmailProviderData, UpdateNotificationEmailProviderErrors, UpdateNotificationEmailProviderResponses, UpdateNotificationProviderData, UpdateNotificationProviderErrors, UpdateNotificationProviderResponses, UpdateOidcProviderData, UpdateOidcProviderResponses, UpdatePreferencesData, UpdatePreferencesErrors, UpdatePreferencesResponses, UpdateProjectData, UpdateProjectDeploymentConfigData, UpdateProjectDeploymentConfigErrors, UpdateProjectDeploymentConfigResponses, UpdateProjectErrors, UpdateProjectResponses, UpdateProjectSecretData, UpdateProjectSecretErrors, UpdateProjectSecretResponses, UpdateProjectSettingsData, UpdateProjectSettingsErrors, UpdateProjectSettingsResponses, UpdateProviderData, UpdateProviderErrors, UpdateProviderKeyData, UpdateProviderKeyErrors, UpdateProviderKeyResponses, UpdateProviderResponses, UpdateRouteData, UpdateRouteErrors, UpdateRouteResponses, UpdateS3SourceData, UpdateS3SourceErrors, UpdateS3SourceResponses, UpdateSelfData, UpdateSelfErrors, UpdateSelfResponses, UpdateServiceData, UpdateServiceErrors, UpdateServiceResourcesData, UpdateServiceResourcesErrors, UpdateServiceResourcesResponses, UpdateServiceResponses, UpdateSessionDurationData, UpdateSessionDurationErrors, UpdateSessionDurationResponses, UpdateSettingsData, UpdateSettingsErrors, UpdateSettingsResponses, UpdateSkillData, UpdateSkillErrors, UpdateSkillResponses, UpdateSlackProviderData, UpdateSlackProviderErrors, UpdateSlackProviderResponses, UpdateSpeedMetricsData, UpdateSpeedMetricsErrors, UpdateSpeedMetricsResponses, UpdateTeamData, UpdateTeamErrors, UpdateTeamMemberRoleData, UpdateTeamMemberRoleErrors, UpdateTeamMemberRoleResponses, UpdateTeamResponses, UpdateUserData, UpdateUserErrors, UpdateUserResponses, UpdateWebhookData, UpdateWebhookErrors, UpdateWebhookProviderData, UpdateWebhookProviderErrors, UpdateWebhookProviderResponses, UpdateWebhookResponses, UpgradePreviewGatewayData, UpgradePreviewGatewayResponses, UpgradeServiceData, UpgradeServiceErrors, UpgradeServiceResponses, UploadGlobalSkillData, UploadGlobalSkillErrors, UploadGlobalSkillResponses, UploadReleaseFileData, UploadReleaseFileErrors, UploadReleaseFileResponses, UploadSkillData, UploadSkillErrors, UploadSkillResponses, UploadSourceFileData, UploadSourceFileErrors, UploadSourceFileResponses, UploadSourceMapData, UploadSourceMapErrors, UploadSourceMapResponses, UploadStaticBundleData, UploadStaticBundleErrors, UploadStaticBundleResponses, UpsertSecretData, UpsertSecretErrors, UpsertSecretResponses, ValidateConnectionData, ValidateConnectionErrors, ValidateConnectionResponses, ValidateEmailData, ValidateEmailErrors, ValidateEmailResponses, VerifyAndEnableMfaData, VerifyAndEnableMfaErrors, VerifyAndEnableMfaResponses, VerifyDomainData, VerifyDomainErrors, VerifyDomainResponses, VerifyEmailData, VerifyEmailErrors, VerifyEmailResponses, VerifyManagedDomainData, VerifyManagedDomainErrors, VerifyManagedDomainResponses, VerifyMfaChallengeData, VerifyMfaChallengeErrors, VerifyMfaChallengeResponses, VerifyStepUpData, VerifyStepUpErrors, VerifyStepUpResponses, WakeEnvironmentData, WakeEnvironmentErrors, WakeEnvironmentResponses, WebhookTriggerData, WebhookTriggerErrors, WebhookTriggerResponses, WorkflowDryRunData, WorkflowDryRunErrors, WorkflowDryRunResponses, WriteFileData, WriteFileErrors, WriteFileResponses, WriteFilesData, WriteFilesErrors, WriteFilesResponses } from './types.gen'; export type Options = Options2 & { /** @@ -7253,6 +7253,16 @@ export const getUpdateStatus = (options?: ...options }); +/** + * Ask the release API for the newest version on this install's channel, now, + * instead of waiting for the background notifier's next pass. + */ +export const checkForUpdate = (options?: Options): RequestResult => (options?.client ?? client).post({ + security: [{ scheme: 'bearer', type: 'http' }], + url: '/settings/update/check', + ...options +}); + export const listTeams = (options?: Options): RequestResult => (options?.client ?? client).get({ security: [{ scheme: 'bearer', type: 'http' }], url: '/teams', diff --git a/web/src/api/client/types.gen.ts b/web/src/api/client/types.gen.ts index 561af54ae..5af1f995b 100644 --- a/web/src/api/client/types.gen.ts +++ b/web/src/api/client/types.gen.ts @@ -13184,6 +13184,34 @@ export type ReinstallWebhookResponse = { message: string; }; +/** + * Outcome of an operator-triggered release check. + */ +export type ReleaseCheckResult = { + /** + * Channel that was queried. + */ + channel: string; + /** + * Version tag of the running binary. + */ + current_version: string; + /** + * Newest release published on that channel, if any could be resolved. + */ + latest_version?: string | null; + /** + * Release-notes page for `latest_version`. + */ + release_url?: string | null; + /** + * True when `latest_version` is strictly newer than what is running. + * False on a channel whose newest release is older — which is normal and + * expected right after switching a nightly box onto stable. + */ + update_available: boolean; +}; + export type ReleaseListResponse = { releases: Array; }; @@ -14508,18 +14536,33 @@ export type SelfUpdateAttempt = { * fundamental blocker wins, so the operator fixes the real problem first * rather than clearing one only to hit the next. */ -export type SelfUpdateBlocker = 'disabled_by_flag' | 'disabled_by_setting' | 'container' | 'no_supervisor' | 'binary_not_writable' | 'unsupported_platform' | 'in_progress'; +export type SelfUpdateBlocker = 'disabled_by_flag' | 'disabled_by_setting' | 'not_supported' | 'binary_not_writable' | 'unsupported_platform' | 'in_progress'; /** * Where an in-flight update has got to. Polled by the console so a long * download shows progress instead of an indefinite spinner. */ -export type SelfUpdatePhase = 'idle' | 'resolving' | 'downloading' | 'verifying' | 'installing' | 'restarting' | 'failed'; +export type SelfUpdatePhase = 'idle' | 'resolving' | 'downloading' | 'verifying' | 'installing' | 'restarting' | 'pending_restart' | 'failed'; + +/** + * What happens to the running process once the new binary is in place. + */ +export type SelfUpdateRestartMode = 'automatic' | 'manual'; /** * Controls the console's one-click "Update now" action. */ export type SelfUpdateSettings = { + /** + * Release channel this install tracks: `stable`, `beta` or `nightly`. + * + * `None` (the default) means "infer from the running version tag", which + * is what the CLI has always done — a `-nightly.` build tracks nightly, a + * `-beta.N` build tracks beta, a plain tag tracks stable. Setting it + * explicitly pins the channel, so an operator can move a nightly box back + * onto stable without reinstalling. + */ + channel?: string | null; /** * Allow admins to apply a release and restart the server from the console. * `true` by default: the action is permission-gated, audited, and only @@ -14534,7 +14577,7 @@ export type SelfUpdateSettings = { /** * Outcome of an update attempt, as persisted in the journal. */ -export type SelfUpdateStatus = 'pending' | 'succeeded' | 'failed'; +export type SelfUpdateStatus = 'pending' | 'succeeded' | 'installed_pending_restart' | 'failed'; export type SendEmailRequestBody = { /** @@ -16126,10 +16169,14 @@ export type StartUpdateResponse = { current_version: string; /** * How long to allow for the server to come back before treating the - * restart as failed. + * restart as failed. `0` when nothing restarts. */ estimated_restart_secs: number; message: string; + /** + * `automatic` (temps restarts itself) or `manual` (installed only). + */ + restart_mode: SelfUpdateRestartMode; }; export type StatResponse = { @@ -17317,6 +17364,20 @@ export type UpdateCapabilityResponse = { * Non-blocking warning to show with the confirmation (split topology). */ caveat?: string | null; + /** + * Channel actually tracked, after applying the configured override or + * falling back to inference from the running version tag. + */ + channel: string; + /** + * True when `channel` was set explicitly in settings rather than inferred. + */ + channel_is_pinned: boolean; + /** + * Version tag of the running binary. Always present — the version page + * needs it whether or not an update exists. + */ + current_version: string; last_attempt?: null | SelfUpdateAttempt; /** * The equivalent command to run by hand. Always present. @@ -17334,6 +17395,12 @@ export type UpdateCapabilityResponse = { * Operator-facing explanation of `blocker`. */ reason?: string | null; + /** + * `automatic` when applying an update also restarts temps; `manual` when + * it only installs the binary and the operator restarts on their own + * schedule. Lets the console set expectations before the click. + */ + restart_mode: SelfUpdateRestartMode; /** * What would restart the process: `systemd`, `launchd`, `container`, `none`. */ @@ -47362,6 +47429,43 @@ export type GetUpdateStatusResponses = { export type GetUpdateStatusResponse = GetUpdateStatusResponses[keyof GetUpdateStatusResponses]; +export type CheckForUpdateData = { + body?: never; + path?: never; + query?: never; + url: '/settings/update/check'; +}; + +export type CheckForUpdateErrors = { + /** + * Unauthorized + */ + 401: unknown; + /** + * Insufficient permissions + */ + 403: unknown; + /** + * This process cannot check for updates + */ + 501: ProblemDetails; + /** + * The release API could not be reached + */ + 502: ProblemDetails; +}; + +export type CheckForUpdateError = CheckForUpdateErrors[keyof CheckForUpdateErrors]; + +export type CheckForUpdateResponses = { + /** + * Result of the release check + */ + 200: ReleaseCheckResult; +}; + +export type CheckForUpdateResponse = CheckForUpdateResponses[keyof CheckForUpdateResponses]; + export type ListTeamsData = { body?: never; path?: never; diff --git a/web/src/components/alerts/UpdateNowDialog.tsx b/web/src/components/alerts/UpdateNowDialog.tsx index 5a60dae75..dec10aa90 100644 --- a/web/src/components/alerts/UpdateNowDialog.tsx +++ b/web/src/components/alerts/UpdateNowDialog.tsx @@ -14,7 +14,11 @@ import { useSelfUpdateCapability, useStartSelfUpdate, } from '@/hooks/useSelfUpdate' -import type { SelfUpdateAttempt, SelfUpdatePhase } from '@/api/client/types.gen' +import type { + SelfUpdateAttempt, + SelfUpdatePhase, + SelfUpdateRestartMode, +} from '@/api/client/types.gen' import { AlertTriangle, ArrowUpCircle, @@ -39,6 +43,7 @@ const PHASE_LABEL: Record = { verifying: 'Verifying checksum…', installing: 'Installing…', restarting: 'Restarting the server…', + pending_restart: 'Installed — waiting for you to restart temps', failed: 'Failed', } @@ -155,7 +160,8 @@ export function UpdateNowDialog({ - {result?.status === 'succeeded' ? ( + {result?.status === 'succeeded' || + result?.status === 'installed_pending_restart' ? ( ) : result?.status === 'failed' ? ( @@ -164,18 +170,24 @@ export function UpdateNowDialog({ )} {result?.status === 'succeeded' ? 'Update complete' - : result?.status === 'failed' - ? 'Update failed' - : watching - ? 'Updating temps' - : 'Update temps'} + : result?.status === 'installed_pending_restart' + ? 'Update installed' + : result?.status === 'failed' + ? 'Update failed' + : watching + ? 'Updating temps' + : 'Update temps'}
{result ? ( ) : watching ? ( - + ) : ( )} @@ -205,6 +218,8 @@ export function UpdateNowDialog({ Reload console + ) : result ? ( + Close ) : watching ? ( Hide ) : ( @@ -221,7 +236,9 @@ export function UpdateNowDialog({ {startUpdate.isPending && ( )} - Update and restart + {capability?.restart_mode === 'manual' + ? 'Install update' + : 'Update and restart'} )} @@ -238,6 +255,7 @@ function ConfirmBody({ caveat, manualCommand, binaryPath, + restartMode, loading, }: { currentVersion?: string | null @@ -246,8 +264,10 @@ function ConfirmBody({ caveat: string | null manualCommand: string binaryPath: string + restartMode?: SelfUpdateRestartMode loading: boolean }) { + const willRestart = restartMode !== 'manual' return ( <>

@@ -255,19 +275,19 @@ function ConfirmBody({ {latestVersion ?? 'the latest release'} - , verify its checksum, replace the binary + , verify its checksum and replace the binary {currentVersion && ( <> {' '} (currently {currentVersion}) - )}{' '} - and restart. + )} + {willRestart ? ', then restart.' : '.'}

- The server — including proxied traffic to your deployed apps — is - unavailable for a few seconds while it restarts. The previous binary is - kept alongside the new one so you can roll back by hand. + {willRestart + ? 'The server — including proxied traffic to your deployed apps — is unavailable for a few seconds while it restarts. The previous binary is kept alongside the new one so you can roll back by hand.' + : 'Nothing goes offline: temps keeps serving the current version until you restart it yourself, which is when the new version takes over. The previous binary is kept alongside the new one so you can roll back by hand.'}

{caveat && ( @@ -309,9 +329,11 @@ function ConfirmBody({ function WatchingBody({ phase, waitedTooLong, + expectRestart, }: { phase: SelfUpdatePhase waitedTooLong: boolean + expectRestart: boolean }) { return ( <> @@ -320,10 +342,11 @@ function WatchingBody({ {PHASE_LABEL[phase] ?? 'Working…'}

- The console loses contact with the server while it restarts — that is - expected. This dialog reports the result as soon as it is back. + {expectRestart + ? 'The console loses contact with the server while it restarts — that is expected. This dialog reports the result as soon as it is back.' + : 'temps stays up while this runs; the new version takes over when you restart it.'}

- {waitedTooLong && ( + {waitedTooLong && expectRestart && (

@@ -341,6 +364,29 @@ function WatchingBody({ } function ResultBody({ result }: { result: SelfUpdateAttempt }) { + if (result.status === 'installed_pending_restart') { + // The most important case to be blunt about: the bytes are on disk but the + // running server is unchanged, and only the operator can finish the job. + return ( + <> +

+ {result.to_version} is + installed, but temps is still running{' '} + {result.from_version}. +

+

+ Nothing on this host restarts temps automatically, so the update goes + live the next time you restart it yourself. +

+ {result.previous_binary_path && ( +

+ Previous binary kept at{' '} + {result.previous_binary_path} +

+ )} + + ) + } if (result.status === 'succeeded') { return ( <> diff --git a/web/src/components/dashboard/Sidebar.tsx b/web/src/components/dashboard/Sidebar.tsx index 11ee01350..549e3807f 100644 --- a/web/src/components/dashboard/Sidebar.tsx +++ b/web/src/components/dashboard/Sidebar.tsx @@ -18,6 +18,7 @@ import { Activity, AlarmClock, ArrowLeft, + ArrowUpCircle, BadgeCheck, BarChart3, Bell, @@ -179,6 +180,7 @@ const settingsGroups: SettingsGroupDef[] = [ label: 'General', items: [ { title: 'Platform', url: '/settings', icon: Settings2 }, + { title: 'Version', url: '/settings/version', icon: ArrowUpCircle }, { title: 'AI Providers', url: '/settings/ai-providers', icon: Sparkles }, { title: 'Notifications', url: '/settings/notifications', icon: Bell }, ], diff --git a/web/src/components/settings/PlatformUpdatesCard.tsx b/web/src/components/settings/PlatformUpdatesCard.tsx deleted file mode 100644 index 5a4f0d357..000000000 --- a/web/src/components/settings/PlatformUpdatesCard.tsx +++ /dev/null @@ -1,115 +0,0 @@ -import { - Card, - CardContent, - CardDescription, - CardHeader, - CardTitle, -} from '@/components/ui/card' -import { CopyButton } from '@/components/ui/copy-button' -import { Label } from '@/components/ui/label' -import { Switch } from '@/components/ui/switch' -import { useSelfUpdateCapability } from '@/hooks/useSelfUpdate' -import { useSettings, useUpdateSettings } from '@/hooks/useSettings' -import { AlertTriangle, Info, Terminal } from 'lucide-react' -import { toast } from 'sonner' - -/** - * Operator control for the console's "Update now" action. - * - * Shows the toggle *and* what the server independently makes of it — an admin - * who turns this on while the host has no supervisor (or is a container) would - * otherwise be left wondering why the button never appears. - */ -export function PlatformUpdatesCard() { - const { data: settings } = useSettings() - const updateSettings = useUpdateSettings() - const { data: capability } = useSelfUpdateCapability() - - const enabled = settings?.self_update?.enabled ?? true - // A launch flag beats the database, so the toggle is inert (and says so) - // rather than pretending to control something it doesn't. - const overriddenByFlag = capability?.blocker === 'disabled_by_flag' - - const handleToggle = async (next: boolean) => { - try { - await updateSettings.mutateAsync({ - self_update: { enabled: next }, - }) - toast.success( - next - ? 'Updates can now be applied from the console' - : 'Console updates disabled' - ) - } catch { - // useUpdateSettings surfaces the failure toast. - } - } - - return ( - - - Platform updates - - Whether admins can install a new temps release and restart the server - from the console. The update banner and the manual command are shown - either way. - - - -
-
- -

- Requires the platform:update{' '} - permission. Every attempt is audited. -

-
- -
- - {overriddenByFlag && ( -

- - - This server was started with{' '} - --disable-self-update, which - overrides this setting. Remove the flag and restart temps to allow - console updates. - -

- )} - - {capability && !capability.can_apply && !overriddenByFlag && ( -
-

- - {capability.reason} -

-
- - - {capability.manual_command} - - -
-
- )} - - {capability?.can_apply && ( -

- Managed by{' '} - {capability.supervisor} · - replaces {capability.binary_path} -

- )} -
-
- ) -} diff --git a/web/src/hooks/useSelfUpdate.ts b/web/src/hooks/useSelfUpdate.ts index eaf5c4fd0..20c45f29e 100644 --- a/web/src/hooks/useSelfUpdate.ts +++ b/web/src/hooks/useSelfUpdate.ts @@ -1,5 +1,6 @@ import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query' import { + checkForUpdateMutation, getUpdateCapabilityOptions, getUpdateCapabilityQueryKey, getUpdateStatusQueryKey, @@ -7,8 +8,8 @@ import { } from '@/api/client/@tanstack/react-query.gen' /** - * Whether this server can install a release on request, and how the last - * attempt went. + * Whether this server can install a release on request, which version and + * channel it is on, and how the last attempt went. * * Cheap (in-memory state plus one settings read), but not free, so it is only * fetched where the answer is actually used — pass `enabled: false` to skip it. @@ -24,18 +25,19 @@ export function useSelfUpdateCapability({ enabled, refetchInterval: pollMs, staleTime: pollMs ? 0 : 60 * 1000, - // Deliberately keep retrying while polling: the server is EXPECTED to stop - // answering mid-update (that is the restart), and giving up on the first - // failure would strand the UI on "connection lost" exactly when the user - // most needs to see the outcome. + // Deliberately keep retrying while polling: under automatic restart the + // server is EXPECTED to stop answering mid-update, and giving up on the + // first failure would strand the UI on "connection lost" exactly when the + // user most needs to see the outcome. retry: pollMs ? true : false, retryDelay: 2000, }) } /** - * Start an update. Resolves as soon as the server accepts it — the download and - * restart happen afterwards, observable through {@link useSelfUpdateCapability}. + * Start an update. Resolves as soon as the server accepts it — the install (and + * the restart, where the server does that) happen afterwards, observable + * through {@link useSelfUpdateCapability}. */ export function useStartSelfUpdate() { const queryClient = useQueryClient() @@ -50,6 +52,23 @@ export function useStartSelfUpdate() { }) } +/** + * Query the release API immediately rather than waiting for the server's own + * periodic check. Republishes the shared update notice, so the banner and the + * version page never disagree. + */ +export function useCheckForUpdate() { + const queryClient = useQueryClient() + + return useMutation({ + ...checkForUpdateMutation(), + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: getUpdateStatusQueryKey() }) + queryClient.invalidateQueries({ queryKey: getUpdateCapabilityQueryKey() }) + }, + }) +} + /** Drop the cached "update available" notice once the server is back. */ export function useInvalidateUpdateStatus() { const queryClient = useQueryClient() diff --git a/web/src/pages/Settings.tsx b/web/src/pages/Settings.tsx index 320b8df77..05ac50641 100644 --- a/web/src/pages/Settings.tsx +++ b/web/src/pages/Settings.tsx @@ -25,7 +25,6 @@ import { type PlatformSettings, } from '@/hooks/useSettings' import { client } from '@/api/client/client.gen' -import { PlatformUpdatesCard } from '@/components/settings/PlatformUpdatesCard' import { AlertCircle, Globe, @@ -500,9 +499,6 @@ export function Settings() { - {/* Saves on toggle, so it stays out of this form's dirty tracking. */} - - {isDirty && (
diff --git a/web/src/pages/settings/VersionPage.tsx b/web/src/pages/settings/VersionPage.tsx new file mode 100644 index 000000000..133abe3fd --- /dev/null +++ b/web/src/pages/settings/VersionPage.tsx @@ -0,0 +1,473 @@ +import { Badge } from '@/components/ui/badge' +import { Button } from '@/components/ui/button' +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from '@/components/ui/card' +import { CopyButton } from '@/components/ui/copy-button' +import { Label } from '@/components/ui/label' +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from '@/components/ui/select' +import { Skeleton } from '@/components/ui/skeleton' +import { Switch } from '@/components/ui/switch' +import { UpdateNowDialog } from '@/components/alerts/UpdateNowDialog' +import { useBreadcrumbs } from '@/contexts/BreadcrumbContext' +import { usePageTitle } from '@/hooks/usePageTitle' +import { + useCheckForUpdate, + useSelfUpdateCapability, +} from '@/hooks/useSelfUpdate' +import { useSettings, useUpdateSettings } from '@/hooks/useSettings' +import { useUpdateStatus } from '@/hooks/useUpdateStatus' +import { + AlertTriangle, + ArrowUpCircle, + CheckCircle2, + Info, + Loader2, + RefreshCw, + Terminal, + XCircle, +} from 'lucide-react' +import { useEffect, useState } from 'react' +import { toast } from 'sonner' + +/** Channels the server knows how to track, worst-to-best stability last. */ +const CHANNELS = [ + { + value: 'stable', + label: 'Stable', + hint: 'Tagged releases only. Recommended for production.', + }, + { + value: 'beta', + label: 'Beta', + hint: 'Pre-release cuts plus stable. Excludes nightly builds.', + }, + { + value: 'nightly', + label: 'Nightly', + hint: 'Automated daily builds from main. Least stable.', + }, +] as const + +/** Sentinel for "no explicit channel — follow the running version's tag". */ +const INHERIT = '__inherit__' + +/** + * Version and updates page. + * + * One place to answer "what am I running, is there something newer, and can I + * install it from here" — which previously required reading a banner, the + * release page and the host's service manager. + */ +export function VersionPage() { + const { setBreadcrumbs } = useBreadcrumbs() + const { data: settings } = useSettings() + const updateSettings = useUpdateSettings() + const { data: capability, isPending } = useSelfUpdateCapability() + const { data: status } = useUpdateStatus() + const checkForUpdate = useCheckForUpdate() + const [updateOpen, setUpdateOpen] = useState(false) + + useEffect(() => { + setBreadcrumbs([ + { label: 'Settings', href: '/settings' }, + { label: 'Version' }, + ]) + }, [setBreadcrumbs]) + + usePageTitle('Version') + + const selfUpdate = settings?.self_update + const enabled = selfUpdate?.enabled ?? true + // A launch flag beats the database, so the toggle is inert (and says so) + // rather than pretending to control something it doesn't. + const overriddenByFlag = capability?.blocker === 'disabled_by_flag' + + const saveSelfUpdate = async ( + patch: { enabled?: boolean; channel?: string | null }, + message: string + ) => { + try { + await updateSettings.mutateAsync({ + self_update: { + enabled: patch.enabled ?? enabled, + channel: + patch.channel !== undefined + ? patch.channel + : (selfUpdate?.channel ?? null), + }, + }) + toast.success(message) + } catch { + // useUpdateSettings surfaces the failure toast. + } + } + + const latest = checkForUpdate.data + const canApply = Boolean(capability?.can_apply && capability?.allowed) + + return ( +
+ + + Version + + What this server is running, and what is available on its channel. + + + + {isPending ? ( +
+ + +
+ ) : ( + <> +
+
+
+ + {capability?.current_version ?? 'unknown'} + + {capability?.channel} + {!capability?.channel_is_pinned && ( + + (from the installed version) + + )} +
+

+ Managed by{' '} + {capability?.supervisor}{' '} + ·{' '} + {capability?.restart_mode === 'manual' + ? 'updates install but do not restart temps' + : 'updates restart temps automatically'} +

+
+ +
+ + {capability?.binary_path && ( +

+ Binary{' '} + {capability.binary_path} +

+ )} + + setUpdateOpen(true)} + /> + + )} +
+
+ + + + Release channel + + Which releases this server tracks. Changing it takes effect on the + next check. + + + + + + {/* Switching to a more stable channel usually means the newest + release there is OLDER than what is running, which looks like a + bug unless we say so first. */} +

+ + + Moving to a more stable channel does not downgrade this server. + Its newest release may be older than what you are running, in + which case nothing is offered until that channel catches up. + +

+
+
+ + + + Updating from the console + + Whether admins can install a release from here. The banner and the + manual command are shown either way. + + + +
+
+ +

+ Requires the platform:update{' '} + permission. Every attempt is audited. +

+
+ + saveSelfUpdate( + { enabled: next }, + next + ? 'Updates can now be applied from the console' + : 'Console updates disabled' + ) + } + /> +
+ + {overriddenByFlag && ( +

+ + + This server was started with{' '} + --disable-self-update, which + overrides this setting. Remove the flag and restart temps to + allow console updates. + +

+ )} + + {capability && !capability.can_apply && !overriddenByFlag && ( +
+

+ + {capability.reason} +

+ +
+ )} + + {capability?.caveat && ( +

+ + {capability.caveat} +

+ )} +
+
+ + {capability?.last_attempt && ( + + )} + + +
+ ) +} + +function ManualCommand({ command }: { command: string }) { + return ( +
+ + + {command} + + +
+ ) +} + +function UpdateAvailability({ + latestVersion, + updateAvailable, + currentVersion, + releaseUrl, + checked, + error, + canApply, + onUpdate, +}: { + latestVersion: string | null + updateAvailable: boolean + currentVersion: string | null + releaseUrl: string | null + checked: boolean + error: string | null + canApply: boolean + onUpdate: () => void +}) { + if (error) { + return ( +

+ + {error} +

+ ) + } + + if (updateAvailable && latestVersion) { + return ( +
+

+ + + {latestVersion} is available + {currentVersion && ( + <> + {' '} + (you have {currentVersion}) + + )} + {releaseUrl && ( + <> + {' · '} + + Release notes + + + )} + +

+ {canApply && ( + + )} +
+ ) + } + + // Distinguish "we asked and there is nothing" from "we haven't asked yet", + // so a stale page never reads as a fresh all-clear. + return ( +

+ + + {checked + ? `Up to date${latestVersion ? ` — the newest release on this channel is ${latestVersion}` : ''}.` + : 'No newer release has been found. The server re-checks periodically, or check now.'} + +

+ ) +} + +function LastAttemptCard({ + attempt, +}: { + attempt: NonNullable< + ReturnType['data'] + >['last_attempt'] +}) { + if (!attempt) return null + + const tone = + attempt.status === 'succeeded' + ? 'text-green-700 dark:text-green-400' + : attempt.status === 'failed' + ? 'text-destructive' + : 'text-amber-700 dark:text-amber-400' + + const label = + attempt.status === 'succeeded' + ? 'Succeeded' + : attempt.status === 'failed' + ? 'Failed' + : attempt.status === 'installed_pending_restart' + ? 'Installed — restart temps to apply' + : 'In progress' + + return ( + + + Last update attempt + + +

{label}

+

+ {attempt.from_version} + {attempt.to_version && ( + <> + {' → '} + {attempt.to_version} + + )} + {' · '} + {new Date(attempt.started_at).toLocaleString()} +

+ {attempt.error &&

{attempt.error}

} + {attempt.previous_binary_path && ( +

+ Previous binary kept at{' '} + {attempt.previous_binary_path} +

+ )} +
+
+ ) +} From 52adf309fafe9fa5187868f5439b3d56ad4c78ae Mon Sep 17 00:00:00 2001 From: David Viejo Date: Fri, 7 Aug 2026 10:18:09 +0200 Subject: [PATCH 3/7] fix(cli): reject release tags that escape the temps repository MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The version pin was interpolated straight into the GitHub API path, and the `url` crate resolves `..` segments when parsing. A tag such as `v/../../../../../owner/repo/releases/latest` therefore walked out of `gotempsh/temps` and resolved to another repository's release — confirmed against a running server, which fetched rust-lang/rust 1.97.1. Everything downstream then behaves normally: it downloads that release's `temps-.tar.gz`, checks it against that release's own `.sha256` (which matches, being published by the same author), executes it for the version preflight and installs it over the running binary. So anyone able to reach `temps upgrade --version` — and, since the console update action landed, anyone holding `platform:update` over HTTP — could install an arbitrary binary. Tags are now normalized through a strict semver shape before use, and the URL is assembled by pushing a validated path segment instead of formatting a string, so a future slip in the validator still cannot alter the path structure. --- crates/temps-cli/src/commands/upgrade.rs | 156 +++++++++++++++++++++-- 1 file changed, 145 insertions(+), 11 deletions(-) diff --git a/crates/temps-cli/src/commands/upgrade.rs b/crates/temps-cli/src/commands/upgrade.rs index 4da0978c3..2bf1241b1 100644 --- a/crates/temps-cli/src/commands/upgrade.rs +++ b/crates/temps-cli/src/commands/upgrade.rs @@ -944,19 +944,88 @@ fn pick_release_for_channel( releases.into_iter().find(|r| channel.includes(r)) } -/// Fetch a specific release by tag from GitHub. -pub(crate) async fn fetch_specific_release(version: &str) -> anyhow::Result { - // Ensure the version starts with 'v' - let tag = if version.starts_with('v') { - version.to_string() - } else { - format!("v{}", version) +/// Normalize a caller-supplied version into a release tag, rejecting anything +/// that is not a plain semver-shaped tag. +/// +/// **This is a security boundary, not cosmetics.** The tag is interpolated into +/// a GitHub API path, and the `url` crate resolves `..` segments when parsing — +/// so an unvalidated tag like `v/../../../../../owner/repo/releases/latest` +/// walks out of `gotempsh/temps` and resolves to *another repository's* release. +/// Everything downstream then behaves normally: it downloads that release's +/// `temps-.tar.gz`, checks it against that release's own `.sha256` +/// (which of course matches), executes it for the version preflight, and +/// installs it over the running binary. In other words, a caller who can reach +/// `temps upgrade --version` or `POST /settings/update` could install an +/// arbitrary binary. Keep this strict. +pub(crate) fn normalize_release_tag(version: &str) -> anyhow::Result { + let trimmed = version.trim(); + if trimmed.is_empty() { + return Err(anyhow::anyhow!("Version must not be empty")); + } + + let core = trimmed.strip_prefix('v').unwrap_or(trimmed); + // Split off the prerelease/build suffix; the numeric core is validated + // separately so `1.2.3` and `1.2.3-beta.4` are both accepted but + // `1.2.3/../x` is not. + let (numeric, suffix) = match core.split_once(['-', '+']) { + Some((numeric, suffix)) => (numeric, Some(suffix)), + None => (core, None), }; - let url = format!( - "https://api.github.com/repos/gotempsh/temps/releases/tags/{}", - tag - ); + let mut parts = numeric.split('.'); + let mut components = 0; + for _ in 0..3 { + let component = parts.next().ok_or_else(|| { + anyhow::anyhow!("Version '{version}' must look like 'v1.2.3' or 'v1.2.3-beta.4'") + })?; + if component.is_empty() || !component.bytes().all(|b| b.is_ascii_digit()) { + return Err(anyhow::anyhow!( + "Version '{version}' has a non-numeric component '{component}'" + )); + } + components += 1; + } + if components != 3 || parts.next().is_some() { + return Err(anyhow::anyhow!( + "Version '{version}' must have exactly three numeric components" + )); + } + + if let Some(suffix) = suffix { + // Deliberately narrow: alphanumerics, dot and dash only. No slashes, no + // percent-encoding, nothing that can add or escape a path segment. + if suffix.is_empty() + || !suffix + .bytes() + .all(|b| b.is_ascii_alphanumeric() || b == b'.' || b == b'-') + { + return Err(anyhow::anyhow!( + "Version '{version}' has an unsupported prerelease suffix" + )); + } + if suffix.split('.').any(|segment| segment.is_empty()) { + return Err(anyhow::anyhow!( + "Version '{version}' has an empty prerelease segment" + )); + } + } + + Ok(format!("v{core}")) +} + +/// Fetch a specific release by tag from GitHub. +pub(crate) async fn fetch_specific_release(version: &str) -> anyhow::Result { + let tag = normalize_release_tag(version)?; + + // Built by pushing a validated segment rather than string interpolation, so + // even a future validation slip cannot alter the path structure. + let mut url = reqwest::Url::parse("https://api.github.com/repos/gotempsh/temps/releases/tags/") + .map_err(|e| anyhow::anyhow!("Failed to build the release URL: {e}"))?; + url.path_segments_mut() + .map_err(|_| anyhow::anyhow!("Failed to build the release URL"))? + .pop_if_empty() + .push(&tag); + let url = url.to_string(); let client = reqwest::Client::new(); let response = client @@ -1484,6 +1553,71 @@ mod tests { assert!(!g.contains("systemctl")); } + #[test] + fn test_normalize_release_tag_accepts_real_tags() { + for (input, expected) in [ + ("v1.2.3", "v1.2.3"), + ("1.2.3", "v1.2.3"), + ("v0.1.0-beta.55", "v0.1.0-beta.55"), + ( + "v0.1.0-nightly.20260806.c64e8f98", + "v0.1.0-nightly.20260806.c64e8f98", + ), + (" v1.0.0 ", "v1.0.0"), + ] { + assert_eq!( + normalize_release_tag(input).expect(input), + expected, + "should accept {input}" + ); + } + } + + #[test] + fn test_normalize_release_tag_blocks_path_traversal() { + // The exploit this validation exists for: the `url` crate resolves + // `..` segments, so these escape gotempsh/temps and reach an arbitrary + // repository's release — whose asset would then be installed. + for input in [ + "v/../../../../../rust-lang/rust/releases/latest", + "v1.2.3/../../../../../owner/repo/releases/latest", + "../../owner/repo/releases/latest", + "v1.2.3/..", + "v1.2.3/extra", + ] { + assert!( + normalize_release_tag(input).is_err(), + "must reject traversal: {input}" + ); + } + } + + #[test] + fn test_normalize_release_tag_blocks_encoding_and_injection_tricks() { + for input in [ + "", + " ", + "v", + "v1.2", + "v1.2.3.4", + "v1.2.x", + "v1.2.3-beta/4", + "v1.2.3-beta%2F4", + "v1.2.3-beta 4", + "v1.2.3-", + "v1.2.3-beta..4", + "v1.2.3?foo=bar", + "v1.2.3#frag", + "v1.2.3@evil.com", + "http://evil.com/v1.2.3", + ] { + assert!( + normalize_release_tag(input).is_err(), + "must reject malformed tag: {input:?}" + ); + } + } + #[test] fn test_platform_target() { // Just verify it doesn't panic on the current platform From 6850040469eae62796e19dfc392792ff980f7566 Mon Sep 17 00:00:00 2001 From: David Viejo Date: Fri, 7 Aug 2026 11:11:35 +0200 Subject: [PATCH 4/7] fix(settings): close the review findings on console updates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three defects found reviewing the console update action, each reproduced against a running server before and after the fix. **The off switch failed open.** `AppSettings` deserializes with `#[serde(default)]` and the settings PUT replaces the whole document, so a client that omitted `self_update` reset it to enabled — an operator's deliberate "no console updates" was undone by any unrelated save from a client built before the field existed. The field is now `Option`, absence means "leave it alone", and only an explicit value changes it. Verified: disable, PUT without the field, still disabled. **Two installs could run at once.** The in-progress check read the phase and set it in separate lock acquisitions, so concurrent requests both observed `Idle` and both spawned a job onto the same binary, backup and temp files — capable of leaving a truncated executable behind. Reproduced: six concurrent requests, two accepted. The claim is now a test-and-set under one lock, and the temp/probe paths carry the pid so a separate process cannot collide either. Verified: exactly one acceptance per round, plus a threaded regression test. **A bad version pin failed late.** Tag validation lived in the background job, so a malformed `version` returned 202 and surfaced as a failure the caller had to go looking for, having occupied the updater on the way. It now validates at the boundary and returns 400 with the updater untouched. Also from the review: - The capability response withholds the absolute binary path from callers without `platform:update` — host layout is no use to someone who cannot act on it. - `INVOCATION_ID` is corroborated against a `*.service` cgroup. It is inherited, so a shell inside a unit (or `systemd-run`) carried it without being restartable, and temps would have exited expecting a restart that never came — turning an update into an outage. - The version page renders the Problem Details `detail` instead of `String(error)`, which printed "[object Object]" and told the operator nothing. - `registerPlatformCommands` is registered with the CLI docs generator, so the whole `platform` group — including the new update commands — appears in the reference. It was absent before this branch. --- apps/temps-cli/docs/CLI.md | 111 ++++++++++++- apps/temps-cli/docs/CLI.mdx | 111 ++++++++++++- apps/temps-cli/scripts/generate-docs.ts | 2 + .../src/commands/serve/self_update.rs | 146 +++++++++++++++++- crates/temps-cli/src/commands/upgrade.rs | 18 ++- crates/temps-config/src/handler.rs | 122 +++++++++++++-- crates/temps-core/src/app_settings.rs | 20 ++- crates/temps-core/src/self_update.rs | 25 ++- web/src/pages/settings/VersionPage.tsx | 22 ++- 9 files changed, 542 insertions(+), 35 deletions(-) diff --git a/apps/temps-cli/docs/CLI.md b/apps/temps-cli/docs/CLI.md index 251c617f1..58fd71b47 100644 --- a/apps/temps-cli/docs/CLI.md +++ b/apps/temps-cli/docs/CLI.md @@ -2,7 +2,7 @@ > Auto-generated documentation for the Temps CLI. > -> Generated on: 2026-08-04 +> Generated on: 2026-08-07 ## Installation @@ -235,6 +235,20 @@ Delete a project | `-f, --force` | Skip confirmation | - | No | | `-y, --yes` | Skip confirmation (alias for --force) | - | No | +## `drop` + +Detect and deploy a local source directory or ZIP without Git + +**Options:** + +| Flag | Description | Default | Required | +|------|-------------|---------|----------| +| `--name ` | Project name (slugified automatically) | - | Yes | +| `--preset ` | Select a detected preset | - | Yes | +| `--directory ` | Select a detected project root | - | Yes | +| `--no-wait` | Do not wait for deployment to complete | - | No | +| `--timeout ` | Deployment timeout | `600` | Yes | + ## `deploy` Deploy a project from git @@ -695,7 +709,7 @@ Set an environment variable | `-e, --environments ` | Comma-separated environment names (interactive if not provided) | - | Yes | | `--no-preview` | Exclude from preview environments | - | No | | `--update` | Update existing variable instead of creating new | - | No | -| `--secret` | Store as a secret: the value is masked in the UI and never returned by the API. One-way — a secret cannot later be made non-secret | - | No | +| `--secret` | Store as a secret: the value is masked in the UI and never returned by the API. One-way — to make a secret readable again you must delete the variable and create it anew | - | No | #### `environments vars delete` (alias: `rm`, `unset`) @@ -1973,6 +1987,99 @@ Set the preview domain pattern |------|-------------|---------|----------| | `--domain ` | Preview domain pattern | - | Yes | +## `platform` (alias: `plat`) + +View platform and server information + +**Subcommands:** + +- `info` - Get platform information +- `access` - Get access and networking information +- `private-ip` - Get the server private IP address +- `public-ip` - Get the server public IP address +- `update` - Check for and apply temps releases on the server + +### `platform info` + +Get platform information + +**Options:** + +| Flag | Description | Default | Required | +|------|-------------|---------|----------| +| `--json` | Output in JSON format | - | No | + +### `platform access` + +Get access and networking information + +**Options:** + +| Flag | Description | Default | Required | +|------|-------------|---------|----------| +| `--json` | Output in JSON format | - | No | + +### `platform private-ip` + +Get the server private IP address + +### `platform public-ip` + +Get the server public IP address + +### `platform update` + +Check for and apply temps releases on the server + +**Subcommands:** + +- `status` - Show the available release and whether it can be applied from here +- `check` - Ask the release API for the newest version on this channel now +- `channel` - Show or set the release channel: stable, beta, nightly, or "auto" to follow the installed version +- `apply` - Install a release on the server and restart it + +#### `platform update status` + +Show the available release and whether it can be applied from here + +**Options:** + +| Flag | Description | Default | Required | +|------|-------------|---------|----------| +| `--json` | Output in JSON format | - | No | + +#### `platform update check` + +Ask the release API for the newest version on this channel now + +**Options:** + +| Flag | Description | Default | Required | +|------|-------------|---------|----------| +| `--json` | Output in JSON format | - | No | + +#### `platform update channel` + +Show or set the release channel: stable, beta, nightly, or "auto" to follow the installed version + +**Options:** + +| Flag | Description | Default | Required | +|------|-------------|---------|----------| +| `--json` | Output in JSON format | - | No | + +#### `platform update apply` + +Install a release on the server and restart it + +**Options:** + +| Flag | Description | Default | Required | +|------|-------------|---------|----------| +| `--version ` | Release tag to install (default: newest on this channel) | - | Yes | +| `-y, --yes` | Skip the confirmation prompt | - | No | +| `--json` | Output in JSON format | - | No | + ## `users` Manage platform users diff --git a/apps/temps-cli/docs/CLI.mdx b/apps/temps-cli/docs/CLI.mdx index be787e998..2e8e8b1f6 100644 --- a/apps/temps-cli/docs/CLI.mdx +++ b/apps/temps-cli/docs/CLI.mdx @@ -7,7 +7,7 @@ export const metadata = { > Auto-generated documentation for the Temps CLI. > -> Generated on: 2026-08-04 +> Generated on: 2026-08-07 ## Installation @@ -240,6 +240,20 @@ Delete a project | `-f, --force` | Skip confirmation | - | No | | `-y, --yes` | Skip confirmation (alias for --force) | - | No | +## `drop` + +Detect and deploy a local source directory or ZIP without Git + +**Options:** + +| Flag | Description | Default | Required | +|------|-------------|---------|----------| +| `--name ` | Project name (slugified automatically) | - | Yes | +| `--preset ` | Select a detected preset | - | Yes | +| `--directory ` | Select a detected project root | - | Yes | +| `--no-wait` | Do not wait for deployment to complete | - | No | +| `--timeout ` | Deployment timeout | `600` | Yes | + ## `deploy` Deploy a project from git @@ -700,7 +714,7 @@ Set an environment variable | `-e, --environments ` | Comma-separated environment names (interactive if not provided) | - | Yes | | `--no-preview` | Exclude from preview environments | - | No | | `--update` | Update existing variable instead of creating new | - | No | -| `--secret` | Store as a secret: the value is masked in the UI and never returned by the API. One-way — a secret cannot later be made non-secret | - | No | +| `--secret` | Store as a secret: the value is masked in the UI and never returned by the API. One-way — to make a secret readable again you must delete the variable and create it anew | - | No | #### `environments vars delete` (alias: `rm`, `unset`) @@ -1978,6 +1992,99 @@ Set the preview domain pattern |------|-------------|---------|----------| | `--domain ` | Preview domain pattern | - | Yes | +## `platform` (alias: `plat`) + +View platform and server information + +**Subcommands:** + +- `info` - Get platform information +- `access` - Get access and networking information +- `private-ip` - Get the server private IP address +- `public-ip` - Get the server public IP address +- `update` - Check for and apply temps releases on the server + +### `platform info` + +Get platform information + +**Options:** + +| Flag | Description | Default | Required | +|------|-------------|---------|----------| +| `--json` | Output in JSON format | - | No | + +### `platform access` + +Get access and networking information + +**Options:** + +| Flag | Description | Default | Required | +|------|-------------|---------|----------| +| `--json` | Output in JSON format | - | No | + +### `platform private-ip` + +Get the server private IP address + +### `platform public-ip` + +Get the server public IP address + +### `platform update` + +Check for and apply temps releases on the server + +**Subcommands:** + +- `status` - Show the available release and whether it can be applied from here +- `check` - Ask the release API for the newest version on this channel now +- `channel` - Show or set the release channel: stable, beta, nightly, or "auto" to follow the installed version +- `apply` - Install a release on the server and restart it + +#### `platform update status` + +Show the available release and whether it can be applied from here + +**Options:** + +| Flag | Description | Default | Required | +|------|-------------|---------|----------| +| `--json` | Output in JSON format | - | No | + +#### `platform update check` + +Ask the release API for the newest version on this channel now + +**Options:** + +| Flag | Description | Default | Required | +|------|-------------|---------|----------| +| `--json` | Output in JSON format | - | No | + +#### `platform update channel` + +Show or set the release channel: stable, beta, nightly, or "auto" to follow the installed version + +**Options:** + +| Flag | Description | Default | Required | +|------|-------------|---------|----------| +| `--json` | Output in JSON format | - | No | + +#### `platform update apply` + +Install a release on the server and restart it + +**Options:** + +| Flag | Description | Default | Required | +|------|-------------|---------|----------| +| `--version ` | Release tag to install (default: newest on this channel) | - | Yes | +| `-y, --yes` | Skip the confirmation prompt | - | No | +| `--json` | Output in JSON format | - | No | + ## `users` Manage platform users diff --git a/apps/temps-cli/scripts/generate-docs.ts b/apps/temps-cli/scripts/generate-docs.ts index f0b2b3f15..8bab853ba 100644 --- a/apps/temps-cli/scripts/generate-docs.ts +++ b/apps/temps-cli/scripts/generate-docs.ts @@ -24,6 +24,7 @@ import { registerNotificationsCommands } from '../src/commands/notifications/ind import { registerDnsCommands } from '../src/commands/dns/index.js' import { registerServicesCommands } from '../src/commands/services/index.js' import { registerSettingsCommands } from '../src/commands/settings/index.js' +import { registerPlatformCommands } from '../src/commands/platform/index.js' import { registerUsersCommands } from '../src/commands/users/index.js' import { registerApiKeysCommands } from '../src/commands/apikeys/index.js' import { registerMonitorsCommands } from '../src/commands/monitors/index.js' @@ -344,6 +345,7 @@ async function main() { registerDnsCommands(program) registerServicesCommands(program) registerSettingsCommands(program) + registerPlatformCommands(program) registerUsersCommands(program) registerApiKeysCommands(program) registerMonitorsCommands(program) diff --git a/crates/temps-cli/src/commands/serve/self_update.rs b/crates/temps-cli/src/commands/serve/self_update.rs index 75439d33f..3ca398aea 100644 --- a/crates/temps-cli/src/commands/serve/self_update.rs +++ b/crates/temps-cli/src/commands/serve/self_update.rs @@ -311,12 +311,37 @@ impl BinarySelfUpdater { None } + /// Test-only: production code moves the phase through `try_claim` and the + /// job itself, which owns the transitions after the claim succeeds. + #[cfg(test)] fn set_phase(&self, phase: SelfUpdatePhase, phase_error: Option) { if let Ok(mut state) = self.state.write() { state.phase = phase; state.phase_error = phase_error; } } + + /// Take exclusive ownership of the updater, or report who already has it. + /// + /// Tests and sets the phase in ONE lock acquisition. The equivalent check + /// inside `find_blocker` is advisory only: two concurrent callers can both + /// observe `Idle` there and both proceed, which would put two jobs on the + /// same binary, backup and temp files — capable of leaving a truncated + /// executable behind. This is the check that actually excludes them. + fn try_claim(&self) -> Result<(), SelfUpdateError> { + let mut state = self + .state + .write() + .unwrap_or_else(|poisoned| poisoned.into_inner()); + if state.phase.is_active() { + return Err(SelfUpdateError::AlreadyRunning { + phase: state.phase.as_str(), + }); + } + state.phase = SelfUpdatePhase::Resolving; + state.phase_error = None; + Ok(()) + } } /// Resolve the channel to track: the operator's explicit setting, else the one @@ -397,8 +422,24 @@ impl SelfUpdater for BinarySelfUpdater { return Err(SelfUpdateError::Unavailable { blocker, reason }); } + // Validate the pin BEFORE claiming the updater, so a typo fails the + // request outright rather than occupying the updater and surfacing as + // a background failure the caller has to go hunting for. This is also + // the security boundary for the tag — see `normalize_release_tag`. + let target_version = match target_version { + Some(version) => Some( + crate::commands::upgrade::normalize_release_tag(&version).map_err(|e| { + SelfUpdateError::InvalidVersion { + reason: e.to_string(), + } + })?, + ), + None => None, + }; + + self.try_claim()?; + let current_version = current_version_tag(); - self.set_phase(SelfUpdatePhase::Resolving, None); let restart_mode = self.supervisor.restart_mode(); let (channel, _) = resolve_channel(policy.channel.as_deref(), ¤t_version); @@ -711,7 +752,7 @@ fn detect_supervisor() -> SupervisorKind { if in_container() { return SupervisorKind::Container; } - if std::env::var_os("INVOCATION_ID").is_some() { + if std::env::var_os("INVOCATION_ID").is_some() && running_under_systemd_service() { return SupervisorKind::Systemd; } // launchd sets this for managed jobs; processes started from a terminal @@ -722,6 +763,26 @@ fn detect_supervisor() -> SupervisorKind { SupervisorKind::None } +/// Corroborate `INVOCATION_ID` against the cgroup this process actually lives in. +/// +/// `INVOCATION_ID` is inherited, so a shell started inside a unit — or anything +/// launched via `systemd-run` — carries it without being a restartable service. +/// Believing it there would make temps exit expecting a restart that never +/// comes, i.e. turn an update into an outage. A real service lives in a +/// `*.service` cgroup, so require that too. If the cgroup cannot be read (not +/// Linux, or an unusual mount), fall back to trusting the env var rather than +/// downgrading a legitimate systemd install to manual restarts. +fn running_under_systemd_service() -> bool { + match std::fs::read_to_string("/proc/self/cgroup") { + Ok(cgroup) => cgroup.lines().any(|line| { + line.rsplit('/') + .next() + .is_some_and(|unit| unit.ends_with(".service")) + }), + Err(_) => true, + } +} + /// Run the downloaded binary's `--version` before trusting it. /// /// Catches the failures a checksum cannot: a build for the wrong libc, a @@ -732,7 +793,9 @@ fn preflight_binary(binary_path: &Path, new_binary: &[u8]) -> anyhow::Result<()> let parent = binary_path .parent() .ok_or_else(|| anyhow::anyhow!("Cannot determine the binary's directory"))?; - let probe_path = parent.join(".temps-update-probe"); + // Unique per process: a stale probe from another temps (or a crashed run) + // must never be executed or overwritten mid-flight by a concurrent one. + let probe_path = parent.join(format!(".temps-update-probe.{}", std::process::id())); std::fs::write(&probe_path, new_binary).map_err(|e| { anyhow::anyhow!( @@ -972,7 +1035,34 @@ mod tests { let err = updater(&dir, false, SupervisorKind::Systemd) .start(None, Some(1), &policy(false)) .expect_err("must refuse when disabled in settings"); - assert_eq!(err.blocker(), SelfUpdateBlocker::DisabledBySetting); + assert_eq!(err.blocker(), Some(SelfUpdateBlocker::DisabledBySetting)); + let _ = std::fs::remove_dir_all(&dir); + } + + #[test] + fn test_start_rejects_a_bad_version_without_claiming_the_updater() { + // A typo must fail the request outright and leave the updater free, + // not occupy it and surface later as a background failure. + let dir = temp_dir("bad-version"); + let updater = updater(&dir, false, SupervisorKind::Systemd); + let err = updater + .start( + Some("v/../../../../../owner/repo/releases/latest".to_string()), + Some(1), + &policy(true), + ) + .expect_err("must reject a traversal-shaped version"); + assert!(matches!(err, SelfUpdateError::InvalidVersion { .. })); + assert_eq!( + err.blocker(), + None, + "a bad argument is not an install blocker" + ); + // Still idle, so a corrected retry works immediately. + assert_eq!( + updater.capability(&policy(true)).phase, + SelfUpdatePhase::Idle + ); let _ = std::fs::remove_dir_all(&dir); } @@ -988,6 +1078,50 @@ mod tests { let _ = std::fs::remove_dir_all(&dir); } + #[test] + fn test_concurrent_starts_claim_the_updater_exactly_once() { + // Two callers racing on the same updater must not both win: they + // would share the binary, the .bak and the temp files, and can leave a + // truncated executable behind. The claim is a test-and-set under one + // lock, so exactly one wins however they interleave. + let dir = temp_dir("concurrent-claim"); + let updater = Arc::new(updater(&dir, false, SupervisorKind::Systemd)); + + let accepted = Arc::new(std::sync::atomic::AtomicUsize::new(0)); + let rejected = Arc::new(std::sync::atomic::AtomicUsize::new(0)); + let barrier = Arc::new(std::sync::Barrier::new(8)); + + let handles: Vec<_> = (0..8) + .map(|_| { + let updater = updater.clone(); + let accepted = accepted.clone(); + let rejected = rejected.clone(); + let barrier = barrier.clone(); + std::thread::spawn(move || { + barrier.wait(); + match updater.try_claim() { + Ok(()) => accepted.fetch_add(1, std::sync::atomic::Ordering::SeqCst), + Err(SelfUpdateError::AlreadyRunning { .. }) => { + rejected.fetch_add(1, std::sync::atomic::Ordering::SeqCst) + } + Err(e) => panic!("unexpected error: {e}"), + }; + }) + }) + .collect(); + for handle in handles { + handle.join().expect("thread"); + } + + assert_eq!( + accepted.load(std::sync::atomic::Ordering::SeqCst), + 1, + "exactly one caller may claim the updater" + ); + assert_eq!(rejected.load(std::sync::atomic::Ordering::SeqCst), 7); + let _ = std::fs::remove_dir_all(&dir); + } + #[test] fn test_failed_phase_does_not_block_a_retry() { // A previous failure must not wedge the updater — the operator has to @@ -1159,7 +1293,9 @@ mod tests { .expect_err("must reject"); assert!(err.to_string().contains("left untouched"), "{err}"); // The probe file must not be left behind. - assert!(!dir.join(".temps-update-probe").exists()); + assert!(!dir + .join(format!(".temps-update-probe.{}", std::process::id())) + .exists()); let _ = std::fs::remove_dir_all(&dir); } diff --git a/crates/temps-cli/src/commands/upgrade.rs b/crates/temps-cli/src/commands/upgrade.rs index 2bf1241b1..c8d783948 100644 --- a/crates/temps-cli/src/commands/upgrade.rs +++ b/crates/temps-cli/src/commands/upgrade.rs @@ -841,7 +841,7 @@ pub async fn update_notifier_loop( .get_settings() .await .ok() - .and_then(|s| s.self_update.channel); + .and_then(|s| s.self_update().channel); if let Some(notice) = check_for_newer_release(configured_channel.as_deref()).await { tracing::warn!( current_version = %notice.current_version, @@ -1196,7 +1196,10 @@ pub(crate) fn replace_binary(binary_path: &PathBuf, new_binary: &[u8]) -> anyhow .parent() .ok_or_else(|| anyhow::anyhow!("Cannot determine parent directory"))?; - let tmp_path = parent.join(".temps-upgrade-tmp"); + // Unique per process so a concurrent upgrader (another temps, or the CLI + // run alongside the server) cannot half-write the file this one is about to + // rename over the live binary. + let tmp_path = parent.join(format!(".temps-upgrade-tmp.{}", std::process::id())); // Write the new binary to temp file fs::write(&tmp_path, new_binary) @@ -1576,14 +1579,17 @@ mod tests { #[test] fn test_normalize_release_tag_blocks_path_traversal() { // The exploit this validation exists for: the `url` crate resolves - // `..` segments, so these escape gotempsh/temps and reach an arbitrary - // repository's release — whose asset would then be installed. + // `..` segments, so an unvalidated tag escapes gotempsh/temps and + // reaches an arbitrary repository's release — whose asset would then + // be downloaded, checksum-matched against ITS OWN published hash, + // executed by the preflight and installed over the running binary. for input in [ "v/../../../../../rust-lang/rust/releases/latest", "v1.2.3/../../../../../owner/repo/releases/latest", "../../owner/repo/releases/latest", "v1.2.3/..", "v1.2.3/extra", + "v1.2.3%2f..%2fowner", ] { assert!( normalize_release_tag(input).is_err(), @@ -1593,7 +1599,7 @@ mod tests { } #[test] - fn test_normalize_release_tag_blocks_encoding_and_injection_tricks() { + fn test_normalize_release_tag_blocks_malformed_tags() { for input in [ "", " ", @@ -1601,8 +1607,6 @@ mod tests { "v1.2", "v1.2.3.4", "v1.2.x", - "v1.2.3-beta/4", - "v1.2.3-beta%2F4", "v1.2.3-beta 4", "v1.2.3-", "v1.2.3-beta..4", diff --git a/crates/temps-config/src/handler.rs b/crates/temps-config/src/handler.rs index d9b38134e..ed1778cae 100644 --- a/crates/temps-config/src/handler.rs +++ b/crates/temps-config/src/handler.rs @@ -329,6 +329,9 @@ pub struct DockerRegistrySettingsMasked { impl From for AppSettingsResponse { fn from(settings: AppSettings) -> Self { + // Resolved before the literal below starts moving fields out of + // `settings`; absence means "never configured", which reads as default. + let self_update = settings.self_update(); Self { external_url: settings.external_url, internal_url: settings.internal_url, @@ -427,7 +430,7 @@ impl From for AppSettingsResponse { cluster_dns: settings.cluster_dns, build_limits: settings.build_limits, ai_chat_limits: settings.ai_chat_limits, - self_update: settings.self_update, + self_update, } } } @@ -961,10 +964,13 @@ pub struct StartUpdateResponse { /// capability the operator may have deliberately turned off. async fn load_self_update_policy(app_state: &SettingsState) -> temps_core::SelfUpdatePolicy { match app_state.config_service.get_settings().await { - Ok(settings) => temps_core::SelfUpdatePolicy { - enabled: settings.self_update.enabled, - channel: settings.self_update.channel, - }, + Ok(settings) => { + let self_update = settings.self_update(); + temps_core::SelfUpdatePolicy { + enabled: self_update.enabled, + channel: self_update.channel, + } + } Err(e) => { error!("Could not read self-update settings, treating as disabled: {e}"); temps_core::SelfUpdatePolicy { @@ -1092,7 +1098,14 @@ async fn get_update_capability( channel_is_pinned: capability.channel_is_pinned, supervisor: capability.supervisor, restart_mode: capability.restart_mode, - binary_path: capability.binary_path, + // Host filesystem layout is only useful to someone who can actually + // run an update; readers with `settings:read` alone get nothing from + // it but a hint about where the install lives. + binary_path: if allowed { + capability.binary_path + } else { + String::new() + }, phase: capability.phase, phase_error: capability.phase_error, last_attempt: capability.last_attempt, @@ -1194,14 +1207,20 @@ async fn start_update( fn self_update_error_to_problem(error: temps_core::SelfUpdateError) -> Problem { use temps_core::{SelfUpdateBlocker, SelfUpdateError}; let status = match error { - // Every blocker describes current state that the caller can change - // (a flag, a setting, a running attempt, the host itself) rather than a - // malformed request, so they are all conflicts. + // These describe current state the caller can change (a flag, a + // setting, a running attempt) rather than a malformed request. SelfUpdateError::Unavailable { .. } | SelfUpdateError::AlreadyRunning { .. } => { StatusCode::CONFLICT } + // A bad argument, not a state of the install. + SelfUpdateError::InvalidVersion { .. } => StatusCode::BAD_REQUEST, + }; + let Some(blocker) = error.blocker() else { + return ErrorBuilder::new(status) + .title("Invalid Version") + .detail(error.to_string()) + .build(); }; - let blocker = error.blocker(); let title = match blocker { SelfUpdateBlocker::DisabledByFlag | SelfUpdateBlocker::DisabledBySetting => { "Self-Update Disabled" @@ -1339,6 +1358,22 @@ fn preserve_self_recorded_fields(incoming: &mut AppSettings, current: &AppSettin incoming.console_version = current.console_version.clone(); } +/// Keep security-relevant settings the client did not mention. +/// +/// The settings PUT replaces the whole document and `AppSettings` deserializes +/// with `#[serde(default)]`, so a field a client omits is indistinguishable +/// from one it reset. That is harmless for presentation settings and dangerous +/// for `self_update`: an operator who deliberately forbade console updates +/// would have that silently undone by any unrelated save from a client built +/// before the field existed — including a published CLI, or a stale browser +/// tab. Absence therefore means "leave it alone", and only an explicit value +/// changes it. +fn preserve_omitted_security_fields(incoming: &mut AppSettings, current: &AppSettings) { + if incoming.self_update.is_none() { + incoming.self_update = current.self_update.clone(); + } +} + /// Trim and validate an optional URL setting (`external_url`/`internal_url`). /// A blank value (after trimming) means "unset" and is normalized to `None` /// rather than rejected -- `external_url` previously validated the raw @@ -1573,6 +1608,7 @@ async fn update_settings( // `#[serde(default)]` → None). Done first, before any field is moved // out of `current_settings` below. preserve_self_recorded_fields(&mut settings, ¤t_settings); + preserve_omitted_security_fields(&mut settings, ¤t_settings); // Per-provider credentials: keep existing unless caller supplied a new one for (id, current_cfg) in current_settings.agent_sandbox.providers.iter() { @@ -2026,6 +2062,72 @@ mod tests { use super::*; use temps_core::{AgentSandboxSettings, AiChatLimitsSettings, AppSettings, ProviderConfig}; + /// An operator's decision to forbid console updates must survive a save + /// from a client that has never heard of the field. + /// + /// `AppSettings` deserializes with `#[serde(default)]` and the PUT replaces + /// the whole document, so an omitted `self_update` used to come back as + /// "enabled" — silently re-arming the server's ability to replace its own + /// binary. Regression test for that: absence means "leave it alone". + #[test] + fn omitting_self_update_preserves_the_stored_value() { + let current = AppSettings { + self_update: Some(temps_core::SelfUpdateSettings { + enabled: false, + channel: Some("stable".to_string()), + }), + ..AppSettings::default() + }; + // What serde produces for a body that never mentioned the field. + let mut incoming = AppSettings { + self_update: None, + ..AppSettings::default() + }; + + preserve_omitted_security_fields(&mut incoming, ¤t); + + let effective = incoming.self_update(); + assert!( + !effective.enabled, + "an omitted self_update must not re-enable console updates" + ); + assert_eq!(effective.channel.as_deref(), Some("stable")); + } + + /// An explicit value still wins — this is a preserve, not a freeze. + #[test] + fn an_explicit_self_update_value_overrides_the_stored_one() { + let current = AppSettings { + self_update: Some(temps_core::SelfUpdateSettings { + enabled: false, + channel: None, + }), + ..AppSettings::default() + }; + let mut incoming = AppSettings { + self_update: Some(temps_core::SelfUpdateSettings { + enabled: true, + channel: Some("beta".to_string()), + }), + ..AppSettings::default() + }; + + preserve_omitted_security_fields(&mut incoming, ¤t); + + let effective = incoming.self_update(); + assert!(effective.enabled); + assert_eq!(effective.channel.as_deref(), Some("beta")); + } + + /// A never-configured install reads as the documented default. + #[test] + fn absent_self_update_reads_as_enabled_by_default() { + let settings = AppSettings::default(); + assert!(settings.self_update.is_none()); + assert!(settings.self_update().enabled); + assert_eq!(settings.self_update().channel, None); + } + /// The stored value and the effective value must be the same number. /// /// The runtime clamps on read, so an out-of-range value could never break diff --git a/crates/temps-core/src/app_settings.rs b/crates/temps-core/src/app_settings.rs index 9fc85dcf5..39611fe24 100644 --- a/crates/temps-core/src/app_settings.rs +++ b/crates/temps-core/src/app_settings.rs @@ -128,8 +128,15 @@ pub struct AppSettings { /// write settings can also turn it back on. Operators who need an upgrade /// path that no console session can re-open should start the server with /// `--disable-self-update`, which wins over this field unconditionally. + /// `None` means the client did not express an opinion, NOT "reset to + /// default". Every other field on this struct is safe to re-default on a + /// partial write, but this one gates whether the server may replace its own + /// binary — silently flipping it back on because an older client PUT a + /// settings document without it would undo a deliberate security decision. + /// The update handler preserves the stored value when this is absent; read + /// it through `self_update()`. #[serde(default)] - pub self_update: SelfUpdateSettings, + pub self_update: Option, /// Binary version tag (e.g. "v0.1.0") of the *console* process /// (`temps serve`, role=all or role=console) that last started. Written @@ -915,12 +922,21 @@ impl Default for AppSettings { observability_retention: ObservabilityRetentionSettings::default(), setup_complete: false, require_mfa_for_admins: false, - self_update: SelfUpdateSettings::default(), + self_update: None, console_version: None, } } } +impl AppSettings { + /// Effective self-update settings, treating "never configured" as the + /// default. Use this everywhere instead of touching the `Option` directly, + /// so absence and an explicit default behave identically at read time. + pub fn self_update(&self) -> SelfUpdateSettings { + self.self_update.clone().unwrap_or_default() + } +} + /// Controls the console's one-click "Update now" action. #[derive(Debug, Clone, Serialize, Deserialize, ToSchema, PartialEq, Eq)] #[serde(default)] diff --git a/crates/temps-core/src/self_update.rs b/crates/temps-core/src/self_update.rs index 344a1966f..bc8d590e5 100644 --- a/crates/temps-core/src/self_update.rs +++ b/crates/temps-core/src/self_update.rs @@ -295,14 +295,21 @@ pub enum SelfUpdateError { }, #[error("An update is already running (phase: {phase})")] AlreadyRunning { phase: &'static str }, + /// The pinned version is not a release tag this install will accept. + /// Rejected before any work starts so the caller gets a straight answer + /// instead of a background failure they have to go looking for. + #[error("{reason}")] + InvalidVersion { reason: String }, } impl SelfUpdateError { /// The blocker behind this error, for mapping to a response body. - pub fn blocker(&self) -> SelfUpdateBlocker { + pub fn blocker(&self) -> Option { match self { - Self::Unavailable { blocker, .. } => *blocker, - Self::AlreadyRunning { .. } => SelfUpdateBlocker::InProgress, + Self::Unavailable { blocker, .. } => Some(*blocker), + Self::AlreadyRunning { .. } => Some(SelfUpdateBlocker::InProgress), + // Not a state of the install — a bad argument. + Self::InvalidVersion { .. } => None, } } } @@ -398,7 +405,17 @@ mod tests { let err = SelfUpdateError::AlreadyRunning { phase: "downloading", }; - assert_eq!(err.blocker(), SelfUpdateBlocker::InProgress); + assert_eq!(err.blocker(), Some(SelfUpdateBlocker::InProgress)); + } + + #[test] + fn test_invalid_version_is_not_an_install_blocker() { + // A bad argument says nothing about the install's capability, so it + // must not be reported as one (it maps to 400, not 409). + let err = SelfUpdateError::InvalidVersion { + reason: "bad tag".to_string(), + }; + assert_eq!(err.blocker(), None); } #[test] diff --git a/web/src/pages/settings/VersionPage.tsx b/web/src/pages/settings/VersionPage.tsx index 133abe3fd..365efe98c 100644 --- a/web/src/pages/settings/VersionPage.tsx +++ b/web/src/pages/settings/VersionPage.tsx @@ -187,9 +187,7 @@ export function VersionPage() { currentVersion={capability?.current_version ?? null} releaseUrl={latest?.release_url ?? status?.release_url ?? null} checked={Boolean(latest)} - error={ - checkForUpdate.error ? String(checkForUpdate.error) : null - } + error={problemDetail(checkForUpdate.error)} canApply={canApply} onUpdate={() => setUpdateOpen(true)} /> @@ -326,6 +324,24 @@ export function VersionPage() { ) } +/** + * Pull the human-readable reason out of a failed request. + * + * The API returns RFC 7807 Problem Details, and `String(err)` on that object + * renders "[object Object]" — i.e. the user is told something failed but never + * why, which is exactly the state this page exists to avoid. + */ +function problemDetail(error: unknown): string | null { + if (!error) return null + const problem = error as { detail?: string; title?: string; message?: string } + return ( + problem.detail ?? + problem.title ?? + problem.message ?? + 'The release check failed.' + ) +} + function ManualCommand({ command }: { command: string }) { return (
From 57cce52c01e31b05f3cd8f7ff7601ff352fe856b Mon Sep 17 00:00:00 2001 From: David Viejo Date: Fri, 7 Aug 2026 12:00:29 +0200 Subject: [PATCH 5/7] style(cli): canonicalize openapi.json key order and formatting The committed spec was written in whatever key order serde produced, so every regeneration reordered large unrelated blocks, and writing the server's minified response over it reported ~92,000 deletions. Sort keys recursively, two-space indent, trailing newline. This commit is a pure reformat -- the parsed document is byte-identical in meaning to the previous one -- and exists so later diffs are proportional to the API change rather than to serde's iteration order. --- apps/temps-cli/openapi.json | 92061 +++++++++++++++++++++++++++++++++- 1 file changed, 92060 insertions(+), 1 deletion(-) diff --git a/apps/temps-cli/openapi.json b/apps/temps-cli/openapi.json index f50324de9..f319005a3 100644 --- a/apps/temps-cli/openapi.json +++ b/apps/temps-cli/openapi.json @@ -1 +1,92060 @@ -{"openapi":"3.1.0","info":{"title":"Temps","description":"An API for managing projects, deployments, and infrastructure resources","contact":{"name":"Temps Support","url":"https://temps.sh"},"version":"1.0.0"},"servers":[{"url":"/api","description":"Base path for all API endpoints"}],"paths":{"/.well-known/temps.json":{"get":{"tags":["Platform"],"summary":"Get platform information","operationId":"get_platform_info","responses":{"200":{"description":"Successfully retrieved platform information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlatformInfo"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/0/organizations/{org_slug}/chunk-upload/":{"get":{"tags":["sentry-compat"],"summary":"Chunk upload options (stub for sentry-cli compatibility).","description":"sentry-cli checks this endpoint to determine if chunk-based upload is supported.\nWe return a response indicating that chunk upload is NOT supported, which forces\nsentry-cli to fall back to the standard file-by-file upload.","operationId":"chunk_upload_options","parameters":[{"name":"org_slug","in":"path","description":"Organization slug (ignored)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Chunk upload options","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryChunkUploadResponse"}}}}}}},"/0/organizations/{org_slug}/releases/":{"post":{"tags":["sentry-compat"],"summary":"Create a release (stub for sentry-cli compatibility).","description":"sentry-cli calls this before uploading files. Since Temps implicitly creates\nreleases when source maps are uploaded, this is a no-op that returns the\nexpected response format.","operationId":"create_release","parameters":[{"name":"org_slug","in":"path","description":"Organization slug (ignored in single-tenant mode)","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryCreateReleaseRequest"}}},"required":true},"responses":{"201":{"description":"Release created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryReleaseResponse"}}}},"401":{"description":"Unauthorized"}}}},"/0/projects/{org_slug}/{project_slug}/releases/":{"post":{"tags":["sentry-compat"],"summary":"Create a release for a specific project (stub for sentry-cli compatibility).","description":"sentry-cli calls this endpoint (instead of /organizations/.../releases/) when\nboth SENTRY_ORG and SENTRY_PROJECT env vars are set. Behaves identically to\nthe organizations endpoint but validates the project slug.","operationId":"create_project_release","parameters":[{"name":"org_slug","in":"path","description":"Organization slug (ignored in single-tenant mode)","required":true,"schema":{"type":"string"}},{"name":"project_slug","in":"path","description":"Project slug or numeric ID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryCreateReleaseRequest"}}},"required":true},"responses":{"201":{"description":"Release created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryReleaseResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Project not found"}}}},"/0/projects/{org_slug}/{project_slug}/releases/{version}/":{"put":{"tags":["sentry-compat"],"summary":"Finalize a release (stub for sentry-cli compatibility).","description":"sentry-cli calls `releases finalize` after uploading source maps. This sets\nthe dateReleased on the release. Since Temps stores source maps independently\nof releases, this is a no-op that returns the expected response.","operationId":"finalize_project_release","parameters":[{"name":"org_slug","in":"path","description":"Organization slug (ignored)","required":true,"schema":{"type":"string"}},{"name":"project_slug","in":"path","description":"Project slug or numeric ID","required":true,"schema":{"type":"string"}},{"name":"version","in":"path","description":"Release version to finalize","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Release finalized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryReleaseResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Project not found"}}}},"/0/projects/{org_slug}/{project_slug}/releases/{version}/files/":{"get":{"tags":["sentry-compat"],"summary":"List files for a release.","description":"Returns all source maps stored for a specific release in sentry-cli compatible format.","operationId":"list_release_files","parameters":[{"name":"org_slug","in":"path","description":"Organization slug (ignored)","required":true,"schema":{"type":"string"}},{"name":"project_slug","in":"path","description":"Project slug or numeric ID","required":true,"schema":{"type":"string"}},{"name":"version","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of release files","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SentryReleaseFileResponse"}}}}},"401":{"description":"Unauthorized"},"404":{"description":"Project not found"}}},"post":{"tags":["sentry-compat"],"summary":"Upload a source map file for a release.","description":"Accepts the same multipart format as the Sentry release files API.\nThe `name` field should be the URL path of the file (e.g., `~/dist/bundle.js.map`).\n\nThe route has a 50 MiB body limit applied at the router level (Fix #4).\nA per-field size check provides an additional defense-in-depth layer.","operationId":"upload_release_file","parameters":[{"name":"org_slug","in":"path","description":"Organization slug (ignored)","required":true,"schema":{"type":"string"}},{"name":"project_slug","in":"path","description":"Project slug or numeric ID","required":true,"schema":{"type":"string"}},{"name":"version","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"201":{"description":"File uploaded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryReleaseFileResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"404":{"description":"Project not found"},"413":{"description":"Source map file exceeds the 50 MiB per-field limit"}}}},"/_temps/event":{"post":{"tags":["Metrics"],"summary":"Record analytics event","operationId":"record_event_metrics","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventMetricsPayload"}}},"required":true},"responses":{"204":{"description":"Event recorded successfully"},"400":{"description":"Bad request"},"500":{"description":"Internal server error"}}}},"/_temps/session-replay/events":{"post":{"tags":["Analytics"],"summary":"Add events to existing session replay","operationId":"add_session_replay_events","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionReplayEventsRequest"}}},"required":true},"responses":{"200":{"description":"Events added successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddEventsResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Session not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/_temps/session-replay/init":{"post":{"tags":["Analytics"],"summary":"Initialize session replay with metadata","operationId":"init_session_replay","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionReplayInitRequest"}}},"required":true},"responses":{"201":{"description":"Session initialized successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionReplayInitResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/_temps/speed":{"post":{"tags":["Performance"],"summary":"Record performance metrics from client","operationId":"record_speed_metrics","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpeedMetricsPayload"}}},"required":true},"responses":{"204":{"description":"Metrics recorded successfully"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Host not found in route table","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/_temps/speed/update":{"post":{"tags":["Performance"],"summary":"Update late performance metrics","operationId":"update_speed_metrics","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSpeedMetricsPayload"}}},"required":true},"responses":{"204":{"description":"Metrics updated successfully"},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Host not found or metrics not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/admin/gate-settings":{"get":{"tags":["AdminGate"],"operationId":"get_admin_gate","responses":{"200":{"description":"Current admin gate config","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminGateResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["AdminGate"],"operationId":"patch_admin_gate","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAdminGateRequest"}}},"required":true},"responses":{"200":{"description":"Updated admin gate config","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminGateResponse"}}}},"400":{"description":"Invalid IP/CIDR/host"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"409":{"description":"Env-overridden or would lock out caller"}},"security":[{"bearer_auth":[]}]}},"/admin/oidc/providers":{"get":{"tags":["Authentication"],"operationId":"list_oidc_providers","responses":{"200":{"description":"OIDC providers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/OidcProviderResponse"}}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Authentication"],"operationId":"create_oidc_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateOidcProviderRequest"}}},"required":true},"responses":{"201":{"description":"OIDC provider created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OidcProviderResponse"}}}},"409":{"description":"Another OIDC provider already uses that name"}},"security":[{"bearer_auth":[]}]}},"/admin/oidc/providers/{provider_id}":{"delete":{"tags":["Authentication"],"operationId":"delete_oidc_provider","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"OIDC provider deleted"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Authentication"],"operationId":"update_oidc_provider","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateOidcProviderRequest"}}},"required":true},"responses":{"200":{"description":"OIDC provider updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OidcProviderResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/admin/oidc/providers/{provider_id}/role-mappings":{"get":{"tags":["Authentication"],"operationId":"list_oidc_role_mappings","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"OIDC role mappings","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/OidcRoleMappingResponse"}}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Authentication"],"operationId":"create_oidc_role_mapping","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateOidcRoleMappingRequest"}}},"required":true},"responses":{"201":{"description":"Role mapping created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OidcRoleMappingResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/admin/oidc/providers/{provider_id}/test":{"post":{"tags":["Authentication"],"operationId":"test_oidc_provider","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Connection test result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OidcTestConnectionResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/admin/oidc/providers/{provider_id}/users":{"get":{"tags":["Authentication"],"operationId":"list_oidc_provider_users","parameters":[{"name":"provider_id","in":"path","description":"OIDC provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Users authenticated via this OIDC provider","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/OidcProviderUserResponse"}}}}},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]}},"/admin/oidc/role-mappings/{mapping_id}":{"delete":{"tags":["Authentication"],"operationId":"delete_oidc_role_mapping","parameters":[{"name":"mapping_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Role mapping deleted"}},"security":[{"bearer_auth":[]}]}},"/agents/webhook/{webhook_id}":{"post":{"tags":["Agents"],"summary":"Public webhook endpoint. Authenticated via `X-Webhook-Token` header.","description":"`POST /api/agents/webhook/{webhook_id}`\nHeader: `X-Webhook-Token: `\n\nThe `webhook_id` in the URL is a short non-secret identifier (safe to log).\nThe actual credential is the secret token in the header.\n\nAccepts any JSON body, which is passed as `user_context` to the agent run.","operationId":"webhook_trigger","parameters":[{"name":"webhook_id","in":"path","description":"Webhook ID (non-secret)","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookTriggerRequest"}}},"required":true},"responses":{"202":{"description":"Agent run created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookTriggerResponse"}}}},"401":{"description":"Missing or invalid X-Webhook-Token header"},"404":{"description":"Invalid webhook ID"},"422":{"description":"Agent disabled"}}}},"/ai/conversations":{"get":{"tags":["AI Chat"],"summary":"List every active conversation across all projects, most-recently-active\nfirst, annotated with project name/slug. Powers the unified \"all chats\"\nswitcher in the AI assistant dock.","operationId":"list_all_conversations","responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GlobalConversationResponse"}}}}},"401":{"description":""},"403":{"description":""}},"security":[{"bearer_auth":[]}]}},"/ai/pricing":{"get":{"tags":["AI Gateway Pricing"],"operationId":"get_pricing","responses":{"200":{"description":"Model pricing information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PricingResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/providers":{"get":{"tags":["AI Gateway Admin"],"operationId":"list_provider_keys","responses":{"200":{"description":"List of provider keys","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProviderKeyResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["AI Gateway Admin"],"operationId":"create_provider_key","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProviderKeyRequest"}}},"required":true},"responses":{"201":{"description":"Provider key created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderKeyResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/providers/test":{"post":{"tags":["AI Gateway Admin"],"operationId":"test_provider_key_inline","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestProviderKeyRequest"}}},"required":true},"responses":{"200":{"description":"Test result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestProviderKeyResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/providers/{id}":{"delete":{"tags":["AI Gateway Admin"],"operationId":"delete_provider_key","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Provider key deleted"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["AI Gateway Admin"],"operationId":"update_provider_key","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProviderKeyRequest"}}},"required":true},"responses":{"200":{"description":"Provider key updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderKeyResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/providers/{id}/test":{"post":{"tags":["AI Gateway Admin"],"operationId":"test_provider_key_by_id","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Test result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestProviderKeyResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Provider key not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/usage/by-provider":{"get":{"tags":["AI Gateway Usage"],"operationId":"get_usage_by_provider","parameters":[{"name":"from","in":"query","description":"ISO 8601 start time (defaults to 24h ago)","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","description":"ISO 8601 end time (defaults to now)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Usage broken down by provider","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProviderUsage"}}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/usage/conversations":{"get":{"tags":["AI Gateway Usage"],"operationId":"get_conversations","parameters":[{"name":"from","in":"query","description":"ISO 8601 start time (defaults to 24h ago)","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","description":"ISO 8601 end time (defaults to now)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max results (defaults to 50, max 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"user_id","in":"query","description":"Filter by user ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"tags","in":"query","description":"Filter by tags (comma-separated)","required":false,"schema":{"type":"string"}},{"name":"model","in":"query","description":"Filter by model name","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Conversation summaries","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ConversationSummary"}}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/usage/conversations/{conversation_id}":{"get":{"tags":["AI Gateway Usage"],"operationId":"get_conversation_detail","parameters":[{"name":"conversation_id","in":"path","description":"Conversation ID","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max results (defaults to 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Invocations within a conversation","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/UsageLogEntry"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/usage/recent":{"get":{"tags":["AI Gateway Usage"],"operationId":"get_usage_recent","parameters":[{"name":"limit","in":"query","description":"Page size (defaults to 20, max 50)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"offset","in":"query","description":"Number of results to skip for pagination (defaults to 0)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"provider","in":"query","description":"Filter by provider name","required":false,"schema":{"type":"string"}},{"name":"model","in":"query","description":"Filter by model name","required":false,"schema":{"type":"string"}},{"name":"status","in":"query","description":"Filter by HTTP status code (exact match)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"cost_gte","in":"query","description":"Cost greater-than-or-equal, in microcents","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"cost_gt","in":"query","description":"Cost strictly greater-than, in microcents","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"cost_lte","in":"query","description":"Cost less-than-or-equal, in microcents","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"cost_lt","in":"query","description":"Cost strictly less-than, in microcents","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"tokens_gte","in":"query","description":"Total tokens greater-than-or-equal","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"tokens_gt","in":"query","description":"Total tokens strictly greater-than","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"tokens_lte","in":"query","description":"Total tokens less-than-or-equal","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"tokens_lt","in":"query","description":"Total tokens strictly less-than","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Page of recent usage log entries","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsageLogPage"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/usage/summary":{"get":{"tags":["AI Gateway Usage"],"operationId":"get_usage_summary","parameters":[{"name":"from","in":"query","description":"ISO 8601 start time (defaults to 24h ago)","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","description":"ISO 8601 end time (defaults to now)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Usage summary for the time range","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsageSummary"}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/usage/timeseries":{"get":{"tags":["AI Gateway Usage"],"operationId":"get_usage_timeseries","parameters":[{"name":"from","in":"query","description":"ISO 8601 start time (defaults to 24h ago)","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","description":"ISO 8601 end time (defaults to now)","required":false,"schema":{"type":"string"}},{"name":"bucket","in":"query","description":"Bucket size: hour, day, week (defaults to day)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Time-series usage data","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TimeseriesBucket"}}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/usage/top-models":{"get":{"tags":["AI Gateway Usage"],"operationId":"get_usage_top_models","parameters":[{"name":"from","in":"query","description":"ISO 8601 start time (defaults to 24h ago)","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","description":"ISO 8601 end time (defaults to now)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max results (defaults to 10)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Top models by request count","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ModelUsage"}}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/v1/chat/completions":{"post":{"tags":["AI Gateway"],"operationId":"chat_completions","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatCompletionRequest"}}},"required":true},"responses":{"200":{"description":"Chat completion response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatCompletionResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}},"404":{"description":"Model not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/v1/embeddings":{"post":{"tags":["AI Gateway"],"operationId":"embeddings","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmbeddingRequest"}}},"required":true},"responses":{"200":{"description":"Embedding response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmbeddingResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}},"404":{"description":"Model not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/ai/v1/models":{"get":{"tags":["AI Gateway"],"operationId":"list_models","responses":{"200":{"description":"List of available models","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelListResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAiErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/analytics/active-visitors":{"get":{"tags":["Analytics"],"summary":"Get detailed active visitors","operationId":"get_analytics_active_visitors","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Deployment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"window_minutes","in":"query","description":"Time window in minutes for active visitors (default: 5)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved active visitors","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActiveVisitorsResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/event-detail":{"get":{"tags":["Analytics"],"summary":"Get detailed analytics for a specific event","operationId":"get_event_detail","parameters":[{"name":"event_name","in":"query","description":"Event name to get details for","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date (ISO 8601)","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date (ISO 8601)","required":true,"schema":{"type":"string"}},{"name":"bucket_interval","in":"query","description":"Bucket interval: hour, day, week, month (default: auto)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved event details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventDetailResponse"}}}},"400":{"description":"Invalid parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/event-entries":{"get":{"tags":["Analytics"],"summary":"Get paginated list of raw occurrences of a specific event, including custom JSON properties","operationId":"get_event_entries","parameters":[{"name":"event_name","in":"query","description":"Event name to list occurrences for","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date (ISO 8601)","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date (ISO 8601)","required":true,"schema":{"type":"string"}},{"name":"page","in":"query","description":"Page number (1-based, default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Items per page (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Successfully retrieved event entries","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventEntriesResponse"}}}},"400":{"description":"Invalid parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/event-visitors":{"get":{"tags":["Analytics"],"summary":"Get paginated list of visitors who triggered a specific event","operationId":"get_event_visitors","parameters":[{"name":"event_name","in":"query","description":"Event name to list visitors for","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date (ISO 8601)","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date (ISO 8601)","required":true,"schema":{"type":"string"}},{"name":"page","in":"query","description":"Page number (1-based, default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Items per page (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Successfully retrieved event visitors","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventVisitorsResponse"}}}},"400":{"description":"Invalid parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/events":{"get":{"tags":["Analytics"],"operationId":"get_analytics_events_count","parameters":[{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"limit","in":"query","description":"Maximum number of results to return","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"custom_events_only","in":"query","description":"Only return custom events, excluding system events like page_view, page_leave, heartbeat (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"breakdown","in":"query","description":"Breakdown by geography: 'country', 'region', or 'city' (optional)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved event counts","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EventCount"}}}}},"400":{"description":"Invalid date format, missing required parameters, or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/general-stats":{"get":{"tags":["Analytics"],"summary":"Get general statistics across all projects for a time frame","operationId":"get_general_stats","parameters":[{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"project_ids","in":"query","description":"Optional: Filter by specific project IDs (comma-separated)","required":false,"schema":{"type":"array","items":{"type":"integer","format":"int32"}}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"include_project_breakdown","in":"query","description":"Whether to include per-project breakdown (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Successfully retrieved general statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GeneralStatsResponse"}}}},"400":{"description":"Invalid date format or parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/has-events":{"get":{"tags":["Analytics"],"operationId":"check_analytics_has_events","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Analytics events existence check","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HasAnalyticsEventsResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/live-visitors":{"get":{"tags":["Analytics"],"summary":"Get list of currently live visitors from visitor table","operationId":"get_live_visitors_list","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"window_minutes","in":"query","description":"Time window in minutes for live visitors (default: 5)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved live visitors list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LiveVisitorsListResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/page-flow":{"get":{"tags":["Analytics"],"summary":"Get page flow analytics: entry pages, exit pages, drop-off points, and page transitions","operationId":"get_page_flow","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max entry/exit pages to return (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"transitions_limit","in":"query","description":"Max page transitions to return (default: 50, max: 200)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"min_views_for_dropoff","in":"query","description":"Minimum views for drop-off analysis (default: 5)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved page flow analytics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PageFlowResponse"}}}},"400":{"description":"Invalid parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/page-hourly-sessions":{"get":{"tags":["Analytics"],"operationId":"get_page_hourly_sessions","parameters":[{"name":"page_path","in":"query","description":"The page path to get sessions for","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_time","in":"query","description":"Start time in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"bucket_interval","in":"query","description":"Bucket interval: 'hour', 'day', 'week', or 'month' (default: auto-determined based on range)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved page sessions with time buckets","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PageHourlySessionsResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/page-path-detail":{"get":{"tags":["Analytics"],"summary":"Get detailed analytics for a specific page path\nReturns visitors, page views, activity over time, geographic distribution, and referrers","operationId":"get_page_path_detail","parameters":[{"name":"page_path","in":"query","description":"The page path to get details for (URL-encoded)","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"bucket_interval","in":"query","description":"Bucket interval for time series: 'hour', 'day', 'week', 'month' (default: auto based on date range)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved page path detail analytics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PagePathDetailResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/page-path-visitors":{"get":{"tags":["Analytics"],"summary":"Get individual visitor sessions for a specific page path","operationId":"get_page_path_visitors","parameters":[{"name":"page_path","in":"query","description":"The page path to get visitors for (URL-encoded)","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"page","in":"query","description":"Page number (1-based, default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Items per page (default: 50, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Successfully retrieved page path visitors","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PagePathVisitorsResponse"}}}},"400":{"description":"Invalid parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/page-paths":{"get":{"tags":["Analytics"],"operationId":"get_page_paths","parameters":[{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS (optional)","required":false,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS (optional)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Maximum number of page paths to return (default: 100, max: 1000)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved page paths","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PagePathsResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/page-paths-sparklines":{"get":{"tags":["Analytics"],"operationId":"get_page_paths_sparklines","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_time","in":"query","description":"Start time in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time in ISO 8601 format","required":true,"schema":{"type":"string"}},{"name":"page_paths","in":"query","description":"Comma-separated list of page paths","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sparkline data for all requested page paths","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PagePathsSparklineResponse"}}}},"400":{"description":"Invalid parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/recent-activity":{"get":{"tags":["Analytics"],"summary":"Get recent activity events for real-time activity feed","operationId":"get_recent_activity","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"since_id","in":"query","description":"Return events with ID greater than this (cursor-based polling)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"limit","in":"query","description":"Max events to return (default: 50, max: 100)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved recent activity events","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecentActivityResponse"}}}},"400":{"description":"Invalid parameters"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/sessions/{session_id}":{"get":{"tags":["Analytics"],"summary":"Get detailed information about a specific session including events and request logs","operationId":"get_session_details","parameters":[{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved session details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionDetails"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Session not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/sessions/{session_id}/events":{"get":{"tags":["Analytics"],"operationId":"get_analytics_session_events","parameters":[{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS","required":false,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Number of results to return (default: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"offset","in":"query","description":"Number of results to skip (default: 0)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved session events","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionEventsResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Session not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/sessions/{session_id}/logs":{"get":{"tags":["Analytics"],"operationId":"get_session_logs","parameters":[{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS","required":false,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Number of results to return (default: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"offset","in":"query","description":"Number of results to skip (default: 0)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved session logs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionLogsResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Session not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitor-facets":{"get":{"tags":["Analytics"],"summary":"Get filter dropdown contents for the visitors page. Returns the top\nvalues per dimension with distinct visitor counts so the UI can render\n\"Country — 1,234 visitors\" rows. Each dimension is computed against the\nsegment minus its own filter, so a selected value never collapses its\nown dropdown.","operationId":"get_visitor_facets","parameters":[{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"include_crawlers","in":"query","description":"Include crawlers (default: false)","required":false,"schema":{"type":"boolean"}},{"name":"has_activity_only","in":"query","description":"Hide ghost visitors (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"per_facet_limit","in":"query","description":"Top N values per dimension (default: 50, max: 200)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"filter_country","in":"query","description":"Geolocation country","required":false,"schema":{"type":"string"}},{"name":"filter_region","in":"query","description":"Geolocation region","required":false,"schema":{"type":"string"}},{"name":"filter_city","in":"query","description":"Geolocation city","required":false,"schema":{"type":"string"}},{"name":"filter_channel","in":"query","description":"First-touch channel","required":false,"schema":{"type":"string"}},{"name":"filter_referrer","in":"query","description":"First-touch referrer hostname (use 'Direct' for null)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Top values per dimension","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorFacets"}}}},"400":{"description":"Invalid date format or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors":{"get":{"tags":["Analytics"],"summary":"Get list of visitors with summary information","operationId":"get_visitors","parameters":[{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"include_crawlers","in":"query","description":"Include crawlers (default: false)","required":false,"schema":{"type":"boolean"}},{"name":"limit","in":"query","description":"Maximum number of visitors to return (default: 50)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"offset","in":"query","description":"Number of visitors to skip (default: 0)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"has_activity_only","in":"query","description":"Filter to only include visitors with recorded activity (events/sessions). When true, excludes ghost visitors (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"filter_country","in":"query","description":"Geolocation country","required":false,"schema":{"type":"string"}},{"name":"filter_region","in":"query","description":"Geolocation region","required":false,"schema":{"type":"string"}},{"name":"filter_city","in":"query","description":"Geolocation city","required":false,"schema":{"type":"string"}},{"name":"filter_channel","in":"query","description":"First-touch channel","required":false,"schema":{"type":"string"}},{"name":"filter_referrer","in":"query","description":"First-touch referrer hostname (use 'Direct' for null)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved visitors","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorsResponse"}}}},"400":{"description":"Invalid date format, missing required parameters, or project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/guid/{visitor_id}":{"get":{"tags":["Analytics"],"summary":"Get visitor by GUID with geolocation data","operationId":"get_visitor_by_guid","parameters":[{"name":"visitor_id","in":"path","description":"Visitor GUID (supports enc_ prefix for encrypted IDs)","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved visitor with geolocation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorWithGeolocation"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/id/{id}":{"get":{"tags":["Analytics"],"summary":"Get visitor by numeric ID with geolocation data","operationId":"get_visitor_by_id","parameters":[{"name":"id","in":"path","description":"Visitor numeric ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved visitor with geolocation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorWithGeolocation"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/{visitor_id}":{"get":{"tags":["Analytics"],"summary":"Get detailed information about a specific visitor by numeric ID","operationId":"get_visitor_details","parameters":[{"name":"visitor_id","in":"path","description":"Visitor numeric ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved visitor details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorDetails"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/{visitor_id}/enrich":{"put":{"tags":["Analytics"],"operationId":"enrich_visitor","parameters":[{"name":"visitor_id","in":"path","description":"Visitor ID - can be numeric ID, GUID, or encrypted GUID (enc_xxx)","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnrichVisitorRequest"}}},"required":true},"responses":{"200":{"description":"Successfully enriched visitor data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnrichVisitorResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/{visitor_id}/info":{"get":{"tags":["Analytics"],"summary":"Get visitor record from database","operationId":"get_visitor_info","parameters":[{"name":"visitor_id","in":"path","description":"Visitor numeric ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved visitor info","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorRecord"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/{visitor_id}/journey":{"get":{"tags":["Analytics"],"summary":"Get the complete visitor journey: all events across all sessions, grouped by session","operationId":"get_visitor_journey","parameters":[{"name":"visitor_id","in":"path","description":"Visitor numeric ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"limit_sessions","in":"query","description":"Maximum number of sessions to return (default: 50)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved visitor journey","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorJourneyResponse"}}}},"400":{"description":"Invalid parameters"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/{visitor_id}/sessions":{"get":{"tags":["Analytics"],"summary":"Get all sessions for a specific visitor by numeric ID","operationId":"get_analytics_visitor_sessions","parameters":[{"name":"visitor_id","in":"path","description":"Visitor numeric ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"limit","in":"query","description":"Maximum number of sessions to return (default: 100)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved visitor sessions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorSessionsResponse"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/analytics/visitors/{visitor_id}/stats":{"get":{"tags":["Analytics"],"summary":"Get visitor statistics","operationId":"get_visitor_stats","parameters":[{"name":"visitor_id","in":"path","description":"Visitor numeric ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved visitor statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorStats"}}}},"400":{"description":"Invalid parameters or project not found"},"404":{"description":"Visitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/api-keys":{"get":{"tags":["API Keys"],"operationId":"list_api_keys","parameters":[{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page (default: 20)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"API keys retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["API Keys"],"operationId":"create_api_key","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateApiKeyRequest"}}},"required":true},"responses":{"201":{"description":"API key created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateApiKeyResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"409":{"description":"Conflict - API key name already exists"},"428":{"description":"Recent MFA verification required"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/api-keys/permissions":{"get":{"tags":["API Keys"],"operationId":"get_api_key_permissions","responses":{"200":{"description":"Available permissions and roles retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AvailablePermissions"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/api-keys/{id}":{"get":{"tags":["API Keys"],"operationId":"get_api_key","parameters":[{"name":"id","in":"path","description":"API key ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"API key retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["API Keys"],"operationId":"update_api_key","parameters":[{"name":"id","in":"path","description":"API key ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateApiKeyRequest"}}},"required":true},"responses":{"200":{"description":"API key updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"409":{"description":"Conflict - API key name already exists"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["API Keys"],"operationId":"delete_api_key","parameters":[{"name":"id","in":"path","description":"API key ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"API key deleted successfully"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/api-keys/{id}/activate":{"post":{"tags":["API Keys"],"operationId":"activate_api_key","parameters":[{"name":"id","in":"path","description":"API key ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"API key activated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/api-keys/{id}/deactivate":{"post":{"tags":["API Keys"],"operationId":"deactivate_api_key","parameters":[{"name":"id","in":"path","description":"API key ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"API key deactivated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/api-keys/{id}/rotate":{"post":{"tags":["API Keys"],"operationId":"rotate_api_key","parameters":[{"name":"id","in":"path","description":"API key ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"API key rotated successfully; the response contains the new plaintext secret, shown only once","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateApiKeyResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"428":{"description":"Recent MFA verification required"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/auth/cli/device/approve":{"post":{"tags":["Authentication"],"operationId":"cli_device_approve","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDeviceApproveRequest"}}},"required":true},"responses":{"200":{"description":"Session approved; CLI can now claim the API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDeviceApproveResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Browser session required"},"404":{"description":"Unknown user_code"},"409":{"description":"Already resolved"},"410":{"description":"Session expired"},"428":{"description":"Recent MFA verification required"},"500":{"description":"Internal server error"}},"security":[{"session_token":[]}]}},"/auth/cli/device/deny":{"post":{"tags":["Authentication"],"operationId":"cli_device_deny","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDeviceApproveRequest"}}},"required":true},"responses":{"200":{"description":"Session denied","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDeviceApproveResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Unknown user_code"},"409":{"description":"Already resolved"},"410":{"description":"Session expired"},"500":{"description":"Internal server error"}},"security":[{"session_token":[]}]}},"/auth/cli/device/lookup":{"get":{"tags":["Authentication"],"operationId":"cli_device_lookup","parameters":[{"name":"user_code","in":"query","description":"`user_code` as displayed in the CLI / pasted into the URL.","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Device session metadata","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDeviceLookupResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Unknown user_code"},"410":{"description":"Device session expired"},"500":{"description":"Internal server error"}},"security":[{"session_token":[]}]}},"/auth/cli/device/poll":{"post":{"tags":["Authentication"],"operationId":"cli_device_poll","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDevicePollRequest"}}},"required":true},"responses":{"200":{"description":"Poll result; check `status` field","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDevicePollResponse"}}}},"404":{"description":"Unknown device_code"},"500":{"description":"Internal server error"}}}},"/auth/cli/device/start":{"post":{"tags":["Authentication"],"operationId":"cli_device_start","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDeviceStartRequest"}}},"required":true},"responses":{"200":{"description":"Device session created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliDeviceStartResponse"}}}},"500":{"description":"Internal server error"}}}},"/auth/cli/logout":{"post":{"tags":["Authentication"],"operationId":"cli_logout","responses":{"204":{"description":"API key revoked"},"401":{"description":"Not authenticated"},"403":{"description":"Endpoint requires API key authentication"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/auth/email-status":{"get":{"tags":["Authentication"],"operationId":"email_status","responses":{"200":{"description":"Email configuration status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailStatusResponse"}}}},"500":{"description":"Internal server error"}}}},"/auth/login":{"post":{"tags":["Authentication"],"operationId":"login","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginRequest"}}},"required":true},"responses":{"200":{"description":"Login successful, session cookie set","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthResponse"}}}},"401":{"description":"Invalid credentials, or the account's role requires MFA enrollment that has not been completed"},"500":{"description":"Internal server error"}}}},"/auth/oidc/callback":{"get":{"tags":["Authentication"],"operationId":"oidc_callback","parameters":[{"name":"code","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"state","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"error","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"error_description","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"302":{"description":"Redirect to app with session cookie or login error"}}}},"/auth/oidc/login/{slug}":{"get":{"tags":["Authentication"],"operationId":"start_oidc_login_by_slug","parameters":[{"name":"slug","in":"path","description":"OIDC provider slug (from /email-status or /auth/oidc/providers)","required":true,"schema":{"type":"string"}},{"name":"return_to","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"302":{"description":"Redirect to IdP authorize URL"},"404":{"description":"Provider not found"},"503":{"description":"OIDC provider unreachable"}}}},"/auth/oidc/providers":{"get":{"tags":["Authentication"],"operationId":"list_public_providers","responses":{"200":{"description":"Enabled OIDC providers for login page","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OidcProvidersListResponse"}}}}}}},"/auth/password-change-required":{"post":{"tags":["Authentication"],"operationId":"change_required_password","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RequiredPasswordChangeRequest"}}},"required":true},"responses":{"200":{"description":"Required password change completed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RequiredPasswordChangeResponse"}}}},"400":{"description":"Password does not meet requirements"},"401":{"description":"Password-change session is missing or expired"},"500":{"description":"Internal server error"}}}},"/auth/password-reset/request":{"post":{"tags":["Authentication"],"operationId":"request_password_reset","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailRequest"}}},"required":true},"responses":{"200":{"description":"Reset email sent if account exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthResponse"}}}},"503":{"description":"Email service not configured"}}}},"/auth/password-reset/verify":{"post":{"tags":["Authentication"],"operationId":"reset_password","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResetPasswordRequest"}}},"required":true},"responses":{"200":{"description":"Password reset successful","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthResponse"}}}},"400":{"description":"Invalid or expired token"},"500":{"description":"Internal server error"}}}},"/auth/step-up":{"post":{"tags":["Authentication"],"operationId":"verify_step_up","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyStepUpRequest"}}},"required":true},"responses":{"200":{"description":"Session elevated for sensitive actions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StepUpResponse"}}}},"400":{"description":"Verification code is empty"},"401":{"description":"Invalid code or expired session"},"403":{"description":"Browser session required"},"428":{"description":"MFA setup required"},"429":{"description":"Too many verification attempts"},"500":{"description":"Verification infrastructure failed"}},"security":[{"session_token":[]}]}},"/auth/verify-email":{"get":{"tags":["Authentication"],"operationId":"verify_email","parameters":[{"name":"token","in":"query","description":"Email verification token","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Email verified successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthResponse"}}}},"400":{"description":"Invalid or expired token"},"500":{"description":"Internal server error"}}}},"/auth/verify-mfa":{"post":{"tags":["Authentication"],"operationId":"verify_mfa_challenge","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MfaVerificationRequest"}}},"required":true},"responses":{"204":{"description":"MFA verification successful"},"400":{"description":"Invalid request"},"401":{"description":"Invalid MFA code"},"500":{"description":"Internal server error"}}}},"/backups/alerts":{"get":{"tags":["Backups"],"summary":"List open backup alerts.","description":"Returns all alerts that have not yet been resolved, ordered by `opened_at`\ndescending (newest first). The UI renders these as a banner above the\nBackups page content. Alerts are auto-opened by the watcher and\nauto-resolved when the triggering condition clears.\n\n**Schedule overdue** — the backup scheduler did not enqueue a job within\nthe expected window (1 hour past `next_run`). Usually means the scheduler\ntask is dead or wedged.\n\n**Job stalled** — a `backup_jobs` row has been in `state='pending'` for\nmore than 1 hour. The runner never claimed the job. Usually means the\nrunner task is dead or the runner concurrency cap is too low.","operationId":"list_backup_alerts","responses":{"200":{"description":"List of open backup alerts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupAlertListResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/cleanup":{"post":{"tags":["Backups"],"summary":"Preview or run retention using each selected schedule's configured retention days.","operationId":"cleanup_expired_backups","parameters":[{"name":"dry_run","in":"query","description":"Return the backups selected by retention without deleting anything.","required":false,"schema":{"type":"boolean"}},{"name":"schedule_id","in":"query","description":"Limit cleanup to one backup schedule.","required":false,"schema":{"type":["integer","null"],"format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CleanupExpiredBackupsRequest"}}},"required":true},"responses":{"200":{"description":"Retention cleanup completed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RetentionCleanupReport"}}}},"400":{"description":"Missing or invalid preview candidate list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Schedule or backup not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"409":{"description":"Cleanup preview is stale","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Cleanup could not be started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/external-services/{id}/run":{"post":{"tags":["Backups"],"summary":"Run a backup for an external service manually.","description":"Enqueues the backup for asynchronous execution via the `BackupRunner`\n(ADR-014). Returns `202 Accepted` immediately: pending parent and child\nrows are inserted, and a `backup_jobs` row is enqueued for the resolved\nengine. Poll `GET /backups/{id}` to observe `pending → running → completed`.","operationId":"run_external_service_backup","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RunExternalServiceBackupRequest"}}},"required":true},"responses":{"202":{"description":"Backup enqueued for async execution","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceBackupResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"External service or S3 source not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/external-services/{service_id}/backups":{"get":{"tags":["Backups"],"summary":"List all backups for a specific external service (DB-only, no S3 scan).","description":"Returns a paginated list of backups that belong to this service.\nCompletes in <100 ms regardless of S3 endpoint latency because it\nnever touches S3.","operationId":"list_external_service_backups","parameters":[{"name":"service_id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-based). Defaults to 1.","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"page_size","in":"query","description":"Items per page. Defaults to 20, max 100.","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Paginated list of backups for this service","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceBackupListResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/external-services/{service_id}/schedules":{"get":{"tags":["Backups"],"summary":"List the schedules that target a specific external service. Useful for\nthe service detail page (\"which schedules back this DB up?\").","operationId":"list_service_schedules","parameters":[{"name":"service_id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Schedules backing up this service","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BackupScheduleResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Service not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/s3-sources":{"get":{"tags":["Backups"],"summary":"List all S3 sources","operationId":"list_s3_sources","responses":{"200":{"description":"List of S3 sources","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/S3SourceResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Backups"],"summary":"Create a new S3 source","operationId":"create_s3_source","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateS3SourceRequest"}}},"required":true},"responses":{"201":{"description":"S3 source created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/S3SourceResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/s3-sources/test":{"post":{"tags":["Backups"],"summary":"Test S3 connectivity against a prospective source configuration (before creating it).\nThe credentials are NOT persisted. Useful for validating the form in the UI.","operationId":"test_s3_connection_preview","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateS3SourceRequest"}}},"required":true},"responses":{"200":{"description":"Connection test result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/S3ConnectionTestResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/s3-sources/{id}":{"get":{"tags":["Backups"],"summary":"Get an S3 source by ID","operationId":"get_s3_source","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"S3 source details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/S3SourceResponse"}}}},"404":{"description":"S3 source not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Backups"],"summary":"Delete an S3 source","operationId":"delete_s3_source","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"S3 source deleted"},"404":{"description":"S3 source not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Backups"],"summary":"Update an S3 source","operationId":"update_s3_source","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateS3SourceRequest"}}},"required":true},"responses":{"200":{"description":"S3 source updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/S3SourceResponse"}}}},"404":{"description":"S3 source not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/s3-sources/{id}/backups":{"get":{"tags":["Backups"],"summary":"List all backups in an S3 source","operationId":"list_source_backups","parameters":[{"name":"include_s3_scan","in":"query","description":"When `true`, scan the S3 bucket for backups not tracked in the\nlocal database (useful after disaster-recovery from another Temps\ninstance). Defaults to `false` — the fast DB-only path.","required":false,"schema":{"type":"boolean"}},{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of all backups in the source","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceBackupIndexResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"S3 source not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/backups/s3-sources/{id}/run":{"post":{"tags":["Backups"],"summary":"Run a backup immediately for an S3 source.","description":"Enqueues the backup for asynchronous execution via the `BackupRunner`\n(ADR-014). Returns `202 Accepted` immediately: a `backups` row is inserted\nwith `state='pending'` and a `backup_jobs` row is enqueued for the\n`ControlPlaneEngine`. Poll `GET /backups/{id}` to observe\n`pending → running → completed`.","operationId":"run_backup_for_source","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RunBackupRequest"}}},"required":true},"responses":{"202":{"description":"Backup enqueued for async execution","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"S3 source not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/s3-sources/{id}/set-default":{"post":{"tags":["Backups"],"summary":"Mark an S3 source as the default. All new backups/schedules/services that do not\nexplicitly reference a source will use the default. Returns the updated source.","operationId":"set_default_s3_source","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"S3 source marked as default","content":{"application/json":{"schema":{"$ref":"#/components/schemas/S3SourceResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"S3 source not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/s3-sources/{id}/test":{"post":{"tags":["Backups"],"summary":"Test connectivity to an existing S3 source using its stored credentials.","operationId":"test_s3_source_connection","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Connection test result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/S3ConnectionTestResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"S3 source not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedule-runs/{id}/cancel":{"post":{"tags":["Backups"],"summary":"Cancel every non-terminal child backup belonging to a schedule run.","description":"Loops over `state IN ('pending','running')` children and flips each via\nthe same path as the per-backup cancel endpoint. The parent\n`schedule_runs.finished_at` is stamped automatically once no live\nchildren remain. Idempotent: cancelling a run with no live children is\na 200 with `cancelled = 0`.","operationId":"cancel_schedule_run","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Cancel processed (idempotent)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CancelBackupResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Schedule run not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedule-runs/{id}/jobs":{"get":{"tags":["Backups"],"summary":"List the individual backup jobs for a single scheduler run.","description":"Returns each child `backups` row joined with its external service name and\nthe most-recent `backup_jobs` engine key. Used by the schedule detail\naccordion to show per-job detail on row expand.\n\n`page_size` defaults to 50 and is capped at 200.","operationId":"list_schedule_run_jobs","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Jobs for this scheduler run","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ScheduleRunJobEntry"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedules":{"get":{"tags":["Backups"],"summary":"List all backup schedules","operationId":"list_backup_schedules","responses":{"200":{"description":"List of backup schedules","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BackupScheduleResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Backups"],"summary":"Create a new backup schedule","operationId":"create_backup_schedule","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateBackupScheduleRequest"}}},"required":true},"responses":{"201":{"description":"Backup schedule created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupScheduleResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}":{"get":{"tags":["Backups"],"summary":"Get a backup schedule by ID","operationId":"get_backup_schedule","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Backup schedule details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupScheduleResponse"}}}},"404":{"description":"Backup schedule not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Backups"],"summary":"Delete a backup schedule","operationId":"delete_backup_schedule","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Backup schedule deleted"},"404":{"description":"Backup schedule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Backups"],"summary":"Update a backup schedule (partial update).","description":"All request fields are optional; only fields that are present in the\nJSON body are updated. Absent fields leave the corresponding column\nunchanged. If `schedule_expression` is changed, `next_run` is\nrecomputed automatically.","operationId":"update_backup_schedule","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateBackupScheduleRequest"}}},"required":true},"responses":{"200":{"description":"Schedule updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupScheduleResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Schedule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}/backups":{"get":{"tags":["Backups"],"summary":"List backups for a schedule","operationId":"list_backups_for_schedule","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of backups for the schedule","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BackupResponse"}}}}},"404":{"description":"Backup schedule not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}/disable":{"patch":{"tags":["Backups"],"summary":"Disable a backup schedule","operationId":"disable_backup_schedule","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Backup schedule disabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupScheduleResponse"}}}},"404":{"description":"Backup schedule not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}/enable":{"patch":{"tags":["Backups"],"summary":"Enable a backup schedule","operationId":"enable_backup_schedule","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Backup schedule enabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupScheduleResponse"}}}},"404":{"description":"Backup schedule not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}/run":{"post":{"tags":["Backups"],"summary":"Immediately fan-out a run for the given schedule (Run Now).","description":"Creates one `schedule_runs` row, one control-plane backup job, and one\nbackup job per supported external service — all in a single transaction.\nReturns `202 Accepted` with a [`ScheduleRunResponse`] containing the new\n`schedule_run_id` and the list of enqueued jobs. Returns `409 Conflict` if\na run for this schedule is already in flight or if the schedule is disabled.","operationId":"run_schedule_now","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"202":{"description":"Fan-out run enqueued for async execution","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScheduleRunResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Schedule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"409":{"description":"Run already in flight or schedule disabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}/runs":{"get":{"tags":["Backups"],"summary":"Paginated run history for a backup schedule (one row per scheduler tick).","description":"Returns one [`ScheduleRunSummary`] per scheduler tick, with child backup\ncounts aggregated in a single SQL round-trip. Legacy `backups` rows (pre-\nfan-out) are surfaced as synthetic single-job runs so history does not\ndisappear. Ordered by `started_at DESC` (newest first).\n\nUse `GET /backups/schedule-runs/{run_id}/jobs` to drill into a single run.","operationId":"list_schedule_runs","parameters":[{"name":"page","in":"query","description":"Page number (1-based, defaults to 1, clamped to 1 if < 1).","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"page_size","in":"query","description":"Items per page (defaults to 20, clamped to 100 if > 100).","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Paginated run history for the schedule","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScheduleRunSummaryList"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Schedule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}/services":{"get":{"tags":["Backups"],"summary":"List the external services attached to a backup schedule.","operationId":"list_schedule_services","parameters":[{"name":"id","in":"path","description":"Schedule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Services attached to this schedule","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ExternalServiceSummary"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Schedule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Backups"],"summary":"Attach one or more external services to a backup schedule. Idempotent —\nservices that are already attached are silently skipped (`ON CONFLICT\nDO NOTHING`). Returns the count of newly inserted rows + the total\nmembership after the operation.","operationId":"attach_schedule_services","parameters":[{"name":"id","in":"path","description":"Schedule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttachScheduleServicesRequest"}}},"required":true},"responses":{"200":{"description":"Services attached","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttachScheduleServicesResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Schedule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/schedules/{id}/services/{service_id}":{"delete":{"tags":["Backups"],"summary":"Detach a single external service from a backup schedule. Idempotent —\nreturns `204` whether or not a row was actually removed.","operationId":"detach_schedule_service","parameters":[{"name":"id","in":"path","description":"Schedule ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"service_id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Service detached (or was not attached)"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/{id}":{"get":{"tags":["Backups"],"summary":"Get a backup by ID","operationId":"get_backup","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Backup details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Backup not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Backups"],"summary":"Permanently delete one terminal backup from object storage and the database.","operationId":"delete_backup","parameters":[{"name":"id","in":"path","description":"Backup UUID","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Backup deleted"},"400":{"description":"Backup artifact cannot be safely attributed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Backup not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"409":{"description":"Backup is running, referenced, or lacks safe artifact identity","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Object storage or database error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/{id}/cancel":{"post":{"tags":["Backups"],"summary":"Cancel a single in-flight backup.","description":"Flips the parent `backups` row + its latest `backup_jobs` row to\n`failed` with reason `\"cancelled by user \"`. The in-process\n`CancellationToken` is observed on the next heartbeat tick (≤5s), so the\nengine exits cleanly and rollback reaps the sidecar. Idempotent: cancelling\nan already-terminal backup is a 200 with `cancelled = 0`.","operationId":"cancel_backup","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Cancel processed (idempotent)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CancelBackupResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Backup not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/backups/{id}/children":{"get":{"tags":["Backups"],"summary":"List the external-service child backups that belong to a parent backup.","description":"Each entry in `children` corresponds to one `external_service_backups` row,\njoined with `external_services` so the caller receives the service name and\ntype without a second request.\n\nReturns an empty `{ \"children\": [] }` — **not 404** — when the parent\nbackup exists but has no children (e.g. control-plane backups).\nReturns 404 when the parent backup itself does not exist.","operationId":"list_backup_children","parameters":[{"name":"id","in":"path","description":"Integer row id of the parent backup","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Child backup list (may be empty)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChildBackupListResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Parent backup not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/blob":{"get":{"tags":["Blob"],"summary":"List blobs","operationId":"blob_list","parameters":[{"name":"limit","in":"query","description":"Maximum number of items to return","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"prefix","in":"query","description":"Prefix to filter by","required":false,"schema":{"type":"string"}},{"name":"cursor","in":"query","description":"Continuation token for pagination","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of blobs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListBlobsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Blob"],"summary":"Upload a blob","operationId":"blob_put","requestBody":{"description":"Binary blob data","content":{"application/octet-stream":{"schema":{"type":"string"}}},"required":true},"responses":{"201":{"description":"Blob uploaded successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlobResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Blob"],"summary":"Delete blobs","operationId":"blob_delete","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteBlobRequest"}}},"required":true},"responses":{"200":{"description":"Blobs deleted successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteBlobResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/blob/copy":{"post":{"tags":["Blob"],"summary":"Copy a blob to a new location","operationId":"blob_copy","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CopyBlobRequest"}}},"required":true},"responses":{"200":{"description":"Blob copied successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlobResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Source blob not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/blob/disable":{"delete":{"tags":["Blob Management"],"summary":"Disable Blob service","operationId":"blob_disable","responses":{"200":{"description":"Blob service disabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DisableBlobResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Blob service not enabled"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/blob/enable":{"post":{"tags":["Blob Management"],"summary":"Enable Blob service","operationId":"blob_enable","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnableBlobRequest"}}},"required":true},"responses":{"200":{"description":"Blob service enabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnableBlobResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/blob/status":{"get":{"tags":["Blob Management"],"summary":"Get Blob service status","operationId":"blob_status","responses":{"200":{"description":"Blob service status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlobStatusResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/blob/update":{"patch":{"tags":["Blob Management"],"summary":"Update Blob service configuration","operationId":"blob_update","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateBlobRequest"}}},"required":true},"responses":{"200":{"description":"Blob service updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateBlobResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Blob service not enabled"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/blob/{project_id}/{path}":{"get":{"tags":["Blob"],"summary":"Download a blob","operationId":"blob_download","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","description":"Blob path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Blob content"},"404":{"description":"Blob not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"head":{"tags":["Blob"],"summary":"Get blob metadata","operationId":"blob_head","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","description":"Blob path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Blob metadata in headers"},"404":{"description":"Blob not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/dashboard/projects-analytics":{"get":{"tags":["Events"],"summary":"Get dashboard analytics for multiple projects in a single batch request","description":"Returns unique visitor counts and hourly sparkline data for all requested projects\nusing only 2 SQL queries instead of 2×N per-project queries.","operationId":"get_dashboard_projects_analytics","parameters":[{"name":"project_ids","in":"query","description":"Comma-separated list of project IDs","required":true,"schema":{"type":"string"}},{"name":"start_date","in":"query","description":"Start date for filtering","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date for filtering","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved batch analytics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DashboardProjectsAnalyticsResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/deployments/activity-graph":{"get":{"tags":["Deployments"],"summary":"Get deployment activity graph showing daily deployment counts\nSimilar to GitHub's contribution graph","operationId":"get_activity_graph","parameters":[{"name":"project_id","in":"query","description":"Filter by project ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"days","in":"query","description":"Number of days to include (default: 365)","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved activity graph","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivityGraphResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/deployments/{deployment_id}/vulnerability-scan":{"get":{"tags":["Vulnerability Scans"],"operationId":"get_scan_by_deployment","parameters":[{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Scan for the specified deployment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScanResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"No scan found for deployment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/deployments/{id}/metrics":{"get":{"tags":["Metrics"],"summary":"Fetch a time-series range for a single metric on a deployment.","operationId":"DeploymentMetricsGetRange","parameters":[{"name":"id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"metric","in":"query","description":"Metric name, e.g. `\"pg.connections_active\"`.","required":true,"schema":{"type":"string"}},{"name":"range","in":"query","description":"Time window: `\"1h\"` | `\"6h\"` | `\"24h\"` | `\"7d\"`.","required":false,"schema":{"type":"string"}},{"name":"percentile","in":"query","description":"Optional histogram percentile (0–100). When provided, the endpoint\nfetches histogram buckets and computes the requested quantile.","required":false,"schema":{"type":["number","null"],"format":"double"}}],"responses":{"200":{"description":"Metric time series data points","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MetricDataPoint"}}}}},"400":{"description":"Invalid query parameters"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"},"503":{"description":"Metrics store not available"}},"security":[{"bearer_auth":[]}]}},"/deployments/{id}/metrics/enable":{"patch":{"tags":["Metrics"],"summary":"Enable or disable OTLP metric ingestion for a deployment.","description":"When `enabled=true`, seeds the default container alert rules for the\ndeployment via [`temps_monitoring::seed_default_container_rules`] (idempotent).","operationId":"DeploymentMetricsToggle","parameters":[{"name":"id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToggleDeploymentMetricsRequest"}}},"required":true},"responses":{"200":{"description":"Metrics toggle applied"},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/deployments/{id}/metrics/latest":{"get":{"tags":["Metrics"],"summary":"Fetch the most-recent metric values for a deployment.","operationId":"DeploymentMetricsGetLatest","parameters":[{"name":"id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Map of metric name to latest value","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"number","format":"double"},"propertyNames":{"type":"string"}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"},"503":{"description":"Metrics store not available"}},"security":[{"bearer_auth":[]}]}},"/dns-providers":{"get":{"tags":["DNS Providers"],"summary":"List all DNS providers","operationId":"list_dns_providers","responses":{"200":{"description":"List of DNS providers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/DnsProviderResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["DNS Providers"],"summary":"Create a new DNS provider","description":"The provider's credentials will be tested before creation.\nIf the connection test fails, the provider will not be created.","operationId":"create_dns_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDnsProviderRequest"}}},"required":true},"responses":{"201":{"description":"DNS provider created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsProviderResponse"}}}},"400":{"description":"Invalid request or connection test failed"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{id}":{"get":{"tags":["DNS Providers"],"summary":"Get a DNS provider by ID","operationId":"get_dns_provider","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"DNS provider details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsProviderResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["DNS Providers"],"summary":"Update a DNS provider","description":"If new credentials are supplied, they are tested before the update is\npersisted (same as creation) -- otherwise a provider's credentials (and,\nfor Pebble, its target URL) could be swapped for something invalid or\nunsafe without ever going through validation.","operationId":"update_provider","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDnsProviderRequest"}}},"required":true},"responses":{"200":{"description":"DNS provider updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsProviderResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["DNS Providers"],"summary":"Delete a DNS provider","operationId":"delete_dns_provider","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"DNS provider deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{id}/domains":{"get":{"tags":["DNS Providers"],"summary":"List managed domains for a provider","operationId":"list_managed_domains","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of managed domains","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ManagedDomainResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["DNS Providers"],"summary":"Add a managed domain to a provider","operationId":"add_managed_domain","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddManagedDomainApiRequest"}}},"required":true},"responses":{"201":{"description":"Managed domain added","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagedDomainResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{id}/test":{"post":{"tags":["DNS Providers"],"summary":"Test provider connection","operationId":"test_provider_connection","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Connection test result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectionTestResult"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{id}/zones":{"get":{"tags":["DNS Providers"],"summary":"List zones available in a provider","operationId":"list_provider_zones","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of zones","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ZoneListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{provider_id}/domains/{domain}":{"delete":{"tags":["DNS Providers"],"summary":"Remove a managed domain","operationId":"remove_managed_domain","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Managed domain removed"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["DNS Providers"],"summary":"Update a managed domain's settings (hostname mode, sync opt-in, auto-manage).","operationId":"update_managed_domain","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateManagedDomainApiRequest"}}},"required":true},"responses":{"200":{"description":"Managed domain updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagedDomainResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{provider_id}/domains/{domain}/apply-hostname-mode":{"post":{"tags":["DNS Providers"],"summary":"Apply a hostname mode to a managed domain (persist + optional DNS sync +\nroute reload).","operationId":"apply_hostname_mode","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApplyHostnameModeRequest"}}},"required":true},"responses":{"200":{"description":"Hostname mode applied","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HostnamePreviewResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions or token lacks zone access"},"404":{"description":"Domain not found"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{provider_id}/domains/{domain}/hostname-preview":{"get":{"tags":["DNS Providers"],"summary":"Preview the impact of switching a managed domain's hostname mode.","operationId":"preview_hostname_mode","parameters":[{"name":"mode","in":"query","description":"Target mode: standard|flat","required":true,"schema":{"type":"string"}},{"name":"sync","in":"query","description":"Include DNS record changes","required":false,"schema":{"type":"boolean"}},{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Hostname mode preview","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HostnamePreviewResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"}},"security":[{"bearer_auth":[]}]}},"/dns-providers/{provider_id}/domains/{domain}/verify":{"post":{"tags":["DNS Providers"],"summary":"Verify a managed domain","operationId":"verify_managed_domain","parameters":[{"name":"provider_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Domain verification result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagedDomainResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"}},"security":[{"bearer_auth":[]}]}},"/dns/lookup":{"get":{"tags":["DNS"],"summary":"Lookup DNS A records for a domain","operationId":"lookup_dns_a_records","parameters":[{"name":"domain","in":"query","description":"Domain name to lookup","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved DNS A records","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsLookupResponse"}}}},"400":{"description":"Invalid domain name or lookup failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsLookupError"}}}}}}},"/domains":{"get":{"tags":["Domains"],"summary":"List all domains","operationId":"list_domains","parameters":[{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20},{"name":"search","in":"query","description":"Search domains by name (substring match)","required":false,"schema":{"type":["string","null"]},"example":"example.com"}],"responses":{"200":{"description":"Domains retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListDomainsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Domains"],"summary":"Create a new domain","description":"Creates a new domain and automatically requests a Let's Encrypt challenge.\nYou can specify the challenge type (HTTP-01 or DNS-01) in the request.\n\n- **HTTP-01**: Validates domain ownership by placing a file on your web server at `/.well-known/acme-challenge/`\n- **DNS-01**: Validates domain ownership by adding a TXT record to your DNS (required for wildcard domains)","operationId":"create_domain","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDomainRequest"}}},"required":true},"responses":{"201":{"description":"Domain created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainResponse"}}}},"400":{"description":"Invalid input"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/by-host/{hostname}":{"get":{"tags":["Domains"],"summary":"Get domain details by hostname","operationId":"get_domain_by_host","parameters":[{"name":"hostname","in":"path","description":"Domain hostname","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Domain details retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/by-host/{hostname}/cert-status":{"get":{"tags":["Domains"],"summary":"Get on-demand TLS certificate status for a hostname","description":"Returns the current cert lifecycle state for a single hostname (from the\n`domains` row) plus the most recent on-demand issuance attempt (from the\n`on_demand_cert_attempts` audit log). This is the operator's first-line\ndiagnostic, surfaced by `temps domain cert-status` (ADR-018 §5). Returns the\nhostname with `None` fields when no on-demand activity exists for it (never a\n404, so the CLI can render \"no attempts recorded\").","operationId":"get_on_demand_cert_status","parameters":[{"name":"hostname","in":"path","description":"Domain hostname","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"On-demand cert status retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CertStatusResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/on-demand-certs":{"get":{"tags":["Domains"],"summary":"List on-demand TLS certificate attempts","description":"Returns rows from the append-only `on_demand_cert_attempts` audit log\n(ADR-018 §5), newest first, each joined with the current authoritative cert\nstate (`status`, `expiration_time`, `backoff_until`) from the `domains` row.\nThis backs the console \"Certificates\" surface. No certificate or private-key\nmaterial is returned — only audit metadata.","operationId":"list_on_demand_certs","parameters":[{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20}],"responses":{"200":{"description":"On-demand cert attempts retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListOnDemandCertsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain_id}/order":{"get":{"tags":["Domains"],"summary":"Get ACME order for a domain","operationId":"get_domain_order","parameters":[{"name":"domain_id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Order retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AcmeOrderResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Order not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Domains"],"summary":"Create or recreate ACME order for a domain","description":"Creates a new ACME order with Let's Encrypt for the specified domain.\nIf an order already exists, you should cancel it first using the cancel-order endpoint.\nReturns the challenge details that need to be fulfilled (DNS record or HTTP token).","operationId":"create_or_recreate_order","parameters":[{"name":"domain_id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Order created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainChallengeResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Domains"],"summary":"Cancel ACME order for a domain","description":"Cancels the current ACME order for a domain and clears all challenge data.\nThis allows you to start over with a new order if the previous one failed or got stuck.","operationId":"cancel_domain_order","parameters":[{"name":"domain_id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Order cancelled successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain_id}/order/finalize":{"post":{"tags":["Domains"],"summary":"Finalize ACME order for a domain","description":"Finalizes the ACME order by completing the challenge validation and requesting the certificate.\nThis should be called after the challenge has been set up (DNS record added or HTTP token served).","operationId":"finalize_order","parameters":[{"name":"domain_id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Order finalized successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain or order not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain_id}/setup-dns":{"post":{"tags":["Domains"],"summary":"Setup DNS challenge records automatically using a DNS provider","description":"This endpoint automatically creates the required DNS TXT records for ACME DNS-01 challenge\nvalidation using a configured DNS provider. The domain must have an active DNS challenge\npending (created via POST /domains/{id}/order with dns-01 challenge type).\n\nThis is similar to how email domain DNS records are auto-provisioned.","operationId":"setup_dns_challenge","parameters":[{"name":"domain_id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetupDnsChallengeRequest"}}},"required":true},"responses":{"200":{"description":"DNS records created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetupDnsChallengeResponse"}}}},"400":{"description":"Bad request - DNS provider not configured or no challenge pending"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain or DNS provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain}":{"get":{"tags":["Domains"],"summary":"Get domain by ID","operationId":"get_domain_by_id","parameters":[{"name":"domain","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Domain retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Domains"],"summary":"Delete a domain","operationId":"delete_domain","parameters":[{"name":"domain","in":"path","description":"Domain name","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Domain deleted successfully"},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain}/challenge-token":{"get":{"tags":["Domains"],"summary":"Get challenge token for a domain (returns plain text token)","operationId":"get_challenge_token","parameters":[{"name":"domain","in":"path","description":"Domain name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Challenge token retrieved successfully","content":{"text/plain":{"schema":{"type":"string"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Challenge not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain}/http-challenge-debug":{"get":{"tags":["Domains"],"summary":"Get HTTP challenge debug information","description":"Returns detailed debug information for HTTP-01 challenge including:\n- Whether a challenge exists for the domain\n- The challenge token and URL that Let's Encrypt will access\n- DNS resolution information showing where the domain currently points\n\nThis is useful for debugging why HTTP-01 challenges fail.","operationId":"get_http_challenge_debug","parameters":[{"name":"domain","in":"path","description":"Domain name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Debug information retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpChallengeDebugResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain}/provision":{"post":{"tags":["Domains"],"summary":"Provision a domain certificate","operationId":"provision_domain","parameters":[{"name":"domain","in":"path","description":"Domain name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Certificate provisioning initiated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProvisionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain}/renew":{"post":{"tags":["Domains"],"summary":"Renew domain certificate","description":"For HTTP-01 domains: Automatically renews the certificate\nFor DNS-01 domains (wildcards): Creates a new ACME order and returns challenge data","operationId":"renew_domain","parameters":[{"name":"domain","in":"path","description":"Domain name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Certificate renewal initiated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProvisionResponse"}}}},"202":{"description":"DNS challenge created - manual action required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainChallengeResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/domains/{domain}/status":{"get":{"tags":["Domains"],"summary":"Check domain status","operationId":"check_domain_status","parameters":[{"name":"domain","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Domain status retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/drop/inspect":{"post":{"tags":["Projects"],"summary":"Inspect a source ZIP without creating a project or retaining the upload.","operationId":"inspect_drop_archive","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/DropArchiveUpload"}}},"required":true},"responses":{"200":{"description":"Detected deployable project roots","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DropInspectionResponse"}}}},"400":{"description":"Invalid or unsupported archive"}},"security":[{"bearer_auth":[]}]}},"/email-domains":{"get":{"tags":["Email Domains"],"summary":"List all email domains","operationId":"list_email_domains","parameters":[{"name":"provider_id","in":"query","description":"Only return domains belonging to this provider","required":false,"schema":{"type":["integer","null"],"format":"int32"}}],"responses":{"200":{"description":"List of email domains","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EmailDomainResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Email Domains"],"summary":"Create a new email domain","operationId":"create_email_domain","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEmailDomainRequest"}}},"required":true},"responses":{"201":{"description":"Domain created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailDomainWithDnsResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-domains/by-domain/{domain}":{"get":{"tags":["Email Domains"],"summary":"Get an email domain by domain name with DNS records","operationId":"get_domain_by_name","parameters":[{"name":"domain","in":"path","description":"Domain name (e.g., 'mail.example.com')","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Email domain details with DNS records","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailDomainWithDnsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-domains/{id}":{"get":{"tags":["Email Domains"],"summary":"Get an email domain by ID with DNS records","operationId":"get_domain","parameters":[{"name":"id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Email domain details with DNS records","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailDomainWithDnsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Email Domains"],"summary":"Delete an email domain","operationId":"delete_email_domain","parameters":[{"name":"id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Domain deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-domains/{id}/dns-records":{"get":{"tags":["Email Domains"],"summary":"Get DNS records for an email domain","operationId":"get_domain_dns_records","parameters":[{"name":"id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"DNS records for the domain","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/DnsRecordResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-domains/{id}/setup-dns":{"post":{"tags":["Email Domains"],"summary":"Setup DNS records for an email domain using a configured DNS provider","operationId":"setup_dns","parameters":[{"name":"id","in":"path","description":"Email Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetupDnsRequest"}}},"required":true},"responses":{"200":{"description":"DNS records setup result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetupDnsResponse"}}}},"400":{"description":"Invalid request or DNS provider not configured"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-domains/{id}/verify":{"post":{"tags":["Email Domains"],"summary":"Verify an email domain's DNS configuration","operationId":"verify_domain","parameters":[{"name":"id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Domain verification result with DNS records","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailDomainWithDnsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-providers":{"get":{"tags":["Email Providers"],"summary":"List all email providers","operationId":"list_email_providers","responses":{"200":{"description":"List of email providers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EmailProviderResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Email Providers"],"summary":"Create a new email provider","operationId":"create_email_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEmailProviderRequest"}}},"required":true},"responses":{"201":{"description":"Provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailProviderResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-providers/{id}":{"get":{"tags":["Email Providers"],"summary":"Get an email provider by ID","operationId":"get_email_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Email provider details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailProviderResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Email Providers"],"summary":"Delete an email provider","operationId":"delete_email_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Provider deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Email Providers"],"summary":"Update an email provider","description":"Partial update — any field left out keeps its current value. Most importantly,\nomitting the credential block (`ses_credentials`/`scaleway_credentials`/`smtp_credentials`)\npreserves the stored secret, so operators can rename a provider without re-typing\npasswords. `provider_type` is immutable; to switch providers, delete and recreate.","operationId":"update_email_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEmailProviderRequest"}}},"required":true},"responses":{"200":{"description":"Provider updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailProviderResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"},"409":{"description":"Provider type mismatch"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-providers/{id}/test":{"post":{"tags":["Email Providers"],"summary":"Test an email provider by sending a test email to the logged-in user","operationId":"test_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestEmailRequest"}}},"required":true},"responses":{"200":{"description":"Test email result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestEmailResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/email-providers/{id}/tracking/setup":{"post":{"tags":["Email Providers"],"summary":"One-click AWS-side setup of SES event tracking (SNS topic + webhook\nsubscription + SESv2 event destination), using the provider's stored\ncredentials.","operationId":"setup_email_tracking","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Setup completed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailTrackingSetupResponse"}}}},"400":{"description":"Provider does not support event tracking"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"},"502":{"description":"An AWS call failed — the response detail names the failed step"}},"security":[{"bearer_auth":[]}]}},"/email-providers/{id}/tracking/status":{"get":{"tags":["Email Providers"],"summary":"Live status of SES event tracking for a provider","operationId":"get_email_tracking_status","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Event tracking status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailTrackingStatusResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Provider not found"}},"security":[{"bearer_auth":[]}]}},"/emails":{"get":{"tags":["Emails"],"summary":"List emails with optional filtering","operationId":"list_emails","parameters":[{"name":"domain_id","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"project_id","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"status","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"from_address","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"page","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"page_size","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}}],"responses":{"200":{"description":"List of emails","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedEmailsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Emails"],"summary":"Send an email","operationId":"send_email","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendEmailRequestBody"}}},"required":true},"responses":{"201":{"description":"Email sent successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendEmailResponseBody"}}}},"400":{"description":"Invalid request or domain not verified"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/emails/events":{"get":{"tags":["Email Tracking"],"summary":"GET /emails/events","operationId":"get_global_events","parameters":[{"name":"event_type","in":"query","description":"Filter by event type (open, click)","required":false,"schema":{"type":"string"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Paginated tracking events","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedEventsResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/emails/events/stats":{"get":{"tags":["Email Tracking"],"summary":"GET /emails/events/stats","operationId":"get_global_event_stats","responses":{"200":{"description":"Global tracking statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GlobalEventStatsResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/emails/stats":{"get":{"tags":["Emails"],"summary":"Get email statistics","operationId":"get_email_stats","parameters":[{"name":"domain_id","in":"query","description":"Optional domain ID to filter stats","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Email statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailStatsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/emails/validate":{"post":{"tags":["Email Validation"],"summary":"Validate an email address","operationId":"validate_email","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateEmailRequest"}}},"required":true},"responses":{"200":{"description":"Email validation result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateEmailResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/emails/{email_id}/track/click/{link_index}":{"get":{"tags":["Email Tracking"],"summary":"Track email link click - redirects to original URL","description":"This endpoint replaces original links in tracked emails.\nNo authentication required - it's called when the recipient clicks a link.","operationId":"track_click","parameters":[{"name":"email_id","in":"path","description":"Email ID (UUID)","required":true,"schema":{"type":"string"}},{"name":"link_index","in":"path","description":"Link index","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"302":{"description":"Redirect to original URL"},"404":{"description":"Link not found"}}}},"/emails/{email_id}/track/open":{"get":{"tags":["Email Tracking"],"summary":"Track email open - returns a 1x1 transparent GIF","description":"This endpoint is embedded as an tag in emails.\nNo authentication required - it's called by the email client.","operationId":"track_open","parameters":[{"name":"email_id","in":"path","description":"Email ID (UUID)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"1x1 transparent tracking pixel"},"404":{"description":"Email not found"}}}},"/emails/{id}":{"get":{"tags":["Emails"],"summary":"Get an email by ID","operationId":"get_email","parameters":[{"name":"id","in":"path","description":"Email ID (UUID)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Email details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Email not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/emails/{id}/tracking":{"get":{"tags":["Email Tracking"],"summary":"Get email tracking summary","operationId":"get_email_tracking","parameters":[{"name":"id","in":"path","description":"Email ID (UUID)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Tracking summary","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailTrackingResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Email not found"}},"security":[{"bearer_auth":[]}]}},"/emails/{id}/tracking/events":{"get":{"tags":["Email Tracking"],"summary":"Get email tracking events","operationId":"get_email_events","parameters":[{"name":"id","in":"path","description":"Email ID (UUID)","required":true,"schema":{"type":"string"}},{"name":"event_type","in":"query","description":"Filter by event type (open, click)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Tracking events","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TrackingEventResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Email not found"}},"security":[{"bearer_auth":[]}]}},"/emails/{id}/tracking/links":{"get":{"tags":["Email Tracking"],"summary":"Get tracked links for an email","operationId":"get_email_links","parameters":[{"name":"id","in":"path","description":"Email ID (UUID)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Tracked links","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TrackedLinkResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Email not found"}},"security":[{"bearer_auth":[]}]}},"/external-services":{"get":{"tags":["External Services"],"summary":"Get all external services","operationId":"list_services","parameters":[{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20},{"name":"sort_by","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"List of external services","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}}},"500":{"description":"Internal server error"}}},"post":{"tags":["External Services"],"summary":"Create new external service","operationId":"create_service","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateExternalServiceRequest"}}},"required":true},"responses":{"201":{"description":"Service created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}},"400":{"description":"Invalid request"},"500":{"description":"Internal server error"}}}},"/external-services/available-containers":{"get":{"tags":["External Services"],"summary":"List available Docker containers that can be imported as services","operationId":"list_available_containers","responses":{"200":{"description":"List of available containers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AvailableContainerInfo"}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/by-slug/{slug}":{"get":{"tags":["External Services"],"summary":"Get external service details by slug","operationId":"get_service_by_slug","parameters":[{"name":"slug","in":"path","description":"External service slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"External service details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceDetails"}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/health-status-batch":{"get":{"tags":["External Services"],"summary":"Current health status for many services at once","description":"Powers the status dot on the Storage list page. Pass a comma-separated\nlist of service IDs via `?ids=1,2,3`. Omit to get every service.","operationId":"list_service_health_statuses","parameters":[{"name":"ids","in":"query","description":"Comma-separated service IDs. Omit for all services.","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Batch of current health statuses","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceHealthStatusBatchResponse"}}}},"500":{"description":"Internal server error"}}}},"/external-services/import":{"post":{"tags":["External Services"],"summary":"Import an existing Docker container as a managed external service","operationId":"import_external_service","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportExternalServiceRequest"}}},"required":true},"responses":{"201":{"description":"Service imported successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/projects/{project_id}":{"get":{"tags":["External Services"],"summary":"List services linked to a project","operationId":"list_project_services","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20},{"name":"sort_by","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"List of services linked to project","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProjectServiceInfo"}}}}},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}}},"/external-services/projects/{project_id}/environment":{"get":{"tags":["External Services"],"summary":"Get all environment variables for all services linked to a project","operationId":"get_project_service_environment_variables","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Map of service IDs to their environment variables","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"object","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"propertyNames":{"type":"integer","format":"int32"}}}}},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}}},"/external-services/providers/metadata":{"get":{"tags":["External Services"],"summary":"Get provider metadata (display names, icons, descriptions)","operationId":"get_providers_metadata","responses":{"200":{"description":"List of provider metadata","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProviderMetadata"}}}}},"500":{"description":"Internal server error"}}}},"/external-services/providers/metadata/{service_type}":{"get":{"tags":["External Services"],"summary":"Get metadata for a specific provider","operationId":"get_provider_metadata","parameters":[{"name":"service_type","in":"path","description":"Service type (mongodb, postgres, redis, s3)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Provider metadata","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderMetadata"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}}}},"/external-services/types":{"get":{"tags":["External Services"],"summary":"Get available service types","operationId":"get_service_types","responses":{"200":{"description":"List of available service types","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ServiceTypeRoute"}}}}},"500":{"description":"Internal server error"}}}},"/external-services/types/{service_type}/parameters":{"get":{"tags":["External Services"],"summary":"Get parameter schema for a specific service type","operationId":"get_service_type_parameters","parameters":[{"name":"service_type","in":"path","description":"Service type","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Service type parameter schema"},"404":{"description":"Service type not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}":{"get":{"tags":["External Services"],"summary":"Get external service details","operationId":"get_service","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"External service details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceDetails"}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}},"put":{"tags":["External Services"],"summary":"Update external service","operationId":"update_service","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateExternalServiceRequest"}}},"required":true},"responses":{"200":{"description":"Service updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}},"400":{"description":"Invalid request"},"404":{"description":"Service not found"},"409":{"description":"A major upgrade is in progress for this service"},"500":{"description":"Internal server error"}}},"delete":{"tags":["External Services"],"summary":"Delete external service","operationId":"delete_service","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Service deleted successfully"},"400":{"description":"Cannot delete: service is still linked to projects"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/cluster-health":{"get":{"tags":["External Services"],"summary":"Per-member health for a Postgres HA cluster.","description":"Reads pg_auto_failover's `pgautofailover.node` table from the cluster's\nmonitor (TLS, autoctl_node) and joins each member with its\n`pg_stat_replication` row from the current primary. Returns one row per\ndata member with role/state, sync state, and replay lag.\n\nReturns `200` with `monitor_error` set when the monitor is briefly\nunreachable (UI surfaces it as a banner above the table); the table\nitself is empty in that case. Returns `400` for non-cluster services.","operationId":"get_cluster_health","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Per-member cluster health report","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClusterHealthReportResponse"}}}},"400":{"description":"Service is not a cluster"},"401":{"description":"Unauthorized"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/health-check":{"post":{"tags":["External Services"],"summary":"Run a health check for one service right now","description":"Triggers the same engine-specific probe as the background monitor, writes\na history row, updates the denormalized fields on `external_services`, and\nfires alerts on the Nth consecutive failure (so consecutive-failure state\nstays honest). Returns the fresh snapshot the UI can display immediately.","operationId":"trigger_service_health_check","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Fresh health snapshot after probing","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceHealthResponse"}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"},"503":{"description":"Health monitor not running on this node"}}}},"/external-services/{id}/health-status":{"get":{"tags":["External Services"],"summary":"Persisted health status for an external service","description":"Returns the latest health probe result recorded by\n`ExternalServiceHealthMonitor`, plus recent check history for sparklines\nand a 24-hour uptime percentage. Safe to poll from the UI every 30s.","operationId":"get_service_health_status","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"limit","in":"query","description":"Max number of recent checks (default 50, max 200)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Current health + recent history","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceHealthResponse"}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/members":{"post":{"tags":["External Services"],"summary":"Begin adding a single new member to a running cluster.","description":"Currently only `replica` members can be added at runtime. The\nresponse is **202 Accepted** as soon as the validation passes and\nthe placeholder `service_members` row is inserted. The actual\ncontainer provisioning + DNS registration runs in the background;\npoll `GET /external-services/{id}/members/{member_id}` to watch\n`provisioning_step` advance through the phases.","operationId":"add_cluster_member","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddClusterMemberRequest"}}},"required":true},"responses":{"202":{"description":"Cluster member provisioning started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceMemberInfo"}}}},"400":{"description":"Validation failed (wrong topology, status, or role)"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/members/{member_id}":{"get":{"tags":["External Services"],"summary":"Get a single cluster member's current state.","description":"Used by the add-member page to poll the row every second while the\nbackground provisioning task walks through its phases. The\n`provisioning_step` field advances through `inserting_row` →\n`provisioning_container` → `registering_dns` → `done` (or `failed`\nwith `provisioning_error` set).","operationId":"get_cluster_member","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"member_id","in":"path","description":"Cluster member ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Cluster member details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceMemberInfo"}}}},"404":{"description":"Service or member not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["External Services"],"summary":"Remove a single member from a running cluster.","description":"Refuses to remove the monitor (singleton), the current primary\n(failover first), or any member if the cluster would drop below the\n2-data-member quorum required for HA. Stops + removes the container,\ndeletes the row, and drops the Tier-2 DNS record.","operationId":"remove_cluster_member","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"member_id","in":"path","description":"Cluster member ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Cluster member removed"},"400":{"description":"Validation failed (monitor, primary, or quorum violation)"},"404":{"description":"Service or member not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/members/{member_id}/promote":{"post":{"tags":["External Services"],"summary":"Promote a replica to primary by triggering a pg_auto_failover\nfailover. The monitor demotes the current primary and the chosen\nreplica transitions to primary; the role reconciler then refreshes\nthe role-aliased VIPs (≤30s).","operationId":"promote_cluster_member","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"member_id","in":"path","description":"Cluster member ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"202":{"description":"Promotion initiated"},"400":{"description":"Validation failed (monitor, already primary, not running, etc.)"},"404":{"description":"Service or member not found"},"500":{"description":"pg_autoctl perform promotion failed"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/metrics":{"get":{"tags":["Metrics"],"summary":"Fetch a time-series range for a single metric on an external service.","description":"Pass `percentile` to compute a histogram quantile instead of a plain\ngauge/counter average.","operationId":"ExternalServiceMetricsGetRange","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"metric","in":"query","description":"Metric name, e.g. `\"pg.connections_active\"`.","required":true,"schema":{"type":"string"}},{"name":"range","in":"query","description":"Time window: `\"1h\"` | `\"6h\"` | `\"24h\"` | `\"7d\"`.","required":false,"schema":{"type":"string"}},{"name":"percentile","in":"query","description":"Optional histogram percentile (0–100). When provided, the endpoint\nfetches histogram buckets and computes the requested quantile.","required":false,"schema":{"type":["number","null"],"format":"double"}}],"responses":{"200":{"description":"Metric time series data points","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MetricDataPoint"}}}}},"400":{"description":"Invalid query parameters"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"},"503":{"description":"Metrics store not available"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/metrics/alert-rules":{"get":{"tags":["Metrics"],"summary":"List all monitoring alert rules for an external service.","operationId":"ExternalServiceMetricsGetAlertRules","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of alert rules","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ServiceAlertRuleResponse"}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Metrics"],"summary":"Create a monitoring alert rule for an external service.","description":"If metric collection is enabled and the service engine has default rules,\nseeding is idempotent (ON CONFLICT DO NOTHING).","operationId":"ExternalServiceMetricsCreateAlertRule","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceCreateAlertRuleRequest"}}},"required":true},"responses":{"201":{"description":"Alert rule created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceAlertRuleResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/metrics/alert-rules/{rule_id}":{"put":{"tags":["Metrics"],"summary":"Update an existing monitoring alert rule for an external service.","operationId":"ExternalServiceMetricsUpdateAlertRule","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"rule_id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceUpdateAlertRuleRequest"}}},"required":true},"responses":{"200":{"description":"Updated alert rule","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceAlertRuleResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Alert rule not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Metrics"],"summary":"Delete a monitoring alert rule for an external service.","operationId":"ExternalServiceMetricsDeleteAlertRule","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"rule_id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Alert rule deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Alert rule not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/metrics/by-database":{"get":{"tags":["Metrics"],"summary":"Return the latest per-database metric values for a Postgres service.","description":"Groups `pg_stat_database` / size metrics by `datname` so the UI can show a\nbreakdown table (each database with its own size, cache-hit ratio, etc.)\nrather than collapsing every database into one value.","operationId":"ExternalServiceMetricsByDatabase","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Per-database metric breakdown","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DatabaseMetricsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"},"503":{"description":"Metrics not available"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/metrics/enable":{"patch":{"tags":["Metrics"],"summary":"Enable or disable metric collection for an external service.","description":"When `enabled=true`, seeds the default alert rules for the service's engine\nvia [`temps_monitoring::seed_default_rules`] (idempotent).","operationId":"ExternalServiceMetricsToggle","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToggleServiceMetricsRequest"}}},"required":true},"responses":{"200":{"description":"Metrics toggle applied"},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/metrics/latest":{"get":{"tags":["Metrics"],"summary":"Fetch the most-recent value for every tracked metric on an external service.","operationId":"ExternalServiceMetricsGetLatest","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Map of metric name to latest value","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"number","format":"double"},"propertyNames":{"type":"string"}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"},"503":{"description":"Metrics store not available"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/metrics/status":{"get":{"tags":["Metrics"],"summary":"Return the freshness status (last-received timestamp) for a service.","description":"Cheap O(1) lookup against `service_metrics_status` — used by the UI to show\n\"last received at …\" without scanning the metrics hypertable.","operationId":"ExternalServiceMetricsStatus","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Metrics freshness status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MetricsStatusResponse"}}}},"503":{"description":"Metrics not available"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/parameters/{param_name}":{"get":{"tags":["External Services"],"summary":"Reveal one sensitive service parameter. Service detail responses never\ncontain plaintext values; every successful reveal is recorded separately.","operationId":"reveal_service_parameter","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"param_name","in":"path","description":"Sensitive parameter name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sensitive parameter value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SensitiveValueResponse"}}}},"400":{"description":"Parameter is not sensitive"},"403":{"description":"Caller cannot access a project linked to this service"},"404":{"description":"Service or parameter not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/preview-environment-masked":{"get":{"tags":["External Services"],"summary":"Get environment variables preview with masked sensitive values","operationId":"get_service_preview_environment_variables_masked","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Preview of environment variables with sensitive values masked as ***","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/preview-environment-names":{"get":{"tags":["External Services"],"summary":"Get environment variable names preview (safe - no sensitive values)","operationId":"get_service_preview_environment_variable_names","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of environment variable names that would be provided","content":{"application/json":{"schema":{"type":"array","items":{"type":"string"}}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/projects":{"get":{"tags":["External Services"],"summary":"List projects linked to service","operationId":"list_service_projects","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20},{"name":"sort_by","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"List of linked projects","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProjectServiceInfo"}}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}},"post":{"tags":["External Services"],"summary":"Link service to project","operationId":"link_service_to_project","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LinkServiceRequest"}}},"required":true},"responses":{"201":{"description":"Service linked to project successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectServiceInfo"}}}},"404":{"description":"Service or project not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/projects/{project_id}":{"delete":{"tags":["External Services"],"summary":"Unlink service from project","operationId":"unlink_service_from_project","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Service unlinked from project successfully"},"404":{"description":"Service link not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/projects/{project_id}/environment":{"get":{"tags":["External Services"],"summary":"Get all environment variables for a service-project pair","operationId":"get_service_environment_variables","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of environment variables","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EnvironmentVariableInfo"}}}}},"404":{"description":"Service or project not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/projects/{project_id}/environment/{var_name}":{"get":{"tags":["External Services"],"summary":"Get specific environment variable for a service-project pair","operationId":"get_service_environment_variable","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"var_name","in":"path","description":"Environment variable name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Environment variable value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentVariableInfo"}}}},"403":{"description":"Plaintext secret access is not permitted"},"404":{"description":"Service, project, or variable not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/resources":{"patch":{"tags":["External Services"],"summary":"Update a service's resource limits (memory, CPU caps).","description":"Persists the new caps to the encrypted config AND live-applies them\nvia Docker's update API. Memory and CPU can be hot-changed without a\nrestart on running containers; stopped containers also accept the\nupdate and pick up the new caps on next start.\n\nPass `null` (or omit) any field to leave it unlimited. A request where\nevery field is `null` removes any existing limits.\n\nThe response includes a per-container `applied[]` list so the caller\ncan tell which members got the update and which were skipped (e.g.,\ncontainer not yet created, or `docker update` rejected because the\nnew memory cap is below current usage).","operationId":"update_service_resources","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceResourceLimits"}}},"required":true},"responses":{"200":{"description":"Updated resource limits","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResourceLimitsUpdateResponse"}}}},"400":{"description":"Invalid resource limits"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/restore":{"post":{"tags":["Restore"],"operationId":"start_restore","parameters":[{"name":"id","in":"path","description":"External service id (source for the restore)","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartRestoreRequest"}}},"required":true},"responses":{"202":{"description":"Restore run started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RestoreRunView"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Backup or service not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/restore-capabilities":{"get":{"tags":["Restore"],"operationId":"get_restore_capabilities","parameters":[{"name":"id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Capabilities declared by the service","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RestoreCapabilitiesResponse"}}}},"404":{"description":"Service not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/restore-plan":{"post":{"tags":["Restore"],"operationId":"plan_restore","parameters":[{"name":"id","in":"path","description":"Target service id","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartRestoreRequest"}}},"required":true},"responses":{"200":{"description":"Preview of what the restore will do","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RestorePlan"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Backup or service not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/restore-runs":{"get":{"tags":["Restore"],"operationId":"list_restore_runs_for_service","parameters":[{"name":"id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Recent restore runs for the service","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RestoreRunView"}}}}}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/retry":{"post":{"tags":["External Services"],"summary":"Retry a failed cluster service initialization.","description":"Cleans up any leftover containers from the previous attempt and\nre-runs cluster initialization with the provided member specifications.","operationId":"retry_cluster","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RetryClusterRequest"}}},"required":true},"responses":{"200":{"description":"Cluster retry initiated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}},"400":{"description":"Service is not a failed cluster"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{id}/runtime":{"get":{"tags":["External Services"],"summary":"Inspect a service's container(s): status, restart count, OOM-killed flag,\nexit code, and the cgroup limits actually applied.","operationId":"get_service_runtime","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Container runtime snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceRuntimeReport"}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/start":{"post":{"tags":["External Services"],"summary":"Start an external service","operationId":"start_service","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Service started successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}},"404":{"description":"Service not found"},"409":{"description":"A Postgres major upgrade is in progress for this service"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/stats":{"get":{"tags":["External Services"],"summary":"Sample current CPU/memory usage from each of a service's containers.\nOne-shot sample, no streaming. Cheap to call (single Docker round-trip\nper member) so the UI can poll on a 5–10s interval.","operationId":"get_service_stats","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Container stats snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceStatsReport"}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/stop":{"post":{"tags":["External Services"],"summary":"Stop an external service","operationId":"stop_service","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Service stopped successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/upgrade":{"post":{"tags":["External Services"],"summary":"Upgrade external service to new Docker image with data migration\nThis endpoint uses service-specific upgrade procedures (e.g., pg_upgrade for PostgreSQL)","operationId":"upgrade_service","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpgradeExternalServiceRequest"}}},"required":true},"responses":{"200":{"description":"Service upgraded successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalServiceInfo"}}}},"400":{"description":"Invalid request or upgrade not supported"},"404":{"description":"Service not found"},"409":{"description":"A major upgrade is already in progress for this service"},"500":{"description":"Internal server error"}}}},"/external-services/{id}/wal-health":{"get":{"tags":["External Services"],"summary":"Postgres WAL & archive health snapshot","description":"Returns the latest WAL/archive health snapshot recorded by the background\nhealth monitor for a Postgres external service. Powers the warning banner\non the service detail page when the disk is filling up due to stale\nreplication slots, archive backlog, or misconfigured `archive_command`.\n\nReturns 404 when no snapshot exists yet (probe hasn't run, or the service\nisn't Postgres).","operationId":"getPostgresWalHealth","parameters":[{"name":"id","in":"path","description":"External service ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Latest WAL health snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PostgresWalHealth"}}}},"404":{"description":"Service not found, or no WAL snapshot available"},"500":{"description":"Internal server error"}}}},"/external-services/{service_id}/pg-stat-statements/enable":{"post":{"tags":["External Services"],"summary":"Enable `pg_stat_statements` on a standalone Postgres service.","description":"Stops the container and restarts it so that the\n`shared_preload_libraries=pg_stat_statements` CMD flag (baked into every\nnew standalone Postgres container) takes effect. The named data volume is\nreused unchanged — no data is lost.\n\n**Clustered (HA) services are rejected** with 422 — a blind single-container\nrestart bypasses controlled failover. For clustered services the response\nbody describes the manual rolling-restart steps.\n\nConfirmation is the caller's responsibility (UI dialog / CLI `--yes` flag)\nbefore invoking this endpoint.","operationId":"ExternalServiceEnablePgStatStatements","parameters":[{"name":"service_id","in":"path","description":"ID of the provisioned standalone Postgres service","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Container restarted; pg_stat_statements now active","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnablePgStatStatementsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions (requires external_services:write)"},"404":{"description":"Service not found"},"422":{"description":"Service is not standalone Postgres (cluster or wrong type)"},"500":{"description":"Restart failed"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/pg-stat-statements/reset":{"post":{"tags":["External Services"],"summary":"Reset all statistics accumulated by `pg_stat_statements` for a Postgres\nservice. This affects every user, database, and normalized query tracked by\nthe target Postgres instance and cannot be undone.","operationId":"ExternalServiceResetPgStatStatements","parameters":[{"name":"service_id","in":"path","description":"ID of the provisioned Postgres service","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"Explicit confirmation of the global, irreversible reset","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResetPgStatStatementsRequest"}}},"required":true},"responses":{"200":{"description":"All accumulated pg_stat_statements statistics cleared","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResetPgStatStatementsResponse"}}}},"400":{"description":"Missing or invalid reset confirmation"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions (requires external_services:write)"},"404":{"description":"Service not found"},"422":{"description":"Service is not Postgres"},"502":{"description":"Target Postgres rejected or failed the reset operation"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/pg-stat-statements/slow-queries":{"get":{"tags":["External Services"],"operationId":"get_slow_queries","parameters":[{"name":"service_id","in":"path","description":"ID of the provisioned Postgres service","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-based). Defaults to 1.","required":false,"schema":{"type":["integer","null"],"format":"int32","minimum":0}},{"name":"page_size","in":"query","description":"Number of rows per page (1–100). Defaults to 20.","required":false,"schema":{"type":["integer","null"],"format":"int32","minimum":0}},{"name":"sort_by","in":"query","description":"Column to sort by: one of `calls`, `total_exec_time_ms`,\n`mean_exec_time_ms`, `rows`, `cache_hit_ratio`. Defaults to\n`mean_exec_time_ms`. Applied server-side so ordering stays\nconsistent across pages.","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","description":"Sort direction: `asc` or `desc`. Defaults to `desc`.","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"Paginated slow queries from pg_stat_statements","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SlowQueriesResponse"}}}},"400":{"description":"Invalid pagination or sort parameters"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions (requires external_services:read)"},"404":{"description":"Service not found"},"422":{"description":"Service is not a Postgres service"},"503":{"description":"pg_stat_statements extension not available (container restart required)"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/ai-data-access":{"get":{"tags":["External Services - Query"],"summary":"Report whether the AI assistant may read row data from this service.","description":"Always answers (rather than 404-ing when disabled) so the console can render\nthe capability with an \"off — here's how to turn it on\" state instead of\nhiding it, and so the agent can tell \"not set up\" apart from \"not supported\".","operationId":"get_ai_data_access","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Current AI data access setting","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiDataAccessResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service not found"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["External Services - Query"],"summary":"Enable or disable AI assistant access to this service's row data.","description":"Off by default. Row contents can include password hashes, API tokens and\npersonal data, and enabling this sends them to the configured AI provider —\nso it is a deliberate, audited, per-service decision by the operator.","operationId":"set_ai_data_access","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToggleAiDataAccessRequest"}}},"required":true},"responses":{"200":{"description":"Setting applied","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiDataAccessResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/containers":{"get":{"tags":["External Services - Query"],"summary":"List containers at the root level (databases, keyspaces, etc.)","operationId":"list_root_containers","parameters":[{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of root containers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ContainerResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/containers/{path}":{"get":{"tags":["External Services - Query"],"summary":"List containers at a specific path\nPath segments are separated by forward slashes\nExample: /external-services/1/query/containers/mydb lists schemas in database \"mydb\"","operationId":"list_containers_at_path","parameters":[{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of containers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ContainerResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service or container not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/containers/{path}/entities":{"get":{"tags":["External Services - Query"],"summary":"List entities (tables, collections, etc.) in a container\nExample: /external-services/1/query/containers/mydb/public/entities lists tables in the public schema","operationId":"list_entities","parameters":[{"name":"limit","in":"query","description":"Maximum number of entities to return (default: 100, max: 1000)","required":false,"schema":{"type":"integer","minimum":0}},{"name":"token","in":"query","description":"Continuation token for pagination","required":false,"schema":{"type":"string"}},{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Paginated list of entities","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedEntitiesResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service or container not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/containers/{path}/entities/{entity}":{"get":{"tags":["External Services - Query"],"summary":"Get detailed information about an entity (table schema)","operationId":"get_entity_info","parameters":[{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","required":true,"schema":{"type":"string"}},{"name":"entity","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Entity details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EntityInfoResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service, container, or entity not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/containers/{path}/entities/{entity}/data":{"get":{"tags":["External Services - Query"],"summary":"Read rows from an entity (read-only `GET`; see [`query_data`] for the\n`POST` form used by the console).","description":"Gated for AI callers by the service's `ai_data_access` opt-in — see\n[`temps_core::ai_tool_call::AiToolCall`].","operationId":"read_entity_rows","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","description":"Container path, slash-separated (e.g. `mydb/public`)","required":true,"schema":{"type":"string"}},{"name":"entity","in":"path","description":"Table, collection, key or object name","required":true,"schema":{"type":"string"}},{"name":"filter","in":"query","description":"JSON-encoded backend-specific filter","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Maximum rows to return","required":false,"schema":{"type":"integer","minimum":0}},{"name":"offset","in":"query","description":"Rows to skip","required":false,"schema":{"type":"integer","minimum":0}},{"name":"sort_by","in":"query","description":"Field to sort by","required":false,"schema":{"type":"string"}},{"name":"sort_order","in":"query","description":"asc or desc","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Query results","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QueryDataResponse"}}}},"400":{"description":"Invalid query or filter"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions, or AI data access not enabled for this service"},"404":{"description":"Service, container, or entity not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["External Services - Query"],"summary":"Query data from an entity with optional filters, pagination, and sorting","operationId":"query_data","parameters":[{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","required":true,"schema":{"type":"string"}},{"name":"entity","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QueryDataRequest"}}},"required":true},"responses":{"200":{"description":"Query results","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QueryDataResponse"}}}},"400":{"description":"Invalid query"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service, container, or entity not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/containers/{path}/entities/{entity}/download":{"get":{"tags":["External Services - Query"],"summary":"Download an object (S3 only) as a streaming response","operationId":"download_object","parameters":[{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","required":true,"schema":{"type":"string"}},{"name":"entity","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Object data stream","content":{"application/octet-stream":{}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Object not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/containers/{path}/info":{"get":{"tags":["External Services - Query"],"summary":"Get information about a specific container","operationId":"get_query_container_info","parameters":[{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"path","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Container information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service or container not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/query/explorer-support":{"get":{"tags":["External Services - Query"],"summary":"Check if a service supports query explorer functionality","operationId":"check_explorer_support","parameters":[{"name":"service_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Explorer support information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExplorerSupportResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Service not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/upgrades":{"get":{"tags":["Postgres Upgrades"],"summary":"List recent upgrades for a single service (newest first, page size 50).","operationId":"list_pg_upgrades","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Recent upgrades","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PgUpgradeResponse"}}}}},"500":{"description":"Internal error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Postgres Upgrades"],"summary":"Start a new PostgreSQL major-version upgrade for a service.","operationId":"start_pg_upgrade","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartPgUpgradeRequest"}}},"required":true},"responses":{"201":{"description":"Upgrade started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PgUpgradeResponse"}}}},"400":{"description":"Invalid request"},"409":{"description":"An upgrade is already running for this service"},"412":{"description":"No default S3 source configured"},"500":{"description":"Internal error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/upgrades/{id}":{"get":{"tags":["Postgres Upgrades"],"summary":"Get a single upgrade by id, scoped to a service.","operationId":"get_pg_upgrade","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"id","in":"path","description":"Upgrade id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Upgrade","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PgUpgradeResponse"}}}},"404":{"description":"Not found"},"500":{"description":"Internal error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/upgrades/{id}/cancel":{"post":{"tags":["Postgres Upgrades"],"summary":"Cancel an in-flight upgrade. The orchestrator stops at its next phase\nboundary; already-terminal upgrades return 409.","operationId":"cancel_pg_upgrade","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"id","in":"path","description":"Upgrade id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Cancellation requested","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PgUpgradeResponse"}}}},"404":{"description":"Not found"},"409":{"description":"Upgrade already terminal"},"500":{"description":"Internal error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/upgrades/{id}/logs":{"get":{"tags":["Postgres Upgrades"],"summary":"Get the accumulated JSONL log content for an upgrade (for dashboard display).","operationId":"get_pg_upgrade_logs","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"id","in":"path","description":"Upgrade id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Log content","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PgUpgradeLogResponse"}}}},"404":{"description":"Not found"},"500":{"description":"Internal error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/upgrades/{id}/retry":{"post":{"tags":["Postgres Upgrades"],"summary":"Retry a failed upgrade. The phase is preserved, so the state machine\nresumes from where it failed.","operationId":"retry_pg_upgrade","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"id","in":"path","description":"Upgrade id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Retry scheduled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PgUpgradeResponse"}}}},"400":{"description":"Upgrade is not in a retriable state"},"404":{"description":"Not found"},"500":{"description":"Internal error"}},"security":[{"bearer_auth":[]}]}},"/external-services/{service_id}/upgrades/{id}/rollback":{"post":{"tags":["Postgres Upgrades"],"summary":"Roll a completed upgrade back to its pre-upgrade PGDATA volume and old image.\nOnly valid while the rollback retention window is still open (see\n`ROLLBACK_RETENTION_DAYS`) and the rollback volume has not been swept.","operationId":"rollback_pg_upgrade","parameters":[{"name":"service_id","in":"path","description":"External service id","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"id","in":"path","description":"Upgrade id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Rollback complete","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PgUpgradeResponse"}}}},"404":{"description":"Not found"},"409":{"description":"Upgrade is not in a rollbackable state (not completed, volume swept, or retention expired)"},"500":{"description":"Internal error"}},"security":[{"bearer_auth":[]}]}},"/files/{file_path}":{"get":{"tags":["Files"],"operationId":"get_file","parameters":[{"name":"file_path","in":"path","description":"Relative path to the file from static directory","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"File content retrieved successfully","content":{"application/octet-stream":{}}},"401":{"description":"Authentication required"},"403":{"description":"Access denied - path outside static directory or insufficient permissions"},"404":{"description":"File not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/flags/exposure":{"post":{"tags":["Feature Flags"],"summary":"Record which flags a running app actually evaluated.","description":"This is what makes `last_evaluated_at` mean something. The snapshot\nendpoint hands the SDK every flag in the environment and evaluation then\nhappens locally, so the control plane cannot otherwise tell a flag that is\nreferenced by live code from one nothing has called in a year. Stamping on\nsnapshot fetch would mark every flag as freshly used and defeat the point.\n\nScope comes from the deployment token, never the body. The endpoint writes\nonly `last_evaluated_at` — never a flag's value — so \"a deployment token\ncannot change what a flag serves\" still holds despite this being a write.","operationId":"record_flag_exposure","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecordExposureRequest"}}},"required":true},"responses":{"200":{"description":"Exposure recorded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecordExposureResponse"}}}},"400":{"description":"Deployment token required"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/flags/snapshot":{"get":{"tags":["Feature Flags"],"summary":"Every flag for the caller's environment, collapsed to what the evaluator\nneeds.","description":"Scope comes from the deployment token, never from the URL: a container's\nbaked-in `TEMPS_API_TOKEN` identifies exactly one project (and usually one\nenvironment), so a compromised app cannot read another tenant's flags by\nchanging a path parameter.\n\nSupports `If-None-Match`, so the SDK's background poll is a 304 in the\ncommon case.","operationId":"get_flag_snapshot","parameters":[{"name":"environment_id","in":"query","description":"Required only when the calling token is project-wide rather than scoped\nto a single environment.","required":false,"schema":{"type":["integer","null"],"format":"int32"}}],"responses":{"200":{"description":"Snapshot for the environment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagSnapshotResponse"}}}},"304":{"description":"Snapshot unchanged"},"400":{"description":"Environment could not be determined"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/geo/{ip}":{"get":{"tags":["geo"],"summary":"Get geolocation information for an IP address","operationId":"get_ip_geolocation","parameters":[{"name":"ip","in":"path","description":"IP address to geolocate (IPv4 or IPv6)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Geolocation information retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GeoLocationResponse"}}}},"400":{"description":"Invalid IP address","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"IP address not found in database","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/git-connections":{"get":{"tags":["Git Providers"],"summary":"List user's git provider connections","operationId":"list_connections","parameters":[{"name":"page","in":"query","description":"Page number for pagination (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Number of items per page (default: 30, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"sort","in":"query","description":"Sort field (created_at, updated_at, account_name)","required":false,"schema":{"type":"string"}},{"name":"direction","in":"query","description":"Sort direction (asc, desc), default: desc","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of connections","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectionListResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}":{"delete":{"tags":["Git Providers"],"summary":"Permanently delete a git provider connection","operationId":"delete_connection","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Connection deleted successfully"},"400":{"description":"Connection is in use by projects and cannot be deleted"},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}/activate":{"post":{"tags":["Git Providers"],"summary":"Activate a git provider connection","operationId":"activate_connection","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Connection activated successfully"},"400":{"description":"Provider is deactivated and connection cannot be activated"},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}/deactivate":{"post":{"tags":["Git Providers"],"summary":"Deactivate a git provider connection","operationId":"deactivate_connection","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Connection deactivated successfully"},"400":{"description":"Connection is in use by projects and cannot be deactivated"},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}/health-check":{"post":{"tags":["Git Provider Connections"],"summary":"Run an on-demand health check for a git connection.","description":"Probes the upstream (GitHub App, PAT, or OAuth token), persists the result,\nand fires admin notifications on status transitions. Returns the updated\nconnection.","operationId":"run_connection_health_check","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Health check completed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}/repositories":{"get":{"tags":["Git Providers"],"summary":"List repositories for a specific connection","description":"Fetches repositories from the connected git provider with support for pagination, search, and filtering.\nThis endpoint calls the provider's API directly to get the most up-to-date repository list.","operationId":"list_repositories_by_connection","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"sort","in":"query","description":"Sort field (name, created_at, updated_at, stars, etc.)","required":false,"schema":{"type":"string"}},{"name":"direction","in":"query","description":"Sort direction (asc, desc)","required":false,"schema":{"type":"string"}},{"name":"search","in":"query","description":"Search term to filter repositories","required":false,"schema":{"type":"string"}},{"name":"owner","in":"query","description":"Filter by repository owner","required":false,"schema":{"type":"string"}},{"name":"language","in":"query","description":"Filter by programming language","required":false,"schema":{"type":"string"}},{"name":"private","in":"query","description":"Filter by private status (true/false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of repositories","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositoryListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}/sync":{"post":{"tags":["Git Providers"],"summary":"Start a repository sync for a connection","description":"Kicks off a background sync of the connection's repositories from the\nprovider. Returns `202 Accepted` immediately — the caller should poll\nthe connection endpoint for `syncing` / `synced_repository_count`\nupdates rather than waiting on this response. The sync is guarded by\na hard deadline and always releases the `syncing` flag on exit, so a\nclient that disconnects mid-sync will not leave the connection stuck.","operationId":"sync_repositories","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"202":{"description":"Repository sync started in background","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositorySyncStartedResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"409":{"description":"Sync already in progress"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}/update-token":{"post":{"tags":["Git Provider Connections"],"summary":"Update access token for a connection (when tokens expire or are rotated)","operationId":"update_connection_token","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTokenRequest"}}},"required":true},"responses":{"200":{"description":"Token updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTokenResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-connections/{connection_id}/validate":{"get":{"tags":["Git Provider Connections"],"summary":"Validate a connection by testing the access token","operationId":"validate_connection","parameters":[{"name":"connection_id","in":"path","description":"Connection ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Connection validation result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Connection not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers":{"get":{"tags":["Git Providers"],"summary":"List all git providers","operationId":"list_git_providers","responses":{"200":{"description":"List of providers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProviderResponse"}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Git Providers"],"summary":"Create a new git provider configuration","operationId":"create_git_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProviderRequest"}}},"required":true},"responses":{"201":{"description":"Provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/bitbucket":{"post":{"tags":["Git Providers"],"summary":"Create a Bitbucket Cloud provider with access token or app password authentication","operationId":"create_bitbucket_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateBitbucketRequest"}}},"required":true},"responses":{"201":{"description":"Bitbucket provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request — missing or invalid auth fields"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/generic":{"post":{"tags":["Git Providers"],"summary":"Create a Generic git provider for self-hosted or arbitrary HTTPS git hosts.\nSupports public repositories (no token) and private repositories (token-based).","operationId":"create_generic_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGenericRequest"}}},"required":true},"responses":{"201":{"description":"Generic git provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request — invalid clone URL or missing fields"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/gitea/pat":{"post":{"tags":["Git Providers"],"summary":"Create a Gitea Personal Access Token provider","operationId":"create_gitea_pat_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGiteaPATRequest"}}},"required":true},"responses":{"201":{"description":"Gitea PAT provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request — invalid URL or missing fields"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/github/pat":{"post":{"tags":["Git Providers"],"summary":"Create a GitHub Personal Access Token provider","operationId":"create_github_pat_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGitHubPATRequest"}}},"required":true},"responses":{"201":{"description":"GitHub PAT provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/gitlab/oauth":{"post":{"tags":["Git Providers"],"summary":"Create a GitLab OAuth provider","operationId":"create_gitlab_oauth_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGitLabOAuthRequest"}}},"required":true},"responses":{"201":{"description":"GitLab OAuth provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/gitlab/pat":{"post":{"tags":["Git Providers"],"summary":"Create a GitLab PAT provider","operationId":"create_gitlab_pat_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGitLabPATRequest"}}},"required":true},"responses":{"201":{"description":"GitLab PAT provider created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}":{"get":{"tags":["Git Providers"],"summary":"Get a specific git provider","operationId":"get_git_provider","parameters":[{"name":"provider_id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Provider details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Git Providers"],"summary":"Permanently delete a git provider","operationId":"delete_git_provider","parameters":[{"name":"provider_id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Provider deleted successfully"},"400":{"description":"Provider has connections and cannot be deleted"},"401":{"description":"Unauthorized"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/activate":{"post":{"tags":["Git Providers"],"summary":"Activate a git provider","operationId":"activate_provider","parameters":[{"name":"provider_id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Provider activated successfully"},"401":{"description":"Unauthorized"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/callback":{"get":{"tags":["Git Providers"],"summary":"Handle OAuth callback for a git provider","operationId":"handle_git_provider_oauth_callback","parameters":[{"name":"provider_id","in":"path","description":"Git provider ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"code","in":"query","description":"OAuth authorization code","required":true,"schema":{"type":"string"}},{"name":"state","in":"query","description":"CSRF state token","required":true,"schema":{"type":"string"}}],"responses":{"302":{"description":"Redirect to success page"},"400":{"description":"Bad request"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}}}},"/git-providers/{provider_id}/connections":{"get":{"tags":["Git Providers"],"summary":"Get connections for a specific git provider","operationId":"get_provider_connections","parameters":[{"name":"provider_id","in":"path","description":"Provider ID to get connections for","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of connections for the provider","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ConnectionResponse"}}}}},"401":{"description":"Unauthorized"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/credentials":{"patch":{"tags":["Git Providers"],"summary":"Partially update credentials for an existing git provider. Only the fields\nyou send are replaced; omitted fields keep their stored values. Fields that\ndon't apply to the provider's auth method are ignored on the service side.","operationId":"update_git_provider_credentials","parameters":[{"name":"provider_id","in":"path","description":"Git provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProviderCredentialsRequest"}}},"required":true},"responses":{"200":{"description":"Credentials updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/deactivate":{"post":{"tags":["Git Providers"],"summary":"Deactivate a git provider","operationId":"deactivate_provider","parameters":[{"name":"provider_id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Provider deactivated successfully"},"401":{"description":"Unauthorized"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/deletion-check":{"get":{"tags":["Git Providers"],"summary":"Check if a git provider can be safely deleted","operationId":"check_provider_deletion_safety","parameters":[{"name":"provider_id","in":"path","description":"Git provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deletion check result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderDeletionCheckResponse"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/oauth/authorize":{"get":{"tags":["Git Providers"],"summary":"Start OAuth flow for a git provider","operationId":"start_git_provider_oauth","parameters":[{"name":"provider_id","in":"path","description":"Git provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"302":{"description":"Redirect to OAuth provider"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/repositories":{"get":{"tags":["Git Providers"],"summary":"List all repositories for a specific provider","description":"Lists repositories synced to the database across every connection under\nthis provider, with the same pagination/filtering as `/repositories`.","operationId":"list_repositories_by_provider","parameters":[{"name":"provider_id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"sort","in":"query","description":"Sort field (name, created_at, updated_at, stars, watchers, size, issues)","required":false,"schema":{"type":"string"}},{"name":"direction","in":"query","description":"Sort direction (asc, desc)","required":false,"schema":{"type":"string"}},{"name":"search","in":"query","description":"Search term to filter repositories","required":false,"schema":{"type":"string"}},{"name":"owner","in":"query","description":"Filter by repository owner","required":false,"schema":{"type":"string"}},{"name":"language","in":"query","description":"Filter by programming language","required":false,"schema":{"type":"string"}},{"name":"private","in":"query","description":"Filter by private status (true/false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of repositories","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositoryListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git-providers/{provider_id}/safe-delete":{"delete":{"tags":["Git Providers"],"summary":"Safely delete a git provider (only if no projects are using it)","operationId":"delete_provider_safely","parameters":[{"name":"provider_id","in":"path","description":"Git provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Provider successfully deleted"},"400":{"description":"Cannot delete provider because it's in use"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/git/public/{provider}/{owner}/{repo}":{"get":{"tags":["Public Repositories"],"summary":"Get information about a public repository (supports GitHub and GitLab)","operationId":"get_public_repository","parameters":[{"name":"provider","in":"path","description":"Git provider (github or gitlab)","required":true,"schema":{"type":"string"}},{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"repo","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Repository information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicRepositoryInfo"}}}},"400":{"description":"Provider not supported"},"404":{"description":"Repository not found"},"429":{"description":"API rate limit exceeded"},"500":{"description":"Internal server error"}}}},"/git/public/{provider}/{owner}/{repo}/branches":{"get":{"tags":["Public Repositories"],"summary":"Get branches for a public repository (supports GitHub and GitLab)","operationId":"get_public_branches","parameters":[{"name":"provider","in":"path","description":"Git provider (github or gitlab)","required":true,"schema":{"type":"string"}},{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"repo","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}},{"name":"fresh","in":"query","description":"Force fetch fresh data, bypassing cache (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of branches","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BranchListResponse"}}}},"400":{"description":"Provider not supported"},"404":{"description":"Repository not found"},"429":{"description":"API rate limit exceeded"},"500":{"description":"Internal server error"}}}},"/git/public/{provider}/{owner}/{repo}/presets":{"get":{"tags":["Public Repositories"],"summary":"Detect presets for a public repository (supports GitHub and GitLab)","operationId":"detect_public_presets","parameters":[{"name":"provider","in":"path","description":"Git provider (github or gitlab)","required":true,"schema":{"type":"string"}},{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"repo","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}},{"name":"branch","in":"query","description":"Branch name to detect presets for (default: repository's default branch)","required":false,"schema":{"type":["string","null"]}},{"name":"fresh","in":"query","description":"Force fetch fresh data, bypassing cache (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Detected presets","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicPresetResponse"}}}},"400":{"description":"Provider not supported"},"404":{"description":"Repository or branch not found"},"429":{"description":"API rate limit exceeded"},"500":{"description":"Internal server error"}}}},"/imports/discover":{"post":{"tags":["Imports"],"summary":"Discover workloads from a source","operationId":"discover_workloads","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiscoverRequest"}}},"required":true},"responses":{"200":{"description":"List of discovered workloads","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiscoverResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/imports/execute":{"post":{"tags":["Imports"],"summary":"Execute an import","operationId":"execute_import","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecuteImportRequest"}}},"required":true},"responses":{"202":{"description":"Import execution started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecuteImportResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/imports/plan":{"post":{"tags":["Imports"],"summary":"Create an import plan","operationId":"create_plan","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePlanRequest"}}},"required":true},"responses":{"200":{"description":"Import plan created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePlanResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/imports/sources":{"get":{"tags":["Imports"],"summary":"List available import sources","operationId":"list_sources","responses":{"200":{"description":"List of available import sources","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ImportSourceInfo"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/imports/{session_id}":{"get":{"tags":["Imports"],"summary":"Get import status","operationId":"get_import_status","parameters":[{"name":"session_id","in":"path","description":"Import session ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Import status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportStatusResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Import session not found"}},"security":[{"bearer_auth":[]}]}},"/incidents/{incident_id}":{"get":{"tags":["Status Page"],"summary":"Get an incident by ID","operationId":"get_incident","parameters":[{"name":"incident_id","in":"path","description":"Incident ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved incident","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncidentResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Incident not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/incidents/{incident_id}/status":{"patch":{"tags":["Status Page"],"summary":"Update incident status","operationId":"update_incident_status","parameters":[{"name":"incident_id","in":"path","description":"Incident ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateIncidentStatusRequest"}}},"required":true},"responses":{"200":{"description":"Incident status updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncidentResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Incident not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/incidents/{incident_id}/updates":{"get":{"tags":["Status Page"],"summary":"Get incident updates","operationId":"get_incident_updates","parameters":[{"name":"incident_id","in":"path","description":"Incident ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved incident updates","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/IncidentUpdateResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Incident not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/internal/nodes":{"get":{"tags":["Nodes"],"summary":"List all registered nodes (admin — session auth via RequireAuth)","operationId":"admin_list_nodes","responses":{"200":{"description":"List of nodes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NodeListResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/internal/nodes/register":{"post":{"tags":["Nodes"],"summary":"Register a new worker node or reconnect an existing one","operationId":"register_node","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterNodeApiRequest"}}},"required":true},"responses":{"200":{"description":"Node reconnected successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterNodeResponse"}}}},"201":{"description":"Node registered successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterNodeResponse"}}}},"400":{"description":"Validation error"},"500":{"description":"Internal server error"}}}},"/internal/nodes/{node_id}":{"get":{"tags":["Nodes"],"summary":"Get a specific node by ID (admin — session auth via RequireAuth)","operationId":"admin_get_node","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Node details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NodeInfoResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Nodes"],"summary":"Remove a node from the cluster entirely. The node should be drained first\nto ensure containers have been rescheduled. If the node still has active\ncontainers, it will be drained automatically before removal.","operationId":"admin_remove_node","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Node removed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RemoveNodeResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Node not found"},"409":{"description":"Node still has active containers"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/internal/nodes/{node_id}/containers":{"get":{"tags":["Nodes"],"summary":"List all containers running on a specific node","operationId":"admin_list_node_containers","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Containers on this node","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NodeContainerListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/internal/nodes/{node_id}/dns/ack":{"post":{"tags":["Internal DNS"],"summary":"`POST /internal/nodes/{node_id}/dns/ack`","operationId":"post_dns_ack","parameters":[{"name":"node_id","in":"path","description":"Node id, must match the bearer token's node","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsAckRequest"}}},"required":true},"responses":{"200":{"description":"ACK accepted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsAckResponse"}}}},"400":{"description":"ACK higher than server generation"},"401":{"description":"Missing or invalid bearer token"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}}}},"/internal/nodes/{node_id}/dns/changes":{"get":{"tags":["Internal DNS"],"summary":"`GET /internal/nodes/{node_id}/dns/changes?since=N`","operationId":"get_dns_changes","parameters":[{"name":"node_id","in":"path","description":"Node id, must match the bearer token's node","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"since","in":"query","description":"Highest generation the agent has already applied. Pass `0` to\nrequest a full zone snapshot. Defaults to `0` if omitted.","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Diff or full snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsChangesResponse"}}}},"401":{"description":"Missing or invalid bearer token"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}}}},"/internal/nodes/{node_id}/drain":{"get":{"tags":["Nodes"],"summary":"Get the drain status for a node, including migration progress.","description":"Returns container counts and whether the drain is complete.\nCan be polled to track drain progress.","operationId":"admin_drain_status","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Drain status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DrainStatusResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Nodes"],"summary":"Drain a node: mark it as \"draining\" so no new replicas are scheduled on it,\nand trigger redeployment of all affected environments so their containers\nare rescheduled to healthy nodes.","operationId":"admin_drain_node","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Node drain initiated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DrainNodeResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Nodes"],"summary":"Undrain (reactivate) a node so it can accept new deployments again.\nOnly works for nodes in \"draining\" or \"drained\" status.","operationId":"admin_undrain_node","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Node reactivated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UndrainNodeResponse"}}}},"400":{"description":"Node not in drainable state"},"401":{"description":"Unauthorized"},"404":{"description":"Node not found"}},"security":[{"bearer_auth":[]}]}},"/internal/nodes/{node_id}/heartbeat":{"post":{"tags":["Nodes"],"summary":"Receive a heartbeat from a worker node","operationId":"node_heartbeat","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HeartbeatApiRequest"}}},"required":true},"responses":{"200":{"description":"Heartbeat received","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HeartbeatResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}}}},"/internal/nodes/{node_id}/network/peers":{"get":{"tags":["Nodes"],"summary":"`GET /internal/nodes/{node_id}/network/peers`","operationId":"list_peers","parameters":[{"name":"node_id","in":"path","description":"Node id, must match the bearer token's node","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Peer list and self-allocation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PeerListResponse"}}}},"401":{"description":"Missing or invalid bearer token"},"404":{"description":"Node not found"},"500":{"description":"Internal server error"}}}},"/internal/nodes/{node_id}/s3-credentials/{s3_source_id}":{"get":{"tags":["Nodes"],"summary":"Get decrypted S3 credentials for a backup/restore operation.","description":"Agents call this endpoint to receive the S3 credentials they need to upload\nor download backups. The credentials are decrypted from the stored S3 source\nand returned over the authenticated TLS/WireGuard channel.","operationId":"get_s3_credentials","parameters":[{"name":"node_id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"s3_source_id","in":"path","description":"S3 source ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"S3 credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/S3CredentialsResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"S3 source not found"},"500":{"description":"Internal server error"}}}},"/ip-access-control":{"get":{"tags":["IP Access Control"],"summary":"List all IP access control rules","operationId":"list_ip_access_control","parameters":[{"name":"action","in":"query","description":"Filter by action (\"block\" or \"allow\")","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"List of IP access control rules","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/IpAccessControlResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["IP Access Control"],"summary":"Create a new IP access control rule","operationId":"create_ip_access_control","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateIpAccessControlRequest"}}},"required":true},"responses":{"201":{"description":"IP access control rule created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IpAccessControlResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"409":{"description":"Duplicate IP address","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ip-access-control/check/{ip}":{"get":{"tags":["IP Access Control"],"summary":"Check if an IP address is blocked","operationId":"check_ip_blocked","parameters":[{"name":"ip","in":"path","description":"IP address to check","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"IP block status"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/ip-access-control/{id}":{"get":{"tags":["IP Access Control"],"summary":"Get a single IP access control rule by ID","operationId":"get_ip_access_control","parameters":[{"name":"id","in":"path","description":"IP access control rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"IP access control rule details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IpAccessControlResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"IP access control rule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["IP Access Control"],"summary":"Delete an IP access control rule","operationId":"delete_ip_access_control","parameters":[{"name":"id","in":"path","description":"IP access control rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"IP access control rule deleted"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"IP access control rule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["IP Access Control"],"summary":"Update an IP access control rule","operationId":"update_ip_access_control","parameters":[{"name":"id","in":"path","description":"IP access control rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateIpAccessControlRequest"}}},"required":true},"responses":{"200":{"description":"IP access control rule updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IpAccessControlResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"IP access control rule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/kv/del":{"post":{"tags":["KV Store"],"summary":"Delete one or more keys","operationId":"kv_del","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DelRequest"}}},"required":true},"responses":{"200":{"description":"Keys deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DelResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/disable":{"delete":{"tags":["KV Management"],"summary":"Disable KV service","operationId":"kv_disable","responses":{"200":{"description":"KV service disabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DisableKvResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"KV service not enabled"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/enable":{"post":{"tags":["KV Management"],"summary":"Enable KV service","operationId":"kv_enable","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnableKvRequest"}}},"required":true},"responses":{"200":{"description":"KV service enabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnableKvResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/expire":{"post":{"tags":["KV Store"],"summary":"Set expiration on a key","operationId":"kv_expire","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExpireRequest"}}},"required":true},"responses":{"200":{"description":"Expiration set","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExpireResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/get":{"post":{"tags":["KV Store"],"summary":"Get a value by key","operationId":"kv_get","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetRequest"}}},"required":true},"responses":{"200":{"description":"Value retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/incr":{"post":{"tags":["KV Store"],"summary":"Increment a numeric value","operationId":"kv_incr","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncrRequest"}}},"required":true},"responses":{"200":{"description":"Value incremented","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncrResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/keys":{"post":{"tags":["KV Store"],"summary":"Get keys matching a pattern","operationId":"kv_keys","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KeysRequest"}}},"required":true},"responses":{"200":{"description":"Keys retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KeysResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/set":{"post":{"tags":["KV Store"],"summary":"Set a value with optional expiration","operationId":"kv_set","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetRequest"}}},"required":true},"responses":{"200":{"description":"Value set","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/status":{"get":{"tags":["KV Management"],"summary":"Get KV service status","operationId":"kv_status","responses":{"200":{"description":"KV service status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KvStatusResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/ttl":{"post":{"tags":["KV Store"],"summary":"Get time-to-live for a key","operationId":"kv_ttl","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TtlRequest"}}},"required":true},"responses":{"200":{"description":"TTL retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TtlResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/kv/update":{"patch":{"tags":["KV Management"],"summary":"Update KV service configuration","operationId":"kv_update","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateKvRequest"}}},"required":true},"responses":{"200":{"description":"KV service updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateKvResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"KV service not enabled"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/lb/routes":{"get":{"tags":["Load Balancer"],"operationId":"list_routes","responses":{"200":{"description":"List of routes","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RouteResponse"}}}}},"500":{"description":"Internal server error"}}},"post":{"tags":["Load Balancer"],"operationId":"create_route","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRouteRequest"}}},"required":true},"responses":{"201":{"description":"Route created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteResponse"}}}},"400":{"description":"Invalid request"}}}},"/lb/routes/{domain}":{"get":{"tags":["Load Balancer"],"operationId":"get_route","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Route found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteResponse"}}}},"404":{"description":"Route not found"}}},"put":{"tags":["Load Balancer"],"operationId":"update_route","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateRouteRequest"}}},"required":true},"responses":{"200":{"description":"Route updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteResponse"}}}},"404":{"description":"Route not found"}}},"delete":{"tags":["Load Balancer"],"operationId":"delete_route","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Route deleted successfully"},"404":{"description":"Route not found"}}}},"/logout":{"post":{"tags":["Authentication"],"operationId":"logout","responses":{"200":{"description":"Successfully logged out"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"session_token":[]}]}},"/logs/context":{"get":{"tags":["Logs"],"summary":"Get context lines surrounding a specific log line","operationId":"get_log_context","parameters":[{"name":"chunk_id","in":"query","description":"Chunk ID","required":true,"schema":{"type":"string"}},{"name":"line_offset","in":"query","description":"Line offset within the chunk","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"lines","in":"query","description":"Context lines before and after (default: 25)","required":false,"schema":{"type":"integer","format":"int32","minimum":0}}],"responses":{"200":{"description":"Context lines","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContextLogsResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Chunk not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/logs/search":{"post":{"tags":["Logs"],"summary":"Search logs with structured filters and full text search","operationId":"search_logs","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchLogsRequest"}}},"required":true},"responses":{"200":{"description":"Search results","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchLogsResponse"}}}},"400":{"description":"Invalid search parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/logs/tail":{"get":{"tags":["Logs"],"summary":"Live tail logs via Server-Sent Events","operationId":"tail_logs","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"string"}},{"name":"service","in":"query","description":"Service name","required":true,"schema":{"type":"string"}},{"name":"env","in":"query","description":"Environment","required":true,"schema":{"type":"string"}},{"name":"levels","in":"query","description":"Optional level filters","required":true,"schema":{"type":"array","items":{"type":"string"}}},{"name":"text","in":"query","description":"Optional text filter","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"SSE stream of log lines"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/monitors-health/projects":{"get":{"tags":["Status Page"],"summary":"Get monitor-based health summaries for multiple projects in a single query","operationId":"get_projects_monitor_health","parameters":[{"name":"project_ids","in":"query","description":"Comma-separated list of project IDs","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Health summaries per project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectsMonitorHealthResponse"}}}},"400":{"description":"Invalid parameters"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/monitors/{monitor_id}":{"get":{"tags":["Status Page"],"summary":"Get a monitor by ID","operationId":"get_monitor","parameters":[{"name":"monitor_id","in":"path","description":"Monitor ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved monitor","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MonitorResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Monitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Status Page"],"summary":"Delete a monitor","operationId":"delete_monitor","parameters":[{"name":"monitor_id","in":"path","description":"Monitor ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Monitor deleted successfully"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Monitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/monitors/{monitor_id}/bucketed":{"get":{"tags":["Status Page"],"summary":"Get bucketed status data for a monitor using TimescaleDB","operationId":"get_bucketed_status","parameters":[{"name":"monitor_id","in":"path","description":"Monitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"interval","in":"query","description":"Bucket interval: '5min', 'hourly', or 'daily' (default: hourly)","required":false,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601) (default: 24 hours ago)","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (ISO 8601) (default: now)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved bucketed status data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatusBucketedResponse"}}}},"400":{"description":"Invalid parameters"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Monitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/monitors/{monitor_id}/current-status":{"get":{"tags":["Status Page"],"summary":"Get current status and uptime metrics for a monitor","operationId":"get_current_monitor_status","parameters":[{"name":"monitor_id","in":"path","description":"Monitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_time","in":"query","description":"Custom start time (ISO 8601) - overrides timeframe","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"Custom end time (ISO 8601)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved current status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CurrentStatusResponse"}}}},"400":{"description":"Invalid time parameters"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Monitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/monitors/{monitor_id}/uptime":{"get":{"tags":["Status Page"],"summary":"Get uptime history for a monitor","operationId":"get_uptime_history","parameters":[{"name":"monitor_id","in":"path","description":"Monitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"days","in":"query","description":"Number of days of history (default: 60) - ignored if start_time/end_time provided","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601) - overrides days parameter","required":true,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (ISO 8601) - defaults to now","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved uptime history","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UptimeHistoryResponse"}}}},"400":{"description":"Invalid time parameters"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Monitor not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/nodes/{id}/metrics":{"get":{"tags":["Metrics"],"summary":"Fetch a time-series range for a single metric on a node.","operationId":"NodeMetricsGetRange","parameters":[{"name":"id","in":"path","description":"Node ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"metric","in":"query","description":"Metric name, e.g. `\"pg.connections_active\"`.","required":true,"schema":{"type":"string"}},{"name":"range","in":"query","description":"Time window: `\"1h\"` | `\"6h\"` | `\"24h\"` | `\"7d\"`.","required":false,"schema":{"type":"string"}},{"name":"percentile","in":"query","description":"Optional histogram percentile (0–100). When provided, the endpoint\nfetches histogram buckets and computes the requested quantile.","required":false,"schema":{"type":["number","null"],"format":"double"}}],"responses":{"200":{"description":"Metric time series data points","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MetricDataPoint"}}}}},"400":{"description":"Invalid query parameters"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"},"503":{"description":"Metrics store not available"}},"security":[{"bearer_auth":[]}]}},"/notification-preferences":{"get":{"tags":["Notification Preferences"],"summary":"Get notification preferences","operationId":"get_preferences","responses":{"200":{"description":"Successfully retrieved preferences","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationPreferencesResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Notification Preferences"],"summary":"Update notification preferences","operationId":"update_preferences","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePreferencesRequest"}}},"required":true},"responses":{"200":{"description":"Successfully updated preferences","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationPreferencesResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Notification Preferences"],"summary":"Delete notification preferences","operationId":"delete_preferences","responses":{"204":{"description":"Successfully deleted preferences"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers":{"get":{"tags":["Notification Providers"],"summary":"List all notification providers","operationId":"list_notification_providers","parameters":[{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20},{"name":"sort_by","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"Successfully retrieved providers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}}},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Notification Providers"],"summary":"Create a new notification provider","operationId":"create_notification_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProviderRequest"}}},"required":true},"responses":{"201":{"description":"Successfully created provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"400":{"description":"Invalid request"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/cloudflare":{"post":{"tags":["Notification Providers"],"summary":"Create a new Cloudflare Email Sending notification provider","operationId":"create_cloudflare_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCloudflareProviderRequest"}}},"required":true},"responses":{"201":{"description":"Successfully created Cloudflare provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"400":{"description":"Invalid request"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/cloudflare/{id}":{"put":{"tags":["Notification Providers"],"summary":"Update a Cloudflare Email Sending notification provider","operationId":"update_cloudflare_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCloudflareProviderRequest"}}},"required":true},"responses":{"200":{"description":"Successfully updated Cloudflare provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/email":{"post":{"tags":["Notification Providers"],"summary":"Create a new Email notification provider","operationId":"create_notification_email_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateNotificationEmailProviderRequest"}}},"required":true},"responses":{"201":{"description":"Successfully created Email provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"400":{"description":"Invalid request"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/email/{id}":{"put":{"tags":["Notification Providers"],"summary":"Update an Email notification provider","operationId":"update_notification_email_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateNotificationEmailProviderRequest"}}},"required":true},"responses":{"200":{"description":"Successfully updated Email provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/slack":{"post":{"tags":["Notification Providers"],"summary":"Create a new Slack notification provider","operationId":"create_slack_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSlackProviderRequest"}}},"required":true},"responses":{"201":{"description":"Successfully created Slack provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"400":{"description":"Invalid request"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/slack/{id}":{"put":{"tags":["Notification Providers"],"summary":"Update a Slack notification provider","operationId":"update_slack_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSlackProviderRequest"}}},"required":true},"responses":{"200":{"description":"Successfully updated Slack provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/webhook":{"post":{"tags":["Notification Providers"],"summary":"Create a new Webhook notification provider","description":"Webhook providers send notifications as JSON payloads to any HTTP endpoint.\nYou can configure custom headers for authentication (Bearer tokens, API keys, etc.).\nThe webhook will receive a JSON payload with notification details including:\nid, title, message, type, priority, severity, timestamp, and metadata.","operationId":"create_webhook_provider","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWebhookProviderRequest"}}},"required":true},"responses":{"201":{"description":"Successfully created Webhook provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"400":{"description":"Invalid request"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/webhook/{id}":{"put":{"tags":["Notification Providers"],"summary":"Update a Webhook notification provider","operationId":"update_webhook_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWebhookProviderRequest"}}},"required":true},"responses":{"200":{"description":"Successfully updated Webhook provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/{id}":{"get":{"tags":["Notification Providers"],"summary":"Get a single notification provider","operationId":"get_notification_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Notification Providers"],"summary":"Update a notification provider","operationId":"update_notification_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProviderRequest"}}},"required":true},"responses":{"200":{"description":"Successfully updated provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationProviderResponse"}}}},"400":{"description":"Invalid masked provider configuration"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Notification Providers"],"summary":"Delete a notification provider","operationId":"delete_notification_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Successfully deleted provider"},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/{id}/config/{field}":{"get":{"tags":["Notification Providers"],"operationId":"reveal_notification_provider_config","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"field","in":"path","description":"Sensitive field, such as password or headers.Authorization","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sensitive provider configuration value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SensitiveConfigValueResponse"}}}},"400":{"description":"Field is not revealable"},"403":{"description":"Missing secrets:read permission"},"404":{"description":"Provider or field not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/notification-providers/{id}/test":{"post":{"tags":["Notification Providers"],"summary":"Test a notification provider","operationId":"test_notification_provider","parameters":[{"name":"id","in":"path","description":"Provider ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Test result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestProviderResponse"}}}},"404":{"description":"Provider not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/orders":{"get":{"tags":["Domains"],"summary":"List all ACME orders","operationId":"list_orders","parameters":[{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20},{"name":"sort_by","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"Orders retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListOrdersResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/otel/alerts":{"get":{"tags":["Alerts"],"summary":"List alert rules for a project (newest first, paginated).","operationId":"list_alerts","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Alert rules for the project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricAlertsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Alerts"],"summary":"Create a new alert rule for a project.","operationId":"create_alert","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMetricAlertRequest"}}},"required":true},"responses":{"201":{"description":"Alert rule created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricAlertRuleResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/alerts/preview":{"post":{"tags":["Alerts"],"summary":"Backtest an anomaly detector over a time range without saving a rule.","description":"Replays the metric against the same band the evaluator would use, returning\nthe per-bucket band + which points would have fired. Powers the form's\n\"would this have fired?\" preview and the explorer band overlay. Read-only.","operationId":"preview_alert","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnomalyPreviewRequest"}}},"required":true},"responses":{"200":{"description":"Per-bucket band + breach points","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnomalyPreviewResponse"}}}},"400":{"description":"Not an anomaly detector / bad input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/alerts/{id}":{"get":{"tags":["Alerts"],"summary":"Fetch a single alert rule by id.","operationId":"get_alert","parameters":[{"name":"id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Owning project ID (scopes the lookup)","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Alert rule","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricAlertRuleResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Alert rule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Alerts"],"summary":"Delete an alert rule.","operationId":"delete_alert","parameters":[{"name":"id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Owning project ID (scopes the delete)","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Alert rule deleted"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Alert rule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Alerts"],"summary":"Update an alert rule's fields.","operationId":"update_alert","parameters":[{"name":"id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Owning project ID (scopes the update)","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMetricAlertRequest"}}},"required":true},"responses":{"200":{"description":"Alert rule updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricAlertRuleResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Alert rule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/dashboards":{"get":{"tags":["Dashboards"],"summary":"List dashboards for a project (newest first, paginated).","operationId":"list_dashboards","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Dashboards for the project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelDashboardsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Dashboards"],"summary":"Create a new dashboard for a project.","operationId":"create_dashboard","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDashboardRequest"}}},"required":true},"responses":{"201":{"description":"Dashboard created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelDashboardResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/dashboards/{id}":{"get":{"tags":["Dashboards"],"summary":"Fetch a single dashboard by id.","operationId":"get_dashboard","parameters":[{"name":"id","in":"path","description":"Dashboard ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Owning project ID (scopes the lookup)","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Dashboard","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelDashboardResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Dashboard not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Dashboards"],"summary":"Delete a dashboard.","operationId":"delete_dashboard","parameters":[{"name":"id","in":"path","description":"Dashboard ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Owning project ID (scopes the delete)","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Dashboard deleted"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Dashboard not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Dashboards"],"summary":"Update a dashboard's name and/or layout.","operationId":"update_dashboard","parameters":[{"name":"id","in":"path","description":"Dashboard ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"project_id","in":"query","description":"Owning project ID (scopes the update)","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDashboardRequest"}}},"required":true},"responses":{"200":{"description":"Dashboard updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelDashboardResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Dashboard not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/genai/traces":{"get":{"tags":["GenAI"],"summary":"Query GenAI trace summaries — traces containing spans with `gen_ai.*` attributes.","description":"`duration_ms` is the only field guaranteed to be milliseconds. `gen_ai.*`\nspan attributes (e.g. time-to-first-token, token latency) often follow the\nOTel GenAI semantic conventions, which use **seconds** (a fractional\ndouble), not milliseconds — do not read them as ms without converting.","operationId":"query_genai_traces","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"service_name","in":"query","description":"Filter by service name","required":false,"schema":{"type":"string"}},{"name":"gen_ai_system","in":"query","description":"Filter by AI system (openai, anthropic, etc.)","required":false,"schema":{"type":"string"}},{"name":"gen_ai_model","in":"query","description":"Filter by model (gpt-4, claude-sonnet-4-20250514, etc.)","required":false,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Start time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max traces to return (default: 50, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"offset","in":"query","description":"Offset for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"GenAI trace summaries","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenAiTraceSummariesResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/genai/traces/{project_id}/{trace_id}":{"get":{"tags":["GenAI"],"summary":"Get GenAI span details for a specific trace.","description":"`duration_ms` is the only field guaranteed to be milliseconds. `gen_ai.*`\nspan attributes (e.g. time-to-first-token, token latency) often follow the\nOTel GenAI semantic conventions, which use **seconds** (a fractional\ndouble), not milliseconds — do not read them as ms without converting.","operationId":"get_genai_trace","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"trace_id","in":"path","description":"Trace ID (hex)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"GenAI trace span details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenAiTraceDetailResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/global/traces/{trace_id}":{"get":{"tags":["Traces"],"summary":"Assemble a unified cross-project span waterfall (Phase 2).","description":"Fans out to every project that holds spans for `trace_id` (up to 20\nprojects, 10,000 total spans). Spans are annotated with\n`project_id`/`project_name` and sorted by `start_time ASC`.\n`truncated: true` signals a hit on either cap; `truncated_projects`\nlists the dropped project IDs. See ADR-027 §4 for the full design.","operationId":"getUnifiedTrace","parameters":[{"name":"trace_id","in":"path","description":"Trace ID (32 lowercase hex characters)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Unified cross-project trace waterfall","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnifiedTrace"}}}},"400":{"description":"trace_id is not 32 lowercase hex characters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions or deployment token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/health/{project_id}":{"get":{"tags":["OTel"],"summary":"Get health summaries for a project.","operationId":"get_health","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Health summaries","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/insights/{project_id}":{"get":{"tags":["Insights"],"summary":"List anomaly insights for a project.","operationId":"list_insights","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"status","in":"query","description":"Filter by status (active, resolved)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max insights to return (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"offset","in":"query","description":"Offset for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Insights list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InsightsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/logs":{"get":{"tags":["Telemetry Logs"],"summary":"Query log records with optional filters.","operationId":"query_logs","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"severity","in":"query","description":"Filter by severity (TRACE, DEBUG, INFO, WARN, ERROR, FATAL)","required":false,"schema":{"type":"string"}},{"name":"service_name","in":"query","description":"Filter by service name","required":false,"schema":{"type":"string"}},{"name":"search","in":"query","description":"Full-text search in log body (ILIKE)","required":false,"schema":{"type":"string"}},{"name":"trace_id","in":"query","description":"Filter by correlated trace ID","required":false,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Start time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max logs to return (default: 100, max: 1000)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"offset","in":"query","description":"Offset for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Log records","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LogsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/metric-label-keys":{"get":{"tags":["Telemetry Metrics"],"summary":"List the attribute (label) keys observed on a metric — powers the\nlabel-filter key autocomplete.","operationId":"list_metric_label_keys","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"metric_name","in":"query","description":"Metric to inspect","required":true,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Window start (RFC 3339); defaults to 24h before end","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"Window end (RFC 3339); defaults to now","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Distinct label keys","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricLabelKeysResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/metric-label-values":{"get":{"tags":["Telemetry Metrics"],"summary":"List the distinct values seen for a label key on a metric — powers value\nautocomplete once a key is chosen.","operationId":"list_metric_label_values","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"metric_name","in":"query","description":"Metric to inspect","required":true,"schema":{"type":"string"}},{"name":"label_key","in":"query","description":"Label key whose values to list (must match [a-zA-Z0-9_.:-])","required":true,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Window start (RFC 3339); defaults to 24h before end","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"Window end (RFC 3339); defaults to now","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Distinct label values","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricLabelValuesResponse"}}}},"400":{"description":"Invalid label key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/metric-names/{project_id}":{"get":{"tags":["Telemetry Metrics"],"summary":"List distinct metric names for a project.","operationId":"list_metric_names","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of metric names","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricNamesResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/metrics":{"get":{"tags":["Telemetry Metrics"],"summary":"Query metrics with time bucketing.","operationId":"query_metrics","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"metric_name","in":"query","description":"Filter by metric name","required":false,"schema":{"type":"string"}},{"name":"service_name","in":"query","description":"Filter by service name","required":false,"schema":{"type":"string"}},{"name":"environment","in":"query","description":"Filter by deployment environment","required":false,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Start time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"bucket_interval","in":"query","description":"Bucket interval (e.g. '1 hour', '5 minutes')","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max buckets to return (default: 1000)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"metric_type","in":"query","description":"Filter by metric type (gauge, sum, histogram, exponential_histogram, summary)","required":false,"schema":{"type":"string"}},{"name":"aggregation","in":"query","description":"Per-bucket aggregation: avg (default), sum, min, max, count, rate, p50/p95/p99, quantile:0.95","required":false,"schema":{"type":"string"}},{"name":"label_filters","in":"query","description":"Comma-separated key=value data-point label filters (keys must match [a-zA-Z0-9_.:-])","required":false,"schema":{"type":"string"}},{"name":"group_by","in":"query","description":"Comma-separated label keys to group series by","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Metrics data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtelMetricsResponse"}}}},"400":{"description":"Invalid label key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/pipeline-stats":{"get":{"tags":["OTel"],"summary":"Get OTel pipeline statistics (admin/system view).","operationId":"get_pipeline_stats","responses":{"200":{"description":"Pipeline statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PipelineStatsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/quota/{project_id}":{"get":{"tags":["OTel"],"summary":"Get storage quota for a project.","operationId":"get_quota","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Storage quota","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuotaResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/span-stats":{"get":{"tags":["Traces"],"summary":"Rank operations by latency, volume, or inconsistency.","description":"Groups spans by `(project, service, span name)` over a bounded window and\nreturns count, error rate, total/min/max/avg/stddev duration, p50/p95/p99,\nand two variability ratios per operation. Sorting is what makes it useful:\n\n- `sort_by=total_time` (default) — where the wall-clock actually goes.\n- `sort_by=p95` / `p99` — what users actually feel.\n- `sort_by=variability` or `tail_ratio` — operations whose *spread* is the\n problem: the ones that take 40ms most of the time and 4s the rest.\n- `span_name=payments.charge` — the worst this one operation ever got, in\n `max_duration_ms`.\n\nPair the variability sorts with `min_count` — a ratio computed from three\nsamples is noise, and without a floor it outranks every real signal.\n\nTwo bounds are enforced rather than clamped, so a result never claims to\ncover more than it does: at most 50 projects, and a window no wider than\n31 days. Both return 400. Unlike the trace list this report has no early\nexit — it aggregates every span in the window before it can rank anything.","operationId":"query_span_stats","parameters":[{"name":"project_id","in":"query","description":"Single project to report on","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"project_ids","in":"query","description":"Comma-separated project ids, e.g. `4,5,6` (max 50)","required":false,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Window start (RFC 3339); defaults to 24h before end_time. The window may not exceed 31 days","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"Window end (RFC 3339); defaults to now","required":false,"schema":{"type":"string"}},{"name":"service_name","in":"query","description":"Restrict to one service","required":false,"schema":{"type":"string"}},{"name":"span_name","in":"query","description":"Restrict to one operation by exact span name","required":false,"schema":{"type":"string"}},{"name":"name_pattern","in":"query","description":"Case-insensitive substring match on the span name","required":false,"schema":{"type":"string"}},{"name":"kind","in":"query","description":"server | client | internal | producer | consumer","required":false,"schema":{"type":"string"}},{"name":"status","in":"query","description":"ok | error | unset","required":false,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Restrict to one environment","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Restrict to one deployment","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"attributes","in":"query","description":"Comma-separated key=value span attribute filters","required":false,"schema":{"type":"string"}},{"name":"min_duration_ms","in":"query","description":"Ignore spans faster than this","required":false,"schema":{"type":"number","format":"double"}},{"name":"min_count","in":"query","description":"Drop operations with fewer samples than this","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"sort_by","in":"query","description":"total_time | p50 | p95 | p99 | max | avg | stddev | count | errors | error_rate | variability | tail_ratio","required":false,"schema":{"type":"string"}},{"name":"sort_order","in":"query","description":"asc | desc (default)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Page size (default 20, max 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"offset","in":"query","description":"Page offset","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Per-operation latency statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpanStatsResponse"}}}},"400":{"description":"Invalid query (no project, empty window)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/trace-summaries":{"get":{"tags":["Traces"],"summary":"Query trace summaries — one row per trace with span count, error count,\nroot span info, and proper trace-level pagination.","operationId":"query_trace_summaries","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"trace_id","in":"query","description":"Filter by trace ID","required":false,"schema":{"type":"string"}},{"name":"service_name","in":"query","description":"Filter by service name","required":false,"schema":{"type":"string"}},{"name":"status","in":"query","description":"Filter by status (OK, ERROR)","required":false,"schema":{"type":"string"}},{"name":"min_duration_ms","in":"query","description":"Minimum trace duration in ms","required":false,"schema":{"type":"number","format":"double"}},{"name":"start_time","in":"query","description":"Start time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"name_pattern","in":"query","description":"Filter by span name pattern (ILIKE)","required":false,"schema":{"type":"string"}},{"name":"sort_by","in":"query","description":"Sort field: 'start_time' (default) or 'duration'","required":false,"schema":{"type":"string"}},{"name":"sort_order","in":"query","description":"Sort direction: 'asc' or 'desc' (default)","required":false,"schema":{"type":"string"}},{"name":"include_total","in":"query","description":"Compute the `total` count (default: true). Set false to skip the second aggregation when only the page is needed","required":false,"schema":{"type":"boolean"}},{"name":"limit","in":"query","description":"Max traces to return (default: 50, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"offset","in":"query","description":"Offset for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Trace summaries","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TraceSummariesResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/traces":{"get":{"tags":["Traces"],"summary":"Query trace spans with optional filters.","description":"Each returned span has a `duration_ms` field (float, milliseconds) — this is\nthe ONLY field guaranteed to be in milliseconds. Spans also carry an\n`attributes` map of raw key/value pairs exactly as reported by the\ninstrumenting library: numeric attribute values may be seconds, milliseconds,\nmicroseconds, or nanoseconds depending on that library's convention, and\nnothing in this response labels the unit. Never assume an attribute's\nnumeric value shares `duration_ms`'s unit, and never state a duration in\nmilliseconds unless it came from a `duration_ms` field.","operationId":"query_traces","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"trace_id","in":"query","description":"Filter by trace ID","required":false,"schema":{"type":"string"}},{"name":"service_name","in":"query","description":"Filter by service name","required":false,"schema":{"type":"string"}},{"name":"status","in":"query","description":"Filter by status (OK, ERROR, UNSET)","required":false,"schema":{"type":"string"}},{"name":"min_duration_ms","in":"query","description":"Minimum span duration in ms","required":false,"schema":{"type":"number","format":"double"}},{"name":"start_time","in":"query","description":"Start time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (RFC 3339)","required":false,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"limit","in":"query","description":"Max spans to return (default: 100, max: 1000)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"offset","in":"query","description":"Offset for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Trace spans","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TracesResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/traces/cross-project/{trace_id}":{"get":{"tags":["Traces"],"summary":"Discover sibling projects that share the same `trace_id` (Phase 1 banner).","description":"Returns an empty `siblings` list when the trace is single-project — never\n404. Project names are included so the UI can render navigation links\nwithout a second round-trip. See ADR-027 §3 for the full auth model and\ntopology-disclosure trade-offs.","operationId":"getCrossProjectTraceSiblings","parameters":[{"name":"trace_id","in":"path","description":"Trace ID (32 lowercase hex characters)","required":true,"schema":{"type":"string"}},{"name":"exclude_project_id","in":"query","description":"Project ID to exclude (the caller's own project) so the UI does not render a self-link","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Sibling projects sharing this trace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CrossProjectTraceResponse"}}}},"400":{"description":"trace_id is not 32 lowercase hex characters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions or deployment token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/traces/{project_id}/{trace_id}":{"get":{"tags":["Traces"],"summary":"Get all spans for a specific trace.","description":"Each span has a `duration_ms` field (float, milliseconds) — the ONLY field\nguaranteed to be in milliseconds — plus an `attributes` map of raw\nkey/value pairs exactly as the instrumenting library reported them.\nNumeric attribute values (e.g. connection-pool wait times, queue delays)\nmay be in seconds, milliseconds, microseconds, or nanoseconds depending on\nthat library's own convention; this response never labels the unit. When\nexplaining what a span spent time on, only quote milliseconds from\n`duration_ms` (or from `start_time`/`end_time` deltas) — never assume a raw\nattribute number is already in milliseconds.","operationId":"get_trace","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"trace_id","in":"path","description":"Trace ID (hex)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Trace spans tree","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TracesResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/otel/v1/logs":{"post":{"tags":["OTel Ingest"],"summary":"Ingest log records via OTLP/HTTP protobuf.","description":"Authenticates via API key in header, decompresses, decodes protobuf,\nchecks rate limit and storage quota, routes high-severity logs\nto DB and all logs to S3.","operationId":"ingest_logs","requestBody":{"description":"OTLP ExportLogsServiceRequest (protobuf, optionally gzip/zstd compressed)","content":{"application/x-protobuf":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"Logs accepted (OTLP protobuf response)"},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"413":{"description":"Storage quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"api_key":[]}]}},"/otel/v1/metrics":{"post":{"tags":["OTel Ingest"],"summary":"Ingest metrics via OTLP/HTTP protobuf.","description":"Authenticates via API key in header, decompresses, decodes protobuf,\nchecks rate limit and storage quota, then stores.","operationId":"ingest_metrics","requestBody":{"description":"OTLP ExportMetricsServiceRequest (protobuf, optionally gzip/zstd compressed)","content":{"application/x-protobuf":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"Metrics accepted (OTLP protobuf response)"},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"413":{"description":"Storage quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"api_key":[]}]}},"/otel/v1/traces":{"post":{"tags":["OTel Ingest"],"summary":"Ingest trace spans via OTLP/HTTP protobuf.","description":"Authenticates via API key in header, decompresses, decodes protobuf,\nchecks rate limit and storage quota, then stores spans.","operationId":"ingest_traces","requestBody":{"description":"OTLP ExportTraceServiceRequest (protobuf, optionally gzip/zstd compressed)","content":{"application/x-protobuf":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"Traces accepted (OTLP protobuf response)"},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"413":{"description":"Storage quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"api_key":[]}]}},"/otel/v1/{project_id}/{environment_id}/{deployment_id}/logs":{"post":{"tags":["OTel Ingest"],"summary":"Ingest log records with project/environment/deployment in the URL path.","operationId":"ingest_logs_by_path","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"OTLP ExportLogsServiceRequest (protobuf, optionally gzip/zstd compressed)","content":{"application/x-protobuf":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"Logs accepted (OTLP protobuf response)"},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"413":{"description":"Storage quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"api_key":[]}]}},"/otel/v1/{project_id}/{environment_id}/{deployment_id}/metrics":{"post":{"tags":["OTel Ingest"],"summary":"Ingest metrics with project/environment/deployment in the URL path.","operationId":"ingest_metrics_by_path","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"OTLP ExportMetricsServiceRequest (protobuf, optionally gzip/zstd compressed)","content":{"application/x-protobuf":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"Metrics accepted (OTLP protobuf response)"},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"413":{"description":"Storage quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"api_key":[]}]}},"/otel/v1/{project_id}/{environment_id}/{deployment_id}/traces":{"post":{"tags":["OTel Ingest"],"summary":"Ingest trace spans with project/environment/deployment in the URL path.","operationId":"ingest_traces_by_path","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"OTLP ExportTraceServiceRequest (protobuf, optionally gzip/zstd compressed)","content":{"application/x-protobuf":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"Traces accepted (OTLP protobuf response)"},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"413":{"description":"Storage quota exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"api_key":[]}]}},"/performance/has-metrics":{"get":{"tags":["Performance"],"summary":"Check if performance metrics exist for a project","operationId":"has_performance_metrics","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully checked performance metrics availability","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HasMetricsResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/performance/metrics":{"get":{"tags":["Performance"],"summary":"Get performance metrics","operationId":"get_performance_metrics","parameters":[{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DD HH:MM:SS","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Deployment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"device_type","in":"query","description":"Device type filter: desktop or mobile (optional)","required":false,"schema":{"type":"string"}},{"name":"include_bots","in":"query","description":"Include crawler/datacenter bot samples (default false)","required":false,"schema":{"type":"boolean"}},{"name":"filter_path","in":"query","description":"Filter to one page pathname (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_country","in":"query","description":"Filter to one country (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_region","in":"query","description":"Filter to one region (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_city","in":"query","description":"Filter to one city (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_browser","in":"query","description":"Filter to one browser (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_operating_system","in":"query","description":"Filter to one operating system (optional)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved performance metrics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PerformanceMetricsResponse"}}}},"400":{"description":"Invalid date format or missing parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/performance/metrics-over-time":{"get":{"tags":["Performance"],"summary":"Get metrics over time","operationId":"get_metrics_over_time","parameters":[{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DDTHH:MM:SSZ","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DDTHH:MM:SSZ","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Deployment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"device_type","in":"query","description":"Device type filter: desktop or mobile (optional)","required":false,"schema":{"type":"string"}},{"name":"include_bots","in":"query","description":"Include crawler/datacenter bot samples (default false)","required":false,"schema":{"type":"boolean"}},{"name":"filter_path","in":"query","description":"Filter to one page pathname (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_country","in":"query","description":"Filter to one country (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_region","in":"query","description":"Filter to one region (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_city","in":"query","description":"Filter to one city (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_browser","in":"query","description":"Filter to one browser (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_operating_system","in":"query","description":"Filter to one operating system (optional)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved metrics over time","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MetricsOverTimeResponse"}}}},"400":{"description":"Invalid date format or missing parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/performance/page-metrics":{"get":{"tags":["Performance"],"summary":"Get grouped page metrics","operationId":"get_grouped_page_metrics","parameters":[{"name":"start_date","in":"query","description":"Start date in format YYYY-MM-DDTHH:MM:SSZ","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in format YYYY-MM-DDTHH:MM:SSZ","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Deployment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"group_by","in":"query","description":"Group by: path, country, region, city, device_type, browser, operating_system","required":true,"schema":{"type":"string"}},{"name":"device_type","in":"query","description":"Device type filter: desktop or mobile (optional)","required":false,"schema":{"type":"string"}},{"name":"include_bots","in":"query","description":"Include crawler/datacenter bot samples (default false)","required":false,"schema":{"type":"boolean"}},{"name":"filter_path","in":"query","description":"Filter to one page pathname (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_country","in":"query","description":"Filter to one country (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_region","in":"query","description":"Filter to one region (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_city","in":"query","description":"Filter to one city (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_browser","in":"query","description":"Filter to one browser (optional)","required":false,"schema":{"type":"string"}},{"name":"filter_operating_system","in":"query","description":"Filter to one operating system (optional)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved grouped page metrics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GroupedPageMetricsResponse"}}}},"400":{"description":"Invalid date format, missing parameters, or invalid group_by value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/platform/access-info":{"get":{"tags":["Platform"],"summary":"Get information about how the service is being accessed","description":"Returns details about the server's access mode, public IP address, private IP address,\nand domain creation capabilities. Both IP addresses are always included when available.","operationId":"get_access_info","responses":{"200":{"description":"Service access information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceAccessInfo"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/platform/private-ip":{"get":{"tags":["Platform"],"summary":"Get private/local IP address of the server","operationId":"get_private_ip","responses":{"200":{"description":"Successfully retrieved private IP address"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/platform/public-ip":{"get":{"tags":["Platform"],"summary":"Get public IP address of the server","operationId":"get_public_ip","responses":{"200":{"description":"Successfully retrieved public IP address"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/presets":{"get":{"tags":["Presets"],"summary":"List all available presets","operationId":"list_presets","responses":{"200":{"description":"List of available presets","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListPresetsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/presets/{slug}/dockerfile":{"post":{"tags":["Presets"],"summary":"Generate a Dockerfile from a preset","description":"Returns the Dockerfile content and build arguments for a given preset slug.\nThe CLI can use this to build Docker images locally without needing a Dockerfile\nin the project directory, enabling zero-config deployments.","operationId":"generate_preset_dockerfile","parameters":[{"name":"slug","in":"path","description":"Preset slug (e.g., nextjs, vite, python)","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateDockerfileRequest"}}},"required":true},"responses":{"200":{"description":"Generated Dockerfile","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateDockerfileResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Preset not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/preview-gateway/logs":{"get":{"tags":["Preview Gateway"],"operationId":"get_preview_gateway_logs","parameters":[{"name":"tail","in":"query","description":"Lines to tail (default 200, max 2000)","required":false,"schema":{"type":"integer","minimum":0}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LogsResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/preview-gateway/restart":{"post":{"tags":["Preview Gateway"],"operationId":"restart_preview_gateway","responses":{"204":{"description":"Gateway restarted"}},"security":[{"bearer_auth":[]}]}},"/preview-gateway/settings":{"get":{"tags":["Preview Gateway"],"operationId":"get_preview_gateway_settings","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreviewGatewaySettingsResponse"}}}}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Preview Gateway"],"operationId":"patch_preview_gateway_settings","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PatchSettingsRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreviewGatewaySettingsResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/preview-gateway/status":{"get":{"tags":["Preview Gateway"],"operationId":"get_preview_gateway_status","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GatewayStatus"}}}}},"security":[{"bearer_auth":[]}]}},"/preview-gateway/upgrade":{"post":{"tags":["Preview Gateway"],"operationId":"upgrade_preview_gateway","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpgradeRequest"}}},"required":true},"responses":{"204":{"description":"Gateway upgraded"}},"security":[{"bearer_auth":[]}]}},"/projects":{"get":{"tags":["Projects"],"summary":"Get a list of all projects","operationId":"get_projects","parameters":[{"name":"page","in":"query","description":"Page number (1-based)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"per_page","in":"query","description":"Number of items per page","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"List of projects","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedProjectList"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Projects"],"summary":"Create a new project","operationId":"create_project","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectRequest"}}},"required":true},"responses":{"200":{"description":"Project created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"400":{"description":"Invalid input"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/by-slug/{slug}":{"get":{"tags":["Projects"],"summary":"Get details of a specific project by slug","operationId":"get_project_by_slug","parameters":[{"name":"slug","in":"path","description":"Project slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Project details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"404":{"description":"Project not found"}},"security":[{"bearer_auth":[]}]}},"/projects/from-template":{"post":{"tags":["Projects"],"summary":"Create a new project from a template","description":"Creates a new repository from a template and sets up the project with the\nspecified configuration. The template is cloned to a new repository under\nthe authenticated user's account or specified organization.","operationId":"create_project_from_template","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectFromTemplateRequest"}}},"required":true},"responses":{"201":{"description":"Project created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectFromTemplateResponse"}}}},"400":{"description":"Invalid input"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Template not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/statistics":{"get":{"tags":["Projects"],"summary":"Get project statistics","operationId":"get_project_statistics","responses":{"200":{"description":"Project statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectStatisticsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{id}":{"get":{"tags":["Projects"],"summary":"Get details of a specific project","operationId":"get_project","parameters":[{"name":"id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Project details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"404":{"description":"Project not found"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Projects"],"operationId":"update_project","parameters":[{"name":"id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectRequest"}}},"required":true},"responses":{"200":{"description":"Project updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Projects"],"operationId":"delete_project","parameters":[{"name":"id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Project deleted successfully"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{id}/deployments":{"get":{"tags":["Projects"],"operationId":"get_project_deployments","parameters":[{"name":"id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"per_page","in":"query","description":"Items per page","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"environment_id","in":"query","description":"Environment ID filter","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of deployments","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentListResponse"}}}},"404":{"description":"Project not found"}}}},"/projects/{id}/last-deployment":{"get":{"tags":["Deployments"],"summary":"Get the last deployment for a specific project","operationId":"get_last_deployment","parameters":[{"name":"id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Last deployment details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentResponse"}}}},"404":{"description":"Project not found or no deployments"},"500":{"description":"Internal server error"}}}},"/projects/{id}/source":{"patch":{"tags":["Projects"],"summary":"Change a project's source type to a Git-less type (docker_image /\nstatic_files / manual). Switching TO Git is done via the Git settings\nendpoint (`POST /projects/{id}/git`), which also supplies the repository and\nprovider connection.","operationId":"change_project_source","parameters":[{"name":"id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeProjectSourceRequest"}}},"required":true},"responses":{"200":{"description":"Source type changed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"400":{"description":"Invalid source type change (e.g. switching to Git here)"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{id}/trigger-pipeline":{"post":{"tags":["Projects"],"summary":"Trigger pipeline for a specific project","operationId":"trigger_project_pipeline","parameters":[{"name":"id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerPipelinePayload"}}},"required":true},"responses":{"200":{"description":"Pipeline triggered successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerPipelineResponse"}}}},"400":{"description":"Invalid request"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/access":{"get":{"tags":["Teams"],"operationId":"list_project_access","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Access grants","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProjectAccessResponse"}}}}},"403":{"description":"Insufficient permissions or no access to this project"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Teams"],"operationId":"grant_project_access","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectAccessRequest"}}},"required":true},"responses":{"201":{"description":"Access granted (idempotent upsert)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectAccessResponse"}}}},"403":{"description":"Insufficient permissions or no access to this project"},"404":{"description":"Team not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/access/{team_id}":{"delete":{"tags":["Teams"],"operationId":"revoke_project_access","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"team_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Access revoked"},"403":{"description":"Insufficient permissions or no access to this project"},"404":{"description":"Grant not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/active-visitors":{"get":{"tags":["Events"],"summary":"Get active visitors count","operationId":"get_active_visitors","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved active visitors count","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActiveVisitorsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents":{"get":{"tags":["Agents"],"operationId":"list_agents","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of agents for project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListAgentsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Agents"],"operationId":"create_agent","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertAgentRequest"}}},"required":true},"responses":{"201":{"description":"Agent created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentConfigResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/cli-status":{"get":{"tags":["Agents"],"operationId":"get_cli_status","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"provider","in":"query","description":"AI provider: claude_cli or codex_cli","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"CLI status"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/runs":{"get":{"tags":["Agents"],"operationId":"list_all_runs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-based)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (max 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List of all agent runs for a project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListRunsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/runs/latest-for-source":{"get":{"tags":["Agents"],"operationId":"latest_run_for_source","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"trigger_source_type","in":"query","description":"Trigger source type, e.g. 'error_group'","required":true,"schema":{"type":"string"}},{"name":"trigger_source_id","in":"query","description":"Trigger source ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Latest matching run, or null if none","content":{"application/json":{"schema":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AgentRunResponse"}]}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/runs/{run_id}":{"get":{"tags":["Agents"],"operationId":"get_run_with_logs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Run with logs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRunWithLogsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/runs/{run_id}/cancel":{"post":{"tags":["Agents"],"operationId":"cancel_run","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Agent run ID to cancel","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Run cancelled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRunResponse"}}}},"400":{"description":"Run is already in a terminal state"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/runs/{run_id}/retry":{"post":{"tags":["Agents"],"summary":"Retry a completed, failed, cancelled, or no_fix run with the same trigger context.\nCreates a new run record and spawns the executor.","operationId":"retry_run","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID to retry","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"202":{"description":"New run created from retry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRunResponse"}}}},"400":{"description":"Run is still active"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/runs/{run_id}/stream":{"get":{"tags":["Agents"],"summary":"SSE endpoint for real-time streaming of run events.\nPolls the agent_run_logs table every 500ms for new entries and streams them.\nCloses when the run reaches a terminal status.","operationId":"stream_run_events","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Agent run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Server-Sent Events stream of run log events and terminal status","content":{"text/event-stream":{}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/sandbox-status":{"get":{"tags":["Agents"],"operationId":"get_sandbox_status","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Project-scoped sandbox readiness (Docker + agent image)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxStatusResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/smoke-test":{"post":{"tags":["Agents"],"summary":"Run a smoke test to verify the selected AI CLI works in the environment\nwhere agents will actually execute (host or sandbox container). If no\n`provider_id` is supplied the globally active provider is tested.","operationId":"smoke_test_agent","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"provider_id","in":"query","description":"Provider id to test; defaults to the globally active provider","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Smoke test result for the AI CLI in the agent's execution environment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SmokeTestResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/{slug}":{"get":{"tags":["Agents"],"operationId":"get_agent","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Agent slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Agent config","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentConfigResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Agent not found"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Agents"],"operationId":"update_agent","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Agent slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertAgentRequest"}}},"required":true},"responses":{"200":{"description":"Agent updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentConfigResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Agent not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Agents"],"operationId":"delete_agent","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Agent slug","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Agent deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Agent not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/{slug}/runs":{"get":{"tags":["Agents"],"operationId":"list_agent_runs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Agent slug","required":true,"schema":{"type":"string"}},{"name":"page","in":"query","description":"Page number (1-based)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (max 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List of runs for a specific agent","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListRunsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Agent not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/agents/{slug}/trigger":{"post":{"tags":["Agents"],"operationId":"trigger_agent","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Agent slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerAgentRequest"}}},"required":true},"responses":{"202":{"description":"Agent run created and queued","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRunResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"402":{"description":"Daily budget exceeded"},"403":{"description":"Insufficient permissions"},"404":{"description":"Agent not found"},"422":{"description":"AI CLI not installed"},"429":{"description":"Cooldown active"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/aggregated-buckets":{"get":{"tags":["Events"],"summary":"Get aggregated metrics by time bucket","operationId":"get_aggregated_buckets","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date for the query range","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date for the query range","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Optional environment filter","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Optional deployment filter","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"aggregation_level","in":"query","description":"Aggregation level: events, sessions, or visitors (default: events)","required":false,"schema":{"type":"string"}},{"name":"bucket_size","in":"query","description":"Time bucket size: '1 hour', '1 day', '1 week', etc. (default: '1 hour')","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved aggregated buckets","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AggregatedBucketsResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/conversations":{"get":{"tags":["AI Chat"],"summary":"Find the existing chat for a context (returns `null` if none yet). Requires\nthe per-project `ai_debug_chat_enabled` toggle to be on; returns 403 when the\nfeature is disabled so revoking it consistently hides existing chat content.","operationId":"find_conversation","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"context_type","in":"query","required":true,"schema":{"type":"string"}},{"name":"context_id","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ConversationResponse"}]}}}},"401":{"description":""},"403":{"description":""}},"security":[{"bearer_auth":[]}]},"post":{"tags":["AI Chat"],"summary":"Get-or-create the chat for a context (seeds it on first open).","operationId":"create_conversation","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateConversationRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversationResponse"}}}},"401":{"description":""},"403":{"description":""},"404":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/conversations/list":{"get":{"tags":["AI Chat"],"summary":"List all active conversations for a project, most-recently-active first.\nPowers the conversation switcher in the AI assistant sidebar.","operationId":"list_conversations","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ConversationResponse"}}}}},"401":{"description":""},"403":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/conversations/{public_id}":{"get":{"tags":["AI Chat"],"summary":"Full conversation history (excluding the internal system seed).","operationId":"get_conversation","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"public_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversationDetailResponse"}}}},"401":{"description":""},"403":{"description":""},"404":{"description":""}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["AI Chat"],"summary":"Rename a conversation (set its human-facing title).","operationId":"rename_conversation","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"public_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RenameConversationRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversationResponse"}}}},"400":{"description":""},"401":{"description":""},"403":{"description":""},"404":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/conversations/{public_id}/archive":{"post":{"tags":["AI Chat"],"summary":"Archive (soft-delete) a conversation.","operationId":"archive_conversation","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"public_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":""},"401":{"description":""},"403":{"description":""},"404":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/conversations/{public_id}/messages":{"post":{"tags":["AI Chat"],"summary":"Send a user message; stream the assistant reply as Server-Sent Events.","operationId":"send_message","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"public_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendMessageRequest"}}},"required":true},"responses":{"200":{"description":"SSE stream of assistant text deltas","content":{"text/event-stream":{}}},"401":{"description":""},"403":{"description":""},"404":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/conversations/{public_id}/pending-actions":{"get":{"tags":["AI Chat"],"summary":"List all pending actions for a conversation (most-recently-proposed first).","operationId":"list_pending_actions","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"public_id","in":"path","description":"Conversation public id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PendingActionResponse"}}}}},"401":{"description":""},"403":{"description":""},"404":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/pending-actions/{action_public_id}":{"get":{"tags":["AI Chat"],"summary":"Get a single pending action by its public id (scoped to the project).","operationId":"get_pending_action","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"action_public_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PendingActionResponse"}}}},"401":{"description":""},"403":{"description":""},"404":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/pending-actions/{action_public_id}/confirm":{"post":{"tags":["AI Chat"],"summary":"Confirm a proposed AI action: validate permission, atomically claim, execute,\npersist outcome. The execution uses the CONFIRMING user's auth — never the model's.","operationId":"confirm_pending_action","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"action_public_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PendingActionResponse"}}}},"401":{"description":""},"403":{"description":""},"404":{"description":""},"409":{"description":""},"503":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/pending-actions/{action_public_id}/reject":{"post":{"tags":["AI Chat"],"summary":"Reject a proposed AI action (no execution). Status transitions to \"rejected\".","operationId":"reject_pending_action","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"action_public_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PendingActionResponse"}}}},"401":{"description":""},"403":{"description":""},"404":{"description":""},"409":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/ai/readiness":{"get":{"tags":["AI Chat"],"summary":"Report which AI prerequisites this project satisfies.","description":"Read-only and cheap, so the UI can decide up front whether to show a working\nentry point, an onboarding path, or nothing — instead of letting the user\nclick something that fails with a 409 they can't act on.","operationId":"get_chat_readiness","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Which AI prerequisites are met","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatReadinessResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/alarms":{"get":{"tags":["Alarms"],"summary":"List alarms for a project with optional filters.","operationId":"listProjectAlarms","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"alarm_type","in":"query","description":"Filter by alarm type (e.g. `container_restart`, `outage`).","required":false,"schema":{"type":["string","null"]}},{"name":"status","in":"query","description":"Filter by status: `firing`, `acknowledged`, or `resolved`.","required":false,"schema":{"type":["string","null"]}},{"name":"severity","in":"query","description":"Filter by severity: `info`, `warning`, or `critical`.","required":false,"schema":{"type":["string","null"]}},{"name":"environment_id","in":"query","description":"Filter by environment ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"service_id","in":"query","description":"Filter by external service ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"page","in":"query","description":"Page number (1-based, default 1).","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page (default 20, max 100).","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}}],"responses":{"200":{"description":"Paginated list of alarms","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlarmListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/alarms/summary":{"get":{"tags":["Alarms"],"summary":"Get alarm counts by status/severity/type for a project (dashboard summary widget).","operationId":"getProjectAlarmsSummary","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Alarm summary counts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlarmSummaryResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/alarms/{alarm_id}/acknowledge":{"post":{"tags":["Alarms"],"summary":"Acknowledge a firing alarm (marks it as seen but not resolved).","operationId":"acknowledgeAlarm","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"alarm_id","in":"path","description":"Alarm ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Alarm acknowledged"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Alarm not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/alarms/{alarm_id}/resolve":{"post":{"tags":["Alarms"],"summary":"Resolve an alarm.","operationId":"resolveAlarm","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"alarm_id","in":"path","description":"Alarm ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Alarm resolved"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Alarm not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/analyze":{"post":{"tags":["Autofixer"],"summary":"Start an autofixer analysis run for the given error group.\nCreates the run record immediately and spawns analysis in the background.","operationId":"start_analysis","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartAnalysisRequest"}}},"required":true},"responses":{"202":{"description":"Analysis started; returns run_id for streaming","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutofixerRunResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/runs/{run_id}":{"get":{"tags":["Autofixer"],"summary":"Get a single autofixer run with its logs.","operationId":"get_run","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Run with logs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutofixerRunWithLogsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/runs/{run_id}/add-context":{"post":{"tags":["Autofixer"],"summary":"Append a user message to the run's context field.","operationId":"add_context","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddContextRequest"}}},"required":true},"responses":{"200":{"description":"Context appended"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/runs/{run_id}/cancel":{"post":{"tags":["Autofixer"],"summary":"Cancel an autofixer run and clean up the work directory.","operationId":"cancel","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Run cancelled"},"400":{"description":"Run is already in a terminal state"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/runs/{run_id}/create-pr":{"post":{"tags":["Autofixer"],"summary":"Push the fix branch and create a pull request.\nRequires phase == \"fix_ready\".","operationId":"create_pr","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"201":{"description":"PR created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePrResponse"}}}},"400":{"description":"Run not in fix_ready phase"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/runs/{run_id}/fix":{"post":{"tags":["Autofixer"],"summary":"Transition from analysis to fix phase.\nRequires phase == \"analyzed\".","operationId":"start_fix","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"202":{"description":"Fix generation started"},"400":{"description":"Run not in analyzed phase"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/runs/{run_id}/re-analyze":{"post":{"tags":["Autofixer"],"summary":"Continue the conversation with user feedback.\nUses the same Claude session (--continue) in the existing work directory.\nRequires phase == \"analyzed\".","operationId":"re_analyze","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"202":{"description":"Conversation continued with feedback"},"400":{"description":"Run not in analyzed phase"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/autofixer/runs/{run_id}/stream":{"get":{"tags":["Agents"],"summary":"SSE endpoint: streams run log events in real-time.\nPolls every 500 ms. Keeps the connection open through \"analyzed\" and \"fix_ready\"\nwaiting states; closes only on terminal statuses.","operationId":"stream_events","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"run_id","in":"path","description":"Autofixer run ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Server-Sent Events stream of autofixer run logs and status updates","content":{"text/event-stream":{}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Run not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/automatic-deploy":{"post":{"tags":["Projects"],"summary":"Update automatic deployment setting for a project","operationId":"update_automatic_deploy","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAutomaticDeployRequest"}}},"required":true},"responses":{"200":{"description":"Automatic deployment setting updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/custom-domains":{"get":{"tags":["Custom Domains"],"summary":"List all custom domains for a project","operationId":"list_custom_domains_for_project","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Custom domains retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListCustomDomainsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Custom Domains"],"summary":"Create a custom domain for a project","operationId":"create_custom_domain","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomDomainRequest"}}},"required":true},"responses":{"201":{"description":"Custom domain created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomDomainResponse"}}}},"400":{"description":"Invalid input"},"401":{"description":"Unauthorized"},"409":{"description":"Domain already exists"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/custom-domains/{domain_id}":{"get":{"tags":["Custom Domains"],"summary":"Get a custom domain by ID","operationId":"get_custom_domain","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain_id","in":"path","description":"Custom domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Custom domain retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomDomainResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Custom domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Custom Domains"],"summary":"Update a custom domain","operationId":"update_custom_domain","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain_id","in":"path","description":"Custom domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCustomDomainRequest"}}},"required":true},"responses":{"200":{"description":"Custom domain updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomDomainResponse"}}}},"400":{"description":"Invalid input"},"401":{"description":"Unauthorized"},"404":{"description":"Custom domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Custom Domains"],"summary":"Delete a custom domain","operationId":"delete_custom_domain","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain_id","in":"path","description":"Custom domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Custom domain deleted successfully"},"401":{"description":"Unauthorized"},"404":{"description":"Custom domain not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/custom-domains/{domain_id}/link-certificate/{certificate_id}":{"post":{"tags":["Custom Domains"],"summary":"Link a custom domain to a certificate","operationId":"link_custom_domain_to_certificate","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain_id","in":"path","description":"Custom domain ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"certificate_id","in":"path","description":"Certificate ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Custom domain linked to certificate successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomDomainResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Custom domain or certificate not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/deployment-config":{"patch":{"tags":["Projects"],"summary":"Update deployment configuration for a project","operationId":"update_project_deployment_config","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDeploymentConfigRequest"}}},"required":true},"responses":{"200":{"description":"Deployment configuration updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"400":{"description":"Invalid deployment configuration"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/deployment-tokens":{"get":{"tags":["Deployment Tokens"],"summary":"List all deployment tokens for a project","operationId":"list_deployment_tokens","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List of deployment tokens","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentTokenListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Deployment Tokens"],"summary":"Create a new deployment token for a project","operationId":"create_deployment_token","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDeploymentTokenRequest"}}},"required":true},"responses":{"201":{"description":"Deployment token created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDeploymentTokenResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"409":{"description":"Token with this name already exists"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/deployment-tokens/{token_id}":{"get":{"tags":["Deployment Tokens"],"summary":"Get a specific deployment token","operationId":"get_deployment_token","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"token_id","in":"path","description":"Deployment token ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deployment token details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentTokenResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Deployment token not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Deployment Tokens"],"summary":"Delete a deployment token","operationId":"delete_deployment_token","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"token_id","in":"path","description":"Deployment token ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Deployment token deleted successfully"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Deployment token not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Deployment Tokens"],"summary":"Update a deployment token","operationId":"update_deployment_token","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"token_id","in":"path","description":"Deployment token ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDeploymentTokenRequest"}}},"required":true},"responses":{"200":{"description":"Deployment token updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentTokenResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Deployment token not found"},"409":{"description":"Token with this name already exists"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/deployment-tokens/{token_id}/rotate":{"post":{"tags":["Deployment Tokens"],"summary":"Rotate a deployment token, invalidating its old secret and issuing a new one","operationId":"rotate_deployment_token","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"token_id","in":"path","description":"Deployment token ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deployment token rotated successfully; the response contains the new plaintext token, shown only once","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDeploymentTokenResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Deployment token not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/deployments/{deployment_id}":{"get":{"tags":["Deployments"],"summary":"Get a specific deployment by ID for a project (identified by ID or slug)","operationId":"get_deployment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deployment details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentResponse"}}}},"404":{"description":"Project or deployment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/deployments/{deployment_id}/cancel":{"post":{"tags":["Projects"],"summary":"Cancel a deployment","operationId":"cancel_deployment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deployment cancelled successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentStateResponse"}}}},"400":{"description":"Deployment cannot be cancelled (already completed, failed, or cancelled)"},"404":{"description":"Project or deployment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/deployments/{deployment_id}/container-logs":{"get":{"tags":["Deployments"],"summary":"List the captured (historical) container-log dumps for a deployment.","description":"Container runtime logs are normally only available live from the running\ncontainer. When a deployment is superseded its containers are torn down and\nthose logs would be lost — so just before teardown we capture each\ncontainer's logs to durable storage. This endpoint lists what was captured\nfor a given (often older) deployment, so a user can read the logs of a\ncontainer that no longer exists.","operationId":"list_deployment_container_logs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Captured container logs for the deployment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentContainerLogsListResponse"}}}},"404":{"description":"Deployment not found in this project"},"500":{"description":"Internal server error"}},"security":[{"bearer_token":[]}]}},"/projects/{project_id}/deployments/{deployment_id}/container-logs/{log_id}":{"get":{"tags":["Deployments"],"summary":"Get the captured text content of a single historical container-log dump.","operationId":"get_deployment_container_log_content","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"log_id","in":"path","description":"Captured log ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Captured container log content","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentContainerLogContentResponse"}}}},"404":{"description":"Captured log not found in this project"},"500":{"description":"Internal server error"}},"security":[{"bearer_token":[]}]}},"/projects/{project_id}/deployments/{deployment_id}/jobs":{"get":{"tags":["Deployments"],"summary":"Get jobs for a specific deployment","description":"Returns all jobs (workflow tasks) for a deployment, ordered by execution order.\nThis replaces the old deployment stages endpoint.","operationId":"get_deployment_jobs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Jobs retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentJobsResponse"}}}},"404":{"description":"Deployment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/deployments/{deployment_id}/jobs/{job_id}/logs":{"get":{"tags":["Deployments"],"summary":"Get logs for a specific deployment job","operationId":"get_deployment_job_logs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"job_id","in":"path","description":"Job ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Job logs retrieved successfully","content":{"text/plain":{"schema":{"type":"string"}}}},"404":{"description":"Job or logs not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_token":[]}]}},"/projects/{project_id}/deployments/{deployment_id}/jobs/{job_id}/logs/tail":{"get":{"tags":["Deployments"],"summary":"Tail logs for a specific deployment job in real-time via WebSocket","description":"**WebSocket Streaming**: Logs are sent as raw text, one line per WebSocket message.\n\n**Authentication**: Requires authentication via session cookie (browser clients)\nor API key (API clients). For browser-based WebSocket connections, ensure the user\nis logged in - the browser automatically includes session cookies in the WebSocket\nupgrade request.\n\n**API Client Authentication**: Include API key in Authorization header:\n```text\nAuthorization: Bearer tk_your_api_key_here\n```","operationId":"tail_deployment_job_logs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"job_id","in":"path","description":"Job ID","required":true,"schema":{"type":"string"}}],"responses":{"101":{"description":"WebSocket connection established for streaming deployment job logs"},"404":{"description":"Job or logs not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_token":[]}]}},"/projects/{project_id}/deployments/{deployment_id}/operations":{"get":{"tags":["Deployments"],"summary":"Get all operations for a deployment","operationId":"get_deployment_operations","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of operations","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperationResultsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Deployment not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Deployments"],"summary":"Execute a deployment operation (deploy, mark_complete, take_screenshot)","operationId":"execute_deployment_operation","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecuteOperationRequest"}}},"required":true},"responses":{"202":{"description":"Operation executed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperationResultResponse"}}}},"400":{"description":"Invalid operation"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Deployment not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/deployments/{deployment_id}/operations/{operation_type}":{"get":{"tags":["Deployments"],"summary":"Get the status of a specific operation type","operationId":"get_deployment_operation_status","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","required":true,"schema":{"type":"string"}},{"name":"operation_type","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Operation status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperationResultResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Operation not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/deployments/{deployment_id}/pause":{"post":{"tags":["Projects"],"summary":"Pause a deployment","operationId":"pause_deployment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deployment paused successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentStateResponse"}}}},"404":{"description":"Project or deployment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/deployments/{deployment_id}/promote":{"post":{"tags":["Deployments"],"summary":"Promote a deployment to another environment","description":"Creates a new deployment in the target environment using the source deployment's\nDocker image. Useful for promoting a validated preview/staging deployment to production.","operationId":"promote_deployment","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Source deployment ID to promote","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PromoteDeploymentRequest"}}},"required":true},"responses":{"200":{"description":"Promotion initiated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentResponse"}}}},"400":{"description":"Invalid deployment state for promotion"},"404":{"description":"Project, deployment, or target environment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/deployments/{deployment_id}/resume":{"post":{"tags":["Projects"],"summary":"Resume a deployment","operationId":"resume_deployment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deployment resumed successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentStateResponse"}}}},"404":{"description":"Project or deployment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/deployments/{deployment_id}/rollback":{"post":{"tags":["Projects"],"operationId":"rollback_to_deployment","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID to rollback to","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Rollback initiated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentResponse"}}}},"404":{"description":"Project or deployment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/deployments/{deployment_id}/teardown":{"delete":{"tags":["Projects"],"summary":"Teardown a specific deployment","operationId":"teardown_deployment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"path","description":"Deployment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Deployment torn down successfully"},"404":{"description":"Project or deployment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/dsns":{"get":{"tags":[],"summary":"List all DSNs for a project","operationId":"list_dsns","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of DSNs","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProjectDSNResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"post":{"tags":[],"summary":"Create a new DSN for a project","operationId":"create_dsn","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDSNRequest"}}},"required":true},"responses":{"201":{"description":"DSN created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectDSNResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/dsns/get-or-create":{"post":{"tags":[],"summary":"Get or create DSN for a project/environment/deployment combination","operationId":"get_or_create_dsn","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetOrCreateDSNRequest"}}},"required":true},"responses":{"200":{"description":"DSN retrieved or created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectDSNResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/dsns/{dsn_id}/regenerate":{"post":{"tags":[],"summary":"Regenerate DSN keys (rotate keys)","operationId":"regenerate_dsn","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"dsn_id","in":"path","description":"DSN ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegenerateDSNRequest"}}},"required":true},"responses":{"200":{"description":"DSN keys regenerated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectDSNResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"DSN not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/dsns/{dsn_id}/revoke":{"post":{"tags":[],"summary":"Revoke (deactivate) a DSN","operationId":"revoke_dsn","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"dsn_id","in":"path","description":"DSN ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"DSN revoked"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"DSN not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/env-vars":{"get":{"tags":["Projects"],"summary":"Get environment variables for a project, optionally filtered by environment","operationId":"get_environment_variables","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Optional environment ID to filter by","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of environment variables","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EnvironmentVariableResponse"}}}}},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}},"post":{"tags":["Projects"],"summary":"Create a new environment variable","operationId":"create_environment_variable","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEnvironmentVariableRequest"}}},"required":true},"responses":{"201":{"description":"Environment variables created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentVariableResponse"}}}},"400":{"description":"Invalid input"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/env-vars/resolved":{"get":{"tags":["Projects"],"summary":"Resolved env vars for a project (manual + integration-sourced, merged).","description":"Returns the effective set of environment variables a deployment would see,\ncombining manually-defined vars with those contributed by linked external\nservices (Postgres, Redis, S3, etc.). Each entry is tagged with its source\nso the UI can render an integration icon, and manual entries that shadow an\nintegration key carry a reference to the integration they override.\n\nValues are always returned as a masked preview. Use the per-key reveal\nendpoint for plaintext (audit-logged).","operationId":"get_resolved_environment_variables","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Optional environment ID to filter manual vars by","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Resolved environment variables","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ResolvedEnvVarResponse"}}}}},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/env-vars/resolved/{key}/value":{"get":{"tags":["Projects"],"summary":"Reveal the plaintext value of a resolved environment variable.","description":"Mirrors `GET /projects/{id}/env-vars/{key}/value` but handles keys sourced\nfrom linked integrations (which are not stored in the `env_vars` table).\nResolution order mirrors the merged view:\n\n1. Manual env var with this key — this endpoint reads the manual store when\n the key exists there, then writes its own reveal audit event so callers\n can safely use one endpoint regardless of source.\n2. Integration env var supplied by a linked external service.\n\nReturns 404 when neither a manual var nor an integration produces the key.","operationId":"get_resolved_environment_variable_value","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"key","in":"path","description":"Environment variable key","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Optional environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"var_id","in":"query","description":"Exact manual environment-variable row ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"service_id","in":"query","description":"Integration service ID shown by the resolved list","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Resolved environment variable value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentVariableValueResponse"}}}},"403":{"description":"Plaintext secret access is not permitted"},"404":{"description":"Project, key, or integration not found"},"409":{"description":"Environment variable key is ambiguous"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/env-vars/{key}/value":{"get":{"tags":["Projects"],"summary":"Get environment variable value by key","operationId":"get_environment_variable_value","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"key","in":"path","description":"Environment variable key","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Optional environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"var_id","in":"query","description":"Exact environment-variable row ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Environment variable value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentVariableValueResponse"}}}},"403":{"description":"Plaintext secret access is not permitted"},"404":{"description":"Project or variable not found"},"409":{"description":"Environment variable key is ambiguous"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/env-vars/{var_id}":{"put":{"tags":["Projects"],"summary":"Update an environment variable","operationId":"update_environment_variable","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"var_id","in":"path","description":"Environment variable ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEnvironmentVariableRequest"}}},"required":true},"responses":{"200":{"description":"Environment variables updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentVariableResponse"}}}},"400":{"description":"Invalid input"},"404":{"description":"Project or variable not found"},"500":{"description":"Internal server error"}}},"delete":{"tags":["Projects"],"summary":"Delete an environment variable","operationId":"delete_environment_variable","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"var_id","in":"path","description":"Environment variable ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Environment variable deleted successfully"},"404":{"description":"Project or variable not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments":{"get":{"tags":["Projects"],"summary":"Get all environments for a project","operationId":"get_environments","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of environments","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EnvironmentResponse"}}}}},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}},"post":{"tags":["Projects"],"summary":"Create a new environment for a project","operationId":"create_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEnvironmentRequest"}}},"required":true},"responses":{"201":{"description":"Environment created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentResponse"}}}},"400":{"description":"Invalid input"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}":{"get":{"tags":["Projects"],"summary":"Get a specific environment by ID or slug","operationId":"get_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Environment details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentResponse"}}}},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}}},"delete":{"tags":["Projects"],"summary":"Delete an environment permanently","description":"Permanently deletes an environment and all related data. Cannot delete:\n- Production environments (name = \"Production\")\n\nWarning: This action is permanent and cannot be undone.\nActive deployments are automatically cancelled before deletion.","operationId":"delete_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Environment permanently deleted"},"400":{"description":"Cannot delete production environment"},"404":{"description":"Project or environment not found"},"428":{"description":"Recent MFA verification required"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/crons":{"get":{"tags":["Crons"],"operationId":"get_environment_crons","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of cron jobs","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CronInfo"}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/crons/{cron_id}":{"get":{"tags":["Crons"],"operationId":"get_cron_by_id","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"cron_id","in":"path","description":"Cron Job ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Cron job details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CronInfo"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Cron job not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/crons/{cron_id}/executions":{"get":{"tags":["Crons"],"operationId":"get_cron_executions","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"cron_id","in":"path","description":"Cron Job ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"per_page","in":"query","description":"Items per page (default: 20)","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"List of cron job executions","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CronExecutionInfo"}}}}},"401":{"description":"Unauthorized"},"404":{"description":"Cron job not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/domains":{"get":{"tags":["Projects"],"summary":"Get all environment domains for a specific environment","operationId":"get_environment_domains","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of environment domains","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EnvironmentDomainResponse"}}}}},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}}},"post":{"tags":["Projects"],"summary":"Add a new environment domain","operationId":"add_environment_domain","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddEnvironmentDomainRequest"}}},"required":true},"responses":{"201":{"description":"Domain added successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentDomainResponse"}}}},"400":{"description":"Invalid input"},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/domains/{domain_id}":{"delete":{"tags":["Projects"],"summary":"Delete an environment domain","operationId":"delete_environment_domain","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"domain_id","in":"path","description":"Domain ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Domain deleted successfully"},"404":{"description":"Project, environment, or domain not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/settings":{"put":{"tags":["Projects"],"summary":"Update environment settings","operationId":"update_environment_settings","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEnvironmentSettingsRequest"}}},"required":true},"responses":{"200":{"description":"Environment settings updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentResponse"}}}},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/sleep":{"post":{"tags":["Environments"],"summary":"Sleep an on-demand environment","description":"Manually put an on-demand environment to sleep. Stops containers and sets\n`sleeping = true`. If no OnDemandWaker is available, falls back to DB flag only.","operationId":"sleep_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Environment put to sleep","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentResponse"}}}},"400":{"description":"On-demand not enabled for this environment"},"404":{"description":"Environment not found"},"429":{"description":"Too many state transitions, retry after cooldown"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/subdomain":{"patch":{"tags":["Projects"],"summary":"Rename the auto-managed subdomain for an environment.","description":"Replaces the environment's previous subdomain entirely — the old\nhostname stops resolving once the proxy reloads its route table.\nCustom domains attached to the environment are unaffected.","operationId":"update_environment_subdomain","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEnvironmentSubdomainRequest"}}},"required":true},"responses":{"200":{"description":"Subdomain updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentResponse"}}}},"400":{"description":"Invalid subdomain or conflict with another environment"},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/teardown":{"delete":{"tags":["Projects"],"summary":"Teardown an environment and all its active deployments","operationId":"teardown_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID or slug","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID or slug","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Environment torn down successfully"},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{env_id}/wake":{"post":{"tags":["Environments"],"summary":"Wake a sleeping on-demand environment","description":"Manually wake an environment that has been put to sleep by the on-demand\nidle timeout. Starts containers, waits for health checks, then sets\n`sleeping = false`. If no OnDemandWaker is available (proxy not running\nin same process), falls back to setting the DB flag only.","operationId":"wake_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"env_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Environment woken up","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnvironmentResponse"}}}},"400":{"description":"On-demand not enabled for this environment"},"404":{"description":"Environment not found"},"429":{"description":"Too many state transitions, retry after cooldown"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{environment_id}/container-logs":{"get":{"tags":["Deployments"],"summary":"Get logs for a container in an environment via WebSocket","operationId":"get_container_logs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date for logs","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"end_date","in":"query","description":"End date for logs","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"tail","in":"query","description":"Number of lines to tail (or 'all')","required":false,"schema":{"type":"string"}},{"name":"container_name","in":"query","description":"Optional container name (defaults to first/primary container)","required":false,"schema":{"type":"string"}},{"name":"timestamps","in":"query","description":"Include timestamps in log output (default: false)","required":false,"schema":{"type":"boolean"}},{"name":"follow","in":"query","description":"Follow log output in real-time (default: true)","required":false,"schema":{"type":"boolean"}}],"responses":{"101":{"description":"WebSocket connection established for streaming container logs"},"400":{"description":"Not a server-type project"},"404":{"description":"Project, deployment, or container not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/containers":{"get":{"tags":["Deployments"],"summary":"List all containers for an environment","operationId":"list_containers","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of containers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerListResponse"}}}},"400":{"description":"Not a server-type project"},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}":{"get":{"tags":["Containers"],"summary":"Get detailed information about a specific container","operationId":"get_container_detail","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Container details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerDetailResponse"}}}},"404":{"description":"Container not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/environment/{variable_name}":{"get":{"tags":["Containers"],"operationId":"get_container_environment_variable","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}},{"name":"variable_name","in":"path","description":"Environment variable name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Environment variable value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerEnvironmentVariableValueResponse"}}}},"403":{"description":"Plaintext secret access is not permitted"},"404":{"description":"Container or environment variable not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/logs":{"get":{"tags":["Deployments"],"summary":"Get logs for a specific container by container ID via WebSocket","operationId":"get_container_logs_by_id","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}},{"name":"start_date","in":"query","description":"Start date for logs","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"end_date","in":"query","description":"End date for logs","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"tail","in":"query","description":"Number of lines to tail (or 'all')","required":false,"schema":{"type":"string"}},{"name":"timestamps","in":"query","description":"Include timestamps in log output (default: false)","required":false,"schema":{"type":"boolean"}},{"name":"follow","in":"query","description":"Follow log output in real-time (default: true)","required":false,"schema":{"type":"boolean"}}],"responses":{"101":{"description":"WebSocket connection established for streaming container logs"},"400":{"description":"Not a server-type project"},"404":{"description":"Project, environment, or container not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/metrics":{"get":{"tags":["Containers"],"summary":"Get metrics/stats for a specific container","operationId":"get_container_metrics","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Container metrics retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerMetricsResponse"}}}},"404":{"description":"Container not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/metrics/history":{"get":{"tags":["Containers"],"summary":"Fetch a time-series range for a single container resource metric\n(recorded by the container health monitor every ~30s).","description":"Useful metric names: `container.cpu_percent`,\n`container.cpu_utilization_percent`, `container.memory_used_bytes`,\n`container.memory_percent`, `container.network_rx_bytes_delta`,\n`container.network_tx_bytes_delta`.","operationId":"ContainerMetricsGetHistory","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}},{"name":"metric","in":"query","description":"Dotted metric name, e.g. `container.cpu_percent` or\n`container.memory_used_bytes`.","required":true,"schema":{"type":"string"}},{"name":"range","in":"query","description":"Time window: `1h`, `6h`, `24h`, or `7d` (defaults to `1h`).","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Metric time series data points","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ContainerMetricHistoryPoint"}}}}},"401":{"description":"Unauthorized"},"404":{"description":"Container not found"},"500":{"description":"Internal server error"},"503":{"description":"Metrics store not available"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/metrics/stream":{"get":{"tags":["Containers"],"summary":"Stream container metrics via Server-Sent Events (SSE)","operationId":"stream_container_metrics","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}},{"name":"interval","in":"query","description":"Update interval in milliseconds (default: 1000)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Metrics stream established (Server-Sent Events)"},"404":{"description":"Container not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/restart":{"post":{"tags":["Containers"],"summary":"Restart a container","operationId":"restart_container","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Container restarted successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerActionResponse"}}}},"404":{"description":"Container not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/start":{"post":{"tags":["Containers"],"summary":"Start a container","operationId":"start_container","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Container started successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerActionResponse"}}}},"404":{"description":"Container not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{environment_id}/containers/{container_id}/stop":{"post":{"tags":["Containers"],"summary":"Stop a specific container","operationId":"stop_container","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"container_id","in":"path","description":"Container ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Container stopped successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerActionResponse"}}}},"404":{"description":"Container not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/environments/{environment_id}/deploy/image":{"post":{"tags":["Deployments"],"summary":"Deploy from an external Docker image","description":"Triggers a deployment using a pre-built Docker image from an external registry.\nThe image will be pulled and deployed to the specified environment.","operationId":"deploy_from_image","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeployFromImageRequest"}}},"required":true},"responses":{"202":{"description":"Deployment started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RemoteDeploymentResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project or environment not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/deploy/image-upload":{"post":{"tags":["Deployments"],"summary":"Deploy from an uploaded Docker image tarball","description":"Uploads a Docker image tarball (from `docker save`) and deploys it directly.\nThe image is imported using `docker load` and then deployed to the specified environment.\nThis is useful when you want to deploy an image without pushing to a registry first.\n\nThe uploaded file should be a tarball created by `docker save myimage:tag > image.tar`\nor `docker save myimage:tag | gzip > image.tar.gz` (gzip compressed tarballs are also supported).","operationId":"deploy_from_image_upload","parameters":[{"name":"tag","in":"query","description":"Tag to apply to the imported image (e.g., \"myapp:v1.0\")\nIf not provided, a unique tag will be generated","required":false,"schema":{"type":["string","null"]}},{"name":"health_check_path","in":"query","description":"Optional HTTP health-check path override (e.g. \"/api/healthz\").\nMust start with '/'. When omitted, defaults to \"/\".","required":false,"schema":{"type":["string","null"]}},{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"202":{"description":"Image imported and deployment started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RemoteDeploymentResponse"}}}},"400":{"description":"Invalid request or unsupported format"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project or environment not found"},"413":{"description":"Image tarball too large"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/deploy/source":{"post":{"tags":["Deployments"],"summary":"Upload source code and immediately start a preset-based deployment.","operationId":"deploy_from_uploaded_source","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/SourceArchiveUpload"}}},"required":true},"responses":{"202":{"description":"Source deployment started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RemoteDeploymentResponse"}}}},"400":{"description":"Invalid source archive"},"404":{"description":"Project or environment not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/environments/{environment_id}/deploy/static":{"post":{"tags":["Deployments"],"summary":"Deploy from an uploaded static bundle","description":"Triggers a deployment using a previously uploaded static file bundle.","operationId":"deploy_from_static","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeployFromStaticRequest"}}},"required":true},"responses":{"202":{"description":"Deployment started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RemoteDeploymentResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project, environment, or bundle not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/error-alert-rules":{"get":{"tags":["error-alert-rules"],"summary":"List all alert rules for a project","operationId":"list_alert_rules","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of alert rules","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AlertRuleResponse"}}}}},"500":{"description":"Internal server error"}}},"post":{"tags":["error-alert-rules"],"summary":"Create a new alert rule","operationId":"create_alert_rule","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAlertRuleRequest"}}},"required":true},"responses":{"201":{"description":"Alert rule created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlertRuleResponse"}}}},"400":{"description":"Validation error"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-alert-rules/{rule_id}":{"get":{"tags":["error-alert-rules"],"summary":"Get a specific alert rule","operationId":"get_alert_rule","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"rule_id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Alert rule details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlertRuleResponse"}}}},"404":{"description":"Alert rule not found"},"500":{"description":"Internal server error"}}},"put":{"tags":["error-alert-rules"],"summary":"Update an existing alert rule","operationId":"update_alert_rule","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"rule_id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAlertRuleRequest"}}},"required":true},"responses":{"200":{"description":"Alert rule updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlertRuleResponse"}}}},"400":{"description":"Validation error"},"404":{"description":"Alert rule not found"},"500":{"description":"Internal server error"}}},"delete":{"tags":["error-alert-rules"],"summary":"Delete an alert rule","operationId":"delete_alert_rule","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"rule_id","in":"path","description":"Alert rule ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Alert rule deleted"},"404":{"description":"Alert rule not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-dashboard-stats":{"get":{"tags":["error-tracking"],"summary":"Get error dashboard statistics","operationId":"get_error_dashboard_stats","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_time","in":"query","required":true,"schema":{"type":"string","format":"date-time"}},{"name":"end_time","in":"query","required":true,"schema":{"type":"string","format":"date-time"}},{"name":"environment_id","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"compare_to_previous","in":"query","required":false,"schema":{"type":["boolean","null"]}}],"responses":{"200":{"description":"Error dashboard statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDashboardStatsResponse"}}}},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-groups":{"get":{"tags":["error-tracking"],"summary":"List error groups for a project","operationId":"list_error_groups","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"status","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"environment_id","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"start_date","in":"query","required":false,"schema":{"type":["string","null"],"format":"date-time"}},{"name":"end_date","in":"query","required":false,"schema":{"type":["string","null"],"format":"date-time"}},{"name":"sort_by","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Paginated list of error groups","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedErrorGroupsResponse"}}}},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-groups/{group_id}":{"get":{"tags":["error-tracking"],"summary":"Get a specific error group","operationId":"get_error_group","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"group_id","in":"path","description":"Error group ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Error group details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorGroupResponse"}}}},"404":{"description":"Error group not found"},"500":{"description":"Internal server error"}}},"put":{"tags":["error-tracking"],"summary":"Update error group status","operationId":"update_error_group","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"group_id","in":"path","description":"Error group ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateErrorGroupRequest"}}},"required":true},"responses":{"200":{"description":"Error group updated successfully"},"404":{"description":"Error group not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-groups/{group_id}/events":{"get":{"tags":["error-tracking"],"summary":"List error events for a specific group","operationId":"list_error_events","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"group_id","in":"path","description":"Error group ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Paginated list of error events","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedErrorEventsResponse"}}}},"404":{"description":"Error group not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-groups/{group_id}/events/{event_id}":{"get":{"tags":["error-tracking"],"summary":"Get a specific error event","operationId":"get_error_event","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"group_id","in":"path","description":"Error group ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"event_id","in":"path","description":"Error event ID","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Error event details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEventResponse"}}}},"404":{"description":"Event not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-stats":{"get":{"tags":["error-tracking"],"summary":"Get error statistics for a project","operationId":"get_error_stats","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Error statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorGroupStatsResponse"}}}},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/error-time-series":{"get":{"tags":["error-tracking"],"summary":"Get error time series data for charts","operationId":"get_error_time_series","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_time","in":"query","required":true,"schema":{"type":"string","format":"date-time"}},{"name":"end_time","in":"query","required":true,"schema":{"type":"string","format":"date-time"}},{"name":"bucket","in":"query","description":"Time bucket size (e.g., \"1h\", \"15m\", \"1d\", \"1 hour\", \"30 minutes\")","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Error time series data","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ErrorTimeSeriesDataResponse"}}}}},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/events":{"get":{"tags":["Events"],"summary":"Get event counts with filtering","operationId":"get_events_count","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date for filtering events","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date for filtering events","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"limit","in":"query","description":"Maximum number of events to return (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"custom_events_only","in":"query","description":"Only return custom events, excluding system events like page_view, page_leave, heartbeat (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"aggregation_level","in":"query","description":"Aggregation level: events, sessions, or visitors (default: events)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved event counts","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EventCount"}}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/events/breakdown":{"get":{"tags":["Events"],"summary":"Get event type breakdown","operationId":"get_event_type_breakdown","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date for filtering events","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date for filtering events","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"aggregation_level","in":"query","description":"Aggregation level: events, sessions, or visitors (default: events)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved event type breakdown","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EventTypeBreakdown"}}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/events/ingest":{"post":{"tags":["Events"],"summary":"Record an analytics event via the console API with explicit project ID.","description":"The app backend forwards the user's encrypted Temps cookies, so visitor/session\nidentity is resolved automatically by middleware. No geolocation or user-agent\nenrichment is performed — this is a lightweight server-side ingestion path.","operationId":"record_console_event","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConsoleEventPayload"}}},"required":true},"responses":{"200":{"description":"Event recorded successfully"},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/events/properties/breakdown":{"get":{"tags":["Events"],"summary":"Get property breakdown by grouping events by a column","operationId":"get_property_breakdown","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in '%Y-%m-%d %H:%M:%S' format","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in '%Y-%m-%d %H:%M:%S' format","required":true,"schema":{"type":"string"}},{"name":"group_by","in":"query","description":"Column to group by (channel, device_type, browser, etc.)","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"event_name","in":"query","description":"Filter by event name","required":false,"schema":{"type":"string"}},{"name":"aggregation_level","in":"query","description":"Aggregation level: events, sessions, or visitors - default: events","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Maximum number of results (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"include_crawlers","in":"query","description":"Include crawler/bot traffic (default: false)","required":false,"schema":{"type":"boolean"}},{"name":"filter_country","in":"query","description":"Filter by country (for region/city drill-downs)","required":false,"schema":{"type":"string"}},{"name":"filter_region","in":"query","description":"Filter by region (for city drill-downs)","required":false,"schema":{"type":"string"}},{"name":"filter_browser","in":"query","description":"Filter by browser name (for version drill-downs)","required":false,"schema":{"type":"string"}},{"name":"filter_os","in":"query","description":"Filter by OS name (for version drill-downs)","required":false,"schema":{"type":"string"}},{"name":"filter_channel","in":"query","description":"Filter by channel name (for channel drill-downs)","required":false,"schema":{"type":"string"}},{"name":"filter_referrer","in":"query","description":"Filter by referrer hostname (for referrer drill-downs)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved property breakdown","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PropertyBreakdownResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/events/properties/timeline":{"get":{"tags":["Events"],"summary":"Get property timeline by grouping events by a column over time","operationId":"get_property_timeline","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in '%Y-%m-%d %H:%M:%S' format","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in '%Y-%m-%d %H:%M:%S' format","required":true,"schema":{"type":"string"}},{"name":"group_by","in":"query","description":"Column to group by (channel, device_type, browser, etc.)","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"event_name","in":"query","description":"Filter by event name","required":false,"schema":{"type":"string"}},{"name":"aggregation_level","in":"query","description":"Aggregation level: events, sessions, or visitors - default: events","required":false,"schema":{"type":"string"}},{"name":"bucket_size","in":"query","description":"Time bucket: hour, day, week, month (default: auto-detect)","required":false,"schema":{"type":"string"}},{"name":"include_crawlers","in":"query","description":"Include crawler/bot traffic (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Successfully retrieved property timeline","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PropertyTimelineResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/events/timeline":{"get":{"tags":["Events"],"summary":"Get events timeline","operationId":"get_events_timeline","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date for filtering events","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date for filtering events","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"event_name","in":"query","description":"Filter by specific event name","required":false,"schema":{"type":"string"}},{"name":"bucket_size","in":"query","description":"Bucket size: hour, day, or week (auto-detected if not specified)","required":false,"schema":{"type":"string"}},{"name":"aggregation_level","in":"query","description":"Aggregation level: events, sessions, or visitors (default: events)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved events timeline","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EventTimeline"}}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/events/unique":{"get":{"tags":["Funnels"],"summary":"Get all unique/distinct event types for a project (paginated)","operationId":"get_unique_events","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page (default: 50, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Unique event types retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventTypesResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/external-images":{"get":{"tags":["External Images"],"summary":"List external images for a project","operationId":"list_remote_external_images","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page (default: 20)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List of external images","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedExternalImagesResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["External Images"],"summary":"Register an external Docker image","description":"Registers an external Docker image reference without triggering a deployment.\nThe image can be deployed later using the deploy/image endpoint.","operationId":"register_external_image","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterImageRequest"}}},"required":true},"responses":{"201":{"description":"Image registered successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalImageResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/external-images/{image_id}":{"get":{"tags":["External Images"],"summary":"Get details of a specific external image","operationId":"get_remote_external_image","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"image_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Image details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExternalImageResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Image not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["External Images"],"summary":"Delete an external image","operationId":"delete_external_image","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"image_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Image deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Image not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/flags":{"get":{"tags":["Feature Flags"],"operationId":"list_flags","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"include_archived","in":"query","description":"Include archived flags. Defaults to false.","required":false,"schema":{"type":"boolean"}},{"name":"page","in":"query","description":"1-indexed page number. Defaults to 1.","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page. Defaults to 20, capped at 100.","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}}],"responses":{"200":{"description":"Flags listed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Feature Flags"],"operationId":"create_flag","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFlagRequest"}}},"required":true},"responses":{"201":{"description":"Flag created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"409":{"description":"Flag key already exists"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/flags/{key}":{"get":{"tags":["Feature Flags"],"operationId":"get_flag","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"key","in":"path","description":"Flag key","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Flag retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Flag not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Feature Flags"],"operationId":"archive_flag","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"key","in":"path","description":"Flag key","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Flag archived","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArchiveFlagResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Flag not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Feature Flags"],"operationId":"update_flag","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"key","in":"path","description":"Flag key","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateFlagRequest"}}},"required":true},"responses":{"200":{"description":"Flag updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Flag not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/flags/{key}/environments/{environment_id}":{"put":{"tags":["Feature Flags"],"summary":"Set a flag's value in one environment, and/or flip its kill switch.","operationId":"set_flag_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"key","in":"path","description":"Flag key","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"path","description":"Environment ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetFlagEnvironmentRequest"}}},"required":true},"responses":{"200":{"description":"Environment value set","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagEnvironmentResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Flag or environment not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/flags/{key}/restore":{"post":{"tags":["Feature Flags"],"summary":"Bring an archived flag back.","description":"Archiving is otherwise one-way: the key stays reserved so the flag cannot\neven be re-created under the same name, which makes an accidental archive\nunrecoverable through the API.","operationId":"restore_flag","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"key","in":"path","description":"Flag key","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Flag restored","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Flag not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/funnels":{"get":{"tags":["Funnels"],"summary":"List all funnels for a project","operationId":"list_funnels","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Funnels retrieved successfully","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/FunnelResponse"}}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Funnels"],"summary":"Create a new funnel","operationId":"create_funnel","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFunnelRequest"}}},"required":true},"responses":{"201":{"description":"Funnel created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFunnelResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/funnels/preview":{"post":{"tags":["Funnels"],"summary":"Preview funnel metrics without creating the funnel","operationId":"preview_funnel_metrics","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFunnelRequest"}}},"required":true},"responses":{"200":{"description":"Funnel metrics preview","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FunnelMetricsResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/funnels/{funnel_id}":{"put":{"tags":["Funnels"],"summary":"Update a funnel","operationId":"update_funnel","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"funnel_id","in":"path","description":"Funnel ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFunnelRequest"}}},"required":true},"responses":{"200":{"description":"Funnel updated successfully"},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"404":{"description":"Funnel not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Funnels"],"summary":"Delete a funnel","operationId":"delete_funnel","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"funnel_id","in":"path","description":"Funnel ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Funnel deleted successfully"},"401":{"description":"Unauthorized"},"404":{"description":"Funnel not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/funnels/{funnel_id}/metrics":{"get":{"tags":["Funnels"],"summary":"Get funnel metrics","operationId":"get_funnel_metrics","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"funnel_id","in":"path","description":"Funnel ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID filter","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"country_code","in":"query","description":"Country code filter","required":false,"schema":{"type":"string"}},{"name":"start_date","in":"query","description":"Start date filter (ISO 8601)","required":false,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date filter (ISO 8601)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Funnel metrics retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FunnelMetricsResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"404":{"description":"Funnel not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/git":{"post":{"tags":["Projects"],"summary":"Update git settings for a project","operationId":"update_git_settings","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateGitSettingsRequest"}}},"required":true},"responses":{"200":{"description":"Git settings updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"400":{"description":"Invalid git configuration or branch does not exist"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/gitlab/reinstall-webhook":{"post":{"tags":["Projects"],"summary":"Reinstall the GitLab webhook for a project","description":"Removes the existing webhook (if any) and installs a fresh one.\nUse this when a webhook has been manually deleted on the GitLab side\nand automatic deployments have stopped working.","operationId":"reinstall_gitlab_webhook","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Webhook reinstalled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReinstallWebhookResponse"}}}},"400":{"description":"Project is not connected to a GitLab repository"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/has-error-groups":{"get":{"tags":["error-tracking"],"summary":"Check if project has any error groups","operationId":"has_error_groups","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Error groups existence check","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HasErrorGroupsResponse"}}}},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/has-events":{"get":{"tags":["Events"],"summary":"Check if project has any analytics events","operationId":"has_analytics_events","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully checked for events","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HasEventsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/hourly-visits":{"get":{"tags":["Events"],"summary":"Get hourly visits","operationId":"get_hourly_visits","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date for filtering visits","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date for filtering visits","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"aggregation_level","in":"query","description":"Aggregation level: events (page views), sessions (unique sessions), or visitors (unique visitors) - default: events","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved hourly visits","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EventTimeline"}}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/images":{"get":{"tags":["External Images"],"summary":"List all external images for a project","operationId":"list_external_images","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of external images","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PushedExternalImageResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/images/push":{"post":{"tags":["External Images"],"summary":"Push an external Docker image","operationId":"push_external_image","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PushImageRequest"}}},"required":true},"responses":{"201":{"description":"Image pushed successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PushedExternalImageResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/images/{image_id}":{"get":{"tags":["External Images"],"summary":"Get details of a specific external image","operationId":"get_external_image","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"image_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Image details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PushedExternalImageResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Image not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/incidents":{"get":{"tags":["Status Page"],"summary":"List incidents for a project","operationId":"list_incidents","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"status","in":"query","description":"Filter by status","required":false,"schema":{"type":"string"}},{"name":"page","in":"query","description":"Page number","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Successfully retrieved incidents"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Status Page"],"summary":"Create a new incident","operationId":"create_incident","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateIncidentRequest"}}},"required":true},"responses":{"201":{"description":"Incident created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncidentResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/incidents/bucketed":{"get":{"tags":["Status Page"],"summary":"Get bucketed incident data for a project","operationId":"get_bucketed_incidents","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"interval","in":"query","description":"Bucket interval: '5min', 'hourly', or 'daily' (default: hourly)","required":false,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601) (default: 7 days ago)","required":false,"schema":{"type":"string"}},{"name":"end_time","in":"query","description":"End time (ISO 8601) (default: now)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved bucketed incident data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncidentBucketedResponse"}}}},"400":{"description":"Invalid parameters"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/logs":{"delete":{"tags":["Logs"],"summary":"Purge all logs for a project before a given timestamp","operationId":"purge_project_logs","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PurgeLogsRequest"}}},"required":true},"responses":{"200":{"description":"Purge completed"},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/mcp-servers":{"get":{"tags":["Agents"],"operationId":"list_mcps","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListMcpsResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Agents"],"operationId":"create_mcp","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMcpRequest"}}},"required":true},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpDefinitionResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/mcp-servers/{slug}":{"get":{"tags":["Agents"],"operationId":"get_mcp","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"MCP server not found"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Agents"],"operationId":"update_mcp","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMcpRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"MCP server not found"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Agents"],"operationId":"delete_mcp","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"MCP server deleted"},"401":{"description":"Unauthorized"},"404":{"description":"MCP server not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/mcp-servers/{slug}/config/{field}":{"get":{"tags":["Agents"],"operationId":"reveal_mcp_config","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}},{"name":"field","in":"path","description":"Sensitive field path, such as url or env.API_TOKEN","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SensitiveMcpConfigValueResponse"}}}},"400":{"description":"Field is not revealable"},"401":{"description":"Unauthorized"},"403":{"description":"Missing secrets:read permission"},"404":{"description":"MCP server or field not found"},"500":{"description":"Configuration read or audit failed"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/monitors":{"get":{"tags":["Status Page"],"summary":"List monitors for a project","operationId":"list_monitors","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved monitors","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MonitorResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Status Page"],"summary":"Create a new monitor","operationId":"create_monitor","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMonitorRequest"}}},"required":true},"responses":{"201":{"description":"Monitor created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MonitorResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/observe/events":{"get":{"tags":["Observability"],"summary":"List a merged page of observability events for a project.","description":"Each row carries everything the side panel needs to render — no\nfollow-up fetch is required for the common case. Heavy fields\n(stacktraces, headers, span attributes) are truncated server-side and\nexpose a `*_truncated` flag; clients fetch the full row from the\n`/full` endpoint only when the user explicitly clicks \"Show full\".","operationId":"observability_list_events","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"kinds","in":"query","description":"Comma-separated kinds: `log,request,span,error,revenue`. Empty or\nmissing returns every kind.","required":false,"schema":{"type":"string"}},{"name":"from","in":"query","description":"Inclusive lower bound on event timestamp (ISO 8601, `Z` suffix).","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","description":"Inclusive upper bound on event timestamp.","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"deployment_id","in":"query","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"search","in":"query","description":"Free-text substring matched against per-kind summary fields\n(request path / error class / revenue event_type).","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Page size (default 50, max 200).","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"hide_bots","in":"query","description":"When `true`, exclude bot/crawler request rows. When `false`, only\ninclude bot rows. Omitted means \"include everything\" (default).\nOnly affects the `Request` kind.","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Merged event page","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventsResponse"}}}},"400":{"description":"Invalid filter (kinds, time range, …)","content":{"text/plain":{"schema":{"type":"string"}}}},"401":{"description":"Unauthorized","content":{"text/plain":{"schema":{"type":"string"}}}},"403":{"description":"Insufficient permissions","content":{"text/plain":{"schema":{"type":"string"}}}},"500":{"description":"Internal server error","content":{"text/plain":{"schema":{"type":"string"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/observe/events/{kind}/{event_id}/full":{"get":{"tags":["Observability"],"summary":"Fetch the un-truncated form of one event by `(kind, id)`. Side panel\n\"Show full\" action calls this — the list response carries truncated\npreviews + a `*_truncated` flag to let the UI decide whether to fetch.","operationId":"observability_full_event","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"kind","in":"path","description":"Event kind discriminator","required":true,"schema":{"$ref":"#/components/schemas/EventKind"}},{"name":"event_id","in":"path","description":"Per-kind identity: request_id for requests, `{trace_id}:{span_id}` for spans, serial id for errors/revenue","required":true,"schema":{"type":"string"}},{"name":"ts","in":"query","description":"The row's event timestamp as returned by the list endpoint. Optional,\nbut strongly recommended: it bounds the lookup to the storage\npartitions/chunks around that instant instead of scanning the whole\nretention window.","required":false,"schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"Full row","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FullEvent"}}}},"401":{"description":"Unauthorized","content":{"text/plain":{"schema":{"type":"string"}}}},"403":{"description":"Insufficient permissions","content":{"text/plain":{"schema":{"type":"string"}}}},"404":{"description":"Event not found in project","content":{"text/plain":{"schema":{"type":"string"}}}},"500":{"description":"Internal server error","content":{"text/plain":{"schema":{"type":"string"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/releases/{release}/source-files":{"get":{"tags":["source-maps"],"summary":"List uploaded source files for a release (metadata only).","operationId":"list_source_files","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"release","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of source files","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceFileListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["source-maps"],"summary":"Upload a raw source file for a release (native symbolication).","description":"Accepts a multipart form with:\n- `file`: the source file bytes (required)\n- `file_path`: the path of the file as it appears in stack frames (required;\n derived from the uploaded filename if omitted). Normalized with the `~`\n prefix convention, matching source-map storage.\n\nRequires the project's `error_source_context_enabled` toggle to be on.\nUpserts on (project, release, file_path).","operationId":"upload_source_file","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"release","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"201":{"description":"Source file uploaded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceFileResponse"}}}},"400":{"description":"Missing fields"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"409":{"description":"Source context disabled for project"},"413":{"description":"Source file too large"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["source-maps"],"summary":"Delete all uploaded source files for a release.","operationId":"delete_release_source_files","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"release","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Source files deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/releases/{release}/source-maps":{"get":{"tags":["source-maps"],"summary":"List all source maps for a specific release","operationId":"list_source_maps","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"release","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of source maps","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceMapListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["source-maps"],"summary":"Upload a source map for a release.","description":"Accepts a multipart form with:\n- `file`: The .map file (required)\n- `file_path`: The URL path of the minified file as it appears in stack traces (required).\n Uses the ~ prefix convention (e.g., \"~/assets/main.js\").\n If a full URL is provided, it will be normalized automatically.\n- `dist`: Optional distribution identifier\n\nIf a source map already exists for the same (project, release, file_path), it is replaced.","operationId":"upload_source_map","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"release","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"201":{"description":"Source map uploaded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceMapResponse"}}}},"400":{"description":"Invalid source map or missing fields"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"413":{"description":"Source map too large"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["source-maps"],"summary":"Delete all source maps for a specific release","operationId":"delete_release_source_maps","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"release","in":"path","description":"Release version","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Source maps deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/events":{"get":{"tags":["Revenue"],"summary":"Recent ingested events for the activity feed.","operationId":"revenue_recent_events","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RecentEventResponse"}}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/integrations":{"get":{"tags":["Revenue"],"summary":"List revenue integrations for a project.","operationId":"revenue_list_integrations","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/IntegrationResponse"}}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Revenue"],"summary":"Create a new revenue integration. Response contains the generated\nwebhook path that the user must paste into their provider's dashboard.","operationId":"revenue_create_integration","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateIntegrationBody"}}},"required":true},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntegrationResponse"}}}},"400":{"description":"Validation error"},"409":{"description":"Already connected"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/integrations/{integration_id}":{"delete":{"tags":["Revenue"],"summary":"Delete a revenue integration (permanent — use rotate_token to refresh\ncredentials without breaking history).","operationId":"revenue_delete_integration","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"integration_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":""}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/integrations/{integration_id}/config":{"post":{"tags":["Revenue"],"summary":"Replace the typed provider config on an integration. Passing `null`\nclears the config back to the accept-everything default. The config's\nprovider tag must match the integration's provider.","operationId":"revenue_update_config","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"integration_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateConfigBody"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntegrationResponse"}}}},"400":{"description":"Validation error"},"404":{"description":"Integration not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/integrations/{integration_id}/import/invoices":{"post":{"tags":["Revenue"],"summary":"Import a Stripe invoices CSV export. Each paid invoice becomes an\n`invoice.paid` event so historical MRR/charge totals populate the\ntimeseries. Ingestion is idempotent: re-uploading the same file is a\nno-op.","operationId":"revenue_import_invoices_csv","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"integration_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportOutcomeResponse"}}}},"400":{"description":"Malformed CSV or wrong provider"},"404":{"description":"Integration not found"},"413":{"description":"CSV too large"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/integrations/{integration_id}/import/subscriptions":{"post":{"tags":["Revenue"],"summary":"Import a Stripe subscriptions CSV export. Use this to backfill MRR /\nactive subscriptions when migrating from Stripe without providing\nAPI keys. Webhooks remain the source of truth for live updates —\nCSV rows never overwrite newer webhook state.","operationId":"revenue_import_subscriptions_csv","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"integration_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportOutcomeResponse"}}}},"400":{"description":"Malformed CSV or wrong provider"},"404":{"description":"Integration not found"},"413":{"description":"CSV too large"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/integrations/{integration_id}/rotate-token":{"post":{"tags":["Revenue"],"summary":"Rotate the webhook path token. Returns the new integration state —\nthe user must paste the new URL into their provider's dashboard.","operationId":"revenue_rotate_token","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"integration_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntegrationResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/integrations/{integration_id}/update-secret":{"post":{"tags":["Revenue"],"summary":"Replace the stored signing secret without rotating the webhook URL.\nUse this after rotating the secret in the provider's dashboard.","operationId":"revenue_update_secret","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"integration_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSecretBody"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntegrationResponse"}}}},"400":{"description":"Validation error"},"404":{"description":"Integration not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/metrics/customers":{"get":{"tags":["Revenue"],"summary":"New + churned customers per bucket.","operationId":"revenue_metrics_customers","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CustomerMovementResponse"}}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/metrics/mrr":{"get":{"tags":["Revenue"],"summary":"Bucketed MRR timeseries for the revenue chart.","operationId":"revenue_metrics_mrr","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MrrBucketResponse"}}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/revenue/metrics/summary":{"get":{"tags":["Revenue"],"summary":"Current MRR / ARR / churn / ARPU for a project, in one currency.","operationId":"revenue_metrics_summary","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MetricsSummaryResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/secrets":{"get":{"tags":["Secrets"],"summary":"List project secrets (metadata only — values never returned).","operationId":"listProjectSecrets","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Optional environment filter","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of secrets (metadata only, no values)","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProjectSecretResponse"}}}}},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}}},"post":{"tags":["Secrets"],"summary":"Create a new secret. The value is encrypted before storage and will be\nmounted as a file at `/run/secrets/` on the next deployment.\nThe plaintext value is NOT returned — the response carries only metadata.","operationId":"createProjectSecret","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectSecretRequest"}}},"required":true},"responses":{"201":{"description":"Secret created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectSecretResponse"}}}},"400":{"description":"Invalid key or value too large"},"409":{"description":"Key already exists in project"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/secrets/{secret_id}":{"put":{"tags":["Secrets"],"summary":"Update a project secret. Value rotation requires a redeploy to take effect —\nrunning containers keep their currently-mounted values until the next\ndeployment.","operationId":"updateProjectSecret","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"secret_id","in":"path","description":"Secret ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProjectSecretRequest"}}},"required":true},"responses":{"200":{"description":"Secret updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectSecretResponse"}}}},"400":{"description":"Value too large"},"404":{"description":"Secret not found"},"500":{"description":"Internal server error"}}},"delete":{"tags":["Secrets"],"summary":"Delete a project secret. Running containers keep their mounted secret files\nuntil they are redeployed.","operationId":"deleteProjectSecret","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"secret_id","in":"path","description":"Secret ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Secret deleted"},"404":{"description":"Secret not found"},"500":{"description":"Internal server error"}}}},"/projects/{project_id}/settings":{"post":{"tags":["Projects"],"summary":"Update project settings","operationId":"update_project_settings","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProjectSettingsRequest"}}},"required":true},"responses":{"200":{"description":"Project settings updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/skills":{"get":{"tags":["Agents"],"operationId":"list_skills","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListSkillsResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Agents"],"operationId":"create_skill","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSkillRequest"}}},"required":true},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/skills/upload":{"post":{"tags":["Agents"],"summary":"Upload a skill with an archive (tar.gz) — project-scoped.","operationId":"upload_skill","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"type":"string"}}},"required":true},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/skills/{slug}":{"get":{"tags":["Agents"],"operationId":"get_skill","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Agents"],"operationId":"update_skill","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSkillRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Agents"],"operationId":"delete_skill","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Skill deleted"},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/skills/{slug}/archive":{"get":{"tags":["Agents"],"summary":"Download a skill's archive (tar.gz) — project-scoped.","operationId":"download_skill_archive","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Skill archive tar.gz","content":{"application/gzip":{}}},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found or has no archive"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/source-map-releases":{"get":{"tags":["source-maps"],"summary":"List all releases that have source maps for a project","operationId":"list_releases","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of releases","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReleaseListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/source-maps/{source_map_id}":{"delete":{"tags":["source-maps"],"summary":"Delete a specific source map by ID","operationId":"delete_source_map","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"source_map_id","in":"path","description":"Source map ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Source map deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Source map not found"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/static-bundles":{"get":{"tags":["Static Bundles"],"summary":"List static bundles for a project","operationId":"list_static_bundles","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page (default: 20)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List of static bundles","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedStaticBundlesResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/static-bundles/{bundle_id}":{"get":{"tags":["Static Bundles"],"summary":"Get details of a specific static bundle","operationId":"get_static_bundle","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"bundle_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Bundle details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StaticBundleResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Bundle not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Static Bundles"],"summary":"Delete a static bundle","operationId":"delete_static_bundle","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"bundle_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Bundle deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Bundle not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/status":{"get":{"tags":["Status Page"],"summary":"Get status page overview","operationId":"get_status_overview","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved status overview","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatusPageOverview"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/unique-counts":{"get":{"tags":["Events"],"summary":"Get unique counts over time frame","operationId":"get_unique_counts","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"start_date","in":"query","description":"Start date in '%Y-%m-%d %H:%M:%S' format","required":true,"schema":{"type":"string"}},{"name":"end_date","in":"query","description":"End date in '%Y-%m-%d %H:%M:%S' format","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"metric","in":"query","description":"Metric to count: 'sessions' (unique sessions), 'visitors' (unique visitors), 'returning_visitors' (visitors seen before the range), or 'page_views' (total page views) (default: 'sessions')","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved count","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UniqueCountsResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/upload/static":{"post":{"tags":["Static Bundles"],"summary":"Upload a static bundle for later deployment","description":"Uploads a tar.gz or zip file containing static assets. The bundle can be\ndeployed later using the deploy/static endpoint.","operationId":"upload_static_bundle","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/SourceArchiveUpload"}}},"required":true},"responses":{"201":{"description":"Bundle uploaded successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StaticBundleResponse"}}}},"400":{"description":"Invalid request or unsupported format"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project not found"},"413":{"description":"Bundle too large"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/vulnerability-scans":{"get":{"tags":["Vulnerability Scans"],"operationId":"list_project_scans","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List of vulnerability scans","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ScanResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Vulnerability Scans"],"operationId":"trigger_scan","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerScanRequest"}}},"required":true},"responses":{"202":{"description":"Scan triggered successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerScanResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/vulnerability-scans/environments":{"get":{"tags":["Vulnerability Scans"],"operationId":"get_latest_scans_per_environment","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Latest scans per environment for current deployments","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ScanResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/vulnerability-scans/latest":{"get":{"tags":["Vulnerability Scans"],"operationId":"get_latest_scan","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Latest scan for project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScanResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"No scans found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/webhooks":{"get":{"tags":["Webhooks"],"summary":"List all webhooks for a project","operationId":"list_webhooks","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-indexed)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":1},{"name":"page_size","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0},"example":20},{"name":"sort_by","in":"query","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"List of webhooks","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/WebhookResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Webhooks"],"summary":"Create a new webhook","operationId":"create_webhook","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWebhookRequestBody"}}},"required":true},"responses":{"201":{"description":"Webhook created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/webhooks/{webhook_id}":{"get":{"tags":["Webhooks"],"summary":"Get a specific webhook","operationId":"get_webhook","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"webhook_id","in":"path","description":"Webhook ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Webhook details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Webhook not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Webhooks"],"summary":"Update a webhook","operationId":"update_webhook","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"webhook_id","in":"path","description":"Webhook ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWebhookRequestBody"}}},"required":true},"responses":{"200":{"description":"Webhook updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookResponse"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Webhook not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Webhooks"],"summary":"Delete a webhook","operationId":"delete_webhook","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"webhook_id","in":"path","description":"Webhook ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Webhook deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Webhook not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/webhooks/{webhook_id}/deliveries":{"get":{"tags":["Webhook Deliveries"],"summary":"List webhook deliveries","operationId":"list_deliveries","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"webhook_id","in":"path","description":"Webhook ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"limit","in":"query","description":"Number of deliveries to return (default: 50)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List of deliveries","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/WebhookDeliveryResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/webhooks/{webhook_id}/deliveries/{delivery_id}":{"get":{"tags":["Webhook Deliveries"],"summary":"Get a specific webhook delivery by ID","operationId":"get_delivery","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"webhook_id","in":"path","description":"Webhook ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"delivery_id","in":"path","description":"Delivery ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Delivery details including full payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDeliveryResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Delivery not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/webhooks/{webhook_id}/deliveries/{delivery_id}/retry":{"post":{"tags":["Webhook Deliveries"],"summary":"Retry a failed delivery","operationId":"retry_delivery","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"webhook_id","in":"path","description":"Webhook ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"delivery_id","in":"path","description":"Delivery ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Delivery retried","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDeliveryResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Delivery not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/projects/{project_id}/workflows/dry-run":{"post":{"tags":["Workflows"],"operationId":"workflow_dry_run","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkflowDryRunRequest"}}},"required":true},"responses":{"202":{"description":"Ephemeral run created and queued","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRunResponse"}}}},"400":{"description":"Validation error (bad YAML, oversized payload, capped limits exceeded)"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Project not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/proxy-logs":{"get":{"tags":["Proxy Logs"],"summary":"Get proxy logs with optional filters and pagination","operationId":"get_proxy_logs","parameters":[{"name":"project_id","in":"query","description":"Filter by project ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"session_id","in":"query","description":"Filter by session ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"visitor_id","in":"query","description":"Filter by visitor ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"start_date","in":"query","description":"Start date for filtering (ISO 8601 format).\n\n**Defaults to 1 hour before `end_date` (or before now) when omitted.**\nThe listing is always time-bounded: an unbounded query would have to\nconsider the entire retention window — 100M+ rows on a busy deployment —\nto return a single page. Pass an explicit `start_date` to widen the\nwindow, up to the configured retention horizon.\n\nThe maximum span between `start_date` and `end_date` is 7 days when\n`project_id` is omitted, or 30 days when a single `project_id` is set —\na project-scoped query is bounded by that project's own row count\nrather than the whole deployment's. A wider request is rejected with a\n400 naming the applicable cap.","required":false,"schema":{"type":["string","null"],"format":"date-time"}},{"name":"end_date","in":"query","description":"End date for filtering (ISO 8601 format). Defaults to now.","required":false,"schema":{"type":["string","null"],"format":"date-time"}},{"name":"method","in":"query","description":"Filter by HTTP method (GET, POST, etc.)","required":false,"schema":{"type":["string","null"]}},{"name":"host","in":"query","description":"Filter by host header","required":false,"schema":{"type":["string","null"]}},{"name":"path","in":"query","description":"Filter by path (supports partial match)","required":false,"schema":{"type":["string","null"]}},{"name":"client_ip","in":"query","description":"Filter by client IP address","required":false,"schema":{"type":["string","null"]}},{"name":"status_code","in":"query","description":"Filter by HTTP status code","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"response_time_min","in":"query","description":"Filter by minimum response time in ms","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"response_time_max","in":"query","description":"Filter by maximum response time in ms","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"routing_status","in":"query","description":"Filter by routing status (routed, no_project, error, pending)","required":false,"schema":{"type":["string","null"]}},{"name":"request_source","in":"query","description":"Filter by request source (proxy, api, console, cli)","required":false,"schema":{"type":["string","null"]}},{"name":"is_system_request","in":"query","description":"Filter by system request flag","required":false,"schema":{"type":["boolean","null"]}},{"name":"user_agent","in":"query","description":"Filter by user agent string (partial match)","required":false,"schema":{"type":["string","null"]}},{"name":"browser","in":"query","description":"Filter by browser name","required":false,"schema":{"type":["string","null"]}},{"name":"operating_system","in":"query","description":"Filter by operating system","required":false,"schema":{"type":["string","null"]}},{"name":"device_type","in":"query","description":"Filter by device type (mobile, desktop, tablet)","required":false,"schema":{"type":["string","null"]}},{"name":"is_bot","in":"query","description":"Filter by bot detection","required":false,"schema":{"type":["boolean","null"]}},{"name":"exclude_bots","in":"query","description":"When `true`, exclude rows flagged as bots while KEEPING rows whose\n`is_bot` is NULL (older rows without detection metadata). This is the\ntri-state complement of `is_bot=false`, which matches only rows\nexplicitly detected as non-bots. `false`/omitted is a no-op.","required":false,"schema":{"type":["boolean","null"]}},{"name":"bot_name","in":"query","description":"Filter by bot name","required":false,"schema":{"type":["string","null"]}},{"name":"ai_provider","in":"query","description":"Filter by AI provider (e.g. `OpenAI`, `Anthropic`, `Perplexity`). Matches\nthe canonical provider returned by the AI agent detector.","required":false,"schema":{"type":["string","null"]}},{"name":"ai_agent","in":"query","description":"Filter by AI agent name (e.g. `GPTBot`, `ChatGPT-User`). Equivalent to\nfiltering `bot_name` against a known AI taxonomy.","required":false,"schema":{"type":["string","null"]}},{"name":"is_ai_agent","in":"query","description":"When `true`, only return requests classified as known AI agents\n(regardless of provider/agent). Mutually compatible with the above.","required":false,"schema":{"type":["boolean","null"]}},{"name":"request_size_min","in":"query","description":"Filter by minimum request size in bytes","required":false,"schema":{"type":["integer","null"],"format":"int64"}},{"name":"request_size_max","in":"query","description":"Filter by maximum request size in bytes","required":false,"schema":{"type":["integer","null"],"format":"int64"}},{"name":"response_size_min","in":"query","description":"Filter by minimum response size in bytes","required":false,"schema":{"type":["integer","null"],"format":"int64"}},{"name":"response_size_max","in":"query","description":"Filter by maximum response size in bytes","required":false,"schema":{"type":["integer","null"],"format":"int64"}},{"name":"cache_status","in":"query","description":"Filter by cache status","required":false,"schema":{"type":["string","null"]}},{"name":"container_id","in":"query","description":"Filter by container ID","required":false,"schema":{"type":["string","null"]}},{"name":"upstream_host","in":"query","description":"Filter by upstream host","required":false,"schema":{"type":["string","null"]}},{"name":"has_error","in":"query","description":"Filter by presence of error message","required":false,"schema":{"type":["boolean","null"]}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (default: 20, max: 100)","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"sort_by","in":"query","description":"Sort by field (default: timestamp)","required":false,"schema":{"type":["string","null"]}},{"name":"sort_order","in":"query","description":"Sort order (asc or desc, default: desc)","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"List of proxy logs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProxyLogsPaginatedResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/ai-agents/known":{"get":{"tags":["Proxy Logs"],"summary":"List every AI agent the detector knows how to classify.","description":"Returned in the same order as the internal taxonomy so the UI can use it as\na stable dropdown.","operationId":"list_known_ai_agents","responses":{"200":{"description":"Known AI agents","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KnownAiAgentsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/request/{request_id}":{"get":{"tags":["Proxy Logs"],"summary":"Get a proxy log by request ID (for tracing)","operationId":"get_proxy_log_by_request_id","parameters":[{"name":"request_id","in":"path","description":"Request ID from pingora","required":true,"schema":{"type":"string"}},{"name":"timestamp","in":"query","description":"Event time of the log row (ISO 8601). When provided, the lookup is\nbounded to the hypertable chunks around this instant instead of\nscanning (and decompressing) the whole retention window. The list\nendpoint already returns this value per row — always pass it when\nnavigating from a list.","required":false,"schema":{"type":["string","null"],"format":"date-time"}}],"responses":{"200":{"description":"Proxy log found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProxyLogResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Proxy log not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/ai-agent-pages":{"get":{"tags":["Proxy Logs"],"summary":"Get the top pages accessed by a specific AI agent over a time window.","description":"Returns page paths ranked by request count, scoped to a single canonical\nagent name (e.g. `ChatGPT-User`). Use `GET /proxy-logs/ai-agents/known` to\nlist all valid agent names. Unknown agent names return an empty items array.","operationId":"get_ai_agent_pages","parameters":[{"name":"agent","in":"query","description":"Canonical agent name to filter by (e.g. `ChatGPT-User`, `ClaudeBot`).\nMust be a name returned by `GET /proxy-logs/ai-agents/known`.","required":true,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Filter by project ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601). Defaults to `end_time - 7d`.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-22T00:00:00Z"},{"name":"end_time","in":"query","description":"End time (ISO 8601). Defaults to now.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-29T00:00:00Z"},{"name":"limit","in":"query","description":"Maximum rows to return. Capped at 100 server-side.","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}}],"responses":{"200":{"description":"Pages breakdown for the requested agent","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiAgentPagesResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/ai-agents":{"get":{"tags":["Proxy Logs"],"summary":"Get the per-AI-agent breakdown for a project over a time window.","operationId":"get_ai_agent_breakdown","parameters":[{"name":"project_id","in":"query","description":"Filter by project ID (recommended for per-project analytics).","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601). Defaults to `end_time - 7d`.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-22T00:00:00Z"},{"name":"end_time","in":"query","description":"End time (ISO 8601). Defaults to now.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-29T00:00:00Z"},{"name":"limit","in":"query","description":"Maximum rows to return. Capped at 100 server-side.","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"path","in":"query","description":"Optional exact path filter. Only used by the AI pages breakdown — when\nset, returns the single matching page so callers can ask \"how many AI\nagents hit this page?\".","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"AI agent breakdown","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiAgentBreakdownResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/ai-agents/timeline":{"get":{"tags":["Proxy Logs"],"summary":"Time-bucketed AI-agent request volume, split by provider or agent.","description":"Powers the \"AI agents over time\" stacked chart. Same data source as the AI\nagent breakdown (request logs), just bucketed.","operationId":"get_ai_agent_timeline","parameters":[{"name":"project_id","in":"query","description":"Filter by project ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601). Defaults to `end_time - 7d`.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-22T00:00:00Z"},{"name":"end_time","in":"query","description":"End time (ISO 8601). Defaults to now.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-29T00:00:00Z"},{"name":"group_by","in":"query","description":"Grouping dimension: `provider` (default) or `agent`.","required":false,"schema":{"type":["string","null"]},"example":"provider"},{"name":"bucket","in":"query","description":"Bucket interval override (e.g. `1 hour`, `1 day`). Auto-selected from the\nwindow width when omitted.","required":false,"schema":{"type":["string","null"]},"example":"1 hour"}],"responses":{"200":{"description":"AI agent timeline","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiAgentTimelineResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/ai-pages":{"get":{"tags":["Proxy Logs"],"summary":"Get the top pages crawled by AI agents over a time window.","operationId":"get_ai_page_breakdown","parameters":[{"name":"project_id","in":"query","description":"Filter by project ID (recommended for per-project analytics).","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601). Defaults to `end_time - 7d`.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-22T00:00:00Z"},{"name":"end_time","in":"query","description":"End time (ISO 8601). Defaults to now.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-29T00:00:00Z"},{"name":"limit","in":"query","description":"Maximum rows to return. Capped at 100 server-side.","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"path","in":"query","description":"Optional exact path filter. Only used by the AI pages breakdown — when\nset, returns the single matching page so callers can ask \"how many AI\nagents hit this page?\".","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"AI page breakdown","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiPageBreakdownResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/ai-status":{"get":{"tags":["Proxy Logs"],"summary":"HTTP status-class breakdown for AI-agent traffic — are bots being served\n(2xx) or hitting broken/blocked pages (4xx/5xx)?","operationId":"get_ai_status_breakdown","parameters":[{"name":"project_id","in":"query","description":"Filter by project ID (recommended for per-project analytics).","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID.","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"start_time","in":"query","description":"Start time (ISO 8601). Defaults to `end_time - 7d`.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-22T00:00:00Z"},{"name":"end_time","in":"query","description":"End time (ISO 8601). Defaults to now.","required":false,"schema":{"type":["string","null"]},"example":"2026-05-29T00:00:00Z"},{"name":"limit","in":"query","description":"Maximum rows to return. Capped at 100 server-side.","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"path","in":"query","description":"Optional exact path filter. Only used by the AI pages breakdown — when\nset, returns the single matching page so callers can ask \"how many AI\nagents hit this page?\".","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"AI status breakdown","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiStatusBreakdownResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/projects-health":{"get":{"tags":["Proxy Logs"],"summary":"Get health summaries for multiple projects (last 1 hour)","operationId":"get_projects_health","parameters":[{"name":"project_ids","in":"query","description":"Comma-separated list of project IDs","required":true,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Optional start time (ISO 8601). Defaults to `end_time - 1h`.","required":false,"schema":{"type":["string","null"]},"example":"2025-10-23T00:00:00Z"},{"name":"end_time","in":"query","description":"Optional end time (ISO 8601). Defaults to now.","required":false,"schema":{"type":["string","null"]},"example":"2025-10-23T23:59:59Z"},{"name":"is_bot","in":"query","description":"Filter by bot detection. Pass `false` to exclude bots, `true` for bots only.","required":false,"schema":{"type":["boolean","null"]}}],"responses":{"200":{"description":"Health summaries per project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectsHealthResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/time-buckets":{"get":{"tags":["Proxy Logs"],"summary":"Get time-bucketed statistics with optional filters","operationId":"get_time_bucket_stats","parameters":[{"name":"start_time","in":"query","description":"Start time (ISO 8601 format)","required":true,"schema":{"type":"string"},"example":"2025-10-23T00:00:00Z"},{"name":"end_time","in":"query","description":"End time (ISO 8601 format)","required":true,"schema":{"type":"string"},"example":"2025-10-23T23:59:59Z"},{"name":"bucket_interval","in":"query","description":"Bucket interval (e.g., \"1 hour\", \"1 day\", \"5 minutes\")","required":false,"schema":{"type":"string"}},{"name":"method","in":"query","description":"Filter by HTTP method","required":false,"schema":{"type":"string"}},{"name":"client_ip","in":"query","description":"Filter by client IP","required":false,"schema":{"type":"string"}},{"name":"project_id","in":"query","description":"Filter by project ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"host","in":"query","description":"Filter by host","required":false,"schema":{"type":"string"}},{"name":"status_code","in":"query","description":"Filter by status code","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"status_code_class","in":"query","description":"Filter by status code class (e.g. \"2xx\", \"3xx\", \"4xx\", \"5xx\")","required":false,"schema":{"type":"string"}},{"name":"routing_status","in":"query","description":"Filter by routing status","required":false,"schema":{"type":"string"}},{"name":"request_source","in":"query","description":"Filter by request source","required":false,"schema":{"type":"string"}},{"name":"is_bot","in":"query","description":"Filter by bot detection","required":false,"schema":{"type":"boolean"}},{"name":"device_type","in":"query","description":"Filter by device type","required":false,"schema":{"type":"string"}},{"name":"has_project","in":"query","description":"When true, only count requests that matched a project\n(project_id IS NOT NULL). Makes chart totals line up with the\nper-project health cards.","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Time-bucketed statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TimeBucketStatsResponse"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/stats/today":{"get":{"tags":["Proxy Logs"],"summary":"Get today's request count with optional filters","operationId":"get_today_stats","parameters":[{"name":"method","in":"query","description":"Filter by HTTP method","required":false,"schema":{"type":["string","null"]}},{"name":"client_ip","in":"query","description":"Filter by client IP","required":false,"schema":{"type":["string","null"]}},{"name":"project_id","in":"query","description":"Filter by project ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"deployment_id","in":"query","description":"Filter by deployment ID","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"host","in":"query","description":"Filter by host","required":false,"schema":{"type":["string","null"]}},{"name":"status_code","in":"query","description":"Filter by status code","required":false,"schema":{"type":["integer","null"],"format":"int32"}},{"name":"status_code_class","in":"query","description":"Filter by status code class (e.g. \"2xx\", \"3xx\", \"4xx\", \"5xx\")","required":false,"schema":{"type":["string","null"]}},{"name":"routing_status","in":"query","description":"Filter by routing status","required":false,"schema":{"type":["string","null"]}},{"name":"request_source","in":"query","description":"Filter by request source","required":false,"schema":{"type":["string","null"]}},{"name":"is_bot","in":"query","description":"Filter by bot detection","required":false,"schema":{"type":["boolean","null"]}},{"name":"device_type","in":"query","description":"Filter by device type","required":false,"schema":{"type":["string","null"]}}],"responses":{"200":{"description":"Today's request count","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TodayStatsResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/proxy-logs/{id}":{"get":{"tags":["Proxy Logs"],"summary":"Get a single proxy log by ID","operationId":"get_proxy_log_by_id","parameters":[{"name":"id","in":"path","description":"Proxy log ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"timestamp","in":"query","description":"Event time of the log row (ISO 8601). When provided, the lookup is\nbounded to the hypertable chunks around this instant instead of\nscanning (and decompressing) the whole retention window. The list\nendpoint already returns this value per row — always pass it when\nnavigating from a list.","required":false,"schema":{"type":["string","null"],"format":"date-time"}}],"responses":{"200":{"description":"Proxy log found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProxyLogResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Proxy log not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/repositories":{"get":{"tags":["Git Providers"],"summary":"List synced repositories with advanced filtering","description":"Lists repositories that have been synced to the database with filtering options.\nThis provides fast access to repository metadata with filtering by connection, search, and other criteria.","operationId":"list_synced_repositories","parameters":[{"name":"page","in":"query","description":"Page number for pagination","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Number of items per page (max 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"sort","in":"query","description":"Sort field (name, created_at, updated_at, stars, watchers, size, issues)","required":false,"schema":{"type":"string"}},{"name":"direction","in":"query","description":"Sort direction (asc, desc)","required":false,"schema":{"type":"string"}},{"name":"search","in":"query","description":"Search term to filter repositories","required":false,"schema":{"type":"string"}},{"name":"owner","in":"query","description":"Filter by repository owner","required":false,"schema":{"type":"string"}},{"name":"language","in":"query","description":"Filter by programming language","required":false,"schema":{"type":"string"}},{"name":"private","in":"query","description":"Filter by private status (true/false)","required":false,"schema":{"type":"boolean"}},{"name":"git_provider_connection_id","in":"query","description":"Filter by git provider connection ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"List of synced repositories","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositoryListResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repositories/{owner}/{name}":{"get":{"tags":["Git Providers"],"summary":"Get repository by owner and name from any connection","operationId":"get_repository_by_name","parameters":[{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}},{"name":"connection_id","in":"query","description":"Optional specific connection ID to search","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Repository found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositoryResponse"}}}},"404":{"description":"Repository not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repositories/{owner}/{name}/all":{"get":{"tags":["Git Providers"],"summary":"Get all repositories with same owner/name from all git providers","operationId":"get_all_repositories_by_name","parameters":[{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Repositories found from all providers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RepositoryResponse"}}}}},"404":{"description":"No repositories found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repositories/{owner}/{name}/preset":{"get":{"tags":["Git Providers"],"summary":"Get repository preset by owner and name","operationId":"get_repository_preset_by_name","parameters":[{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}},{"name":"branch","in":"query","description":"Git branch to check (defaults to repository's default branch)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Repository preset calculated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositoryPresetResponse"}}}},"404":{"description":"Repository not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repositories/{owner}/{repo}/branches":{"get":{"tags":["Repositories"],"summary":"Get repository branches","operationId":"get_repository_branches","parameters":[{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"repo","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}},{"name":"connection_id","in":"query","description":"Git provider connection ID (required when multiple connections have the same repo)","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"fresh","in":"query","description":"Force fetch fresh data, bypassing cache (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of branches","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BranchListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Repository not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repositories/{owner}/{repo}/tags":{"get":{"tags":["Repositories"],"summary":"Get repository tags","operationId":"get_repository_tags","parameters":[{"name":"owner","in":"path","description":"Repository owner","required":true,"schema":{"type":"string"}},{"name":"repo","in":"path","description":"Repository name","required":true,"schema":{"type":"string"}},{"name":"connection_id","in":"query","description":"Git provider connection ID (required when multiple connections have the same repo)","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"fresh","in":"query","description":"Force fetch fresh data, bypassing cache (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of tags","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TagListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Repository not found"},"429":{"description":"Fresh tag lookup rate limit exceeded"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repositories/{repository_id}/preset/live":{"get":{"tags":["Git Providers"],"operationId":"get_repository_preset_live","parameters":[{"name":"repository_id","in":"path","description":"Repository ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"branch","in":"query","description":"Git branch to check (defaults to repository's default branch)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Repository presets calculated successfully - includes root preset and projects in subdirectories","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositoryPresetResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"The git provider rejected the stored credential - the connection must be re-authorized"},"404":{"description":"Repository not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repository/{repository_id}":{"get":{"tags":["Git Providers"],"summary":"Get repository by ID","operationId":"get_repository_by_id","parameters":[{"name":"repository_id","in":"path","description":"Repository ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Repository found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepositoryResponse"}}}},"404":{"description":"Repository not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repository/{repository_id}/branches":{"get":{"tags":["Repositories"],"summary":"Get repository branches by repository ID","operationId":"get_branches_by_repository_id","parameters":[{"name":"repository_id","in":"path","description":"Repository ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"fresh","in":"query","description":"Force fetch fresh data, bypassing cache (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of branches","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BranchListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Repository not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repository/{repository_id}/commits":{"get":{"tags":["Repositories"],"summary":"List recent commits for a repository branch","operationId":"list_commits_by_repository_id","parameters":[{"name":"repository_id","in":"path","description":"Repository ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"branch","in":"query","description":"Branch name to list commits for","required":true,"schema":{"type":"string"}},{"name":"per_page","in":"query","description":"Number of commits to return (default: 20, max: 100)","required":false,"schema":{"type":["integer","null"],"format":"int32","minimum":0}}],"responses":{"200":{"description":"List of commits","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommitListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Repository not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/repository/{repository_id}/commits/{commit_sha}":{"get":{"tags":["Repositories"],"summary":"Check if a commit exists in a repository","operationId":"check_commit_exists","parameters":[{"name":"repository_id","in":"path","description":"Repository ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"commit_sha","in":"path","description":"Commit SHA to check","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Commit existence check result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommitExistsResponse"}}}},"400":{"description":"Invalid commit SHA"},"401":{"description":"Unauthorized"},"404":{"description":"Repository not found"},"429":{"description":"Commit lookup rate limit exceeded"},"500":{"description":"Internal server error"},"502":{"description":"Git provider request failed"}},"security":[{"bearer_auth":[]}]}},"/repository/{repository_id}/tags":{"get":{"tags":["Repositories"],"summary":"Get repository tags by repository ID","operationId":"get_tags_by_repository_id","parameters":[{"name":"repository_id","in":"path","description":"Repository ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"fresh","in":"query","description":"Force fetch fresh data, bypassing cache (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of tags","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TagListResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Repository not found"},"429":{"description":"Fresh tag lookup rate limit exceeded"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/restore-runs/{id}":{"get":{"tags":["Restore"],"operationId":"get_restore_run","parameters":[{"name":"id","in":"path","description":"Restore run id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Restore run progress","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RestoreRunView"}}}},"404":{"description":"Restore run not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/revenue/events":{"get":{"tags":["Revenue"],"summary":"Org-wide revenue events across every project. Powers the revenue\ntransactions page. Supports filtering by project, date range, and\nevent type.","operationId":"revenue_global_events","parameters":[{"name":"project_id","in":"query","description":"Filter to a single project","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"from","in":"query","description":"Lower bound (inclusive), ISO-8601","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","description":"Upper bound (inclusive), ISO-8601","required":false,"schema":{"type":"string"}},{"name":"event_types","in":"query","description":"Comma-separated event types (e.g. `invoice.paid,charge.succeeded`)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max rows, default 100, max 500","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GlobalRecentEventResponse"}}}}}},"security":[{"bearer_auth":[]}]}},"/revenue/metrics/global-mrr":{"get":{"tags":["Revenue"],"summary":"Org-wide MRR total, summed across every project in the install.\nPowers the single-number MRR card on the main dashboard.","operationId":"revenue_metrics_global_mrr","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GlobalMrrResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/revenue/metrics/global-summary":{"get":{"tags":["Revenue"],"summary":"Org-wide revenue summary: MRR, paid cash (30d + all-time), refunds,\nactive subscriptions/customers, and transaction count. Powers the\nheader on the Revenue transactions page.","operationId":"revenue_metrics_global_summary","parameters":[{"name":"currency","in":"query","description":"ISO-4217 currency code, default USD","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GlobalRevenueSummaryResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/revenue/providers":{"get":{"tags":["Revenue"],"summary":"List registered providers (what the UI needs to render the \"Connect\"\ndropdown + its wizard instructions).","operationId":"revenue_list_providers","responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProviderDescriptor"}}}}}},"security":[{"bearer_auth":[]}]}},"/session-replays":{"get":{"tags":["Analytics"],"summary":"Get session replays for a project","operationId":"get_project_session_replays","parameters":[{"name":"project_id","in":"query","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"environment_id","in":"query","description":"Environment ID (optional)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-based)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Items per page","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Session replays retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetProjectSessionReplaysResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/sessions/{session_id}/events":{"get":{"tags":["Events"],"summary":"Get events for a specific session","operationId":"get_session_events","parameters":[{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"string"}},{"name":"environment_id","in":"query","description":"Filter by environment ID","required":false,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Successfully retrieved session events","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalyticsSessionEventsResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Session not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings":{"get":{"tags":["Settings"],"summary":"Get application settings","operationId":"get_settings","responses":{"200":{"description":"Application settings with masked sensitive fields","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppSettingsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Settings"],"summary":"Update application settings","operationId":"update_settings","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppSettings"}}},"required":true},"responses":{"200":{"description":"Settings updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SettingsUpdateResponse"}}}},"400":{"description":"Bad request - invalid settings"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/agent-token":{"post":{"tags":["Agents"],"summary":"Save an encrypted AI provider token for use in sandbox containers.","operationId":"save_agent_token","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveAgentTokenRequest"}}},"required":true},"responses":{"200":{"description":"Token encrypted and persisted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveAgentTokenResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Encryption or database error"}},"security":[{"bearer_auth":[]}]}},"/settings/ai-providers":{"get":{"tags":["Agents"],"summary":"List the AI provider catalog. Includes per-provider \"is a credential\nconfigured?\" so the settings UI can render configured/not-configured\nbadges without leaking the encrypted credential.","operationId":"list_ai_providers","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderCatalogResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/settings/ai-providers/{provider_id}":{"patch":{"tags":["Agents"],"summary":"Update provider-scoped settings without touching the saved credential.\nToday that means just `default_model`; future per-provider settings\n(base URL overrides, request headers, etc.) can land here too without\nchanging the shape of `save_credential`.","operationId":"update_ai_provider","parameters":[{"name":"provider_id","in":"path","description":"AI provider ID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAiProviderRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAiProviderResponse"}}}},"400":{"description":"Unknown provider"},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/settings/ai-providers/{provider_id}/activate":{"post":{"tags":["Agents"],"summary":"Activate a provider as the platform-wide default. Refuses to activate a\nprovider that doesn't have a credential saved yet — the UI enforces the\nsame rule on the button, but we re-check server-side so a stale tab\ncan't bypass it.","operationId":"activate_ai_provider","parameters":[{"name":"provider_id","in":"path","description":"AI provider ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivateProviderResponse"}}}},"400":{"description":"Provider not configured"},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/settings/ai-providers/{provider_id}/credential":{"post":{"tags":["Agents"],"summary":"Save (or replace) a provider's credential. The credential is encrypted\nwith `EncryptionService` and stored inside\n`agent_sandbox.providers[provider_id].credentials_encrypted`.","description":"The plaintext shape depends on the flavor's `credential_format`:\n - `ApiKey` / `OauthToken`: the key/token string.\n - `ConfigFile`: the full file body (e.g. OpenCode's `auth.json`).","operationId":"save_ai_provider_credential","parameters":[{"name":"provider_id","in":"path","description":"AI provider ID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveCredentialRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveCredentialResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/settings/disk-status":{"get":{"tags":["Settings"],"summary":"Get current disk usage for the control-plane server","description":"Returns live disk usage for the monitored path along with any disks that\nmeet or exceed the configured alert threshold. Read-only — does not send\nnotifications. Used by the dashboard to surface a low-disk-space warning.","operationId":"get_disk_status","responses":{"200":{"description":"Current disk usage and threshold alerts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiskSpaceCheckResult"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/enrollment-tokens":{"get":{"tags":["Settings"],"summary":"List currently-valid node enrollment tokens (hashes elided).","operationId":"list_enrollment_tokens","responses":{"200":{"description":"Active enrollment tokens","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnrollmentTokenListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Settings"],"summary":"Mint a short-lived, single-use node enrollment token.","operationId":"mint_enrollment_token","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MintEnrollmentTokenRequest"}}},"required":true},"responses":{"200":{"description":"Enrollment token minted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MintEnrollmentTokenResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/enrollment-tokens/{id}":{"delete":{"tags":["Settings"],"summary":"Revoke a node enrollment token by id.","operationId":"revoke_enrollment_token","parameters":[{"name":"id","in":"path","description":"Enrollment token id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Enrollment token revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SettingsUpdateResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Enrollment token not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/join-token":{"delete":{"tags":["Settings"],"summary":"Revoke the current join token","description":"Removes the stored join token hash, allowing any node to register\n(if no other authentication is in place).","operationId":"revoke_join_token","responses":{"200":{"description":"Join token revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SettingsUpdateResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/join-token/generate":{"post":{"tags":["Settings"],"summary":"Generate a new join token for multi-node cluster registration","description":"Creates a random 32-byte hex token, stores the SHA-256 hash in settings,\nand returns the plaintext exactly once. If a token already exists, it is replaced.","operationId":"generate_join_token","responses":{"200":{"description":"Join token generated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateJoinTokenResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/join-token/status":{"get":{"tags":["Settings"],"summary":"Check whether a join token is currently configured","operationId":"get_join_token_status","responses":{"200":{"description":"Join token status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JoinTokenStatusResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/mcp-servers":{"get":{"tags":["Agents"],"operationId":"list_global_mcps","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListMcpsResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Agents"],"operationId":"create_global_mcp","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMcpRequest"}}},"required":true},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpDefinitionResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/settings/mcp-servers/{slug}":{"get":{"tags":["Agents"],"operationId":"get_global_mcp","parameters":[{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"MCP server not found"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Agents"],"operationId":"update_global_mcp","parameters":[{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMcpRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"MCP server not found"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Agents"],"operationId":"delete_global_mcp","parameters":[{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"MCP server deleted"},"401":{"description":"Unauthorized"},"404":{"description":"MCP server not found"}},"security":[{"bearer_auth":[]}]}},"/settings/mcp-servers/{slug}/config/{field}":{"get":{"tags":["Agents"],"operationId":"reveal_global_mcp_config","parameters":[{"name":"slug","in":"path","description":"MCP server slug","required":true,"schema":{"type":"string"}},{"name":"field","in":"path","description":"Sensitive field path, such as url or env.API_TOKEN","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SensitiveMcpConfigValueResponse"}}}},"400":{"description":"Field is not revealable"},"401":{"description":"Unauthorized"},"403":{"description":"Missing secrets:read permission"},"404":{"description":"MCP server or field not found"},"500":{"description":"Configuration read or audit failed"}},"security":[{"bearer_auth":[]}]}},"/settings/routes/refresh":{"post":{"tags":["Settings"],"summary":"Manually refresh the proxy route table","description":"Reloads all routes from the database into the in-memory proxy cache.\nUseful as a workaround when routes are out of sync.","operationId":"refresh_route_table","responses":{"200":{"description":"Route table refreshed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteRefreshResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/settings/sandbox-rebuild":{"post":{"tags":["Agents"],"operationId":"rebuild_sandbox_image","responses":{"200":{"description":"Server-Sent Events stream of rebuild progress; final event `{\"type\":\"done\",\"success\":bool,...}`","content":{"text/event-stream":{}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/settings/sandbox-status":{"get":{"tags":["Agents"],"operationId":"get_global_sandbox_status","responses":{"200":{"description":"Global sandbox readiness for the settings page","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxStatusResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/settings/secrets":{"get":{"tags":["Secrets"],"operationId":"list_secrets","responses":{"200":{"description":"List of global agent secrets","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListSecretsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Secrets"],"operationId":"upsert_secret","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertSecretRequest"}}},"required":true},"responses":{"201":{"description":"Secret created/updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SecretResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/settings/secrets/{name}":{"delete":{"tags":["Secrets"],"operationId":"delete_secret","parameters":[{"name":"name","in":"path","description":"Secret name","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Secret deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Secret not found"}},"security":[{"bearer_auth":[]}]}},"/settings/skills":{"get":{"tags":["Agents"],"operationId":"list_global_skills","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListSkillsResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Agents"],"operationId":"create_global_skill","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSkillRequest"}}},"required":true},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/settings/skills/upload":{"post":{"tags":["Agents"],"summary":"Upload a skill with an archive (tar.gz) — global.","operationId":"upload_global_skill","requestBody":{"content":{"multipart/form-data":{"schema":{"type":"string"}}},"required":true},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/settings/skills/{slug}":{"get":{"tags":["Agents"],"operationId":"get_global_skill","parameters":[{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found"}},"security":[{"bearer_auth":[]}]},"put":{"tags":["Agents"],"operationId":"update_global_skill","parameters":[{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSkillRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillDefinitionResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Agents"],"operationId":"delete_global_skill","parameters":[{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Skill deleted"},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found"}},"security":[{"bearer_auth":[]}]}},"/settings/skills/{slug}/archive":{"get":{"tags":["Agents"],"summary":"Download a skill's archive (tar.gz) — global.","operationId":"download_global_skill_archive","parameters":[{"name":"slug","in":"path","description":"Skill slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Skill archive tar.gz","content":{"application/gzip":{}}},"401":{"description":"Unauthorized"},"404":{"description":"Skill not found or has no archive"}},"security":[{"bearer_auth":[]}]}},"/settings/update":{"get":{"tags":["Settings"],"summary":"Report whether a release update can be applied from the console.","operationId":"get_update_capability","responses":{"200":{"description":"Self-update capability for this install","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCapabilityResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Settings"],"summary":"Install a release and restart the server.","description":"Returns as soon as the attempt is accepted: the download and swap run in the\nbackground and the process then exits so its supervisor restarts it on the\nnew binary. Poll `GET /settings/update` for progress — after the restart,\n`last_attempt` carries the outcome.","operationId":"start_update","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartUpdateRequest"}}},"required":true},"responses":{"202":{"description":"Update accepted; the server will restart","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartUpdateResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"409":{"description":"Update unavailable or already running","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"501":{"description":"This process cannot apply updates","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/settings/update-status":{"get":{"tags":["Settings"],"summary":"Report whether a newer temps release is available for this install.","operationId":"get_update_status","responses":{"200":{"description":"Release update status for this install","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateStatusResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/settings/update/check":{"post":{"tags":["Settings"],"summary":"Ask the release API for the newest version on this install's channel, now,\ninstead of waiting for the background notifier's next pass.","operationId":"check_for_update","responses":{"200":{"description":"Result of the release check","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReleaseCheckResult"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"501":{"description":"This process cannot check for updates","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"502":{"description":"The release API could not be reached","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/teams":{"get":{"tags":["Teams"],"operationId":"list_teams","parameters":[{"name":"page","in":"query","description":"1-indexed page","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"default 20, max 100","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Paginated teams","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamListResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Teams"],"operationId":"create_team","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTeamRequest"}}},"required":true},"responses":{"201":{"description":"Team created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamResponse"}}}},"400":{"description":"Validation error"},"403":{"description":"Insufficient permissions"},"409":{"description":"Slug already taken"}},"security":[{"bearer_auth":[]}]}},"/teams/{team_id}":{"get":{"tags":["Teams"],"operationId":"get_team","parameters":[{"name":"team_id","in":"path","description":"Team id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Team","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamResponse"}}}},"403":{"description":"Insufficient permissions"},"404":{"description":"Team not found"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Teams"],"operationId":"delete_team","parameters":[{"name":"team_id","in":"path","description":"Team id","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Team deleted"},"403":{"description":"Insufficient permissions"},"404":{"description":"Team not found"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Teams"],"operationId":"update_team","parameters":[{"name":"team_id","in":"path","description":"Team id","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTeamRequest"}}},"required":true},"responses":{"200":{"description":"Updated team","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamResponse"}}}},"400":{"description":"Validation error"},"403":{"description":"Insufficient permissions"},"404":{"description":"Team not found"}},"security":[{"bearer_auth":[]}]}},"/teams/{team_id}/members":{"get":{"tags":["Teams"],"operationId":"list_team_members","parameters":[{"name":"team_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Members","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TeamMemberResponse"}}}}},"403":{"description":"Insufficient permissions"},"404":{"description":"Team not found"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Teams"],"operationId":"add_team_member","parameters":[{"name":"team_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTeamMemberRequest"}}},"required":true},"responses":{"201":{"description":"Member added","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamMemberResponse"}}}},"403":{"description":"Insufficient permissions"},"404":{"description":"Team not found"},"409":{"description":"User already a member"}},"security":[{"bearer_auth":[]}]}},"/teams/{team_id}/members/{user_id}":{"delete":{"tags":["Teams"],"operationId":"remove_team_member","parameters":[{"name":"team_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"user_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Member removed"},"403":{"description":"Insufficient permissions"},"404":{"description":"Member not found"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Teams"],"operationId":"update_team_member_role","parameters":[{"name":"team_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"user_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMemberRoleRequest"}}},"required":true},"responses":{"200":{"description":"Updated membership","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamMemberResponse"}}}},"403":{"description":"Insufficient permissions"},"404":{"description":"Member not found"}},"security":[{"bearer_auth":[]}]}},"/teams/{team_id}/projects":{"get":{"tags":["Teams"],"operationId":"list_team_projects","parameters":[{"name":"team_id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Projects this team has access to","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProjectAccessResponse"}}}}},"403":{"description":"Insufficient permissions"},"404":{"description":"Team not found"}},"security":[{"bearer_auth":[]}]}},"/templates":{"get":{"tags":["Templates"],"summary":"List all available templates","description":"Returns a list of all public templates, optionally filtered by tag or featured status.","operationId":"list_project_templates","parameters":[{"name":"tag","in":"query","description":"Filter templates by tag","required":false,"schema":{"type":"string"}},{"name":"featured","in":"query","description":"Only return featured templates","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of templates","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListTemplatesResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/templates/tags":{"get":{"tags":["Templates"],"summary":"List all available template tags","description":"Returns a list of all unique tags used by public templates.","operationId":"list_project_template_tags","responses":{"200":{"description":"List of tags","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListTagsResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/templates/{slug}":{"get":{"tags":["Templates"],"summary":"Get a specific template by slug","description":"Returns detailed information about a single template.","operationId":"get_project_template","parameters":[{"name":"slug","in":"path","description":"Template slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Template details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TemplateResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"Template not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/user/me":{"get":{"tags":["Authentication"],"operationId":"get_current_user","responses":{"200":{"description":"Successfully retrieved user information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserResponse"}}}},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"session_token":[]}]}},"/users":{"get":{"tags":["Users"],"operationId":"list_users","parameters":[{"name":"include_deleted","in":"query","description":"Include deleted users in the response","required":true,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List all users with their roles","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RouteUserWithRoles"}}}}},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Users"],"summary":"Create a new user with roles","operationId":"create_user","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUserRequest"}}},"required":true},"responses":{"201":{"description":"User created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteUserWithRoles"}}}},"400":{"description":"Invalid input"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/me":{"patch":{"tags":["Users"],"summary":"Update current user's information","operationId":"update_self","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSelfRequest"}}},"required":true},"responses":{"200":{"description":"User updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteUserWithRoles"}}}},"400":{"description":"Invalid input"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/me/mfa":{"delete":{"tags":["Users"],"operationId":"disable_mfa","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DisableMfaRequest"}}},"required":true},"responses":{"204":{"description":"MFA disabled"},"400":{"description":"Invalid verification code"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/me/mfa/setup":{"post":{"tags":["Users"],"operationId":"setup_mfa","responses":{"200":{"description":"MFA setup data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MfaSetupResponse"}}}},"401":{"description":"Unauthorized"},"409":{"description":"MFA is already enabled; verify and disable it before re-enrollment"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/me/mfa/verify":{"post":{"tags":["Users"],"operationId":"verify_and_enable_mfa","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyMfaRequest"}}},"required":true},"responses":{"204":{"description":"MFA verified and enabled"},"400":{"description":"Invalid code"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/me/password":{"post":{"tags":["Users"],"operationId":"change_password_self","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangePasswordRequest"}}},"required":true},"responses":{"204":{"description":"Password updated"},"400":{"description":"Validation error (weak password, same as current, MFA missing)"},"401":{"description":"Current password incorrect or MFA code invalid"},"403":{"description":"Account has no password set (SSO only)"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/{user_id}":{"delete":{"tags":["Users"],"summary":"Delete a user","operationId":"delete_user","parameters":[{"name":"user_id","in":"path","description":"User ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"User deleted successfully"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden - Cannot delete yourself or non-admin attempt"},"404":{"description":"User not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["Users"],"summary":"Update user information (admin only)","operationId":"update_user","parameters":[{"name":"user_id","in":"path","description":"User ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUserRequest"}}},"required":true},"responses":{"200":{"description":"User updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteUserWithRoles"}}}},"400":{"description":"Invalid input"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden - Non-admin attempt"},"404":{"description":"User not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/{user_id}/restore":{"post":{"tags":["Users"],"operationId":"restore_user","parameters":[{"name":"user_id","in":"path","description":"User ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"User restored successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouteUserWithRoles"}}}},"400":{"description":"User is not deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden - Non-admin attempt"},"404":{"description":"User not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/{user_id}/roles":{"post":{"tags":["Users"],"operationId":"assign_role","parameters":[{"name":"user_id","in":"path","description":"User ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssignRoleRequest"}}},"required":true},"responses":{"200":{"description":"Role assigned successfully"},"400":{"description":"Invalid role type"},"401":{"description":"Unauthorized"},"403":{"description":"Admin role required or self-modification forbidden"},"404":{"description":"User or role not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/users/{user_id}/roles/{role_type}":{"delete":{"tags":["Users"],"operationId":"remove_role","parameters":[{"name":"user_id","in":"path","description":"User ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"role_type","in":"path","description":"Role type to remove","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Role removed successfully"},"400":{"description":"Invalid role type"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden - Cannot modify own roles or non-admin attempt"},"404":{"description":"User or role not found"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes":{"get":{"tags":["Sandboxes"],"operationId":"list_sandboxes","parameters":[{"name":"page","in":"query","description":"Page (1-indexed)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Items per page (default 20, max 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"List sandboxes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListSandboxesResponse"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Sandboxes"],"operationId":"create_sandbox","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSandboxBody"}}},"required":true},"responses":{"201":{"description":"Sandbox created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"500":{"description":"Internal server error"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/rootfs":{"get":{"tags":["Sandboxes"],"summary":"Inspect rootfs storage: the Firecracker digest-keyed cache (with which\nsandboxes reference each entry) and per-VM disks. Empty on Docker-only\nhosts. Admin/read scope — this exposes host storage layout.","operationId":"rootfs_report","responses":{"200":{"description":"Rootfs storage report"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/rootfs/gc":{"post":{"tags":["Sandboxes"],"summary":"Reclaim rootfs cache entries not backing any live sandbox. Idempotent;\nsafe to call any time (live VMs hold their own per-VM disks).","operationId":"rootfs_gc","responses":{"200":{"description":"Reclaimed cache entries"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}":{"get":{"tags":["Sandboxes"],"operationId":"get_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sandbox details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"404":{"description":"Not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/cmd":{"post":{"tags":["Sandboxes"],"summary":"Run a command inside the sandbox (`@vercel/sandbox`-compatible).","description":"`wait=false` (default) returns `{ command: {..., exitCode: null} }`\nimmediately once the background task is spawned.\n\n`wait=true` streams `application/x-ndjson`: the first line is the\nrunning envelope, the second is the finished envelope with `exitCode`.","operationId":"cmd","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CmdBody"}}},"required":true},"responses":{"200":{"description":"Command started (wait=false) or finished (wait=true)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CmdResponse"}}}},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/cmd/{cmd_id}":{"get":{"tags":["Sandboxes"],"operationId":"get_cmd","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"cmd_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Command snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CmdResponse"}}}},"404":{"description":"Sandbox or command not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/cmd/{cmd_id}/logs":{"get":{"tags":["Sandboxes"],"summary":"Stream a command's stdout/stderr as `application/x-ndjson`\n(`@vercel/sandbox`-compatible). Each line is either\n`{stream:\"stdout\"|\"stderr\", data:\"...\"}` or\n`{stream:\"error\", data:{code, message}}`.","operationId":"cmd_logs","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"cmd_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"NDJSON stream of log events"},"404":{"description":"Sandbox or command not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/destroy":{"post":{"tags":["Sandboxes"],"operationId":"destroy_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Sandbox destroyed (alias for `/stop` with an explicit verb)"},"404":{"description":"Not found"},"409":{"description":"Sandbox belongs to an active agent run — stop the run instead"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/domain":{"get":{"tags":["Sandboxes"],"operationId":"domain","parameters":[{"name":"port","in":"query","description":"Port inside the sandbox (1..=65535)","required":true,"schema":{"type":"integer","format":"int32","minimum":0}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Preview URL for the port","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxDomainResponse"}}}},"400":{"description":"Invalid port"},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/events":{"get":{"tags":["Sandboxes"],"summary":"The operations timeline for a sandbox (lifecycle events only — never\nshell/exec activity), newest first.","operationId":"list_events","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Operations timeline","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxEventsResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/exec":{"post":{"tags":["Sandboxes"],"operationId":"exec","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecBody"}}},"required":true},"responses":{"200":{"description":"Command finished (non-zero exit is NOT an error)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecResponse"}}}},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/exec-detached":{"post":{"tags":["Sandboxes"],"operationId":"exec_detached","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecBody"}}},"required":true},"responses":{"202":{"description":"Command accepted; poll /jobs/{job_id}","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecDetachedResponse"}}}},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/extend-timeout":{"post":{"tags":["Sandboxes"],"operationId":"extend_timeout","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExtendTimeoutBody"}}},"required":true},"responses":{"200":{"description":"Timeout extended","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"400":{"description":"Validation error"},"404":{"description":"Not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/fs/mkdir":{"post":{"tags":["Sandboxes"],"operationId":"mkdir","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MkdirBody"}}},"required":true},"responses":{"204":{"description":"Directory created (or already existed)"},"400":{"description":"Validation error"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/fs/read":{"get":{"tags":["Sandboxes"],"operationId":"read_file","parameters":[{"name":"path","in":"query","description":"Absolute file path inside the sandbox","required":true,"schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"File contents (base64)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReadFileResponse"}}}},"400":{"description":"Validation error"},"404":{"description":"Sandbox or file not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/fs/stat":{"get":{"tags":["Sandboxes"],"operationId":"stat_path","parameters":[{"name":"path","in":"query","description":"Absolute path inside the sandbox","required":true,"schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Stat info (exists=false when missing — not an error)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatResponse"}}}},"400":{"description":"Validation error"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/fs/write":{"post":{"tags":["Sandboxes"],"summary":"Write a file into the sandbox. Accepts two body shapes — the SDK\npicks one based on `Content-Type`:","description":"- **`application/json`** (temps-native): `{path, contents_b64, mode}`\n — one file, base64-encoded.\n- **`application/gzip`** (`@vercel/sandbox`): a gzipped tarball of\n one-or-more entries, with the target extract dir carried in the\n `x-cwd` header. The SDK's `writeFile` and `writeFiles` both post\n here; they differ only in how many entries the tarball contains.\n\nWhy merge them on one route: the SDK is hardcoded to\n`POST /fs/write`, so splitting tar uploads onto a separate path would\nforce us to break SDK compat. Instead we dispatch on Content-Type,\npreserve JSON for native callers, and add tar for SDK callers.","operationId":"write_file","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WriteFileBody"}}},"required":true},"responses":{"204":{"description":"File(s) written"},"400":{"description":"Validation error or invalid base64"},"404":{"description":"Sandbox not found"},"415":{"description":"Unsupported Content-Type (expected application/json or application/gzip)"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/fs/write-batch":{"post":{"tags":["Sandboxes"],"summary":"Batch-write multiple files in a single request. Mirrors\n`@vercel/sandbox` `writeFiles()`. Semantics are fail-fast: if any\nfile errors, previously-written entries are left in place and the\nerror describes which file broke.","operationId":"write_files","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WriteFilesBody"}}},"required":true},"responses":{"200":{"description":"All files written","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WriteFilesResponse"}}}},"400":{"description":"Validation error or invalid base64"},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/jobs":{"get":{"tags":["Sandboxes"],"operationId":"list_jobs","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Detached jobs for this sandbox","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListJobsResponse"}}}},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/jobs/{job_id}":{"get":{"tags":["Sandboxes"],"operationId":"job_status","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"job_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Job status snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobStatusResponse"}}}},"404":{"description":"Sandbox or job not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/jobs/{job_id}/kill":{"post":{"tags":["Sandboxes"],"summary":"Terminate a detached job. Aborts the server-side tracking task and\nsends SIGTERM (or SIGKILL if `force=true`) to any matching processes\ninside the sandbox container. Returns 204 on success; 404 if the\nsandbox or job is unknown.","operationId":"kill_job","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"job_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KillJobBody"}}},"required":true},"responses":{"204":{"description":"Job killed"},"404":{"description":"Sandbox or job not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/jobs/{job_id}/logs":{"get":{"tags":["Sandboxes"],"summary":"SSE endpoint streaming each stdout/stderr line from a detached job\nas it's produced. Mirrors the `Command.logs()` async iterator shape\non `@vercel/sandbox` — events carry `{ stream, data }`.","description":"Late subscribers only see events produced after they connect. The\nJobState snapshot (`GET /jobs/{job_id}`) covers the history.\n\nA \"done\" sentinel event fires when the broadcast channel closes\n(the exec task has exited and dropped the sender), signalling\ncallers they can stop reading.","operationId":"job_logs","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"job_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"SSE stream of log events"},"404":{"description":"Sandbox or job not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/pause":{"post":{"tags":["Sandboxes"],"operationId":"pause_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sandbox paused (container stopped, state preserved)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"404":{"description":"Not found"},"409":{"description":"Sandbox is in an incompatible state (e.g. already destroyed)"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/preview-link":{"post":{"tags":["Sandboxes"],"summary":"Mint a shareable link to a sandbox preview.","description":"`GET /domain` returns the bare preview URL, which is useless to anyone who\ndoes not already hold the sandbox's preview password — so sharing a\nprotected preview meant sharing that password, which is the same secret for\nevery recipient and can only be withdrawn by rotating it for all of them.\n\nThis returns the same URL carrying a short-lived, sandbox-scoped grant. The\nrecipient's browser exchanges it for the ordinary preview cookie and lands\non `path`. The grant never reaches the sandbox, so preview application code\ncannot read it and re-share it.\n\nAnyone holding the returned URL can view the preview until it expires;\nthere is no per-link revocation short of rotating the preview password.","operationId":"sandbox_create_preview_link","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreviewShareLinkBody"}}},"required":true},"responses":{"200":{"description":"Shareable preview link","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreviewShareLinkResponse"}}}},"400":{"description":"Invalid port"},"404":{"description":"Sandbox not found"},"409":{"description":"Sandbox has no preview password"},"500":{"description":"Preview grant minting failed"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/preview-password":{"put":{"tags":["Sandboxes"],"operationId":"set_preview_password","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetPreviewPasswordBody"}}},"required":true},"responses":{"200":{"description":"Preview password set or rotated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetPreviewPasswordResponse"}}}},"400":{"description":"Password too short or too long"},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Sandboxes"],"operationId":"clear_preview_password","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Preview password removed (sandbox is now URL-only protected)"},"404":{"description":"Sandbox not found"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/resize":{"post":{"tags":["Sandboxes"],"summary":"Grow a Firecracker sandbox's root disk. Offline resize — the VM reboots\n(filesystem/data persist) rather than resizing fully live.","operationId":"resize_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResizeSandboxBody"}}},"required":true},"responses":{"200":{"description":"Resized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"400":{"description":"Invalid size or unsupported backend"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/restart":{"post":{"tags":["Sandboxes"],"operationId":"restart_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sandbox container restarted in place","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"404":{"description":"Not found"},"409":{"description":"Sandbox is stopped (use /resume) or already destroyed"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/resume":{"post":{"tags":["Sandboxes"],"operationId":"resume_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sandbox resumed; expires_at refreshed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"404":{"description":"Not found"},"409":{"description":"Sandbox is not in a resumable state"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/source":{"post":{"tags":["Sandboxes"],"operationId":"source_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceBody"}}},"required":true},"responses":{"200":{"description":"Source content seeded into the sandbox work dir","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SandboxResponse"}}}},"400":{"description":"Validation error (embedded creds, conflicting fields, etc.)"},"404":{"description":"Sandbox not found"},"409":{"description":"Sandbox is not running"},"500":{"description":"Source seed failed inside sandbox"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/stop":{"post":{"tags":["Sandboxes"],"operationId":"stop_sandbox","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Sandbox stopped and destroyed"},"404":{"description":"Not found"},"409":{"description":"Sandbox belongs to an active agent run — stop the run instead"}},"security":[{"bearer_auth":[]}]}},"/v1/sandboxes/{id}/{cmd_id}/kill":{"post":{"tags":["Sandboxes"],"summary":"Kill a running command (`@vercel/sandbox`-compatible). The SDK\ncalls `POST /v1/sandboxes/{id}/{cmdId}/kill` — note the path has the\ncommand ID directly under the sandbox, NOT under `/jobs/` or `/cmd/`.","operationId":"cmd_kill","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"cmd_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CmdKillBody"}}}},"responses":{"200":{"description":"Command killed; returns final snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CmdResponse"}}}},"404":{"description":"Sandbox or command not found"}},"security":[{"bearer_auth":[]}]}},"/visitors/{visitor_id}/session-replays":{"get":{"tags":["Analytics"],"summary":"Get session replays for a visitor","operationId":"get_visitor_sessions","parameters":[{"name":"visitor_id","in":"path","description":"Visitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (1-based)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"per_page","in":"query","description":"Items per page","required":false,"schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"Session replays retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetVisitorSessionsResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/visitors/{visitor_id}/session-replays/{session_id}":{"get":{"tags":["Analytics"],"summary":"Get session replay data with visitor info (without events)","operationId":"get_session_replay","parameters":[{"name":"visitor_id","in":"path","description":"Visitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Session replay retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetSessionReplayResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Session not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Analytics"],"summary":"Delete a session replay","operationId":"delete_session_replay","parameters":[{"name":"visitor_id","in":"path","description":"Visitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Session replay deleted successfully"},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Session not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/visitors/{visitor_id}/session-replays/{session_id}/duration":{"put":{"tags":["Analytics"],"summary":"Update session duration","operationId":"update_session_duration","parameters":[{"name":"visitor_id","in":"path","description":"Visitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSessionDurationRequest"}}},"required":true},"responses":{"200":{"description":"Session duration updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSessionDurationResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Session not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/visitors/{visitor_id}/session-replays/{session_id}/events":{"get":{"tags":["Analytics"],"summary":"Get session replay events (with session and visitor metadata)","operationId":"get_session_replay_events","parameters":[{"name":"visitor_id","in":"path","description":"Visitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Session replay with events retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionReplayWithEventsDto"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Session not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["Analytics"],"summary":"Add events to an existing session","operationId":"add_events","parameters":[{"name":"visitor_id","in":"path","description":"Visitor ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"session_id","in":"path","description":"Session ID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddEventsRequest"}}},"required":true},"responses":{"200":{"description":"Events added successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddEventsResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Session not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/vulnerability-scans/{scan_id}":{"get":{"tags":["Vulnerability Scans"],"operationId":"get_scan","parameters":[{"name":"scan_id","in":"path","description":"Scan ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Scan details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScanResponse"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Scan not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]},"delete":{"tags":["Vulnerability Scans"],"operationId":"delete_scan","parameters":[{"name":"scan_id","in":"path","description":"Scan ID","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"204":{"description":"Scan deleted"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Scan not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/vulnerability-scans/{scan_id}/vulnerabilities":{"get":{"tags":["Vulnerability Scans"],"operationId":"get_scan_vulnerabilities","parameters":[{"name":"scan_id","in":"path","description":"Scan ID","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"page","in":"query","description":"Page number (default: 1)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"page_size","in":"query","description":"Page size (default: 20, max: 100)","required":false,"schema":{"type":"integer","format":"int64","minimum":0}},{"name":"severity","in":"query","description":"Filter by severity (CRITICAL, HIGH, MEDIUM, LOW)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of vulnerabilities","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/VulnerabilityResponse"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"403":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"404":{"description":"Scan not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"security":[{"bearer_auth":[]}]}},"/webhook-event-types":{"get":{"tags":["Webhooks"],"summary":"List available event types","operationId":"list_event_types","responses":{"200":{"description":"List of available event types","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EventTypeResponse"}}}}}}}},"/weekly-digest/trigger":{"post":{"tags":["Notification Preferences"],"summary":"Trigger weekly digest generation manually","operationId":"trigger_weekly_digest","responses":{"200":{"description":"Weekly digest triggered successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerDigestResponse"}}}},"500":{"description":"Failed to generate digest"}},"security":[{"bearer_auth":[]}]}},"/x/plugins":{"get":{"tags":["External Plugins"],"summary":"List all running external plugins and their manifests.","description":"Requires only a valid session/token (no specific permission) since the\nmanifest drives sidebar navigation rendering for every authenticated\nuser, not just admins.","operationId":"list_external_plugins","responses":{"200":{"description":"List of all running external plugins","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PluginManifest"}}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]}},"/x/plugins/reload":{"post":{"tags":["External Plugins"],"summary":"Reload all external plugins.","description":"Stops all running plugin processes, re-scans the plugins directory,\nstarts any discovered binaries, and hot-swaps the proxy router so new\nand removed plugins take effect immediately without a server restart.\n\nRequires `SystemAdmin` permission.","operationId":"reload_plugins","responses":{"200":{"description":"Plugins reloaded successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReloadResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"}},"security":[{"bearer_auth":[]}]}},"/{project_id}/envelope/":{"post":{"tags":["sentry-ingestor"],"summary":"Ingest a Sentry envelope (binary payload)","operationId":"ingest_sentry_envelope","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"Sentry envelope as binary data","content":{"application/octet-stream":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"Envelope ingested"},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"413":{"description":"Request body too large (exceeds 2 MiB)"}}}},"/{project_id}/store/":{"post":{"tags":["sentry-ingestor"],"summary":"Ingest a Sentry event (JSON payload)","operationId":"ingest_sentry_event","parameters":[{"name":"project_id","in":"path","description":"Project ID","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryEventRequest"}}},"required":true},"responses":{"200":{"description":"Event ingested","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentryEventResponse"}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"413":{"description":"Request body too large (exceeds 2 MiB)"}}}},"audit/logs":{"get":{"tags":["Audit Logs"],"summary":"List audit logs with optional filtering","operationId":"list_audit_logs","parameters":[{"name":"operation_type","in":"query","description":"Filter logs by operation type (omit for all)","required":false,"schema":{"type":"string"},"example":"user.login"},{"name":"user_id","in":"query","description":"Filter logs by user ID (omit for all users)","required":false,"schema":{"type":"integer","format":"int32"},"example":1},{"name":"from","in":"query","description":"Start timestamp (milliseconds since epoch)","required":false,"schema":{"type":"string","format":"date-time"},"example":1},{"name":"to","in":"query","description":"End timestamp (milliseconds since epoch)","required":false,"schema":{"type":"string","format":"date-time"},"example":1},{"name":"limit","in":"query","description":"Maximum number of logs to return","required":false,"schema":{"type":"integer","format":"int32"},"example":100},{"name":"offset","in":"query","description":"Number of logs to skip","required":false,"schema":{"type":"integer","format":"int32"},"example":0}],"responses":{"200":{"description":"List of audit logs","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AuditLogResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"500":{"description":"Internal server error"}},"security":[{"api_key":[]}]}},"audit/logs/{id}":{"get":{"tags":["Audit Logs"],"summary":"Get a specific audit log entry by ID","operationId":"get_audit_log","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Audit log details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuditLogResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient permissions"},"404":{"description":"Audit log not found"},"500":{"description":"Internal server error"}},"security":[{"api_key":[]}]}}},"components":{"schemas":{"AcmeOrderResponse":{"type":"object","required":["id","order_url","domain_id","email","status","identifiers","created_at","updated_at"],"properties":{"authorizations":{},"certificate_url":{"type":["string","null"]},"challenge_validation":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ChallengeValidationStatus","description":"Live challenge validation status fetched from Let's Encrypt"}]},"created_at":{"type":"integer","format":"int64"},"domain_id":{"type":"integer","format":"int32"},"email":{"type":"string"},"error":{"type":["string","null"]},"error_type":{"type":["string","null"]},"expires_at":{"type":["integer","null"],"format":"int64"},"finalize_url":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"identifiers":{},"order_url":{"type":"string"},"status":{"type":"string"},"updated_at":{"type":"integer","format":"int64"}}},"ActivateProviderResponse":{"type":"object","required":["default_provider"],"properties":{"default_provider":{"type":"string"}}},"ActiveVisitor":{"type":"object","required":["session_id","session_start","last_activity","page_count","event_count","duration_seconds","is_active"],"properties":{"current_page":{"type":["string","null"]},"duration_seconds":{"type":"integer","format":"int64"},"event_count":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"last_activity":{"type":"string"},"page_count":{"type":"integer","format":"int32"},"session_id":{"type":"string"},"session_start":{"type":"string"},"visitor_id":{"type":["string","null"]}}},"ActiveVisitorsQuery":{"type":"object","properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"}}},"ActiveVisitorsResponse":{"type":"object","required":["active_visitors","window_minutes"],"properties":{"active_visitors":{"type":"integer","format":"int64"},"window_minutes":{"type":"integer","format":"int32"}}},"ActivityDay":{"type":"object","description":"Daily activity count for a single day","required":["date","count","level"],"properties":{"count":{"type":"integer","format":"int64","description":"Number of deployments on this day"},"date":{"type":"string","description":"Date in YYYY-MM-DD format","example":"2024-06-15"},"level":{"type":"integer","format":"int32","description":"Intensity level (0-4) for visualization\n0: No activity, 1: Low (1-2), 2: Medium (3-5), 3: High (6-10), 4: Very High (11+)","example":2}}},"ActivityEvent":{"type":"object","description":"A single activity event for the real-time activity feed","required":["id","timestamp","event_type","page_path","is_crawler"],"properties":{"browser":{"type":["string","null"],"description":"Browser"},"city":{"type":["string","null"],"description":"Visitor's city (from ip_geolocations)"},"country":{"type":["string","null"],"description":"Visitor's country (from ip_geolocations)"},"country_code":{"type":["string","null"],"description":"Visitor's country code (from ip_geolocations)"},"device_type":{"type":["string","null"],"description":"Device type"},"event_name":{"type":["string","null"],"description":"Event name (for custom events)"},"event_type":{"type":"string","description":"Event type: \"page_view\", \"custom\", etc."},"id":{"type":"integer","format":"int64","description":"Event ID"},"is_crawler":{"type":"boolean","description":"Whether this event was from a crawler"},"latitude":{"type":["number","null"],"format":"double","description":"Latitude"},"longitude":{"type":["number","null"],"format":"double","description":"Longitude"},"operating_system":{"type":["string","null"],"description":"Operating system"},"page_path":{"type":"string","description":"Page path where the event happened"},"page_title":{"type":["string","null"],"description":"Page title"},"referrer":{"type":["string","null"],"description":"Referrer"},"timestamp":{"type":"string","format":"date-time","description":"When the event occurred"},"visitor_id":{"type":["integer","null"],"format":"int32","description":"Visitor numeric ID"}}},"ActivityGraphQuery":{"type":"object","description":"Query parameters for activity graph endpoint","properties":{"days":{"type":"integer","format":"int32","description":"Number of days to include (default: 365 for last year)"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Optional environment ID to filter activity"},"project_id":{"type":["integer","null"],"format":"int32","description":"Optional project ID to filter activity"}}},"ActivityGraphResponse":{"type":"object","description":"Response for activity graph showing daily deployment activity","required":["days","total_count","start_date","end_date"],"properties":{"days":{"type":"array","items":{"$ref":"#/components/schemas/ActivityDay"},"description":"Array of daily activity counts"},"end_date":{"type":"string","description":"Date range end (YYYY-MM-DD)","example":"2024-12-31"},"start_date":{"type":"string","description":"Date range start (YYYY-MM-DD)","example":"2024-01-01"},"total_count":{"type":"integer","format":"int64","description":"Total count of activities across all days"}}},"AddClusterMemberRequest":{"type":"object","description":"Request body for adding a single member to a running cluster.","required":["role"],"properties":{"node_id":{"type":["integer","null"],"format":"int32","description":"Target worker node ID. Omit or null to run on the control plane."},"role":{"type":"string","description":"Member role. Currently only `replica` is accepted at runtime —\nmonitor is a singleton, primary is elected by pg_auto_failover.","example":"replica"}}},"AddContextRequest":{"type":"object","required":["message"],"properties":{"message":{"type":"string"}}},"AddEnvironmentDomainRequest":{"type":"object","required":["domain","is_primary"],"properties":{"domain":{"type":"string"},"is_primary":{"type":"boolean"}}},"AddEventsRequest":{"type":"object","required":["events"],"properties":{"events":{"type":"string"}}},"AddEventsResponse":{"type":"object","required":["event_count","message"],"properties":{"event_count":{"type":"integer","minimum":0},"message":{"type":"string"}}},"AddManagedDomainApiRequest":{"type":"object","description":"Request to add a managed domain","required":["domain"],"properties":{"auto_manage":{"type":"boolean"},"domain":{"type":"string","example":"example.com"},"generated_hostname_mode":{"type":["string","null"],"description":"Generated hostname layout: `\"standard\"` (default) or `\"flat\"`."},"sync_generated_records":{"type":"boolean","description":"Opt in to reconciling generated hostnames into this domain's DNS zone."}}},"AdminGateResponse":{"type":"object","required":["allowed_ips","allowed_hosts","trust_forwarded_for","source","editable"],"properties":{"allowed_hosts":{"type":"array","items":{"type":"string"},"description":"`Host` header values allowed. Empty = any host."},"allowed_ips":{"type":"array","items":{"type":"string"},"description":"IPs / CIDRs allowed to reach the admin listener. Empty = any source."},"editable":{"type":"boolean","description":"True when the config is writable through this API. False when env\nvars are dictating the active config."},"source":{"$ref":"#/components/schemas/AdminGateSource","description":"Where the active config came from."},"trust_forwarded_for":{"type":"boolean","description":"When true, the gate trusts `X-Forwarded-For` from loopback peers."}}},"AdminGateSource":{"type":"string","description":"Where the active gate configuration came from. Env-supplied configs are\nfrozen at the process level — the UI shows them read-only and refuses to\npersist DB writes. DB-supplied configs are editable at runtime.","enum":["default","db","env"]},"AgentConfigResponse":{"type":"object","description":"Response DTO for a single agent — masks the encrypted API key.","required":["id","project_id","slug","name","source","enabled","trigger_config","ai_provider","api_key_set","max_turns","timeout_seconds","daily_budget_cents","cooldown_minutes","branch_prefix","deliverable","created_at","updated_at"],"properties":{"ai_model":{"type":["string","null"],"description":"Preferred model for the CLI (e.g. \"sonnet\", \"gpt-5-codex\"). `None` means default."},"ai_provider":{"type":"string"},"ai_provider_key_id":{"type":["integer","null"],"format":"int32"},"api_key_set":{"type":"boolean","description":"`true` if an API key is set; `false` otherwise."},"branch_prefix":{"type":"string"},"config_repo_branch":{"type":["string","null"],"description":"Branch of the config repo to use."},"config_repo_url":{"type":["string","null"],"description":"Private config repo containing .claude/ directory (skills, MCP, plugins)."},"cooldown_minutes":{"type":"integer","format":"int32"},"created_at":{"type":"string"},"daily_budget_cents":{"type":"integer","format":"int32"},"deliverable":{"type":"string"},"description":{"type":["string","null"]},"enabled":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"max_turns":{"type":"integer","format":"int32"},"mcp_servers_config":{"description":"MCP servers config (Claude Code settings.json mcpServers format).\nCredential-bearing legacy inline values are write-only and appear as\n`***`. Omit this field on update to preserve their stored values."},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"prompt":{"type":["string","null"]},"sandbox_enabled":{"type":["boolean","null"],"description":"None = use global sandbox setting, true = force on, false = force off"},"skills_config":{"description":"Skills config as JSON array."},"slug":{"type":"string"},"source":{"type":"string"},"timeout_seconds":{"type":"integer","format":"int32"},"tools_config":{"description":"Tools config as JSON array. Legacy custom-tool webhook URLs and headers\nare write-only and appear as `***`. Omit this field on update to\npreserve their stored values."},"trigger_config":{},"updated_at":{"type":"string"},"webhook_token":{"type":["string","null"],"description":"Secret token for the `X-Webhook-Token` header. Shown once when created,\nmasked with `***` prefix in subsequent reads."},"webhook_url":{"type":["string","null"],"description":"Public webhook URL for triggering this agent externally.\nOnly set when `on: { webhook: true }` is configured.\nUsage: `POST {webhook_url}` with header `X-Webhook-Token: {webhook_token}`"}}},"AgentRunLogResponse":{"type":"object","required":["id","run_id","level","message","created_at"],"properties":{"created_at":{"type":"string"},"id":{"type":"integer","format":"int64"},"level":{"type":"string"},"message":{"type":"string"},"metadata":{},"run_id":{"type":"integer","format":"int32"}}},"AgentRunResponse":{"type":"object","required":["id","project_id","source","trigger_type","status","tokens_input","tokens_output","estimated_cost_cents","files_changed","created_at","sandbox_enabled"],"properties":{"agent_name":{"type":["string","null"],"description":"Name of the agent that created this run, if available."},"agent_slug":{"type":["string","null"],"description":"Slug of the agent that created this run, if available."},"ai_model":{"type":["string","null"]},"ai_output":{"type":["string","null"]},"ai_provider":{"type":["string","null"],"description":"AI provider slug that executed this run (e.g. claude_cli, codex_cli, opencode)."},"ai_reasoning":{"type":["string","null"]},"ai_session_id":{"type":["string","null"],"description":"Claude CLI session UUID for resuming conversations via `--resume`."},"analysis":{"type":["string","null"],"description":"Report / analysis text produced by the agent (used for report/notification deliverables)."},"branch_name":{"type":["string","null"]},"commit_sha":{"type":["string","null"]},"completed_at":{"type":["string","null"]},"config_id":{"type":["integer","null"],"format":"int32","description":"Optional. NULL for ephemeral CLI runs (`source = \"cli_ephemeral\"`) and\nhistorical autofixer runs that pre-date the agent_id column."},"created_at":{"type":"string"},"ephemeral_yaml":{"type":["string","null"],"description":"Full WorkflowYamlConfig as YAML text. Populated only when\n`source = \"cli_ephemeral\"`. Used by the web UI to show a \"View YAML\"\nmodal so the user can see exactly what the executor ran."},"error_message":{"type":["string","null"]},"estimated_cost_cents":{"type":"integer","format":"int32"},"files_changed":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"phase":{"type":["string","null"],"description":"Autofixer phase: \"analyzing\", \"analyzed\", \"fixing\", \"fix_ready\", \"no_fix\",\n\"pr_created\", or NULL for non-autofixer runs."},"pr_number":{"type":["integer","null"],"format":"int32"},"pr_url":{"type":["string","null"]},"preview_url":{"type":["string","null"]},"project_id":{"type":"integer","format":"int32"},"prompt_text":{"type":["string","null"],"description":"Final assembled prompt the AI CLI actually saw (trigger context block +\nYAML prompt, with error-group fields interpolated). Captured once per\nrun. `None` for pre-migration rows."},"run_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AutofixRunConfig","description":"Per-run AI options the user chose when starting an autofixer run\n(provider, model, max_turns, branch). NULL for generic agent runs\nand historical rows. Used to prefill the retry dialog."}]},"sandbox_enabled":{"type":"boolean","description":"Legacy field — all runs now execute in a sandbox. Kept for\nbackwards-compatible JSON shape; always `true`."},"source":{"type":"string","description":"`committed` (the run's config lives in `project_agents`) or\n`cli_ephemeral` (the config was uploaded via the CLI for a one-off\ndry run; see `ephemeral_yaml`)."},"started_at":{"type":["string","null"]},"status":{"type":"string"},"tokens_input":{"type":"integer","format":"int32"},"tokens_output":{"type":"integer","format":"int32"},"trigger_source_id":{"type":["integer","null"],"format":"int32"},"trigger_source_type":{"type":["string","null"]},"trigger_type":{"type":"string"},"user_context":{"type":["string","null"],"description":"User-provided context for this run (e.g. webhook payload, manual instructions)."}}},"AgentRunWithLogsResponse":{"type":"object","required":["run","logs"],"properties":{"logs":{"type":"array","items":{"$ref":"#/components/schemas/AgentRunLogResponse"}},"run":{"$ref":"#/components/schemas/AgentRunResponse"}}},"AgentSandboxSettings":{"type":"object","description":"Global agent sandbox settings. Controls whether agent runs are isolated\ninside Docker containers by default. Individual agents can override this.","properties":{"api_key_encrypted":{"type":["string","null"],"description":"DEPRECATED: use `providers[default_provider].credentials_encrypted` instead.","default":null},"auth_type":{"type":"string","description":"DEPRECATED: use `providers[default_provider].auth_type` instead.","default":"subscription"},"cpu_limit":{"type":"number","format":"double","description":"CPU limit in cores for sandbox containers","default":4.0,"example":4.0},"custom_image":{"type":"string","description":"Custom Docker image (only used when runtime is \"custom\").\nMust have git and claude CLI installed.","default":"","example":""},"default_provider":{"type":"string","description":"Default AI provider for agents: \"claude_cli\", \"opencode\", or \"codex_cli\".\nWorkspaces always use this provider — no per-session override.","default":"claude_cli","example":"claude_cli"},"enabled":{"type":"boolean","description":"Sandbox is always enabled — the executor refuses to run any agent\noutside a sandboxed container. Field is retained so existing settings\nrows still deserialize, but it is ignored at runtime.","default":true},"memory_limit_mb":{"type":"integer","format":"int64","description":"Memory limit in MB for sandbox containers","default":8192,"example":8192,"minimum":0},"network_mode":{"type":"string","description":"Network access level: \"full\" (unrestricted), \"restricted\" (Temps network only), \"none\" (no network)","default":"full","example":"full"},"providers":{"type":"object","description":"Per-provider auth + config. Keyed by provider id (e.g. `claude_cli`,\n`codex_cli`, `opencode`). Adding a new provider only requires a new\ncatalog entry on the Rust side — the JSON column stays migration-free.","default":{},"additionalProperties":{"$ref":"#/components/schemas/ProviderConfig"},"propertyNames":{"type":"string"}},"runtime":{"type":"string","description":"Runtime preset: \"node\", \"bun\", \"python\", \"rust\", \"go\", \"full\", or \"custom\"","default":"node","example":"node"},"sandbox_backend":{"type":["string","null"],"description":"Default isolation backend for sandboxes: \"docker\" (default) or\n\"firecracker\" (ADR-029; requires `temps firecracker setup`). Only\nconsulted when the Firecracker backend probes available — otherwise\nDocker is used regardless.","default":null,"example":"docker"}}},"AgentSandboxSettingsMasked":{"type":"object","description":"Agent sandbox settings with masked per-provider credentials.\nEach provider entry reports only whether a credential is saved, not\nthe encrypted blob itself. Non-sensitive fields (auth_type, default_model,\nextra) are passed through so the UI can render provider-specific state.","required":["default_provider","providers","api_key_saved","auth_type","enabled","runtime","custom_image","cpu_limit","memory_limit_mb","network_mode","sandbox_backend"],"properties":{"api_key_saved":{"type":"boolean"},"auth_type":{"type":"string"},"cpu_limit":{"type":"number","format":"double"},"custom_image":{"type":"string"},"default_provider":{"type":"string"},"enabled":{"type":"boolean"},"memory_limit_mb":{"type":"integer","format":"int64","minimum":0},"network_mode":{"type":"string"},"providers":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/ProviderConfigMasked"},"propertyNames":{"type":"string"}},"runtime":{"type":"string"},"sandbox_backend":{"type":"string"}}},"AggregatedBucketItem":{"type":"object","required":["timestamp","count"],"properties":{"count":{"type":"integer","format":"int64"},"timestamp":{"type":"string"}}},"AggregatedBucketsQuery":{"type":"object","description":"Query parameters for aggregated metrics by time bucket","required":["start_date","end_date"],"properties":{"aggregation_level":{"$ref":"#/components/schemas/AggregationLevel","description":"Aggregation level: events, sessions, or visitors"},"bucket_size":{"type":"string","description":"Time bucket size: \"1 hour\", \"1 day\", \"1 week\", etc. (default: \"1 hour\")"},"deployment_id":{"type":["integer","null"],"format":"int32","description":"Optional deployment filter"},"end_date":{"type":"string","format":"date-time","description":"End date for the query range"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Optional environment filter"},"start_date":{"type":"string","format":"date-time","description":"Start date for the query range"}}},"AggregatedBucketsResponse":{"type":"object","required":["bucket_size","aggregation_level","items","total"],"properties":{"aggregation_level":{"type":"string"},"bucket_size":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/AggregatedBucketItem"}},"total":{"type":"integer","format":"int64"}}},"AggregationLevel":{"type":"string","enum":["events","sessions","visitors"]},"AggregationTemporality":{"type":"string","description":"The aggregation temporality of a Sum/Histogram/ExponentialHistogram metric.\n\nMirrors OTel's `AggregationTemporality` proto enum: whether reported values\nare cumulative since the start of the series (Cumulative) or only the delta\nsince the previous report (Delta).","enum":["unspecified","delta","cumulative"]},"AiAgentBreakdownResponse":{"type":"object","description":"Response wrapping the AI agent breakdown rows.","required":["items","start_time","end_time"],"properties":{"end_time":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/AiAgentBreakdownRow"}},"start_time":{"type":"string"}}},"AiAgentBreakdownRow":{"type":"object","description":"One row in the AI-agent analytics breakdown. `agent` is the canonical\ncrawler name (e.g. `GPTBot`, `Claude-User`), `provider` is the vendor used\nfor grouping + logos. The UI mirrors the browsers card and ranks by\n`request_count`.","required":["provider","agent","purpose","request_count","unique_ips"],"properties":{"agent":{"type":"string"},"last_seen":{"type":["string","null"],"description":"Last-seen timestamp in RFC3339 format, or `None` if no rows matched.","example":"2026-05-29T12:00:00Z"},"provider":{"type":"string"},"purpose":{"type":"string"},"request_count":{"type":"integer","format":"int64"},"unique_ips":{"type":"integer","format":"int64"}}},"AiAgentDescriptor":{"type":"object","description":"Static descriptor for one entry in the known-AI-agents taxonomy.","required":["provider","agent","purpose"],"properties":{"agent":{"type":"string"},"provider":{"type":"string"},"purpose":{"type":"string"}}},"AiAgentPageRow":{"type":"object","description":"One row in the pages-by-agent breakdown. Returned by\n[`ProxyLogService::get_ai_agent_pages`] for a single named agent.\n`unique_ips` counts distinct client IPs that hit this path via that agent\n(same definition as the per-agent unique-IPs in [`AiAgentBreakdownRow`]).","required":["path","request_count","unique_ips"],"properties":{"last_seen":{"type":["string","null"],"description":"Last-seen timestamp in RFC3339 format, or `None` if no rows matched.","example":"2026-05-29T12:00:00Z"},"path":{"type":"string"},"request_count":{"type":"integer","format":"int64"},"unique_ips":{"type":"integer","format":"int64"}}},"AiAgentPagesResponse":{"type":"object","description":"Response wrapping the per-agent pages breakdown rows.","required":["agent","items","start_time","end_time"],"properties":{"agent":{"type":"string","description":"The agent name this breakdown is scoped to."},"end_time":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/AiAgentPageRow"}},"start_time":{"type":"string"}}},"AiAgentTimelineResponse":{"type":"object","description":"Response wrapping the AI agent timeline rows.","required":["items","start_time","end_time","bucket","group_by"],"properties":{"bucket":{"type":"string","description":"Bucket interval used for the buckets (so the UI can label the x-axis).","example":"1 hour"},"end_time":{"type":"string"},"group_by":{"type":"string","description":"Echoes the grouping dimension actually applied.","example":"provider"},"items":{"type":"array","items":{"$ref":"#/components/schemas/AiAgentTimelineRow"}},"start_time":{"type":"string"}}},"AiAgentTimelineRow":{"type":"object","description":"One point in the AI-agent timeline: the request count for a single\n(`bucket`, `key`) pair, where `key` is a provider or agent name depending on\nthe requested grouping. The UI pivots these into one stacked series per\n`key` across the shared bucket x-axis.","required":["bucket","key","request_count"],"properties":{"bucket":{"type":"string","description":"Bucket start in RFC3339 format.","example":"2026-05-29T12:00:00Z"},"key":{"type":"string","description":"Provider or agent name this count belongs to.","example":"OpenAI"},"request_count":{"type":"integer","format":"int64"}}},"AiChatLimitsSettings":{"type":"object","description":"Bounds on one AI chat turn.\n\nA turn is bounded by TIME rather than by a number of steps. A step count\nsays nothing about cost or about how long someone has been watching a\nspinner, and it cuts short exactly the long, productive turns the chat\nexists for. The user can already see each tool call and press Stop; the\ndeadline is what guarantees an *unattended* turn still ends.\n\nThe right value is a property of the model, which is why it is configurable\nrather than compiled in: a full alert-suggestion turn takes ~10 minutes\nagainst a slow local model and seconds against a hosted one.","properties":{"turn_timeout_secs":{"type":"integer","format":"int32","description":"How long one turn may run before it is stopped and the partial answer\nreturned, in seconds. The user is told the turn was cut short.\n\nChecked between steps, not mid-call: a model round already in flight\nfinishes, so a turn can overrun by up to one round. Against a slow\nself-hosted model that is a minute or two. Aborting mid-stream would cut\nthe answer off in the middle of a sentence and throw away work already\npaid for, which is worse than a late stop.","default":900,"example":900,"maximum":3600,"minimum":30}}},"AiConfigSettings":{"type":"object","description":"Global AI configuration settings. Controls the default config repo\ncontaining `.claude/` directory (skills, MCP servers, plugins) that\ngets overlaid into every agent sandbox.","properties":{"config_repo":{"type":"string","description":"Global config repo URL in \"owner/repo\" format (e.g. \"myorg/claude-config\").\nCloned at agent run time and overlaid into the sandbox's `.claude/` directory.","default":"","example":""},"config_repo_branch":{"type":"string","description":"Branch of the config repo to use.","default":"main","example":"main"}}},"AiDataAccessResponse":{"type":"object","required":["service_id","enabled"],"properties":{"enabled":{"type":"boolean","description":"Whether the AI assistant may read row data from this service","example":false},"service_id":{"type":"integer","format":"int32","description":"Service id"}}},"AiPageBreakdownResponse":{"type":"object","description":"Response wrapping the AI page breakdown rows.","required":["items","start_time","end_time"],"properties":{"end_time":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/AiPageBreakdownRow"}},"start_time":{"type":"string"}}},"AiPageBreakdownRow":{"type":"object","description":"One row in the AI-crawled-pages breakdown. `agent_count` is the number of\n*distinct* AI agents that hit this path, so the UI can show both how heavily\nand how broadly a page is being crawled.","required":["path","request_count","agent_count"],"properties":{"agent_count":{"type":"integer","format":"int64"},"last_seen":{"type":["string","null"],"description":"Last-seen timestamp in RFC3339 format, or `None` if no rows matched.","example":"2026-05-29T12:00:00Z"},"path":{"type":"string"},"request_count":{"type":"integer","format":"int64"}}},"AiStatusBreakdownResponse":{"type":"object","description":"Response wrapping the AI status breakdown rows.","required":["items","start_time","end_time"],"properties":{"end_time":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/AiStatusBreakdownRow"}},"start_time":{"type":"string"}}},"AiStatusBreakdownRow":{"type":"object","description":"One row in the AI-agent HTTP status breakdown: the request count for a\nstatus class (`2xx`/`3xx`/`4xx`/`5xx`/`other`) across crawler traffic.","required":["status_class","request_count"],"properties":{"request_count":{"type":"integer","format":"int64"},"status_class":{"type":"string","description":"Status class label.","example":"2xx"}}},"AlarmListResponse":{"type":"object","description":"Paginated list of alarms.","required":["items","total","page","page_size"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AlarmResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"AlarmResponse":{"type":"object","description":"Full alarm representation returned by list/summary endpoints.","required":["id","project_id","alarm_type","severity","status","title","fired_at","created_at","updated_at"],"properties":{"acknowledged_at":{"type":["string","null"],"description":"ISO-8601 UTC timestamp when the alarm was acknowledged, if any."},"acknowledged_by":{"type":["integer","null"],"format":"int32","description":"User ID who acknowledged the alarm, if any."},"alarm_type":{"type":"string"},"container_id":{"type":["integer","null"],"format":"int32"},"created_at":{"type":"string","description":"ISO-8601 UTC timestamp when the row was created."},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"fired_at":{"type":"string","description":"ISO-8601 UTC timestamp when the alarm fired."},"id":{"type":"integer","format":"int32"},"message":{"type":["string","null"]},"metadata":{"description":"Arbitrary JSON metadata attached by the alarm source."},"project_id":{"type":"integer","format":"int32"},"resolved_at":{"type":["string","null"],"description":"ISO-8601 UTC timestamp when the alarm was resolved, if any."},"service_id":{"type":["integer","null"],"format":"int32"},"severity":{"type":"string"},"status":{"type":"string"},"title":{"type":"string"},"updated_at":{"type":"string","description":"ISO-8601 UTC timestamp when the row was last updated."}}},"AlarmSummaryResponse":{"type":"object","description":"Re-export AlarmSummary for the OpenAPI schema.","required":["total_active","firing","acknowledged","critical","warning","by_type"],"properties":{"acknowledged":{"type":"integer","format":"int32","minimum":0},"by_type":{"type":"object","additionalProperties":{"type":"integer","format":"int32","minimum":0},"propertyNames":{"type":"string"}},"critical":{"type":"integer","format":"int32","minimum":0},"firing":{"type":"integer","format":"int32","minimum":0},"total_active":{"type":"integer","format":"int32","minimum":0},"warning":{"type":"integer","format":"int32","minimum":0}}},"AlertRuleResponse":{"type":"object","required":["id","project_id","name","trigger_type","trigger_config","notification_priority","cooldown_minutes","enabled","created_at","updated_at"],"properties":{"cooldown_minutes":{"type":"integer","format":"int32"},"created_at":{"type":"string"},"enabled":{"type":"boolean"},"environment_filter":{"type":["integer","null"],"format":"int32"},"error_level_filter":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"notification_priority":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"trigger_config":{},"trigger_type":{"type":"string"},"updated_at":{"type":"string"}}},"AllocEntry":{"type":"object","description":"Wire-format allocation. `null` in the JSON when the node hasn't been\nallocated yet — workers should treat that as \"single-host mode, do\nnot bring up the overlay\".","required":["node_id","compute_cidr","bridge_address","underlay_address"],"properties":{"bridge_address":{"type":"string"},"compute_cidr":{"type":"string"},"node_id":{"type":"string","description":"Stable v5 UUID derived from the database node id."},"underlay_address":{"type":"string"}}},"AnalyticsSessionEventsResponse":{"type":"object","required":["session_id","events","total_events"],"properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/SessionEvent"}},"session_id":{"type":"string"},"total_events":{"type":"integer","minimum":0}}},"AnnotatedSpan":{"type":"object","description":"A single span annotated with the project that originally stored it.\nUsed in `UnifiedTrace` to let the UI colour-code spans by project.","required":["project_id","project_name","span"],"properties":{"project_id":{"type":"integer","format":"int32","description":"The project that stored this span (same as `span.project_id`)."},"project_name":{"type":"string","description":"Human-readable project name for waterfall colour-coding and legend."},"span":{"$ref":"#/components/schemas/SpanRecord","description":"Original span data verbatim from storage."}}},"AnomalyAlgorithm":{"type":"string","description":"Anomaly baseline algorithm. Adding one (e.g. a new robust variant) is a\ncode-only enum addition — no migration, since it lives inside the blob.","enum":["robust","basic","agile","ewma"]},"AnomalyParams":{"type":"object","description":"Seasonal anomaly-band detector parameters (stub — not yet evaluated).","properties":{"algorithm":{"$ref":"#/components/schemas/AnomalyAlgorithm","description":"Baseline model. `robust` is the default (seasonal, stable, flags level\nshifts); `ewma`/`agile` adopt level shifts; `basic` is non-seasonal."},"baseline_lookback_days":{"type":["integer","null"],"format":"int32","description":"How far back to build the baseline. `None` = an evaluator default."},"deviations":{"type":"number","format":"double","description":"Band width in robust standard deviations (Datadog's `bounds`)."},"direction":{"$ref":"#/components/schemas/Direction","description":"Which side(s) of the band a deviation must be on to count."},"pct_anomalous":{"type":"number","format":"double","description":"Fraction (0..=1) of points in the window that must be anomalous to fire."},"seasonality":{"$ref":"#/components/schemas/Seasonality","description":"Seasonality model for the baseline."}}},"AnomalyPreviewPointResponse":{"type":"object","required":["bucket","value","lower","upper","breaching"],"properties":{"breaching":{"type":"boolean"},"bucket":{"type":"string","example":"2025-10-12T12:15:47Z"},"lower":{"type":"number","format":"double","description":"Lower edge of the expected band at this point."},"upper":{"type":"number","format":"double","description":"Upper edge of the expected band at this point."},"value":{"type":"number","format":"double"}}},"AnomalyPreviewRequest":{"type":"object","required":["project_id","metric_name","aggregation","window_secs","detection_config"],"properties":{"aggregation":{"type":"string","description":"One of `avg|sum|min|max|count|rate|p50|p90|p95|p99`."},"detection_config":{"$ref":"#/components/schemas/DetectionConfig","description":"The detector to backtest. `static` and `anomaly` are supported — the\nkinds the evaluator actually runs."},"end_time":{"type":["string","null"],"description":"RFC 3339; defaults to now.","example":"2025-10-12T12:15:47Z"},"metric_name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"start_time":{"type":["string","null"],"description":"RFC 3339; defaults to 7 days before `end_time`.","example":"2025-10-12T12:15:47Z"},"window_secs":{"type":"integer","format":"int32"}}},"AnomalyPreviewResponse":{"type":"object","required":["points","breach_count","baseline_samples","sufficient"],"properties":{"baseline_samples":{"type":"integer","format":"int64","description":"Baseline sample count (drives the `sufficient` flag)."},"breach_count":{"type":"integer","format":"int64","description":"How many points in the range would have fired."},"points":{"type":"array","items":{"$ref":"#/components/schemas/AnomalyPreviewPointResponse"}},"sufficient":{"type":"boolean","description":"Whether the baseline had enough history for a trustworthy band."}}},"ApiKeyListResponse":{"type":"object","required":["api_keys","total"],"properties":{"api_keys":{"type":"array","items":{"$ref":"#/components/schemas/ApiKeyResponse"}},"total":{"type":"integer","format":"int64","minimum":0}}},"ApiKeyResponse":{"type":"object","required":["id","name","key_prefix","role_type","is_active","created_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00Z"},"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"key_prefix":{"type":"string"},"last_used_at":{"type":["string","null"],"format":"date-time","example":"2024-01-01T00:00:00Z"},"name":{"type":"string"},"permissions":{"type":["array","null"],"items":{"type":"string"}},"role_type":{"type":"string"}}},"AppSettings":{"type":"object","description":"Application settings stored in the database\nAll fields have sensible defaults for easy onboarding","properties":{"agent_sandbox":{"oneOf":[{"$ref":"#/components/schemas/AgentSandboxSettings"}],"default":{"default_provider":"claude_cli","providers":{},"auth_type":"subscription","api_key_encrypted":null,"enabled":true,"runtime":"node","custom_image":"","cpu_limit":4.0,"memory_limit_mb":8192,"network_mode":"full","sandbox_backend":null}},"ai_chat_limits":{"oneOf":[{"$ref":"#/components/schemas/AiChatLimitsSettings","description":"Limits on a single AI chat turn. Operator-tunable because the right\nvalue depends on the model: a turn against a slow self-hosted model can\nlegitimately take ten minutes, while a hosted one finishes in seconds\nand a shorter ceiling keeps costs predictable."}],"default":{"turn_timeout_secs":900}},"ai_config":{"oneOf":[{"$ref":"#/components/schemas/AiConfigSettings"}],"default":{"config_repo":"","config_repo_branch":"main"}},"build_limits":{"oneOf":[{"$ref":"#/components/schemas/BuildLimitsSettings","description":"Build-time resource limits applied on the control plane to prevent\n`docker build` from saturating host CPU/RAM. Worker nodes are\nintentionally NOT subject to these limits (each worker is dedicated\nhardware that already has its own per-host headroom)."}],"default":{"max_concurrent":2,"cpu_limit_cores":0.0,"memory_limit_mb":0}},"cluster_dns":{"oneOf":[{"$ref":"#/components/schemas/ClusterDnsSettings","description":"Cluster-DNS resolver settings (ADR-024, experimental beta). Off by\ndefault — see `ClusterDnsSettings` for the incident background and\ntrade-offs. Must be explicitly enabled by operators who need\n`*.temps.local` service-to-service resolution inside containers."}],"default":{"enabled":false}},"console_version":{"type":["string","null"],"description":"Binary version tag (e.g. \"v0.1.0\") of the *console* process\n(`temps serve`, role=all or role=console) that last started. Written\non console startup; read by the standalone `temps proxy` to detect\nversion skew during a rolling upgrade (ADR-017 Phase 3). `None` on\ninstalls that never ran a console build carrying this field.\n\nThis is informational state written by the binary itself — NOT an\noperator-tunable setting. It is intentionally absent from\n`AppSettingsResponse` and the PATCH path so an operator cannot\naccidentally overwrite the self-recorded value.","default":null},"container_logs":{"oneOf":[{"$ref":"#/components/schemas/ContainerLogSettings"}],"default":{"max_size":"50m","max_file":3,"service_max_size":"20m","service_max_file":3}},"disk_space_alert":{"oneOf":[{"$ref":"#/components/schemas/DiskSpaceAlertSettings"}],"default":{"enabled":true,"threshold_percent":80,"check_interval_seconds":300,"monitor_path":null}},"dns_provider":{"oneOf":[{"$ref":"#/components/schemas/DnsProviderSettings"}],"default":{"provider":"manual","cloudflare_api_key":null}},"docker_registry":{"oneOf":[{"$ref":"#/components/schemas/DockerRegistrySettings"}],"default":{"enabled":false,"registry_url":null,"username":null,"password":null,"tls_verify":true,"ca_certificate":null}},"edge_target":{"type":["string","null"],"description":"Public edge target that generated DNS records point at when a managed\ndomain opts into automatic record sync. An IPv4/IPv6 address produces an\n`A`/`AAAA` record; anything else is treated as a `CNAME` target. `None`\ndisables DNS record sync regardless of per-domain opt-in.","default":null},"external_url":{"type":["string","null"],"default":null},"insecure_tls":{"type":"boolean","description":"Skip TLS certificate verification on outbound HTTP clients built by the\nserver (deployer, agent, remote service client). Strictly opt-in for\noperators running self-signed control plane / worker certs on a trusted\ninternal network. Worker→control-plane traffic that traverses the public\ninternet must keep this `false` — otherwise a MitM steals the join token.","default":false},"internal_url":{"type":["string","null"],"description":"URL that service containers use to reach the Temps API from *inside*\nthe Docker network (OTLP metrics ingest, agent callbacks, etc.). On\nDocker Desktop this defaults to `http://host.docker.internal:`;\non Linux it requires the `host.docker.internal:host-gateway` host\nmapping (which Temps adds to provisioned containers). Distinct from\n`external_url`, which is the public-facing address.","default":null},"letsencrypt":{"oneOf":[{"$ref":"#/components/schemas/LetsEncryptSettings"}],"default":{"email":null,"environment":"production"}},"monitoring":{"oneOf":[{"$ref":"#/components/schemas/MonitoringSettings","description":"Metrics observability settings. Controls the MetricsStore backend,\nscrape interval, and tiered retention windows."}],"default":{"enabled":false,"store":"timescale_db","scrape_interval_secs":30,"retention_raw_days":7,"retention_hourly_days":90,"retention_daily_years":2,"clickhouse_url":null}},"multi_node":{"oneOf":[{"$ref":"#/components/schemas/MultiNodeSettings"}],"default":{"join_token_hash":null,"private_address":null,"legacy_shared_token_enabled":true,"cluster_ca_cert_pem":null,"cluster_ca_key_encrypted":null,"require_mtls":false,"node_cpu_alert_percent":90.0,"node_memory_alert_percent":90.0,"node_disk_alert_percent":90.0}},"observability_compression":{"oneOf":[{"$ref":"#/components/schemas/ObservabilityCompressionSettings","description":"TimescaleDB compression delays for immutable observability data.\nChanges are applied at runtime by the Settings API."}],"default":{"proxy_logs_after_hours":24,"otel_spans_after_hours":24}},"observability_retention":{"oneOf":[{"$ref":"#/components/schemas/ObservabilityRetentionSettings","description":"Retention windows for raw proxy and OpenTelemetry telemetry.\nTimescaleDB policies are updated at runtime by the Settings API."}],"default":{"proxy_logs_days":30,"otel_spans_days":90,"otel_logs_days":90,"otel_metrics_days":90}},"on_demand_tls":{"oneOf":[{"$ref":"#/components/schemas/OnDemandTlsSettings"}],"default":{"enabled":false,"zone":null,"max_concurrent":3,"hourly_cap":10,"deployment_url_mode":"http"}},"preview_domain":{"type":"string","default":"localho.st"},"preview_gateway":{"oneOf":[{"$ref":"#/components/schemas/PreviewGatewaySettings"}],"default":{"image":"ghcr.io/gotempsh/temps-preview-gateway:latest","host_port":8090,"auto_upgrade":true}},"rate_limiting":{"oneOf":[{"$ref":"#/components/schemas/RateLimitSettings"}],"default":{"enabled":false,"max_requests_per_minute":60,"max_requests_per_hour":1000,"whitelist_ips":[],"blacklist_ips":[]}},"require_mfa_for_admins":{"type":"boolean","description":"When `true`, any user holding the `Admin` role must have MFA enrolled\n(`users.mfa_enabled = true`) to complete a **password** login. Users\nwithout MFA enrolled are rejected with a typed error instructing them\nto enroll before retrying. This only gates the password-login path\n(`AuthService::login`) -- SSO/OIDC logins are handled by a separate\ncode path (`OidcService::resolve_user` + `oidc_handler`) and are\nintentionally unaffected, since federating identity to a\nproperly-hardened IdP is itself an acceptable alternative to local\nTOTP MFA. Modeled as a settings row (not an env var) per CLAUDE.md so\nan operator can flip it at runtime via the Settings API without\nrestarting the binary.","default":false},"screenshots":{"oneOf":[{"$ref":"#/components/schemas/ScreenshotSettings"}],"default":{"enabled":false,"provider":"local","url":""}},"security_headers":{"oneOf":[{"$ref":"#/components/schemas/SecurityHeadersSettings"}],"default":{"enabled":false,"preset":"moderate","content_security_policy":"default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self'; frame-ancestors 'self'","x_frame_options":"SAMEORIGIN","x_content_type_options":"nosniff","x_xss_protection":"1; mode=block","strict_transport_security":"max-age=31536000; includeSubDomains","referrer_policy":"strict-origin-when-cross-origin","permissions_policy":"geolocation=(), microphone=(), camera=()"}},"self_update":{"oneOf":[{"$ref":"#/components/schemas/SelfUpdateSettings","description":"One-click \"Update now\" from the console. Enabled by default; an admin\ncan turn it off here to keep upgrades on the CLI/config-management path.\n\nThis is the *soft* switch — it is stored in the database, so whoever can\nwrite settings can also turn it back on. Operators who need an upgrade\npath that no console session can re-open should start the server with\n`--disable-self-update`, which wins over this field unconditionally."}],"default":{"enabled":true,"channel":null}},"setup_complete":{"type":"boolean","description":"Set to `true` by `temps setup` (all modes) once initial configuration\nhas been applied. The web onboarding wizard reads this from the server\nand skips itself when true, preventing the \"Configure Base Domain\" wall\nfrom appearing on installs that were already configured via the CLI.","default":false}}},"AppSettingsResponse":{"type":"object","description":"Safe response for application settings that masks sensitive fields","required":["preview_domain","screenshots","letsencrypt","dns_provider","security_headers","rate_limiting","docker_registry","disk_space_alert","container_logs","agent_sandbox","ai_config","preview_gateway","multi_node","monitoring","observability_compression","observability_retention","effective_metrics_store","effective_observability_store","insecure_tls","setup_complete","require_mfa_for_admins","cluster_dns","build_limits","ai_chat_limits","self_update"],"properties":{"agent_sandbox":{"$ref":"#/components/schemas/AgentSandboxSettingsMasked"},"ai_chat_limits":{"$ref":"#/components/schemas/AiChatLimitsSettings","description":"Per-turn limits for the AI chat. No sensitive content."},"ai_config":{"$ref":"#/components/schemas/AiConfigSettings"},"build_limits":{"$ref":"#/components/schemas/BuildLimitsSettings","description":"Build-time resource limits (control-plane only). No sensitive content,\npassed through as-is."},"cluster_dns":{"$ref":"#/components/schemas/ClusterDnsSettings","description":"Cluster-DNS resolver settings (ADR-024, experimental beta). No masking\nneeded — `enabled` is a plain bool with no sensitive content. Passed\nthrough as-is so the settings UI can read and toggle the flag."},"container_logs":{"$ref":"#/components/schemas/ContainerLogSettings"},"disk_space_alert":{"$ref":"#/components/schemas/DiskSpaceAlertSettings"},"dns_provider":{"$ref":"#/components/schemas/DnsProviderSettingsMasked"},"docker_registry":{"$ref":"#/components/schemas/DockerRegistrySettingsMasked"},"edge_target":{"type":["string","null"],"description":"Public edge target that synced DNS records point at (IP → A/AAAA, else CNAME)."},"effective_metrics_store":{"$ref":"#/components/schemas/MetricsStoreKind","description":"The storage backend the runtime is **actually** using for metrics,\nafter reconciling the `monitoring.store` toggle with the server's\n`TEMPS_CLICKHOUSE_*` configuration. When `monitoring.store` is\n`click_house` but those env vars are not fully set, the runtime falls\nback to TimescaleDB — in that case this reports `timescale_db` even\nthough `monitoring.store` says `click_house`. The UI shows this as the\neffective backend and warns when it diverges from the configured store."},"effective_observability_store":{"$ref":"#/components/schemas/MetricsStoreKind","description":"Storage backend actually used for proxy logs, OTel spans, and OTel\nmetrics. OTel logs remain TimescaleDB-backed. Unlike resource metrics,\nthese domains switch to ClickHouse whenever the server-level ClickHouse\nconnection is configured; they do not use the monitoring store toggle."},"external_url":{"type":["string","null"]},"insecure_tls":{"type":"boolean"},"internal_url":{"type":["string","null"]},"letsencrypt":{"$ref":"#/components/schemas/LetsEncryptSettings"},"monitored_services_count":{"type":["integer","null"],"format":"int64","description":"Number of enabled, running services the MetricsScraper currently\nincludes. Used for the lightweight storage estimate in the UI.","minimum":0},"monitoring":{"$ref":"#/components/schemas/MonitoringSettingsMasked"},"multi_node":{"$ref":"#/components/schemas/MultiNodeSettingsMasked"},"observability_compression":{"$ref":"#/components/schemas/ObservabilityCompressionSettings","description":"TimescaleDB compression delays for immutable proxy logs and OTel spans."},"observability_retention":{"$ref":"#/components/schemas/ObservabilityRetentionSettings","description":"Retention windows for raw proxy logs and OpenTelemetry data."},"preview_domain":{"type":"string"},"preview_gateway":{"$ref":"#/components/schemas/PreviewGatewaySettingsMasked"},"rate_limiting":{"$ref":"#/components/schemas/RateLimitSettings"},"require_mfa_for_admins":{"type":"boolean","description":"When enabled, Admin-role accounts without MFA enrolled are rejected\nat password login (bherila/temps#32). SSO/OIDC logins are unaffected."},"screenshots":{"$ref":"#/components/schemas/ScreenshotSettings"},"security_headers":{"$ref":"#/components/schemas/SecurityHeadersSettings"},"self_update":{"$ref":"#/components/schemas/SelfUpdateSettings","description":"Whether admins may apply a release from the console. This is the\ndatabase-backed toggle only — a server started with\n`--disable-self-update` refuses regardless of what this says, which\n`GET /settings/update` reports as the authoritative answer."},"setup_complete":{"type":"boolean","description":"Whether `temps setup` has been run at least once. The web onboarding\nwizard checks this field on load and skips itself when true."}}},"ApplyHostnameModeRequest":{"type":"object","description":"Request to apply a hostname mode (recompute + optional DNS sync).","required":["mode"],"properties":{"mode":{"type":"string","description":"Target mode to apply: `\"standard\"` or `\"flat\"`."},"sync_dns":{"type":"boolean","description":"Also reconcile the provider's DNS zone for the affected hostnames."}}},"ArchiveFlagResponse":{"type":"object","required":["key"],"properties":{"archived_at":{"type":["string","null"]},"key":{"type":"string"}}},"ArchiveMode":{"type":"string","enum":["off","on","always","unknown"]},"AssignRoleRequest":{"type":"object","required":["user_id","role_type"],"properties":{"role_type":{"type":"string"},"user_id":{"type":"integer","format":"int32"}}},"AttachScheduleServicesRequest":{"type":"object","description":"Body for `POST /api/backups/schedules/{id}/services` — attach external\nservices to a backup schedule. Idempotent.","required":["service_ids"],"properties":{"service_ids":{"type":"array","items":{"type":"integer","format":"int32"},"description":"External service ids to attach. Duplicates are de-duplicated server-side."}}},"AttachScheduleServicesResponse":{"type":"object","description":"Response for `POST /api/backups/schedules/{id}/services`.","required":["inserted","total_attached"],"properties":{"inserted":{"type":"integer","format":"int64","description":"Number of rows actually inserted (excludes rows skipped by\n`ON CONFLICT DO NOTHING`).","minimum":0},"total_attached":{"type":"integer","description":"Total number of services now attached to the schedule.","minimum":0}}},"AuditLogIpInfo":{"type":"object","description":"IP address information in audit log","required":["ip"],"properties":{"city":{"type":["string","null"],"description":"City name","example":"San Francisco"},"country":{"type":["string","null"],"description":"Country code","example":"US"},"ip":{"type":"string","description":"IP address","example":"192.168.1.1"},"latitude":{"type":["number","null"],"format":"double","description":"Latitude","example":37.7749},"longitude":{"type":["number","null"],"format":"double","description":"Longitude","example":122.4194}}},"AuditLogResponse":{"type":"object","description":"Response type for audit log entries","required":["id","operation_type","audit_date"],"properties":{"audit_date":{"type":"integer","format":"int64","description":"When the action occurred","example":11932193},"data":{"description":"Additional context about the action"},"id":{"type":"integer","format":"int32","description":"Unique identifier for the audit log entry"},"ip_address":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AuditLogIpInfo","description":"IP address details"}]},"operation_type":{"type":"string","description":"The type of action that was performed","example":"USER_LOGIN"},"user":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AuditLogUserInfo","description":"User details who performed the action"}]},"user_id":{"type":["integer","null"],"format":"int32","description":"The user who performed the action (`null` when that account has\nsince been deleted; `data` retains the original actor context)"}}},"AuditLogUserInfo":{"type":"object","description":"User information in audit log","required":["id","name","email"],"properties":{"email":{"type":"string","description":"User's email","example":"john.doe@example.com"},"id":{"type":"integer","format":"int32","description":"User ID"},"name":{"type":"string","description":"User's name","example":"John Doe"}}},"AuthFlavorDto":{"type":"object","description":"One auth flavor surfaced to the UI. Mirrors `AuthFlavor` in the catalog\nbut without the seed-path / env-var fields the frontend doesn't need\n(those are server-side only — exposing them just bloats the response).","required":["id","label","description","format"],"properties":{"description":{"type":"string"},"env_var":{"type":["string","null"],"description":"For `api_key` format: the env var name that will be set inside the\nsandbox. Useful for showing the user \"we'll set OPENAI_API_KEY\" so\nthey know what their key controls."},"format":{"type":"string","description":"`api_key`, `oauth_token`, or `config_file` — drives which input UI\nthe settings page renders (single-line vs. multi-line textarea)."},"id":{"type":"string"},"label":{"type":"string"}}},"AuthResponse":{"type":"object","required":["success","message","mfa_required","mfa_enrollment_required","password_change_required"],"properties":{"message":{"type":"string"},"mfa_enrollment_required":{"type":"boolean"},"mfa_required":{"type":"boolean"},"mfa_setup":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/MfaSetupResponse"}]},"password_change_required":{"type":"boolean"},"success":{"type":"boolean"},"user_id":{"type":["integer","null"],"format":"int32"}}},"AuthStatusResponse":{"type":"object","required":["status"],"properties":{"cli_token":{"type":["string","null"]},"status":{"type":"string"}}},"AuthTokenResponse":{"type":"object","required":["access_token","refresh_token","expires_at"],"properties":{"access_token":{"type":"string"},"expires_at":{"type":"integer","format":"int64"},"refresh_token":{"type":"string"}}},"AutoWatchParams":{"type":"object","description":"Auto-watch (Watchdog-style) detector parameters (stub — not evaluated).","properties":{"direction":{"$ref":"#/components/schemas/Direction","description":"The engine self-tunes the band; the user supplies only the direction."}}},"AutofixRunConfig":{"type":"object","description":"User-chosen per-run options, persisted as JSON in `agent_runs.run_config`.\nEvery field is optional — unset fields fall back to the provider defaults\nin settings, then to built-in defaults.","properties":{"branch":{"type":["string","null"],"description":"Branch to clone instead of the project's main branch.","default":null},"max_turns":{"type":["integer","null"],"format":"int32","description":"Per-run turn cap applied to every phase of this run. Only enforced\nfor CLIs with a turn flag (Claude Code); Codex/OpenCode run to\ncompletion. `None` uses the provider's per-phase defaults.","default":null},"model":{"type":["string","null"],"description":"Model id for the chosen provider. `None` uses the provider's saved\ndefault model, or the CLI's own default.","default":null},"provider":{"type":["string","null"],"description":"AI provider id (\"claude_cli\", \"codex_cli\", \"opencode\"). `None` uses\nthe platform default provider from agent sandbox settings.","default":null}}},"AutofixerRunResponse":{"type":"object","required":["id","project_id","status","tokens_input","tokens_output","files_changed","created_at"],"properties":{"ai_model":{"type":["string","null"]},"ai_output":{"type":["string","null"]},"ai_provider":{"type":["string","null"],"description":"AI provider slug this run executes with (e.g. claude_cli, codex_cli)."},"analysis":{"type":["string","null"]},"branch_name":{"type":["string","null"]},"completed_at":{"type":["string","null"]},"created_at":{"type":"string"},"error_message":{"type":["string","null"]},"files_changed":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"phase":{"type":["string","null"]},"pr_number":{"type":["integer","null"],"format":"int32"},"pr_url":{"type":["string","null"]},"project_id":{"type":"integer","format":"int32"},"run_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AutofixRunConfig","description":"Per-run options the run was started with; used to prefill the\nretry / start-over dialog."}]},"started_at":{"type":["string","null"]},"status":{"type":"string"},"tokens_input":{"type":"integer","format":"int32"},"tokens_output":{"type":"integer","format":"int32"},"trigger_source_id":{"type":["integer","null"],"format":"int32"},"user_context":{"type":["string","null"]}}},"AutofixerRunWithLogsResponse":{"type":"object","required":["run","logs"],"properties":{"logs":{"type":"array","items":{"$ref":"#/components/schemas/AgentRunLogResponse"}},"run":{"$ref":"#/components/schemas/AutofixerRunResponse"}}},"AvailableContainerInfo":{"type":"object","description":"Available Docker container that can be imported as a service","required":["container_id","container_name","image","version","service_type","is_running"],"properties":{"container_id":{"type":"string","description":"Container ID or name","example":"abc123def456"},"container_name":{"type":"string","description":"Container display name","example":"my-postgres"},"exposed_ports":{"type":"array","items":{"type":"integer","format":"int32","minimum":0},"description":"Exposed ports (e.g., [5432] for PostgreSQL, [6379] for Redis)"},"image":{"type":"string","description":"Docker image name (e.g., \"gotempsh/postgres-walg:18-bookworm\")","example":"gotempsh/postgres-walg:18-bookworm"},"is_running":{"type":"boolean","description":"Whether the container is currently running","example":true},"service_type":{"$ref":"#/components/schemas/ServiceTypeRoute","description":"Service type this container represents"},"version":{"type":"string","description":"Extracted version from image","example":"18"}}},"AvailablePermissions":{"type":"object","description":"Response containing all available permissions for frontend validation","required":["permissions","roles"],"properties":{"permissions":{"type":"array","items":{"$ref":"#/components/schemas/PermissionInfo"},"description":"All available permissions in the system"},"roles":{"type":"array","items":{"$ref":"#/components/schemas/RoleInfo"},"description":"All available roles"}}},"BackupAlertListResponse":{"type":"object","description":"Response body for the list-backup-alerts endpoint.","required":["alerts"],"properties":{"alerts":{"type":"array","items":{"$ref":"#/components/schemas/BackupAlertResponse"},"description":"All currently open (unresolved) alerts, newest first."}}},"BackupAlertResponse":{"type":"object","description":"A single open backup alert surfaced in the UI banner.\n\nAlerts are auto-opened by the watcher and auto-resolved when the triggering\ncondition clears. No manual dismiss is required or supported.\n\nThe optional `schedule_s3_source_id` field is included so the UI can\ndeep-link an `overdue_schedule` alert to the S3 source detail page that\nhosts the schedule. `stalled_job` alerts no longer carry a deep-link\ntarget — the alert message text contains the backup id for display.","required":["id","kind","severity","message","opened_at"],"properties":{"id":{"type":"integer","format":"int64","description":"Database id of the alert row."},"kind":{"type":"string","description":"`\"overdue_schedule\"` or `\"stalled_job\"`."},"message":{"type":"string","description":"Human-readable description of the alert condition."},"opened_at":{"type":"string","description":"RFC 3339 timestamp when the alert was opened.","example":"2026-05-15T10:00:00Z"},"schedule_id":{"type":["integer","null"],"format":"int32","description":"FK to `backup_schedules.id`. Set for `overdue_schedule` alerts."},"schedule_name":{"type":["string","null"],"description":"Human-readable name of the linked schedule, if applicable."},"schedule_s3_source_id":{"type":["integer","null"],"format":"int32","description":"FK to `backup_schedules.s3_source_id`. The UI uses this to deep-link\nthe alert to the S3 source detail page that hosts the schedule.\nSet for `overdue_schedule` alerts."},"severity":{"type":"string","description":"`\"warning\"` or `\"critical\"`."}}},"BackupResponse":{"type":"object","description":"Response type for backup","required":["id","name","backup_id","backup_type","state","started_at","s3_source_id","s3_location","metadata","compression_type","created_by","tags"],"properties":{"attempts":{"type":["integer","null"],"format":"int32","description":"How many times this job has been claimed and run. `null` for legacy\nbackups with no `backup_jobs` row."},"backup_id":{"type":"string"},"backup_type":{"type":"string"},"checksum":{"type":["string","null"]},"completed_at":{"type":["integer","null"],"format":"int64"},"compression_type":{"type":"string"},"created_by":{"type":"integer","format":"int32"},"current_step":{"type":["string","null"],"description":"Name of the engine step currently executing (e.g., `\"walg_push\"`).\n`null` when no `backup_jobs` row exists for this backup (legacy rows\npre-dating ADR-014), or when the job has not yet completed its first step."},"error_message":{"type":["string","null"]},"expires_at":{"type":["integer","null"],"format":"int64"},"external_service":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ExternalServiceSummary","description":"External service that owns this backup (Redis, Postgres, etc.).\n`null` for control-plane backups (the Temps server's own database)."}]},"file_count":{"type":["integer","null"],"format":"int32"},"id":{"type":"integer","format":"int32"},"live_size_bytes":{"type":["integer","null"],"format":"int64","description":"Best-effort partial size while a backup is still running, computed\nby listing the S3 prefix. Null when the backup is finished\n(`size_bytes` is authoritative in that case)."},"max_attempts":{"type":["integer","null"],"format":"int32","description":"Maximum attempts before the job is permanently failed. `null` for\nlegacy backups."},"max_runtime_secs":{"type":["integer","null"],"format":"int64","description":"Resolved wall-clock timeout for this backup job (seconds). `null` for\nlegacy backups. Derived from the three-tier resolution order:\ncaller override → schedule override → engine default."},"metadata":{},"name":{"type":"string"},"s3_location":{"type":"string"},"s3_source_id":{"type":"integer","format":"int32"},"schedule_id":{"type":["integer","null"],"format":"int32"},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Final size of the backup once completed. Null while running."},"started_at":{"type":"integer","format":"int64"},"state":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}}}},"BackupScheduleResponse":{"type":"object","description":"Response type for backup schedule","required":["id","name","backup_type","retention_period","s3_source_id","schedule_expression","enabled","created_at","updated_at","tags","target_all_services","include_control_plane"],"properties":{"backup_type":{"type":"string"},"created_at":{"type":"integer","format":"int64"},"description":{"type":["string","null"]},"enabled":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"include_control_plane":{"type":"boolean","description":"When `true`, every run also produces a `control_plane` backup\n(Temps's own Postgres). When `false`, only the external service\nfan-out happens."},"last_run":{"type":["integer","null"],"format":"int64"},"max_runtime_secs":{"type":["integer","null"],"format":"int64","description":"Per-schedule wall-clock timeout override for backup jobs (seconds).\n`null` means the engine-family default is used. See\n`temps_backup_core::timeouts::default_max_runtime_secs`."},"name":{"type":"string"},"next_run":{"type":["integer","null"],"format":"int64"},"retention_period":{"type":"integer","format":"int32"},"s3_source_id":{"type":"integer","format":"int32"},"schedule_expression":{"type":"string","example":"0 0 * * *"},"tags":{"type":"array","items":{"type":"string"}},"target_all_services":{"type":"boolean","description":"When `true`, the schedule auto-includes every external service on\nthe host (and any future ones). When `false`, the schedule only\ntargets services attached via `backup_schedule_services`."},"updated_at":{"type":"integer","format":"int64"}}},"BitbucketAuthInput":{"oneOf":[{"type":"object","description":"Personal / Workspace / Repository Access Token.","required":["token","type"],"properties":{"token":{"type":"string","description":"The Bitbucket access token value."},"type":{"type":"string","enum":["access_token"]}}},{"type":"object","description":"HTTP Basic / App Password authentication.","required":["username","password","type"],"properties":{"password":{"type":"string","description":"App password generated in Bitbucket security settings."},"type":{"type":"string","enum":["app_password"]},"username":{"type":"string","description":"Bitbucket account username."}}}],"description":"Authentication input for a Bitbucket Cloud provider. Use `access_token` for\na Repository or Workspace Access Token (PAT), or `username` + `app_password`\nfor App Password (HTTP Basic) authentication."},"BlobResponse":{"type":"object","description":"Response after uploading a blob","required":["url","pathname","contentType","size","uploadedAt"],"properties":{"contentType":{"type":"string","description":"Content type of the blob","example":"image/png"},"pathname":{"type":"string","description":"Original pathname","example":"images/avatar-abc123.png"},"size":{"type":"integer","format":"int64","description":"Size in bytes","example":12345},"uploadedAt":{"type":"string","format":"date-time","description":"Upload timestamp","example":"2025-01-03T12:00:00Z"},"url":{"type":"string","description":"URL path to access the blob","example":"/api/blob/123/images/avatar-abc123.png"}}},"BlobStatusResponse":{"type":"object","description":"Response for Blob service status","required":["enabled","healthy"],"properties":{"docker_image":{"type":["string","null"],"description":"Docker image being used","example":"ghcr.io/rustfs/rustfs:0.5.0"},"enabled":{"type":"boolean","description":"Whether the Blob service is enabled","example":true},"healthy":{"type":"boolean","description":"Whether the service is healthy","example":true},"version":{"type":["string","null"],"description":"Current version (if running)","example":"0.5.0"}}},"BranchInfo":{"type":"object","required":["name","commit_sha","protected"],"properties":{"commit_sha":{"type":"string"},"name":{"type":"string"},"protected":{"type":"boolean"}}},"BranchListResponse":{"type":"object","required":["branches"],"properties":{"branches":{"type":"array","items":{"$ref":"#/components/schemas/BranchInfo"}}}},"BrowserCount":{"type":"object","required":["browser","count","percentage"],"properties":{"browser":{"type":"string"},"count":{"type":"integer","format":"int64"},"percentage":{"type":"number","format":"double"}}},"BrowsersQuery":{"type":"object","required":["start_date","end_date","project_id"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"BuildConfiguration":{"type":"object","description":"Build configuration (for building images from source)","required":["context","args"],"properties":{"args":{"type":"object","description":"Build arguments","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"context":{"type":"string","description":"Build context (Dockerfile path or buildpack)"},"dockerfile":{"type":["string","null"],"description":"Dockerfile path (relative to context)"},"target":{"type":["string","null"],"description":"Target stage (for multi-stage builds)"}}},"BuildLimitsSettings":{"type":"object","description":"Control-plane build resource limits.\n\nCaps how many builds run concurrently AND how much CPU/memory each build\nis allowed to consume. A single global semaphore in the deployer crate\ngates every `DockerRuntime::build_image` call to `max_concurrent`. When\nthe semaphore is full, additional builds queue and wait — they do not\nfail. Per-build CPU/memory caps are forwarded to Docker via\n`BuildImageOptions { memory, cpuquota, cpuperiod }`.\n\n`cpu_limit_cores = 0.0` or `memory_limit_mb = 0` means \"no explicit cap\"\n— fall back to the legacy 50%-of-host heuristic for backwards\ncompatibility with operators who never visit the settings page.","properties":{"cpu_limit_cores":{"type":"number","format":"float","description":"CPU cores allowed per build (float, e.g. 2.0 = 2 cores, 0.5 = half\na core). 0 means \"use the legacy 50%-of-host default\".","default":0.0,"example":2.0,"minimum":0},"max_concurrent":{"type":"integer","format":"int32","description":"Maximum number of `docker build` operations allowed to run at the\nsame time on the control plane. Additional builds queue. Min 1.","default":2,"example":2,"minimum":1},"memory_limit_mb":{"type":"integer","format":"int32","description":"Memory allowed per build, in megabytes. 0 means \"use the legacy\n50%-of-host default\". Docker enforces this as a hard cap — builds\nthat exceed it OOM-kill.","default":0,"example":2048,"minimum":0}}},"CancelBackupResponse":{"type":"object","description":"Response body for cancel endpoints.","required":["cancelled"],"properties":{"cancelled":{"type":"integer","format":"int64","description":"Number of rows that were actually flipped to `failed`. `0` is a valid\nsuccess and means the backup was already terminal — the call is\nidempotent.","minimum":0}}},"CertStatusResponse":{"type":"object","description":"Current on-demand cert status for a single hostname (ADR-018 §5). Backs\n`GET /domains/by-host/{hostname}/cert-status`.","required":["hostname"],"properties":{"backoff_until":{"type":["integer","null"],"format":"int64","description":"On-demand negative-cache deadline (epoch millis), when in backoff."},"hostname":{"type":"string","description":"SNI hostname."},"last_attempt":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/OnDemandCertAttemptResponse","description":"The most recent on-demand issuance attempt for this hostname, if any."}]},"status":{"type":["string","null"],"description":"Current cert lifecycle status from the `domains` row, when one exists."}}},"ChallengeConfig":{"type":"object","description":"Challenge configuration (future feature)\nFor CAPTCHA, JS challenges, proof-of-work, etc.","required":["challengeType","difficulty"],"properties":{"challengeType":{"type":"string","description":"Challenge type: \"captcha\", \"js_challenge\", \"proof_of_work\""},"difficulty":{"type":"integer","format":"int32","description":"Challenge difficulty level (1-10)","minimum":0},"protectedPaths":{"type":"array","items":{"type":"string"},"description":"Paths that require challenges"}}},"ChallengeError":{"type":"object","required":["type","detail","status"],"properties":{"detail":{"type":"string","description":"Human-readable error description"},"status":{"type":"integer","format":"int32","description":"HTTP status code"},"type":{"type":"string","description":"Error type (e.g., \"urn:ietf:params:acme:error:unauthorized\")"}}},"ChallengeValidationStatus":{"type":"object","required":["type","url","status","token"],"properties":{"error":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ChallengeError","description":"Error details if validation failed"}]},"status":{"type":"string","description":"Challenge status (e.g., \"pending\", \"valid\", \"invalid\")"},"token":{"type":"string","description":"Challenge token"},"type":{"type":"string","description":"Challenge type (e.g., \"dns-01\", \"http-01\")"},"url":{"type":"string","description":"Challenge validation URL"},"validated":{"type":["string","null"],"description":"When the challenge was validated (if successful)"}}},"ChangePasswordRequest":{"type":"object","required":["current_password","new_password"],"properties":{"current_password":{"type":"string","example":"current_password_value"},"mfa_code":{"type":["string","null"],"description":"TOTP code (or recovery code). Required iff the user has MFA enabled.","example":"123456"},"new_password":{"type":"string","example":"new_password_value"},"revoke_other_sessions":{"type":"boolean","description":"When true, every session OTHER than the one making this request is\nrevoked. Defaults to false; the UI surfaces this as a checkbox."}}},"ChangeProjectSourceRequest":{"type":"object","description":"Change a project's source type to a Git-less type (docker_image /\nstatic_files / manual). Switching TO `git` is done via the Git settings\nendpoint (which also supplies the repository + provider connection).","required":["source_type"],"properties":{"source_type":{"$ref":"#/components/schemas/SourceType"}}},"ChatCompletionChoice":{"type":"object","required":["index","message"],"properties":{"finish_reason":{"type":["string","null"]},"index":{"type":"integer","format":"int32"},"message":{"$ref":"#/components/schemas/ChatMessage"}}},"ChatCompletionRequest":{"allOf":[{"type":["object","null"],"description":"Tolerates extra SDK fields (stream_options, logprobs, etc.)","additionalProperties":{},"propertyNames":{"type":"string"}},{"type":"object","required":["model","messages"],"properties":{"frequency_penalty":{"type":["number","null"],"format":"double"},"max_tokens":{"type":["integer","null"],"format":"int64"},"messages":{"type":"array","items":{"$ref":"#/components/schemas/ChatMessage"}},"model":{"type":"string"},"n":{"type":["integer","null"],"format":"int32"},"presence_penalty":{"type":["number","null"],"format":"double"},"response_format":{},"seed":{"type":["integer","null"],"format":"int64"},"stop":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/StopSequence"}]},"stream":{"type":"boolean"},"temperature":{"type":["number","null"],"format":"double"},"tool_choice":{},"tools":{"type":["array","null"],"items":{}},"top_p":{"type":["number","null"],"format":"double"},"user":{"type":["string","null"]}}}],"description":"OpenAI-compatible chat completion request.\nUses `deny_unknown_fields = false` (serde default) so that SDK-specific\nfields like `stream_options`, `logprobs`, `top_logprobs`, `logit_bias`,\n`parallel_tool_calls`, etc. are silently accepted without breaking."},"ChatCompletionResponse":{"type":"object","required":["id","object","created","model","choices"],"properties":{"choices":{"type":"array","items":{"$ref":"#/components/schemas/ChatCompletionChoice"}},"created":{"type":"integer","format":"int64"},"id":{"type":"string"},"model":{"type":"string"},"object":{"type":"string"},"usage":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/UsageInfo"}]}}},"ChatMessage":{"type":"object","required":["role"],"properties":{"content":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/MessageContent"}]},"name":{"type":["string","null"]},"role":{"type":"string"},"tool_call_id":{"type":["string","null"]},"tool_calls":{"type":["array","null"],"items":{}}}},"ChatReadinessResponse":{"type":"object","description":"What still has to be true before an AI chat can run a turn in this project.\n\nThe three gates are independent and fail for different reasons with different\nfixes, so they are reported separately rather than collapsed into one boolean:\nan instance admin configures a provider (instance-wide), while the two toggles\nare per-project. Collapsing them would leave the user with \"AI unavailable\"\nand no idea which of three places to go.","required":["ai_configured","chat_enabled","write_actions_enabled"],"properties":{"ai_configured":{"type":"boolean","description":"An AI provider is configured on this instance. Fixed in\nSettings → AI Providers; instance-wide, not per project."},"chat_enabled":{"type":"boolean","description":"The per-project read-only chat toggle is on (the default)."},"write_actions_enabled":{"type":"boolean","description":"The per-project write-actions opt-in is on. Required for any flow where\nthe assistant *proposes* changes; irrelevant for read-only questions."}}},"ChildBackupEntryResponse":{"type":"object","description":"A single child backup entry in the `GET /backups/{id}/children` response.\n\nEach entry corresponds to one `external_service_backups` row joined with\n`external_services`, providing service metadata without a second request.","required":["id","service_id","service_name","service_type","state","backup_type","started_at","s3_location","compression_type"],"properties":{"backup_type":{"type":"string","description":"Backup variant (e.g. \"full\", \"incremental\")."},"compression_type":{"type":"string","description":"Compression algorithm used (e.g. \"gzip\", \"lz4\")."},"error_message":{"type":["string","null"],"description":"Engine-reported error message when `state = \"failed\"`."},"finished_at":{"type":["string","null"],"description":"When the child backup finished, if known.","example":"2025-01-15T14:35:00.456Z"},"id":{"type":"integer","format":"int32","description":"Row ID from `external_service_backups`."},"s3_location":{"type":"string","description":"Object key or `s3://` URL where the backup data lives."},"service_id":{"type":"integer","format":"int32","description":"FK to `external_services.id`."},"service_name":{"type":"string","description":"Human-readable name of the external service (e.g. \"redis-prod\")."},"service_type":{"type":"string","description":"Service type string (e.g. \"postgres\", \"redis\", \"mongodb\", \"s3\").","example":"postgres"},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Size of the child backup in bytes, if available."},"started_at":{"type":"string","description":"When the child backup started (RFC 3339).","example":"2025-01-15T14:30:00.123Z"},"state":{"type":"string","description":"Current state: \"pending\" | \"running\" | \"completed\" | \"failed\"."}}},"ChildBackupListResponse":{"type":"object","description":"Response body for `GET /backups/{id}/children`.\n\nReturns an empty `children` list (not 404) when the parent backup has no\nchild records (e.g. control-plane backups).","required":["children"],"properties":{"children":{"type":"array","items":{"$ref":"#/components/schemas/ChildBackupEntryResponse"},"description":"Zero or more child backup entries ordered by `external_service_backups.id` ASC."}}},"CleanupExpiredBackupsRequest":{"type":"object","properties":{"expected_backup_ids":{"type":["array","null"],"items":{"type":"string"},"description":"Exact candidates returned by the dry run. Execution fails if the\nretention selection has changed since preview."}}},"CliDeviceApproveRequest":{"type":"object","required":["user_code"],"properties":{"user_code":{"type":"string"}}},"CliDeviceApproveResponse":{"type":"object","required":["user_code","status"],"properties":{"status":{"type":"string"},"user_code":{"type":"string"}}},"CliDeviceLookupResponse":{"type":"object","required":["user_code","status","expires_at"],"properties":{"client_name":{"type":["string","null"]},"expires_at":{"type":"string","format":"date-time"},"requested_ip":{"type":["string","null"]},"status":{"type":"string","description":"`pending` | `approved` | `denied` | `expired`."},"user_code":{"type":"string"}}},"CliDevicePollRequest":{"type":"object","required":["device_code"],"properties":{"device_code":{"type":"string"}}},"CliDevicePollResponse":{"oneOf":[{"type":"object","description":"Still waiting on the user to approve in the browser.","required":["status"],"properties":{"status":{"type":"string","enum":["authorization_pending"]}}},{"type":"object","description":"CLI is polling faster than the server-suggested interval.","required":["status"],"properties":{"status":{"type":"string","enum":["slow_down"]}}},{"type":"object","description":"User denied the request in the browser.","required":["status"],"properties":{"status":{"type":"string","enum":["access_denied"]}}},{"type":"object","description":"The session has expired without approval.","required":["status"],"properties":{"status":{"type":"string","enum":["expired_token"]}}},{"type":"object","description":"The session was approved; this is the only response that carries\nthe API key. The key is returned exactly once and then cleared\nfrom the session row.","required":["user_id","email","role","api_key","key_prefix","status"],"properties":{"api_key":{"type":"string"},"email":{"type":"string"},"expires_at":{"type":["string","null"],"format":"date-time"},"key_prefix":{"type":"string"},"role":{"type":"string"},"status":{"type":"string","enum":["approved"]},"user_id":{"type":"integer","format":"int32"}}}]},"CliDeviceStartRequest":{"type":"object","properties":{"client_name":{"type":["string","null"],"description":"Friendly hostname / client identifier shown in the browser approval\nscreen. Sanitized before display.","example":"dviejo-mac.local"}}},"CliDeviceStartResponse":{"type":"object","required":["device_code","user_code","verification_uri","verification_uri_complete","expires_in","interval"],"properties":{"device_code":{"type":"string","description":"Opaque secret the CLI polls with. Never display to a human."},"expires_in":{"type":"integer","format":"int64","description":"Seconds until the device_code expires."},"interval":{"type":"integer","format":"int64","description":"Suggested polling interval, in seconds."},"user_code":{"type":"string","description":"Short human-readable code the user types into the browser.","example":"ABCD-1234"},"verification_uri":{"type":"string","description":"Base verification URL — the CLI may display this when the\npre-filled URL is too long to be useful.","example":"https://temps.example.com/cli-login"},"verification_uri_complete":{"type":"string","description":"`verification_uri` with `user_code` pre-filled. Open this directly.","example":"https://temps.example.com/cli-login/ABCD-1234"}}},"CliLoginRequest":{"type":"object","required":["username","password"],"properties":{"password":{"type":"string"},"username":{"type":"string"}}},"CloudProvider":{"type":"string","description":"Cloud provider detected from node metadata","enum":["aws","gcp","azure","hetzner","digitalocean","other"]},"CloudflareConfig":{"type":"object","description":"Configuration for a Cloudflare Email Sending notification provider.\n\nNotifications are delivered through Cloudflare's transactional Email Sending\nAPI. Only the account, token, sender and recipients are configured here —\nsubject and body are derived from each notification.","required":["account_id","api_token","from_address","to_addresses"],"properties":{"account_id":{"type":"string","description":"Cloudflare account id that owns the Email Sending configuration.","example":"023e105f4ecef8ad9ca31a8372d0c353"},"api_token":{"type":"string","description":"Cloudflare API token with the Email Sending permission. Encrypted at\nrest and masked in normal API responses."},"from_address":{"type":"string","description":"Verified sender address (must belong to a domain enabled for Cloudflare\nEmail Sending).","example":"welcome@infracf.example.com"},"from_name":{"type":["string","null"],"description":"Optional human-friendly sender name shown in the recipient's inbox."},"to_addresses":{"type":"array","items":{"type":"string"},"description":"Recipients that should receive the notification."}}},"ClusterCapacity":{"type":"object","description":"Total cluster capacity (sum of node allocatable resources)","required":["node_count","cpu_millis","memory_mb"],"properties":{"cpu_millis":{"type":"integer","format":"int64","description":"Total allocatable CPU in millicores"},"memory_mb":{"type":"integer","format":"int64","description":"Total allocatable memory in MB"},"node_count":{"type":"integer","description":"Number of nodes","minimum":0}}},"ClusterDnsSettings":{"type":"object","description":"Cluster-DNS resolver settings (ADR-024, experimental beta).\n\nWhen `enabled`, the Temps control plane starts a Hickory DNS resolver and\ninjects it as the first nameserver into every deployed container via\n`HostConfig.Dns` — giving containers the ability to resolve `*.temps.local`\nFQDNs for service-to-service communication. Worker nodes pick this flag up\nfrom the `/api/internal/nodes/{id}/network/peers` wire response and gate\ntheir own per-node resolver the same way.\n\n**Default: `false` (disabled).**\n\nWhy disabled by default: a production incident showed that when the injected\nHickory resolver was slow or transiently unresponsive for a non-`*.temps.local`\n(external) hostname, glibc's resolver cycled through all three nameservers\n(`172.20.0.1`, `1.1.1.1`, `8.8.8.8`) at ~5 s timeout × 2 attempts each,\ncausing 22–27 s delays for outbound TCP connections. Disabling the injection\nrestores Docker's embedded DNS as the sole resolver, eliminating that failure\nmode. Operators running single/multi-node installs that depend on\n`*.temps.local` resolution must explicitly opt in by setting `enabled: true`.\n\n`bool` defaults to `false` in Rust and JSON (`#[serde(default)]`), so the\nsafe-off behaviour is automatic for new installs and legacy settings rows.","properties":{"enabled":{"type":"boolean","description":"Master switch. When `false` (default), no custom DNS is injected into\ncontainers — they use Docker's embedded DNS which forwards to the host's\nown `resolv.conf`. When `true`, the control-plane Hickory resolver is\nstarted and its bridge IP is injected as the first nameserver so\n`*.temps.local` FQDNs resolve inside containers.","default":false,"example":false}}},"ClusterHealthReportResponse":{"type":"object","description":"Response body for `GET /external-services/{id}/cluster-health`.","required":["checked_at","monitor_response_ms","members"],"properties":{"checked_at":{"type":"string","description":"ISO-8601 wall-clock when the report was generated.","example":"2025-10-12T12:15:47.609192Z"},"members":{"type":"array","items":{"$ref":"#/components/schemas/ClusterMemberHealthResponse"}},"monitor_error":{"type":["string","null"],"description":"Set when the monitor itself was unreachable. UI shows a banner."},"monitor_response_ms":{"type":"integer","format":"int64","description":"Round-trip to query the monitor (ms)."}}},"ClusterMemberHealthResponse":{"type":"object","description":"One row in the cluster Members table — see `GET /external-services/{id}/cluster-health`.","required":["nodename","nodehost","nodeport","reported_state","goal_state","health","seconds_since_report","candidate_priority","replication_quorum"],"properties":{"candidate_priority":{"type":"integer","format":"int32"},"goal_state":{"type":"string","description":"What the monitor *wants* the node to be. Differs from\n`reported_state` mid-transition (failover, demotion, etc.)."},"health":{"type":"integer","format":"int32","description":"pg_auto_failover liveness signal: `1` healthy, `0` unknown\n(no recent report), `-1` unhealthy."},"nodehost":{"type":"string"},"nodename":{"type":"string"},"nodeport":{"type":"integer","format":"int32"},"replay_lag_ms":{"type":["integer","null"],"format":"int64","description":"`replay_lag` from `pg_stat_replication`, in milliseconds."},"replication_quorum":{"type":"boolean"},"reported_state":{"type":"string","description":"What the node *last told the monitor* it was. Stale during outages."},"seconds_since_report":{"type":"integer","format":"int64","description":"Wall-clock seconds since the node last reported in."},"sync_state":{"type":["string","null"],"description":"`sync` / `quorum` / `async` for secondaries; `null` for the primary."}}},"ClusterMemberRequest":{"type":"object","description":"Request spec for a single cluster member.","required":["role"],"properties":{"node_id":{"type":["integer","null"],"format":"int32","description":"Target worker node ID. Omit or null to run on the control plane."},"role":{"type":"string","description":"Service-type-specific role (e.g., \"monitor\", \"primary\", \"replica\")","example":"primary"}}},"CmdBody":{"type":"object","required":["command"],"properties":{"args":{"type":"array","items":{"type":"string"},"description":"Arguments to pass to the binary. Defaults to empty."},"command":{"type":"string","description":"Binary name (argv[0]) — e.g. `\"ls\"`, `\"node\"`. The SDK sends this\nseparately from `args`."},"cwd":{"type":["string","null"],"description":"Working directory override."},"env":{"type":"object","description":"Extra env vars.","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"sudo":{"type":"boolean","description":"When true, the SDK runs the command privileged. We ignore it today\n— the underlying provider always runs as the sandbox's own user."},"wait":{"type":"boolean","description":"When true, the response is an `application/x-ndjson` stream where\nthe first line is the running-command envelope and the second line\nis the finished-command envelope with `exitCode`."}}},"CmdInner":{"type":"object","description":"Inner `command` object — matches the SDK's zod validator exactly.\n`exitCode` is `null` until the command terminates; `startedAt` is Unix\nepoch milliseconds.","required":["id","name","args","cwd","sandboxId","startedAt"],"properties":{"args":{"type":"array","items":{"type":"string"}},"cwd":{"type":"string"},"exitCode":{"type":["integer","null"],"format":"int32"},"id":{"type":"string"},"name":{"type":"string"},"sandboxId":{"type":"string"},"startedAt":{"type":"integer","format":"int64"}}},"CmdKillBody":{"type":"object","description":"SDK-shaped kill body. The SDK sends `{signal: AbortSignal}` but only\nuses the signal for HTTP request abortion client-side; there's no\nsignal name on the wire.","properties":{"force":{"type":"boolean","description":"Optional: when true, SIGKILL instead of SIGTERM."}}},"CmdResponse":{"type":"object","description":"`@vercel/sandbox` envelope: `{ command: {...} }`.","required":["command"],"properties":{"command":{"$ref":"#/components/schemas/CmdInner"}}},"CommitExistsResponse":{"type":"object","required":["exists"],"properties":{"commit":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/CommitInfo","description":"Commit metadata when the requested SHA exists."}]},"commit_sha":{"type":["string","null"]},"exists":{"type":"boolean"}}},"CommitInfo":{"type":"object","required":["sha","message","author","author_email","date"],"properties":{"author":{"type":"string","description":"Author name"},"author_email":{"type":"string","description":"Author email"},"date":{"type":"string","format":"date-time","description":"Commit date in ISO 8601 format","example":"2025-10-12T12:15:47.609192Z"},"message":{"type":"string","description":"Commit message"},"sha":{"type":"string","description":"Commit SHA hash"}}},"CommitListResponse":{"type":"object","required":["commits"],"properties":{"commits":{"type":"array","items":{"$ref":"#/components/schemas/CommitInfo"}}}},"Comparator":{"type":"string","description":"Comparator for static/forecast threshold detectors. Serializes to the\nkeyword forms `gt|gte|lt|lte` (NOT the SQL operators used by\n`temps-monitoring::compare`).","enum":["gt","gte","lt","lte"]},"ComposePublicPort":{"type":"object","description":"A port that should be exposed publicly through the proxy for a compose service.","required":["service","port"],"properties":{"port":{"type":"integer","format":"int32","description":"Container port to expose (e.g. 8123)","minimum":0},"service":{"type":"string","description":"Compose service name (e.g. \"web\", \"clickhouse\")"}}},"ConnectionListQuery":{"type":"object","properties":{"direction":{"type":["string","null"]},"page":{"type":["integer","null"],"format":"int64","minimum":0},"per_page":{"type":["integer","null"],"format":"int64","minimum":0},"sort":{"type":["string","null"]}}},"ConnectionListResponse":{"type":"object","required":["connections","total_count","page","per_page"],"properties":{"connections":{"type":"array","items":{"$ref":"#/components/schemas/ConnectionResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"per_page":{"type":"integer","format":"int64","minimum":0},"total_count":{"type":"integer","minimum":0}}},"ConnectionResponse":{"type":"object","required":["id","provider_id","account_name","account_type","is_active","is_expired","syncing","synced_repository_count","health_status","consecutive_health_failures","created_at","updated_at"],"properties":{"account_name":{"type":"string"},"account_type":{"type":"string"},"consecutive_health_failures":{"type":"integer","format":"int32"},"created_at":{"type":"string","format":"date-time"},"health_message":{"type":["string","null"],"description":"Human-readable reason when health_status is \"unhealthy\"; null otherwise."},"health_status":{"type":"string","description":"Current health status: \"healthy\", \"unhealthy\", or \"unknown\"."},"id":{"type":"integer","format":"int32"},"installation_id":{"type":["string","null"]},"is_active":{"type":"boolean"},"is_expired":{"type":"boolean"},"last_health_check_at":{"type":["string","null"],"format":"date-time"},"last_synced_at":{"type":["string","null"],"format":"date-time"},"provider_id":{"type":"integer","format":"int32"},"synced_repository_count":{"type":"integer","format":"int32","description":"Running count of repositories persisted by the current (or most\nrecent) sync. Resets to 0 when a new sync begins; useful for showing\nlive progress on large syncs."},"syncing":{"type":"boolean"},"updated_at":{"type":"string","format":"date-time"},"user_id":{"type":["integer","null"],"format":"int32"}}},"ConnectionTestResult":{"type":"object","description":"Connection test result","required":["success","message"],"properties":{"message":{"type":"string"},"success":{"type":"boolean"}}},"ConsoleEventPayload":{"type":"object","description":"Payload for server-side event ingestion via the console API.\n\nThe app backend reads the encrypted `_temps_visitor_id` and `_temps_sid`\ncookie values from the user's request and forwards them here.\nTemps decrypts them server-side to resolve visitor/session identity.","required":["event_name","environment_id","deployment_id"],"properties":{"deployment_id":{"type":"integer","format":"int32","description":"Deployment ID to attribute the event to"},"environment_id":{"type":"integer","format":"int32","description":"Environment ID to attribute the event to"},"event_data":{"description":"Arbitrary JSON event data"},"event_name":{"type":"string","description":"Event name (e.g. \"purchase\", \"signup\", custom event names)"},"request_path":{"type":"string","description":"Page path context (defaults to \"/\")"},"request_query":{"type":"string","description":"Query string context"},"session_id":{"type":["string","null"],"description":"Encrypted `_temps_sid` cookie value from the user's browser"},"visitor_id":{"type":["string","null"],"description":"Encrypted `_temps_visitor_id` cookie value from the user's browser"}}},"ContainerActionResponse":{"type":"object","description":"Response indicating success of container state change","required":["container_id","container_name","action","status","message"],"properties":{"action":{"type":"string"},"container_id":{"type":"string"},"container_name":{"type":"string"},"message":{"type":"string"},"status":{"type":"string"}}},"ContainerDetailResponse":{"type":"object","description":"Detailed container information with environment variables and metrics","required":["id","container_id","container_name","image_name","status","deployment_id","created_at","deployed_at","container_port","environment_variables"],"properties":{"container_id":{"type":"string"},"container_name":{"type":"string"},"container_port":{"type":"integer","format":"int32","description":"Port inside the container"},"cpu_limit_cores":{"type":["number","null"],"format":"double","description":"CPU limit in whole cores (e.g. 1.0). None when no limit is configured."},"created_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"deployed_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"deployment_id":{"type":"integer","format":"int32"},"environment_variables":{"type":"array","items":{"$ref":"#/components/schemas/EnvVarResponse"},"description":"Environment variables (sensitive values masked)"},"error_message":{"type":["string","null"],"description":"Free-form error string from Docker's container state on exit."},"exit_code":{"type":["integer","null"],"format":"int32","description":"Process exit code reported by Docker. None while still running."},"exit_reason":{"type":["string","null"],"description":"Human-readable reason the container exited."},"finished_at":{"type":["string","null"],"description":"When the container exited (Docker's FinishedAt). None while running.","example":"2025-10-12T12:16:47.609192Z"},"host_port":{"type":["integer","null"],"format":"int32","description":"Port on the host machine"},"id":{"type":"integer","format":"int32"},"image_name":{"type":"string"},"oom_killed":{"type":["boolean","null"],"description":"True when Docker's OOM killer terminated the container."},"ready_at":{"type":["string","null"],"example":"2025-10-12T12:16:47.609192Z"},"resource_limits":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ResourceLimitsResponse","description":"Resource limits"}]},"restart_count":{"type":["integer","null"],"format":"int64","description":"Container restart count from Docker"},"service_name":{"type":["string","null"],"description":"Compose service name (e.g. \"web\", \"redis\"). None for single-container deployments."},"service_url":{"type":["string","null"],"description":"Per-service URL for compose deployments"},"started_at":{"type":["string","null"],"description":"When the container's main process most recently started.","example":"2025-10-12T12:15:50.000000Z"},"status":{"type":"string"}}},"ContainerEnvironmentVariableValueResponse":{"type":"object","required":["value"],"properties":{"value":{"type":"string"}}},"ContainerInfoResponse":{"type":"object","required":["container_id","container_name","image_name","status","created_at"],"properties":{"container_id":{"type":"string"},"container_name":{"type":"string"},"cpu_limit_cores":{"type":["number","null"],"format":"double","description":"CPU limit in whole cores (e.g. 1.0). None when no limit is configured."},"created_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"error_message":{"type":["string","null"],"description":"Free-form error string from Docker's container state on exit."},"exit_code":{"type":["integer","null"],"format":"int32","description":"Process exit code reported by Docker. None while still running."},"exit_reason":{"type":["string","null"],"description":"Human-readable reason the container exited (e.g. \"OOMKilled\",\n\"Killed by SIGKILL (exit code 137)\", \"Exit code 1\"). None while running."},"finished_at":{"type":["string","null"],"description":"When the container exited (Docker's FinishedAt). None while running.","example":"2025-10-12T12:16:47.609192Z"},"image_name":{"type":"string"},"node_name":{"type":["string","null"],"description":"Node name where this container is running. None for local (single-node) deployments."},"oom_killed":{"type":["boolean","null"],"description":"True when Docker's OOM killer terminated the container."},"restart_count":{"type":["integer","null"],"format":"int64","description":"Container restart count from Docker. The UI shows a chip when this is\n> 0 so a crash loop is visible without opening detail."},"service_name":{"type":["string","null"],"description":"Compose service name (e.g. \"web\", \"redis\"). None for single-container deployments."},"service_url":{"type":["string","null"],"description":"Per-service URL for compose deployments (e.g. \"https://web-myapp.localho.st\")"},"started_at":{"type":["string","null"],"description":"When the container's main process most recently started. The UI uses\nthis for the uptime label so the count resets when a container is\nrestarted in place. None for containers that never started.","example":"2025-10-12T12:15:50.000000Z"},"status":{"type":"string"}}},"ContainerInventoryItem":{"type":"object","description":"A container reported by the agent during heartbeat reconciliation.","required":["container_id","container_name"],"properties":{"container_id":{"type":"string","description":"Docker container ID"},"container_name":{"type":"string","description":"Docker container name"}}},"ContainerListResponse":{"type":"object","required":["containers","total"],"properties":{"containers":{"type":"array","items":{"$ref":"#/components/schemas/ContainerInfoResponse"}},"total":{"type":"integer","minimum":0}}},"ContainerLogSettings":{"type":"object","description":"Docker container log rotation settings\nControls the `--log-opt max-size` and `--log-opt max-file` for containers","properties":{"max_file":{"type":"integer","format":"int32","description":"Maximum number of rotated log files to keep (e.g., 3 means up to 3 x max_size total)","default":3,"example":3,"minimum":0},"max_size":{"type":"string","description":"Maximum size of each log file (e.g., \"50m\", \"100m\", \"1g\")\nDocker default is unlimited; we default to \"50m\" to prevent disk exhaustion","default":"50m","example":"50m"},"service_max_file":{"type":"integer","format":"int32","description":"Maximum rotated log files for external service containers","default":3,"example":3,"minimum":0},"service_max_size":{"type":"string","description":"Maximum size for external service container logs (postgres, redis, etc.)\nDefaults to \"20m\" since services are typically less verbose than app containers","default":"20m","example":"20m"}}},"ContainerLogsQuery":{"type":"object","properties":{"container_name":{"type":["string","null"],"description":"Optional container name to get logs from (if deployment has multiple containers)"},"end_date":{"type":["integer","null"],"format":"int64"},"follow":{"type":"boolean","description":"Follow log output in real-time (default: true for backward compatibility)"},"start_date":{"type":["integer","null"],"format":"int64"},"tail":{"type":["string","null"]},"timestamps":{"type":"boolean","description":"Include timestamps in log output (default: false)"}}},"ContainerMetricHistoryPoint":{"type":"object","description":"One bucketed data point of a container resource metric time series.","required":["time","value"],"properties":{"time":{"type":"string","description":"Bucket timestamp (ISO 8601 with `Z` suffix).","example":"2025-10-12T12:15:00+00:00"},"value":{"type":"number","format":"double","description":"Averaged metric value for the bucket."}}},"ContainerMetricsHistoryQuery":{"type":"object","description":"Query parameters for the container metrics history endpoint.","required":["metric"],"properties":{"metric":{"type":"string","description":"Dotted metric name, e.g. `container.cpu_percent` or\n`container.memory_used_bytes`."},"range":{"type":"string","description":"Time window: `1h`, `6h`, `24h`, or `7d` (defaults to `1h`)."}}},"ContainerMetricsResponse":{"type":"object","description":"Container resource metrics (CPU, memory usage)","required":["container_id","container_name","cpu_percent","memory_bytes","network_rx_bytes","network_tx_bytes","timestamp"],"properties":{"container_id":{"type":"string"},"container_name":{"type":"string"},"cpu_limit_cores":{"type":["number","null"],"format":"double","description":"CPU limit in whole cores (e.g. 1.0). None = no limit."},"cpu_percent":{"type":"number","format":"double","description":"CPU usage as a multi-core percentage (Docker convention: 200 = 2 cores\nfully pinned). Divide by 100 to get cores used."},"memory_bytes":{"type":"integer","format":"int64","description":"Memory usage in bytes","minimum":0},"memory_limit_bytes":{"type":["integer","null"],"format":"int64","description":"Memory limit in bytes (if set)","minimum":0},"memory_percent":{"type":["number","null"],"format":"double","description":"Memory usage percentage (0-100) if limit is set"},"network_rx_bytes":{"type":"integer","format":"int64","description":"Network bytes received","minimum":0},"network_tx_bytes":{"type":"integer","format":"int64","description":"Network bytes transmitted","minimum":0},"timestamp":{"type":"string","description":"Timestamp of metrics collection","example":"2025-10-12T12:15:47.609192Z"}}},"ContainerResponse":{"type":"object","required":["name","container_type","can_contain_containers","can_contain_entities","metadata"],"properties":{"can_contain_containers":{"type":"boolean","description":"Can this container hold other containers?","example":true},"can_contain_entities":{"type":"boolean","description":"Can this container hold entities (tables, collections, etc.)?","example":false},"child_container_type":{"type":["string","null"],"description":"Type of child containers (if can_contain_containers is true)","example":"schema"},"container_type":{"type":"string","description":"Container type (database, schema, keyspace, bucket, etc.)","example":"database"},"entity_count_hint":{"type":["string","null"],"description":"Hint for UI on expected entity count (small = sidebar, large = pagination)","example":"large"},"entity_type_label":{"type":["string","null"],"description":"Label for entity type (if can_contain_entities is true)","example":"table"},"metadata":{"description":"Additional metadata"},"name":{"type":"string","description":"Container name","example":"mydb"}}},"ContainerRuntimeInfo":{"type":"object","description":"Snapshot of a container's lifecycle state from `docker inspect`.\n`restart_count` and `oom_killed` are the load-bearing fields when\ndiagnosing crash loops — the kernel OOM killer never reaches the\napplication's logs, so seeing `oom_killed=true` is the only signal\nthat a memory limit was the cause.","required":["role","container_name","resource_limits"],"properties":{"container_id":{"type":["string","null"],"description":"Container Docker id, when present. None = container does not exist\n(was never created or was removed externally)."},"container_name":{"type":"string","description":"Stable name of the Docker container (e.g. `postgres-mydb`)."},"exit_code":{"type":["integer","null"],"format":"int64","description":"Last container exit code, when known. Non-zero = unclean stop."},"finished_at":{"type":["string","null"],"description":"ISO-8601 timestamp of the most recent termination, when known."},"image":{"type":["string","null"],"description":"Currently-effective Docker image (e.g. `gotempsh/postgres-walg:18-bookworm`)."},"oom_killed":{"type":["boolean","null"],"description":"True when the container's last termination was caused by the\nkernel OOM killer. Set if the user enabled hard memory limits\nand the working set exceeded them."},"resource_limits":{"$ref":"#/components/schemas/ServiceResourceLimits","description":"Currently-applied resource limits read off the container's\n`HostConfig`. Compare this against the user-configured limits to\ndetect drift (an old container that never picked up new caps)."},"restart_count":{"type":["integer","null"],"format":"int64","description":"Total restarts since the container was created. Useful for\ndetecting crash loops — a steady stream means something is killing\nthe container repeatedly (frequently OOM)."},"role":{"type":"string","description":"`service_members.role` for cluster members; \"standalone\" otherwise."},"started_at":{"type":["string","null"],"description":"ISO-8601 timestamp of when the container last started. None when\nit has never started (i.e. created but never run)."},"status":{"type":["string","null"],"description":"Bollard container state (\"running\", \"exited\", \"dead\", etc.). None\nwhen the container does not exist."}}},"ContainerStatsSample":{"type":"object","description":"Live resource usage sample for a single container.\n\n`cpu_percent` is computed by Docker's standard formula:\n ((cpu_delta / system_delta) * online_cpus) * 100\n`memory_percent` is `(memory_usage / memory_limit) * 100` — when no\nmemory limit is set the limit reported by Docker is the host's total\nRAM, so a 5% reading means \"5% of host RAM\", not \"5% of allocated\".","required":["role","container_name"],"properties":{"container_name":{"type":"string"},"cpu_percent":{"type":["number","null"],"format":"double","description":"CPU usage as a percentage. `None` when the container is not running\n(Docker returns no usable counters)."},"memory_limit_bytes":{"type":["integer","null"],"format":"int64","description":"Memory limit in bytes (host RAM if no limit set).","minimum":0},"memory_percent":{"type":["number","null"],"format":"double","description":"Memory usage as a percentage of `memory_limit_bytes`."},"memory_usage_bytes":{"type":["integer","null"],"format":"int64","description":"Resident memory usage in bytes.","minimum":0},"online_cpus":{"type":["integer","null"],"format":"int32","description":"Number of cores Docker observed at sample time. Used by the UI\nto label \"x/y cores\" instead of just a percent.","minimum":0},"role":{"type":"string"}}},"ContentPart":{"type":"object","required":["type"],"properties":{"image_url":{},"text":{"type":["string","null"]},"type":{"type":"string"}}},"ContextLine":{"type":"object","description":"A line in context response","required":["timestamp","level","message","line_offset","is_match"],"properties":{"fields":{},"is_match":{"type":"boolean","description":"Whether this line matched the original search"},"level":{"$ref":"#/components/schemas/LogLevel"},"line_offset":{"type":"integer","format":"int32"},"message":{"type":"string"},"timestamp":{"type":"string"}}},"ContextLogsRequest":{"type":"object","required":["chunk_id","line_offset"],"properties":{"chunk_id":{"type":"string"},"line_offset":{"type":"integer","format":"int32"},"lines":{"type":["integer","null"],"format":"int32","description":"Number of context lines before and after (default: 25)","minimum":0}}},"ContextLogsResponse":{"type":"object","required":["lines","target_index"],"properties":{"lines":{"type":"array","items":{"$ref":"#/components/schemas/ContextLine"}},"target_index":{"type":"integer","minimum":0}}},"ConversationDetailResponse":{"allOf":[{"$ref":"#/components/schemas/ConversationResponse"},{"type":"object","required":["messages"],"properties":{"messages":{"type":"array","items":{"$ref":"#/components/schemas/MessageResponse"},"description":"Turns oldest-first. The `system` seed message is omitted (internal)."}}}]},"ConversationResponse":{"type":"object","required":["public_id","context_type","context_id","status","created_at","last_activity_at"],"properties":{"context_id":{"type":"string"},"context_type":{"type":"string"},"created_at":{"type":"string"},"last_activity_at":{"type":"string"},"public_id":{"type":"string"},"status":{"type":"string"},"title":{"type":["string","null"]}}},"ConversationSummary":{"type":"object","description":"A conversation summary grouping related AI invocations.","required":["conversation_id","message_count","total_input_tokens","total_output_tokens","total_tokens","total_cost_microcents","avg_latency_ms","models_used","first_at","last_at"],"properties":{"avg_latency_ms":{"type":"number","format":"double"},"conversation_id":{"type":"string"},"first_at":{"type":"string"},"last_at":{"type":"string"},"message_count":{"type":"integer","format":"int64"},"models_used":{"type":"array","items":{"type":"string"}},"total_cost_microcents":{"type":"integer","format":"int64"},"total_input_tokens":{"type":"integer","format":"int64"},"total_output_tokens":{"type":"integer","format":"int64"},"total_tokens":{"type":"integer","format":"int64"}}},"ConversationsQueryParams":{"type":"object","properties":{"from":{"type":["string","null"],"description":"ISO 8601 start time (defaults to 24h ago)"},"limit":{"type":["integer","null"],"format":"int64","description":"Max results (defaults to 50, max 100)","minimum":0},"model":{"type":["string","null"],"description":"Filter by model name"},"tags":{"type":["string","null"],"description":"Filter by tags (comma-separated, AND logic)"},"to":{"type":["string","null"],"description":"ISO 8601 end time (defaults to now)"},"user_id":{"type":["integer","null"],"format":"int32","description":"Filter by user ID"}}},"CopyBlobRequest":{"type":"object","description":"Request to copy a blob","required":["fromUrl","toPathname"],"properties":{"fromUrl":{"type":"string","description":"Source blob URL or pathname","example":"/api/blob/10/images/avatar.png"},"projectId":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1},"toPathname":{"type":"string","description":"Destination pathname","example":"images/avatar-copy.png"}}},"CostAnalysis":{"type":"object","description":"Full cluster cost + rightsizing analysis attached to an import plan.","required":["nodes","capacity","requested","usage_source","overprovisioning","recommendation","notes"],"properties":{"actual_usage":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ResourceFootprint","description":"Measured usage from the metrics API (`metrics.k8s.io`).\n`None` when metrics-server is not installed."}]},"capacity":{"$ref":"#/components/schemas/ClusterCapacity","description":"Total cluster capacity (sum of node allocatable resources)"},"control_plane_monthly_usd":{"type":["number","null"],"format":"double","description":"Managed control-plane fee included in `current_monthly_usd` (EKS/GKE\ncharge ~$73/mo per cluster). `None` when not applicable/unknown."},"current_monthly_usd":{"type":["number","null"],"format":"double","description":"Estimated total infrastructure cost per month in USD (compute nodes +\ncontrol-plane fee). `None` when no node could be priced."},"nodes":{"type":"array","items":{"$ref":"#/components/schemas/NodeCostInfo"},"description":"Per-node inventory with price estimates where the instance type is known"},"notes":{"type":"array","items":{"type":"string"},"description":"Honesty notes: what could not be measured, which numbers are\nestimates, and any assumptions made. Always shown to the user."},"overprovisioning":{"$ref":"#/components/schemas/OverprovisioningAssessment","description":"Requests-vs-capacity-vs-usage assessment"},"provider":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/CloudProvider","description":"Detected cloud provider (from node `providerID` prefixes)"}]},"recommendation":{"$ref":"#/components/schemas/TargetRecommendation","description":"The temps/Hetzner target sizing and savings estimate"},"requested":{"$ref":"#/components/schemas/ResourceFootprint","description":"Sum of pod resource *requests* across running pods — what the\nscheduler has reserved, i.e. what the cluster is sized for."},"usage_source":{"$ref":"#/components/schemas/UsageSource","description":"How the usage numbers were obtained (drives UI wording)"}}},"CreateAlertRuleRequest":{"type":"object","required":["name","trigger_type"],"properties":{"cooldown_minutes":{"type":"integer","format":"int32","description":"Minimum minutes between notifications for same rule+group"},"enabled":{"type":"boolean"},"environment_filter":{"type":["integer","null"],"format":"int32","description":"Optional environment ID to filter alerts"},"error_level_filter":{"type":["string","null"],"description":"Optional error type/level filter"},"name":{"type":"string"},"notification_priority":{"type":"string","description":"Notification priority: Low, Normal, High, Critical"},"trigger_config":{"description":"Trigger-specific configuration (e.g., {\"count\": 100, \"window_minutes\": 60} for frequency)"},"trigger_type":{"type":"string","description":"Trigger type: new_issue, regression, frequency, new_user, user_count, status_change"}}},"CreateApiKeyRequest":{"type":"object","required":["name","role_type"],"properties":{"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"name":{"type":"string"},"permissions":{"type":["array","null"],"items":{"type":"string"},"example":["projects:read","deployments:read"]},"role_type":{"type":"string","example":"admin"}}},"CreateApiKeyResponse":{"type":"object","required":["id","name","key_prefix","role_type","api_key","created_at"],"properties":{"api_key":{"type":"string"},"created_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00Z"},"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"id":{"type":"integer","format":"int32"},"key_prefix":{"type":"string"},"name":{"type":"string"},"permissions":{"type":["array","null"],"items":{"type":"string"}},"role_type":{"type":"string"}}},"CreateBackupScheduleRequest":{"type":"object","required":["name","backup_type","retention_period","schedule_expression","enabled","tags"],"properties":{"backup_type":{"type":"string"},"description":{"type":["string","null"]},"enabled":{"type":"boolean"},"include_control_plane":{"type":["boolean","null"],"description":"When `true` (default), every run also produces a `control_plane`\nbackup of Temps's own database. Operators who use Temps purely as\na backup orchestrator for external DBs can set this to `false` to\nkeep the run history focused on those services."},"max_runtime_secs":{"type":["integer","null"],"format":"int64","description":"Optional wall-clock timeout override for jobs created by this schedule\n(seconds). When set, overrides the engine-family default. `null` means\n\"use engine default.\" The per-job `max_runtime_secs` in\n`EnqueueJobParams` can still override this for ad-hoc triggers."},"name":{"type":"string"},"retention_period":{"type":"integer","format":"int32"},"s3_source_id":{"type":["integer","null"],"format":"int32","description":"Optional S3 source. If omitted, the current default S3 source is used."},"schedule_expression":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"target_all_services":{"type":["boolean","null"],"description":"When `true` (default), the schedule backs up every external service\non the host — including databases created in the future. When\n`false`, the schedule backs up only the services explicitly attached\nvia `POST /backups/schedules/{id}/services`. Omit to use the default."}}},"CreateBitbucketRequest":{"type":"object","required":["name","auth"],"properties":{"auth":{"$ref":"#/components/schemas/BitbucketAuthInput","description":"Authentication credentials — either an access token or an app password."},"name":{"type":"string","description":"Display name for this provider."}}},"CreateCloudflareProviderRequest":{"type":"object","required":["name","config"],"properties":{"config":{"$ref":"#/components/schemas/CloudflareConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":"string"}}},"CreateConversationRequest":{"type":"object","required":["context_type","context_id"],"properties":{"context_id":{"type":"string","description":"The entity id (ints stringified)."},"context_type":{"type":"string","description":"e.g. `\"deployment\"`."}}},"CreateDSNRequest":{"type":"object","properties":{"base_url":{"type":["string","null"]},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"name":{"type":["string","null"]}}},"CreateDashboardRequest":{"type":"object","required":["project_id","name","layout"],"properties":{"layout":{"$ref":"#/components/schemas/DashboardLayout"},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"}}},"CreateDeploymentTokenRequest":{"type":"object","required":["name"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32","description":"Optional deployment ID - if set, token is scoped to a specific deployment"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Optional environment ID - if not set, token applies to all environments"},"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"name":{"type":"string"},"permissions":{"type":["array","null"],"items":{"type":"string"},"description":"List of permissions (e.g., [\"visitors:enrich\", \"emails:send\"])\nIf not provided, defaults to full access","example":["visitors:enrich","emails:send"]}}},"CreateDeploymentTokenResponse":{"type":"object","required":["id","project_id","name","token_prefix","token","created_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00Z"},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"permissions":{"type":["array","null"],"items":{"type":"string"}},"project_id":{"type":"integer","format":"int32"},"token":{"type":"string","description":"The full token value - only returned on creation"},"token_prefix":{"type":"string"}}},"CreateDnsProviderRequest":{"type":"object","description":"Request to create a new DNS provider","required":["name","provider_type","credentials"],"properties":{"credentials":{"$ref":"#/components/schemas/DnsProviderCredentials","description":"Provider credentials"},"description":{"type":["string","null"],"description":"Optional description"},"name":{"type":"string","description":"User-friendly name","example":"My Cloudflare"},"provider_type":{"$ref":"#/components/schemas/DnsProviderType","description":"Provider type"}}},"CreateDomainRequest":{"type":"object","required":["domain"],"properties":{"challenge_type":{"type":"string","description":"Challenge type for Let's Encrypt validation. Options: \"http-01\" (default) or \"dns-01\""},"domain":{"type":"string"}}},"CreateEmailDomainRequest":{"type":"object","required":["provider_id","domain"],"properties":{"domain":{"type":"string","description":"Domain name (e.g., \"updates.example.com\")","example":"updates.example.com"},"provider_id":{"type":"integer","format":"int32","description":"Provider ID to use for this domain"}}},"CreateEmailProviderRequest":{"type":"object","required":["name","provider_type","region"],"properties":{"name":{"type":"string","description":"User-friendly name for the provider","example":"My AWS SES"},"provider_type":{"$ref":"#/components/schemas/EmailProviderTypeRoute","description":"Provider type"},"region":{"type":"string","description":"Cloud region. For SMTP this is informational only — the host/port carry the real routing.","example":"us-east-1"},"scaleway_credentials":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ScalewayCredentialsRequest","description":"Scaleway credentials (required if provider_type is scaleway)"}]},"ses_credentials":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SesCredentialsRequest","description":"AWS SES credentials (required if provider_type is ses)"}]},"smtp_credentials":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SmtpCredentialsRequest","description":"Generic SMTP credentials (required if provider_type is smtp). Use when\nyou only have SMTP creds and want to import an already-set-up domain."}]},"sns_topic_arn":{"type":["string","null"],"description":"Exact SNS topic allowed to deliver SES events for this provider."}}},"CreateEnvironmentRequest":{"type":"object","required":["name","branch"],"properties":{"branch":{"type":"string"},"name":{"type":"string"},"set_as_preview":{"type":"boolean","description":"If true, set this environment as the preview environment for the project"}}},"CreateEnvironmentVariableRequest":{"type":"object","required":["key","value","environment_ids"],"properties":{"environment_ids":{"type":"array","items":{"type":"integer","format":"int32"}},"include_in_preview":{"type":"boolean","description":"Include this environment variable in preview environments (default: true)"},"is_secret":{"type":"boolean","description":"When true the variable is treated as write-only: never returned in\nplaintext from the API, masked in the UI, and updates that omit the\nvalue preserve the existing ciphertext. The flag is one-way — secret\nvars cannot be demoted back to regular vars."},"key":{"type":"string"},"value":{"type":"string"}}},"CreateExternalServiceRequest":{"type":"object","required":["name","service_type","parameters"],"properties":{"members":{"type":"array","items":{"$ref":"#/components/schemas/ClusterMemberRequest"},"description":"Cluster member specifications. Required when topology is \"cluster\"."},"name":{"type":"string"},"node_id":{"type":["integer","null"],"format":"int32","description":"Target node ID for the service. Omit or null to run on the control plane."},"parameters":{"type":"object","additionalProperties":{},"propertyNames":{"type":"string"}},"service_type":{"$ref":"#/components/schemas/ServiceTypeRoute"},"topology":{"type":"string","description":"Service topology: \"standalone\" (default) or \"cluster\" (HA multi-member).","example":"standalone"},"version":{"type":["string","null"]}}},"CreateFlagRequest":{"type":"object","required":["key","value_type","default_value"],"properties":{"client_visible":{"type":"boolean","description":"Whether the flag may be exposed on the unauthenticated same-origin\nevaluation endpoint. Defaults to `false`: flags are server-only unless\nexplicitly opted in, because targeting rules can encode business logic."},"default_value":{"description":"Served whenever evaluation cannot do better. Must match `value_type`.\n\nLeft unannotated so utoipa emits a free-form schema: a bool flag's\ndefault is `false`, not an object, and `value_type = Object` would tell\nevery generated client otherwise."},"description":{"type":["string","null"]},"key":{"type":"string","description":"Stable key used in application code. Immutable after create.","example":"checkout.v2"},"value_type":{"$ref":"#/components/schemas/FlagValueType","description":"Fixed at create: retyping would invalidate every stored value and every\ncall site."}}},"CreateFunnelRequest":{"type":"object","required":["name","steps"],"properties":{"description":{"type":["string","null"]},"name":{"type":"string"},"steps":{"type":"array","items":{"$ref":"#/components/schemas/CreateFunnelStep"}}}},"CreateFunnelResponse":{"type":"object","required":["funnel_id","message"],"properties":{"funnel_id":{"type":"integer","format":"int32"},"message":{"type":"string"}}},"CreateFunnelStep":{"type":"object","required":["event_name"],"properties":{"event_filter":{"type":"array","items":{"$ref":"#/components/schemas/SmartFilter"}},"event_name":{"type":"string"}}},"CreateGenericRequest":{"type":"object","required":["name","clone_url"],"properties":{"base_url":{"type":["string","null"],"description":"Optional base URL of the git host for display purposes (no API is called)."},"clone_url":{"type":"string","description":"HTTPS clone URL for the repository, e.g. `https://git.example.com/org/repo.git`."},"name":{"type":"string","description":"Display name for this provider."},"token":{"type":["string","null"],"description":"Access token or password. Omit (or set to `null`) for public repositories."},"token_username":{"type":["string","null"],"description":"HTTP Basic username used with the token. Defaults to `x-access-token` when\nabsent or empty. Ignored for public (unauthenticated) repositories."}}},"CreateGitHubPATRequest":{"type":"object","required":["name","token"],"properties":{"name":{"type":"string"},"token":{"type":"string"}}},"CreateGitLabOAuthRequest":{"type":"object","required":["name","client_id","client_secret","redirect_uri"],"properties":{"base_url":{"type":["string","null"]},"client_id":{"type":"string"},"client_secret":{"type":"string"},"name":{"type":"string"},"redirect_uri":{"type":"string"}}},"CreateGitLabPATRequest":{"type":"object","required":["name","token"],"properties":{"base_url":{"type":["string","null"]},"name":{"type":"string"},"token":{"type":"string"}}},"CreateGiteaPATRequest":{"type":"object","required":["name","token","base_url"],"properties":{"base_url":{"type":"string","description":"HTTPS base URL of the Gitea instance, e.g. `https://git.example.com`."},"name":{"type":"string","description":"Display name for this provider."},"token":{"type":"string","description":"Personal access token issued by the Gitea instance."}}},"CreateIncidentRequest":{"type":"object","required":["title","severity"],"properties":{"description":{"type":["string","null"]},"environment_id":{"type":["integer","null"],"format":"int32"},"monitor_id":{"type":["integer","null"],"format":"int32"},"severity":{"type":"string"},"title":{"type":"string"}}},"CreateIntegrationBody":{"type":"object","required":["provider","signing_secret"],"properties":{"provider":{"type":"string","description":"Registered provider name, e.g. \"stripe\"."},"signing_secret":{"type":"string","description":"Signing secret from the provider's dashboard."}}},"CreateIpAccessControlRequest":{"type":"object","description":"Request to create an IP access control rule","required":["ip_address","action"],"properties":{"action":{"type":"string","description":"Action to take: \"block\" or \"allow\"","example":"block"},"ip_address":{"type":"string","description":"IP address in CIDR notation (e.g., \"192.168.1.1\" or \"10.0.0.0/24\")","example":"192.168.1.100"},"reason":{"type":["string","null"],"description":"Optional reason for the action","example":"Malicious activity detected"}}},"CreateMcpRequest":{"type":"object","required":["slug","name","config"],"properties":{"config":{"type":"object"},"description":{"type":["string","null"]},"name":{"type":"string"},"slug":{"type":"string"}}},"CreateMetricAlertRequest":{"type":"object","required":["project_id","name","metric_name","aggregation","detection_config","window_secs","for_duration_secs","severity","enabled"],"properties":{"aggregation":{"type":"string","description":"One of `avg|sum|min|max|count|rate|p50|p90|p95|p99`."},"detection_config":{"$ref":"#/components/schemas/DetectionConfig","description":"The detector: a discriminated union keyed by `kind`. Today only\n`{ \"kind\": \"static\", \"comparator\": \"gt\", \"threshold\": 500 }` is evaluable."},"dynamic_alerts":{"type":"boolean","description":"When true (and `group_by` is set) fire one independent alarm per breaching\nseries. Static detectors only. Default false."},"enabled":{"type":"boolean"},"for_duration_secs":{"type":"integer","format":"int32"},"group_by":{"type":"array","items":{"type":"string"},"description":"Label keys to break the metric down by, e.g. `[\"endpoint\",\"region\"]`. Empty\n(the default) = one aggregate stream. Max 2 keys; keys must match\n`[a-zA-Z0-9_.:-]`."},"grouped_notification_threshold":{"type":"integer","format":"int32","description":"When more than this many series transition to firing in the same tick, only\nthe first gets the expensive chart/AI enrichment. Range 1–1000, default 5."},"label_filters":{"type":"array","items":{"type":"array","items":false,"prefixItems":[{"type":"string"},{"type":"string"}]},"description":"AND-combined label equality filters: `[[\"key\",\"value\"],…]`. Empty = no\nfiltering (the default). Max 10 pairs; keys must match `[a-zA-Z0-9_.:-]`;\nvalues capped at 500 characters."},"max_series":{"type":"integer","format":"int32","description":"Cardinality cap for dynamic alerting: at most this many series (top by\n`|value|`). Range 1–100, default 20."},"metric_name":{"type":"string"},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"severity":{"type":"string","description":"One of `info|warning|critical`."},"window_secs":{"type":"integer","format":"int32"}}},"CreateMonitorRequest":{"type":"object","required":["name","monitor_type","environment_id"],"properties":{"check_interval_seconds":{"type":["integer","null"],"format":"int32"},"check_path":{"type":["string","null"]},"environment_id":{"type":"integer","format":"int32"},"monitor_type":{"type":"string"},"name":{"type":"string"}}},"CreateNotificationEmailProviderRequest":{"type":"object","required":["name","config"],"properties":{"config":{"$ref":"#/components/schemas/EmailConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":"string"}}},"CreateOidcProviderRequest":{"type":"object","required":["name","issuer_url","client_id","client_secret"],"properties":{"client_id":{"type":"string"},"client_secret":{"type":"string"},"default_role":{"type":"string"},"enabled":{"type":"boolean"},"group_claim":{"type":"string"},"issuer_url":{"type":"string"},"jit_provisioning":{"type":"boolean"},"name":{"type":"string"},"role_claim":{"type":"string"},"scopes":{"type":"string"},"template":{"type":"string"},"trust_idp_email":{"type":"boolean","description":"Defaults false. Set to true only for IdPs where an admin\ncontrols user provisioning (corporate Okta, Azure AD) and\nself-signup of arbitrary emails is not possible — see the\n`trust_idp_email` field on `oidc_providers::Model` for the\nsecurity tradeoff this enables."}}},"CreateOidcRoleMappingRequest":{"type":"object","required":["priority","idp_group","role"],"properties":{"idp_group":{"type":"string"},"priority":{"type":"integer","format":"int32"},"role":{"type":"string"}}},"CreatePlanRequest":{"type":"object","description":"Request to create an import plan","required":["source","workload_id"],"properties":{"credentials":{"$ref":"#/components/schemas/ImportCredentials","description":"Platform credentials (required for cloud platforms like Vercel, Railway)"},"repository_id":{"type":["integer","null"],"format":"int32","description":"Optional repository ID to associate with the import\nIf provided, preset will be detected from the repository"},"source":{"$ref":"#/components/schemas/ImportSource","description":"Source to import from"},"workload_id":{"$ref":"#/components/schemas/WorkloadId","description":"Workload ID to import"}}},"CreatePlanResponse":{"type":"object","description":"Response with created plan","required":["session_id","plan","validation","can_execute"],"properties":{"can_execute":{"type":"boolean","description":"Whether the plan can be executed"},"plan":{"$ref":"#/components/schemas/ImportPlan","description":"Generated import plan"},"session_id":{"type":"string","description":"Session ID for tracking"},"validation":{"$ref":"#/components/schemas/ValidationReport","description":"Validation report"}}},"CreatePrResponse":{"type":"object","required":["run","pr_url","pr_number","branch_name"],"properties":{"branch_name":{"type":"string"},"pr_number":{"type":"integer","format":"int32"},"pr_url":{"type":"string"},"run":{"$ref":"#/components/schemas/AutofixerRunResponse"}}},"CreateProjectAccessRequest":{"type":"object","required":["team_id","role"],"properties":{"role":{"$ref":"#/components/schemas/TeamRole"},"team_id":{"type":"integer","format":"int32"}}},"CreateProjectFromTemplateRequest":{"type":"object","description":"Request to create a project from a template\n\nSupports two deploy modes:\n * **Fork mode** — when `git_provider_connection_id` is set, the template\n repo is cloned into a new repository under the user's Git account and the\n project tracks that fork (git-push deploys, automatic deploy on push).\n * **One-click public-repo mode** — when `git_provider_connection_id` is\n omitted, the project deploys directly from the template's public source\n repository (no fork, no Git account required). This is the activation\n path: a brand-new user with no Git provider connected can still deploy a\n demo in one click. `repository_name` / `repository_owner` are ignored in\n this mode, and automatic-deploy-on-push is unavailable (there is no fork\n to receive webhooks).","required":["template_slug","project_name"],"properties":{"automatic_deploy":{"type":"boolean","description":"Enable automatic deployment on push (defaults to true). Only honoured in\nfork mode; public-repo deploys cannot receive push webhooks."},"environment_variables":{"type":"array","items":{"$ref":"#/components/schemas/EnvVarInput"},"description":"Environment variables to set (key-value pairs)"},"git_provider_connection_id":{"type":["integer","null"],"format":"int32","description":"Git provider connection ID. When omitted, the project deploys directly\nfrom the template's public source repository instead of forking it."},"private":{"type":"boolean","description":"Whether to make the repository private (defaults to true)"},"project_name":{"type":"string","description":"Name for the new project"},"repository_name":{"type":["string","null"],"description":"Name for the new repository to create. Required in fork mode; ignored in\none-click public-repo mode."},"repository_owner":{"type":["string","null"],"description":"Owner/organization for the new repository (defaults to authenticated user)"},"storage_service_ids":{"type":"array","items":{"type":"integer","format":"int32"},"description":"External storage service IDs to attach to the project"},"template_slug":{"type":"string","description":"Template slug to use as the base"}}},"CreateProjectFromTemplateResponse":{"type":"object","description":"Response after creating a project from template","required":["project_id","project_slug","project_name","repository_url","template_slug","message"],"properties":{"message":{"type":"string","description":"Message with additional info"},"project_id":{"type":"integer","format":"int32","description":"ID of the created project"},"project_name":{"type":"string","description":"Name of the created project"},"project_slug":{"type":"string","description":"Slug of the created project"},"repository_url":{"type":"string","description":"URL of the created repository"},"template_slug":{"type":"string","description":"Template that was used"}}},"CreateProjectRequest":{"type":"object","required":["name","directory","main_branch","preset","storage_service_ids"],"properties":{"automatic_deploy":{"type":["boolean","null"]},"build_command":{"type":["string","null"]},"custom_domain":{"type":["string","null"]},"directory":{"type":"string"},"environment_variables":{"type":["array","null"],"items":{"type":"array","items":false,"prefixItems":[{"type":"string"},{"type":"string"}]}},"exposed_port":{"type":["integer","null"],"format":"int32","description":"Port exposed by the container (fallback when image has no EXPOSE directive)\n\nPriority order for port resolution:\n1. Image EXPOSE directive (auto-detected from built image)\n2. Environment-level exposed_port (overrides this value per environment)\n3. This project-level exposed_port (fallback)\n4. Default: 3000\n\nOnly set this if your image doesn't use EXPOSE directive.","example":8080},"git_provider_connection_id":{"type":["integer","null"],"format":"int32"},"git_url":{"type":["string","null"]},"install_command":{"type":["string","null"]},"is_on_demand":{"type":["boolean","null"]},"is_public_repo":{"type":["boolean","null"]},"is_web_app":{"type":["boolean","null"]},"main_branch":{"type":"string"},"name":{"type":"string"},"output_dir":{"type":["string","null"]},"performance_metrics_enabled":{"type":"boolean"},"preset":{"type":"string"},"preset_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PresetConfigSchema","description":"Preset-specific configuration\n\nDifferent presets accept different configuration options:\n- **Dockerfile preset**: Accepts `DockerfilePresetConfig` with `dockerfile_path` and `build_context`\n- **Nixpacks preset**: Accepts ordered `providers` (for example `[\"...\", \"python\"]`)\n and optional inline `nixpacksConfig` TOML\n- **Static presets** (Vite, Next.js, etc.): Accept `StaticPresetConfig` with build commands and output dir\n\nExample for Dockerfile preset:\n```json\n{\n \"dockerfilePath\": \"docker/Dockerfile\",\n \"buildContext\": \"./api\"\n}\n```"}]},"project_type":{"type":["string","null"]},"repo_name":{"type":["string","null"]},"repo_owner":{"type":["string","null"]},"source_type":{"$ref":"#/components/schemas/SourceType","description":"Source type for deployments\n\nDetermines how the project is deployed:\n- **git** (default): Traditional Git-based deployments - source code is pulled, built, and deployed\n- **docker_image**: Deploy pre-built Docker images from external registries (DockerHub, GHCR, etc.)\n- **static_files**: Deploy pre-built static files uploaded as tar.gz or zip bundles\n\nFor `docker_image` and `static_files` source types, `repo_name` and `repo_owner` are optional."},"storage_service_ids":{"type":"array","items":{"type":"integer","format":"int32"}},"use_default_wildcard":{"type":["boolean","null"]}}},"CreateProjectSecretRequest":{"type":"object","description":"Request to create a new project secret.\n\nProject secrets are mounted into the container as files under\n`/run/secrets/` (mode 0400, tmpfs) instead of as environment variables.\nValues are always encrypted at rest and never returned in plaintext from\nthe API after create. Distinct from agent secrets (global `/settings/secrets`).","required":["key","value"],"properties":{"environment_ids":{"type":"array","items":{"type":"integer","format":"int32"}},"include_in_preview":{"type":"boolean","description":"Include this secret in preview environments."},"key":{"type":"string","description":"Identifier for the secret. Becomes the filename at `/run/secrets/`.\nMust start with a letter or underscore and contain only A-Z, a-z, 0-9, _."},"value":{"type":"string","description":"Plaintext value, <= 1 MiB."}}},"CreateProviderKeyRequest":{"type":"object","required":["provider","display_name","api_key"],"properties":{"api_key":{"type":"string"},"base_url":{"type":["string","null"]},"default_model":{"type":["string","null"],"description":"Optional model id to pin for this provider (e.g. \"gpt-4o-mini\")."},"display_name":{"type":"string"},"provider":{"type":"string"}}},"CreateProviderRequest":{"type":"object","required":["name","provider_type","config"],"properties":{"config":{},"enabled":{"type":["boolean","null"]},"name":{"type":"string"},"provider_type":{"type":"string"}}},"CreateRouteRequest":{"type":"object","required":["domain","host","port"],"properties":{"domain":{"type":"string"},"host":{"type":"string"},"port":{"type":"integer","format":"int32"},"route_type":{"type":["string","null"],"description":"Route type: \"http\" (default) matches on HTTP Host header,\n\"tls\" matches on TLS SNI hostname for TCP passthrough"}}},"CreateS3SourceRequest":{"type":"object","required":["name","bucket_name","bucket_path","access_key_id","secret_key","region"],"properties":{"access_key_id":{"type":"string"},"bucket_name":{"type":"string"},"bucket_path":{"type":"string"},"endpoint":{"type":["string","null"],"description":"Optional endpoint URL for S3-compatible services like MinIO","example":"http://minio.example.com:9000"},"force_path_style":{"type":["boolean","null"],"description":"Whether to use path-style addressing (default: true)","example":true},"is_default":{"type":["boolean","null"],"description":"When true, make this the default source (will swap out any existing default).\nThe very first S3 source is always created as default regardless of this flag.","example":false},"name":{"type":"string"},"region":{"type":"string"},"secret_key":{"type":"string"}}},"CreateSandboxBody":{"type":"object","properties":{"_runtime":{"type":["string","null"]},"backend":{"type":["string","null"],"description":"Isolation backend: `\"docker\"` (default) or `\"firecracker\"` (ADR-029,\nhardware-virtualized microVM — requires a host provisioned with\n`temps firecracker setup`). Omit for the platform default; existing\nclients are unaffected. Requesting an unavailable backend fails with\n400 rather than silently downgrading isolation."},"cpu_limit":{"type":["number","null"],"format":"double"},"disk_size_mb":{"type":["integer","null"],"format":"int64","description":"Root disk size in MB (Firecracker only; Docker ignores it). Omit for\nthe platform default (1 GiB).","minimum":0},"env":{"type":"object","description":"Extra env vars baked into the container on create.","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"image":{"type":["string","null"],"description":"Docker image override. `null` uses the platform default."},"memory_limit_mb":{"type":["integer","null"],"format":"int64","minimum":0},"name":{"type":["string","null"]},"networkPolicy":{},"pids_limit":{"type":["integer","null"],"format":"int64"},"ports":{"type":"array","items":{"type":"integer","format":"int32","minimum":0},"description":"Ports the sandbox will listen on. Each port becomes a `routes[]`\nentry in the create/get response so `@vercel/sandbox`'s\n`sandbox.domain(port)` can resolve it client-side without an\nextra round-trip."},"preview_password":{"type":["string","null"],"description":"Optional preview-URL password. When set, every preview URL served\nfor this sandbox is gated behind a login form. 8–256 characters.\nOmit to leave preview URLs open (the sandbox ID remains the only\ngate). The plaintext is never returned; only the last-4 hint is\nsurfaced in `SandboxResponse.preview_password_hint`."},"projectId":{"type":["string","null"]},"resources":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ResourcesBody","description":"`@vercel/sandbox`'s nested resources object. When present, its\n`memory` / `vcpus` populate `memory_limit_mb` / `cpu_limit` if those\nweren't sent directly."}]},"source":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SourceBody","description":"Optional initial content to seed into the work dir. Clones a\nrepo or extracts a tarball after the sandbox is created."}]},"timeout":{"type":["integer","null"],"format":"int64","description":"Idle timeout as sent by `@vercel/sandbox` (milliseconds). Converted\nto seconds when `timeout_secs` is absent.","minimum":0},"timeout_secs":{"type":["integer","null"],"format":"int64","description":"Idle timeout in seconds (temps-native). Clamped to `[60, 86400]`.","minimum":0}}},"CreateSkillRequest":{"type":"object","required":["slug","name","content"],"properties":{"content":{"type":"string"},"description":{"type":["string","null"]},"name":{"type":"string"},"slug":{"type":"string"}}},"CreateSlackProviderRequest":{"type":"object","required":["name","config"],"properties":{"config":{"$ref":"#/components/schemas/SlackConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":"string"}}},"CreateTeamMemberRequest":{"type":"object","required":["user_id","role"],"properties":{"role":{"$ref":"#/components/schemas/TeamRole"},"user_id":{"type":"integer","format":"int32"}}},"CreateTeamRequest":{"type":"object","required":["name","slug"],"properties":{"description":{"type":["string","null"]},"name":{"type":"string"},"slug":{"type":"string"}}},"CreateUserRequest":{"type":"object","required":["username","roles"],"properties":{"email":{"type":["string","null"]},"must_change_password":{"type":"boolean"},"password":{"type":["string","null"]},"roles":{"type":"array","items":{"type":"string"}},"username":{"type":"string"}}},"CreateWebhookProviderRequest":{"type":"object","required":["name","config"],"properties":{"config":{"$ref":"#/components/schemas/WebhookConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":"string"}}},"CreateWebhookRequestBody":{"type":"object","required":["url","events"],"properties":{"enabled":{"type":["boolean","null"],"description":"Whether the webhook is enabled","default":true},"events":{"type":"array","items":{"type":"string"},"description":"Event types to subscribe to","example":["deployment.created","deployment.succeeded"]},"secret":{"type":["string","null"],"description":"Secret for HMAC signature verification (optional)"},"url":{"type":"string","description":"Target URL for webhook delivery","example":"https://example.com/webhook"}}},"CreatedResource":{"type":"object","description":"Resource created during import (for rollback / audit)","required":["resource_type","resource_id","resource_name"],"properties":{"resource_id":{"type":"integer","format":"int32","description":"Resource ID"},"resource_name":{"type":"string","description":"Resource name"},"resource_type":{"type":"string","description":"Resource type (project, environment, deployment, service, domain, etc.)"}}},"CronExecutionInfo":{"type":"object","required":["id","cron_id","executed_at","url","status_code","headers","response_time_ms"],"properties":{"cron_id":{"type":"integer","format":"int32"},"error_message":{"type":["string","null"]},"executed_at":{"type":"string"},"headers":{"type":"string"},"id":{"type":"integer","format":"int32"},"response_time_ms":{"type":"integer","format":"int32"},"status_code":{"type":"integer","format":"int32"},"url":{"type":"string"}}},"CronInfo":{"type":"object","required":["id","project_id","environment_id","path","schedule","created_at","updated_at"],"properties":{"created_at":{"type":"string"},"deleted_at":{"type":["string","null"]},"environment_id":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"next_run":{"type":["string","null"]},"path":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"schedule":{"type":"string"},"updated_at":{"type":"string"}}},"CrossProjectSiblingRef":{"type":"object","description":"A sibling project that shares the same `trace_id`, returned by the\nPhase 1 cross-project banner endpoint.","required":["project_id","project_name","project_slug","first_seen"],"properties":{"first_seen":{"type":"string","format":"date-time","description":"ISO 8601 timestamp (UTC, `Z` suffix) of first span ingest for this\n`(trace_id, project_id)` pair."},"project_id":{"type":"integer","format":"int32"},"project_name":{"type":"string"},"project_slug":{"type":"string","description":"URL slug used to link into the sibling project's single-project trace view."}}},"CrossProjectTraceResponse":{"type":"object","description":"Response body for `GET /otel/traces/cross-project/{trace_id}`.\n\nAn empty `siblings` vec is the normal single-project case — never 404.","required":["trace_id","siblings"],"properties":{"siblings":{"type":"array","items":{"$ref":"#/components/schemas/CrossProjectSiblingRef"},"description":"Projects other than the caller's that hold spans for this trace,\nordered by `first_seen ASC`."},"trace_id":{"type":"string","description":"The trace_id that was queried (echoed back for client convenience)."}}},"CurrentStatusResponse":{"type":"object","required":["monitor_id","current_status","uptime_percentage"],"properties":{"avg_response_time_ms":{"type":["number","null"],"format":"double"},"current_status":{"type":"string"},"last_check_at":{"type":["string","null"],"format":"date-time"},"monitor_id":{"type":"integer","format":"int32"},"uptime_percentage":{"type":"number","format":"double"}}},"CustomDomainRequest":{"type":"object","required":["domain","environment_id"],"properties":{"branch":{"type":["string","null"]},"domain":{"type":"string"},"environment_id":{"type":"integer","format":"int32"},"redirect_to":{"type":["string","null"]},"service_name":{"type":["string","null"],"description":"Docker Compose service name this domain routes to (only for docker-compose projects)"},"status_code":{"type":["integer","null"],"format":"int32"}}},"CustomDomainResponse":{"type":"object","required":["id","project_id","domain","status","created_at","updated_at"],"properties":{"branch":{"type":["string","null"]},"created_at":{"type":"integer","format":"int64"},"domain":{"type":"string"},"domain_id":{"type":["integer","null"],"format":"int32"},"environment":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DomainEnvironmentResponse"}]},"expiration_time":{"type":["integer","null"],"format":"int64"},"id":{"type":"integer","format":"int32"},"last_renewed":{"type":["integer","null"],"format":"int64"},"message":{"type":["string","null"]},"project_id":{"type":"integer","format":"int32"},"redirect_to":{"type":["string","null"]},"service_name":{"type":["string","null"],"description":"Docker Compose service name this domain routes to"},"status":{"type":"string"},"status_code":{"type":["integer","null"],"format":"int32"},"updated_at":{"type":"integer","format":"int64"}}},"CustomerMovementResponse":{"type":"object","required":["bucket","new_customers","churned_customers"],"properties":{"bucket":{"type":"string","format":"date-time"},"churned_customers":{"type":"integer","format":"int64"},"new_customers":{"type":"integer","format":"int64"}}},"DashboardLayout":{"type":"object","description":"The typed layout persisted (as JSONB) in `metric_dashboards.layout`.","required":["sections"],"properties":{"sections":{"type":"array","items":{"$ref":"#/components/schemas/DashboardSection"},"description":"Ordered sections that make up the dashboard."}}},"DashboardProjectsAnalyticsQuery":{"type":"object","description":"Query parameters for batch dashboard analytics","required":["project_ids","start_date","end_date"],"properties":{"end_date":{"type":"string","format":"date-time","description":"End date for the query range"},"project_ids":{"type":"string","description":"Comma-separated list of project IDs"},"start_date":{"type":"string","format":"date-time","description":"Start date for the query range"}}},"DashboardProjectsAnalyticsResponse":{"type":"object","description":"Batch response for dashboard project analytics","required":["projects"],"properties":{"projects":{"type":"object","description":"Map of project_id -> analytics data","additionalProperties":{"$ref":"#/components/schemas/ProjectDashboardAnalytics"},"propertyNames":{"type":"string"}}}},"DashboardSection":{"type":"object","description":"A titled group of tiles within a dashboard.","required":["id","title","tiles"],"properties":{"id":{"type":"string","description":"Stable client-generated section id."},"tiles":{"type":"array","items":{"$ref":"#/components/schemas/DashboardTile"},"description":"Tiles rendered within this section."},"title":{"type":"string","description":"Section heading."}}},"DashboardTile":{"type":"object","description":"A single metric tile within a dashboard section.","required":["id","metric_name","aggregation"],"properties":{"aggregation":{"type":"string","description":"Aggregation applied per bucket: one of\n`avg|sum|min|max|count|rate|p50|p90|p95|p99`."},"group_by":{"type":"array","items":{"type":"string"},"description":"Label keys to break the metric down by (group-by / multi-series view).\nEmpty = single aggregated series (current behavior). Max 2 keys — more\ndimensions are unreadable in a chart (ADR-026 Phase 2). Each key must\nmatch `[a-zA-Z0-9_.:-]`. Wired directly to `MetricQuery.group_by` by\nthe tile query path (separate frontend task)."},"id":{"type":"string","description":"Stable client-generated tile id (used as a React key / for reordering)."},"label_filters":{"type":"array","items":{"type":"array","items":false,"prefixItems":[{"type":"string"},{"type":"string"}]},"description":"AND-combined label equality filters: `[[\"key\",\"value\"],…]`. Empty = no\nfiltering. Max 10 pairs; keys must match `[a-zA-Z0-9_.:-]`; values\ncapped at 500 characters. Not yet wired into the tile query path\n(Phase 1 ADR-026 — field round-trips and validates; query wiring is\na separate frontend task)."},"metric_name":{"type":"string","description":"The metric name to chart (e.g. `http.server.duration`)."},"title":{"type":["string","null"],"description":"Optional display title; falls back to the metric name in the UI."}}},"DataImplication":{"type":"object","description":"A specific data implication the user needs to understand","required":["severity","message"],"properties":{"message":{"type":"string","description":"Human-readable description of what could happen"},"recommended_action":{"type":["string","null"],"description":"What the user should do about it (if anything)"},"severity":{"$ref":"#/components/schemas/DataImplicationSeverity","description":"Severity of this implication"}}},"DataImplicationSeverity":{"type":"string","description":"Severity of a data implication","enum":["info","warning","data-not-migrated","potential-data-loss"]},"DatabaseMetricsResponse":{"type":"object","description":"Response for the per-database metrics breakdown.","required":["databases"],"properties":{"databases":{"type":"array","items":{"$ref":"#/components/schemas/DatabaseMetricsRow"},"description":"One entry per database, sorted by the first metric descending\n(largest first) so the biggest database leads the table."}}},"DatabaseMetricsRow":{"type":"object","description":"Per-database metric values for a Postgres service.\n\nA Postgres instance can host many databases (some unrelated to this\nservice). The collector records per-`datname` series; this groups the\nlatest value of each requested metric by database so the UI can render a\n\"Databases\" breakdown table instead of one collapsed number.","required":["database","metrics"],"properties":{"database":{"type":"string","description":"Database name (`datname`)."},"metrics":{"type":"object","description":"Latest value of each requested metric for this database\n(e.g. `{\"pg.database_size_bytes\": 7943871, \"pg.cache_hit_ratio\": 0.99}`).","additionalProperties":{"type":"number","format":"double"},"propertyNames":{"type":"string"}}}},"DelRequest":{"type":"object","description":"Request to delete keys","required":["keys"],"properties":{"keys":{"type":"array","items":{"type":"string"},"description":"The key(s) to delete","example":["user:123","user:456"]},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1}}},"DelResponse":{"type":"object","description":"Response for delete operation","required":["deleted"],"properties":{"deleted":{"type":"integer","format":"int64","description":"Number of keys deleted","example":2}}},"DeleteBlobRequest":{"type":"object","description":"Request to delete blobs","required":["pathnames"],"properties":{"pathnames":{"type":"array","items":{"type":"string"},"description":"Pathnames to delete (relative to project)","example":["images/avatar.png","documents/file.pdf"]},"projectId":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1}}},"DeleteBlobResponse":{"type":"object","description":"Response after deleting blobs","required":["deleted"],"properties":{"deleted":{"type":"integer","format":"int64","description":"Number of blobs deleted","example":2}}},"DeleteResponse":{"type":"object","required":["deleted"],"properties":{"deleted":{"type":"integer","format":"int64","minimum":0}}},"DeployFromImageRequest":{"type":"object","properties":{"external_image_id":{"type":["integer","null"],"format":"int32","description":"External image ID (if already registered). If provided without image_ref,\nthe image reference will be fetched from the registered external image."},"health_check_path":{"type":["string","null"],"description":"Optional HTTP health-check path override (e.g. \"/api/healthz\").\nImage deploys can't read `.temps.yaml`, so this sets the path the deployer\nprobes after the container starts and the path the environment's uptime\nmonitor checks. Must start with '/'. When omitted, defaults to \"/\".","example":"/api/healthz"},"image_ref":{"type":["string","null"],"description":"Docker image reference (e.g., \"ghcr.io/org/app:v1.0\")\nRequired if external_image_id is not provided","example":"ghcr.io/myorg/myapp:v1.0"},"metadata":{"description":"Optional deployment metadata"}}},"DeployFromImageUploadQuery":{"type":"object","description":"Query parameters for deploying from an uploaded image tarball","properties":{"health_check_path":{"type":["string","null"],"description":"Optional HTTP health-check path override (e.g. \"/api/healthz\").\nMust start with '/'. When omitted, defaults to \"/\".","example":"/api/healthz"},"tag":{"type":["string","null"],"description":"Tag to apply to the imported image (e.g., \"myapp:v1.0\")\nIf not provided, a unique tag will be generated","example":"myapp:v1.0"}}},"DeployFromStaticRequest":{"type":"object","required":["static_bundle_id"],"properties":{"health_check_path":{"type":["string","null"],"description":"Optional HTTP health-check path override (e.g. \"/api/healthz\").\nStatic deploys can't read `.temps.yaml`, so this sets the path the deployer\nprobes after the container starts and the path the environment's uptime\nmonitor checks. Must start with '/'. When omitted, defaults to \"/\".","example":"/api/healthz"},"metadata":{"description":"Optional deployment metadata"},"static_bundle_id":{"type":"integer","format":"int32","description":"Static bundle ID (required)"}}},"DeploymentConfig":{"type":"object","description":"Deployment configuration shared between projects and environments\n\nThis configuration can be set at the project level (as defaults) and\noverridden at the environment level for specific deployments.\n\nNote: Environment variables are managed separately and are not part of this config.","properties":{"antiAffinity":{"type":"boolean","description":"Anti-affinity: spread replicas across different nodes.\n\nWhen enabled, the scheduler avoids placing two replicas of the same\nenvironment on the same node. If there are fewer eligible nodes than\nreplicas, remaining replicas wrap around (best-effort spreading).\n\nDefaults to `true` — replicas spread by default."},"automaticDeploy":{"type":["boolean","null"],"description":"Enable automatic deployments on git push.\n`None` = inherit from project config; `Some(true/false)` = explicit override.\nStored as JSONB so absent key → `None` (inherit), never silently defaults to false."},"containerExecEnabled":{"type":"boolean","description":"Enable container exec/shell access (disabled by default for security)"},"cpuLimit":{"type":["integer","null"],"format":"int32","description":"CPU limit in microcores, where 1_000_000 = 1 full CPU core\n(e.g., 2_000_000 = 2 CPUs). NOT millicores. `None` = uncapped."},"cpuRequest":{"type":["integer","null"],"format":"int32","description":"CPU request in microcores, where 1_000_000 = 1 full CPU core\n(e.g., 100_000 = 0.1 CPU, 500_000 = 0.5 CPU, 2_000_000 = 2 CPUs).\nNOT millicores — the deployer formats this as `{n}u` and converts\n`n / 1_000_000` cores into Docker nano_cpus."},"crossArchitectureBuilds":{"type":["boolean","null"],"description":"Build one image per architecture the eligible nodes run.\n\n`None`/`false` (the default) builds exactly once, on the control\nplane's native platform — byte-for-byte the behaviour of a\nsingle-architecture cluster. When enabled and the nodes this\ndeployment could land on span more than one architecture, the build\njob produces one image per architecture; the non-native ones go\nthrough the daemon's `platform` option, which requires QEMU binfmt\nhandlers registered on the control plane.\n\n**Opt-in on purpose.** Cross-architecture builds are emulated and\nsubstantially slower, and deriving them from cluster topology would\nmean a single node joining silently changes build behaviour for every\ndeployment in the cluster. It also keeps the decision on operator\nconfig rather than on a value each node reports about itself.\n\n`Option` so an environment inherits the project's setting\n(`None`) or overrides it, matching `automatic_deploy`."},"exposedPort":{"type":["integer","null"],"format":"int32","description":"Port exposed by the container\nIf not specified, will be auto-detected from Docker image or default to 3000"},"idleTimeoutSeconds":{"type":"integer","format":"int32","description":"Seconds of inactivity before containers are stopped in on-demand mode.\nOnly used when `on_demand` is true. Min: 60, Max: 86400 (24h).\nDefault: 300 (5 minutes)."},"memoryLimit":{"type":["integer","null"],"format":"int32","description":"Memory limit in megabytes. Three-state semantics:\n- `None` → inherit the parent layer (env inherits project, project\n inherits the seeded default); used by the settings UI's \"Use default\".\n- `Some(0)` → explicit **uncapped**: stop inheriting and run with no\n memory limit. This is the deliberate escape hatch for dedicated\n workloads, distinct from `None`.\n- `Some(n)` → hard cap of `n` MB.\n\n`merge`/resolution keep `Some(0)` as a present value (it wins precedence\nover a parent cap), and the deployer collapses it to \"no limit\" before\ntalking to Docker."},"memoryRequest":{"type":["integer","null"],"format":"int32","description":"Memory request in megabytes (e.g., 128 = 128MB)"},"onDemand":{"type":"boolean","description":"Enable on-demand mode (scale-to-zero).\nWhen enabled, containers are stopped after `idle_timeout_seconds` of no traffic\nand automatically started when a new request arrives."},"performanceMetricsEnabled":{"type":"boolean","description":"Enable performance metrics collection (speed insights)"},"replicas":{"type":"integer","format":"int32","description":"Number of replicas/instances to run\nDefaults to 1 replica"},"security":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SecurityConfig","description":"Security configuration (headers, rate limiting, attack mode, etc.)\nThese settings inherit and override from parent level (Environment > Project > Global)"}]},"sessionRecordingEnabled":{"type":"boolean","description":"Enable session recording for analytics"},"targetLabels":{"description":"Label selector for node-based scheduling. Replicas are only deployed to\nnodes whose labels match the selector.\n\nMatching rules:\n- **Same key, array value** → OR: node must match any value\n- **Different keys** → AND: node must satisfy all keys\n\nExample: `{\"region\": [\"us\", \"asia\"], \"gpu\": \"true\"}`\n→ (region=us OR region=asia) AND gpu=true\n\nApplied after `target_nodes` filtering (they stack)."},"targetNodes":{"type":["array","null"],"items":{"type":"integer","format":"int32"},"description":"Optional list of node IDs to deploy to. When set, replicas are distributed\nonly across these nodes (round-robin). When None, the scheduler distributes\nacross all active nodes (or deploys locally if no nodes exist)."},"wakeTimeoutSeconds":{"type":"integer","format":"int32","description":"Max seconds to wait for containers to start when waking from on-demand sleep.\nRequests return 503 if exceeded. Default: 30."}}},"DeploymentConfigSnapshot":{"type":"object","description":"Deployment configuration snapshot for deployments\n\nThis extends DeploymentConfig with environment variables to capture\nthe complete state of a deployment at the time it was created.","properties":{"automaticDeploy":{"type":"boolean","description":"Enable automatic deployments on git push"},"containerExecEnabled":{"type":"boolean","description":"Enable container exec/shell access"},"cpuLimit":{"type":["integer","null"],"format":"int32","description":"CPU limit in millicores"},"cpuRequest":{"type":["integer","null"],"format":"int32","description":"CPU request in millicores"},"environmentVariables":{"type":"object","description":"Environment variables used for this deployment","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"exposedPort":{"type":["integer","null"],"format":"int32","description":"Port exposed by the container"},"memoryLimit":{"type":["integer","null"],"format":"int32","description":"Memory limit in megabytes"},"memoryRequest":{"type":["integer","null"],"format":"int32","description":"Memory request in megabytes"},"performanceMetricsEnabled":{"type":"boolean","description":"Enable performance metrics collection"},"replicas":{"type":"integer","format":"int32","description":"Number of replicas"},"sessionRecordingEnabled":{"type":"boolean","description":"Enable session recording"}}},"DeploymentConfiguration":{"type":"object","description":"Deployment-level configuration","required":["image","strategy","env_vars","ports","volumes","network","resources"],"properties":{"build":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/BuildConfiguration","description":"Build configuration (if building from source)"}]},"command":{"type":["array","null"],"items":{"type":"string"},"description":"Command override"},"entrypoint":{"type":["array","null"],"items":{"type":"string"},"description":"Entrypoint override"},"env_vars":{"type":"array","items":{"$ref":"#/components/schemas/EnvironmentVariable"},"description":"Environment variables"},"git":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/GitSourcePlan","description":"Where the application's source code lives, when the source platform\nbuilds from a git repository. Execution uses this to link the temps\nproject to the same repository so the real deployment pipeline can\nclone and build it."}]},"health_check":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/HealthCheckConfiguration","description":"Health check configuration"}]},"image":{"type":"string","description":"Image to deploy"},"network":{"$ref":"#/components/schemas/NetworkConfiguration","description":"Network configuration"},"ports":{"type":"array","items":{"$ref":"#/components/schemas/PortMapping"},"description":"Port mappings"},"resources":{"$ref":"#/components/schemas/ResourceLimits","description":"Resource limits"},"strategy":{"$ref":"#/components/schemas/DeploymentStrategy","description":"Deployment strategy"},"volumes":{"type":"array","items":{"$ref":"#/components/schemas/VolumeMount"},"description":"Volume mounts"},"working_dir":{"type":["string","null"],"description":"Working directory"}}},"DeploymentContainerLogContentResponse":{"type":"object","description":"A single captured container-log dump, including its full text content.","required":["id","container_name","size_bytes","truncated","captured_at","content"],"properties":{"captured_at":{"type":"integer","format":"int64"},"container_name":{"type":"string"},"content":{"type":"string","description":"The captured plain-text log content."},"id":{"type":"integer","format":"int32"},"service_name":{"type":["string","null"]},"size_bytes":{"type":"integer","format":"int64"},"truncated":{"type":"boolean"}}},"DeploymentContainerLogResponse":{"type":"object","description":"Metadata for one captured (historical) container-log dump. Listed on the\ndeployment detail page so a user can pick which past container's logs to read.","required":["id","deployment_id","container_id","container_name","size_bytes","truncated","captured_at"],"properties":{"captured_at":{"type":"integer","format":"int64","description":"Unix epoch milliseconds of when the logs were captured (just before\nteardown). Matches the timestamp convention used by `DeploymentResponse`."},"container_id":{"type":"string"},"container_name":{"type":"string"},"deployment_id":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"node_id":{"type":["integer","null"],"format":"int32"},"service_name":{"type":["string","null"]},"size_bytes":{"type":"integer","format":"int64"},"truncated":{"type":"boolean"}}},"DeploymentContainerLogsListResponse":{"type":"object","description":"The list of captured container-log dumps for a deployment.","required":["logs"],"properties":{"logs":{"type":"array","items":{"$ref":"#/components/schemas/DeploymentContainerLogResponse"}}}},"DeploymentEnvironmentResponse":{"type":"object","required":["id","name","slug","domains"],"properties":{"domains":{"type":"array","items":{"type":"string"}},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"slug":{"type":"string"}}},"DeploymentJobResponse":{"type":"object","required":["id","deployment_id","job_id","job_type","name","status","created_at","updated_at","log_id"],"properties":{"created_at":{"type":"integer","format":"int64"},"dependencies":{},"deployment_id":{"type":"integer","format":"int32"},"description":{"type":["string","null"]},"error_message":{"type":["string","null"]},"execution_order":{"type":["integer","null"],"format":"int32"},"finished_at":{"type":["integer","null"],"format":"int64"},"id":{"type":"integer","format":"int32"},"job_config":{"description":"Internal workflow configuration is intentionally redacted. It can\ncontain legacy plaintext secrets or encrypted secret envelopes."},"job_id":{"type":"string"},"job_type":{"type":"string"},"log_id":{"type":"string"},"name":{"type":"string"},"outputs":{},"started_at":{"type":["integer","null"],"format":"int64"},"status":{"type":"string"},"updated_at":{"type":"integer","format":"int64"}}},"DeploymentJobsResponse":{"type":"object","required":["jobs","total"],"properties":{"jobs":{"type":"array","items":{"$ref":"#/components/schemas/DeploymentJobResponse"}},"total":{"type":"integer","minimum":0}}},"DeploymentListResponse":{"type":"object","required":["deployments","total","page","per_page"],"properties":{"deployments":{"type":"array","items":{"$ref":"#/components/schemas/DeploymentResponse"}},"page":{"type":"integer","format":"int64"},"per_page":{"type":"integer","format":"int64"},"total":{"type":"integer","format":"int64"}}},"DeploymentMetadata":{"type":"object","description":"Deployment metadata - typed information about the deployment","properties":{"buildDurationMs":{"type":["integer","null"],"format":"int64","description":"Build duration in milliseconds"},"builder":{"type":["string","null"],"description":"Docker builder used (e.g., \"nixpacks\", \"dockerfile\")"},"deploymentDurationMs":{"type":["integer","null"],"format":"int64","description":"Deployment duration in milliseconds"},"deploymentSourceType":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SourceType","description":"Source type for THIS specific deployment (for Manual/flexible projects)\nThis allows Manual projects to have deployments via different methods\n(docker_image, static_files, or git) while keeping per-deployment tracking"}]},"dockerfilePath":{"type":["string","null"],"description":"Dockerfile path if using Dockerfile builder"},"externalImageId":{"type":["integer","null"],"format":"int32","description":"External image ID (reference to external_images table)"},"externalImageRef":{"type":["string","null"],"description":"External Docker image reference (for docker_image source type)\ne.g., \"ghcr.io/org/app:v1.0\" or \"docker.io/myapp:sha-abc123\""},"fileCount":{"type":["integer","null"],"format":"int32","description":"Number of files in the build output"},"gitPushEvent":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/GitPushEvent","description":"Git push event that triggered this deployment (if from webhook)"}]},"healthCheckPath":{"type":["string","null"],"description":"Explicit deploy-time HTTP health-check path override.\nImage/static deploys can't read `.temps.yaml`, so this lets the deploy\nrequest set a custom path (e.g. \"/api/healthz\"). When present it takes\npriority over any `.temps.yaml` `health.path` value. Always starts with '/'."},"imageSizeBytes":{"type":["integer","null"],"format":"int64","description":"Total size of the built image in bytes"},"imageUploadedLocally":{"type":"boolean","description":"Whether the image was uploaded directly (via docker save/load) rather than pulled from registry\nWhen true, the PullExternalImageJob is skipped since the image is already loaded locally"},"isRollback":{"type":"boolean","description":"Whether this is a rollback deployment"},"labels":{"type":"array","items":{"type":"string"},"description":"Custom labels/tags for the deployment"},"rolledBackFromId":{"type":["integer","null"],"format":"int32","description":"ID of the deployment this was rolled back from (if applicable)"},"sourceBundleContentType":{"type":["string","null"],"description":"Uploaded source archive content type."},"sourceBundleId":{"type":["integer","null"],"format":"int32","description":"Uploaded source archive ID. Source archives are extracted before the\nregular preset build pipeline and do not require Git metadata."},"sourceBundlePath":{"type":["string","null"],"description":"Uploaded source archive path in the Temps data directory."},"staticBundleContentType":{"type":["string","null"],"description":"Static bundle content type (for proper extraction: application/gzip or application/zip)"},"staticBundleId":{"type":["integer","null"],"format":"int32","description":"Static bundle ID (reference to static_bundles table, for static_files source type)"},"staticBundlePath":{"type":["string","null"],"description":"Static bundle path in blob storage (for static_files source type)"},"uploadedImageId":{"type":["string","null"],"description":"Docker image ID of the locally uploaded image (sha256:...)\nUsed to verify the image exists before deployment"}}},"DeploymentResponse":{"type":"object","required":["id","project_id","environment_id","environment","status","url","created_at","is_current"],"properties":{"branch":{"type":["string","null"]},"cancelled_reason":{"type":["string","null"]},"commit_author":{"type":["string","null"]},"commit_date":{"type":["integer","null"],"format":"int64"},"commit_hash":{"type":["string","null"]},"commit_message":{"type":["string","null"]},"created_at":{"type":"integer","format":"int64"},"deployment_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DeploymentConfigSnapshot","description":"Deployment configuration snapshot (CPU, memory, replicas, environment variables, etc.)"}]},"environment":{"$ref":"#/components/schemas/DeploymentEnvironmentResponse"},"environment_id":{"type":"integer","format":"int32"},"finished_at":{"type":["integer","null"],"format":"int64"},"id":{"type":"integer","format":"int32"},"is_current":{"type":"boolean"},"metadata":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DeploymentMetadata","description":"Deployment metadata (build info, git event, etc.)"}]},"project_id":{"type":"integer","format":"int32"},"screenshot_location":{"type":["string","null"]},"started_at":{"type":["integer","null"],"format":"int64"},"status":{"type":"string"},"tag":{"type":["string","null"]},"url":{"type":"string"}}},"DeploymentStateResponse":{"type":"object","required":["id","state","message"],"properties":{"id":{"type":"integer","format":"int32"},"message":{"type":"string"},"state":{"type":"string"}}},"DeploymentStrategy":{"type":"string","description":"Deployment strategy","enum":["replace","blue-green","rolling"]},"DeploymentTokenListResponse":{"type":"object","required":["tokens","total"],"properties":{"tokens":{"type":"array","items":{"$ref":"#/components/schemas/DeploymentTokenResponse"}},"total":{"type":"integer","format":"int64","minimum":0}}},"DeploymentTokenResponse":{"type":"object","required":["id","project_id","name","token_prefix","is_active","created_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00Z"},"created_by":{"type":["integer","null"],"format":"int32"},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"last_used_at":{"type":["string","null"],"format":"date-time","example":"2024-01-01T00:00:00Z"},"name":{"type":"string"},"permissions":{"type":["array","null"],"items":{"type":"string"}},"project_id":{"type":"integer","format":"int32"},"token_prefix":{"type":"string"}}},"DetectionConfig":{"oneOf":[{"allOf":[{"$ref":"#/components/schemas/StaticParams","description":"v0 (shipping): static threshold comparison of the aggregated value."},{"type":"object","required":["kind"],"properties":{"kind":{"type":"string","enum":["static"]}}}],"description":"v0 (shipping): static threshold comparison of the aggregated value."},{"allOf":[{"$ref":"#/components/schemas/AnomalyParams","description":"Seasonal anomaly band (basic/agile/robust/ewma share this variant — the\nalgorithm is a field, not a new kind). Creation rejected until evaluated."},{"type":"object","required":["kind"],"properties":{"kind":{"type":"string","enum":["anomaly"]}}}],"description":"Seasonal anomaly band (basic/agile/robust/ewma share this variant — the\nalgorithm is a field, not a new kind). Creation rejected until evaluated."},{"allOf":[{"$ref":"#/components/schemas/ForecastParams","description":"Predict a future threshold breach (capacity planning). Stub."},{"type":"object","required":["kind"],"properties":{"kind":{"type":"string","enum":["forecast"]}}}],"description":"Predict a future threshold breach (capacity planning). Stub."},{"allOf":[{"$ref":"#/components/schemas/OutlierParams","description":"Cross-series population outlier (one host misbehaving vs its peers). Stub."},{"type":"object","required":["kind"],"properties":{"kind":{"type":"string","enum":["outlier"]}}}],"description":"Cross-series population outlier (one host misbehaving vs its peers). Stub."},{"allOf":[{"$ref":"#/components/schemas/AutoWatchParams","description":"Watchdog-style self-tuning auto-watch (engine picks bounds). Stub."},{"type":"object","required":["kind"],"properties":{"kind":{"type":"string","enum":["auto_watch"]}}}],"description":"Watchdog-style self-tuning auto-watch (engine picks bounds). Stub."}],"description":"The typed detector definition stored (as jsonb) in\n`metric_alert_rules.detection_config`.\n\nToday only [`DetectionConfig::Static`] is evaluable; the other variants are\nschema-present (so the SDK/UI and storage are already future-shaped) but\nrejected by [`DetectionConfig::validate`] until their evaluator lands. Each is\nthen enabled code-only, with no schema migration."},"DeviceCount":{"type":"object","required":["device_type","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"device_type":{"type":"string"},"percentage":{"type":"number","format":"double"}}},"DigestSections":{"type":"object","description":"Sections that can be included in the weekly digest\nNote: `#[serde(default)]` allows backward compatibility when deserializing\nold data that may have `security` and `resources` fields instead of `projects`","properties":{"deployments":{"type":"boolean","default":true},"errors":{"type":"boolean","default":true},"funnels":{"type":"boolean","default":true},"performance":{"type":"boolean","default":true},"projects":{"type":"boolean","default":true}}},"Direction":{"type":"string","description":"Which side(s) of an anomaly band count as a deviation.","enum":["both","above","below"]},"DisableBlobResponse":{"type":"object","description":"Response after disabling Blob service","required":["success","message"],"properties":{"message":{"type":"string","description":"Human-readable message","example":"Blob service disabled successfully"},"success":{"type":"boolean","description":"Whether the operation succeeded","example":true}}},"DisableKvResponse":{"type":"object","description":"Response after disabling KV service","required":["success","message"],"properties":{"message":{"type":"string","description":"Status message","example":"KV service disabled successfully"},"success":{"type":"boolean","description":"Whether the service was successfully disabled"}}},"DisableMfaRequest":{"type":"object","required":["code"],"properties":{"code":{"type":"string"}}},"DiscoverRequest":{"type":"object","description":"Request to discover workloads","required":["source"],"properties":{"credentials":{"$ref":"#/components/schemas/ImportCredentials","description":"Platform credentials (required for cloud platforms like Vercel, Railway)"},"selector":{"$ref":"#/components/schemas/ImportSelector","description":"Optional selector to filter workloads"},"source":{"$ref":"#/components/schemas/ImportSource","description":"Source to discover from"}}},"DiscoverResponse":{"type":"object","description":"Response with discovered workloads","required":["workloads"],"properties":{"workloads":{"type":"array","items":{"$ref":"#/components/schemas/WorkloadDescriptor"},"description":"Discovered workloads"}}},"DiskInfo":{"type":"object","description":"Disk space information for a single disk/partition","required":["mount_point","total_bytes","used_bytes","available_bytes","usage_percent","file_system"],"properties":{"available_bytes":{"type":"integer","format":"int64","description":"Available space in bytes","minimum":0},"file_system":{"type":"string","description":"File system type (e.g., \"ext4\", \"apfs\")"},"mount_point":{"type":"string","description":"Mount point of the disk"},"total_bytes":{"type":"integer","format":"int64","description":"Total space in bytes","minimum":0},"usage_percent":{"type":"number","format":"double","description":"Usage percentage (0-100)"},"used_bytes":{"type":"integer","format":"int64","description":"Used space in bytes","minimum":0}}},"DiskSpaceAlert":{"type":"object","description":"Alert for a disk that exceeds the threshold","required":["mount_point","usage_percent","threshold_percent","available_bytes","available_human"],"properties":{"available_bytes":{"type":"integer","format":"int64","description":"Available space in bytes","minimum":0},"available_human":{"type":"string","description":"Human-readable available space"},"mount_point":{"type":"string","description":"Mount point of the disk"},"threshold_percent":{"type":"integer","format":"int32","description":"Configured threshold percentage","minimum":0},"usage_percent":{"type":"number","format":"double","description":"Current usage percentage"}}},"DiskSpaceAlertSettings":{"type":"object","description":"Disk space alert settings for monitoring disk usage","properties":{"check_interval_seconds":{"type":"integer","format":"int64","description":"Interval in seconds between disk space checks","default":300,"example":300,"minimum":60},"enabled":{"type":"boolean","description":"Whether disk space alerts are enabled","default":true},"monitor_path":{"type":["string","null"],"description":"Restrict monitoring to the disk backing this path. When unset (the\ndefault), every mounted writable volume is monitored — including\ndedicated volumes such as `/var/lib/docker`.","default":null},"threshold_percent":{"type":"integer","format":"int32","description":"Threshold percentage (0-100) at which to trigger alerts","default":80,"example":80,"maximum":100,"minimum":0}}},"DiskSpaceCheckResult":{"type":"object","description":"Result of a disk space check","required":["checked_at","enabled","threshold_percent","disks","alerts"],"properties":{"alerts":{"type":"array","items":{"$ref":"#/components/schemas/DiskSpaceAlert"},"description":"Disks that meet or exceed the threshold"},"checked_at":{"type":"string","format":"date-time","description":"Timestamp of the check (ISO 8601, UTC)","example":"2026-05-28T12:15:47.609192Z"},"disks":{"type":"array","items":{"$ref":"#/components/schemas/DiskInfo"},"description":"List of all monitored disks"},"enabled":{"type":"boolean","description":"Whether disk space monitoring is enabled in settings"},"threshold_percent":{"type":"integer","format":"int32","description":"Configured alert threshold percentage (0-100)","minimum":0}}},"DnsAckRequest":{"type":"object","required":["applied_generation"],"properties":{"applied_generation":{"type":"integer","format":"int64","description":"Highest generation the agent has actually applied locally."}}},"DnsAckResponse":{"type":"object","required":["node_id","applied_generation","server_generation"],"properties":{"applied_generation":{"type":"integer","format":"int64"},"node_id":{"type":"integer","format":"int32"},"server_generation":{"type":"integer","format":"int64"}}},"DnsChallengeRecordResult":{"type":"object","description":"Result of a single DNS TXT record creation for ACME challenge","required":["name","value","success","message"],"properties":{"message":{"type":"string","description":"Human-readable message about the operation"},"name":{"type":"string","description":"TXT record name (e.g., \"_acme-challenge.example.com\")","example":"_acme-challenge.example.com"},"success":{"type":"boolean","description":"Whether the record was created successfully"},"value":{"type":"string","description":"TXT record value (the ACME challenge token)","example":"abc123..."}}},"DnsChangesResponse":{"type":"object","required":["generation","full_snapshot","records","removed_ids"],"properties":{"full_snapshot":{"type":"boolean","description":"`true` ⇒ replace the local zone with `records`. `false` ⇒ merge\n`records` into the existing zone (and remove `removed_ids`)."},"generation":{"type":"integer","format":"int64","description":"Highest generation included in this response. Agent ACKs this back."},"records":{"type":"array","items":{"$ref":"#/components/schemas/EndpointDto"}},"removed_ids":{"type":"array","items":{"type":"integer","format":"int64"},"description":"IDs the agent should remove from its zone. Always empty in the v1\nprotocol — the resolver reconciles by name on snapshot mode. Kept\nin the wire format so a future tombstone-based protocol doesn't\nrequire a breaking change."}}},"DnsCompletionResponse":{"type":"object","required":["domain","status"],"properties":{"domain":{"type":"string"},"status":{"type":"string"}}},"DnsLookupError":{"type":"object","description":"Error response for DNS lookup failures","required":["error","domain"],"properties":{"domain":{"type":"string","description":"Domain name that failed","example":"nonexistent.com"},"error":{"type":"string","description":"Error message","example":"DNS lookup failed: domain not found"}}},"DnsLookupRequest":{"type":"object","description":"Request to lookup DNS A records for a domain","required":["domain"],"properties":{"domain":{"type":"string","description":"Domain name to lookup","example":"example.com"}}},"DnsLookupResponse":{"type":"object","description":"Response containing DNS A records","required":["domain","records","count","dns_servers"],"properties":{"count":{"type":"integer","description":"Number of records found","example":1,"minimum":0},"dns_servers":{"type":"array","items":{"type":"string"},"description":"DNS servers used for the lookup","example":["8.8.8.8","8.8.4.4"]},"domain":{"type":"string","description":"Domain name that was queried","example":"example.com"},"records":{"type":"array","items":{"type":"string"},"description":"List of A record IP addresses","example":["93.184.216.34"]}}},"DnsProviderCredentials":{"oneOf":[{"type":"object","required":["api_token","type"],"properties":{"account_id":{"type":["string","null"]},"api_token":{"type":"string","example":"your-api-token"},"type":{"type":"string","enum":["cloudflare"]}}},{"type":"object","required":["api_user","api_key","type"],"properties":{"api_key":{"type":"string","example":"your-api-key"},"api_user":{"type":"string","example":"your-username"},"client_ip":{"type":["string","null"]},"sandbox":{"type":"boolean"},"type":{"type":"string","enum":["namecheap"]}}},{"type":"object","required":["access_key_id","secret_access_key","type"],"properties":{"access_key_id":{"type":"string","example":"AKIAIOSFODNN7EXAMPLE"},"region":{"type":["string","null"],"example":"us-east-1"},"secret_access_key":{"type":"string","example":"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"},"session_token":{"type":["string","null"]},"type":{"type":"string","enum":["route53"]}}},{"type":"object","required":["api_token","type"],"properties":{"api_token":{"type":"string","example":"dop_v1_your-token"},"type":{"type":"string","enum":["digitalocean"]}}},{"type":"object","required":["service_account_email","private_key","project_id","type"],"properties":{"private_key":{"type":"string","example":"-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----"},"project_id":{"type":"string","example":"my-gcp-project"},"service_account_email":{"type":"string","example":"dns-admin@myproject.iam.gserviceaccount.com"},"type":{"type":"string","enum":["gcp"]}}},{"type":"object","required":["tenant_id","client_id","client_secret","subscription_id","resource_group","type"],"properties":{"client_id":{"type":"string","example":"00000000-0000-0000-0000-000000000000"},"client_secret":{"type":"string"},"resource_group":{"type":"string","example":"my-resource-group"},"subscription_id":{"type":"string","example":"00000000-0000-0000-0000-000000000000"},"tenant_id":{"type":"string","example":"00000000-0000-0000-0000-000000000000"},"type":{"type":"string","enum":["azure"]}}},{"type":"object","description":"Pebble challtestsrv mock DNS (LOCAL DEV/TEST ONLY)","required":["management_url","type"],"properties":{"management_url":{"type":"string","example":"http://localhost:8055"},"type":{"type":"string","enum":["pebble"]}}}],"description":"DNS provider credentials (API-facing)"},"DnsProviderResponse":{"type":"object","description":"DNS provider response","required":["id","name","provider_type","credentials","is_active","flat_hostnames_supported","created_at","updated_at"],"properties":{"created_at":{"type":"string"},"credentials":{"description":"Masked credentials for display"},"description":{"type":["string","null"]},"flat_hostnames_supported":{"type":"boolean","description":"Whether this provider benefits from the flat hostname mode (e.g. Cloudflare\nUniversal SSL). The UI surfaces/recommends the Flat toggle when true."},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"last_error":{"type":["string","null"]},"last_used_at":{"type":["string","null"]},"name":{"type":"string"},"provider_type":{"type":"string"},"updated_at":{"type":"string"}}},"DnsProviderSettings":{"type":"object","properties":{"cloudflare_api_key":{"type":["string","null"],"default":null},"provider":{"type":"string","default":"manual"}}},"DnsProviderSettingsMasked":{"type":"object","description":"DNS provider settings with masked sensitive fields","required":["provider"],"properties":{"cloudflare_api_key":{"type":["string","null"]},"provider":{"type":"string"}}},"DnsProviderType":{"type":"string","description":"Supported DNS provider types","enum":["cloudflare","namecheap","route53","digitalocean","gcp","azure","manual","pebble"]},"DnsRecord":{"type":"object","description":"A DNS record","required":["zone","name","fqdn","content","ttl"],"properties":{"content":{"$ref":"#/components/schemas/DnsRecordContent","description":"Record content"},"fqdn":{"type":"string","description":"Fully qualified domain name","example":"www.example.com"},"id":{"type":["string","null"],"description":"Provider-specific record ID (if exists)","example":"abc123"},"metadata":{"type":"object","description":"Provider-specific metadata","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"name":{"type":"string","description":"Record name (without zone, e.g., \"www\" or \"@\" for root)","example":"www"},"proxied":{"type":"boolean","description":"Whether this record is proxied (Cloudflare-specific)"},"ttl":{"type":"integer","format":"int32","description":"Time to live in seconds","example":300,"minimum":0},"zone":{"type":"string","description":"Zone/domain this record belongs to","example":"example.com"}}},"DnsRecordChange":{"type":"object","description":"A single DNS record change the Cloudflare sync would make.","required":["action","name","record_type","value"],"properties":{"action":{"type":"string","description":"`\"create\"`, `\"update\"`, or `\"delete\"`."},"name":{"type":"string"},"record_type":{"type":"string","description":"Record type, e.g. `\"A\"` or `\"CNAME\"`."},"value":{"type":"string"}}},"DnsRecordContent":{"oneOf":[{"type":"object","description":"A record - IPv4 address (as string, e.g., \"192.0.2.1\")","required":["value","type"],"properties":{"type":{"type":"string","enum":["A"]},"value":{"type":"object","description":"A record - IPv4 address (as string, e.g., \"192.0.2.1\")","required":["address"],"properties":{"address":{"type":"string","example":"192.0.2.1"}}}}},{"type":"object","description":"AAAA record - IPv6 address (as string, e.g., \"2001:db8::1\")","required":["value","type"],"properties":{"type":{"type":"string","enum":["AAAA"]},"value":{"type":"object","description":"AAAA record - IPv6 address (as string, e.g., \"2001:db8::1\")","required":["address"],"properties":{"address":{"type":"string","example":"2001:db8::1"}}}}},{"type":"object","description":"CNAME record - canonical name","required":["value","type"],"properties":{"type":{"type":"string","enum":["CNAME"]},"value":{"type":"object","description":"CNAME record - canonical name","required":["target"],"properties":{"target":{"type":"string"}}}}},{"type":"object","description":"TXT record - text content","required":["value","type"],"properties":{"type":{"type":"string","enum":["TXT"]},"value":{"type":"object","description":"TXT record - text content","required":["content"],"properties":{"content":{"type":"string"}}}}},{"type":"object","description":"MX record - mail exchange","required":["value","type"],"properties":{"type":{"type":"string","enum":["MX"]},"value":{"type":"object","description":"MX record - mail exchange","required":["priority","target"],"properties":{"priority":{"type":"integer","format":"int32","minimum":0},"target":{"type":"string"}}}}},{"type":"object","description":"NS record - nameserver","required":["value","type"],"properties":{"type":{"type":"string","enum":["NS"]},"value":{"type":"object","description":"NS record - nameserver","required":["nameserver"],"properties":{"nameserver":{"type":"string"}}}}},{"type":"object","description":"SRV record - service","required":["value","type"],"properties":{"type":{"type":"string","enum":["SRV"]},"value":{"type":"object","description":"SRV record - service","required":["priority","weight","port","target"],"properties":{"port":{"type":"integer","format":"int32","minimum":0},"priority":{"type":"integer","format":"int32","minimum":0},"target":{"type":"string"},"weight":{"type":"integer","format":"int32","minimum":0}}}}},{"type":"object","description":"CAA record - certification authority authorization","required":["value","type"],"properties":{"type":{"type":"string","enum":["CAA"]},"value":{"type":"object","description":"CAA record - certification authority authorization","required":["flags","tag","value"],"properties":{"flags":{"type":"integer","format":"int32","minimum":0},"tag":{"type":"string"},"value":{"type":"string"}}}}},{"type":"object","description":"PTR record - pointer","required":["value","type"],"properties":{"type":{"type":"string","enum":["PTR"]},"value":{"type":"object","description":"PTR record - pointer","required":["target"],"properties":{"target":{"type":"string"}}}}}],"description":"DNS record content - varies by record type"},"DnsRecordResponse":{"type":"object","required":["record_type","name","value","status"],"properties":{"name":{"type":"string","description":"DNS record name (host)","example":"temps._domainkey.example.com"},"priority":{"type":["integer","null"],"format":"int32","description":"Priority (for MX records)","example":"10","minimum":0},"record_type":{"type":"string","description":"Record type: TXT, CNAME, MX","example":"TXT"},"status":{"$ref":"#/components/schemas/DnsRecordStatusResponse","description":"Verification status: unknown, verified, pending, failed"},"value":{"type":"string","description":"DNS record value","example":"v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3..."}}},"DnsRecordSetupResult":{"type":"object","description":"Result of a single DNS record creation","required":["record_type","name","success","automatic","message"],"properties":{"automatic":{"type":"boolean","description":"Whether the operation was automatic or manual"},"message":{"type":"string","description":"Human-readable message"},"name":{"type":"string","description":"Record name"},"record_type":{"type":"string","description":"Record type (TXT, CNAME, MX)"},"success":{"type":"boolean","description":"Whether the record was created successfully"}}},"DnsRecordStatusResponse":{"type":"string","description":"DNS record verification status","enum":["unknown","verified","pending","failed"]},"DnsZone":{"type":"object","description":"A DNS zone (domain managed by the provider)","required":["id","name","status","nameservers"],"properties":{"id":{"type":"string","description":"Provider-specific zone ID","example":"zone123"},"metadata":{"type":"object","description":"Provider-specific metadata","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"name":{"type":"string","description":"Zone name (domain)","example":"example.com"},"nameservers":{"type":"array","items":{"type":"string"},"description":"Nameservers for this zone"},"status":{"type":"string","description":"Zone status","example":"active"}}},"DockerComposePresetConfig":{"type":"object","description":"Configuration for Docker Compose deployments.","properties":{"composeOverride":{"type":["string","null"],"description":"User-provided docker-compose.override.yml content."},"composePath":{"type":["string","null"],"description":"Path to the Compose file relative to the project directory."},"publicPorts":{"type":"array","items":{"$ref":"#/components/schemas/ComposePublicPort"},"description":"Compose service ports that should be publicly routed."}}},"DockerRegistrySettings":{"type":"object","properties":{"ca_certificate":{"type":["string","null"],"default":null},"enabled":{"type":"boolean","default":false},"password":{"type":["string","null"],"default":null},"registry_url":{"type":["string","null"],"default":null},"tls_verify":{"type":"boolean","default":true},"username":{"type":["string","null"],"default":null}}},"DockerRegistrySettingsMasked":{"type":"object","description":"Docker registry settings with masked sensitive fields","required":["enabled","tls_verify"],"properties":{"ca_certificate":{"type":["string","null"]},"enabled":{"type":"boolean"},"password":{"type":["string","null"]},"registry_url":{"type":["string","null"]},"tls_verify":{"type":"boolean"},"username":{"type":["string","null"]}}},"DockerfilePresetConfig":{"type":"object","description":"Configuration for Dockerfile preset\nAllows customizing the Dockerfile path and build context for Docker-based deployments","properties":{"buildContext":{"type":["string","null"],"description":"Custom build context path (relative to repository root)\nIf not specified, uses the project's directory setting","example":"./api"},"dockerfilePath":{"type":["string","null"],"description":"Custom Dockerfile path (relative to build context)\nIf not specified, defaults to \"Dockerfile\" in the build context","example":"docker/Dockerfile"},"variant":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DockerfileVariant","description":"Catalog variant. Normally omitted; `custom` selects the generated\nDockerfile compatibility preset."}]}}},"DockerfileVariant":{"type":"string","description":"Catalog variant persisted under the canonical Dockerfile preset.\n\nExisting rows predate this discriminator and therefore deserialize as\n[`DockerfileVariant::File`].","enum":["file","custom"]},"DomainAction":{"type":"string","description":"What to do with a domain during migration","enum":["import","skip"]},"DomainChallengeResponse":{"type":"object","required":["domain","txt_records","status"],"properties":{"domain":{"type":"string"},"status":{"type":"string"},"txt_records":{"type":"array","items":{"$ref":"#/components/schemas/TxtRecord"},"description":"Array of TXT records to add to DNS. For wildcards, multiple records are required."}}},"DomainEnvironmentResponse":{"type":"object","required":["id","name","slug"],"properties":{"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"slug":{"type":"string"}}},"DomainError":{"type":"object","required":["message","code"],"properties":{"code":{"type":"string"},"details":{"type":["string","null"]},"message":{"type":"string"}}},"DomainPlan":{"type":"object","description":"Plan for migrating a single custom domain","required":["domain","environment","action","action_description"],"properties":{"action":{"$ref":"#/components/schemas/DomainAction","description":"What to do with this domain"},"action_description":{"type":"string","description":"Human-readable explanation"},"domain":{"type":"string","description":"Full domain name"},"environment":{"type":"string","description":"Which environment to associate with (\"production\")"},"redirect_to":{"type":["string","null"],"description":"Redirect target (if this is a redirect domain)"},"replacement":{"type":["string","null"],"description":"The temps-side address that replaces this domain when it is skipped.\n\nSource-generated domains (sslip.io / traefik.me / platform subdomains)\nembed the source server's IP and would keep pointing at the old\nmachine — this tells the user where the app will be reachable on\ntemps instead."},"status_code":{"type":["integer","null"],"format":"int32","description":"Redirect status code"}}},"DomainResponse":{"type":"object","required":["id","domain","status","is_wildcard","verification_method","created_at","updated_at"],"properties":{"certificate":{"type":["string","null"],"description":"The PEM-encoded certificate chain (can be displayed in browser or downloaded)"},"created_at":{"type":"integer","format":"int64"},"dns_challenge_token":{"type":["string","null"]},"dns_challenge_value":{"type":["string","null"]},"domain":{"type":"string"},"expiration_time":{"type":["integer","null"],"format":"int64"},"id":{"type":"integer","format":"int32"},"is_wildcard":{"type":"boolean"},"last_error":{"type":["string","null"]},"last_error_type":{"type":["string","null"]},"last_renewed":{"type":["integer","null"],"format":"int64"},"on_demand_backoff_until":{"type":["integer","null"],"format":"int64","description":"On-demand TLS negative-cache deadline (epoch millis), when this hostname's\non-demand HTTP-01 issuance is in backoff after a failure (ADR-018 §4).\n`None` means no active backoff."},"status":{"type":"string"},"updated_at":{"type":"integer","format":"int64"},"verification_method":{"type":"string"}}},"DrainNodeResponse":{"type":"object","required":["id","name","status","affected_environments","message"],"properties":{"affected_environments":{"type":"integer","minimum":0},"id":{"type":"integer","format":"int32"},"message":{"type":"string"},"name":{"type":"string"},"status":{"type":"string"}}},"DrainStatusResponse":{"type":"object","description":"Progress of a node drain operation.","required":["node_id","node_name","status","remaining_containers","drain_complete","can_remove","message"],"properties":{"can_remove":{"type":"boolean","description":"Can the node be safely removed?"},"drain_complete":{"type":"boolean","description":"Whether the drain is complete (all containers migrated)"},"message":{"type":"string"},"node_id":{"type":"integer","format":"int32"},"node_name":{"type":"string"},"remaining_containers":{"type":"integer","description":"Number of containers still on this node","minimum":0},"status":{"type":"string"}}},"DropArchiveUpload":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary"}}},"DropInspectionResponse":{"type":"object","required":["suggestedName","candidates"],"properties":{"candidates":{"type":"array","items":{"$ref":"#/components/schemas/DropPresetCandidate"}},"suggestedName":{"type":"string"}}},"DropOffPoint":{"type":"object","description":"Drop-off point: pages where visitors leave the site","required":["page_path","exit_count","total_views","exit_rate"],"properties":{"exit_count":{"type":"integer","format":"int64","description":"Number of exits from this page"},"exit_rate":{"type":"number","format":"double","description":"Exit rate for this page (exit_count / total_views)"},"page_path":{"type":"string","description":"The page path where visitors drop off"},"total_views":{"type":"integer","format":"int64","description":"Total views of this page"}}},"DropPresetCandidate":{"type":"object","required":["directory","preset","label","confidence","reason","isStatic"],"properties":{"confidence":{"type":"string"},"directory":{"type":"string"},"isStatic":{"type":"boolean"},"label":{"type":"string"},"preset":{"type":"string"},"reason":{"type":"string"}}},"EmailConfig":{"type":"object","required":["smtp_host","smtp_port","username","password","from_address","to_addresses"],"properties":{"accept_invalid_certs":{"type":"boolean"},"from_address":{"type":"string"},"from_name":{"type":["string","null"]},"password":{"type":"string"},"smtp_host":{"type":"string"},"smtp_port":{"type":"integer","format":"int32","minimum":0},"starttls_required":{"type":"boolean"},"tls_mode":{"$ref":"#/components/schemas/TlsMode"},"to_addresses":{"type":"array","items":{"type":"string"}},"username":{"type":"string"}}},"EmailDomainResponse":{"type":"object","required":["id","provider_id","domain","status","created_at","updated_at"],"properties":{"created_at":{"type":"string","example":"2025-12-03T10:30:00Z"},"domain":{"type":"string","example":"updates.example.com"},"id":{"type":"integer","format":"int32"},"last_verified_at":{"type":["string","null"]},"provider_id":{"type":"integer","format":"int32"},"status":{"type":"string","example":"verified"},"updated_at":{"type":"string","example":"2025-12-03T10:30:00Z"},"verification_error":{"type":["string","null"]}}},"EmailDomainWithDnsResponse":{"type":"object","required":["domain","dns_records"],"properties":{"dns_records":{"type":"array","items":{"$ref":"#/components/schemas/DnsRecordResponse"}},"domain":{"$ref":"#/components/schemas/EmailDomainResponse"}}},"EmailProviderResponse":{"type":"object","required":["id","name","provider_type","region","is_active","credentials","created_at","updated_at"],"properties":{"created_at":{"type":"string","example":"2025-12-03T10:30:00Z"},"credentials":{"description":"Masked credentials for display"},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"name":{"type":"string","example":"My AWS SES"},"provider_type":{"$ref":"#/components/schemas/EmailProviderTypeRoute"},"region":{"type":"string","example":"us-east-1"},"sns_topic_arn":{"type":["string","null"]},"updated_at":{"type":"string","example":"2025-12-03T10:30:00Z"}}},"EmailProviderTypeRoute":{"type":"string","enum":["ses","scaleway","smtp"]},"EmailRequest":{"type":"object","description":"Request body carrying just an email address (password-reset request).","required":["email"],"properties":{"email":{"type":"string"}}},"EmailResponse":{"type":"object","required":["id","from_address","to_addresses","subject","status","created_at","track_opens","track_clicks","open_count","click_count"],"properties":{"bcc_addresses":{"type":["array","null"],"items":{"type":"string"}},"cc_addresses":{"type":["array","null"],"items":{"type":"string"}},"click_count":{"type":"integer","format":"int32","description":"Number of times links in the email were clicked"},"created_at":{"type":"string","example":"2025-12-03T10:30:00Z"},"domain_id":{"type":["integer","null"],"format":"int32"},"error_message":{"type":["string","null"]},"first_clicked_at":{"type":["string","null"],"description":"When a link was first clicked"},"first_opened_at":{"type":["string","null"],"description":"When the email was first opened"},"from_address":{"type":"string","example":"hello@updates.example.com"},"from_name":{"type":["string","null"]},"headers":{"type":["object","null"],"additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"html_body":{"type":["string","null"]},"id":{"type":"string","example":"550e8400-e29b-41d4-a716-446655440000"},"open_count":{"type":"integer","format":"int32","description":"Number of times the email was opened"},"project_id":{"type":["integer","null"],"format":"int32"},"provider_message_id":{"type":["string","null"]},"reply_to":{"type":["string","null"]},"sent_at":{"type":["string","null"]},"status":{"type":"string","example":"sent"},"subject":{"type":"string"},"tags":{"type":["array","null"],"items":{"type":"string"}},"text_body":{"type":["string","null"]},"to_addresses":{"type":"array","items":{"type":"string"}},"track_clicks":{"type":"boolean","description":"Whether click tracking is enabled"},"track_opens":{"type":"boolean","description":"Whether open tracking is enabled"},"tracked_html_body":{"type":["string","null"],"description":"The final HTML sent to the provider (with tracking pixel and rewritten links)"}}},"EmailStatsResponse":{"type":"object","required":["total","sent","failed","queued","captured"],"properties":{"captured":{"type":"integer","format":"int64","description":"Emails captured without sending (Mailhog mode - no provider configured)","minimum":0},"failed":{"type":"integer","format":"int64","minimum":0},"queued":{"type":"integer","format":"int64","minimum":0},"sent":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"EmailStatusResponse":{"type":"object","required":["email_configured","password_reset_available","oidc_providers"],"properties":{"email_configured":{"type":"boolean"},"oidc_providers":{"type":"array","items":{"$ref":"#/components/schemas/OidcProviderSummary"}},"password_reset_available":{"type":"boolean"}}},"EmailTrackingResponse":{"type":"object","description":"Email tracking summary","required":["email_id","track_opens","track_clicks","open_count","click_count","unique_opens","unique_clicks","links"],"properties":{"click_count":{"type":"integer","format":"int32"},"email_id":{"type":"string"},"first_clicked_at":{"type":["string","null"]},"first_opened_at":{"type":["string","null"]},"links":{"type":"array","items":{"$ref":"#/components/schemas/TrackedLinkResponse"}},"open_count":{"type":"integer","format":"int32"},"track_clicks":{"type":"boolean"},"track_opens":{"type":"boolean"},"unique_clicks":{"type":"integer","format":"int64","minimum":0},"unique_opens":{"type":"integer","format":"int64","minimum":0}}},"EmailTrackingSetupResponse":{"type":"object","description":"Result of the one-click AWS-side event-tracking setup.","required":["topic_arn","webhook_url","subscription_requested","event_destination_attached"],"properties":{"event_destination_attached":{"type":"boolean","description":"The SESv2 event destination (bounce/complaint/delivery) is attached\nto the `temps-tracking` configuration set."},"subscription_requested":{"type":"boolean","description":"The webhook subscription was requested; SNS confirms it\nasynchronously through the webhook itself."},"topic_arn":{"type":"string","example":"arn:aws:sns:us-east-1:123456789012:temps-email-events-1"},"webhook_url":{"type":"string"}}},"EmailTrackingStatusResponse":{"type":"object","description":"Live status of the SES event-tracking pipeline for one provider.","required":["webhook_url","supports_event_tracking"],"properties":{"last_event_at":{"type":["string","null"],"description":"Most recent delivered/bounced/complained event recorded for an email\nsent through this provider. `null` means no provider feedback has\narrived yet.","example":"2026-07-18T10:31:00Z"},"sns_topic_arn":{"type":["string","null"]},"subscription_confirmed_at":{"type":["string","null"],"description":"When the SNS subscription for the current topic was confirmed.\n`null` with a topic set usually means the subscription is still\npending — most often because the endpoint was subscribed before the\ntopic ARN was saved here.","example":"2026-07-18T10:30:00Z"},"supports_event_tracking":{"type":"boolean","description":"Only SES providers support SNS event tracking."},"webhook_url":{"type":"string","description":"Public webhook endpoint SNS must deliver events to.","example":"https://temps.example.com/api/t/webhook/ses"}}},"EmbeddingData":{"type":"object","required":["object","embedding","index"],"properties":{"embedding":{"type":"array","items":{"type":"number","format":"double"}},"index":{"type":"integer","format":"int32"},"object":{"type":"string"}}},"EmbeddingInput":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]},"EmbeddingRequest":{"type":"object","required":["model","input"],"properties":{"dimensions":{"type":["integer","null"],"format":"int32"},"encoding_format":{"type":["string","null"]},"input":{"$ref":"#/components/schemas/EmbeddingInput"},"model":{"type":"string"}}},"EmbeddingResponse":{"type":"object","required":["object","data","model","usage"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/EmbeddingData"}},"model":{"type":"string"},"object":{"type":"string"},"usage":{"$ref":"#/components/schemas/EmbeddingUsage"}}},"EmbeddingUsage":{"type":"object","required":["prompt_tokens","total_tokens"],"properties":{"prompt_tokens":{"type":"integer","format":"int64"},"total_tokens":{"type":"integer","format":"int64"}}},"EnableBlobRequest":{"type":"object","description":"Request to enable Blob service","properties":{"docker_image":{"type":["string","null"],"description":"Docker image to use (optional, defaults to RustFS)","example":"ghcr.io/rustfs/rustfs:0.5.0"},"root_password":{"type":["string","null"],"description":"Root password for S3 access"},"root_user":{"type":["string","null"],"description":"Root user for S3 access"}}},"EnableBlobResponse":{"type":"object","description":"Response after enabling Blob service","required":["success","message","status"],"properties":{"message":{"type":"string","description":"Human-readable message","example":"Blob service enabled successfully"},"status":{"$ref":"#/components/schemas/BlobStatusResponse","description":"Current status"},"success":{"type":"boolean","description":"Whether the operation succeeded","example":true}}},"EnableKvRequest":{"type":"object","description":"Request to enable the KV service","properties":{"docker_image":{"type":["string","null"],"description":"Docker image to use (optional, uses default if not provided)","example":"gotempsh/redis-walg:8-bookworm"},"max_memory":{"type":["string","null"],"description":"Maximum memory allocation (e.g., \"256mb\", \"1gb\")","example":"256mb"},"persistence":{"type":"boolean","description":"Enable data persistence"}}},"EnableKvResponse":{"type":"object","description":"Response after enabling KV service","required":["success","message","status"],"properties":{"message":{"type":"string","description":"Status message","example":"KV service enabled successfully"},"status":{"$ref":"#/components/schemas/KvStatusResponse","description":"Current service status"},"success":{"type":"boolean","description":"Whether the service was successfully enabled"}}},"EnablePgStatStatementsResponse":{"type":"object","description":"Response for the enable pg_stat_statements endpoint.","required":["message"],"properties":{"message":{"type":"string","description":"Human-readable message confirming the action."}}},"EndpointDto":{"type":"object","description":"One DNS record on the wire. Mirrors `service_endpoints::Model` but\nkeeps the API stable across entity evolution. `target_ip` is a string\n(v4 or v6 literal, or CNAME target hostname) parsed by the resolver.","required":["id","fqdn","record_type","ttl","owner_kind","owner_id","generation"],"properties":{"fqdn":{"type":"string"},"generation":{"type":"integer","format":"int64"},"id":{"type":"integer","format":"int64"},"node_id":{"type":["integer","null"],"format":"int32"},"owner_id":{"type":"integer","format":"int64"},"owner_kind":{"type":"string"},"record_type":{"type":"string"},"target_ip":{"type":["string","null"]},"target_port":{"type":["integer","null"],"format":"int32"},"ttl":{"type":"integer","format":"int32"}}},"EnqueuedJob":{"type":"object","description":"A single job that was successfully enqueued during a fan-out run.","required":["backup_id","job_id","engine"],"properties":{"backup_id":{"type":"integer","format":"int32","description":"FK to `backups.id` for this job."},"engine":{"type":"string","description":"Engine key (e.g. `\"control_plane\"`, `\"redis\"`, `\"postgres_pgdump\"`)."},"job_id":{"type":"integer","format":"int64","description":"FK to `backup_jobs.id` for this job."},"target_service_id":{"type":["integer","null"],"format":"int32","description":"FK to `external_services.id` when this is an external-service job.\n`None` for the control-plane job."}}},"EnrichVisitorRequest":{"type":"object","required":["custom_data"],"properties":{"custom_data":{"type":"object"}}},"EnrichVisitorResponse":{"type":"object","required":["success","visitor_id","message"],"properties":{"message":{"type":"string"},"success":{"type":"boolean"},"visitor_id":{"type":"string"}}},"EnrollmentTokenInfo":{"type":"object","required":["id","expires_at","used_count","max_uses","created_at"],"properties":{"bound_node_name":{"type":["string","null"]},"created_at":{"type":"string"},"expires_at":{"type":"string"},"id":{"type":"integer","format":"int32"},"max_uses":{"type":"integer","format":"int32"},"used_count":{"type":"integer","format":"int32"}}},"EnrollmentTokenListResponse":{"type":"object","required":["tokens"],"properties":{"tokens":{"type":"array","items":{"$ref":"#/components/schemas/EnrollmentTokenInfo"}}}},"EntityInfoResponse":{"type":"object","required":["container_path","entity","entity_type","fields"],"properties":{"container_path":{"type":"array","items":{"type":"string"},"description":"Full container path","example":["mydb","public"]},"entity":{"type":"string","description":"Entity name","example":"users"},"entity_type":{"type":"string","description":"Entity type","example":"table"},"fields":{"type":"array","items":{"$ref":"#/components/schemas/FieldResponse"},"description":"Field definitions"},"metadata":{"description":"Additional metadata (content_type, last_modified, etag, etc.)"},"row_count":{"type":["integer","null"],"description":"Approximate row count (for tables/collections)","example":1234,"minimum":0},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Size in bytes (for objects/files)","example":1048576,"minimum":0},"sort_schema":{"description":"JSON Schema for sort options (if supported)"}}},"EntityResponse":{"type":"object","required":["name","entity_type"],"properties":{"entity_type":{"type":"string","description":"Entity type (table, view, collection, etc.)","example":"table"},"name":{"type":"string","description":"Entity name (table/collection)","example":"users"},"row_count":{"type":["integer","null"],"description":"Approximate row count","example":1234,"minimum":0},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Size in bytes (for files/objects)","example":1048576,"minimum":0}}},"EnvVarInput":{"type":"object","description":"Input for environment variable","required":["name","value"],"properties":{"name":{"type":"string","description":"Variable name"},"value":{"type":"string","description":"Variable value"}}},"EnvVarIntegrationInfo":{"type":"object","required":["service_id","service_name","service_type","service_updated_at"],"properties":{"service_id":{"type":"integer","format":"int32"},"service_name":{"type":"string"},"service_slug":{"type":["string","null"]},"service_type":{"type":"string"},"service_updated_at":{"type":"string"}}},"EnvVarResponse":{"type":"object","description":"Environment variable with masked sensitive values","required":["key","value","is_masked"],"properties":{"is_masked":{"type":"boolean","description":"Whether this is a sensitive/masked value"},"key":{"type":"string"},"value":{"type":"string"}}},"EnvVarTemplateResponse":{"type":"object","description":"Environment variable template response","required":["name","required"],"properties":{"default":{"type":["string","null"],"description":"Default value if not provided by user"},"default_generator":{"type":["string","null"],"description":"Frontend-side generator hint for the default value\n(e.g. `app_url`, `random_secret`, `random_hex_32`)"},"description":{"type":["string","null"],"description":"Description of what this variable is used for"},"example":{"type":["string","null"],"description":"Example value for documentation"},"name":{"type":"string","description":"Name of the environment variable"},"required":{"type":"boolean","description":"Whether this variable is required"}}},"EnvironmentConfiguration":{"type":"object","description":"Environment-level configuration","required":["name","subdomain","resources"],"properties":{"name":{"type":"string","description":"Environment name"},"resources":{"$ref":"#/components/schemas/ResourceLimits","description":"Resource limits for environment"},"subdomain":{"type":"string","description":"Proposed subdomain"}}},"EnvironmentDomainResponse":{"type":"object","required":["id","environment_id","domain","created_at","url"],"properties":{"created_at":{"type":"integer","format":"int64"},"domain":{"type":"string"},"environment_id":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"url":{"type":"string","description":"Full URL for this domain (e.g., https://buildtolearndev-production.example.com)","example":"https://buildtolearndev-production.example.com"}}},"EnvironmentInfo":{"type":"object","required":["id","name","main_url"],"properties":{"current_deployment_id":{"type":["integer","null"],"format":"int32"},"id":{"type":"integer","format":"int32"},"main_url":{"type":"string"},"name":{"type":"string"}}},"EnvironmentResponse":{"type":"object","required":["id","project_id","name","slug","main_url","subdomain","created_at","updated_at","is_preview","protected","sleeping"],"properties":{"attack_mode":{"type":["boolean","null"],"description":"Per-environment CAPTCHA attack-mode override.\n`null` means inherit the project-level `attack_mode`; `true`/`false`\nexplicitly enable/disable the challenge for this environment. Always\nserialized (NOT skipped) so the UI can distinguish `null` from `false`."},"branch":{"type":["string","null"]},"created_at":{"type":"integer","format":"int64"},"current_deployment_id":{"type":["integer","null"],"format":"int32"},"deployment_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DeploymentConfig","description":"Deployment configuration for this environment (overrides project-level config)"}]},"estimated_sleep_at":{"type":["integer","null"],"format":"int64","description":"Estimated time (epoch millis) when the environment will go to sleep\nbased on last activity + idle timeout. NULL when sleeping or on-demand disabled."},"force_https":{"type":["boolean","null"],"description":"Per-environment HTTP→HTTPS redirect override.\n`null` means inherit the proxy default (redirect only when the host has\nan active TLS certificate); `true` always redirects plain HTTP for this\nenvironment, `false` never does. Always serialized (NOT skipped) so the\nUI can distinguish `null` from `false`."},"id":{"type":"integer","format":"int32"},"is_preview":{"type":"boolean","description":"Indicates if this is a preview environment (auto-created per branch)\nFor preview environments, 'branch' contains the feature branch name"},"last_activity_at":{"type":["integer","null"],"format":"int64","description":"Last proxied request timestamp (epoch millis) for on-demand environments.\nNULL when on-demand is disabled or no traffic has been received yet."},"main_url":{"type":"string"},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"protected":{"type":"boolean","description":"When true, git pushes do NOT auto-deploy to this environment.\nDeployments must be promoted from another environment."},"sleeping":{"type":"boolean","description":"When true, the environment's containers are currently stopped due to\ninactivity (on-demand mode) and will start on the next request."},"slug":{"type":"string"},"subdomain":{"type":"string","description":"The host label stored for this environment (e.g.\n`myproject-production`). This is the prefix that is combined with the\nplatform's preview domain at request time to produce `main_url`. Edit\nthis via the rename-subdomain endpoint, not the full URL."},"updated_at":{"type":"integer","format":"int64"}}},"EnvironmentVariable":{"type":"object","description":"Environment variable","required":["key","value","is_secret"],"properties":{"is_secret":{"type":"boolean","description":"Whether this is a secret (should be encrypted)"},"key":{"type":"string","description":"Variable name"},"source_description":{"type":["string","null"],"description":"Where this env var originates from (for traceability)"},"value":{"type":"string","description":"Variable value (may be redacted for secrets)"}}},"EnvironmentVariableInfo":{"type":"object","required":["name","value","sensitive"],"properties":{"name":{"type":"string"},"sensitive":{"type":"boolean","description":"Whether this variable contains sensitive data (passwords, keys, tokens)","example":false},"value":{"type":"string"}}},"EnvironmentVariableResponse":{"type":"object","required":["id","key","created_at","updated_at","environments","include_in_preview","is_secret"],"properties":{"created_at":{"type":"integer","format":"int64"},"environments":{"type":"array","items":{"$ref":"#/components/schemas/EnvironmentInfo"}},"id":{"type":"integer","format":"int32"},"include_in_preview":{"type":"boolean","description":"Include this environment variable in preview environments"},"is_secret":{"type":"boolean","description":"Whether the variable is a write-only secret. Secrets always have\n`value: None` in responses."},"key":{"type":"string"},"updated_at":{"type":"integer","format":"int64"},"value":{"type":["string","null"],"description":"Plaintext value for non-secret vars (or `\"***\"` mask for list responses).\n`None` for secret vars — secrets are write-only."}}},"EnvironmentVariableValueResponse":{"type":"object","required":["value"],"properties":{"value":{"type":"string"}}},"ErrorDashboardStatsQuery":{"type":"object","required":["start_time","end_time"],"properties":{"compare_to_previous":{"type":["boolean","null"]},"end_time":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"start_time":{"type":"string","format":"date-time"}}},"ErrorDashboardStatsResponse":{"type":"object","required":["total_errors","total_errors_previous_period","total_errors_change_percent","error_groups","error_groups_previous_period","start_time","end_time"],"properties":{"comparison_end_time":{"type":["string","null"],"format":"date-time"},"comparison_start_time":{"type":["string","null"],"format":"date-time"},"end_time":{"type":"string","format":"date-time"},"error_groups":{"type":"integer","format":"int64"},"error_groups_previous_period":{"type":"integer","format":"int64"},"start_time":{"type":"string","format":"date-time"},"total_errors":{"type":"integer","format":"int64"},"total_errors_change_percent":{"type":"number","format":"double"},"total_errors_previous_period":{"type":"integer","format":"int64"}}},"ErrorEventResponse":{"type":"object","required":["id","error_group_id","timestamp","created_at"],"properties":{"created_at":{"type":"string"},"data":{"description":"Full error event data (contains raw Sentry event or custom error data)"},"error_group_id":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int64"},"source":{"type":["string","null"],"description":"Source of the error event (e.g., \"sentry\", \"custom\", \"bugsnag\")"},"timestamp":{"type":"string"}}},"ErrorGroupResponse":{"type":"object","required":["id","title","error_type","first_seen","last_seen","total_count","status","project_id","created_at","updated_at"],"properties":{"assigned_to":{"type":["string","null"]},"created_at":{"type":"string"},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"error_type":{"type":"string"},"first_seen":{"type":"string"},"id":{"type":"integer","format":"int32"},"last_seen":{"type":"string"},"message_template":{"type":["string","null"]},"project_id":{"type":"integer","format":"int32"},"status":{"type":"string"},"title":{"type":"string"},"total_count":{"type":"integer","format":"int32"},"updated_at":{"type":"string"},"visitor_id":{"type":["integer","null"],"format":"int32"}}},"ErrorGroupStatsResponse":{"type":"object","required":["total_groups","unresolved_groups","resolved_groups","ignored_groups"],"properties":{"ignored_groups":{"type":"integer","format":"int64"},"resolved_groups":{"type":"integer","format":"int64"},"total_groups":{"type":"integer","format":"int64"},"unresolved_groups":{"type":"integer","format":"int64"}}},"ErrorResponse":{"type":"object","required":["error"],"properties":{"details":{"type":["string","null"]},"error":{"type":"string"}}},"ErrorRow":{"type":"object","required":["id","ts","error_group_id","fingerprint","error_class","stacktrace_preview","stacktrace_truncated"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"error_class":{"type":"string"},"error_group_id":{"type":"integer","format":"int32"},"fingerprint":{"type":"string"},"id":{"type":"integer","format":"int64"},"message":{"type":["string","null"]},"stacktrace_preview":{},"stacktrace_truncated":{"type":"boolean"},"trace_id":{"type":["string","null"]},"ts":{"type":"string","format":"date-time"}}},"ErrorTimeSeriesDataResponse":{"type":"object","required":["timestamp","count"],"properties":{"count":{"type":"integer","format":"int64"},"timestamp":{"type":"string"}}},"ErrorTimeSeriesQuery":{"type":"object","required":["start_time","end_time"],"properties":{"bucket":{"type":"string","description":"Time bucket size (e.g., \"1h\", \"15m\", \"1d\", \"1 hour\", \"30 minutes\")","example":"1h"},"end_time":{"type":"string","format":"date-time"},"start_time":{"type":"string","format":"date-time"}}},"EventActivityBucket":{"type":"object","description":"Time bucket data point for event activity graph","required":["timestamp","count","unique_visitors"],"properties":{"count":{"type":"integer","format":"int64","description":"Number of event occurrences in this bucket"},"timestamp":{"type":"string","description":"Timestamp for this bucket (ISO 8601)"},"unique_visitors":{"type":"integer","format":"int64","description":"Number of unique visitors in this bucket"}}},"EventBreakdown":{"type":"string","enum":["country","region","city"]},"EventBrowserStats":{"type":"object","description":"Browser stats for an event","required":["browser","count","percentage"],"properties":{"browser":{"type":"string","description":"Browser name"},"count":{"type":"integer","format":"int64","description":"Number of event occurrences from this browser"},"percentage":{"type":"number","format":"double","description":"Percentage of total events"}}},"EventCount":{"type":"object","required":["event_name","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"event_name":{"type":"string"},"percentage":{"type":"number","format":"double"}}},"EventCountryStats":{"type":"object","description":"Country stats for an event","required":["country","count","percentage"],"properties":{"count":{"type":"integer","format":"int64","description":"Number of event occurrences from this country"},"country":{"type":"string","description":"Country name"},"country_code":{"type":["string","null"],"description":"ISO country code (2-letter)"},"percentage":{"type":"number","format":"double","description":"Percentage of total events"}}},"EventDetailQuery":{"type":"object","description":"Query parameters for event detail analytics","required":["event_name","project_id","start_date","end_date"],"properties":{"bucket_interval":{"type":["string","null"],"description":"Bucket interval for time series: 'hour', 'day', 'week', 'month' (default: auto)"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"event_name":{"type":"string","description":"The specific event name to get details for"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"EventDetailResponse":{"type":"object","description":"Summary response for a specific event's analytics","required":["event_name","total_count","unique_visitors","unique_sessions","activity_over_time","referrers","countries","browsers","bucket_interval"],"properties":{"activity_over_time":{"type":"array","items":{"$ref":"#/components/schemas/EventActivityBucket"},"description":"Time series data for event activity graph"},"browsers":{"type":"array","items":{"$ref":"#/components/schemas/EventBrowserStats"},"description":"Browser distribution of visitors who triggered this event"},"bucket_interval":{"type":"string","description":"Bucket interval used for time series ('hour', 'day', etc.)"},"countries":{"type":"array","items":{"$ref":"#/components/schemas/EventCountryStats"},"description":"Geographic distribution of visitors who triggered this event"},"event_name":{"type":"string","description":"The event name being analyzed"},"referrers":{"type":"array","items":{"$ref":"#/components/schemas/EventReferrerStats"},"description":"Top referrer hostnames for visitors who triggered this event"},"total_count":{"type":"integer","format":"int64","description":"Total number of times this event was triggered in the date range"},"unique_sessions":{"type":"integer","format":"int64","description":"Number of unique sessions where this event occurred"},"unique_visitors":{"type":"integer","format":"int64","description":"Number of unique visitors who triggered this event"}}},"EventEntriesQuery":{"type":"object","description":"Query parameters for the raw event entries list","required":["event_name","project_id","start_date","end_date"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"event_name":{"type":"string","description":"The specific event name to list occurrences for"},"page":{"type":["integer","null"],"format":"int64","description":"Page number (1-based, default: 1)","minimum":0},"per_page":{"type":["integer","null"],"format":"int64","description":"Items per page (default: 20, max: 100)","minimum":0},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"EventEntriesResponse":{"type":"object","description":"Paginated response for raw event entries","required":["event_name","total_count","page","per_page","entries"],"properties":{"entries":{"type":"array","items":{"$ref":"#/components/schemas/EventEntryInfo"},"description":"Individual event occurrences, most recent first"},"event_name":{"type":"string","description":"The event name"},"page":{"type":"integer","format":"int64","description":"Current page number","minimum":0},"per_page":{"type":"integer","format":"int64","description":"Items per page","minimum":0},"total_count":{"type":"integer","format":"int64","description":"Total number of occurrences of this event in the date range"}}},"EventEntryInfo":{"type":"object","description":"A single raw occurrence of an event, including its custom JSON properties","required":["id","timestamp","page_path","href"],"properties":{"browser":{"type":["string","null"],"description":"Browser name"},"city":{"type":["string","null"],"description":"City of the visitor at the time of the event"},"country":{"type":["string","null"],"description":"Country of the visitor at the time of the event"},"country_code":{"type":["string","null"],"description":"ISO country code (2-letter)"},"device_type":{"type":["string","null"],"description":"Device type (Desktop, Mobile, Tablet)"},"href":{"type":"string","description":"Full URL where the event was triggered"},"id":{"type":"integer","format":"int64","description":"Event row ID"},"page_path":{"type":"string","description":"Page path where the event was triggered"},"props":{"type":["object","null"],"description":"Custom event properties as JSON (null when the event carried no data)"},"session_id":{"type":["string","null"],"description":"Session ID the event belongs to (if any)"},"timestamp":{"type":"string","format":"date-time","description":"When the event occurred"},"visitor_id":{"type":["integer","null"],"format":"int32","description":"Visitor numeric ID (if known)"},"visitor_uuid":{"type":["string","null"],"description":"Visitor UUID (if known)"}}},"EventKind":{"type":"string","description":"Tag enum for filter parameters and routing. Matches the variant\ndiscriminator used by `ObservabilityEvent`.","enum":["request","span","error","revenue"]},"EventMetricsPayload":{"type":"object","required":["event_name","event_data","request_path","request_query"],"properties":{"cls":{"type":["number","null"],"format":"float","description":"Cumulative Layout Shift (score)"},"event_data":{},"event_name":{"type":"string"},"fcp":{"type":["number","null"],"format":"float","description":"First Contentful Paint (milliseconds)"},"fid":{"type":["number","null"],"format":"float","description":"First Input Delay (milliseconds)"},"inp":{"type":["number","null"],"format":"float","description":"Interaction to Next Paint (milliseconds)"},"language":{"type":["string","null"]},"lcp":{"type":["number","null"],"format":"float","description":"Largest Contentful Paint (milliseconds)"},"page_title":{"type":["string","null"]},"referrer":{"type":["string","null"],"description":"Referrer URL (falls back to Referer header if not provided)"},"request_path":{"type":"string"},"request_query":{"type":"string"},"screen_height":{"type":["integer","null"],"format":"int32","minimum":0},"screen_width":{"type":["integer","null"],"format":"int32","minimum":0},"ttfb":{"type":["number","null"],"format":"float","description":"Time to First Byte (milliseconds)"},"viewport_height":{"type":["integer","null"],"format":"int32","minimum":0},"viewport_width":{"type":["integer","null"],"format":"int32","minimum":0}}},"EventReferrerStats":{"type":"object","description":"Referrer stats for an event","required":["referrer","count","percentage"],"properties":{"count":{"type":"integer","format":"int64","description":"Number of event occurrences from this referrer"},"percentage":{"type":"number","format":"double","description":"Percentage of total events"},"referrer":{"type":"string","description":"Referrer hostname or \"Direct\""}}},"EventTimeline":{"type":"object","required":["date","count"],"properties":{"count":{"type":"integer","format":"int64"},"date":{"type":"string","format":"date-time"}}},"EventTimelineQuery":{"type":"object","required":["start_date","end_date"],"properties":{"aggregation_level":{"$ref":"#/components/schemas/AggregationLevel","description":"Aggregation level: events (raw count), sessions (unique sessions), or visitors (unique visitors)"},"bucket_size":{"type":["string","null"],"description":"Bucket size: hour, day, or week (auto-detected if not specified)"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"event_name":{"type":["string","null"]},"start_date":{"type":"string","format":"date-time"}}},"EventType":{"type":"object","required":["name","count"],"properties":{"count":{"type":"integer","format":"int64"},"name":{"type":"string"}}},"EventTypeBreakdown":{"type":"object","required":["event_type","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"event_type":{"type":"string"},"percentage":{"type":"number","format":"double"}}},"EventTypeBreakdownQuery":{"type":"object","required":["start_date","end_date"],"properties":{"aggregation_level":{"$ref":"#/components/schemas/AggregationLevel","description":"Aggregation level: events (raw count), sessions (unique sessions), or visitors (unique visitors)"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"EventTypeResponse":{"type":"object","required":["event_type","description","category"],"properties":{"category":{"type":"string"},"description":{"type":"string"},"event_type":{"type":"string"}}},"EventTypesResponse":{"type":"object","required":["events","total","page","page_size"],"properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/EventType"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"EventVisitorInfo":{"type":"object","description":"A visitor who triggered a specific event","required":["visitor_id","visitor_uuid","event_count","first_triggered","last_triggered"],"properties":{"browser":{"type":["string","null"],"description":"Browser name"},"city":{"type":["string","null"],"description":"Visitor's city"},"country":{"type":["string","null"],"description":"Visitor's country"},"country_code":{"type":["string","null"],"description":"Visitor's country code"},"device_type":{"type":["string","null"],"description":"Device type (Desktop, Mobile, Tablet)"},"event_count":{"type":"integer","format":"int64","description":"Number of times this visitor triggered the event"},"first_triggered":{"type":"string","format":"date-time","description":"When the visitor first triggered the event in the date range"},"last_triggered":{"type":"string","format":"date-time","description":"When the visitor last triggered the event in the date range"},"referrer_hostname":{"type":["string","null"],"description":"Referrer hostname for the event"},"visitor_id":{"type":"integer","format":"int32","description":"Visitor numeric ID"},"visitor_uuid":{"type":"string","description":"Visitor UUID"}}},"EventVisitorsQuery":{"type":"object","description":"Query parameters for event visitors list","required":["event_name","project_id","start_date","end_date"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"event_name":{"type":"string","description":"The specific event name to list visitors for"},"page":{"type":["integer","null"],"format":"int64","description":"Page number (1-based, default: 1)","minimum":0},"per_page":{"type":["integer","null"],"format":"int64","description":"Items per page (default: 20, max: 100)","minimum":0},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"EventVisitorsResponse":{"type":"object","description":"Paginated response for event visitors","required":["event_name","total_count","page","per_page","visitors"],"properties":{"event_name":{"type":"string","description":"The event name"},"page":{"type":"integer","format":"int64","description":"Current page number","minimum":0},"per_page":{"type":"integer","format":"int64","description":"Items per page","minimum":0},"total_count":{"type":"integer","format":"int64","description":"Total number of unique visitors who triggered this event"},"visitors":{"type":"array","items":{"$ref":"#/components/schemas/EventVisitorInfo"},"description":"Individual visitors who triggered this event"}}},"EventsCountQuery":{"type":"object","required":["start_date","end_date"],"properties":{"aggregation_level":{"$ref":"#/components/schemas/AggregationLevel","description":"Aggregation level: events (raw count), sessions (unique sessions), or visitors (unique visitors)"},"custom_events_only":{"type":["boolean","null"],"description":"Only return custom events, excluding system events like page_view, page_leave, heartbeat (default: true)"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"EventsResponse":{"type":"object","required":["events","applied_kinds"],"properties":{"applied_kinds":{"type":"array","items":{"$ref":"#/components/schemas/EventKind"},"description":"Echo of the kinds filter actually applied (server-resolved). Useful\nfor clients that pass `kinds=` empty and want to know what they got."},"events":{"type":"array","items":{"$ref":"#/components/schemas/ObservabilityEvent"}}}},"ExecBody":{"type":"object","required":["cmd"],"properties":{"cmd":{"type":"array","items":{"type":"string"}},"cwd":{"type":["string","null"]},"env":{"type":"object","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}}},"additionalProperties":false},"ExecDetachedResponse":{"type":"object","required":["job_id"],"properties":{"job_id":{"type":"string"}}},"ExecResponse":{"type":"object","required":["exit_code","stdout","stderr"],"properties":{"exit_code":{"type":"integer","format":"int32"},"stderr":{"type":"string"},"stdout":{"type":"string"}}},"ExecuteImportRequest":{"type":"object","description":"Request to execute an import","required":["session_id","project_name","preset","directory","main_branch"],"properties":{"directory":{"type":"string","description":"Project directory","example":"."},"dry_run":{"type":["boolean","null"],"description":"Dry run mode (don't create resources)"},"main_branch":{"type":"string","description":"Main branch name","example":"main"},"preset":{"type":"string","description":"Preset to use for the project (e.g., \"nextjs\", \"express\", \"docker\")"},"project_name":{"type":"string","description":"Project name to use (overrides the name from the plan)","example":"my-app"},"session_id":{"type":"string","description":"Session ID from plan creation"}}},"ExecuteImportResponse":{"type":"object","description":"Response from import execution","required":["session_id","status","step_results"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32","description":"Created deployment ID (if completed)"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Created environment ID (if completed)"},"project_id":{"type":["integer","null"],"format":"int32","description":"Created project ID (if completed)"},"session_id":{"type":"string","description":"Session ID"},"status":{"$ref":"#/components/schemas/ImportExecutionStatus","description":"Execution status"},"step_results":{"type":"array","items":{"$ref":"#/components/schemas/StepResult"},"description":"Per-step results (in execution order)"}}},"ExecuteOperationRequest":{"type":"object","required":["operation"],"properties":{"operation":{"type":"string"}}},"ExpireRequest":{"type":"object","description":"Request to set expiration on a key","required":["key","seconds"],"properties":{"key":{"type":"string","description":"The key to set expiration on","example":"session:abc"},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1},"seconds":{"type":"integer","format":"int64","description":"Expiration time in seconds","example":3600}}},"ExpireResponse":{"type":"object","description":"Response for expire operation","required":["success"],"properties":{"success":{"type":"boolean","description":"True if expiration was set, false if key doesn't exist"}}},"ExplorerSupportResponse":{"type":"object","required":["supported","service_type","capabilities","hierarchy"],"properties":{"capabilities":{"type":"array","items":{"type":"string"},"description":"Capabilities supported by this service","example":["sql"]},"filter_schema":{"description":"JSON Schema for filter format with embedded UI hints (if supported)"},"hierarchy":{"type":"array","items":{"$ref":"#/components/schemas/HierarchyLevel"},"description":"Hierarchy levels (describes the navigation structure)"},"reason":{"type":["string","null"],"description":"Reason why explorer is not supported (if applicable)"},"service_type":{"type":"string","description":"Service type","example":"postgres"},"supported":{"type":"boolean","description":"Whether the service supports query explorer functionality","example":true}}},"ExtendTimeoutBody":{"type":"object","properties":{"duration":{"type":["integer","null"],"format":"int64","description":"`@vercel/sandbox`-compatible alternative — duration in milliseconds.\nUsed when `extra_secs` is absent.","minimum":0},"extra_secs":{"type":["integer","null"],"format":"int64","description":"Extra seconds to add to the existing `expires_at` (temps-native).","minimum":0}}},"ExternalImageResponse":{"type":"object","required":["id","project_id","image_ref","pushed_at","created_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"digest":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"image_ref":{"type":"string"},"metadata":{},"project_id":{"type":"integer","format":"int32"},"pushed_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"size_bytes":{"type":["integer","null"],"format":"int64"},"tag":{"type":["string","null"]}}},"ExternalServiceBackupResponse":{"type":"object","description":"Response type for external service backup","required":["id","service_id","backup_id","backup_type","state","started_at","s3_location","metadata","compression_type","created_by"],"properties":{"backup_id":{"type":"integer","format":"int32"},"backup_type":{"type":"string"},"checksum":{"type":["string","null"]},"compression_type":{"type":"string"},"created_by":{"type":"integer","format":"int32"},"error_message":{"type":["string","null"]},"expires_at":{"type":["string","null"],"example":"2025-02-15T14:30:00.123Z"},"finished_at":{"type":["string","null"],"example":"2025-01-15T14:35:00.456Z"},"id":{"type":"integer","format":"int32"},"metadata":{},"s3_location":{"type":"string"},"service_id":{"type":"integer","format":"int32"},"size_bytes":{"type":["integer","null"],"format":"int64"},"started_at":{"type":"string","example":"2025-01-15T14:30:00.123Z"},"state":{"type":"string"}}},"ExternalServiceDetails":{"type":"object","required":["service","sensitive_parameters"],"properties":{"current_parameters":{"type":["object","null"],"additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"parameter_schema":{},"sensitive_parameters":{"type":"array","items":{"type":"string"},"description":"Parameter names whose values are masked in `current_parameters` and\nmay be fetched only through the audited reveal endpoint."},"service":{"$ref":"#/components/schemas/ExternalServiceInfo"}}},"ExternalServiceInfo":{"type":"object","required":["id","name","service_type","status","created_at","updated_at","topology"],"properties":{"connection_info":{"type":["string","null"]},"created_at":{"type":"string"},"error_message":{"type":["string","null"],"description":"Error message from failed initialization."},"id":{"type":"integer","format":"int32"},"members":{"type":"array","items":{"$ref":"#/components/schemas/ServiceMemberInfo"},"description":"Cluster members (empty for standalone services)."},"metrics_enabled":{"type":"boolean","description":"Whether metric collection is enabled for this service. The UI uses this\nto decide whether to poll the monitoring endpoints."},"name":{"type":"string"},"node_id":{"type":["integer","null"],"format":"int32","description":"Node ID where the service runs. Null means control plane (local)."},"service_type":{"$ref":"#/components/schemas/ServiceTypeRoute"},"status":{"type":"string"},"topology":{"type":"string","description":"Service topology: \"standalone\" (single container) or \"cluster\" (HA multi-member).","example":"standalone"},"updated_at":{"type":"string"},"version":{"type":["string","null"]}}},"ExternalServiceSummary":{"type":"object","description":"Summary of the external service that owns a backup. Only populated for\nexternal-service backups (Redis, Postgres, etc.); absent for control-plane\nbackups.","required":["id","name","service_type"],"properties":{"id":{"type":"integer","format":"int32","description":"Database id of the external service."},"name":{"type":"string","description":"Human-readable service name (e.g. \"redis-prod\")."},"service_type":{"type":"string","description":"Service type string (e.g. \"postgres\", \"redis\", \"mongodb\").","example":"postgres"}}},"FieldResponse":{"type":"object","required":["name","field_type","nullable"],"properties":{"field_type":{"type":"string","description":"Field type (Int32, String, Timestamp, etc.)","example":"Int64"},"name":{"type":"string","description":"Field name","example":"id"},"nullable":{"type":"boolean","description":"Whether the field is nullable","example":false}}},"FiringSeriesEntry":{"type":"object","description":"A single currently-firing series for a dynamic alert rule, snapshotted from\nthe evaluator's in-memory per-series firing map at read time (ADR-026 Phase 3).","required":["series_key","series_label"],"properties":{"alarm_id":{"type":["integer","null"],"format":"int32","description":"The open alarm's id, when one was created (absent if suppressed)."},"series_key":{"type":"array","items":{"type":"array","items":false,"prefixItems":[{"type":"string"},{"type":"string"}]},"description":"The series' label pairs, e.g. `[[\"endpoint\",\"/checkout\"],[\"region\",\"eu-west\"]]`."},"series_label":{"type":"string","description":"The human-readable joined label, e.g. `endpoint=/checkout, region=eu-west`."}}},"FlagEnvironmentResponse":{"type":"object","required":["environment_id","enabled"],"properties":{"enabled":{"type":"boolean"},"environment_id":{"type":"integer","format":"int32"},"value":{}}},"FlagListResponse":{"type":"object","description":"Note the absence of `salt`: it is never exposed. Publishing the bucketing\nsalt would let a client predict, and self-select into, a rollout cohort.","required":["flags","total","page","page_size","total_pages"],"properties":{"flags":{"type":"array","items":{"$ref":"#/components/schemas/FlagResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","description":"Total flags matching the filter, across all pages.","minimum":0},"total_pages":{"type":"integer","format":"int64","minimum":0}}},"FlagResponse":{"type":"object","required":["id","key","value_type","default_value","client_visible","created_at","updated_at","environments"],"properties":{"archived_at":{"type":["string","null"]},"client_visible":{"type":"boolean"},"created_at":{"type":"string"},"default_value":{},"description":{"type":["string","null"]},"environments":{"type":"array","items":{"$ref":"#/components/schemas/FlagEnvironmentResponse"},"description":"Per-environment overrides. Empty means the flag inherits its default\neverywhere."},"id":{"type":"integer","format":"int32"},"key":{"type":"string"},"last_evaluated_at":{"type":["string","null"],"description":"When an app last actually evaluated this flag. `None` means never seen,\nwhich is a real answer rather than missing data."},"updated_at":{"type":"string"},"value_type":{"type":"string"}}},"FlagSnapshot":{"type":"object","description":"A single flag, already resolved down to one environment. This is what the\nevaluator sees and what the SDK caches in memory.","required":["key","value_type","default_value","enabled"],"properties":{"default_value":{"description":"Served whenever evaluation cannot do better. Genuinely polymorphic by\ndesign — the surrounding struct carries the type."},"enabled":{"type":"boolean","description":"False means the kill switch is engaged for this environment."},"environment_value":{"description":"`None` means \"inherit `default_value`\"."},"key":{"type":"string"},"value_type":{"$ref":"#/components/schemas/FlagValueType"}}},"FlagSnapshotResponse":{"type":"object","required":["environment_id","flags"],"properties":{"environment_id":{"type":"integer","format":"int32"},"flags":{"type":"array","items":{"$ref":"#/components/schemas/FlagSnapshot"},"description":"Flags collapsed to what the evaluator needs, sorted by key so the\nserialized form — and therefore the ETag — is stable."}}},"FlagValueType":{"type":"string","description":"The declared type of a flag's value. Fixed at create time.","enum":["bool","string","number","json"]},"ForecastAlgorithm":{"type":"string","description":"Forecast model family.","enum":["linear","seasonal"]},"ForecastParams":{"type":"object","description":"Forecast detector parameters (stub — not yet evaluated).","required":["forecast_horizon_secs","comparator","threshold"],"properties":{"algorithm":{"$ref":"#/components/schemas/ForecastAlgorithm"},"comparator":{"$ref":"#/components/schemas/Comparator","description":"Comparator + threshold the *forecast* is checked against."},"deviations":{"type":"number","format":"double"},"forecast_horizon_secs":{"type":"integer","format":"int32","description":"How far ahead to project before checking the breach condition."},"threshold":{"type":"number","format":"double"}}},"FullError":{"type":"object","required":["id","ts","error_group_id","fingerprint","error_class"],"properties":{"data":{"description":"Full JSONB blob from `error_events.data` — stack trace, breadcrumbs,\nrequest context, everything. Schema is documented per source SDK."},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"error_class":{"type":"string"},"error_group_id":{"type":"integer","format":"int32"},"fingerprint":{"type":"string"},"id":{"type":"integer","format":"int64"},"message":{"type":["string","null"]},"trace_id":{"type":["string","null"]},"ts":{"type":"string","format":"date-time"}}},"FullEvent":{"oneOf":[{"allOf":[{"$ref":"#/components/schemas/FullRequest"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["request"]}}}]},{"allOf":[{"$ref":"#/components/schemas/FullError"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["error"]}}}]},{"allOf":[{"$ref":"#/components/schemas/RevenueRow"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["revenue"]}}}]},{"allOf":[{"$ref":"#/components/schemas/SpanRow","description":"`SpanRow.attributes` is the truncated form; re-fetching returns\nthe same shape so the panel has a stable contract."},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["span"]}}}],"description":"`SpanRow.attributes` is the truncated form; re-fetching returns\nthe same shape so the panel has a stable contract."}],"description":"One un-truncated row, returned by the `/full/{type}/{id}` endpoint when\nthe user clicks \"Show full\". Same shape as the list rows, but with the\nraw heavy fields restored (no truncation flags) so the side panel can\nrender the long form."},"FullRequest":{"type":"object","required":["id","ts","method","host","path","status"],"properties":{"client_ip":{"type":["string","null"]},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"error_group_id":{"type":["integer","null"],"format":"int32"},"host":{"type":"string"},"id":{"type":"string","description":"The request's unique `request_id` — same identity the list rows carry\n(backend-agnostic; ClickHouse rows have no serial PK)."},"latency_ms":{"type":["integer","null"],"format":"int32"},"method":{"type":"string"},"path":{"type":"string"},"referrer":{"type":["string","null"]},"request_headers":{},"response_headers":{},"status":{"type":"integer","format":"int32"},"trace_id":{"type":["string","null"]},"ts":{"type":"string","format":"date-time"},"user_agent":{"type":["string","null"]}}},"FunnelMetricsResponse":{"type":"object","required":["funnel_id","funnel_name","total_entries","step_conversions","overall_conversion_rate","average_completion_time_seconds"],"properties":{"average_completion_time_seconds":{"type":"number","format":"double"},"funnel_id":{"type":"integer","format":"int32"},"funnel_name":{"type":"string"},"overall_conversion_rate":{"type":"number","format":"double"},"step_conversions":{"type":"array","items":{"$ref":"#/components/schemas/StepConversionResponse"}},"total_entries":{"type":"integer","format":"int64","minimum":0}}},"FunnelResponse":{"type":"object","required":["id","name","is_active","created_at","updated_at"],"properties":{"created_at":{"type":"string"},"description":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"name":{"type":"string"},"updated_at":{"type":"string"}}},"GatewayStatus":{"type":"object","description":"Detailed gateway container status surfaced to the settings UI.","required":["present","running","health","container_name","expected_image","drift","auto_upgrade"],"properties":{"auto_upgrade":{"type":"boolean","description":"True if `auto_upgrade` is enabled in settings."},"container_name":{"type":"string","description":"Container name."},"drift":{"type":"boolean","description":"True when `image != expected_image` and the container is present."},"expected_image":{"type":"string","description":"The image the supervisor *expects* (from settings/constant). If this\ndiffers from `image`, the UI shows a \"drift\" badge."},"health":{"type":"string","description":"Higher-level health label: \"running\" | \"restarting\" | \"crash_looping\"\n| \"stopped\" | \"missing\". UI should prefer this over `running`."},"host_port":{"type":["integer","null"],"format":"int32","description":"Host port that the container's :8080 is published on.","minimum":0},"image":{"type":["string","null"],"description":"Image reference the container was created with (e.g.\n`ghcr.io/gotempsh/temps-preview-gateway:latest`)."},"image_digest":{"type":["string","null"],"description":"Image digest if available (e.g. `sha256:…`)."},"last_error":{"type":["string","null"],"description":"Error string Docker recorded for the container (e.g. startup failure)."},"last_exit_code":{"type":["integer","null"],"format":"int64","description":"Exit code of the last run, if the container is not currently running."},"network":{"type":["string","null"],"description":"Network the container is attached to (should be `temps-sandbox-net`)."},"present":{"type":"boolean","description":"Whether the container exists at all."},"restart_count":{"type":["integer","null"],"format":"int64","description":"Number of times Docker has restarted the container."},"running":{"type":"boolean","description":"Whether the container is currently running."},"started_at":{"type":["string","null"],"description":"ISO 8601 timestamp the container was started at, if running."}}},"GenAiEvent":{"type":"object","description":"A GenAI-related event extracted from span events.\n\nCovers `gen_ai.client.inference.operation.details` and `gen_ai.evaluation.result`\nevents per the OTel GenAI semantic conventions.","required":["span_id","trace_id","event_name","timestamp","attributes"],"properties":{"attributes":{"type":"object","description":"All event attributes.","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"event_name":{"type":"string"},"span_id":{"type":"string"},"timestamp":{"type":"string","format":"date-time"},"trace_id":{"type":"string"}}},"GenAiSpanDetail":{"type":"object","description":"A single GenAI span with extracted semantic convention fields.\n\nFields are aligned with the OpenTelemetry GenAI Semantic Conventions spec:\n","required":["span_id","name","kind","start_time","duration_ms","status_code","attributes"],"properties":{"agent_description":{"type":["string","null"],"description":"Agent description from `gen_ai.agent.description`."},"agent_id":{"type":["string","null"],"description":"Agent identifier from `gen_ai.agent.id`."},"agent_name":{"type":["string","null"],"description":"Agent name from `gen_ai.agent.name`."},"agent_version":{"type":["string","null"],"description":"Agent version from `gen_ai.agent.version`."},"attributes":{"type":"object","description":"All span attributes for extensibility.","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"aws_bedrock_guardrail_id":{"type":["string","null"],"description":"AWS Bedrock guardrail ID from `aws.bedrock.guardrail.id`."},"aws_bedrock_knowledge_base_id":{"type":["string","null"],"description":"AWS Bedrock knowledge base ID from `aws.bedrock.knowledge_base.id`."},"azure_resource_provider_namespace":{"type":["string","null"],"description":"Azure resource provider namespace from `azure.resource_provider.namespace`."},"cache_creation_input_tokens":{"type":["integer","null"],"format":"int64","description":"Tokens written to provider cache from `gen_ai.usage.cache_creation.input_tokens`."},"cache_read_input_tokens":{"type":["integer","null"],"format":"int64","description":"Tokens served from provider cache from `gen_ai.usage.cache_read.input_tokens`."},"conversation_id":{"type":["string","null"],"description":"Unique conversation/session/thread ID from `gen_ai.conversation.id`."},"data_source_id":{"type":["string","null"],"description":"Data source identifier from `gen_ai.data_source.id`."},"duration_ms":{"type":"number","format":"double"},"embeddings_dimension_count":{"type":["integer","null"],"format":"int64","description":"Output embedding dimensions from `gen_ai.embeddings.dimension.count`."},"error_type":{"type":["string","null"],"description":"Error type from `error.type` when the span status is ERROR."},"gen_ai_model":{"type":["string","null"],"description":"The requested model from `gen_ai.request.model`."},"gen_ai_operation":{"type":["string","null"],"description":"The operation type from `gen_ai.operation.name` (e.g. \"chat\", \"embeddings\", \"execute_tool\")."},"gen_ai_response_model":{"type":["string","null"],"description":"The model that actually generated the response from `gen_ai.response.model`."},"gen_ai_system":{"type":["string","null"],"description":"The GenAI provider from `gen_ai.provider.name` (falls back to deprecated `gen_ai.system`)."},"input_messages":{"type":["string","null"],"description":"Chat history input from `gen_ai.input.messages` (opt-in, JSON string)."},"input_tokens":{"type":["integer","null"],"format":"int64"},"kind":{"$ref":"#/components/schemas/SpanKind"},"name":{"type":"string"},"openai_api_type":{"type":["string","null"],"description":"OpenAI API type from `openai.api.type` (chat_completions, responses)."},"openai_request_service_tier":{"type":["string","null"],"description":"Requested service tier from `openai.request.service_tier`."},"openai_response_service_tier":{"type":["string","null"],"description":"Actual service tier from `openai.response.service_tier`."},"openai_system_fingerprint":{"type":["string","null"],"description":"System fingerprint from `openai.response.system_fingerprint`."},"output_messages":{"type":["string","null"],"description":"Model output from `gen_ai.output.messages` (opt-in, JSON string)."},"output_tokens":{"type":["integer","null"],"format":"int64"},"output_type":{"type":["string","null"],"description":"Output content type from `gen_ai.output.type` (text, json, image, speech)."},"parent_span_id":{"type":["string","null"]},"request_choice_count":{"type":["integer","null"],"format":"int64","description":"Number of choices requested from `gen_ai.request.choice.count`."},"request_encoding_formats":{"type":["array","null"],"items":{"type":"string"},"description":"Requested encoding formats from `gen_ai.request.encoding_formats`."},"request_frequency_penalty":{"type":["number","null"],"format":"double","description":"Frequency penalty from `gen_ai.request.frequency_penalty`."},"request_max_tokens":{"type":["integer","null"],"format":"int64","description":"Max tokens from `gen_ai.request.max_tokens`."},"request_presence_penalty":{"type":["number","null"],"format":"double","description":"Presence penalty from `gen_ai.request.presence_penalty`."},"request_seed":{"type":["integer","null"],"format":"int64","description":"Seed for reproducibility from `gen_ai.request.seed`."},"request_stop_sequences":{"type":["array","null"],"items":{"type":"string"},"description":"Stop sequences from `gen_ai.request.stop_sequences`."},"request_temperature":{"type":["number","null"],"format":"double","description":"Temperature setting from `gen_ai.request.temperature`."},"request_top_k":{"type":["number","null"],"format":"double","description":"Top-k setting from `gen_ai.request.top_k`."},"request_top_p":{"type":["number","null"],"format":"double","description":"Top-p setting from `gen_ai.request.top_p`."},"response_finish_reasons":{"type":["array","null"],"items":{"type":"string"},"description":"Reasons the model stopped from `gen_ai.response.finish_reasons` (e.g. [\"stop\"])."},"response_id":{"type":["string","null"],"description":"Unique completion ID from `gen_ai.response.id` (e.g. \"chatcmpl-123\")."},"retrieval_documents":{"type":["string","null"],"description":"Retrieved documents from `gen_ai.retrieval.documents` (opt-in, JSON string)."},"retrieval_query_text":{"type":["string","null"],"description":"Retrieval query text from `gen_ai.retrieval.query.text` (opt-in)."},"server_address":{"type":["string","null"],"description":"GenAI server address from `server.address`."},"server_port":{"type":["integer","null"],"format":"int64","description":"GenAI server port from `server.port`."},"span_id":{"type":"string"},"start_time":{"type":"string","format":"date-time"},"status_code":{"$ref":"#/components/schemas/SpanStatusCode"},"system_instructions":{"type":["string","null"],"description":"System instructions from `gen_ai.system_instructions` (opt-in, JSON string)."},"tool_call_arguments":{"type":["string","null"],"description":"Tool call arguments from `gen_ai.tool.call.arguments` (opt-in, JSON string)."},"tool_call_id":{"type":["string","null"],"description":"Tool call ID from `gen_ai.tool.call.id`."},"tool_call_result":{"type":["string","null"],"description":"Tool call result from `gen_ai.tool.call.result` (opt-in, JSON string)."},"tool_definitions":{"type":["string","null"],"description":"Tool definitions from `gen_ai.tool.definitions` (opt-in, JSON string)."},"tool_description":{"type":["string","null"],"description":"Tool description from `gen_ai.tool.description`."},"tool_name":{"type":["string","null"],"description":"Tool name from `gen_ai.tool.name`."},"tool_type":{"type":["string","null"],"description":"Tool type from `gen_ai.tool.type` (function, extension, datastore)."}}},"GenAiTraceDetailResponse":{"type":"object","required":["trace_id","spans","span_count","events","event_count"],"properties":{"event_count":{"type":"integer","minimum":0},"events":{"type":"array","items":{"$ref":"#/components/schemas/GenAiEvent"}},"span_count":{"type":"integer","minimum":0},"spans":{"type":"array","items":{"$ref":"#/components/schemas/GenAiSpanDetail"}},"trace_id":{"type":"string"}}},"GenAiTraceSummariesResponse":{"type":"object","required":["data","total"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/GenAiTraceSummary"}},"total":{"type":"integer","format":"int64","minimum":0}}},"GenAiTraceSummary":{"type":"object","description":"Summary of a GenAI conversation — aggregated from OTel spans with `gen_ai.*` attributes.","required":["trace_id","root_span_name","service_name","start_time","duration_ms","span_count","error_count"],"properties":{"duration_ms":{"type":"number","format":"double"},"error_count":{"type":"integer","format":"int64"},"gen_ai_model":{"type":["string","null"],"description":"The requested model from `gen_ai.request.model`."},"gen_ai_operation":{"type":["string","null"],"description":"The operation type from `gen_ai.operation.name` (e.g. \"chat\", \"embeddings\")."},"gen_ai_system":{"type":["string","null"],"description":"The GenAI provider (e.g. \"openai\", \"anthropic\") from `gen_ai.provider.name`."},"root_span_name":{"type":"string"},"service_name":{"type":"string"},"span_count":{"type":"integer","format":"int64"},"start_time":{"type":"string","format":"date-time"},"total_cache_creation_input_tokens":{"type":["integer","null"],"format":"int64","description":"Total cache-creation input tokens across all spans."},"total_cache_read_input_tokens":{"type":["integer","null"],"format":"int64","description":"Total cache-read input tokens across all spans."},"total_input_tokens":{"type":["integer","null"],"format":"int64","description":"Total input tokens across all spans in this trace."},"total_output_tokens":{"type":["integer","null"],"format":"int64","description":"Total output tokens across all spans in this trace."},"trace_id":{"type":"string"}}},"GeneralStatsQuery":{"type":"object","required":["start_date","end_date"],"properties":{"end_date":{"type":"string","format":"date-time"},"start_date":{"type":"string","format":"date-time"}}},"GeneralStatsResponse":{"type":"object","required":["total_unique_visitors","total_visits","total_page_views","total_events","total_projects","avg_bounce_rate","avg_engagement_rate","project_breakdown"],"properties":{"avg_bounce_rate":{"type":"number","format":"double"},"avg_engagement_rate":{"type":"number","format":"double"},"page_views_trend_percentage":{"type":["number","null"],"format":"double","description":"Percentage change in page views vs previous period"},"previous_page_views":{"type":["integer","null"],"format":"int64","description":"Previous period page views"},"previous_unique_visitors":{"type":["integer","null"],"format":"int64","description":"Previous period unique visitors (same duration, shifted back)"},"project_breakdown":{"type":"array","items":{"$ref":"#/components/schemas/ProjectStatsBreakdown"}},"total_events":{"type":"integer","format":"int64"},"total_page_views":{"type":"integer","format":"int64"},"total_projects":{"type":"integer","format":"int64"},"total_unique_visitors":{"type":"integer","format":"int64"},"total_visits":{"type":"integer","format":"int64"},"visitors_trend_percentage":{"type":["number","null"],"format":"double","description":"Percentage change in unique visitors vs previous period"}}},"GenerateDockerfileRequest":{"type":"object","description":"Request body for generating a Dockerfile from a preset","properties":{"build_command":{"type":["string","null"],"description":"Custom build command (overrides preset default)","example":"npm run build"},"install_command":{"type":["string","null"],"description":"Custom install command (overrides preset default)","example":"npm ci"},"output_dir":{"type":["string","null"],"description":"Output directory for static builds","example":"dist"},"package_manager":{"type":["string","null"],"description":"Package manager used by the project (npm, yarn, pnpm, bun)\nIf not provided, defaults to npm","example":"npm"},"project_name":{"type":["string","null"],"description":"Project name/slug used for container naming","example":"my-app"},"use_buildkit":{"type":"boolean","description":"Whether to use BuildKit cache mounts for faster builds"}}},"GenerateDockerfileResponse":{"type":"object","description":"Response containing a generated Dockerfile and build arguments","required":["dockerfile","build_args","preset"],"properties":{"build_args":{"type":"object","description":"Build arguments to pass to `docker build --build-arg KEY=VALUE`","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"dockerfile":{"type":"string","description":"The generated Dockerfile content"},"preset":{"type":"string","description":"The preset slug used for generation"}}},"GenerateJoinTokenResponse":{"type":"object","description":"Response returned when a join token is generated (plaintext shown once)","required":["token","message"],"properties":{"message":{"type":"string"},"token":{"type":"string","description":"The plaintext join token — shown only once, save it now"}}},"GeoLocationResponse":{"type":"object","description":"Response containing geolocation information for an IP address","required":["ip","is_eu"],"properties":{"city":{"type":["string","null"],"description":"City name","example":"Mountain View"},"country":{"type":["string","null"],"description":"Country name","example":"United States"},"country_code":{"type":["string","null"],"description":"ISO country code (2 letters)","example":"US"},"ip":{"type":"string","description":"IP address that was geolocated","example":"8.8.8.8"},"is_eu":{"type":"boolean","description":"Whether the IP is in the European Union","example":false},"latitude":{"type":["number","null"],"format":"double","description":"Latitude coordinate","example":37.386},"longitude":{"type":["number","null"],"format":"double","description":"Longitude coordinate","example":-122.0838},"region":{"type":["string","null"],"description":"Region/state name","example":"California"},"timezone":{"type":["string","null"],"description":"Timezone identifier","example":"America/Los_Angeles"}}},"GeoRestrictionsConfig":{"type":"object","description":"Geographic restrictions configuration (future feature)","properties":{"allowedCountries":{"type":"array","items":{"type":"string"},"description":"Allow traffic only from specific countries"},"blockedCountries":{"type":"array","items":{"type":"string"},"description":"Block traffic from specific countries (ISO 3166-1 alpha-2 codes)"}}},"GetDeploymentsParams":{"type":"object","properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"page":{"type":["integer","null"],"format":"int64"},"per_page":{"type":["integer","null"],"format":"int64"}}},"GetEnvironmentVariablesQuery":{"type":"object","properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"service_id":{"type":["integer","null"],"format":"int32","description":"Required by integration-value reveals to bind the plaintext response to\nthe exact service displayed by the client."},"var_id":{"type":["integer","null"],"format":"int32","description":"Exact manual env-var row to reveal. Required by the dashboard so\nduplicate keys on disjoint environments cannot cross-reveal."}}},"GetFunnelMetricsQuery":{"type":"object","properties":{"country_code":{"type":["string","null"]},"end_date":{"type":["string","null"],"format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"start_date":{"type":["string","null"],"format":"date-time"}}},"GetOrCreateDSNRequest":{"type":"object","properties":{"base_url":{"type":["string","null"]},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"}}},"GetProjectSecretsQuery":{"type":"object","properties":{"environment_id":{"type":["integer","null"],"format":"int32"}}},"GetProjectSessionReplaysQuery":{"type":"object","required":["project_id"],"properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"page":{"type":["integer","null"],"format":"int64","minimum":0},"per_page":{"type":["integer","null"],"format":"int64","minimum":0},"project_id":{"type":"integer","format":"int32"}}},"GetProjectSessionReplaysResponse":{"type":"object","required":["sessions","page","per_page","total_count"],"properties":{"page":{"type":"integer","format":"int64","minimum":0},"per_page":{"type":"integer","format":"int64","minimum":0},"sessions":{"type":"array","items":{"$ref":"#/components/schemas/SessionReplayWithVisitorDto"}},"total_count":{"type":"integer","format":"int64","minimum":0}}},"GetRequest":{"type":"object","description":"Request to get a value by key","required":["key"],"properties":{"key":{"type":"string","description":"The key to retrieve","example":"user:123"},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1}}},"GetResponse":{"type":"object","description":"Response for get operation","properties":{"value":{"description":"The value, or null if not found"}}},"GetSessionReplayResponse":{"type":"object","required":["session"],"properties":{"session":{"$ref":"#/components/schemas/SessionReplayWithVisitorDto"}}},"GetUniqueEventsQuery":{"type":"object","properties":{"page":{"type":["integer","null"],"format":"int64","minimum":0},"page_size":{"type":["integer","null"],"format":"int64","minimum":0}}},"GetVisitorSessionsQuery":{"type":"object","properties":{"page":{"type":["integer","null"],"format":"int64","minimum":0},"per_page":{"type":["integer","null"],"format":"int64","minimum":0}}},"GetVisitorSessionsResponse":{"type":"object","required":["sessions","page","per_page","total_count"],"properties":{"page":{"type":"integer","format":"int64","minimum":0},"per_page":{"type":"integer","format":"int64","minimum":0},"sessions":{"type":"array","items":{"$ref":"#/components/schemas/SessionReplayWithVisitorDto"}},"total_count":{"type":"integer","minimum":0}}},"GitPushEvent":{"type":"object","description":"Git push event information that triggered the deployment","required":["repo","owner","branch","commit"],"properties":{"branch":{"type":"string","description":"Branch that was pushed"},"commit":{"type":"string","description":"Commit SHA"},"owner":{"type":"string","description":"Repository owner/organization"},"repo":{"type":"string","description":"Repository name"}}},"GitRefResponse":{"type":"object","description":"Git repository reference response","required":["url","ref"],"properties":{"path":{"type":["string","null"],"description":"Path within the repository (for monorepos)"},"ref":{"type":"string","description":"Git reference (branch, tag, or commit)"},"url":{"type":"string","description":"Git repository URL"}}},"GitSourcePlan":{"type":"object","description":"Git repository the source platform deploys from","required":["owner","repo","branch","is_public"],"properties":{"branch":{"type":"string","description":"Branch the source platform deploys"},"clone_url":{"type":["string","null"],"description":"Full clone URL, e.g. `https://github.com/owner/repo.git`"},"is_public":{"type":"boolean","description":"True when the repository is public (no credentials on the source\nplatform) — the project can then build without a git provider\nconnection."},"owner":{"type":"string","description":"Repository owner (organization or user)"},"repo":{"type":"string","description":"Repository name"}}},"GlobalConversationResponse":{"type":"object","description":"A conversation in the unified cross-project switcher: carries the project it\nbelongs to (name/slug) so the UI can show where the chat was started and\nlink back to the source.","required":["public_id","project_id","context_type","context_id","status","created_at","last_activity_at"],"properties":{"context_id":{"type":"string"},"context_type":{"type":"string"},"created_at":{"type":"string"},"last_activity_at":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"project_name":{"type":["string","null"]},"project_slug":{"type":["string","null"]},"public_id":{"type":"string"},"status":{"type":"string"},"title":{"type":["string","null"]}}},"GlobalEventStatsResponse":{"type":"object","required":["delivered","opened","clicked","bounced","complained"],"properties":{"bounce_rate":{"type":["number","null"],"format":"double"},"bounced":{"type":"integer","format":"int64","minimum":0},"click_rate":{"type":["number","null"],"format":"double"},"clicked":{"type":"integer","format":"int64","minimum":0},"complained":{"type":"integer","format":"int64","minimum":0},"delivered":{"type":"integer","format":"int64","minimum":0},"open_rate":{"type":["number","null"],"format":"double"},"opened":{"type":"integer","format":"int64","minimum":0}}},"GlobalMrrResponse":{"type":"object","required":["currency","current_mrr_minor","previous_mrr_minor"],"properties":{"change_percentage":{"type":["number","null"],"format":"double","description":"Percentage change vs 24h ago. Null when previous MRR is zero\n(no baseline to compare against)."},"currency":{"type":"string"},"current_mrr_minor":{"type":"integer","format":"int64"},"previous_mrr_minor":{"type":"integer","format":"int64","description":"MRR 24h before now, reconstructed from the event log."}}},"GlobalRecentEventResponse":{"type":"object","required":["id","project_id","project_name","occurred_at","event_type"],"properties":{"amount_minor":{"type":["integer","null"],"format":"int64"},"currency":{"type":["string","null"]},"customer_ref":{"type":["string","null"]},"event_type":{"type":"string"},"id":{"type":"integer","format":"int64"},"mrr_minor":{"type":["integer","null"],"format":"int64"},"occurred_at":{"type":"string","format":"date-time"},"project_id":{"type":"integer","format":"int32"},"project_name":{"type":"string"}}},"GlobalRevenueSummaryResponse":{"type":"object","required":["currency","current_mrr_minor","paid_last_30d_minor","refunded_last_30d_minor","paid_all_time_minor","refunded_all_time_minor","active_subscriptions","active_customers","transactions_last_30d"],"properties":{"active_customers":{"type":"integer","format":"int64"},"active_subscriptions":{"type":"integer","format":"int64"},"currency":{"type":"string"},"current_mrr_minor":{"type":"integer","format":"int64"},"paid_all_time_minor":{"type":"integer","format":"int64"},"paid_last_30d_minor":{"type":"integer","format":"int64"},"refunded_all_time_minor":{"type":"integer","format":"int64"},"refunded_last_30d_minor":{"type":"integer","format":"int64"},"transactions_last_30d":{"type":"integer","format":"int64"}}},"GroupedPageMetric":{"type":"object","required":["group_key","events"],"properties":{"cls":{"type":["number","null"],"format":"float"},"country_code":{"type":["string","null"],"description":"ISO 3166-1 alpha-2 code of the group's country. Populated for the\ngeographic dimensions (country/region/city) so clients can match map\ngeometries without name-based lookups; null otherwise."},"events":{"type":"integer","format":"int64"},"fcp":{"type":["number","null"],"format":"float"},"group_key":{"type":"string"},"inp":{"type":["number","null"],"format":"float"},"lcp":{"type":["number","null"],"format":"float"},"ttfb":{"type":["number","null"],"format":"float"}}},"GroupedPageMetricsQuery":{"allOf":[{"$ref":"#/components/schemas/SpeedSegmentFilters","description":"Segment filters — same shape as `PerformanceMetricsQuery`."},{"type":"object","required":["start_date","end_date","project_id","group_by"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"device_type":{"type":["string","null"],"description":"Device type filter: \"desktop\" or \"mobile\""},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"group_by":{"type":"string"},"include_bots":{"type":["boolean","null"],"description":"Include crawler/datacenter (bot) samples. Defaults to false."},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}}]},"GroupedPageMetricsResponse":{"type":"object","required":["groups","total_events","grouped_by"],"properties":{"grouped_by":{"type":"string"},"groups":{"type":"array","items":{"$ref":"#/components/schemas/GroupedPageMetric"}},"total_events":{"type":"integer","format":"int64"}}},"HasAnalyticsEventsResponse":{"type":"object","required":["has_events"],"properties":{"has_events":{"type":"boolean"}}},"HasErrorGroupsResponse":{"type":"object","required":["has_error_groups"],"properties":{"has_error_groups":{"type":"boolean"}}},"HasEventsQuery":{"type":"object","required":["project_id"],"properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"}}},"HasEventsResponse":{"type":"object","required":["has_events"],"properties":{"has_events":{"type":"boolean"}}},"HasMetricsQuery":{"type":"object","required":["project_id"],"properties":{"project_id":{"type":"integer","format":"int32"}}},"HasMetricsResponse":{"type":"object","required":["has_metrics"],"properties":{"has_metrics":{"type":"boolean"}}},"HealthCheckConfiguration":{"type":"object","description":"Health check configuration","required":["port","interval","timeout","retries"],"properties":{"http_path":{"type":["string","null"],"description":"HTTP path to check (if applicable)"},"interval":{"type":"integer","format":"int32","description":"Interval between checks (seconds)","minimum":0},"port":{"type":"integer","format":"int32","description":"Port to check","minimum":0},"retries":{"type":"integer","format":"int32","description":"Number of retries before marking unhealthy","minimum":0},"timeout":{"type":"integer","format":"int32","description":"Timeout for each check (seconds)","minimum":0}}},"HealthCheckEntryResponse":{"type":"object","required":["checked_at","status"],"properties":{"checked_at":{"type":"string","description":"ISO 8601 timestamp of when the probe ran.","example":"2026-04-22T11:30:00Z"},"error_message":{"type":["string","null"],"description":"Present only when the probe failed or was degraded."},"response_time_ms":{"type":["integer","null"],"format":"int32","description":"TCP connect latency in milliseconds."},"status":{"type":"string","description":"\"operational\" | \"degraded\" | \"down\"","example":"operational"}}},"HealthResponse":{"type":"object","required":["summaries"],"properties":{"summaries":{"type":"array","items":{"$ref":"#/components/schemas/HealthSummary"}}}},"HealthStatus":{"type":"string","description":"Overall health status.","enum":["healthy","degraded","down","unknown"]},"HealthSummary":{"type":"object","description":"Pre-computed health summary for a project environment.","required":["project_id","service_name","status","uptime_pct","error_rate","p95_latency_ms","cpu_usage_pct","memory_usage_pct","computed_at"],"properties":{"computed_at":{"type":"string","format":"date-time"},"cpu_usage_pct":{"type":"number","format":"double"},"environment_id":{"type":["integer","null"],"format":"int32"},"error_rate":{"type":"number","format":"double"},"last_deploy_at":{"type":["string","null"],"format":"date-time"},"last_deploy_id":{"type":["integer","null"],"format":"int32"},"memory_usage_pct":{"type":"number","format":"double"},"p95_latency_ms":{"type":"number","format":"double"},"project_id":{"type":"integer","format":"int32"},"service_name":{"type":"string"},"status":{"$ref":"#/components/schemas/HealthStatus"},"uptime_pct":{"type":"number","format":"double"}}},"HeartbeatApiRequest":{"type":"object","properties":{"architecture":{"type":["string","null"],"description":"Container platform of this node's Docker daemon (`linux/amd64`,\n`linux/arm64`), read from `docker info` by the agent. Absent from\npre-multi-arch agents; the stored value is then left untouched."},"capacity":{"description":"Resource capacity/usage info as JSON (cpu_usage, memory_usage, etc.)"},"containers":{"type":["array","null"],"items":{"$ref":"#/components/schemas/ContainerInventoryItem"},"description":"Container inventory for reconciliation (sent on first heartbeat after agent startup).\nEach entry has `container_id` and `container_name` of temps-managed containers."},"labels":{"description":"Updated node labels for scheduling (allows runtime label changes)."}}},"HeartbeatResponse":{"type":"object","required":["status","message"],"properties":{"message":{"type":"string"},"status":{"type":"string"}}},"HierarchyLevel":{"type":"object","description":"Describes a level in the data source hierarchy","required":["level","name","container_type","can_list_containers","can_list_entities"],"properties":{"can_list_containers":{"type":"boolean","description":"Can list containers at this level?","example":true},"can_list_entities":{"type":"boolean","description":"Can list entities at this level?","example":false},"container_type":{"type":"string","description":"Type of container at this level","example":"database"},"level":{"type":"integer","format":"int32","description":"Level number (0 = root)","example":0,"minimum":0},"name":{"type":"string","description":"Human-readable name for this level","example":"root"}}},"HistogramSummary":{"type":"object","description":"An explicit-bucket histogram aggregated over a time bucket.\n\nCarries the reduced scalars (count/sum/min/max) plus the explicit bucket\nlayout — `bounds` (the upper bounds) and `bucket_counts` (observation counts,\nsummed element-wise across the window; length is `bounds.len() + 1`, the last\nentry being the +Inf overflow bucket). With these, a caller can reconstruct\nany quantile (e.g. p95) via cumulative-count interpolation.","required":["count","sum","bounds","bucket_counts"],"properties":{"bounds":{"type":"array","items":{"type":"number","format":"double"},"description":"Explicit bucket upper bounds (OTLP `explicit_bounds`), ascending."},"bucket_counts":{"type":"array","items":{"type":"integer","format":"int64","minimum":0},"description":"Per-bucket observation counts summed element-wise across the window.\nLength is `bounds.len() + 1` (the trailing element is the +Inf bucket)."},"count":{"type":"integer","format":"int64","description":"Total observation count summed across the bucket window.","minimum":0},"max":{"type":["number","null"],"format":"double","description":"Maximum observed value, when reported by the producer."},"min":{"type":["number","null"],"format":"double","description":"Minimum observed value, when reported by the producer."},"sum":{"type":"number","format":"double","description":"Sum of observed values across the bucket window."}}},"HostnameChange":{"type":"object","description":"A single generated-hostname change in a flatten preview/apply.","required":["kind","id","old","new"],"properties":{"id":{"type":"integer","format":"int32","description":"Row id of the affected record."},"kind":{"type":"string","description":"`\"deployment\"` or `\"environment\"`."},"new":{"type":"string"},"old":{"type":"string"}}},"HostnamePreviewResponse":{"type":"object","description":"Combined preview of a hostname-mode change.","required":["hostname_changes","dns_changes","total"],"properties":{"dns_changes":{"type":"array","items":{"$ref":"#/components/schemas/DnsRecordChange"}},"hostname_changes":{"type":"array","items":{"$ref":"#/components/schemas/HostnameChange"}},"total":{"type":"integer","minimum":0},"zone_access_ok":{"type":["boolean","null"],"description":"Whether the provider token can manage this zone (None if not checked)."}}},"HourlyPageSessions":{"type":"object","required":["timestamp","session_count","event_count","avg_duration_seconds"],"properties":{"avg_duration_seconds":{"type":"number","format":"double"},"event_count":{"type":"integer","format":"int64"},"session_count":{"type":"integer","format":"int64"},"timestamp":{"type":"string"}}},"HourlyVisitsQuery":{"type":"object","required":["start_date","end_date"],"properties":{"aggregation_level":{"$ref":"#/components/schemas/AggregationLevel","description":"Aggregation level: events (page views), sessions (unique sessions), or visitors (unique visitors)"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"HttpChallengeDebugResponse":{"type":"object","required":["domain","challenge_exists","dns_a_records","dns_aaaa_records"],"properties":{"challenge_exists":{"type":"boolean"},"challenge_token":{"type":["string","null"]},"challenge_url":{"type":["string","null"],"description":"The full URL that Let's Encrypt will try to access to validate the challenge"},"dns_a_records":{"type":"array","items":{"type":"string"},"description":"IPv4 addresses the domain points to"},"dns_aaaa_records":{"type":"array","items":{"type":"string"},"description":"IPv6 addresses the domain points to"},"dns_error":{"type":["string","null"],"description":"Any DNS resolution errors"},"domain":{"type":"string"},"validation_url":{"type":["string","null"],"description":"The ACME validation URL (internal to ACME protocol)"}}},"ImportCredentials":{"type":"object","description":"Platform-specific credentials for accessing the source system.\n\nFor platforms like Vercel and Railway, this contains the API token.\nFor self-hosted platforms like Coolify and Dokploy, this also contains\nthe `base_url` of the instance.\n\nLocal importers (Docker) can use `ImportCredentials::none()`.","properties":{"base_url":{"type":["string","null"],"description":"Base URL override (for self-hosted platforms like Coolify, Dokploy)\n\nExample: `https://coolify.example.com`"},"extra":{"type":"object","description":"Additional platform-specific parameters","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"team_id":{"type":["string","null"],"description":"Team or organization ID (for platforms with team scoping like Vercel)"},"token":{"type":["string","null"],"description":"API token / bearer token for the source platform"}}},"ImportExecutionStatus":{"type":"string","description":"Import execution status","enum":["pending","inprogress","completed","failed"]},"ImportExternalServiceRequest":{"type":"object","description":"Request to import a Docker container as a managed service","required":["name","service_type","parameters","container_id"],"properties":{"container_id":{"type":"string","description":"Container ID or name to import","example":"abc123def456"},"name":{"type":"string","description":"Name to register the service as in Temps","example":"production-database"},"parameters":{"type":"object","description":"Service configuration parameters","additionalProperties":{},"propertyNames":{"type":"string"}},"service_type":{"$ref":"#/components/schemas/ServiceTypeRoute","description":"Service type"},"version":{"type":["string","null"],"description":"Optional version override"}}},"ImportOutcomeResponse":{"type":"object","required":["rows_read","inserted","updated","skipped_stale","skipped_invalid","errors"],"properties":{"errors":{"type":"array","items":{"$ref":"#/components/schemas/ImportRowErrorResponse"}},"inserted":{"type":"integer","minimum":0},"rows_read":{"type":"integer","minimum":0},"skipped_invalid":{"type":"integer","minimum":0},"skipped_stale":{"type":"integer","minimum":0},"updated":{"type":"integer","minimum":0}}},"ImportPlan":{"type":"object","description":"Complete import plan describing all operations to onboard a workload.\n\nThe plan is generated from a snapshot and presented to the user for review\nbefore any resources are created. Users can modify individual items\n(skip services, change actions) before approving execution.","required":["version","source","source_id","project","environment","deployment","summary","metadata"],"properties":{"additional_deployments":{"type":"array","items":{"$ref":"#/components/schemas/DeploymentConfiguration"},"description":"Additional deployments (workers, cron jobs, etc.)"},"cost_analysis":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/CostAnalysis","description":"Cost, overprovisioning, and savings analysis. Populated by importers\nthat can observe the whole source cluster (currently Kubernetes);\n`None` for container/platform imports."}]},"deployment":{"$ref":"#/components/schemas/DeploymentConfiguration","description":"Primary deployment configuration"},"domains":{"type":"array","items":{"$ref":"#/components/schemas/DomainPlan"},"description":"Custom domains to migrate"},"environment":{"$ref":"#/components/schemas/EnvironmentConfiguration","description":"Environment configuration"},"metadata":{"$ref":"#/components/schemas/PlanMetadata","description":"Plan metadata"},"project":{"$ref":"#/components/schemas/ProjectConfiguration","description":"Project configuration"},"services":{"type":"array","items":{"$ref":"#/components/schemas/ServicePlan"},"description":"Services to migrate (databases, caches, blob stores)\n\nEach service has an `action` field the user can change before execution."},"source":{"type":"string","description":"Source system this plan was generated from"},"source_id":{"type":"string","description":"Source workload / project ID in the source system"},"steps":{"type":"array","items":{"$ref":"#/components/schemas/MigrationStep"},"description":"Ordered list of migration steps that will be executed.\n\nThis is the human-readable execution plan. Each step describes what\nwill happen, what risks are involved, and what the user should verify.\nSteps are executed in order. If a step fails, execution stops and\nalready-created resources are reported for manual cleanup."},"summary":{"$ref":"#/components/schemas/MigrationSummary","description":"Human-readable summary of the entire migration"},"version":{"type":"string","description":"Plan version for compatibility tracking"}}},"ImportRowErrorResponse":{"type":"object","required":["row","reason"],"properties":{"reason":{"type":"string"},"row":{"type":"integer","minimum":0}}},"ImportSelector":{"type":"object","description":"Selector for discovering workloads","properties":{"label_filter":{"type":["object","null"],"description":"Filter by labels/tags","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"limit":{"type":["integer","null"],"description":"Limit number of results","minimum":0},"name_pattern":{"type":["string","null"],"description":"Filter by name pattern (glob/regex)"},"status_filter":{"type":["array","null"],"items":{"type":"string"},"description":"Filter by status (running, stopped, deployed, etc.)"},"workload_type_filter":{"type":["array","null"],"items":{"type":"string"},"description":"Filter by workload type (container, function, static-site, etc.)"}}},"ImportSource":{"type":"string","description":"Import source identifier","enum":["docker","coolify","dokploy","vercel","netlify","railway","render","fly","kubernetes","caprover","portainer","kamal","custom"]},"ImportSourceCapabilities":{"type":"object","description":"Source capabilities","required":["supports_volumes","supports_networks","supports_health_checks","supports_resource_limits","supports_build","supports_services","supports_domains","supports_project_snapshot","supports_cost_analysis","requires_credentials"],"properties":{"requires_credentials":{"type":"boolean","description":"Whether this source requires API credentials (token, base URL)"},"supports_build":{"type":"boolean"},"supports_cost_analysis":{"type":"boolean","description":"Supports cluster cost + overprovisioning analysis in the plan"},"supports_domains":{"type":"boolean","description":"Supports custom domain migration"},"supports_health_checks":{"type":"boolean"},"supports_networks":{"type":"boolean"},"supports_project_snapshot":{"type":"boolean","description":"Supports full project-level snapshots"},"supports_resource_limits":{"type":"boolean"},"supports_services":{"type":"boolean","description":"Supports service migration (databases, caches, etc.)"},"supports_volumes":{"type":"boolean"}}},"ImportSourceInfo":{"type":"object","description":"Information about an import source","required":["source","name","version","available","capabilities"],"properties":{"available":{"type":"boolean","description":"Whether the source is currently available"},"capabilities":{"$ref":"#/components/schemas/ImportSourceCapabilities","description":"Capabilities"},"name":{"type":"string","description":"Human-readable name"},"source":{"$ref":"#/components/schemas/ImportSource","description":"Source identifier"},"version":{"type":"string","description":"Source version"}}},"ImportStatusResponse":{"type":"object","description":"Response with import status","required":["session_id","status","errors","warnings","created_at","updated_at"],"properties":{"created_at":{"type":"string","format":"date-time","description":"Created at timestamp"},"deployment_id":{"type":["integer","null"],"format":"int32","description":"Created deployment ID"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Created environment ID"},"errors":{"type":"array","items":{"type":"string"},"description":"Errors (if any)"},"plan":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ImportPlan","description":"Import plan"}]},"project_id":{"type":["integer","null"],"format":"int32","description":"Created project ID"},"session_id":{"type":"string","description":"Session ID"},"status":{"$ref":"#/components/schemas/ImportExecutionStatus","description":"Current status"},"updated_at":{"type":"string","format":"date-time","description":"Updated at timestamp"},"validation":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ValidationReport","description":"Validation report"}]},"warnings":{"type":"array","items":{"type":"string"},"description":"Warnings (if any)"}}},"IncidentBucket":{"type":"object","required":["bucket_start","total_incidents","minor_incidents","major_incidents","critical_incidents","resolved_incidents","active_incidents"],"properties":{"active_incidents":{"type":"integer","format":"int64"},"avg_resolution_time_minutes":{"type":["number","null"],"format":"double"},"bucket_start":{"type":"string","format":"date-time"},"critical_incidents":{"type":"integer","format":"int64"},"major_incidents":{"type":"integer","format":"int64"},"minor_incidents":{"type":"integer","format":"int64"},"resolved_incidents":{"type":"integer","format":"int64"},"total_incidents":{"type":"integer","format":"int64"}}},"IncidentBucketedResponse":{"type":"object","required":["project_id","interval","buckets"],"properties":{"buckets":{"type":"array","items":{"$ref":"#/components/schemas/IncidentBucket"}},"environment_id":{"type":["integer","null"],"format":"int32"},"interval":{"type":"string"},"project_id":{"type":"integer","format":"int32"}}},"IncidentResponse":{"type":"object","required":["id","project_id","title","severity","status","started_at","created_at","updated_at"],"properties":{"created_at":{"type":"string","format":"date-time"},"description":{"type":["string","null"]},"environment_id":{"type":["integer","null"],"format":"int32"},"id":{"type":"integer","format":"int32"},"monitor_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"resolved_at":{"type":["string","null"],"format":"date-time"},"severity":{"type":"string"},"started_at":{"type":"string","format":"date-time"},"status":{"type":"string"},"title":{"type":"string"},"updated_at":{"type":"string","format":"date-time"}}},"IncidentUpdateResponse":{"type":"object","required":["id","incident_id","status","message","created_at"],"properties":{"created_at":{"type":"string","format":"date-time"},"id":{"type":"integer","format":"int32"},"incident_id":{"type":"integer","format":"int32"},"message":{"type":"string"},"status":{"type":"string"}}},"IncrRequest":{"type":"object","description":"Request to increment a value","required":["key"],"properties":{"amount":{"type":["integer","null"],"format":"int64","description":"Amount to increment by (default: 1)"},"key":{"type":"string","description":"The key to increment","example":"counter"},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1}}},"IncrResponse":{"type":"object","description":"Response for increment operation","required":["value"],"properties":{"value":{"type":"integer","format":"int64","description":"New value after increment","example":42}}},"InitAuthResponse":{"type":"object","required":["auth_url","session_token"],"properties":{"auth_url":{"type":"string"},"session_token":{"type":"string"}}},"Insight":{"type":"object","description":"An anomaly insight.","required":["id","project_id","service_name","severity","status","title","description","anomaly_ids","started_at","created_at","updated_at"],"properties":{"anomaly_ids":{"type":"array","items":{"type":"integer","format":"int64"}},"correlated_deploy_id":{"type":["integer","null"],"format":"int32"},"created_at":{"type":"string","format":"date-time"},"description":{"type":"string"},"environment":{"type":["string","null"]},"id":{"type":"integer","format":"int64"},"metric_name":{"type":["string","null"]},"project_id":{"type":"integer","format":"int32"},"resolved_at":{"type":["string","null"],"format":"date-time"},"service_name":{"type":"string"},"severity":{"$ref":"#/components/schemas/InsightSeverity"},"started_at":{"type":"string","format":"date-time"},"status":{"$ref":"#/components/schemas/InsightStatus"},"title":{"type":"string"},"updated_at":{"type":"string","format":"date-time"}}},"InsightSeverity":{"type":"string","description":"Severity of an anomaly insight.","enum":["low","medium","high","critical"]},"InsightStatus":{"type":"string","description":"Status of an insight.","enum":["active","resolved"]},"InsightsResponse":{"type":"object","required":["data","count"],"properties":{"count":{"type":"integer","minimum":0},"data":{"type":"array","items":{"$ref":"#/components/schemas/Insight"}}}},"IntegrationResponse":{"type":"object","required":["id","project_id","provider","webhook_path_token","webhook_path","status","has_secret","created_at"],"properties":{"config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ProviderConfig","description":"Typed provider config — allowlist and metered-billing mode. Null\nwhen the operator hasn't configured one yet (accept everything)."}]},"created_at":{"type":"string","format":"date-time"},"has_secret":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"last_event_at":{"type":["string","null"],"format":"date-time"},"project_id":{"type":"integer","format":"int32"},"provider":{"type":"string"},"status":{"type":"string"},"webhook_path":{"type":"string","description":"Relative path the UI can display and copy. The frontend builds\nthe full URL by prefixing its own origin."},"webhook_path_token":{"type":"string","description":"Unguessable token embedded in the public webhook URL. The full\nURL is `{api_origin}/webhooks/revenue/{provider}/{webhook_path_token}`."}}},"IpAccessControlQuery":{"type":"object","description":"Query parameters for listing IP access control rules","properties":{"action":{"type":["string","null"],"description":"Filter by action (\"block\" or \"allow\")"}}},"IpAccessControlResponse":{"type":"object","description":"Response model for IP access control rules","required":["id","ip_address","action","created_at","updated_at"],"properties":{"action":{"type":"string"},"created_at":{"type":"string","example":"2025-10-12T12:15:47.609Z"},"created_by":{"type":["integer","null"],"format":"int32"},"id":{"type":"integer","format":"int32"},"ip_address":{"type":"string"},"reason":{"type":["string","null"]},"updated_at":{"type":"string","example":"2025-10-12T12:15:47.609Z"}}},"JobStatusResponse":{"type":"object","description":"Snapshot of a background job. `status` is one of \"running\" | \"exited\"\n| \"failed\"; `exit_code` is populated only when `status == \"exited\"`.","required":["status","stdout","stderr"],"properties":{"exit_code":{"type":["integer","null"],"format":"int32"},"reason":{"type":["string","null"]},"status":{"type":"string"},"stderr":{"type":"string"},"stdout":{"type":"string"}}},"JobSummaryResponse":{"type":"object","description":"Row in the jobs list. Omits stdout/stderr so a noisy dev server doesn't\nbloat the list payload — callers drill into `GET /jobs/{id}` for the\nfull buffer.","required":["id","status","cmd","started_at"],"properties":{"cmd":{"type":"string"},"exit_code":{"type":["integer","null"],"format":"int32"},"id":{"type":"string"},"reason":{"type":["string","null"]},"started_at":{"type":"string"},"status":{"type":"string"}}},"JoinTokenStatusResponse":{"type":"object","description":"Response for join token status check","required":["has_token"],"properties":{"has_token":{"type":"boolean","description":"Whether a join token has been configured"}}},"JourneyEvent":{"type":"object","description":"A single event in the visitor journey timeline","required":["id","event_type","event_name","occurred_at","is_entry","is_exit","is_bounce"],"properties":{"event_data":{"description":"Custom event properties (for custom events)"},"event_name":{"type":"string","description":"Resolved event name (event_name for custom events, event_type for system events)"},"event_type":{"type":"string","description":"Event type: \"page_view\", \"page_leave\", \"custom\", \"web_vitals\""},"id":{"type":"integer","format":"int64","description":"Event ID"},"is_bounce":{"type":"boolean","description":"Whether this was a bounce"},"is_entry":{"type":"boolean","description":"Whether this is the entry page of the session"},"is_exit":{"type":"boolean","description":"Whether this is the exit page of the session"},"occurred_at":{"type":"string","format":"date-time","description":"When the event occurred"},"page_path":{"type":["string","null"],"description":"Page path where the event happened"},"page_title":{"type":["string","null"],"description":"Page title (if available)"},"referrer":{"type":["string","null"],"description":"Referrer URL for this event"},"scroll_depth":{"type":["integer","null"],"format":"int32","description":"Scroll depth percentage (0-100)"},"session_page_number":{"type":["integer","null"],"format":"int32","description":"Page number within the session (1-indexed)"},"time_on_page":{"type":["integer","null"],"format":"int32","description":"Time spent on page in seconds (computed, not from column)"}}},"JourneySession":{"type":"object","description":"A session within the visitor journey, grouping events","required":["session_id","started_at","duration_seconds","page_views","events_count","is_bounced","is_engaged","events"],"properties":{"channel":{"type":["string","null"],"description":"Traffic source: channel (e.g. \"organic\", \"direct\", \"social\")"},"duration_seconds":{"type":"integer","format":"int64","description":"Session duration in seconds"},"ended_at":{"type":["string","null"],"format":"date-time","description":"When the session ended"},"entry_path":{"type":["string","null"],"description":"Entry page path"},"events":{"type":"array","items":{"$ref":"#/components/schemas/JourneyEvent"},"description":"Events within this session, ordered chronologically"},"events_count":{"type":"integer","format":"int64","description":"Total events in this session"},"exit_path":{"type":["string","null"],"description":"Exit page path"},"is_bounced":{"type":"boolean","description":"Whether the session was a bounce"},"is_engaged":{"type":"boolean","description":"Whether the visitor was engaged (had non-pageview events)"},"page_views":{"type":"integer","format":"int64","description":"Number of page views in this session"},"referrer":{"type":["string","null"],"description":"Traffic source: referrer URL"},"referrer_hostname":{"type":["string","null"],"description":"Traffic source: referrer hostname"},"session_id":{"type":"integer","format":"int32","description":"Session internal ID"},"started_at":{"type":"string","format":"date-time","description":"When the session started"},"utm_campaign":{"type":["string","null"],"description":"UTM campaign parameter"},"utm_medium":{"type":["string","null"],"description":"UTM medium parameter"},"utm_source":{"type":["string","null"],"description":"UTM source parameter"}}},"KeysRequest":{"type":"object","description":"Request to get keys matching a pattern","required":["pattern"],"properties":{"pattern":{"type":"string","description":"Pattern to match (supports * and ? wildcards)","example":"user:*"},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1}}},"KeysResponse":{"type":"object","description":"Response for keys operation","required":["keys"],"properties":{"keys":{"type":"array","items":{"type":"string"},"description":"List of matching keys","example":["user:1","user:2","user:3"]}}},"KillJobBody":{"type":"object","properties":{"force":{"type":"boolean","description":"When true, sends SIGKILL immediately. Defaults to SIGTERM so the\nprocess gets a chance to flush (mirrors `Command.kill()` in\n`@vercel/sandbox`, which also accepts a signal override)."}},"additionalProperties":false},"KnownAiAgentsResponse":{"type":"object","description":"Response listing every AI agent the detector knows about.","required":["items"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AiAgentDescriptor"}}}},"KvStatusResponse":{"type":"object","description":"Response for KV service status","required":["enabled","healthy"],"properties":{"docker_image":{"type":["string","null"],"description":"Docker image being used","example":"gotempsh/redis-walg:8-bookworm"},"enabled":{"type":"boolean","description":"Whether the KV service is enabled"},"healthy":{"type":"boolean","description":"Whether the underlying Redis service is healthy"},"version":{"type":["string","null"],"description":"Service version","example":"7.2"}}},"LemonSqueezyConfig":{"type":"object","properties":{"product_allowlist":{"type":"array","items":{"type":"string"}},"variant_allowlist":{"type":"array","items":{"type":"string"}}}},"LetsEncryptSettings":{"type":"object","properties":{"email":{"type":["string","null"],"default":null},"environment":{"type":"string","default":"production"}}},"LineContext":{"type":"object","description":"Raw surrounding lines for a single match (grep -C style).","required":["before","after"],"properties":{"after":{"type":"array","items":{"$ref":"#/components/schemas/ContextLine"},"description":"Lines immediately after the match, oldest-first."},"before":{"type":"array","items":{"$ref":"#/components/schemas/ContextLine"},"description":"Lines immediately before the match, oldest-first."}}},"LinkServiceRequest":{"type":"object","required":["project_id"],"properties":{"project_id":{"type":"integer","format":"int32"}}},"ListAgentsResponse":{"type":"object","required":["items","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AgentConfigResponse"}},"total":{"type":"integer","minimum":0}}},"ListApiKeysQuery":{"type":"object","properties":{"page":{"type":["integer","null"],"format":"int64","minimum":0},"page_size":{"type":["integer","null"],"format":"int64","minimum":0}}},"ListAuditLogsQuery":{"type":"object","description":"Query parameters for listing audit logs.\n\nEvery field is optional — omitting one means \"don't filter on it\". Deriving\n`IntoParams` makes utoipa render them as optional query params with the\ncorrect types; the previous hand-written `params((\"operation_type\", Query,\n…))` tuples defaulted every param to `required: true, type: string`, which\nmisled both API clients and the AI `describe_api`/`call_api` tools into\nthinking all filters were mandatory.","properties":{"from":{"type":["string","null"],"format":"date-time","description":"Start timestamp (milliseconds since epoch)"},"limit":{"type":["integer","null"],"format":"int32","description":"Maximum number of logs to return"},"offset":{"type":["integer","null"],"format":"int32","description":"Number of logs to skip"},"operation_type":{"type":["string","null"],"description":"Filter logs by operation type (omit for all)"},"to":{"type":["string","null"],"format":"date-time","description":"End timestamp (milliseconds since epoch)"},"user_id":{"type":["integer","null"],"format":"int32","description":"Filter logs by user ID (omit for all users)"}}},"ListBlobsQuery":{"type":"object","description":"Query parameters for listing blobs","properties":{"cursor":{"type":["string","null"],"description":"Continuation token for pagination"},"limit":{"type":["integer","null"],"format":"int32","description":"Maximum number of items to return","example":100},"prefix":{"type":["string","null"],"description":"Prefix to filter by","example":"images/"},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1}}},"ListBlobsResponse":{"type":"object","description":"Response for listing blobs","required":["blobs","hasMore"],"properties":{"blobs":{"type":"array","items":{"$ref":"#/components/schemas/BlobResponse"},"description":"List of blobs"},"cursor":{"type":["string","null"],"description":"Continuation token for next page"},"hasMore":{"type":"boolean","description":"Whether there are more results","example":false}}},"ListCustomDomainsResponse":{"type":"object","required":["domains","total"],"properties":{"domains":{"type":"array","items":{"$ref":"#/components/schemas/CustomDomainResponse"}},"total":{"type":"integer","minimum":0}}},"ListDeploymentTokensQuery":{"type":"object","properties":{"page":{"type":["integer","null"],"format":"int64","example":1,"minimum":0},"page_size":{"type":["integer","null"],"format":"int64","example":20,"minimum":0}}},"ListDomainsResponse":{"type":"object","required":["domains","total","page","page_size"],"properties":{"domains":{"type":"array","items":{"$ref":"#/components/schemas/DomainResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"ListEntitiesQuery":{"type":"object","properties":{"limit":{"type":"integer","description":"Maximum number of entities to return","example":100,"minimum":0},"token":{"type":["string","null"],"description":"Continuation token for pagination (backend-specific)"}}},"ListErrorEventsQuery":{"type":"object","properties":{"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0}}},"ListErrorGroupsQuery":{"type":"object","properties":{"end_date":{"type":["string","null"],"format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"sort_by":{"type":["string","null"]},"sort_order":{"type":"string"},"start_date":{"type":["string","null"],"format":"date-time"},"status":{"type":["string","null"]}}},"ListJobsResponse":{"type":"object","required":["items"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/JobSummaryResponse"}}}},"ListMcpsResponse":{"type":"object","description":"Concrete list wrapper for MCP server definitions (utoipa requires non-generic types).","required":["items","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/McpDefinitionResponse"}},"total":{"type":"integer","minimum":0}}},"ListOnDemandCertsResponse":{"type":"object","description":"Paginated list of on-demand cert attempts (ADR-018 §5 console \"Certificates\"\nsurface). Joined with current `domains.status`, newest first.","required":["certs","total","page","page_size"],"properties":{"certs":{"type":"array","items":{"$ref":"#/components/schemas/OnDemandCertRow"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"ListOrdersResponse":{"type":"object","required":["orders"],"properties":{"orders":{"type":"array","items":{"$ref":"#/components/schemas/AcmeOrderResponse"}}}},"ListPresetsResponse":{"type":"object","required":["presets","total"],"properties":{"presets":{"type":"array","items":{"$ref":"#/components/schemas/PresetResponse"}},"total":{"type":"integer","minimum":0}}},"ListRunsResponse":{"type":"object","required":["items","total","page","page_size"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AgentRunResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"ListSandboxesResponse":{"type":"object","description":"SDK list response: `{ sandboxes: [...], pagination: {...} }`.","required":["sandboxes","pagination"],"properties":{"pagination":{"$ref":"#/components/schemas/Pagination"},"sandboxes":{"type":"array","items":{"$ref":"#/components/schemas/SandboxInner"}}}},"ListScansQuery":{"type":"object","properties":{"page":{"type":["integer","null"],"format":"int64","example":1,"minimum":0},"page_size":{"type":["integer","null"],"format":"int64","example":20,"minimum":0}}},"ListSecretsResponse":{"type":"object","required":["items","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/SecretResponse"}},"total":{"type":"integer","minimum":0}}},"ListSkillsResponse":{"type":"object","description":"Concrete list wrapper for skill definitions (utoipa requires non-generic types).","required":["items","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/SkillDefinitionResponse"}},"total":{"type":"integer","minimum":0}}},"ListTagsResponse":{"type":"object","description":"Response for listing tags","required":["tags","total"],"properties":{"tags":{"type":"array","items":{"type":"string"},"description":"List of available tags"},"total":{"type":"integer","description":"Total number of tags","minimum":0}}},"ListTemplatesQuery":{"type":"object","description":"Query parameters for listing templates","properties":{"featured":{"type":["boolean","null"],"description":"Only return featured templates"},"tag":{"type":["string","null"],"description":"Filter templates by tag"}}},"ListTemplatesResponse":{"type":"object","description":"Response for listing templates","required":["templates","total"],"properties":{"templates":{"type":"array","items":{"$ref":"#/components/schemas/TemplateResponse"},"description":"List of templates"},"total":{"type":"integer","description":"Total number of templates","minimum":0}}},"ListVulnerabilitiesQuery":{"type":"object","properties":{"page":{"type":["integer","null"],"format":"int64","example":1,"minimum":0},"page_size":{"type":["integer","null"],"format":"int64","example":20,"minimum":0},"severity":{"type":["string","null"],"example":"CRITICAL"}}},"LiveVisitorInfo":{"type":"object","required":["id","visitor_id","project_id","environment_id","first_seen","last_seen","is_crawler"],"properties":{"city":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"crawler_name":{"type":["string","null"]},"current_page":{"type":["string","null"],"description":"Most recent page path visited by this visitor"},"custom_data":{},"environment_id":{"type":"integer","format":"int32"},"first_channel":{"type":["string","null"],"description":"Marketing channel from the first visit (e.g. \"Organic Search\", \"Direct\")"},"first_referrer":{"type":["string","null"],"description":"Full referrer URL from the visitor's first session"},"first_referrer_hostname":{"type":["string","null"],"description":"Hostname extracted from first_referrer"},"first_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"id":{"type":"integer","format":"int32"},"ip_address":{"type":["string","null"]},"ip_address_id":{"type":["integer","null"],"format":"int32"},"is_crawler":{"type":"boolean"},"is_eu":{"type":["boolean","null"]},"last_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"latitude":{"type":["number","null"],"format":"double"},"longitude":{"type":["number","null"],"format":"double"},"project_id":{"type":"integer","format":"int32"},"region":{"type":["string","null"]},"timezone":{"type":["string","null"]},"user_agent":{"type":["string","null"]},"visitor_id":{"type":"string"}}},"LiveVisitorsListResponse":{"type":"object","required":["total_count","visitors","window_minutes"],"properties":{"total_count":{"type":"integer","format":"int64"},"visitors":{"type":"array","items":{"$ref":"#/components/schemas/LiveVisitorInfo"}},"window_minutes":{"type":"integer","format":"int32"}}},"LocationCount":{"type":"object","required":["location","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"location":{"type":"string"},"percentage":{"type":"number","format":"double"}}},"LocationGranularity":{"type":"string","enum":["country","region","city"]},"LocationInfo":{"type":"object","properties":{"city":{"type":["string","null"]},"country":{"type":["string","null"]},"region":{"type":["string","null"]}}},"LogLevel":{"type":"string","description":"Normalized log level","enum":["TRACE","DEBUG","INFO","WARN","ERROR"]},"LogRecord":{"type":"object","description":"A single log record ready for storage.","required":["project_id","resource","timestamp","observed_timestamp","severity","severity_text","body","attributes"],"properties":{"attributes":{"type":"object","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"body":{"type":"string"},"deployment_id":{"type":["integer","null"],"format":"int32"},"observed_timestamp":{"type":"string","format":"date-time"},"project_id":{"type":"integer","format":"int32"},"resource":{"$ref":"#/components/schemas/ResourceInfo"},"severity":{"$ref":"#/components/schemas/LogSeverity"},"severity_text":{"type":"string"},"span_id":{"type":["string","null"]},"timestamp":{"type":"string","format":"date-time"},"trace_id":{"type":["string","null"]}}},"LogSearchLine":{"type":"object","description":"A single line in search results","required":["timestamp","level","service","message","chunk_id","line_offset"],"properties":{"chunk_id":{"type":"string"},"container_id":{"type":"string","description":"Container this line came from — lets the UI tag/group lines by container\nin a combined (\"show all\") multi-container view."},"context":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/LineContext","description":"Raw surrounding lines (grep -C). `None` unless `context_lines > 0` was\nrequested. Overlapping windows between nearby matches are merged: the\nshared neighbors appear on the earlier match only, so the frontend can\nrender one continuous block without duplicated lines."}]},"deploy_id":{"type":["integer","null"],"format":"int32"},"fields":{},"level":{"$ref":"#/components/schemas/LogLevel"},"line_offset":{"type":"integer","format":"int32"},"message":{"type":"string"},"node_id":{"type":["integer","null"],"format":"int32","description":"Worker node the line came from (`None` = control-plane-local)."},"node_name":{"type":["string","null"],"description":"Human-readable node name for display."},"service":{"type":"string"},"timestamp":{"type":"string"}}},"LogSeverity":{"type":"string","description":"Log severity level (simplified from OTel's 24 levels).","enum":["TRACE","DEBUG","INFO","WARN","ERROR","FATAL"]},"LogSource":{"type":"object","description":"A distinct log source (container) seen in the queried scope. Used to populate\nthe history filter dropdowns with the *full* set of containers/nodes for the\nproject + env + deployment + time window — independent of the active\ncontainer/node/service filter, so the user can switch between them.","required":["container_id","service"],"properties":{"container_id":{"type":"string"},"node_id":{"type":["integer","null"],"format":"int32"},"node_name":{"type":["string","null"]},"service":{"type":"string"}}},"LogStream":{"type":"string","description":"Log output stream","enum":["stdout","stderr"]},"LoginRequest":{"type":"object","required":["email","password"],"properties":{"email":{"type":"string"},"password":{"type":"string"}}},"LogsQuery":{"type":"object","properties":{"tail":{"type":["integer","null"],"description":"Number of lines to return from the tail. Defaults to 200, capped at 2000.","minimum":0}}},"LogsResponse":{"type":"object","required":["data","count"],"properties":{"count":{"type":"integer","minimum":0},"data":{"type":"array","items":{"$ref":"#/components/schemas/LogRecord"}}}},"ManagedDomainResponse":{"type":"object","description":"Managed domain response","required":["id","provider_id","domain","auto_manage","verified","generated_hostname_mode","sync_generated_records","created_at","updated_at"],"properties":{"auto_manage":{"type":"boolean"},"created_at":{"type":"string"},"domain":{"type":"string"},"generated_hostname_mode":{"type":"string","description":"Generated hostname layout: `\"standard\"` or `\"flat\"`."},"id":{"type":"integer","format":"int32"},"provider_id":{"type":"integer","format":"int32"},"sync_generated_records":{"type":"boolean","description":"Whether generated hostnames are reconciled into the provider's DNS zone."},"updated_at":{"type":"string"},"verification_error":{"type":["string","null"]},"verified":{"type":"boolean"},"verified_at":{"type":["string","null"]},"zone_access_error":{"type":["string","null"],"description":"Detail for a failed zone-access check."},"zone_access_ok":{"type":["boolean","null"],"description":"Last token zone-access check: `Some(true)`/`Some(false)`/`None` (unchecked)."},"zone_id":{"type":["string","null"]}}},"ManualAction":{"type":"object","description":"A manual action the user must perform outside of the automated migration","required":["timing","description","reason"],"properties":{"description":{"type":"string","description":"Human-readable description"},"reason":{"type":"string","description":"Why this can't be automated"},"timing":{"$ref":"#/components/schemas/ManualActionTiming","description":"When this action needs to happen"}}},"ManualActionTiming":{"type":"string","description":"When a manual action needs to happen relative to migration","enum":["before-migration","after-migration","within-hours"]},"McpDefinitionResponse":{"type":"object","required":["id","slug","name","config","created_at","updated_at"],"properties":{"config":{"type":"object"},"created_at":{"type":"string"},"description":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"project_id":{"type":["integer","null"],"format":"int32"},"slug":{"type":"string"},"updated_at":{"type":"string"}}},"MessageContent":{"oneOf":[{"type":"string"},{"type":"array","items":{"$ref":"#/components/schemas/ContentPart"}}]},"MessagePart":{"oneOf":[{"type":"object","required":["text","type"],"properties":{"text":{"type":"string"},"type":{"type":"string","enum":["text"]}}},{"type":"object","required":["tool","type"],"properties":{"tool":{"$ref":"#/components/schemas/ToolInfo"},"type":{"type":"string","enum":["tool"]}}}],"description":"One ordered segment of an assistant turn: a chunk of prose, or a tool\ninvocation. Mirrors the `metadata.parts` persisted by the chat service."},"MessageResponse":{"type":"object","required":["role","content","created_at"],"properties":{"content":{"type":"string"},"created_at":{"type":"string"},"parts":{"type":["array","null"],"items":{"$ref":"#/components/schemas/MessagePart"},"description":"Ordered render segments (text / tool, in the order they occurred) so a\nreloaded chat shows the same interleaving as the live stream. Absent for\nolder messages persisted before parts were tracked; the client then falls\nback to `tools` (rendered first) + `content`."},"role":{"type":"string"},"tools":{"type":["array","null"],"items":{"$ref":"#/components/schemas/ToolInfo"},"description":"Tools the assistant ran on this turn (persisted in message metadata), so\nthe chat replays its tool work after a reload. Absent for plain turns."}}},"MeteredMode":{"type":"string","description":"How to treat metered-billing subscriptions when computing MRR.\n\n* `DeriveFromInvoices` (default): ignore the subscription row's\n `mrr_minor` for metered items and rely on the per-invoice\n [`NormalizedEventType::MrrRealized`] events instead. Correct for\n pure-metered, hybrid, tiered, and flat — recommended.\n* `UseSubscription`: trust whatever MRR the subscription parser\n returns (0 for metered). Legacy behavior.\n* `Ignore`: drop metered subscriptions from MRR entirely.","enum":["derive_from_invoices","use_subscription","ignore"]},"MetricAggregation":{"oneOf":[{"type":"string","description":"Arithmetic mean of the scalar value in each bucket. The default.","enum":["avg"]},{"type":"string","description":"Sum of the scalar value in each bucket.","enum":["sum"]},{"type":"string","description":"Minimum scalar value in each bucket.","enum":["min"]},{"type":"string","description":"Maximum scalar value in each bucket.","enum":["max"]},{"type":"string","description":"Number of points in each bucket.","enum":["count"]},{"type":"string","description":"Per-second rate of change of a cumulative monotonic counter, computed as\n`(max - min) / window_seconds` within each bucket. Non-monotonic series\nfall back to a simple delta.","enum":["rate_per_sec"]},{"type":"object","description":"A quantile of the scalar value in each bucket. The carried `f64` is the\nrequested quantile in `[0.0, 1.0]`.","required":["quantile"],"properties":{"quantile":{"type":"number","format":"double","description":"A quantile of the scalar value in each bucket. The carried `f64` is the\nrequested quantile in `[0.0, 1.0]`."}}}],"description":"The aggregation applied when reducing raw metric points into a time bucket.\n\nStore-neutral: every storage backend (ClickHouse today, TimescaleDB later)\nmust be able to satisfy this contract. `Quantile(q)` carries the requested\nquantile in `[0.0, 1.0]` (e.g. `0.95` for p95)."},"MetricBucket":{"type":"object","description":"A time-bucketed metric aggregate for chart display.\n\nStore-neutral response contract. The legacy scalar fields\n(`avg_value`/`min_value`/`max_value`/`count`) are always populated for chart\nback-compat. The richer fields describe the explicitly-requested\n[`MetricAggregation`] (`value`), optional `quantiles`, an optional\n`histogram_summary`, and a `series_key` identifying the label-set when the\nquery used `group_by`.","required":["bucket","avg_value","min_value","max_value","count"],"properties":{"avg_value":{"type":"number","format":"double"},"bucket":{"type":"string","format":"date-time"},"count":{"type":"integer","format":"int64"},"histogram_summary":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/HistogramSummary","description":"A reduced histogram summary when the bucketed metric is a histogram."}]},"max_value":{"type":"number","format":"double"},"min_value":{"type":"number","format":"double"},"quantiles":{"type":"array","items":{"type":"array","items":false,"prefixItems":[{"type":"number","format":"double"},{"type":"number","format":"double"}]},"description":"Computed quantile/value pairs `(quantile, value)` when the query asked for\nquantile aggregation; otherwise empty."},"series_key":{"type":["array","null"],"items":{"type":"array","items":false,"prefixItems":[{"type":"string"},{"type":"string"}]},"description":"The label-set this bucket belongs to, as ordered `(key, value)` pairs,\nwhen the query grouped by labels. Empty/`None` = the single ungrouped\naggregate stream."},"value":{"type":"number","format":"double","description":"The value of the requested [`MetricAggregation`] for this bucket. For the\ndefault `Avg` aggregation this equals `avg_value`. `#[serde(default)]` so\npre-existing payloads (which only carried avg/min/max/count) still parse."}}},"MetricDataPoint":{"type":"object","description":"A single `(timestamp, value)` data point in a metric series.","required":["time","value"],"properties":{"time":{"type":"string","description":"ISO 8601 timestamp with `Z` suffix."},"value":{"type":"number","format":"double","description":"Metric value at this bucket."}}},"MetricType":{"type":"string","description":"The type of an OTel metric.","enum":["gauge","sum","histogram","exponential_histogram","summary"]},"MetricsOverTimeResponse":{"type":"object","required":["timestamps","ttfb","lcp","fid","fcp","cls","inp"],"properties":{"cls":{"type":"array","items":{"type":["number","null"],"format":"float"}},"cls_p75":{"type":["number","null"],"format":"float"},"cls_p90":{"type":["number","null"],"format":"float"},"cls_p95":{"type":["number","null"],"format":"float"},"cls_p99":{"type":["number","null"],"format":"float"},"fcp":{"type":"array","items":{"type":["number","null"],"format":"float"}},"fcp_p75":{"type":["number","null"],"format":"float"},"fcp_p90":{"type":["number","null"],"format":"float"},"fcp_p95":{"type":["number","null"],"format":"float"},"fcp_p99":{"type":["number","null"],"format":"float"},"fid":{"type":"array","items":{"type":["number","null"],"format":"float"}},"fid_p75":{"type":["number","null"],"format":"float"},"fid_p90":{"type":["number","null"],"format":"float"},"fid_p95":{"type":["number","null"],"format":"float"},"fid_p99":{"type":["number","null"],"format":"float"},"inp":{"type":"array","items":{"type":["number","null"],"format":"float"}},"inp_p75":{"type":["number","null"],"format":"float"},"inp_p90":{"type":["number","null"],"format":"float"},"inp_p95":{"type":["number","null"],"format":"float"},"inp_p99":{"type":["number","null"],"format":"float"},"lcp":{"type":"array","items":{"type":["number","null"],"format":"float"}},"lcp_p75":{"type":["number","null"],"format":"float"},"lcp_p90":{"type":["number","null"],"format":"float"},"lcp_p95":{"type":["number","null"],"format":"float"},"lcp_p99":{"type":["number","null"],"format":"float"},"timestamps":{"type":"array","items":{"type":"string"}},"ttfb":{"type":"array","items":{"type":["number","null"],"format":"float"}},"ttfb_p75":{"type":["number","null"],"format":"float"},"ttfb_p90":{"type":["number","null"],"format":"float"},"ttfb_p95":{"type":["number","null"],"format":"float"},"ttfb_p99":{"type":["number","null"],"format":"float"}}},"MetricsQuery":{"type":"object","required":["start_date","end_date","project_id"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"MetricsRangeQuery":{"type":"object","description":"Query params for range metric queries.","required":["metric"],"properties":{"metric":{"type":"string","description":"Metric name, e.g. `\"pg.connections_active\"`."},"percentile":{"type":["number","null"],"format":"double","description":"Optional histogram percentile (0–100). When provided, the endpoint\nfetches histogram buckets and computes the requested quantile."},"range":{"type":"string","description":"Time window: `\"1h\"` | `\"6h\"` | `\"24h\"` | `\"7d\"`."}}},"MetricsStatusResponse":{"type":"object","description":"Freshness status: when metrics were last received for this service.","properties":{"last_received_at":{"type":["string","null"],"description":"ISO 8601 timestamp of the most recent metric row, or null if none yet."}}},"MetricsStoreKind":{"type":"string","description":"Which storage backend to use for the MetricsStore.","enum":["timescale_db","click_house"]},"MetricsSummaryResponse":{"type":"object","required":["currency","current_mrr_minor","current_arr_minor","active_subscriptions","active_customers","churned_last_30d","arpu_minor"],"properties":{"active_customers":{"type":"integer","format":"int64"},"active_subscriptions":{"type":"integer","format":"int64"},"arpu_minor":{"type":"integer","format":"int64"},"churned_last_30d":{"type":"integer","format":"int64"},"currency":{"type":"string"},"current_arr_minor":{"type":"integer","format":"int64"},"current_mrr_minor":{"type":"integer","format":"int64"}}},"MfaRequiredResponse":{"type":"object","required":["requires_mfa","session_token"],"properties":{"requires_mfa":{"type":"boolean"},"session_token":{"type":"string"}}},"MfaSetupResponse":{"type":"object","required":["secret_key","qr_code","recovery_codes"],"properties":{"qr_code":{"type":"string"},"recovery_codes":{"type":"array","items":{"type":"string"}},"secret_key":{"type":"string"}}},"MfaVerificationRequest":{"type":"object","required":["code"],"properties":{"code":{"type":"string"}}},"MigrationStep":{"type":"object","description":"A single step in the migration execution plan.\n\nSteps are presented to the user before execution so they know exactly\nwhat will happen. During execution, each step runs in order and reports\nits outcome before proceeding to the next.","required":["order","id","title","description","resource_type","risk","skippable","reversible"],"properties":{"data_implications":{"type":"array","items":{"$ref":"#/components/schemas/DataImplication"},"description":"Data implications — what could go wrong or what the user needs to know"},"description":{"type":"string","description":"Detailed description of what this step does"},"estimated_duration":{"type":["string","null"],"description":"Estimated duration hint (e.g., \"< 1 second\", \"10-30 seconds\")"},"id":{"type":"string","description":"Machine-readable step identifier (e.g., \"create-project\", \"create-service-postgres\")"},"order":{"type":"integer","description":"Step number (1-based, for display)","minimum":0},"post_conditions":{"type":"array","items":{"type":"string"},"description":"Things the user should verify AFTER this step completes"},"pre_conditions":{"type":"array","items":{"type":"string"},"description":"Things the user should verify BEFORE this step runs"},"resource_type":{"$ref":"#/components/schemas/StepResourceType","description":"What kind of resource this step creates/modifies"},"reversible":{"type":"boolean","description":"Whether this step is reversible (can be cleaned up on failure)"},"risk":{"$ref":"#/components/schemas/RiskLevel","description":"Risk level for this step"},"skippable":{"type":"boolean","description":"Whether this step can be skipped by the user"},"skipped":{"type":"boolean","description":"Whether the user has chosen to skip this step (set during review)"},"title":{"type":"string","description":"Human-readable title (e.g., \"Create project 'my-app'\")"}}},"MigrationSummary":{"type":"object","description":"Human-readable summary of the entire migration plan","required":["headline","overall_risk","resource_counts"],"properties":{"critical_warnings":{"type":"array","items":{"type":"string"},"description":"Critical warnings that must be acknowledged before proceeding.\nThese are the most important things the user needs to know."},"headline":{"type":"string","description":"One-line summary (e.g., \"Migrate 'my-app' from Vercel with 1 database, 2 domains\")"},"manual_actions_required":{"type":"array","items":{"$ref":"#/components/schemas/ManualAction"},"description":"Manual actions the user must perform (before or after migration)"},"overall_risk":{"$ref":"#/components/schemas/RiskLevel","description":"Overall risk assessment for the migration"},"resource_counts":{"$ref":"#/components/schemas/ResourceCounts","description":"Resource counts for quick overview"},"unsupported_features":{"type":"array","items":{"$ref":"#/components/schemas/UnsupportedFeature"},"description":"Features from the source platform that cannot be migrated"}}},"MintEnrollmentTokenRequest":{"type":"object","properties":{"bound_node_name":{"type":["string","null"],"description":"Optional: restrict the token to register one specific node name."},"max_uses":{"type":["integer","null"],"format":"int32","description":"Maximum registrations this token may authorize (default 1)."},"ttl_secs":{"type":["integer","null"],"format":"int64","description":"Time-to-live in seconds (default 3600 = 1h)."}}},"MintEnrollmentTokenResponse":{"type":"object","required":["id","token","expires_at","max_uses","message"],"properties":{"ca_fingerprint":{"type":["string","null"],"description":"SHA-256 fingerprint of the cluster CA (if mTLS is set up). Pass it to the\nworker as `temps join --ca-fingerprint ` to verify the CA on join."},"expires_at":{"type":"string"},"id":{"type":"integer","format":"int32"},"max_uses":{"type":"integer","format":"int32"},"message":{"type":"string"},"token":{"type":"string","description":"The plaintext enrollment token — shown only once, save it now."}}},"MiscResult":{"type":"object","description":"Miscellaneous validation result","required":["is_disposable","is_role_account","is_b2c"],"properties":{"gravatar_url":{"type":["string","null"],"description":"Gravatar URL if available"},"is_b2c":{"type":"boolean","description":"Whether the email provider is a B2C (consumer) email provider"},"is_disposable":{"type":"boolean","description":"Whether the email is from a disposable email provider"},"is_role_account":{"type":"boolean","description":"Whether the email is a role-based account (e.g., admin@, info@)"}}},"MkdirBody":{"type":"object","required":["path"],"properties":{"path":{"type":"string"}},"additionalProperties":false},"ModelInfo":{"type":"object","required":["id","object","owned_by"],"properties":{"id":{"type":"string"},"object":{"type":"string"},"owned_by":{"type":"string"}}},"ModelListResponse":{"type":"object","required":["object","data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ModelInfo"}},"object":{"type":"string"}}},"ModelPricing":{"type":"object","description":"Pricing for a single model, all values in USD per 1M tokens.\nFields are optional because not every provider supports every pricing tier.","required":["model","display_name","provider","input_per_million","output_per_million"],"properties":{"batch_input_per_million":{"type":["number","null"],"format":"double","description":"Batch API input cost per 1M tokens (if provider offers batch pricing)"},"batch_output_per_million":{"type":["number","null"],"format":"double","description":"Batch API output cost per 1M tokens"},"cache_hit_per_million":{"type":["number","null"],"format":"double","description":"Cache hit / refresh cost per 1M tokens"},"cache_write_1h_per_million":{"type":["number","null"],"format":"double","description":"1-hour cache write cost per 1M tokens"},"cache_write_5m_per_million":{"type":["number","null"],"format":"double","description":"5-minute cache write cost per 1M tokens (Anthropic-style prompt caching)"},"deprecated":{"type":"boolean","description":"Whether the model is deprecated"},"display_name":{"type":"string","description":"Human-readable model name (e.g. \"Claude Sonnet 4.6\")"},"input_per_million":{"type":"number","format":"double","description":"Base input token cost per 1M tokens"},"model":{"type":"string","description":"Model identifier (e.g. \"gpt-5.4\", \"claude-sonnet-4-6\")"},"output_per_million":{"type":"number","format":"double","description":"Output token cost per 1M tokens"},"provider":{"type":"string","description":"Provider ID (e.g. \"openai\", \"anthropic\")"}}},"ModelUsage":{"type":"object","required":["model","provider","request_count","input_tokens","output_tokens","total_tokens","avg_latency_ms"],"properties":{"avg_latency_ms":{"type":"number","format":"double"},"input_tokens":{"type":"integer","format":"int64"},"model":{"type":"string"},"output_tokens":{"type":"integer","format":"int64"},"provider":{"type":"string"},"request_count":{"type":"integer","format":"int64"},"total_tokens":{"type":"integer","format":"int64"}}},"MonitorResponse":{"type":"object","required":["id","project_id","name","monitor_type","monitor_url","check_interval_seconds","is_active","created_at","updated_at"],"properties":{"check_interval_seconds":{"type":"integer","format":"int32"},"check_path":{"type":["string","null"]},"created_at":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"monitor_type":{"type":"string"},"monitor_url":{"type":"string"},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"updated_at":{"type":"string","format":"date-time"}}},"MonitorStatus":{"type":"object","required":["monitor","current_status","uptime_percentage"],"properties":{"avg_response_time_ms":{"type":["integer","null"],"format":"int32"},"current_status":{"type":"string"},"monitor":{"$ref":"#/components/schemas/MonitorResponse"},"uptime_percentage":{"type":"number","format":"double"}}},"MonitoringSettings":{"type":"object","description":"Global metrics observability configuration.\n\nControls whether the MetricsScraper and AlertEvaluator background tasks\nare active, which storage backend they write to, and how long data is kept\nat each retention tier.","properties":{"clickhouse_url":{"type":["string","null"],"description":"ClickHouse DSN (legacy, optional). The runtime metrics store is built\nfrom the `TEMPS_CLICKHOUSE_*` env vars, never from this field; it is\nretained for compatibility and operator reference only.\nExample: `\"http://localhost:8123\"`.","default":null},"enabled":{"type":"boolean","description":"Enable or disable all metrics collection (scraping + alerting).\nDefaults to `false` so new installs don't write to TimescaleDB until\nan operator explicitly enables the feature.","default":false},"retention_daily_years":{"type":"integer","format":"int32","description":"How many years of daily-aggregate data to keep (converted to days internally).","default":2,"example":2,"maximum":10,"minimum":1},"retention_hourly_days":{"type":"integer","format":"int32","description":"How many days of hourly-aggregate data to keep.","default":90,"example":90,"minimum":1},"retention_raw_days":{"type":"integer","format":"int32","description":"How many days of raw (30 s resolution) metric data to keep.","default":7,"example":7,"minimum":1},"scrape_interval_secs":{"type":"integer","format":"int64","description":"How often the MetricsScraper collects data from all sources, in seconds.\nMinimum effective value is 10 s; values below that are clamped at runtime.","default":30,"example":30,"minimum":10},"store":{"oneOf":[{"$ref":"#/components/schemas/MetricsStoreKind","description":"Storage backend for metric data."}],"default":"timescale_db"}}},"MonitoringSettingsMasked":{"type":"object","description":"Monitoring settings with the ClickHouse DSN masked.\n\n`clickhouse_url` can embed credentials (`http://user:pass@host`), so it is\nreported only as a boolean (`clickhouse_url_set`) rather than echoed back —\nconsistent with how the DNS API key and Docker registry password are masked.","required":["enabled","store","scrape_interval_secs","retention_raw_days","retention_hourly_days","retention_daily_years","clickhouse_url_set"],"properties":{"clickhouse_url_set":{"type":"boolean","description":"True when a ClickHouse DSN is configured. The DSN itself is never\nreturned over HTTP because it may contain credentials."},"enabled":{"type":"boolean"},"retention_daily_years":{"type":"integer","format":"int32","minimum":0},"retention_hourly_days":{"type":"integer","format":"int32","minimum":0},"retention_raw_days":{"type":"integer","format":"int32","minimum":0},"scrape_interval_secs":{"type":"integer","format":"int64","minimum":0},"store":{"$ref":"#/components/schemas/MetricsStoreKind"}}},"MrrBucketResponse":{"type":"object","required":["bucket","mrr_minor","charge_total_minor","refund_total_minor","charge_count"],"properties":{"bucket":{"type":"string","format":"date-time"},"charge_count":{"type":"integer","format":"int64"},"charge_total_minor":{"type":"integer","format":"int64"},"mrr_minor":{"type":"integer","format":"int64"},"refund_total_minor":{"type":"integer","format":"int64"}}},"MultiNodeSettings":{"type":"object","description":"Multi-node cluster settings","properties":{"cluster_ca_cert_pem":{"type":["string","null"],"description":"Per-cluster CA certificate (PEM) for multi-node mTLS (ADR-020 WS-2.1).\nPublic — distributed to nodes as the trust root and used by the control\nplane as the root for verifying agent server certs. Minted lazily on the\nfirst CSR-bearing registration.","default":null},"cluster_ca_key_encrypted":{"type":["string","null"],"description":"Per-cluster CA private key, AES-256-GCM ciphertext (EncryptionService).\nSECRET — never returned over HTTP (elided in the masked response).","default":null},"join_token_hash":{"type":["string","null"],"description":"SHA-256 hash of the join token (never store plaintext)","default":null},"legacy_shared_token_enabled":{"type":"boolean","description":"Whether the legacy single shared join token is still accepted for node\nregistration (ADR-020 WS-1.1). Defaults to `true` so existing clusters\nkeep working on upgrade; fresh installs should set it `false` and rely on\nshort-lived, single-use enrollment tokens instead.","default":true},"node_cpu_alert_percent":{"type":["number","null"],"format":"double","description":"CPU-usage percent above which a worker node raises a resource alert\n(ADR-020 / monitoring). `None` disables CPU alerting. Default 90.","default":90.0},"node_disk_alert_percent":{"type":["number","null"],"format":"double","description":"Disk-usage percent above which a worker node raises a resource alert.\n`None` disables disk alerting. Default 90.","default":90.0},"node_memory_alert_percent":{"type":["number","null"],"format":"double","description":"Memory-usage percent above which a worker node raises a resource alert.\n`None` disables memory alerting. Default 90.","default":90.0},"private_address":{"type":["string","null"],"description":"Private/WireGuard IP address of the control plane node.\nUsed by remote worker nodes to reach services (databases, etc.) running on the control plane.\nSet via `--private-address` or `TEMPS_PRIVATE_ADDRESS`.","default":null},"require_mtls":{"type":"boolean","description":"Whether to enforce multi-node mTLS (ADR-020 WS-2.1). When `false`\n(default), the control plane ignores join-time CSRs and nodes keep\nserving plaintext HTTP — zero behavior change. When `true`, the CP signs\nnode CSRs, nodes serve mutual TLS, and every CP→agent call uses the\ncluster client cert. Observe-then-enforce: flip this on only once all\nworkers have re-enrolled with certs.","default":false}}},"MultiNodeSettingsMasked":{"type":"object","description":"Multi-node settings with `join_token_hash` elided.","required":["has_join_token","require_mtls","legacy_shared_token_enabled"],"properties":{"cluster_ca_fingerprint":{"type":["string","null"],"description":"SHA-256 fingerprint of the cluster CA certificate (public — operators can\nverify it out of band; the CA private key is never exposed)."},"has_join_token":{"type":"boolean"},"legacy_shared_token_enabled":{"type":"boolean","description":"Whether the deprecated shared join token is still accepted."},"node_cpu_alert_percent":{"type":["number","null"],"format":"double","description":"Node resource-alert thresholds (percent); `None` = that alert disabled."},"node_disk_alert_percent":{"type":["number","null"],"format":"double"},"node_memory_alert_percent":{"type":["number","null"],"format":"double"},"private_address":{"type":["string","null"]},"require_mtls":{"type":"boolean","description":"Whether control-plane↔agent mutual TLS is enforced."}}},"MxResult":{"type":"object","description":"MX (Mail Exchange) validation result","required":["accepts_mail","records"],"properties":{"accepts_mail":{"type":"boolean","description":"Whether the domain accepts mail"},"error":{"type":["string","null"],"description":"Error message if MX lookup failed"},"records":{"type":"array","items":{"type":"string"},"description":"List of MX records for the domain","example":["alt1.gmail-smtp-in.l.google.com.","gmail-smtp-in.l.google.com."]}}},"NavEntry":{"type":"object","description":"A navigation entry that the plugin contributes to the Temps UI.","required":["label","icon","section","path","order"],"properties":{"icon":{"type":"string","description":"Lucide icon name (e.g., \"puzzle\", \"database\", \"activity\")"},"label":{"type":"string","description":"Display label in the sidebar"},"order":{"type":"integer","format":"int32","description":"Sort order within the section (lower = higher in list)","minimum":0},"path":{"type":"string","description":"Client-side route path (e.g., \"/my-plugin\")"},"section":{"$ref":"#/components/schemas/NavSection","description":"Which sidebar section this entry belongs to"}}},"NavSection":{"type":"string","description":"Where the plugin's nav entry appears in the Temps UI sidebar.","enum":["platform","settings","project"]},"NetworkConfiguration":{"type":"object","description":"Network configuration","required":["mode","dns_servers"],"properties":{"dns_servers":{"type":"array","items":{"type":"string"},"description":"DNS servers"},"hostname":{"type":["string","null"],"description":"Hostname"},"mode":{"$ref":"#/components/schemas/NetworkMode","description":"Network mode"}}},"NetworkMode":{"oneOf":[{"type":"string","enum":["bridge"]},{"type":"string","enum":["host"]},{"type":"string","enum":["none"]},{"type":"object","required":["custom"],"properties":{"custom":{"type":"string"}}}],"description":"Network mode"},"NixpacksPresetConfig":{"type":"object","description":"Configuration for Nixpacks preset\nNixpacks provider and inline build-plan configuration.","properties":{"nixpacksConfig":{"type":["string","null"],"description":"Optional inline nixpacks.toml contents."},"providers":{"type":"array","items":{"$ref":"#/components/schemas/NixpacksProvider"},"description":"Ordered Nixpacks providers. Empty means repository config or auto-detect;\ninclude `...` to combine auto-detection with explicit providers."}}},"NixpacksProvider":{"type":"string","description":"A Nixpacks build provider.\n\n`Auto` serializes as the native Nixpacks `...` marker, which includes the\nprovider detected from the project alongside any explicitly listed\nproviders.","enum":["...","node","python","rust","go","java","php","ruby","deno","elixir","csharp","fsharp","dart","swift","zig","scala","haskell","clojure","crystal","cobol","gleam","lunatic","scheme","static"]},"NodeContainerListResponse":{"type":"object","required":["containers","total"],"properties":{"containers":{"type":"array","items":{"$ref":"#/components/schemas/NodeContainerResponse"}},"total":{"type":"integer","minimum":0}}},"NodeContainerResponse":{"type":"object","description":"A container running on a specific node, enriched with project/environment context.","required":["container_id","container_name","image_name","status","created_at","deployment_id","project_id","project_name","environment_id","environment_name"],"properties":{"container_id":{"type":"string"},"container_name":{"type":"string"},"created_at":{"type":"string"},"deployment_id":{"type":"integer","format":"int32"},"environment_id":{"type":"integer","format":"int32"},"environment_name":{"type":"string"},"image_name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"project_name":{"type":"string"},"status":{"type":"string"}}},"NodeCostInfo":{"type":"object","description":"One cluster node with capacity and (when priceable) a cost estimate","required":["name","cpu_millis","memory_mb"],"properties":{"cpu_millis":{"type":"integer","format":"int64","description":"CPU capacity in millicores"},"instance_type":{"type":["string","null"],"description":"Instance type from `node.kubernetes.io/instance-type` (e.g. \"m5.xlarge\")"},"memory_mb":{"type":"integer","format":"int64","description":"Memory capacity in MB"},"monthly_usd":{"type":["number","null"],"format":"double","description":"Estimated on-demand monthly price in USD. `None` when the instance\ntype is unknown or not in the price table."},"name":{"type":"string","description":"Node name"},"region":{"type":["string","null"],"description":"Region from `topology.kubernetes.io/region`"}}},"NodeInfoResponse":{"type":"object","required":["id","name","address","private_address","role","status","labels","capacity","created_at"],"properties":{"address":{"type":"string"},"architecture":{"type":["string","null"],"description":"Container platform this node runs (`linux/amd64`, `linux/arm64`).\n`None` until an agent that reports it has heartbeated."},"capacity":{"description":"Resource capacity/usage metrics from the latest heartbeat"},"created_at":{"type":"string"},"id":{"type":"integer","format":"int32"},"labels":{},"last_heartbeat":{"type":["string","null"]},"name":{"type":"string"},"private_address":{"type":"string"},"role":{"type":"string"},"status":{"type":"string"}}},"NodeListResponse":{"type":"object","required":["nodes","total"],"properties":{"nodes":{"type":"array","items":{"$ref":"#/components/schemas/NodeInfoResponse"}},"total":{"type":"integer","minimum":0}}},"NotificationPreferencesResponse":{"type":"object","required":["email_enabled","slack_enabled","batch_similar_notifications","minimum_severity","deployment_failures_enabled","build_errors_enabled","runtime_errors_enabled","error_threshold","error_time_window","ssl_expiration_enabled","ssl_days_before_expiration","domain_expiration_enabled","dns_changes_enabled","backup_failures_enabled","backup_successes_enabled","s3_connection_issues_enabled","retention_policy_violations_enabled","route_downtime_enabled","load_balancer_issues_enabled","weekly_digest_enabled","digest_send_day","digest_send_time","digest_sections"],"properties":{"backup_failures_enabled":{"type":"boolean"},"backup_successes_enabled":{"type":"boolean"},"batch_similar_notifications":{"type":"boolean"},"build_errors_enabled":{"type":"boolean"},"deployment_failures_enabled":{"type":"boolean"},"digest_sections":{"$ref":"#/components/schemas/DigestSections"},"digest_send_day":{"type":"string"},"digest_send_time":{"type":"string"},"dns_changes_enabled":{"type":"boolean"},"domain_expiration_enabled":{"type":"boolean"},"email_enabled":{"type":"boolean"},"error_threshold":{"type":"integer","format":"int32"},"error_time_window":{"type":"integer","format":"int32"},"load_balancer_issues_enabled":{"type":"boolean"},"minimum_severity":{"type":"string"},"retention_policy_violations_enabled":{"type":"boolean"},"route_downtime_enabled":{"type":"boolean"},"runtime_errors_enabled":{"type":"boolean"},"s3_connection_issues_enabled":{"type":"boolean"},"slack_enabled":{"type":"boolean"},"ssl_days_before_expiration":{"type":"integer","format":"int32"},"ssl_expiration_enabled":{"type":"boolean"},"weekly_digest_enabled":{"type":"boolean"}}},"NotificationProviderResponse":{"type":"object","required":["id","name","provider_type","config","enabled","created_at","updated_at"],"properties":{"config":{},"created_at":{"type":"integer","format":"int64"},"enabled":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"provider_type":{"type":"string"},"updated_at":{"type":"integer","format":"int64"}}},"ObservabilityCompressionSettings":{"type":"object","description":"TimescaleDB compression policy configuration for append-only observability\ntables. Values are expressed in hours so operators can choose sub-day\nwindows while keeping the API representation unambiguous.","properties":{"otel_spans_after_hours":{"type":"integer","format":"int32","description":"Compress OpenTelemetry span chunks after this many hours. Defaults to\n24 hours.","default":24,"example":24,"maximum":2160,"minimum":1},"proxy_logs_after_hours":{"type":"integer","format":"int32","description":"Compress proxy-log chunks after this many hours. Defaults to 24 hours.","default":24,"example":24,"maximum":720,"minimum":1}}},"ObservabilityEvent":{"oneOf":[{"allOf":[{"$ref":"#/components/schemas/RequestRow"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["request"]}}}]},{"allOf":[{"$ref":"#/components/schemas/SpanRow"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["span"]}}}]},{"allOf":[{"$ref":"#/components/schemas/ErrorRow"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["error"]}}}]},{"allOf":[{"$ref":"#/components/schemas/RevenueRow"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["revenue"]}}}]}],"description":"Discriminated union of every row that can appear in the Observe list.\n\nSerializes to `{ \"type\": \"request\" | \"span\" | ... , ...rest }` so the UI\ncan switch on `event.type` without ambiguity.\n\n**No `Log` variant**: runtime stdout/stderr lines live on a dedicated\nLogs page rather than Observe. Logs are too high-volume to interleave\nwith business signals (requests, errors, revenue) without dominating\nthe timeline, and they have their own retention/storage constraints\n(TimescaleDB hypertable + chunked file/S3 store) that don't compose\nwith the merge service's per-kind LIMIT strategy."},"ObservabilityRetentionSettings":{"type":"object","description":"Retention policy configuration for raw observability tables. Values are in\ndays. The Settings API applies them to TimescaleDB; ClickHouse-backed proxy\nlogs and spans retain their storage-level per-row TTL behavior.","properties":{"otel_logs_days":{"type":"integer","format":"int32","description":"Retain OpenTelemetry log events for this many days.","default":90,"example":90,"maximum":3650,"minimum":1},"otel_metrics_days":{"type":"integer","format":"int32","description":"Retain OpenTelemetry metric points for this many days.","default":90,"example":90,"maximum":3650,"minimum":1},"otel_spans_days":{"type":"integer","format":"int32","description":"Retain OpenTelemetry spans (traces) for this many days.","default":90,"example":90,"maximum":3650,"minimum":1},"proxy_logs_days":{"type":"integer","format":"int32","description":"Retain proxy request logs for this many days.","default":30,"example":30,"maximum":3650,"minimum":1}}},"OidcProviderResponse":{"type":"object","required":["id","name","issuer_url","client_id","client_secret","scopes","jit_provisioning","enabled","template","group_claim","role_claim","default_role","trust_idp_email"],"properties":{"client_id":{"type":"string"},"client_secret":{"type":"string","description":"Always masked — the secret is never returned after creation."},"default_role":{"type":"string"},"enabled":{"type":"boolean"},"group_claim":{"type":"string"},"id":{"type":"integer","format":"int32"},"issuer_url":{"type":"string"},"jit_provisioning":{"type":"boolean"},"name":{"type":"string"},"role_claim":{"type":"string"},"scopes":{"type":"string"},"template":{"type":"string"},"trust_idp_email":{"type":"boolean","description":"When true, the resolver skips the `email_verified` claim gate\nduring SSO login. Only safe for IdPs where an admin controls\nuser provisioning — see `oidc_providers::Model::trust_idp_email`."}}},"OidcProviderSummary":{"type":"object","required":["slug","name","template"],"properties":{"name":{"type":"string"},"slug":{"type":"string","description":"Stable opaque slug — use this as the path parameter when initiating\nOIDC login (`/auth/oidc/login/{slug}`). The integer database ID is\nintentionally omitted from this public endpoint to prevent provider\nenumeration."},"template":{"type":"string","description":"The template the provider was created from — e.g. `keycloak`,\n`okta`, `auth0`, `google`, `azure-ad`, or `generic`. Surfaced on\nthe public login endpoint so the unauthenticated login page can\nrender the right brand logo on the \"Sign in with X\" button.\nNever sensitive — the template name is part of the provider's\npublic identity, not configuration."}}},"OidcProviderUserResponse":{"type":"object","description":"A user that has logged in via a given OIDC provider. Used by the\nadmin \"Users for provider\" panel — the `oidc_subject` is the\nIdP-side identifier we matched on, useful when diagnosing why a\nuser can or can't log in.","required":["id","name","email","email_verified","mfa_enabled","created_at","updated_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2024-01-15T14:30:00Z"},"email":{"type":"string"},"email_verified":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"mfa_enabled":{"type":"boolean"},"name":{"type":"string"},"oidc_subject":{"type":["string","null"]},"updated_at":{"type":"string","format":"date-time","example":"2024-01-15T14:30:00Z"}}},"OidcProvidersListResponse":{"type":"object","required":["providers"],"properties":{"providers":{"type":"array","items":{"$ref":"#/components/schemas/OidcProviderSummary"}}}},"OidcRoleMappingResponse":{"type":"object","required":["id","provider_id","priority","idp_group","role"],"properties":{"id":{"type":"integer","format":"int32"},"idp_group":{"type":"string"},"priority":{"type":"integer","format":"int32"},"provider_id":{"type":"integer","format":"int32"},"role":{"type":"string"}}},"OidcTestConnectionResponse":{"type":"object","required":["success","message"],"properties":{"message":{"type":"string"},"success":{"type":"boolean"}}},"OnDemandCertAttemptResponse":{"type":"object","description":"A single on-demand HTTP-01 issuance attempt from the append-only\n`on_demand_cert_attempts` audit log. Carries the full forensic detail for one\nattempt; the current cert state lives on the enclosing row's domain fields.\n\nContains no private-key or certificate material — only audit metadata — so it\nis safe to return without masking.","required":["id","hostname","trigger","outcome","created_at"],"properties":{"acme_request_sent":{"type":["boolean","null"],"description":"Did we reach the Let's Encrypt API?"},"acme_response_status":{"type":["string","null"],"description":"HTTP status or ACME error type returned by Let's Encrypt, when known."},"challenge_served":{"type":["boolean","null"],"description":"Did the proxy serve the `/.well-known/acme-challenge/` request?"},"created_at":{"type":"integer","format":"int64","description":"When the attempt was recorded (epoch millis)."},"duration_ms":{"type":["integer","null"],"format":"int32","description":"End-to-end issuance duration in milliseconds (0/None for skipped)."},"error_category":{"type":["string","null"],"description":"Coarse error category for UI labelling: `\"rate_limited\"`, `\"dns_failure\"`,\n`\"acme_order_expired\"`, `\"challenge_mismatch\"`, `\"timeout\"`, `\"internal\"`."},"error_chain":{"type":["string","null"],"description":"Full `Display` chain of the error (all `source()` levels), when failed."},"hostname":{"type":"string","description":"SNI hostname that triggered the attempt."},"id":{"type":"integer","format":"int32"},"outcome":{"type":"string","description":"Final outcome: `\"issued\"`, `\"failed\"`, `\"skipped_duplicate\"`,\n`\"skipped_gate\"`, `\"skipped_rate_limit\"`, or `\"skipped_no_route\"`."},"trigger":{"type":"string","description":"What triggered the attempt (always `\"tls_callback\"` today)."}}},"OnDemandCertRow":{"type":"object","description":"One row of the on-demand certificates list: the most-recent attempt for a\nhostname plus the current authoritative cert state from its `domains` row.","required":["hostname","attempt"],"properties":{"attempt":{"$ref":"#/components/schemas/OnDemandCertAttemptResponse","description":"The audit record for the attempt this row represents (newest first in\nthe list)."},"backoff_until":{"type":["integer","null"],"format":"int64","description":"On-demand negative-cache deadline (epoch millis), when in backoff."},"expiration_time":{"type":["integer","null"],"format":"int64","description":"Certificate expiration (epoch millis), when an active cert exists."},"hostname":{"type":"string","description":"SNI hostname."},"status":{"type":["string","null"],"description":"Current cert lifecycle status from the `domains` row, when one exists:\n`on_demand_pending`, `on_demand_issuing`, `active`, `on_demand_failed`,\netc. `None` when no `domains` row exists yet for this hostname."}}},"OnDemandTlsSettings":{"type":"object","description":"On-demand (lazy) HTTP-01 TLS issuance settings (ADR-018).\n\nWhen `enabled`, the proxy's `certificate_callback` triggers ACME HTTP-01\nissuance for allowlisted, STABLE hostnames (per-environment aliases and the\nconsole host) that have no active cert, rather than silently failing the\nhandshake. Ephemeral per-deployment hostnames are NEVER certed (ADR §2).\n\nOff by default — operators opt in explicitly, except QuickStart (`sslip.io`)\ninstalls where `temps setup` auto-enables it and derives `zone`.","properties":{"deployment_url_mode":{"type":"string","description":"How ephemeral per-deployment hostnames behave when they have no cert\n(they are NEVER certed — see ADR §2). One of:\n - `\"http\"` (default): serve plain HTTP on :80.\n - `\"redirect_to_env\"`: 308-redirect to the stable per-environment URL,\n which IS certed.","default":"http","example":"http"},"enabled":{"type":"boolean","description":"Master switch. When `false` (default) the proxy's on-demand cert gate\nrejects every SNI and no issuance is ever triggered.","default":false,"example":false},"hourly_cap":{"type":"integer","format":"int32","description":"Global cap on total on-demand issuances per hour across all hostnames\n(ADR §4 Layer 3). The operator's self-imposed safety net, separate from\nthe Let's Encrypt rate limit.","default":10,"example":10,"minimum":1},"max_concurrent":{"type":"integer","format":"int32","description":"Maximum number of ACME issuance flows allowed to run simultaneously\n(the concurrent-issuance semaphore, ADR §4 Layer 1). Min 1.","default":3,"example":3,"minimum":1},"zone":{"type":["string","null"],"description":"Zone suffix for the allowlist gate. A hostname passes the gate only if\nit is a direct subdomain of this zone (e.g. zone `1.2.3.4.sslip.io`\nadmits `myapp.1.2.3.4.sslip.io` but not `deep.sub.1.2.3.4.sslip.io`).\n`None` (default) means \"auto-derive from `external_url`\"; if no zone can\nbe derived the gate rejects all SNI, disabling the feature.","default":null,"example":"1.2.3.4.sslip.io"}}},"OpenAiError":{"type":"object","required":["message","type"],"properties":{"code":{"type":["string","null"]},"message":{"type":"string"},"type":{"type":"string"}}},"OpenAiErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"$ref":"#/components/schemas/OpenAiError"}}},"OperatingSystemCount":{"type":"object","required":["operating_system","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"operating_system":{"type":"string"},"percentage":{"type":"number","format":"double"}}},"OperationResultResponse":{"type":"object","required":["operation","success","message","executed_at"],"properties":{"data":{},"executed_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"message":{"type":"string"},"operation":{"type":"string"},"success":{"type":"boolean"}}},"OperationResultsResponse":{"type":"object","required":["deployment_id","operations"],"properties":{"deployment_id":{"type":"string"},"operations":{"type":"array","items":{"$ref":"#/components/schemas/OperationResultResponse"}}}},"OtelDashboardResponse":{"type":"object","required":["id","project_id","name","layout","created_at","updated_at"],"properties":{"created_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"id":{"type":"integer","format":"int32"},"layout":{"$ref":"#/components/schemas/DashboardLayout"},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"updated_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"}}},"OtelDashboardsResponse":{"type":"object","required":["data","total"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/OtelDashboardResponse"}},"total":{"type":"integer","format":"int64","minimum":0}}},"OtelMetricAlertRuleResponse":{"type":"object","required":["id","project_id","name","metric_name","aggregation","detection_kind","detection_config","window_secs","for_duration_secs","severity","enabled","last_state","label_filters","group_by","dynamic_alerts","max_series","grouped_notification_threshold","last_dropped_series_count","series_states","created_at","updated_at"],"properties":{"aggregation":{"type":"string"},"created_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"detection_config":{"$ref":"#/components/schemas/DetectionConfig","description":"The typed detector definition (discriminated union keyed by `kind`)."},"detection_kind":{"type":"string","description":"Coarse detector discriminator: `static|anomaly|forecast|outlier|auto_watch`."},"dynamic_alerts":{"type":"boolean","description":"Whether per-series (\"dynamic\") alerting is enabled for this rule."},"enabled":{"type":"boolean"},"firing_series":{"type":"array","items":{"$ref":"#/components/schemas/FiringSeriesEntry"},"description":"Currently-firing series for a dynamic rule, snapshotted from the evaluator's\nin-memory firing map at read time. Empty for static/aggregate rules or when\nnothing is firing."},"for_duration_secs":{"type":"integer","format":"int32"},"group_by":{"type":"array","items":{"type":"string"},"description":"Label keys the rule breaks the metric down by. Empty = one aggregate stream."},"grouped_notification_threshold":{"type":"integer","format":"int32","description":"Notification-grouping threshold: when more than this many series fire in the\nsame tick, only the first gets chart/AI enrichment (1–1000)."},"id":{"type":"integer","format":"int32"},"label_filters":{"type":"array","items":{"type":"array","items":false,"prefixItems":[{"type":"string"},{"type":"string"}]},"description":"AND-combined label equality filters applied when evaluating this rule.\nEmpty = no filtering (matches all series)."},"last_dropped_series_count":{"type":"integer","format":"int32","description":"Number of series dropped by the cardinality cap on the latest dynamic tick\n(0 when nothing was dropped or for static/aggregate rules). Lets a UI warn\n\"N series were dropped this tick\" without reading server logs."},"last_evaluated_at":{"type":["string","null"],"example":"2025-10-12T12:15:47.609192Z"},"last_state":{"type":"string","description":"One of `ok|firing|unknown`."},"last_value":{"type":["number","null"],"format":"double"},"max_series":{"type":"integer","format":"int32","description":"Cardinality cap for dynamic alerting (1–100)."},"metric_name":{"type":"string"},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"series_states":{"type":"object","description":"Full per-series state snapshot persisted after the latest dynamic-rule tick,\nkeyed by the human-readable series label (`endpoint=/checkout`). Empty for\nstatic/aggregate rules. Unlike `firing_series` (a live in-memory snapshot),\nthis is decoded from the persisted `series_states` jsonb column, so an\nexternal consumer that only reads the rule row still sees per-series detail.","additionalProperties":{"$ref":"#/components/schemas/SeriesStateEntry"},"propertyNames":{"type":"string"}},"severity":{"type":"string"},"updated_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"window_secs":{"type":"integer","format":"int32"}}},"OtelMetricAlertsResponse":{"type":"object","required":["data","total"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/OtelMetricAlertRuleResponse"}},"total":{"type":"integer","format":"int64","minimum":0}}},"OtelMetricLabelKeysResponse":{"type":"object","required":["keys"],"properties":{"keys":{"type":"array","items":{"type":"string"}}}},"OtelMetricLabelValuesResponse":{"type":"object","required":["values"],"properties":{"values":{"type":"array","items":{"type":"string"}}}},"OtelMetricNamesResponse":{"type":"object","required":["names"],"properties":{"names":{"type":"array","items":{"type":"string"}}}},"OtelMetricsResponse":{"type":"object","required":["data","count"],"properties":{"count":{"type":"integer","minimum":0},"data":{"type":"array","items":{"$ref":"#/components/schemas/MetricBucket"}}}},"OutlierAlgorithm":{"type":"string","description":"Outlier detection algorithm.","enum":["dbscan","scaled_dbscan","mad","scaled_mad"]},"OutlierParams":{"type":"object","description":"Outlier (cross-series population) detector parameters (stub — not evaluated).","required":["peer_group_key"],"properties":{"algorithm":{"$ref":"#/components/schemas/OutlierAlgorithm"},"peer_group_key":{"type":"string","description":"Label key defining the peer population compared across series (e.g. `host`)."},"tolerance":{"type":"number","format":"double","description":"Sensitivity; higher tolerates larger spread before flagging."}}},"OverprovisioningAssessment":{"type":"object","description":"Requests-vs-capacity-vs-usage assessment","required":["verdict","explanation"],"properties":{"cpu_request_inflation_ratio":{"type":["number","null"],"format":"double","description":"Ratio of requested CPU to measured CPU usage (e.g. 40.0 = requests\nreserve 40× what the workloads actually use). `None` without metrics."},"cpu_requested_pct":{"type":["number","null"],"format":"double","description":"Requested CPU as % of cluster capacity"},"cpu_utilization_pct":{"type":["number","null"],"format":"double","description":"Measured CPU usage as % of cluster capacity (`None` without metrics)"},"explanation":{"type":"string","description":"Human-readable explanation of the verdict, e.g. \"Cluster capacity is\n8 vCPU but measured usage is 0.3 vCPU (3.7%) — severely overprovisioned\""},"memory_request_inflation_ratio":{"type":["number","null"],"format":"double","description":"Ratio of requested memory to measured memory usage"},"memory_requested_pct":{"type":["number","null"],"format":"double","description":"Requested memory as % of cluster capacity"},"memory_utilization_pct":{"type":["number","null"],"format":"double","description":"Measured memory usage as % of cluster capacity (`None` without metrics)"},"verdict":{"$ref":"#/components/schemas/OverprovisioningVerdict","description":"Overall verdict"}}},"OverprovisioningVerdict":{"type":"string","description":"Overall overprovisioning verdict","enum":["severe","moderate","reasonable","unknown"]},"PageActivityBucket":{"type":"object","description":"Time bucket data point for page activity graph","required":["timestamp","visitors","page_views","avg_time_seconds"],"properties":{"avg_time_seconds":{"type":"number","format":"double","description":"Average time on page in seconds"},"page_views":{"type":"integer","format":"int64","description":"Number of page views in this bucket"},"timestamp":{"type":"string","description":"Timestamp for this bucket (ISO 8601)"},"visitors":{"type":"integer","format":"int64","description":"Number of unique visitors in this bucket"}}},"PageCountryStats":{"type":"object","description":"Geographic distribution of visitors for a page","required":["country","visitors","page_views","percentage"],"properties":{"country":{"type":"string","description":"Country name"},"country_code":{"type":["string","null"],"description":"ISO country code (2-letter)"},"page_views":{"type":"integer","format":"int64","description":"Number of page views from this country"},"percentage":{"type":"number","format":"double","description":"Percentage of total visitors"},"visitors":{"type":"integer","format":"int64","description":"Number of unique visitors from this country"}}},"PageFlowEntry":{"type":"object","description":"A single page with its entry/exit/bounce statistics","required":["page_path","entry_count","exit_count","bounce_count","total_views","entry_rate","exit_rate","bounce_rate"],"properties":{"avg_time_on_page":{"type":["number","null"],"format":"double","description":"Average time spent on this page in seconds"},"bounce_count":{"type":"integer","format":"int64","description":"Number of times visitors bounced on this page"},"bounce_rate":{"type":"number","format":"double","description":"Bounce rate: bounce_count / entry_count (only meaningful for entry pages)"},"entry_count":{"type":"integer","format":"int64","description":"Number of times this page was the entry page of a session"},"entry_rate":{"type":"number","format":"double","description":"Entry rate: entry_count / total_views"},"exit_count":{"type":"integer","format":"int64","description":"Number of times this page was the exit page of a session"},"exit_rate":{"type":"number","format":"double","description":"Exit rate: exit_count / total_views"},"page_path":{"type":"string","description":"The page path (e.g. \"/pricing\", \"/docs/getting-started\")"},"total_views":{"type":"integer","format":"int64","description":"Total page views for this page"}}},"PageFlowQuery":{"type":"object","description":"Query parameters for page flow analytics","required":["project_id","start_date","end_date"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32","description":"Maximum number of entry/exit pages to return (default: 20)"},"min_views_for_dropoff":{"type":["integer","null"],"format":"int32","description":"Minimum views for drop-off analysis (default: 5)"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"},"transitions_limit":{"type":["integer","null"],"format":"int32","description":"Maximum number of transitions to return (default: 50)"}}},"PageFlowResponse":{"type":"object","description":"Complete page flow analytics response","required":["top_entry_pages","top_exit_pages","drop_off_points","transitions","total_pages","total_sessions"],"properties":{"drop_off_points":{"type":"array","items":{"$ref":"#/components/schemas/DropOffPoint"},"description":"Top drop-off points (highest exit rates with meaningful traffic)"},"top_entry_pages":{"type":"array","items":{"$ref":"#/components/schemas/PageFlowEntry"},"description":"Top entry pages (where visitors land), sorted by entry_count DESC"},"top_exit_pages":{"type":"array","items":{"$ref":"#/components/schemas/PageFlowEntry"},"description":"Top exit pages (where visitors leave), sorted by exit_count DESC"},"total_pages":{"type":"integer","format":"int64","description":"Total unique pages seen in the period"},"total_sessions":{"type":"integer","format":"int64","description":"Total sessions in the period"},"transitions":{"type":"array","items":{"$ref":"#/components/schemas/PageTransition"},"description":"Page-to-page transitions (most common navigation paths)"}}},"PageHourlySessionsQuery":{"type":"object","description":"Query parameters for page hourly sessions endpoint","required":["page_path","project_id","start_time","end_time"],"properties":{"bucket_interval":{"type":["string","null"]},"end_time":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"page_path":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"start_time":{"type":"string","format":"date-time"}}},"PageHourlySessionsResponse":{"type":"object","required":["page_path","hourly_data","total_sessions","hours"],"properties":{"hourly_data":{"type":"array","items":{"$ref":"#/components/schemas/HourlyPageSessions"}},"hours":{"type":"integer","format":"int32"},"page_path":{"type":"string"},"total_sessions":{"type":"integer","format":"int64"}}},"PagePathDetailQuery":{"type":"object","description":"Query parameters for page path detail analytics","required":["page_path","project_id","start_date","end_date"],"properties":{"bucket_interval":{"type":["string","null"],"description":"Bucket interval for time series: 'hour', 'day', 'week', 'month' (default: auto)"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"page_path":{"type":"string","description":"The specific page path to get details for (URL-encoded)"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"PagePathDetailResponse":{"type":"object","description":"Detailed analytics response for a specific page path","required":["page_path","unique_visitors","total_page_views","avg_time_on_page","bounce_rate","entry_rate","exit_rate","activity_over_time","countries","referrers","bucket_interval"],"properties":{"activity_over_time":{"type":"array","items":{"$ref":"#/components/schemas/PageActivityBucket"},"description":"Time series data for activity graph"},"avg_time_on_page":{"type":"number","format":"double","description":"Average time on page in seconds"},"bounce_rate":{"type":"number","format":"double","description":"Bounce rate percentage (0-100)"},"bucket_interval":{"type":"string","description":"Bucket interval used for time series ('hour', 'day', etc.)"},"countries":{"type":"array","items":{"$ref":"#/components/schemas/PageCountryStats"},"description":"Geographic distribution of visitors"},"entry_rate":{"type":"number","format":"double","description":"Entry rate - percentage of sessions that started on this page"},"exit_rate":{"type":"number","format":"double","description":"Exit rate - percentage of sessions that ended on this page"},"page_path":{"type":"string","description":"The page path being analyzed"},"referrers":{"type":"array","items":{"$ref":"#/components/schemas/PageReferrerStats"},"description":"Top referrers to this page"},"total_page_views":{"type":"integer","format":"int64","description":"Total page views in the date range"},"unique_visitors":{"type":"integer","format":"int64","description":"Total unique visitors to this page in the date range"}}},"PagePathInfo":{"type":"object","required":["page_path","session_count","page_view_count","first_seen","last_seen"],"properties":{"avg_time_seconds":{"type":["number","null"],"format":"double"},"first_seen":{"type":"string"},"last_seen":{"type":"string"},"page_path":{"type":"string"},"page_view_count":{"type":"integer","format":"int64"},"session_count":{"type":"integer","format":"int64"}}},"PagePathSparkline":{"type":"object","required":["page_path","points"],"properties":{"page_path":{"type":"string"},"points":{"type":"array","items":{"$ref":"#/components/schemas/PagePathSparklinePoint"}}}},"PagePathSparklinePoint":{"type":"object","required":["timestamp","session_count"],"properties":{"session_count":{"type":"integer","format":"int64"},"timestamp":{"type":"string"}}},"PagePathVisitorsQuery":{"type":"object","description":"Query parameters for page path visitors","required":["page_path","project_id","start_date","end_date"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"page":{"type":["integer","null"],"format":"int64","description":"Page number (1-based, default: 1)","minimum":0},"page_path":{"type":"string","description":"The specific page path to get visitors for"},"per_page":{"type":["integer","null"],"format":"int64","description":"Items per page (default: 50, max: 100)","minimum":0},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"PagePathVisitorsResponse":{"type":"object","description":"Response for page path visitors endpoint","required":["page_path","total_count","page","per_page","sessions"],"properties":{"page":{"type":"integer","format":"int64","description":"Current page number","minimum":0},"page_path":{"type":"string","description":"The page path"},"per_page":{"type":"integer","format":"int64","description":"Items per page","minimum":0},"sessions":{"type":"array","items":{"$ref":"#/components/schemas/PageVisitorSession"},"description":"Individual visitor sessions"},"total_count":{"type":"integer","format":"int64","description":"Total number of visitor sessions matching the query"}}},"PagePathsQuery":{"type":"object","required":["project_id"],"properties":{"end_date":{"type":["string","null"],"format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":["string","null"],"format":"date-time"}}},"PagePathsResponse":{"type":"object","required":["page_paths","total_count"],"properties":{"page_paths":{"type":"array","items":{"$ref":"#/components/schemas/PagePathInfo"}},"total_count":{"type":"integer","minimum":0}}},"PagePathsSparklineQuery":{"type":"object","description":"Query parameters for batch page paths sparkline endpoint","required":["project_id","start_time","end_time","page_paths"],"properties":{"end_time":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"page_paths":{"type":"string","description":"Comma-separated list of page paths"},"project_id":{"type":"integer","format":"int32"},"start_time":{"type":"string","format":"date-time"}}},"PagePathsSparklineResponse":{"type":"object","required":["sparklines"],"properties":{"sparklines":{"type":"array","items":{"$ref":"#/components/schemas/PagePathSparkline"}}}},"PageReferrerStats":{"type":"object","description":"Referrer source for the page","required":["referrer","visits","percentage"],"properties":{"percentage":{"type":"number","format":"double","description":"Percentage of total visits"},"referrer":{"type":"string","description":"Referrer URL or domain"},"visits":{"type":"integer","format":"int64","description":"Number of visits from this referrer"}}},"PageSessionComparison":{"type":"object","required":["page_path","date","session_count","event_count","avg_duration_seconds"],"properties":{"avg_duration_seconds":{"type":"number","format":"double"},"date":{"type":"string"},"event_count":{"type":"integer","format":"int64"},"page_path":{"type":"string"},"session_count":{"type":"integer","format":"int64"}}},"PageSessionStats":{"type":"object","required":["page_path","total_sessions","avg_time_seconds","min_time_seconds","max_time_seconds","total_page_views","avg_page_views_per_session"],"properties":{"avg_page_views_per_session":{"type":"number","format":"double"},"avg_time_seconds":{"type":"number","format":"double"},"max_time_seconds":{"type":"number","format":"double"},"min_time_seconds":{"type":"number","format":"double"},"page_path":{"type":"string"},"total_page_views":{"type":"integer","format":"int64"},"total_sessions":{"type":"integer","format":"int64"}}},"PageSessionStatsQuery":{"type":"object","required":["page_path","project_id","start_date","end_date"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"page_path":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"PageTransition":{"type":"object","description":"A page-to-page transition with count","required":["from_page","to_page","transition_count","percentage"],"properties":{"from_page":{"type":"string","description":"The source page path"},"percentage":{"type":"number","format":"double","description":"Percentage of transitions from the source page that go to this destination"},"to_page":{"type":"string","description":"The destination page path"},"transition_count":{"type":"integer","format":"int64","description":"Number of times this transition occurred"}}},"PageVisit":{"type":"object","required":["path","visits"],"properties":{"path":{"type":"string"},"visits":{"type":"integer","format":"int64"}}},"PageVisitorSession":{"type":"object","description":"Individual visitor session that viewed a specific page","required":["visitor_id","visitor_uuid","viewed_at","is_entry","is_exit","is_bounce"],"properties":{"browser":{"type":["string","null"],"description":"Browser name"},"city":{"type":["string","null"],"description":"Visitor's city"},"country":{"type":["string","null"],"description":"Visitor's country"},"country_code":{"type":["string","null"],"description":"Visitor's country code"},"device_type":{"type":["string","null"],"description":"Device type (Desktop, Mobile, Tablet)"},"is_bounce":{"type":"boolean","description":"Whether this was a bounce"},"is_entry":{"type":"boolean","description":"Whether this was the entry page for the session"},"is_exit":{"type":"boolean","description":"Whether this was the exit page for the session"},"operating_system":{"type":["string","null"],"description":"Operating system"},"referrer":{"type":["string","null"],"description":"Referrer URL"},"session_id":{"type":["string","null"],"description":"Session ID"},"session_page_number":{"type":["integer","null"],"format":"int32","description":"Page number in session flow"},"time_on_page":{"type":["integer","null"],"format":"int32","description":"Time spent on this page in seconds"},"viewed_at":{"type":"string","format":"date-time","description":"When the page was viewed"},"visitor_id":{"type":"integer","format":"int32","description":"Visitor numeric ID"},"visitor_uuid":{"type":"string","description":"Visitor UUID"}}},"PagesComparisonResponse":{"type":"object","required":["comparisons","page_paths"],"properties":{"comparisons":{"type":"array","items":{"$ref":"#/components/schemas/PageSessionComparison"}},"page_paths":{"type":"array","items":{"type":"string"}}}},"PaginatedEmailsResponse":{"type":"object","required":["data","total","page","page_size"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/EmailResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"PaginatedEntitiesResponse":{"type":"object","required":["entities","count","limit","has_more"],"properties":{"count":{"type":"integer","description":"Number of entities returned","minimum":0},"entities":{"type":"array","items":{"$ref":"#/components/schemas/EntityResponse"},"description":"List of entities"},"has_more":{"type":"boolean","description":"Whether there are more entities available"},"limit":{"type":"integer","description":"Limit used for this request","minimum":0},"next_token":{"type":["string","null"],"description":"Continuation token for next page (S3, etc.)"},"total":{"type":["integer","null"],"description":"Total number of entities (if available)","minimum":0}}},"PaginatedErrorEventsResponse":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ErrorEventResponse"}},"pagination":{"$ref":"#/components/schemas/PaginationMeta"}}},"PaginatedErrorGroupsResponse":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ErrorGroupResponse"}},"pagination":{"$ref":"#/components/schemas/PaginationMeta"}}},"PaginatedEventsResponse":{"type":"object","required":["events","total","page","page_size"],"properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/TrackingEventResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"PaginatedExternalImagesResponse":{"type":"object","required":["data","total","page","page_size"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ExternalImageResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"PaginatedProjectList":{"type":"object","required":["projects","total","page","per_page"],"properties":{"page":{"type":"integer","format":"int64"},"per_page":{"type":"integer","format":"int64"},"projects":{"type":"array","items":{"$ref":"#/components/schemas/ProjectResponse"}},"total":{"type":"integer","format":"int64"}}},"PaginatedStaticBundlesResponse":{"type":"object","required":["data","total","page","page_size"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/StaticBundleResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0}}},"Pagination":{"type":"object","description":"SDK pagination cursor. We use opaque page numbers internally but\nexpose `count`/`next`/`prev` the way `@vercel/sandbox` expects.","required":["count"],"properties":{"count":{"type":"integer","format":"int64","minimum":0},"next":{"type":["integer","null"],"format":"int64","minimum":0},"prev":{"type":["integer","null"],"format":"int64","minimum":0}}},"PaginationMeta":{"type":"object","required":["page","page_size","total_count","total_pages"],"properties":{"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total_count":{"type":"integer","format":"int64","minimum":0},"total_pages":{"type":"integer","format":"int64","minimum":0}}},"PaginationParams":{"type":"object","properties":{"page":{"type":"integer","format":"int64"},"per_page":{"type":"integer","format":"int64"}}},"PasswordProtectionConfig":{"type":"object","description":"Password protection configuration\n\nWhen enabled, the proxy shows an HTML password form before allowing access.\nAfter the user enters the correct password, an HMAC-signed cookie is set\nso subsequent requests pass through without re-entering the password.","required":["enabled","passwordHash"],"properties":{"enabled":{"type":"boolean","description":"Whether password protection is enabled"},"passwordHash":{"type":"string","description":"The bcrypt-hashed password (never stored or returned in plaintext)"}}},"PatchSettingsRequest":{"type":"object","properties":{"auto_upgrade":{"type":["boolean","null"]},"host_port":{"type":["integer","null"],"format":"int32","minimum":0},"image":{"type":["string","null"]}}},"PathVisitors":{"type":"object","required":["name","visitors","percentage"],"properties":{"name":{"type":"string"},"percentage":{"type":"number","format":"double"},"visitors":{"type":"integer","format":"int64"}}},"PathVisitorsAnalyticsQuery":{"type":"object","required":["start_date","end_date","project_id"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"PathVisitorsResponse":{"type":"object","required":["results"],"properties":{"results":{"type":"array","items":{"$ref":"#/components/schemas/PathVisitors"}}}},"PeerEntry":{"type":"object","description":"Wire-format peer entry. Matches `temps_network::config::Peer` but\nuses strings on the wire to keep the API stable across underlying\ntype evolution.","required":["node_id","compute_cidr","underlay_address"],"properties":{"compute_cidr":{"type":"string","description":"Per-node CIDR (e.g. `\"172.20.5.0/24\"`)."},"node_id":{"type":"string","description":"Stable v5 UUID derived from the database node id. Workers use\nthis as the kernel-layer identifier when calling\n`NetworkManager::reconcile_peers`."},"underlay_address":{"type":"string","description":"Address the local node should use to reach this peer over the\nunderlay (private VPC IP for same-DC, public IP for cross-DC)."}}},"PeerListResponse":{"type":"object","description":"Response body for `GET /internal/nodes/{node_id}/network/peers`.","required":["peers","cluster_dns_enabled"],"properties":{"alloc":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/AllocEntry","description":"Caller's own allocation, or `null` if multi-host networking has\nnot been enabled for this node yet."}]},"cluster_dns_enabled":{"type":"boolean","description":"Whether the cluster-DNS resolver is enabled on this control plane\n(`AppSettings.cluster_dns.enabled`). Workers should start their\nper-node resolver and write `overlay_bridge_address` only when this\nis `true`. Always serialized (never `skip_serializing_if`) so older\nand newer version skew degrades to the safe default of `false`."},"peers":{"type":"array","items":{"$ref":"#/components/schemas/PeerEntry"},"description":"All other nodes with a `compute_cidr` set, excluding the caller."}}},"PendingActionResponse":{"type":"object","description":"A proposed AI write action awaiting human confirmation.","required":["public_id","operation_id","method","summary","status","step_index","params","created_at"],"properties":{"confirmed_at":{"type":["string","null"]},"created_at":{"type":"string"},"error":{"type":["string","null"]},"executed_at":{"type":["string","null"]},"method":{"type":"string"},"operation_id":{"type":"string"},"params":{"description":"The flat params to be replayed at execute time (shown pre-execution for review)."},"plan_public_id":{"type":["string","null"],"description":"Set when this action is one step of a multi-step plan (chained actions);\nall steps of the plan share this id. Absent for standalone single actions."},"public_id":{"type":"string"},"required_permission":{"type":["string","null"]},"result":{},"status":{"type":"string"},"step_index":{"type":"integer","format":"int32","description":"0-based order of this step within its plan (0 for standalone actions)."},"summary":{"type":"string"}}},"PerformanceMetricsQuery":{"allOf":[{"$ref":"#/components/schemas/SpeedSegmentFilters","description":"Segment filters (filter_path, filter_country, filter_region,\nfilter_city, filter_browser, filter_operating_system) — flattened so\neach remains a top-level query string param."},{"type":"object","required":["start_date","end_date","project_id"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"device_type":{"type":["string","null"],"description":"Device type filter: \"desktop\" or \"mobile\""},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"include_bots":{"type":["boolean","null"],"description":"Include crawler/datacenter (bot) samples. Defaults to false — bots\nare excluded from the read view but always stored at ingest."},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}}]},"PerformanceMetricsResponse":{"type":"object","properties":{"cls":{"type":["number","null"],"format":"float"},"cls_p75":{"type":["number","null"],"format":"float"},"cls_p90":{"type":["number","null"],"format":"float"},"cls_p95":{"type":["number","null"],"format":"float"},"cls_p99":{"type":["number","null"],"format":"float"},"fcp":{"type":["number","null"],"format":"float"},"fcp_p75":{"type":["number","null"],"format":"float"},"fcp_p90":{"type":["number","null"],"format":"float"},"fcp_p95":{"type":["number","null"],"format":"float"},"fcp_p99":{"type":["number","null"],"format":"float"},"fid":{"type":["number","null"],"format":"float"},"fid_p75":{"type":["number","null"],"format":"float"},"fid_p90":{"type":["number","null"],"format":"float"},"fid_p95":{"type":["number","null"],"format":"float"},"fid_p99":{"type":["number","null"],"format":"float"},"inp":{"type":["number","null"],"format":"float"},"inp_p75":{"type":["number","null"],"format":"float"},"inp_p90":{"type":["number","null"],"format":"float"},"inp_p95":{"type":["number","null"],"format":"float"},"inp_p99":{"type":["number","null"],"format":"float"},"lcp":{"type":["number","null"],"format":"float"},"lcp_p75":{"type":["number","null"],"format":"float"},"lcp_p90":{"type":["number","null"],"format":"float"},"lcp_p95":{"type":["number","null"],"format":"float"},"lcp_p99":{"type":["number","null"],"format":"float"},"ttfb":{"type":["number","null"],"format":"float"},"ttfb_p75":{"type":["number","null"],"format":"float"},"ttfb_p90":{"type":["number","null"],"format":"float"},"ttfb_p95":{"type":["number","null"],"format":"float"},"ttfb_p99":{"type":["number","null"],"format":"float"}}},"PermissionInfo":{"type":"object","description":"Information about a single permission","required":["name","description","category"],"properties":{"category":{"type":"string","description":"Category of the permission (e.g., \"Projects\", \"Deployments\")"},"description":{"type":"string","description":"Human-readable description of the permission"},"name":{"type":"string","description":"The permission identifier (e.g., \"projects:read\")"}}},"PgUpgradeLogResponse":{"type":"object","required":["log_id","content"],"properties":{"content":{"type":"string"},"log_id":{"type":"string"}}},"PgUpgradeResponse":{"type":"object","required":["id","service_id","from_version","to_version","from_image","to_image","status","phase","log_id","attempt","created_at"],"properties":{"attempt":{"type":"integer","format":"int32"},"created_at":{"type":"string"},"error_message":{"type":["string","null"]},"finished_at":{"type":["string","null"]},"from_image":{"type":"string"},"from_version":{"type":"string"},"id":{"type":"integer","format":"int32"},"log_id":{"type":"string"},"phase":{"type":"string"},"pre_upgrade_backup_id":{"type":["integer","null"],"format":"int32"},"rollback_volume_name":{"type":["string","null"]},"service_id":{"type":"integer","format":"int32"},"started_at":{"type":["string","null"]},"status":{"type":"string"},"to_image":{"type":"string"},"to_version":{"type":"string"}}},"PipelineStats":{"type":"object","description":"Internal pipeline statistics for self-observability.","required":["metrics_received","metrics_stored","metrics_dropped","spans_received","spans_stored","spans_dropped","logs_received","logs_stored_db","logs_stored_s3","logs_dropped","ingest_errors"],"properties":{"ingest_errors":{"type":"integer","format":"int64","minimum":0},"logs_dropped":{"type":"integer","format":"int64","minimum":0},"logs_received":{"type":"integer","format":"int64","minimum":0},"logs_stored_db":{"type":"integer","format":"int64","minimum":0},"logs_stored_s3":{"type":"integer","format":"int64","minimum":0},"metrics_dropped":{"type":"integer","format":"int64","minimum":0},"metrics_received":{"type":"integer","format":"int64","minimum":0},"metrics_stored":{"type":"integer","format":"int64","minimum":0},"spans_dropped":{"type":"integer","format":"int64","minimum":0},"spans_received":{"type":"integer","format":"int64","minimum":0},"spans_stored":{"type":"integer","format":"int64","minimum":0}}},"PipelineStatsResponse":{"type":"object","required":["stats"],"properties":{"stats":{"$ref":"#/components/schemas/PipelineStats"}}},"PlanComplexity":{"type":"string","description":"Plan complexity indicator","enum":["low","medium","high"]},"PlanMetadata":{"type":"object","description":"Plan metadata","required":["generated_at","generator_version","complexity","warnings"],"properties":{"complexity":{"$ref":"#/components/schemas/PlanComplexity","description":"Estimated complexity (low, medium, high)"},"generated_at":{"type":"string","format":"date-time","description":"When the plan was generated"},"generator_version":{"type":"string","description":"Generator (importer) version"},"warnings":{"type":"array","items":{"type":"string"},"description":"Warnings detected during planning"}}},"PlanSourceBackup":{"type":"object","required":["location","location_was_resolved","format"],"properties":{"created_at":{"type":["string","null"]},"format":{"type":"string","description":"\"walg\", \"pg_dump\", \"unknown\"."},"id":{"type":["integer","null"],"format":"int32","description":"DB id, absent for orphan (S3-scan) backups."},"location":{"type":"string","description":"Resolved S3 location the orchestrator will actually use."},"location_was_resolved":{"type":"boolean","description":"True when the original row's `s3_location` was empty and we resolved\na location by probing S3. The UI shows this as a warning."},"origin_service_name":{"type":["string","null"],"description":"Service that originally produced the backup, if known."},"size_bytes":{"type":["integer","null"],"format":"int64"}}},"PlanTarget":{"type":"object","required":["id","name","container"],"properties":{"container":{"type":"string","description":"Expected Docker container name."},"id":{"type":"integer","format":"int32"},"name":{"type":"string"}}},"PlatformInfo":{"type":"object","description":"Platform compatibility information","required":["os_type","architecture","platforms"],"properties":{"architecture":{"type":"string","description":"System architecture (e.g., \"x86_64\", \"aarch64\")"},"os_type":{"type":"string","description":"Operating system type (e.g., \"linux\", \"windows\", \"darwin\")"},"platforms":{"type":"array","items":{"type":"string"},"description":"List of supported platforms in \"os/arch\" format (e.g., [\"linux/amd64\"])"}}},"PluginManifest":{"type":"object","description":"The complete plugin manifest — the handshake contract.","required":["name","version"],"properties":{"description":{"type":["string","null"],"description":"Short description of what the plugin does"},"display_name":{"type":["string","null"],"description":"Human-readable display name"},"events":{"type":"array","items":{"type":"string"},"description":"Platform event types the plugin subscribes to.\n\nWhen specified, Temps will POST matching events to the plugin's\n`/_events` endpoint. Uses dot-notation event names matching the\nwebhook event types (e.g., \"deployment.succeeded\", \"project.created\").\n\nAvailable events:\n- `deployment.created`, `deployment.succeeded`, `deployment.failed`,\n `deployment.cancelled`, `deployment.ready`\n- `project.created`, `project.deleted`\n- `domain.created`, `domain.provisioned`"},"health_path":{"type":"string","description":"Health check endpoint path (relative to plugin root)"},"name":{"type":"string","description":"Unique plugin identifier (kebab-case, e.g., \"backup-manager\")"},"nav":{"type":"array","items":{"$ref":"#/components/schemas/NavEntry"},"description":"Navigation entries for the UI sidebar"},"requires_db":{"type":"boolean","description":"Whether the plugin needs database access"},"ui":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/UiManifest","description":"UI bundle manifest (if the plugin has a UI)"}]},"version":{"type":"string","description":"SemVer version string"}}},"PortMapping":{"type":"object","description":"Port mapping","required":["container_port","protocol","is_primary"],"properties":{"container_port":{"type":"integer","format":"int32","description":"Container port","minimum":0},"host_port":{"type":["integer","null"],"format":"int32","description":"Host port (optional - can be assigned dynamically)","minimum":0},"is_primary":{"type":"boolean","description":"Whether this is the primary HTTP port"},"protocol":{"$ref":"#/components/schemas/Protocol","description":"Protocol (tcp, udp)"}}},"PostgresWalHealth":{"type":"object","required":["probed_at","pg_wal_bytes","max_wal_size_bytes","archive_mode","archive_backlog","stale_slots","oldest_wal_age_secs","warnings"],"properties":{"archive_backlog":{"type":"integer","format":"int64","description":"Number of `archive_status/*.ready` files — un-shipped WAL segments."},"archive_command":{"type":["string","null"],"description":"The literal `archive_command` setting. May be empty or `/bin/true`\nwhen archiving is effectively disabled despite `archive_mode = on`."},"archive_mode":{"$ref":"#/components/schemas/ArchiveMode"},"archiver_failed_count":{"type":["integer","null"],"format":"int64"},"archiver_last_failed_at":{"type":["string","null"],"format":"date-time"},"max_wal_size_bytes":{"type":"integer","format":"int64","description":"`max_wal_size` setting in bytes (parsed from `pg_settings`)."},"oldest_wal_age_secs":{"type":"integer","format":"int64","description":"Age of the oldest WAL file in `pg_wal/` (seconds)."},"pg_wal_bytes":{"type":"integer","format":"int64","description":"Total size of files under `pg_wal/`, from `pg_ls_waldir()`."},"probed_at":{"type":"string","format":"date-time","description":"When the snapshot was taken."},"stale_slots":{"type":"array","items":{"$ref":"#/components/schemas/StaleSlot"}},"warnings":{"type":"array","items":{"$ref":"#/components/schemas/WalWarning"},"description":"Computed warnings, ordered by severity (critical first)."}}},"PresetConfigSchema":{"oneOf":[{"$ref":"#/components/schemas/DockerfilePresetConfig","description":"Configuration for Dockerfile preset"},{"$ref":"#/components/schemas/DockerComposePresetConfig","description":"Configuration for Docker Compose"},{"$ref":"#/components/schemas/NixpacksPresetConfig","description":"Configuration for Nixpacks provider selection and inline build plan"},{"$ref":"#/components/schemas/StaticPresetConfig","description":"Configuration for static site presets (Vite, Next.js, etc.)"}],"description":"Union type for preset configurations\nUse the appropriate configuration type based on your preset"},"PresetInfo":{"type":"object","description":"Detected preset information","required":["path","preset","preset_label","project_type"],"properties":{"compose_files":{"type":["array","null"],"items":{"type":"string"},"description":"Compose file paths found in the repository (only for docker-compose preset)"},"exposed_port":{"type":["integer","null"],"format":"int32","description":"Default exposed port for this preset"},"icon_url":{"type":["string","null"],"description":"Icon URL for this preset"},"path":{"type":"string","description":"Path where preset was detected (empty for root)"},"preset":{"type":"string","description":"Preset slug (e.g., \"nextjs\", \"fastapi\")"},"preset_label":{"type":"string","description":"Human-readable preset label"},"project_type":{"type":"string","description":"Project type (e.g., \"frontend\", \"backend\", \"fullstack\")"}}},"PresetResponse":{"type":"object","required":["slug","label","icon_url","project_type","description"],"properties":{"default_port":{"type":["integer","null"],"format":"int32","description":"Default port the application listens on (None for static sites)","example":3000,"minimum":0},"description":{"type":"string","description":"Description of what this preset does"},"icon_url":{"type":"string","description":"Icon URL for the preset"},"label":{"type":"string","description":"Display name/label for the preset"},"project_type":{"type":"string","description":"Project type (server or static)"},"slug":{"type":"string","description":"Unique identifier slug for the preset"}}},"PreviewGatewaySettings":{"type":"object","description":"Workspace preview gateway settings.\n\nThe preview gateway is a single shared Docker container that lives on the\n`temps-sandbox-net` network and routes requests to workspace sandbox dev\nservers based on the `Host` header (`ws--.`).\n`temps serve` reconciles this container on startup; these settings let an\noperator override the image, host port, and auto-upgrade behavior.","properties":{"auto_upgrade":{"type":"boolean","description":"When true (default), the supervisor will pull and apply the image\npinned in the Temps binary on every startup. When false, the\ncurrently-running image is left alone — operators upgrade manually\nfrom the settings UI.","default":true,"example":true},"host_port":{"type":"integer","format":"int32","description":"Host port to publish the gateway on (always bound to 127.0.0.1).\nPingora forwards `ws-*` traffic to this port after authenticating.","default":8090,"example":8090,"minimum":0},"image":{"type":"string","description":"Docker image reference for the gateway. Pinned per Temps release.\nOperators can override this to test a custom build.","default":"ghcr.io/gotempsh/temps-preview-gateway:latest","example":"ghcr.io/gotempsh/temps-preview-gateway:latest"},"shared_secret":{"type":"string","description":"Shared secret the host-side Pingora sends on every forwarded preview\nrequest via `X-Temps-Preview-Token`; the gateway rejects requests\nwithout it. Auto-generated on first boot, persisted in DB so the\nsecret is stable across `temps serve` restarts regardless of cwd,\n`TEMPS_DATA_DIR`, or data-dir changes. MUST be masked (`***`) in any\nAPI response — never expose it over HTTP.","default":"","example":""}}},"PreviewGatewaySettingsMasked":{"type":"object","description":"Preview gateway settings with `shared_secret` elided.","required":["image","host_port","auto_upgrade","shared_secret_set"],"properties":{"auto_upgrade":{"type":"boolean"},"host_port":{"type":"integer","format":"int32","minimum":0},"image":{"type":"string"},"shared_secret_set":{"type":"boolean"}}},"PreviewGatewaySettingsResponse":{"type":"object","required":["image","host_port","auto_upgrade","default_image","default_host_port"],"properties":{"auto_upgrade":{"type":"boolean"},"default_host_port":{"type":"integer","format":"int32","description":"The compile-time default host port.","minimum":0},"default_image":{"type":"string","description":"The compile-time default image — exposed so the UI can offer a\n\"Reset to default\" link without round-tripping."},"host_port":{"type":"integer","format":"int32","minimum":0},"image":{"type":"string"}}},"PreviewShareLinkBody":{"type":"object","description":"Request body for minting a preview share link.","required":["port"],"properties":{"path":{"type":["string","null"],"description":"Path the recipient lands on. Must be same-origin (start with a single\n`/`); anything else is replaced with `/` so a share link can never be\nturned into an open redirect."},"port":{"type":"integer","format":"int32","description":"Port inside the sandbox the preview serves on.","minimum":0},"ttl_seconds":{"type":["integer","null"],"format":"int64","description":"How long the link stays usable, in seconds. Clamped to 24 hours.\nDefaults to one hour — long enough to send to a reviewer, short enough\nthat a link pasted in a ticket does not stay live indefinitely.","minimum":0}}},"PreviewShareLinkResponse":{"type":"object","required":["url","expires_at"],"properties":{"expires_at":{"type":"integer","format":"int64","description":"Unix seconds after which the link stops working.","minimum":0},"url":{"type":"string","description":"The full link. Its fragment contains the grant and must be treated as a\ncredential; URL fragments are not sent to servers or in Referer headers."}}},"PricingResponse":{"type":"object","required":["models"],"properties":{"models":{"type":"array","items":{"$ref":"#/components/schemas/ModelPricing"}}}},"ProblemDetails":{"type":"object","description":"Representation of a Problem error to return to the client.\nFollows RFC 7807 - Problem Details for HTTP APIs","required":["title","extensions"],"properties":{"detail":{"type":["string","null"],"description":"A human-readable explanation specific to this occurrence of the problem","example":"The server encountered an unexpected condition"},"extensions":{"type":"object","description":"Additional properties of the problem","additionalProperties":true},"instance":{"type":["string","null"],"description":"A URI reference that identifies the specific occurrence of the problem","example":"/account/12345/msgs/abc"},"title":{"type":"string","description":"A short, human-readable summary of the problem type","example":"Internal Server Error"},"type":{"type":["string","null"],"description":"A URI reference that identifies the problem type","example":"https://example.com/probs/out-of-memory"}},"example":{"type":"https://example.com/probs/out-of-memory","title":"Internal Server Error","detail":"The server encountered an unexpected condition","instance":"/account/12345/msgs/abc","additional_info":"Custom field with additional details"}},"ProjectAccessResponse":{"type":"object","required":["id","project_id","team_id","role","granted_by","created_at","updated_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2026-07-30T12:15:47.609192Z"},"granted_by":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"project_id":{"type":"integer","format":"int32"},"role":{"$ref":"#/components/schemas/TeamRole"},"team_id":{"type":"integer","format":"int32"},"updated_at":{"type":"string","format":"date-time","example":"2026-07-30T12:15:47.609192Z"}}},"ProjectConfiguration":{"type":"object","description":"Project-level configuration","required":["name","slug","project_type","is_web_app"],"properties":{"is_web_app":{"type":"boolean","description":"Whether this is a web application"},"name":{"type":"string","description":"Proposed project name"},"project_type":{"$ref":"#/components/schemas/ProjectType","description":"Project type"},"slug":{"type":"string","description":"Proposed slug (URL-safe identifier)"}}},"ProjectDSNResponse":{"type":"object","required":["id","project_id","name","public_key","dsn","created_at","is_active","event_count"],"properties":{"created_at":{"type":"string"},"deployment_id":{"type":["integer","null"],"format":"int32"},"dsn":{"type":"string"},"environment_id":{"type":["integer","null"],"format":"int32"},"event_count":{"type":"integer","format":"int64"},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"name":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"public_key":{"type":"string"}}},"ProjectDashboardAnalytics":{"type":"object","description":"Analytics data for a single project in the dashboard batch response","required":["project_id","unique_visitors","previous_unique_visitors","hourly_visits"],"properties":{"hourly_visits":{"type":"array","items":{"$ref":"#/components/schemas/EventTimeline"},"description":"Hourly sparkline data points"},"previous_unique_visitors":{"type":"integer","format":"int64","description":"Unique visitor count in the previous period (same duration, shifted back)"},"project_id":{"type":"integer","format":"int32"},"trend_percentage":{"type":["number","null"],"format":"double","description":"Percentage change from previous period (positive = growth, negative = decline)\nNull when previous period had zero visitors (no baseline to compare)"},"unique_visitors":{"type":"integer","format":"int64","description":"Unique visitor count in the current time range"}}},"ProjectHealthSummary":{"type":"object","description":"Health summary for a single project (last 1 hour)","required":["project_id","total_requests","total_errors","avg_response_time_ms","error_rate","status"],"properties":{"avg_response_time_ms":{"type":"number","format":"double","description":"Average response time in ms"},"error_rate":{"type":"number","format":"double","description":"Error rate as a percentage (0-100)"},"project_id":{"type":"integer","format":"int32"},"status":{"type":"string","description":"Health status: \"healthy\", \"degraded\", \"down\", \"unknown\""},"total_errors":{"type":"integer","format":"int64","description":"Total server errors (status >= 500) in the period"},"total_requests":{"type":"integer","format":"int64","description":"Total requests in the period"}}},"ProjectInfo":{"type":"object","required":["id","slug","created_at"],"properties":{"created_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"id":{"type":"integer","format":"int32"},"slug":{"type":"string"}}},"ProjectMonitorHealth":{"type":"object","description":"Health summary for a single project based on its production monitors","required":["project_id","status"],"properties":{"project_id":{"type":"integer","format":"int32"},"status":{"type":"string","description":"Overall status: \"operational\", \"degraded\", \"down\", or \"no_monitors\""}}},"ProjectPresetResponse":{"type":"object","required":["path","preset","presetLabel","projectType"],"properties":{"composeFiles":{"type":["array","null"],"items":{"type":"string"},"description":"Compose file paths found in the repository (only for docker-compose preset)"},"exposedPort":{"type":["integer","null"],"format":"int32","description":"Default exposed port for this preset (e.g., 3000 for Next.js, 8000 for FastAPI)"},"iconUrl":{"type":["string","null"],"description":"Icon URL for the preset"},"path":{"type":"string"},"preset":{"type":"string"},"presetLabel":{"type":"string"},"projectType":{"type":"string","description":"Project type category (e.g., \"frontend\", \"backend\", \"fullstack\")"}}},"ProjectQuery":{"type":"object","required":["project_id"],"properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"}}},"ProjectRef":{"type":"object","description":"A lightweight project descriptor included in `UnifiedTrace`.","required":["project_id","project_name","project_slug"],"properties":{"project_id":{"type":"integer","format":"int32"},"project_name":{"type":"string"},"project_slug":{"type":"string","description":"URL slug used to link a span back into its owning project's trace view."}}},"ProjectResponse":{"type":"object","required":["id","slug","name","directory","main_branch","created_at","updated_at","deployment_config","attack_mode","ai_write_actions_enabled","error_source_context_enabled","enable_preview_environments","preview_envs_on_demand","preview_envs_idle_timeout_seconds","preview_envs_wake_timeout_seconds","source_type","cross_project_trace_sharing"],"properties":{"ai_alert_summaries_enabled":{"type":["boolean","null"],"description":"Opt-in to AI summarization of metric alert notifications (NULL/false = off)."},"ai_debug_chat_enabled":{"type":["boolean","null"],"description":"Opt-in to AI debugging chat, e.g. on deployment failures (NULL/false = off)."},"ai_write_actions_enabled":{"type":"boolean","description":"Opt-in to AI propose-then-confirm write capability (false = off)."},"attack_mode":{"type":"boolean","description":"Attack mode - when enabled, requires CAPTCHA verification for all project environments"},"created_at":{"type":"integer","format":"int64"},"cross_project_trace_sharing":{"type":"boolean","description":"ADR-027 Phase 3 opt-out: when false, this project's traces are suppressed\nfrom cross-project discovery results. Default true (consistent with the\nOSS global-observability model where any OtelRead holder can query any\nproject's telemetry)."},"deployment_config":{"$ref":"#/components/schemas/DeploymentConfig","description":"Deployment configuration (resources, autoscaling, features)"},"directory":{"type":"string"},"enable_preview_environments":{"type":"boolean","description":"Enable automatic preview environment creation for each branch"},"error_source_context_enabled":{"type":"boolean","description":"Opt-in to native error-tracking source context (false = off). When on,\nTemps stores uploaded source files and shows source code in stack traces."},"error_source_root":{"type":["string","null"],"description":"Where auto-capture reads source from (relative to the checkout). Null =\nthe deployment's Docker build context."},"git_provider_connection_id":{"type":["integer","null"],"format":"int32"},"git_url":{"type":["string","null"],"description":"Git clone URL for the repository (used for public repos without a provider connection)"},"gitlab_webhook_id":{"type":["integer","null"],"format":"int32","description":"GitLab webhook ID installed on the connected repository.\n`null` when no GitLab webhook is installed (not connected to GitLab,\nor webhook was removed / never created).","example":42},"id":{"type":"integer","format":"int32"},"last_deployment":{"type":["integer","null"],"format":"int64"},"main_branch":{"type":"string"},"name":{"type":"string"},"preset":{"type":["string","null"]},"preset_config":{"description":"Preset-specific configuration (Dockerfile path, build context, etc.)"},"preview_envs_idle_timeout_seconds":{"type":"integer","format":"int32","description":"Idle timeout (seconds) for on-demand preview environments."},"preview_envs_on_demand":{"type":"boolean","description":"When true, newly-created preview environments default to on-demand mode\n(containers stop after the configured idle timeout to save resources)."},"preview_envs_wake_timeout_seconds":{"type":"integer","format":"int32","description":"Wake timeout (seconds) for on-demand preview environments."},"repo_name":{"type":["string","null"]},"repo_owner":{"type":["string","null"]},"slug":{"type":"string"},"source_type":{"$ref":"#/components/schemas/SourceType","description":"Source type for deployments (git, docker_image, or static_files)"},"updated_at":{"type":"integer","format":"int64"}}},"ProjectSecretEnvironmentInfo":{"type":"object","required":["id","name","main_url"],"properties":{"id":{"type":"integer","format":"int32"},"main_url":{"type":"string"},"name":{"type":"string"}}},"ProjectSecretResponse":{"type":"object","description":"Project secret metadata. There is deliberately no `value` field — secret\nplaintext is never returned after creation. Callers that need the value\nmust read it from the mounted file inside the container.","required":["id","project_id","key","include_in_preview","created_at","updated_at","environments"],"properties":{"created_at":{"type":"integer","format":"int64"},"environments":{"type":"array","items":{"$ref":"#/components/schemas/ProjectSecretEnvironmentInfo"}},"id":{"type":"integer","format":"int32"},"include_in_preview":{"type":"boolean"},"key":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"updated_at":{"type":"integer","format":"int64"}}},"ProjectServiceInfo":{"type":"object","required":["id","project","service"],"properties":{"id":{"type":"integer","format":"int32"},"project":{"$ref":"#/components/schemas/ProjectInfo"},"service":{"$ref":"#/components/schemas/ExternalServiceInfo"}}},"ProjectStatisticsResponse":{"type":"object","required":["total_count"],"properties":{"total_count":{"type":"integer","format":"int64"}}},"ProjectStatsBreakdown":{"type":"object","required":["project_id","unique_visitors","total_visits","total_page_views","bounce_rate","engagement_rate"],"properties":{"bounce_rate":{"type":"number","format":"double"},"engagement_rate":{"type":"number","format":"double"},"project_id":{"type":"integer","format":"int32"},"project_name":{"type":["string","null"]},"total_page_views":{"type":"integer","format":"int64"},"total_visits":{"type":"integer","format":"int64"},"unique_visitors":{"type":"integer","format":"int64"}}},"ProjectType":{"type":"string","description":"Project type enumeration","enum":["static","docker","buildpack","git"]},"ProjectUsageInfoResponse":{"type":"object","required":["id","name","slug","connection_id","connection_name"],"properties":{"connection_id":{"type":"integer","format":"int32"},"connection_name":{"type":"string"},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"slug":{"type":"string"}}},"ProjectsHealthResponse":{"type":"object","description":"Batch health summary response","required":["projects"],"properties":{"projects":{"type":"object","description":"Health summaries keyed by project ID","additionalProperties":{"$ref":"#/components/schemas/ProjectHealthSummary"},"propertyNames":{"type":"string"}}}},"ProjectsMonitorHealthResponse":{"type":"object","description":"Batch response for projects health","required":["projects"],"properties":{"projects":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/ProjectMonitorHealth"},"propertyNames":{"type":"string"}}}},"PromoteDeploymentRequest":{"type":"object","required":["target_environment_id"],"properties":{"target_environment_id":{"type":"integer","format":"int32","description":"Target environment ID to promote the deployment to"}}},"PropertyBreakdownItem":{"type":"object","required":["value","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"percentage":{"type":"number","format":"double"},"value":{"type":"string"}}},"PropertyBreakdownQuery":{"type":"object","description":"Query parameters for property breakdown (group by column)","required":["start_date","end_date","group_by"],"properties":{"aggregation_level":{"$ref":"#/components/schemas/AggregationLevel","description":"Aggregation level"},"deployment_id":{"type":["integer","null"],"format":"int32","description":"Optional deployment filter"},"end_date":{"type":"string","format":"date-time","description":"End date for the query range"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Optional environment filter"},"event_name":{"type":["string","null"],"description":"Optional event name filter (e.g., \"page_view\", \"click\")"},"filter_browser":{"type":["string","null"],"description":"Filter by browser name (for browser version drill-downs)"},"filter_channel":{"type":["string","null"],"description":"Filter by channel name (for channel -> referrer drill-downs)"},"filter_country":{"type":["string","null"],"description":"Filter by country (for region/city drill-downs). Requires geolocation join."},"filter_os":{"type":["string","null"],"description":"Filter by operating system name (for OS version drill-downs)"},"filter_referrer":{"type":["string","null"],"description":"Filter by referrer hostname (for referrer -> pages drill-downs)"},"filter_region":{"type":["string","null"],"description":"Filter by region (for city drill-downs). Requires geolocation join."},"group_by":{"$ref":"#/components/schemas/PropertyColumn","description":"Property column to group by"},"include_crawlers":{"type":["boolean","null"],"description":"Include crawler/bot traffic (default: false). Off by default so the\nbreakdown percentages share a denominator with the headline counts,\nwhich always exclude crawlers."},"limit":{"type":["integer","null"],"format":"int32","description":"Maximum number of results to return (default: 20, max: 100)"},"start_date":{"type":"string","format":"date-time","description":"Start date for the query range"}}},"PropertyBreakdownResponse":{"type":"object","required":["property","items","total"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/PropertyBreakdownItem"}},"property":{"type":"string"},"total":{"type":"integer","format":"int64"}}},"PropertyColumn":{"type":"string","enum":["channel","device_type","browser","browser_version","operating_system","operating_system_version","utm_source","utm_medium","utm_campaign","utm_term","utm_content","referrer_hostname","language","event_type","event_name","page_path","pathname","country","region","city"]},"PropertyTimelineItem":{"type":"object","required":["timestamp","value","count"],"properties":{"count":{"type":"integer","format":"int64"},"timestamp":{"type":"string"},"value":{"type":"string"}}},"PropertyTimelineQuery":{"type":"object","description":"Query parameters for property timeline (group by column over time)","required":["start_date","end_date","group_by"],"properties":{"aggregation_level":{"$ref":"#/components/schemas/AggregationLevel","description":"Aggregation level"},"bucket_size":{"type":["string","null"],"description":"Time bucket size: \"hour\", \"day\", \"week\", \"month\" (default: auto-detect)"},"deployment_id":{"type":["integer","null"],"format":"int32","description":"Optional deployment filter"},"end_date":{"type":"string","format":"date-time","description":"End date for the query range"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Optional environment filter"},"event_name":{"type":["string","null"],"description":"Optional event name filter"},"group_by":{"$ref":"#/components/schemas/PropertyColumn","description":"Property column to group by"},"include_crawlers":{"type":["boolean","null"],"description":"Include crawler/bot traffic (default: false). See\n[`PropertyBreakdownQuery::include_crawlers`]."},"start_date":{"type":"string","format":"date-time","description":"Start date for the query range"}}},"PropertyTimelineResponse":{"type":"object","required":["property","bucket_size","items"],"properties":{"bucket_size":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/PropertyTimelineItem"}},"property":{"type":"string"}}},"Protocol":{"type":"string","description":"Network protocol","enum":["tcp","udp"]},"ProviderCatalogDto":{"type":"object","description":"One catalog entry rendered for the settings UI.","required":["id","name","install_command","auth_command","auth_flavors","models","credential_saved","supports_max_turns"],"properties":{"auth_command":{"type":"string"},"auth_flavors":{"type":"array","items":{"$ref":"#/components/schemas/AuthFlavorDto"}},"credential_saved":{"type":"boolean","description":"True when a credential is currently saved for this provider in the\nsettings JSON. Lets the UI render \"Configured\" badges without the\nfrontend having to inspect the encrypted blob."},"current_auth_type":{"type":["string","null"],"description":"Currently saved auth flavor id (when `credential_saved` is true).\n`None` when no credential is saved yet."},"default_model":{"type":["string","null"],"description":"Currently saved default model id for this provider, if one was\npicked. `None` means \"use the CLI's own default\" — the UI renders\nthat as \"Use provider default\"."},"id":{"type":"string"},"install_command":{"type":"string"},"max_turns_analysis":{"type":["integer","null"],"format":"int32","description":"Default max turns for the autofixer analysis phase. `None` = built-in\ndefault (10). Only enforced for CLIs with a turn flag (Claude Code)."},"max_turns_feedback":{"type":["integer","null"],"format":"int32","description":"Default max turns for autofixer feedback rounds. `None` = built-in\ndefault (10)."},"max_turns_fix":{"type":["integer","null"],"format":"int32","description":"Default max turns for the autofixer fix phase. `None` = built-in\ndefault (20)."},"models":{"type":"array","items":{"type":"string"},"description":"Model ids this provider accepts, in display order. The first entry is\nthe recommended default. Empty when the provider doesn't expose model\nselection (e.g. OpenCode), which the UI uses to hide the dropdown."},"name":{"type":"string"},"supports_max_turns":{"type":"boolean","description":"True when this provider's CLI supports enforcing a turn cap. False\nfor Codex/OpenCode, which run to completion — the UI labels their\nmax-turns inputs accordingly."}}},"ProviderCatalogResponse":{"type":"object","required":["default_provider","providers"],"properties":{"default_provider":{"type":"string","description":"Active provider id from `agent_sandbox.default_provider`. The settings\nUI uses this to highlight which card is the active one."},"providers":{"type":"array","items":{"$ref":"#/components/schemas/ProviderCatalogDto"}}}},"ProviderConfig":{"oneOf":[{"allOf":[{"$ref":"#/components/schemas/StripeConfig"},{"type":"object","required":["provider"],"properties":{"provider":{"type":"string","enum":["stripe"]}}}]},{"allOf":[{"$ref":"#/components/schemas/LemonSqueezyConfig"},{"type":"object","required":["provider"],"properties":{"provider":{"type":"string","enum":["lemon_squeezy"]}}}]}],"description":"Provider-specific integration settings persisted in\n`revenue_integrations.config`.\n\nThe tag is the lowercase provider name, so adding a new provider\nmeans adding a new variant and the existing rows are untouched.\nOld rows (pre-config) and rows with `NULL` config are treated as\n\"accept all events, no filtering\" via [`ProviderConfig::default_for`]."},"ProviderConfigMasked":{"type":"object","required":["auth_type","credential_saved","extra"],"properties":{"auth_type":{"type":"string"},"credential_saved":{"type":"boolean","description":"True if a credential is stored for this provider. The encrypted blob\nis never returned over HTTP."},"default_model":{"type":["string","null"]},"extra":{}}},"ProviderDeletionCheckResponse":{"type":"object","required":["can_delete","projects_in_use","message"],"properties":{"can_delete":{"type":"boolean"},"message":{"type":"string"},"projects_in_use":{"type":"array","items":{"$ref":"#/components/schemas/ProjectUsageInfoResponse"}}}},"ProviderDescriptor":{"type":"object","required":["name","display_name","recommended_events"],"properties":{"display_name":{"type":"string"},"name":{"type":"string"},"recommended_events":{"type":"array","items":{"type":"string"}}}},"ProviderKeyResponse":{"type":"object","required":["id","provider","display_name","api_key_masked","is_active","created_at","updated_at"],"properties":{"api_key_masked":{"type":"string","description":"Masked API key (only last 4 chars visible)"},"base_url":{"type":["string","null"]},"created_at":{"type":"string"},"default_model":{"type":["string","null"],"description":"Model id this provider serves (NULL → per-provider default)."},"display_name":{"type":"string"},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"provider":{"type":"string"},"updated_at":{"type":"string"}}},"ProviderMetadata":{"type":"object","required":["service_type","display_name","description","icon_url","color"],"properties":{"color":{"type":"string","example":"#336791"},"description":{"type":"string","example":"Relational database management system"},"display_name":{"type":"string","example":"PostgreSQL"},"icon_url":{"type":"string","example":"https://cdn.simpleicons.org/postgresql"},"service_type":{"$ref":"#/components/schemas/ServiceTypeRoute"}}},"ProviderResponse":{"type":"object","required":["id","name","provider_type","auth_method","is_active","is_default","created_at","updated_at"],"properties":{"auth_method":{"type":"string"},"base_url":{"type":["string","null"]},"created_at":{"type":"string","format":"date-time"},"id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"is_default":{"type":"boolean"},"name":{"type":"string"},"provider_type":{"type":"string"},"updated_at":{"type":"string","format":"date-time"}}},"ProviderUsage":{"type":"object","required":["provider","request_count","input_tokens","output_tokens","avg_latency_ms","error_count"],"properties":{"avg_latency_ms":{"type":"number","format":"double"},"error_count":{"type":"integer","format":"int64"},"input_tokens":{"type":"integer","format":"int64"},"output_tokens":{"type":"integer","format":"int64"},"provider":{"type":"string"},"request_count":{"type":"integer","format":"int64"}}},"ProvisionResponse":{"oneOf":[{"allOf":[{"$ref":"#/components/schemas/DomainError"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["error"]}}}]},{"allOf":[{"$ref":"#/components/schemas/DomainResponse"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["complete"]}}}]},{"allOf":[{"$ref":"#/components/schemas/DomainChallengeResponse"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["pending"]}}}]}]},"ProxyLogResponse":{"type":"object","description":"Response model for proxy logs","required":["id","timestamp","method","path","host","status_code","request_source","is_system_request","routing_status","request_id"],"properties":{"bot_name":{"type":["string","null"]},"browser":{"type":["string","null"]},"browser_version":{"type":["string","null"]},"cache_status":{"type":["string","null"]},"client_ip":{"type":["string","null"]},"container_id":{"type":["string","null"]},"deployment_id":{"type":["integer","null"],"format":"int32"},"device_type":{"type":["string","null"]},"environment_id":{"type":["integer","null"],"format":"int32"},"error_message":{"type":["string","null"]},"host":{"type":"string"},"id":{"type":"integer","format":"int32"},"ip_geolocation_id":{"type":["integer","null"],"format":"int32"},"is_bot":{"type":["boolean","null"]},"is_system_request":{"type":"boolean"},"method":{"type":"string"},"operating_system":{"type":["string","null"]},"path":{"type":"string"},"project_id":{"type":["integer","null"],"format":"int32"},"query_string":{"type":["string","null"]},"referrer":{"type":["string","null"]},"request_id":{"type":"string"},"request_size_bytes":{"type":["integer","null"],"format":"int64"},"request_source":{"type":"string"},"response_size_bytes":{"type":["integer","null"],"format":"int64"},"response_time_ms":{"type":["integer","null"],"format":"int32"},"routing_status":{"type":"string"},"session_id":{"type":["integer","null"],"format":"int32"},"status_code":{"type":"integer","format":"int32"},"timestamp":{"type":"string"},"upstream_host":{"type":["string","null"]},"user_agent":{"type":["string","null"]},"visitor_id":{"type":["integer","null"],"format":"int32"}}},"ProxyLogsPaginatedResponse":{"type":"object","description":"Paginated response for proxy logs","required":["logs","total","page","page_size","total_pages"],"properties":{"logs":{"type":"array","items":{"$ref":"#/components/schemas/ProxyLogResponse"}},"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"total":{"type":"integer","format":"int64","minimum":0},"total_pages":{"type":"integer","format":"int64","minimum":0}}},"PublicHostnameStrategy":{"type":"string","description":"Public hostname generation mode for Temps-managed preview routes.\n\nThe mode is stored per managed domain (`dns_managed_domains.generated_hostname_mode`)\nrather than globally, so a provider such as Cloudflare can offer the flat layout\nrequired by its Universal SSL wildcard cert without changing every domain's behaviour.","enum":["standard","flat"]},"PublicPresetResponse":{"type":"object","description":"Response for preset detection","required":["branch","presets"],"properties":{"branch":{"type":"string","description":"Branch name where presets were detected"},"presets":{"type":"array","items":{"$ref":"#/components/schemas/PresetInfo"},"description":"List of detected presets"}}},"PublicRepositoryInfo":{"type":"object","description":"Public repository information","required":["owner","name","full_name","default_branch","stars","forks"],"properties":{"default_branch":{"type":"string","description":"Default branch name"},"description":{"type":["string","null"],"description":"Repository description"},"forks":{"type":"integer","format":"int32","description":"Fork count"},"full_name":{"type":"string","description":"Full repository name (owner/repo)"},"language":{"type":["string","null"],"description":"Primary programming language"},"name":{"type":"string","description":"Repository name"},"owner":{"type":"string","description":"Repository owner"},"stars":{"type":"integer","format":"int32","description":"Star count"}}},"PurgeLogsRequest":{"type":"object","required":["before"],"properties":{"before":{"type":"string","description":"Delete all logs before this timestamp (ISO 8601)"}}},"PushImageRequest":{"type":"object","description":"Request to push an external image","required":["image_ref"],"properties":{"image_ref":{"type":"string"},"metadata":{}}},"PushedExternalImageResponse":{"type":"object","description":"Response for in-memory external image operations (legacy push flow).\n\nRenamed to avoid shadowing the richer database-backed `ExternalImageResponse`\nin `handlers/remote_deployments.rs`. The two types serve different routes\n(`/images` ephemeral push vs `/external-images` registered images).","required":["id","image_ref","pushed_at"],"properties":{"digest":{"type":["string","null"]},"id":{"type":"string"},"image_ref":{"type":"string"},"pushed_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"size":{"type":["integer","null"],"format":"int64","minimum":0}}},"QueryDataRequest":{"type":"object","properties":{"filters":{"description":"JSON filters (backend-specific format)"},"limit":{"type":"integer","description":"Maximum number of rows to return","example":100,"minimum":0},"offset":{"type":"integer","description":"Number of rows to skip","example":0,"minimum":0},"sort_by":{"type":["string","null"],"description":"Sort by field name"},"sort_order":{"type":["string","null"],"description":"Sort order (asc/desc)"}}},"QueryDataResponse":{"type":"object","required":["fields","rows","total_count","returned_count","execution_time_ms","truncated"],"properties":{"execution_time_ms":{"type":"integer","format":"int64","description":"Query execution time in milliseconds","example":45,"minimum":0},"fields":{"type":"array","items":{"$ref":"#/components/schemas/FieldResponse"},"description":"Field definitions"},"returned_count":{"type":"integer","description":"Number of rows returned in this response","example":100,"minimum":0},"rows":{"type":"array","items":{},"description":"Data rows (array of JSON objects)"},"total_count":{"type":"integer","format":"int64","description":"Total number of rows matching the query (before limit/offset)","example":1234,"minimum":0},"truncated":{"type":"boolean","description":"Whether rows were dropped from this response to stay inside the byte\nbudget.\n\n`returned_count` is always the number of rows actually present, so a\ntruncated page is still internally consistent — but a caller comparing\nit against the requested limit would otherwise conclude the table simply\nended. Reported explicitly so a partial page is never mistaken for a\ncomplete one, by a human, a script, or a model reading a tool result.","example":false}}},"QuotaResponse":{"type":"object","required":["quota"],"properties":{"quota":{"$ref":"#/components/schemas/StorageQuota"}}},"RateLimitConfig":{"type":"object","description":"Rate limiting configuration (subset of global RateLimitSettings)","properties":{"blacklistIps":{"type":"array","items":{"type":"string"},"description":"Blacklist specific IPs for this project/environment"},"maxRequestsPerHour":{"type":["integer","null"],"format":"int32","description":"Override rate limit per hour","minimum":0},"maxRequestsPerMinute":{"type":["integer","null"],"format":"int32","description":"Override rate limit per minute","minimum":0},"whitelistIps":{"type":"array","items":{"type":"string"},"description":"Whitelist specific IPs for this project/environment"}}},"RateLimitSettings":{"type":"object","properties":{"blacklist_ips":{"type":"array","items":{"type":"string"},"default":[]},"enabled":{"type":"boolean","default":false},"max_requests_per_hour":{"type":"integer","format":"int32","default":1000,"minimum":0},"max_requests_per_minute":{"type":"integer","format":"int32","default":60,"minimum":0},"whitelist_ips":{"type":"array","items":{"type":"string"},"default":[]}}},"ReachabilityStatus":{"type":"string","description":"Email reachability status","enum":["safe","risky","invalid","unknown"]},"ReadFileResponse":{"type":"object","required":["path","contents_b64","size"],"properties":{"contents_b64":{"type":"string","description":"File contents, base64-encoded. Symmetric with `WriteFileBody`."},"path":{"type":"string"},"size":{"type":"integer","format":"int64","minimum":0}}},"ReadRowsQuery":{"type":"object","description":"Query-string form of [`QueryDataRequest`] for the read-only `GET` rows\nendpoint.\n\nThe `POST` variant exists because filters are arbitrary backend-specific\nJSON. Reading rows is nonetheless a *read*, and the AI agent's tool index\nis GET-only by construction, so the same capability has to be reachable\nwithout a body. `filter` therefore carries the JSON as a string.","properties":{"filter":{"type":["string","null"],"description":"Backend-specific filter, JSON-encoded. Fetch the expected shape from\nthe `filter_schema` field of the explorer-support endpoint — e.g.\n`{\"where\":\"created_at > now() - interval '7 days'\"}` for SQL sources."},"limit":{"type":"integer","description":"Maximum number of rows to return","example":100,"minimum":0},"offset":{"type":"integer","description":"Number of rows to skip","example":0,"minimum":0},"sort_by":{"type":["string","null"],"description":"Sort by field name"},"sort_order":{"type":["string","null"],"description":"Sort order (asc/desc)"}}},"RecentActivityQuery":{"type":"object","description":"Query parameters for recent activity endpoint","required":["project_id"],"properties":{"environment_id":{"type":["integer","null"],"format":"int32","description":"Environment ID (optional)"},"limit":{"type":["integer","null"],"format":"int32","description":"Max number of events to return (default: 50, max: 100)"},"project_id":{"type":"integer","format":"int32","description":"Project ID"},"since_id":{"type":["integer","null"],"format":"int64","description":"Return events with ID greater than this (for cursor-based polling)"}}},"RecentActivityResponse":{"type":"object","description":"Response for recent activity events endpoint","required":["events","count"],"properties":{"count":{"type":"integer","description":"Total events returned","minimum":0},"events":{"type":"array","items":{"$ref":"#/components/schemas/ActivityEvent"},"description":"Recent events, newest first"}}},"RecentEventResponse":{"type":"object","required":["occurred_at","event_type"],"properties":{"amount_minor":{"type":["integer","null"],"format":"int64"},"currency":{"type":["string","null"]},"customer_ref":{"type":["string","null"]},"event_type":{"type":"string"},"mrr_minor":{"type":["integer","null"],"format":"int64"},"occurred_at":{"type":"string","format":"date-time"}}},"RecentQueryParams":{"type":"object","properties":{"conversation_id":{"type":["string","null"],"description":"Filter by conversation ID"},"cost_gt":{"type":["integer","null"],"format":"int64","description":"Cost strictly greater-than, in microcents"},"cost_gte":{"type":["integer","null"],"format":"int64","description":"Cost greater-than-or-equal, in microcents"},"cost_lt":{"type":["integer","null"],"format":"int64","description":"Cost strictly less-than, in microcents"},"cost_lte":{"type":["integer","null"],"format":"int64","description":"Cost less-than-or-equal, in microcents"},"limit":{"type":["integer","null"],"format":"int64","description":"Page size (defaults to 20, max 50)","minimum":0},"model":{"type":["string","null"],"description":"Filter by model name"},"offset":{"type":["integer","null"],"format":"int64","description":"Number of results to skip for pagination (defaults to 0)","minimum":0},"provider":{"type":["string","null"],"description":"Filter by provider name"},"status":{"type":["integer","null"],"format":"int32","description":"Filter by HTTP status code (exact match)"},"tags":{"type":["string","null"],"description":"Filter by tags (comma-separated, AND logic)"},"tokens_gt":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) strictly greater-than"},"tokens_gte":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) greater-than-or-equal"},"tokens_lt":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) strictly less-than"},"tokens_lte":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) less-than-or-equal"},"user_id":{"type":["integer","null"],"format":"int32","description":"Filter by user ID"}}},"RecordExposureRequest":{"type":"object","description":"Keys a running app actually evaluated since its last report.","required":["keys"],"properties":{"keys":{"type":"array","items":{"type":"string"},"description":"Flag keys evaluated since the last report. Unknown keys are ignored.","example":["checkout.v2","api.rate_limit"]}}},"RecordExposureResponse":{"type":"object","required":["recorded"],"properties":{"recorded":{"type":"integer","format":"int64","description":"How many keys were accepted for processing.\n\nDeliberately not the number of rows updated: echoing that back would\nlet a caller post a single candidate key and read the result as \"this\nflag exists\", turning the endpoint into an existence oracle.","minimum":0}}},"RecordListResponse":{"type":"object","description":"Record list response","required":["records"],"properties":{"records":{"type":"array","items":{"$ref":"#/components/schemas/DnsRecord"}}}},"RecoveryTarget":{"oneOf":[{"type":"object","description":"Recover to a specific timestamp.","required":["time","kind"],"properties":{"kind":{"type":"string","enum":["time"]},"time":{"type":"string","format":"date-time"}}},{"type":"object","description":"Recover to a specific transaction id (Postgres).","required":["xid","kind"],"properties":{"kind":{"type":"string","enum":["xid"]},"xid":{"type":"string"}}},{"type":"object","description":"Recover to a specific log sequence number (Postgres).","required":["lsn","kind"],"properties":{"kind":{"type":"string","enum":["lsn"]},"lsn":{"type":"string"}}},{"type":"object","description":"Recover to a named restore point created via `pg_create_restore_point` (Postgres).","required":["name","kind"],"properties":{"kind":{"type":"string","enum":["name"]},"name":{"type":"string"}}}],"description":"Engine-specific recovery target for PITR.\n\nPostgres honors all variants; Redis/Mongo/S3 will likely reject non-Time\nvariants or define their own semantics when they grow PITR support."},"ReferrerCount":{"type":"object","required":["referrer","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"percentage":{"type":"number","format":"double"},"referrer":{"type":"string"}}},"ReferrersAnalyticsQuery":{"type":"object","required":["start_date","end_date","project_id"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"RegenerateDSNRequest":{"type":"object","properties":{"base_url":{"type":["string","null"]}}},"RegisterImageRequest":{"type":"object","required":["image_ref"],"properties":{"digest":{"type":["string","null"],"description":"Image digest (sha256:...)","example":"sha256:abc123def456"},"image_ref":{"type":"string","description":"Docker image reference (e.g., \"ghcr.io/org/app:v1.0\")","example":"ghcr.io/myorg/myapp:v1.0"},"metadata":{"description":"Additional metadata"},"tag":{"type":["string","null"],"description":"Image tag","example":"v1.0"}}},"RegisterNodeApiRequest":{"type":"object","required":["name","token","address","private_address"],"properties":{"address":{"type":"string","description":"Node's reachable address (e.g., \"10.100.0.2\" or \"192.168.1.50\")"},"architecture":{"type":["string","null"],"description":"Container platform of this node's Docker daemon (`linux/amd64`,\n`linux/arm64`). Optional: agents older than multi-arch support omit it\nand the value is learned from the first heartbeat instead."},"csr_pem":{"type":["string","null"],"description":"Node-generated certificate signing request (PEM) for multi-node mTLS\n(ADR-020 WS-2.1). When present, the control plane signs it with the\ncluster CA and returns the leaf + CA cert. Optional — token-only nodes\n(legacy / edge) still register without one."},"edge_public_key":{"type":["string","null"],"description":"X25519 public key for ECIES certificate encryption (base64-encoded, edge nodes only)"},"join_token":{"type":["string","null"],"description":"Join token to authorize this registration (must match the token generated in Settings)"},"labels":{"description":"Labels for scheduling (e.g., {\"region\": \"us-east\", \"gpu\": \"true\"})"},"name":{"type":"string","description":"Unique name for this node"},"prior_token":{"type":["string","null"],"description":"The node's *current* token, supplied to prove possession when\nre-registering (changing the identity of) a node that already exists.\nOptional; only needed to rebind a still-live node. (ADR-020 WS-1.2.)"},"private_address":{"type":"string","description":"Private/WireGuard address for inter-node communication"},"public_endpoint":{"type":["string","null"],"description":"Public endpoint for WireGuard (e.g., \"203.0.113.1:51820\")"},"role":{"type":["string","null"],"description":"Node role (default: \"worker\")"},"token":{"type":"string","description":"Registration token (plaintext, will be hashed before storage)"},"wg_public_key":{"type":["string","null"],"description":"WireGuard public key"}}},"RegisterNodeResponse":{"type":"object","required":["id","name","status","message"],"properties":{"ca_cert_pem":{"type":["string","null"],"description":"The cluster CA certificate (PEM) the node pins as its trust root.\nPresent only when a `csr_pem` was supplied. (ADR-020 WS-2.1.)"},"cert_pem":{"type":["string","null"],"description":"The signed per-node leaf certificate (PEM) the agent serves as its TLS\nserver cert. Present only when a `csr_pem` was supplied. (ADR-020 WS-2.1.)"},"id":{"type":"integer","format":"int32"},"message":{"type":"string"},"name":{"type":"string"},"status":{"type":"string"}}},"RegisterRequest":{"type":"object","required":["email","password","name"],"properties":{"email":{"type":"string"},"name":{"type":"string"},"password":{"type":"string"}}},"ReinstallWebhookResponse":{"type":"object","description":"Response for `POST /projects/{project_id}/gitlab/reinstall-webhook`","required":["hook_id","message"],"properties":{"hook_id":{"type":"integer","format":"int32","description":"The new GitLab hook ID that was installed."},"message":{"type":"string","description":"Human-readable status message."}}},"ReleaseCheckResult":{"type":"object","description":"Outcome of an operator-triggered release check.","required":["channel","current_version","update_available"],"properties":{"channel":{"type":"string","description":"Channel that was queried."},"current_version":{"type":"string","description":"Version tag of the running binary."},"latest_version":{"type":["string","null"],"description":"Newest release published on that channel, if any could be resolved."},"release_url":{"type":["string","null"],"description":"Release-notes page for `latest_version`."},"update_available":{"type":"boolean","description":"True when `latest_version` is strictly newer than what is running.\nFalse on a channel whose newest release is older — which is normal and\nexpected right after switching a nightly box onto stable."}}},"ReleaseListResponse":{"type":"object","required":["releases"],"properties":{"releases":{"type":"array","items":{"type":"string"}}}},"ReloadResponse":{"type":"object","description":"Response from the reload endpoint.","required":["loaded","plugins","message"],"properties":{"loaded":{"type":"integer","description":"Number of plugins successfully loaded after reload","minimum":0},"message":{"type":"string","description":"Human-readable status message"},"plugins":{"type":"array","items":{"type":"string"},"description":"Names of loaded plugins"}}},"RemoteDeploymentResponse":{"type":"object","required":["id","project_id","environment_id","slug","state","source_type","created_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"environment_id":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"project_id":{"type":"integer","format":"int32"},"slug":{"type":"string"},"source_type":{"type":"string"},"state":{"type":"string"}}},"RemoveNodeResponse":{"type":"object","required":["id","message"],"properties":{"id":{"type":"integer","format":"int32"},"message":{"type":"string"}}},"RenameConversationRequest":{"type":"object","required":["title"],"properties":{"title":{"type":"string","description":"New human-facing title. Trimmed; must be non-empty after trimming."}}},"RepositoryListQuery":{"type":"object","properties":{"direction":{"type":["string","null"]},"language":{"type":["string","null"]},"owner":{"type":["string","null"]},"page":{"type":["integer","null"],"format":"int64","minimum":0},"per_page":{"type":["integer","null"],"format":"int64","minimum":0},"private":{"type":["boolean","null"]},"search":{"type":["string","null"]},"sort":{"type":["string","null"]}}},"RepositoryListResponse":{"type":"object","required":["repositories","total_count"],"properties":{"repositories":{"type":"array","items":{"$ref":"#/components/schemas/RepositoryResponse"}},"total_count":{"type":"integer","minimum":0}}},"RepositoryPresetResponse":{"type":"object","required":["repository_id","owner","name","presets","calculated_at"],"properties":{"calculated_at":{"type":"string","format":"date-time"},"name":{"type":"string"},"owner":{"type":"string"},"presets":{"type":"array","items":{"$ref":"#/components/schemas/ProjectPresetResponse"}},"repository_id":{"type":"integer","format":"int32"}}},"RepositoryResponse":{"type":"object","required":["id","owner","name","full_name","private","default_branch","created_at","updated_at","pushed_at","git_provider_connection_id"],"properties":{"clone_url":{"type":["string","null"],"description":"HTTPS clone URL (e.g., https://github.com/owner/repo.git)"},"created_at":{"type":"string","format":"date-time"},"default_branch":{"type":"string"},"description":{"type":["string","null"]},"full_name":{"type":"string"},"git_provider_connection_id":{"type":"integer","format":"int32","description":"ID of the git provider connection this repository was synced from."},"id":{"type":"integer","format":"int32"},"language":{"type":["string","null"]},"name":{"type":"string"},"owner":{"type":"string"},"preset":{"type":["array","null"],"items":{"$ref":"#/components/schemas/ProjectPresetResponse"}},"private":{"type":"boolean"},"pushed_at":{"type":"string","format":"date-time"},"ssh_url":{"type":["string","null"],"description":"SSH clone URL (e.g., git@github.com:owner/repo.git)"},"updated_at":{"type":"string","format":"date-time"}}},"RepositorySyncStartedResponse":{"type":"object","description":"Returned by `POST /git-connections/{id}/sync` to acknowledge that a\nsync has been kicked off in the background. Clients should poll the\nconnection's `syncing` and `synced_repository_count` fields to track\nprogress rather than waiting on this response.","required":["connection_id","syncing","started_at"],"properties":{"connection_id":{"type":"integer","format":"int32"},"started_at":{"type":"string","format":"date-time"},"syncing":{"type":"boolean"}}},"RequestRow":{"type":"object","required":["id","ts","method","host","path","status","request_headers","response_headers","headers_truncated"],"properties":{"client_ip":{"type":["string","null"]},"country":{"type":["string","null"]},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"error_group_id":{"type":["integer","null"],"format":"int32"},"headers_truncated":{"type":"boolean"},"host":{"type":"string"},"id":{"type":"string","description":"The request's unique `request_id` (assigned by the proxy). Used as the\nrow identity instead of the storage PK because the ClickHouse backend\nhas no serial id (rows come back with `id = 0`) while `request_id` is\nunique and present on both backends."},"latency_ms":{"type":["integer","null"],"format":"int32"},"method":{"type":"string"},"path":{"type":"string"},"query_string":{"type":["string","null"]},"referrer":{"type":["string","null"]},"request_headers":{},"response_headers":{},"status":{"type":"integer","format":"int32"},"trace_id":{"type":["string","null"]},"ts":{"type":"string","format":"date-time"},"user_agent":{"type":["string","null"]}}},"RequiredPasswordChangeRequest":{"type":"object","required":["new_password"],"properties":{"new_password":{"type":"string"}}},"RequiredPasswordChangeResponse":{"type":"object","required":["success","message","user_id","mfa_enrollment_required"],"properties":{"message":{"type":"string"},"mfa_enrollment_required":{"type":"boolean"},"mfa_setup":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/MfaSetupResponse"}]},"success":{"type":"boolean"},"user_id":{"type":"integer","format":"int32"}}},"ResetPasswordRequest":{"type":"object","required":["token","new_password"],"properties":{"new_password":{"type":"string"},"token":{"type":"string"}}},"ResetPgStatStatementsRequest":{"type":"object","description":"Explicit confirmation required for the destructive statistics reset.\n\nRequiring JSON makes the endpoint non-simple for browsers, preventing a\ndeployed same-site application from triggering it with a plain HTML form.","required":["confirm"],"properties":{"confirm":{"type":"boolean","description":"Must be `true` to acknowledge the global, irreversible reset."}}},"ResetPgStatStatementsResponse":{"type":"object","description":"Response for the pg_stat_statements reset endpoint.","required":["message"],"properties":{"message":{"type":"string","description":"Human-readable message confirming the destructive action."}}},"ResizeSandboxBody":{"type":"object","required":["disk_size_mb"],"properties":{"disk_size_mb":{"type":"integer","format":"int64","description":"New root disk size in MB. Grow-only; must exceed the current size.","minimum":0}},"additionalProperties":false},"ResolvedEnvVarResponse":{"type":"object","description":"One entry in the computed env-var view that merges manual and integration\nsources and tags each result with its origin. `value_preview` is always\nmasked — plaintext must be fetched per-key via the existing reveal endpoint,\nwhich is audit-logged.","required":["key","value_preview","source","environments","include_in_preview"],"properties":{"environments":{"type":"array","items":{"$ref":"#/components/schemas/EnvironmentInfo"},"description":"Environments this var applies to. For integration-sourced vars this\nreflects every environment of the project (integrations are global)."},"include_in_preview":{"type":"boolean","description":"Whether the var would be auto-applied to preview environments.\nIntegration vars always surface in preview; manual vars follow the flag."},"key":{"type":"string"},"source":{"$ref":"#/components/schemas/ResolvedEnvVarSource"},"value_preview":{"type":"string","description":"Masked or truncated preview. Never the raw value."}}},"ResolvedEnvVarSource":{"oneOf":[{"type":"object","description":"Manually-defined env var. If `overrides_service` is set, this key would\notherwise have been supplied by an integration — the UI should show the\nintegration icon plus an \"overridden\" indicator.","required":["var_id","type"],"properties":{"overrides_service":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/EnvVarIntegrationInfo"}]},"type":{"type":"string","enum":["manual"]},"var_id":{"type":"integer","format":"int32"}}},{"type":"object","description":"Supplied by a linked external service (Postgres, Redis, S3, etc.).","required":["service","type"],"properties":{"service":{"$ref":"#/components/schemas/EnvVarIntegrationInfo"},"type":{"type":"string","enum":["integration"]}}}],"description":"Where a resolved env var comes from. Integration-sourced vars may be\n\"shadowed\" by a manual entry with the same key, in which case the response\ncarries `Manual` with `overrides_service` populated so the UI can still show\nthe integration icon."},"ResourceCounts":{"type":"object","description":"Quick count of resources involved in the migration","required":["projects","environments","deployments","environment_variables","services","domains"],"properties":{"deployments":{"type":"integer","minimum":0},"domains":{"type":"integer","minimum":0},"environment_variables":{"type":"integer","minimum":0},"environments":{"type":"integer","minimum":0},"projects":{"type":"integer","minimum":0},"services":{"type":"integer","minimum":0}}},"ResourceFootprint":{"type":"object","description":"A CPU + memory footprint (requests or measured usage)","required":["cpu_millis","memory_mb"],"properties":{"cpu_millis":{"type":"integer","format":"int64","description":"CPU in millicores"},"memory_mb":{"type":"integer","format":"int64","description":"Memory in MB"}}},"ResourceInfo":{"type":"object","description":"Resource attributes extracted from OTel resource descriptors.","required":["service_name","attributes"],"properties":{"attributes":{"type":"object"},"deployment_environment":{"type":["string","null"]},"service_name":{"type":"string"},"service_version":{"type":["string","null"]}}},"ResourceLimitApplyResult":{"type":"object","description":"Per-container outcome of a live `docker update` call. Surfaced from the\nPATCH /resources endpoint so the UI can tell the operator whether the\nnew caps are already in effect or whether they only apply on next\nrecreate (e.g., container was missing).","required":["role","container_name","outcome"],"properties":{"container_name":{"type":"string"},"error":{"type":["string","null"],"description":"Populated only when `outcome == \"failed\"`."},"outcome":{"type":"string","description":"One of:\n- \"applied\" — Docker accepted the update; caps are live now.\n- \"missing\" — container does not exist; caps stored, will apply on next start.\n- \"stopped\" — container exists but isn't running; Docker still\n accepts the update (the new caps apply on next start).\n- \"failed\" — `docker update` returned an error (see `error`)."},"role":{"type":"string","description":"`service_members.role` for cluster members; \"standalone\" otherwise."}}},"ResourceLimits":{"type":"object","description":"Resource limits and requests","properties":{"cpu_limit":{"type":["integer","null"],"format":"int32","description":"CPU limit (millicores)"},"cpu_request":{"type":["integer","null"],"format":"int32","description":"CPU request (millicores)"},"memory_limit":{"type":["integer","null"],"format":"int32","description":"Memory limit (MB)"},"memory_request":{"type":["integer","null"],"format":"int32","description":"Memory request (MB)"}}},"ResourceLimitsResponse":{"type":"object","description":"Container resource limits","properties":{"cpu_limit":{"type":["integer","null"],"format":"int32"},"cpu_request":{"type":["integer","null"],"format":"int32"},"memory_limit":{"type":["integer","null"],"format":"int32"},"memory_request":{"type":["integer","null"],"format":"int32"}}},"ResourceLimitsUpdateResponse":{"type":"object","description":"Response from PATCH /external-services/{id}/resources.","required":["limits","applied"],"properties":{"applied":{"type":"array","items":{"$ref":"#/components/schemas/ResourceLimitApplyResult"},"description":"Per-container result of trying to apply the limits live."},"limits":{"$ref":"#/components/schemas/ServiceResourceLimits","description":"The limits that were persisted to the encrypted config."}}},"ResourcesBody":{"type":"object","description":"Nested `resources: { memory, vcpus }` as sent by `@vercel/sandbox`.\n`memory` is in MB, `vcpus` is fractional CPU count.","properties":{"memory":{"type":["integer","null"],"format":"int64","minimum":0},"vcpus":{"type":["number","null"],"format":"double"}}},"RestoreCapabilities":{"type":"object","description":"Capabilities a service exposes for the generic restore framework.\n\nEach engine overrides `ExternalService::restore_capabilities` to declare\nwhat it supports. The handler layer uses this to validate requests and\nthe UI uses it to conditionally show options (e.g., PITR picker).","required":["restore_in_place","restore_to_new_service","pitr"],"properties":{"earliest_pitr_time":{"type":["string","null"],"format":"date-time","description":"Earliest recoverable timestamp, if `pitr` is true. Derived from\nengine-specific archive metadata (e.g., `pg_stat_archiver`)."},"latest_pitr_time":{"type":["string","null"],"format":"date-time","description":"Latest recoverable timestamp, if `pitr` is true."},"pitr":{"type":"boolean","description":"Point-in-time recovery using engine-specific continuous archives\n(WAL for Postgres, AOF for Redis, oplog for MongoDB, object versions for S3)."},"restore_in_place":{"type":"boolean","description":"Restore a backup onto the same running service (destructive)."},"restore_to_new_service":{"type":"boolean","description":"Restore a backup into a freshly provisioned service."}}},"RestoreCapabilitiesResponse":{"allOf":[{"$ref":"#/components/schemas/RestoreCapabilities","description":"Trait-declared capabilities."},{"type":"object","required":["suggested_new_service_name"],"properties":{"suggested_new_service_name":{"type":"string","description":"Suggested name for the new service when creating a clone. Safe to\npre-fill into the UI dialog; the user can edit before submitting."}}}]},"RestorePlan":{"type":"object","description":"Preview of a restore operation. Answers \"what will happen if I click\nstart?\" with engine-level specificity so the user can confirm before\ncommitting to a destructive action.","required":["engine","target_service","source_backup","strategy","steps","warnings","errors","destructive","mode"],"properties":{"destructive":{"type":"boolean","description":"Whether any step overwrites existing data on the target service."},"engine":{"type":"string","description":"Target engine (\"postgres\", etc.)."},"errors":{"type":"array","items":{"type":"string"},"description":"Blocking problems. The UI disables the Start button when non-empty."},"mode":{"type":"string","description":"Echo of the requested mode for the UI."},"source_backup":{"$ref":"#/components/schemas/PlanSourceBackup","description":"Backup we'll read from."},"steps":{"type":"array","items":{"type":"string"},"description":"Ordered list of human-readable actions the orchestrator will take."},"strategy":{"type":"string","description":"How the restore will be performed: \"walg_restore\", \"pg_dump_restore\",\nor \"unsupported\"."},"target_service":{"$ref":"#/components/schemas/PlanTarget","description":"Service we'll operate on (or provision a sibling of)."},"warnings":{"type":"array","items":{"type":"string"},"description":"Non-blocking caveats the user should see (cross-service, empty\nlocation that will be auto-resolved, missing engine metadata, ...)."}}},"RestoreRequestMode":{"oneOf":[{"type":"object","description":"Restore the backup onto the existing service (destructive).","required":["mode"],"properties":{"mode":{"type":"string","enum":["in_place"]}}},{"type":"object","description":"Provision a new service and restore into it.","required":["name","mode"],"properties":{"mode":{"type":"string","enum":["new_service"]},"name":{"type":"string","description":"Name for the new service. Orchestrator auto-suggests\n`{source}-restore-{yyyymmdd-hhmm}` if caller omits, but we require\nan explicit value at the API boundary."},"parameter_overrides":{"description":"Optional parameter overrides (port, docker_image, database)."}}},{"type":"object","description":"Point-in-time recovery. Only valid on WAL-G backups (Postgres).","required":["to_new_service","target","mode"],"properties":{"mode":{"type":"string","enum":["pitr"]},"new_service_name":{"type":["string","null"],"description":"Required when `to_new_service` is true."},"target":{"$ref":"#/components/schemas/RecoveryTarget","description":"Recovery target kind + value."},"to_new_service":{"type":"boolean","description":"Whether PITR restores in place or creates a new service."}}}],"description":"What the caller wants to do. Mirrors `externalsvc::RestoreMode` but\nflattened for JSON over the wire."},"RestoreRunView":{"type":"object","required":["id","source_backup_id","source_service_id","mode","status","phase","created_at"],"properties":{"created_at":{"type":"string"},"error_message":{"type":["string","null"]},"finished_at":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"mode":{"type":"string"},"phase":{"type":"string"},"recovery_target":{},"source_backup_id":{"type":"integer","format":"int32"},"source_service_id":{"type":"integer","format":"int32"},"started_at":{"type":["string","null"]},"status":{"type":"string"},"target_service_id":{"type":["integer","null"],"format":"int32"},"target_service_name":{"type":["string","null"]}}},"RetentionCleanupFailure":{"type":"object","required":["backup_id","reason","partial","deleted_objects"],"properties":{"backup_id":{"type":"string"},"deleted_objects":{"type":"integer","format":"int64","minimum":0},"partial":{"type":"boolean"},"reason":{"type":"string"}}},"RetentionCleanupReport":{"type":"object","required":["dry_run","expired","deleted","failed","failures","deleted_backup_ids","deleted_backup_ids_truncated","partially_deleted_backup_ids","partially_deleted_backup_ids_truncated","candidate_backup_ids","candidate_backup_ids_truncated"],"properties":{"candidate_backup_ids":{"type":"array","items":{"type":"string"},"description":"Capped sample of backups selected by the retention policy."},"candidate_backup_ids_truncated":{"type":"boolean"},"deleted":{"type":"integer","format":"int64","minimum":0},"deleted_backup_ids":{"type":"array","items":{"type":"string"},"description":"Capped sample of deleted backup UUIDs for audit attribution."},"deleted_backup_ids_truncated":{"type":"boolean"},"dry_run":{"type":"boolean","description":"True when this report is a non-destructive preview."},"expired":{"type":"integer","format":"int64","minimum":0},"failed":{"type":"integer","format":"int64","minimum":0},"failures":{"type":"array","items":{"$ref":"#/components/schemas/RetentionCleanupFailure"},"description":"Capped diagnostic sample; `failed` remains the authoritative total."},"partially_deleted_backup_ids":{"type":"array","items":{"type":"string"}},"partially_deleted_backup_ids_truncated":{"type":"boolean"},"schedule_id":{"type":["integer","null"],"format":"int32","description":"Schedule scope, or `None` when every schedule was considered."}}},"RetryClusterRequest":{"type":"object","description":"Request body for retrying a failed cluster initialization.","properties":{"members":{"type":"array","items":{"$ref":"#/components/schemas/ClusterMemberRequest"},"description":"Cluster member specifications (same format as create).\nIf omitted, the original member configuration is reconstructed from\nthe preserved service_members records."}}},"RevenueRow":{"type":"object","required":["id","ts","provider","event_type"],"properties":{"amount_minor":{"type":["integer","null"],"format":"int64"},"currency":{"type":["string","null"]},"customer_ref":{"type":["string","null"]},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"event_type":{"type":"string"},"id":{"type":"integer","format":"int64"},"provider":{"type":"string"},"trace_id":{"type":["string","null"]},"ts":{"type":"string","format":"date-time"}}},"RiskLevel":{"type":"string","description":"Risk level for a migration step","enum":["none","low","medium","high","critical"]},"RoleInfo":{"type":"object","description":"Information about a role","required":["name","description","permissions"],"properties":{"description":{"type":"string","description":"Human-readable description of the role"},"name":{"type":"string","description":"The role identifier (e.g., \"admin\")"},"permissions":{"type":"array","items":{"type":"string"},"description":"Permissions included in this role"}}},"RootfsCacheEntry":{"type":"object","description":"A cached rootfs image (Firecracker backend). Digest-keyed build artifact\nshared by all VMs created from the same image.","required":["digest","bytes","referenced_by"],"properties":{"bytes":{"type":"integer","format":"int64","description":"Actual on-disk size in bytes (sparse-aware).","minimum":0},"digest":{"type":"string","description":"Image digest this rootfs was built from (the cache key)."},"referenced_by":{"type":"array","items":{"type":"string"},"description":"IDs of live sandboxes whose per-VM disk was cloned from this entry.\nEmpty means the entry is reclaimable — no sandbox needs it."}}},"RootfsGcReport":{"type":"object","description":"Outcome of a rootfs garbage-collection pass.","required":["removed_digests","freed_bytes"],"properties":{"freed_bytes":{"type":"integer","format":"int64","minimum":0},"removed_digests":{"type":"array","items":{"type":"string"},"description":"Digests of cache entries removed because no sandbox referenced them."}}},"RootfsReport":{"type":"object","description":"Snapshot of a backend's rootfs storage for the management API. Backends\nwithout a rootfs concept (Docker, local) return an empty report.","required":["cache_bytes","cache","vm_bytes","vms"],"properties":{"cache":{"type":"array","items":{"$ref":"#/components/schemas/RootfsCacheEntry"}},"cache_bytes":{"type":"integer","format":"int64","minimum":0},"vm_bytes":{"type":"integer","format":"int64","minimum":0},"vms":{"type":"array","items":{"$ref":"#/components/schemas/RootfsVmEntry"}}}},"RootfsVmEntry":{"type":"object","description":"A per-sandbox rootfs disk (Firecracker backend). One per non-destroyed\nsandbox — the authoritative storage, independent of the cache.","required":["sandbox_name","bytes","running"],"properties":{"bytes":{"type":"integer","format":"int64","minimum":0},"running":{"type":"boolean"},"sandbox_name":{"type":"string"}}},"RouteRefreshResponse":{"type":"object","required":["route_count","message"],"properties":{"message":{"type":"string","description":"Human-readable message"},"route_count":{"type":"integer","description":"Number of routes loaded","minimum":0}}},"RouteResponse":{"type":"object","required":["id","domain","host","port","enabled","route_type","created_at","updated_at"],"properties":{"created_at":{"type":"integer","format":"int64"},"domain":{"type":"string"},"enabled":{"type":"boolean"},"host":{"type":"string"},"id":{"type":"integer","format":"int32"},"port":{"type":"integer","format":"int32"},"route_type":{"type":"string","description":"Route type: \"http\" or \"tls\""},"updated_at":{"type":"integer","format":"int64"}}},"RouteRole":{"type":"object","required":["id","name","created_at","updated_at"],"properties":{"created_at":{"type":"integer","format":"int64","example":"1683900000000"},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"updated_at":{"type":"integer","format":"int64","example":"1683900000000"}}},"RouteUser":{"type":"object","required":["id","name","username","email","image","mfa_enabled","email_verified","must_change_password","created_at","updated_at"],"properties":{"created_at":{"type":"integer","format":"int64","example":"1683900000000"},"deleted_at":{"type":["integer","null"],"format":"int64"},"email":{"type":"string"},"email_verified":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"image":{"type":"string"},"mfa_enabled":{"type":"boolean"},"must_change_password":{"type":"boolean"},"name":{"type":"string"},"updated_at":{"type":"integer","format":"int64","example":"1683900000000"},"username":{"type":"string"}}},"RouteUserWithRoles":{"type":"object","required":["user","roles"],"properties":{"roles":{"type":"array","items":{"$ref":"#/components/schemas/RouteRole"}},"user":{"$ref":"#/components/schemas/RouteUser"}}},"RunBackupRequest":{"type":"object","required":["backup_type"],"properties":{"backup_type":{"type":"string","description":"Type of backup to perform","example":"full"}}},"RunExternalServiceBackupRequest":{"type":"object","properties":{"backup_type":{"type":["string","null"],"description":"Type of backup to perform (e.g., \"full\", \"incremental\")","example":"full"},"s3_source_id":{"type":["integer","null"],"format":"int32","description":"ID of the S3 source to store the backup. If omitted, the current default S3 source is used.","example":1}}},"S3ConnectionTestResponse":{"type":"object","description":"Response body for an S3 connection test.","required":["ok","message"],"properties":{"message":{"type":"string","description":"Human-readable message (success confirmation or error detail)."},"ok":{"type":"boolean","description":"Whether the connection and credentials worked."}}},"S3CredentialsResponse":{"type":"object","description":"S3 credentials distributed to agents for backup/restore operations.","required":["access_key_id","secret_key","region","bucket_name","force_path_style"],"properties":{"access_key_id":{"type":"string"},"bucket_name":{"type":"string"},"endpoint":{"type":["string","null"]},"force_path_style":{"type":"boolean"},"region":{"type":"string"},"secret_key":{"type":"string"}}},"S3SourceResponse":{"type":"object","description":"Response type for S3 source","required":["id","name","bucket_name","bucket_path","access_key_id","secret_key","region","is_default","created_at","updated_at"],"properties":{"access_key_id":{"type":"string","example":"AKIAXXXXXXXXXXXXXXXX"},"bucket_name":{"type":"string"},"bucket_path":{"type":"string"},"created_at":{"type":"integer","format":"int64"},"endpoint":{"type":["string","null"],"example":"http://minio.example.com:9000"},"force_path_style":{"type":["boolean","null"]},"id":{"type":"integer","format":"int32"},"is_default":{"type":"boolean"},"name":{"type":"string"},"region":{"type":"string"},"secret_key":{"type":"string","writeOnly":true},"updated_at":{"type":"integer","format":"int64"}}},"SandboxDomainResponse":{"type":"object","required":["url"],"properties":{"url":{"type":"string"}}},"SandboxEvent":{"type":"object","description":"One entry in a sandbox's operations timeline.","required":["event_type","at"],"properties":{"at":{"type":"integer","format":"int64","description":"Unix epoch milliseconds."},"detail":{"description":"Optional structured context (shape depends on `event_type`)."},"event_type":{"type":"string","description":"Machine-readable operation (`created`, `stopped`, `resumed`,\n`restarted`, `timeout_extended`, `resized`, `preview_password_set`,\n`preview_password_cleared`, `preview_share_link_created`, `source_seeded`,\n`destroyed`)."}}},"SandboxEventsResponse":{"type":"object","required":["events"],"properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/SandboxEvent"}}}},"SandboxInner":{"type":"object","description":"Inner `sandbox` object in `@vercel/sandbox` responses. Strict shape —\nthe SDK's zod validator rejects missing required fields.","required":["id","memory","vcpus","region","runtime","timeout","status","requestedAt","createdAt","updatedAt","cwd","name","preview_url_template"],"properties":{"agent_run_id":{"type":["integer","null"],"format":"int32","description":"Agent run this sandbox executes (autofixer / workflow agent).\n`None` for sandboxes created via this API."},"backend":{"type":["string","null"],"description":"Isolation backend: \"docker\" | \"firecracker\". `None` on legacy rows\ncreated before the backend was recorded."},"createdAt":{"type":"integer","format":"int64"},"cwd":{"type":"string"},"disk_size_mb":{"type":["integer","null"],"format":"int64","description":"Configured root disk size in MB (Firecracker). `None` when unknown or\nthe default.","minimum":0},"id":{"type":"string"},"image":{"type":["string","null"]},"memory":{"type":"integer","format":"int64","minimum":0},"name":{"type":"string"},"preview_password_hint":{"type":["string","null"]},"preview_url_template":{"type":"string"},"region":{"type":"string"},"requestedAt":{"type":"integer","format":"int64","description":"Creation time as Unix epoch milliseconds."},"runtime":{"type":"string"},"status":{"type":"string"},"timeout":{"type":"integer","format":"int64","description":"Idle timeout in milliseconds (SDK convention).","minimum":0},"updatedAt":{"type":"integer","format":"int64"},"vcpus":{"type":"number","format":"double"}}},"SandboxResponse":{"type":"object","description":"`@vercel/sandbox` wraps every single-sandbox response as\n`{ sandbox: {...}, routes: [...] }`. The SDK reads both.","required":["sandbox","routes"],"properties":{"routes":{"type":"array","items":{"$ref":"#/components/schemas/SandboxRoute"}},"sandbox":{"$ref":"#/components/schemas/SandboxInner"}}},"SandboxRoute":{"type":"object","description":"A single preview route, one per declared port. We don't know ports\nupfront, so we surface an empty array by default — SDK clients use\ntheir own port when calling `sandbox.domain(port)`.","required":["url","subdomain","port"],"properties":{"port":{"type":"integer","format":"int32","minimum":0},"subdomain":{"type":"string"},"url":{"type":"string"}}},"SandboxStatusResponse":{"type":"object","required":["docker_available","image_ready","image_name","firecracker_available"],"properties":{"docker_available":{"type":"boolean"},"error":{"type":["string","null"]},"firecracker_available":{"type":"boolean"},"image_name":{"type":"string"},"image_ready":{"type":"boolean"}}},"SaveAgentTokenRequest":{"type":"object","required":["token"],"properties":{"token":{"type":"string","description":"The OAuth token from `claude setup-token` or an API key.\nWill be encrypted before storage."}}},"SaveAgentTokenResponse":{"type":"object","required":["saved"],"properties":{"saved":{"type":"boolean"}}},"SaveCredentialRequest":{"type":"object","required":["auth_type","credential"],"properties":{"auth_type":{"type":"string","description":"Auth flavor id (must match one of the provider's catalog entries)."},"credential":{"type":"string","description":"Plaintext credential body (API key, OAuth token, or full config file\ncontents). Encrypted with `EncryptionService` before being persisted\ninside the `agent_sandbox.providers` JSON map."}}},"SaveCredentialResponse":{"type":"object","required":["saved","provider_id","auth_type"],"properties":{"auth_type":{"type":"string"},"provider_id":{"type":"string"},"saved":{"type":"boolean"}}},"ScalewayCredentialsRequest":{"type":"object","required":["api_key","project_id"],"properties":{"api_key":{"type":"string","example":"scw-secret-key-12345"},"project_id":{"type":"string","example":"12345678-1234-1234-1234-123456789012"}}},"ScanResponse":{"type":"object","required":["id","project_id","scanner_type","status","total_count","critical_count","high_count","medium_count","low_count","unknown_count","started_at","created_at","updated_at"],"properties":{"branch":{"type":["string","null"]},"commit_hash":{"type":["string","null"]},"completed_at":{"type":["string","null"],"example":"2025-12-08T12:15:47.609192Z"},"created_at":{"type":"string","example":"2025-12-08T12:15:47.609192Z"},"critical_count":{"type":"integer","format":"int32"},"deployment_id":{"type":["integer","null"],"format":"int32"},"environment_id":{"type":["integer","null"],"format":"int32"},"error_message":{"type":["string","null"]},"high_count":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"low_count":{"type":"integer","format":"int32"},"medium_count":{"type":"integer","format":"int32"},"project_id":{"type":"integer","format":"int32"},"scanner_type":{"type":"string"},"scanner_version":{"type":["string","null"]},"started_at":{"type":"string","example":"2025-12-08T12:15:47.609192Z"},"status":{"type":"string"},"total_count":{"type":"integer","format":"int32"},"unknown_count":{"type":"integer","format":"int32"},"updated_at":{"type":"string","example":"2025-12-08T12:15:47.609192Z"}}},"ScheduleRunEntry":{"type":"object","description":"A single run-history entry for the schedule detail page (deliverable 1).\n\nCombines one `backups` row with the most-recent `backup_jobs` row for that\nbackup via a lateral JOIN. Fields from `backup_jobs` are `None` for legacy\nbackup rows that pre-date ADR-014.","required":["backup_id","backup_uuid","state","started_at","s3_location"],"properties":{"attempts":{"type":["integer","null"],"format":"int32","description":"Number of claim-and-run attempts so far. `None` for legacy rows."},"backup_id":{"type":"integer","format":"int32","description":"DB id of the `backups` row."},"backup_uuid":{"type":"string","description":"UUID string (`backups.backup_id`)."},"current_step":{"type":["string","null"],"description":"Last completed step reported by the engine (e.g. `\"upload\"`).\n`None` when no step has been persisted yet."},"error_message":{"type":["string","null"],"description":"Engine-reported error message when `state = \"failed\"`."},"finished_at":{"type":["string","null"],"description":"When the backup finished, if known."},"job_id":{"type":["integer","null"],"format":"int64","description":"Most recent `backup_jobs.id` for this backup. `None` for legacy rows."},"s3_location":{"type":"string","description":"S3 object key or URL where the backup data lives."},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Final size in bytes once completed. `None` while running."},"started_at":{"type":"string","description":"When the backup was started (ISO 8601 / RFC 3339)."},"state":{"type":"string","description":"Current state: `\"pending\"`, `\"running\"`, `\"completed\"`, `\"failed\"`."}}},"ScheduleRunJobEntry":{"type":"object","description":"A single job entry inside an expanded schedule run, returned by\n[`BackupService::list_schedule_run_jobs`].","required":["backup_id","backup_uuid","engine","service_name","state","started_at","s3_source_id"],"properties":{"backup_id":{"type":"integer","format":"int32","description":"`backups.id` for this job."},"backup_uuid":{"type":"string","description":"`backups.backup_id` UUID string."},"engine":{"type":"string","description":"Engine key (e.g. `\"control_plane\"`, `\"redis\"`)."},"error_message":{"type":["string","null"],"description":"Engine-reported error message when `state = \"failed\"`."},"finished_at":{"type":["string","null"],"description":"When this child backup finished, if known."},"s3_source_id":{"type":"integer","format":"int32","description":"FK to `s3_sources.id` — needed for the backup detail link."},"service_id":{"type":["integer","null"],"format":"int32","description":"`external_services.id` — `NULL` for the control-plane job."},"service_name":{"type":"string","description":"Name of the external service, or `\"control plane\"` for the\ncontrol-plane job."},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Size in bytes once completed; `None` while running."},"started_at":{"type":"string","description":"When this child backup started (ISO 8601 / RFC 3339)."},"state":{"type":"string","description":"Current state of this child backup."}}},"ScheduleRunListResponse":{"type":"object","description":"Paginated run-history response for a backup schedule (deliverable 1).","required":["runs","total","page","page_size"],"properties":{"page":{"type":"integer","format":"int64","description":"Current page (1-based)."},"page_size":{"type":"integer","format":"int64","description":"Number of items per page (clamped to 1–100)."},"runs":{"type":"array","items":{"$ref":"#/components/schemas/ScheduleRunEntry"},"description":"Run entries, newest first."},"total":{"type":"integer","format":"int64","description":"Total number of runs across all pages."}}},"ScheduleRunResponse":{"type":"object","description":"HTTP response body for `POST /api/backups/schedules/{id}/run` (fan-out).","required":["schedule_run_id","jobs"],"properties":{"jobs":{"type":"array","items":{"$ref":"#/components/schemas/EnqueuedJob"},"description":"All jobs that were enqueued in this fan-out."},"schedule_run_id":{"type":"integer","format":"int64","description":"The `schedule_runs.id` of the newly created run."}}},"ScheduleRunSummary":{"type":"object","description":"Summary of one scheduler tick (or one \"Run now\" click), returned by\n[`BackupService::list_schedule_runs`].\n\nThe `aggregate_state` is computed at read time from child backup counts:\n- `\"running\"` — at least one child is `\"pending\"` or `\"running\"`.\n- `\"failed\"` — at least one child is `\"failed\"` and none are running.\n- `\"completed\"` — all children are `\"completed\"`.","required":["run_id","schedule_id","triggered_by","started_at","aggregate_state","total_jobs","completed_jobs","failed_jobs","running_jobs","pending_jobs"],"properties":{"aggregate_state":{"type":"string","description":"Aggregate state computed from child counts (see struct docs)."},"completed_jobs":{"type":"integer","format":"int64","description":"Number of children in `state = \"completed\"`."},"failed_jobs":{"type":"integer","format":"int64","description":"Number of children in `state = \"failed\"`."},"finished_at":{"type":["string","null"],"description":"When all children reached a terminal state. `None` while any child is\nstill `\"pending\"` or `\"running\"`."},"pending_jobs":{"type":"integer","format":"int64","description":"Number of children in `state = \"pending\"`."},"run_id":{"type":"integer","format":"int64","description":"`schedule_runs.id` for this tick."},"running_jobs":{"type":"integer","format":"int64","description":"Number of children in `state = \"running\"`."},"schedule_id":{"type":"integer","format":"int32","description":"FK to `backup_schedules.id`."},"started_at":{"type":"string","description":"When the fan-out started (ISO 8601 / RFC 3339)."},"total_jobs":{"type":"integer","format":"int64","description":"Total number of child backup jobs in this run."},"triggered_by":{"type":"string","description":"How the run was triggered: `\"cron\"` or `\"manual\"`."}}},"ScheduleRunSummaryList":{"type":"object","description":"Paginated list of schedule run summaries returned by the new\n[`BackupService::list_schedule_runs`].","required":["runs","total","page","page_size"],"properties":{"page":{"type":"integer","format":"int64","description":"Current page (1-based)."},"page_size":{"type":"integer","format":"int64","description":"Number of items per page."},"runs":{"type":"array","items":{"$ref":"#/components/schemas/ScheduleRunSummary"},"description":"Run summaries, newest first. Includes synthetic single-job rows for\nlegacy `backups` rows that have `schedule_id` set but no\n`schedule_run_id` (pre-fan-out history)."},"total":{"type":"integer","format":"int64","description":"Total number of run entries across all pages."}}},"ScreenshotSettings":{"type":"object","properties":{"enabled":{"type":"boolean","default":false},"provider":{"type":"string","default":"local"},"url":{"type":"string","default":""}}},"SearchLogsRequest":{"type":"object","required":["project_id"],"properties":{"container_ids":{"type":"array","items":{"type":"string"},"description":"Filter to specific containers (Docker container IDs). Empty = all\ncontainers. Drives \"filter by container / show all\" in a project's\nhistory, which spans multiple deployments and containers."},"context_lines":{"type":["integer","null"],"format":"int32","description":"grep -C: number of raw context lines to include before and after each\nmatch (0 = none, default). Clamped to 50 server-side. The surrounding\nlines ignore the level/text filters — they are the actual adjacent log\nlines, merged across overlapping matches.","minimum":0},"cursor":{"type":["string","null"],"description":"Pagination cursor"},"deploy_id":{"type":["integer","null"],"format":"int32","description":"Filter by deployment ID (deployments.id)"},"end_time":{"type":["string","null"],"description":"End of time range (ISO 8601). Defaults to now."},"envs":{"type":"array","items":{"type":"string"},"description":"Filter by environments"},"external_service_id":{"type":["integer","null"],"format":"int32","description":"When set, search an imported/managed external service's logs instead\nof a project's. `project_id` is ignored in this mode."},"levels":{"type":"array","items":{"type":"string"},"description":"Filter by log levels"},"node_ids":{"type":"array","items":{"type":"integer","format":"int32"},"description":"Filter to specific worker nodes (node_id). Empty = all nodes, including\ncontrol-plane-local logs."},"page_size":{"type":["integer","null"],"format":"int32","description":"Page size (default: 100, max: 500)","minimum":0},"project_id":{"type":"integer","format":"int32","description":"Project ID (integer, as used by the rest of the platform)"},"services":{"type":"array","items":{"type":"string"},"description":"Filter by services"},"start_time":{"type":["string","null"],"description":"Start of time range (ISO 8601). Defaults to 1 hour ago."},"text":{"type":["string","null"],"description":"Full text search query"}}},"SearchLogsResponse":{"type":"object","required":["lines","search_mode","total_scanned"],"properties":{"available_sources":{"type":"array","items":{"$ref":"#/components/schemas/LogSource"},"description":"Distinct containers/nodes/services available in the queried scope, for\nthe filter dropdowns. Populated on the first page (no cursor)."},"lines":{"type":"array","items":{"$ref":"#/components/schemas/LogSearchLine"}},"next_cursor":{"type":["string","null"]},"search_mode":{"$ref":"#/components/schemas/SearchMode"},"total_scanned":{"type":"integer","format":"int64","minimum":0}}},"SearchMode":{"type":"string","description":"Search execution mode","enum":["index","archive"]},"Seasonality":{"type":"string","description":"Seasonality model for an anomaly baseline.","enum":["none","hourly","daily","weekly"]},"SecretResponse":{"type":"object","required":["id","name","secret_type","value","created_at","updated_at"],"properties":{"created_at":{"type":"string"},"description":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"mount_path":{"type":["string","null"]},"name":{"type":"string"},"secret_type":{"type":"string"},"updated_at":{"type":"string"},"value":{"type":"string","description":"Always masked in responses"}}},"SecurityConfig":{"type":"object","description":"Security configuration for projects and environments\n\nThis configuration can be set at three levels:\n1. Global (in settings table) - applies to all projects\n2. Project level - overrides global settings for specific project\n3. Environment level - overrides project settings for specific environment\n\nThe inheritance chain: Environment > Project > Global","properties":{"attackMode":{"type":["string","null"],"description":"Attack mode configuration (future: \"off\", \"challenge\", \"block\")\nPlaceholder for DDoS protection, bot detection, etc."},"challengeConfig":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ChallengeConfig","description":"Challenge configuration (future: CAPTCHA, JS challenge, etc.)"}]},"enabled":{"type":["boolean","null"],"description":"Enable/disable security features at this level\nIf None, inherits from parent level"},"geoRestrictions":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/GeoRestrictionsConfig","description":"Geographic restrictions (future: country blocking, etc.)"}]},"headers":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SecurityHeadersConfig","description":"Security headers configuration"}]},"passwordProtection":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PasswordProtectionConfig","description":"Password protection: shows an HTML password form before allowing access"}]},"rateLimiting":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/RateLimitConfig","description":"Rate limiting configuration"}]}}},"SecurityHeadersConfig":{"type":"object","description":"Security headers configuration (subset of global SecurityHeadersSettings)","properties":{"contentSecurityPolicy":{"type":["string","null"],"description":"Custom CSP (only used if preset is \"custom\")"},"preset":{"type":["string","null"],"description":"Use a preset: \"strict\", \"moderate\", \"permissive\", \"disabled\", \"custom\""},"referrerPolicy":{"type":["string","null"],"description":"Referrer-Policy override"},"strictTransportSecurity":{"type":["string","null"],"description":"HSTS override"},"xFrameOptions":{"type":["string","null"],"description":"X-Frame-Options override"}}},"SecurityHeadersSettings":{"type":"object","properties":{"content_security_policy":{"type":["string","null"],"default":"default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self'; frame-ancestors 'self'"},"enabled":{"type":"boolean","default":false},"permissions_policy":{"type":["string","null"],"default":"geolocation=(), microphone=(), camera=()"},"preset":{"type":"string","default":"moderate"},"referrer_policy":{"type":"string","default":"strict-origin-when-cross-origin"},"strict_transport_security":{"type":"string","default":"max-age=31536000; includeSubDomains"},"x_content_type_options":{"type":"string","default":"nosniff"},"x_frame_options":{"type":"string","default":"SAMEORIGIN"},"x_xss_protection":{"type":"string","default":"1; mode=block"}}},"SelfUpdateAttempt":{"type":"object","description":"A single update attempt. Persisted to `/self-update.json` so the\nresult survives the restart it causes.","required":["from_version","status","started_at"],"properties":{"error":{"type":["string","null"],"description":"Operator-facing failure reason. Always set when `status` is `Failed`."},"finished_at":{"type":["string","null"],"format":"date-time","description":"When the outcome was decided. `None` while still `Pending`."},"from_version":{"type":"string","description":"Version the attempt started from."},"previous_binary_path":{"type":["string","null"],"description":"Where the replaced binary was kept, so a bad release can be reverted by\nhand (`mv `). Set once the swap completes."},"started_at":{"type":"string","format":"date-time","example":"2026-08-06T09:12:31Z"},"status":{"$ref":"#/components/schemas/SelfUpdateStatus"},"to_version":{"type":["string","null"],"description":"Version the attempt targeted. `None` if it failed before resolving one."},"triggered_by_user_id":{"type":["integer","null"],"format":"int32","description":"User who clicked the button. `None` for attempts started by the CLI."}}},"SelfUpdateBlocker":{"type":"string","description":"Why a one-click update is unavailable. Exactly one is reported — the most\nfundamental blocker wins, so the operator fixes the real problem first\nrather than clearing one only to hit the next.","enum":["disabled_by_flag","disabled_by_setting","not_supported","binary_not_writable","unsupported_platform","in_progress"]},"SelfUpdatePhase":{"type":"string","description":"Where an in-flight update has got to. Polled by the console so a long\ndownload shows progress instead of an indefinite spinner.","enum":["idle","resolving","downloading","verifying","installing","restarting","pending_restart","failed"]},"SelfUpdateRestartMode":{"type":"string","description":"What happens to the running process once the new binary is in place.","enum":["automatic","manual"]},"SelfUpdateSettings":{"type":"object","description":"Controls the console's one-click \"Update now\" action.","properties":{"channel":{"type":["string","null"],"description":"Release channel this install tracks: `stable`, `beta` or `nightly`.\n\n`None` (the default) means \"infer from the running version tag\", which\nis what the CLI has always done — a `-nightly.` build tracks nightly, a\n`-beta.N` build tracks beta, a plain tag tracks stable. Setting it\nexplicitly pins the channel, so an operator can move a nightly box back\nonto stable without reinstalling.","default":null,"example":"stable"},"enabled":{"type":"boolean","description":"Allow admins to apply a release and restart the server from the console.\n`true` by default: the action is permission-gated, audited, and only\never installs an official release whose published SHA-256 matches.\n\nTurning this off hides nothing — the console still shows the update\nbanner and the manual command, it just refuses to run it for you.","default":true,"example":true}}},"SelfUpdateStatus":{"type":"string","description":"Outcome of an update attempt, as persisted in the journal.","enum":["pending","succeeded","installed_pending_restart","failed"]},"SendEmailRequestBody":{"type":"object","required":["from","to","subject"],"properties":{"bcc":{"type":["array","null"],"items":{"type":"string"},"description":"BCC recipients"},"cc":{"type":["array","null"],"items":{"type":"string"},"description":"CC recipients"},"from":{"type":"string","description":"Sender email address (domain will be auto-extracted for lookup)","example":"hello@updates.example.com"},"from_name":{"type":["string","null"],"description":"Sender display name","example":"My App"},"headers":{"type":["object","null"],"description":"Custom headers","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"html":{"type":["string","null"],"description":"HTML body content","example":"

Hello World

"},"reply_to":{"type":["string","null"],"description":"Reply-to address"},"subject":{"type":"string","description":"Email subject","example":"Welcome to our platform!"},"tags":{"type":["array","null"],"items":{"type":"string"},"description":"Tags for categorization","example":["welcome","onboarding"]},"text":{"type":["string","null"],"description":"Plain text body content","example":"Hello World"},"to":{"type":"array","items":{"type":"string"},"description":"Recipient email addresses","example":["user@example.com"]},"track_clicks":{"type":["boolean","null"],"description":"Enable click tracking (link rewriting). Defaults to false."},"track_opens":{"type":["boolean","null"],"description":"Enable open tracking (tracking pixel injection). Defaults to false."}}},"SendEmailResponseBody":{"type":"object","required":["id","status"],"properties":{"id":{"type":"string","description":"Email ID","example":"550e8400-e29b-41d4-a716-446655440000"},"provider_message_id":{"type":["string","null"],"description":"Provider message ID"},"status":{"type":"string","description":"Email status","example":"sent"}}},"SendMessageRequest":{"type":"object","required":["content"],"properties":{"content":{"type":"string"},"page_context":{"type":["string","null"],"description":"Optional, client-supplied description of the page/entity the user is\ncurrently viewing (e.g. a trace in a project). Injected into the model's\nview of this turn only — never stored or shown in history. Capped server\nside; oversized values are ignored rather than rejected."}}},"SensitiveConfigValueResponse":{"type":"object","required":["value"],"properties":{"value":{"type":"string"}}},"SensitiveMcpConfigValueResponse":{"type":"object","required":["value"],"properties":{"value":{"type":"string"}}},"SensitiveValueResponse":{"type":"object","required":["value"],"properties":{"value":{"type":"string"}}},"SentryChunkUploadResponse":{"type":"object","required":["url","chunkSize","chunksPerRequest","maxFileSize","maxRequestSize","concurrency","hashAlgorithm","compression","accept"],"properties":{"accept":{"type":"array","items":{"type":"string"}},"chunkSize":{"type":"integer","format":"int64","minimum":0},"chunksPerRequest":{"type":"integer","format":"int32","minimum":0},"compression":{"type":"array","items":{"type":"string"}},"concurrency":{"type":"integer","format":"int32","minimum":0},"hashAlgorithm":{"type":"string"},"maxFileSize":{"type":"integer","format":"int64","minimum":0},"maxRequestSize":{"type":"integer","format":"int64","minimum":0},"url":{"type":"string"}}},"SentryCreateReleaseRequest":{"type":"object","required":["version"],"properties":{"projects":{"type":"array","items":{"type":"string"},"description":"Project slugs this release belongs to"},"version":{"type":"string","description":"Release version identifier"}}},"SentryEventRequest":{"type":"object","properties":{"event_id":{"type":["string","null"]},"message":{"type":["string","null"]},"platform":{"type":["string","null"]},"timestamp":{"type":["string","null"]}}},"SentryEventResponse":{"type":"object","required":["id"],"properties":{"id":{"type":"string"}}},"SentryReleaseFileResponse":{"type":"object","required":["id","name","headers","size","sha1","dateCreated"],"properties":{"dateCreated":{"type":"string"},"dist":{"type":["string","null"]},"headers":{},"id":{"type":"string"},"name":{"type":"string"},"sha1":{"type":"string"},"size":{"type":"integer","format":"int64"}}},"SentryReleaseProjectRef":{"type":"object","required":["name","slug"],"properties":{"name":{"type":"string"},"slug":{"type":"string"}}},"SentryReleaseResponse":{"type":"object","required":["version","dateCreated","shortVersion","projects"],"properties":{"dateCreated":{"type":"string"},"dateReleased":{"type":["string","null"]},"projects":{"type":"array","items":{"$ref":"#/components/schemas/SentryReleaseProjectRef"}},"shortVersion":{"type":"string"},"version":{"type":"string"}}},"SeriesStateEntry":{"type":"object","description":"One series' persisted state snapshot for a dynamic rule (ADR-026 follow-up):\nthe state after the latest tick, the value evaluated this tick, and the open\nalarm id (when firing). Serialized into the `series_states` jsonb column keyed\nby the human-readable [`series_label`]; the alert response decodes it back.","required":["state","value"],"properties":{"alarm_id":{"type":["integer","null"],"format":"int32","description":"The open alarm's id when the series is firing; `null` when ok."},"state":{"type":"string","description":"`firing` or `ok` for this series after the latest tick."},"value":{"type":"number","format":"double","description":"The value the rule evaluated for this series this tick."}}},"ServiceAccessInfo":{"type":"object","description":"Response containing information about how the service is being accessed","required":["access_mode","can_create_domains"],"properties":{"access_mode":{"type":"string","description":"Mode of access: \"local\", \"direct\", \"nat\", or \"cloudflare_tunnel\""},"can_create_domains":{"type":"boolean","description":"Whether domain creation is allowed in this mode"},"domain_creation_error":{"type":["string","null"],"description":"Error message if domain creation is not allowed"},"private_ip":{"type":["string","null"],"description":"Server's private/local IP address (always returned if available)"},"public_ip":{"type":["string","null"],"description":"Server's public IP address (always returned if available)"}}},"ServiceAction":{"type":"string","description":"What to do with a service during migration","enum":["create","link-external","skip"]},"ServiceAlertRuleResponse":{"type":"object","description":"Wire representation of a monitoring alert rule.\n\nRegistered under a domain-prefixed OpenAPI schema name to avoid colliding\nwith `temps-error-tracking`'s unrelated `AlertRuleResponse` (utoipa keys\nschemas by their bare struct name, so without `as = ...` the last crate to\nregister would silently shadow this one in the merged spec / generated SDK).","required":["id","name","metric_name","threshold","comparator","severity","for_duration_secs","enabled"],"properties":{"comparator":{"type":"string"},"deployment_id":{"type":["integer","null"],"format":"int32"},"enabled":{"type":"boolean"},"for_duration_secs":{"type":"integer","format":"int32"},"id":{"type":"integer","format":"int32"},"metric_name":{"type":"string"},"name":{"type":"string"},"service_id":{"type":["integer","null"],"format":"int32"},"severity":{"type":"string"},"silenced_until":{"type":["string","null"]},"threshold":{"type":"number","format":"double"}}},"ServiceBackupEntryResponse":{"type":"object","description":"A single backup entry in the per-service backup list.","required":["id","backup_id","name","state","backup_type","started_at","s3_location","compression_type","s3_source_id","s3_source_name","external_service_backup_id"],"properties":{"backup_id":{"type":"string","description":"UUID string assigned at backup creation time."},"backup_type":{"type":"string","description":"Backup variant (e.g. \"full\", \"incremental\")."},"compression_type":{"type":"string","description":"Compression algorithm used (e.g. \"gzip\")."},"error_message":{"type":["string","null"],"description":"Engine-reported error message, populated when `state = \"failed\"`."},"external_service_backup_id":{"type":"integer","format":"int32","description":"Row ID from `external_service_backups`."},"finished_at":{"type":["string","null"],"description":"ISO 8601 timestamp when the backup finished, if known.","example":"2025-01-15T14:35:00Z"},"id":{"type":"integer","format":"int32","description":"Row ID from the `backups` table."},"name":{"type":"string","description":"Human-friendly display name."},"s3_location":{"type":"string","description":"Object key or `s3://` URL for the backup data."},"s3_source_id":{"type":"integer","format":"int32","description":"FK to `s3_sources.id`."},"s3_source_name":{"type":"string","description":"Human-readable name of the S3 source."},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Size of the backup in bytes, if available."},"started_at":{"type":"string","description":"ISO 8601 timestamp when the backup started.","example":"2025-01-15T14:30:00Z"},"state":{"type":"string","description":"Current state: \"completed\", \"running\", \"failed\"."}}},"ServiceBackupListResponse":{"type":"object","description":"Paginated list of backups for a specific external service.\n\nReturned by `GET /backups/external-services/{service_id}/backups`.","required":["backups","total","page","page_size"],"properties":{"backups":{"type":"array","items":{"$ref":"#/components/schemas/ServiceBackupEntryResponse"},"description":"Backups belonging to this service, newest first."},"page":{"type":"integer","format":"int64","description":"Current page (1-based)."},"page_size":{"type":"integer","format":"int64","description":"Number of items per page."},"total":{"type":"integer","format":"int64","description":"Total number of backups for this service across all pages."}}},"ServiceCreateAlertRuleRequest":{"type":"object","description":"Request body for creating an alert rule on an external service.\n\nDomain-prefixed schema name — see [`AlertRuleResponse`] for why.","required":["name","metric_name","threshold","comparator","severity"],"properties":{"comparator":{"type":"string","description":"One of `>`, `<`, `>=`, `<=`."},"enabled":{"type":"boolean"},"for_duration_secs":{"type":"integer","format":"int32","description":"Seconds the breach must persist before the alarm fires (0 = immediate)."},"metric_name":{"type":"string"},"name":{"type":"string"},"severity":{"type":"string","description":"`\"warning\"` or `\"critical\"`."},"threshold":{"type":"number","format":"double"}}},"ServiceHealthResponse":{"type":"object","required":["service_id","consecutive_failures","recent_checks"],"properties":{"consecutive_failures":{"type":"integer","format":"int32","description":"Consecutive failed probes. Alert fires at 3."},"last_checked_at":{"type":["string","null"]},"last_error":{"type":["string","null"]},"recent_checks":{"type":"array","items":{"$ref":"#/components/schemas/HealthCheckEntryResponse"},"description":"Most recent checks, newest-first (capped at `limit`)."},"response_time_ms":{"type":["integer","null"],"format":"int32"},"service_id":{"type":"integer","format":"int32"},"status":{"type":["string","null"],"description":"Current health. `null` if the service has not been probed yet.","example":"operational"},"uptime_24h_percent":{"type":["number","null"],"format":"double","description":"Uptime percentage over the last 24 hours (0.0 — 100.0).\n`null` when there is not enough history."}}},"ServiceHealthStatusBatchResponse":{"type":"object","required":["statuses"],"properties":{"statuses":{"type":"array","items":{"$ref":"#/components/schemas/ServiceHealthStatusEntryResponse"}}}},"ServiceHealthStatusEntryResponse":{"type":"object","required":["service_id","consecutive_failures"],"properties":{"consecutive_failures":{"type":"integer","format":"int32"},"last_checked_at":{"type":["string","null"]},"service_id":{"type":"integer","format":"int32"},"status":{"type":["string","null"],"description":"\"operational\" | \"degraded\" | \"down\". `null` when the service has not\nbeen probed yet.","example":"operational"}}},"ServiceMemberInfo":{"type":"object","description":"Public info about a cluster member.","required":["id","role","container_name","status","ordinal"],"properties":{"compute_ip":{"type":["string","null"],"description":"Container's IP on the `temps-overlay` multi-host network. Populated\nby the lifecycle hook (ADR-011 Phase 3); `None` on single-host\nclusters where the overlay isn't attached."},"container_name":{"type":"string"},"hostname":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"live_state":{"type":["string","null"],"description":"Live FSM state from the pg_auto_failover monitor (`primary`,\n`secondary`, `catchingup`, `report_lsn`, …). `None` when the\nmonitor is unreachable, the service is not a cluster, or the row\nis the monitor itself.\n\n**The UI must render the role badge from this field**, falling\nback to `role` only when `live_state` is null. `role` is now\nconfig-only (`monitor` or `replica`); flipping the badge to\n\"primary\" when the monitor elects a new one used to require a\nreconciler that lagged ~5s behind real failovers — and during\nthat window the UI showed two primaries. `live_state` is read\ndirectly from the monitor on every list, so it can never lag."},"node_id":{"type":["integer","null"],"format":"int32"},"ordinal":{"type":"integer","format":"int32"},"port":{"type":["integer","null"],"format":"int32"},"provisioning_error":{"type":["string","null"],"description":"Most recent provisioning failure message, when `status='failed'`.\nSet by the background task so the UI can show *why* the new\nreplica didn't come up."},"provisioning_step":{"type":["string","null"],"description":"Last-attempted phase of the async `add_cluster_member` background\ntask (e.g. `validating`, `provisioning_container`, `done`,\n`failed`). `None` for members not created through that flow —\nthe UI falls back to the `status` column for those."},"role":{"type":"string"},"status":{"type":"string"}}},"ServiceParameter":{"type":"object","required":["name","required","encrypted","description"],"properties":{"choices":{"type":["array","null"],"items":{"type":"string"}},"default_value":{"type":["string","null"]},"description":{"type":"string"},"encrypted":{"type":"boolean"},"name":{"type":"string"},"required":{"type":"boolean"},"validation_pattern":{"type":["string","null"]}}},"ServicePlan":{"type":"object","description":"Plan for migrating a single service (database, cache, etc.)","required":["name","service_type","action","action_description"],"properties":{"action":{"$ref":"#/components/schemas/ServiceAction","description":"What to do with this service"},"action_description":{"type":"string","description":"Human-readable explanation of what this action means"},"data_implications":{"type":"array","items":{"$ref":"#/components/schemas/DataImplication"},"description":"Data implications specific to this service"},"env_var_mappings":{"type":"object","description":"Environment variable key mappings: source_key -> temps_key\n\nFor example, Vercel's `POSTGRES_URL` might map to Temps' `DATABASE_URL`.\nBoth keys will be set during migration so the app works with either.","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"name":{"type":"string","description":"Human-readable service name"},"parameters":{"type":"object","description":"Parameters for creating the service in Temps","additionalProperties":{},"propertyNames":{"type":"string"}},"service_type":{"type":"string","description":"Service type (maps to temps-providers ServiceType)"},"version":{"type":["string","null"],"description":"Service version to create (e.g., \"16\" for Postgres 16)"}}},"ServiceResourceLimits":{"type":"object","description":"Optional cgroup resource limits applied to a service container.\n\nAll fields are `Option`: `None` means \"no limit\" (the kernel default),\nmatching Docker's behavior when the corresponding `HostConfig` field is\nleft at zero. Operators opt in to limits explicitly through the\n`PATCH /external-services/{id}/resources` endpoint or by writing the\n`resources` block into `ServiceConfig::parameters` at create time.\n\nThese map directly onto bollard fields:\n- `memory_mb` → `HostConfig.memory` (bytes)\n- `memory_swap_mb`→ `HostConfig.memory_swap` (bytes; ≥ memory)\n- `nano_cpus` → `HostConfig.nano_cpus` (1e9 = 1 full CPU)\n- `cpu_shares` → `HostConfig.cpu_shares` (relative weight, default 1024)\n- `shm_size_mb` → `HostConfig.shm_size` (bytes; default 64 MiB)\n\nIMPORTANT: enabling hard memory limits causes the kernel OOM killer to\nterminate the container when the working set exceeds the limit. The\ncontainer will restart (RestartPolicy::ALWAYS) but in-flight queries\nfail. Surface this clearly in any UI that lets users set limits.","properties":{"cpu_shares":{"type":["integer","null"],"format":"int64","description":"Relative CPU weight (default 1024). Only used when `nano_cpus` is None."},"memory_mb":{"type":["integer","null"],"format":"int64","description":"Hard memory limit in MiB. None = unlimited."},"memory_swap_mb":{"type":["integer","null"],"format":"int64","description":"Memory + swap limit in MiB. None = unlimited.\nMUST be >= memory_mb when both are set; Docker rejects the request otherwise.\nSet equal to `memory_mb` to disable swap entirely."},"nano_cpus":{"type":["integer","null"],"format":"int64","description":"CPU quota in nano-cpus. 1_000_000_000 = 1 full CPU core. None = unlimited."},"shm_size_mb":{"type":["integer","null"],"format":"int64","description":"Shared memory (/dev/shm) size in MiB. None = Docker default (64 MiB).\nMaps to HostConfig.shm_size (bytes). PostgreSQL uses /dev/shm for parallel\nquery workers and large work_mem; the 64 MiB default causes \"could not\nresize shared memory segment ... No space left on device\" under load.\nNOTE: shm_size is fixed at container-create time — Docker's live update\nAPI cannot change it, so changing this value recreates the container."}}},"ServiceRuntimeReport":{"type":"object","description":"Aggregate runtime info for an external service. For standalone services,\n`members` has exactly one entry. For clusters, one entry per member.","required":["service_id","topology","members"],"properties":{"members":{"type":"array","items":{"$ref":"#/components/schemas/ContainerRuntimeInfo"}},"service_id":{"type":"integer","format":"int32"},"topology":{"type":"string"}}},"ServiceStatsReport":{"type":"object","required":["service_id","topology","members"],"properties":{"members":{"type":"array","items":{"$ref":"#/components/schemas/ContainerStatsSample"}},"service_id":{"type":"integer","format":"int32"},"topology":{"type":"string"}}},"ServiceTypeInfo":{"type":"object","required":["service_type","parameters"],"properties":{"parameters":{"type":"array","items":{"$ref":"#/components/schemas/ServiceParameter"},"example":"[{\"name\": \"host\", \"required\": true, \"encrypted\": false, \"description\": \"Database host\"}]"},"service_type":{"$ref":"#/components/schemas/ServiceTypeRoute"}}},"ServiceTypeRoute":{"type":"string","enum":["mariadb","mongodb","postgres","redis","s3","kv","blob","rustfs","minio"]},"ServiceUpdateAlertRuleRequest":{"type":"object","description":"Request body for updating an existing alert rule.\n\nDomain-prefixed schema name — see [`AlertRuleResponse`] for why.","properties":{"comparator":{"type":["string","null"]},"enabled":{"type":["boolean","null"]},"for_duration_secs":{"type":["integer","null"],"format":"int32"},"metric_name":{"type":["string","null"]},"name":{"type":["string","null"]},"severity":{"type":["string","null"]},"threshold":{"type":["number","null"],"format":"double"}}},"SesCredentialsRequest":{"type":"object","required":["access_key_id","secret_access_key"],"properties":{"access_key_id":{"type":"string","example":"AKIAIOSFODNN7EXAMPLE"},"secret_access_key":{"type":"string","example":"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"}}},"SessionDetails":{"type":"object","required":["session_id","visitor_id","started_at","duration_seconds","is_bounced","is_engaged","page_views"],"properties":{"duration_seconds":{"type":"integer","format":"int64"},"ended_at":{"type":["string","null"],"format":"date-time","example":"2024-01-01T00:00:00"},"entry_path":{"type":["string","null"]},"exit_path":{"type":["string","null"]},"is_bounced":{"type":"boolean"},"is_engaged":{"type":"boolean"},"page_views":{"type":"integer","format":"int64"},"referrer":{"type":["string","null"]},"session_id":{"type":"integer","format":"int32"},"started_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"visitor_id":{"type":"string"}}},"SessionDetailsQuery":{"type":"object","required":["project_id"],"properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"}}},"SessionEvent":{"type":"object","required":["id","timestamp"],"properties":{"event_data":{},"event_name":{"type":["string","null"]},"event_type":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"page_title":{"type":["string","null"]},"page_url":{"type":["string","null"]},"timestamp":{"type":"string"}}},"SessionEventDto":{"type":"object","required":["id","session_id","data","timestamp"],"properties":{"data":{},"event_type":{"type":["integer","null"],"format":"int32"},"id":{"type":"integer","format":"int32"},"session_id":{"type":"integer","format":"int32"},"timestamp":{"type":"integer","format":"int64"}}},"SessionEventsQuery":{"type":"object","required":["project_id"],"properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"}}},"SessionEventsResponse":{"type":"object","required":["session_id","events","total_count","offset","limit"],"properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/SessionEvent"}},"limit":{"type":"integer","format":"int32"},"offset":{"type":"integer","format":"int32"},"session_id":{"type":"integer","format":"int32"},"total_count":{"type":"integer","format":"int64"}}},"SessionLogsQuery":{"type":"object","required":["project_id"],"properties":{"end_date":{"type":["string","null"],"format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32"},"offset":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"sort_order":{"type":["string","null"]},"start_date":{"type":["string","null"],"format":"date-time"},"visitor_id":{"type":["integer","null"],"format":"int32"}}},"SessionLogsResponse":{"type":"object","required":["session_id","logs","total_count","offset","limit"],"properties":{"limit":{"type":"integer","format":"int32"},"logs":{"type":"array","items":{"$ref":"#/components/schemas/SessionRequestLog"}},"offset":{"type":"integer","format":"int32"},"session_id":{"type":"integer","format":"int32"},"total_count":{"type":"integer","format":"int64"}}},"SessionReplayEventsRequest":{"type":"object","required":["sessionId","events"],"properties":{"events":{"type":"string"},"sessionId":{"type":"string"}}},"SessionReplayInfoDto":{"type":"object","required":["id","visitor_id"],"properties":{"created_at":{"type":["string","null"]},"duration":{"type":["integer","null"],"format":"int32"},"id":{"type":"string"},"language":{"type":["string","null"]},"screen_height":{"type":["integer","null"],"format":"int32"},"screen_width":{"type":["integer","null"],"format":"int32"},"timezone":{"type":["string","null"]},"url":{"type":["string","null"]},"user_agent":{"type":["string","null"]},"viewport_height":{"type":["integer","null"],"format":"int32"},"viewport_width":{"type":["integer","null"],"format":"int32"},"visitor_id":{"type":"integer","format":"int32"}}},"SessionReplayInitRequest":{"type":"object","required":["sessionId"],"properties":{"colorDepth":{"type":["integer","null"],"format":"int32","minimum":0},"language":{"type":["string","null"]},"screenHeight":{"type":["integer","null"],"format":"int32","minimum":0},"screenWidth":{"type":["integer","null"],"format":"int32","minimum":0},"sessionId":{"type":"string"},"timestamp":{"type":["string","null"]},"timezone":{"type":["string","null"]},"url":{"type":["string","null"]},"userAgent":{"type":["string","null"]},"viewportHeight":{"type":["integer","null"],"format":"int32","minimum":0},"viewportWidth":{"type":["integer","null"],"format":"int32","minimum":0}}},"SessionReplayInitResponse":{"type":"object","required":["session_id","message"],"properties":{"message":{"type":"string"},"session_id":{"type":"string"}}},"SessionReplayWithEventsDto":{"type":"object","required":["session","events"],"properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/SessionEventDto"}},"session":{"$ref":"#/components/schemas/SessionReplayWithVisitorDto"}}},"SessionReplayWithVisitorDto":{"type":"object","required":["id","session_replay_id","visitor_id","visitor_uuid","visitor_project_id","visitor_environment_id","visitor_first_seen","visitor_last_seen","visitor_is_crawler"],"properties":{"browser":{"type":["string","null"]},"browser_version":{"type":["string","null"]},"created_at":{"type":["string","null"]},"device_type":{"type":["string","null"]},"duration":{"type":["integer","null"],"format":"int32"},"id":{"type":"integer","format":"int32"},"language":{"type":["string","null"]},"operating_system":{"type":["string","null"]},"operating_system_version":{"type":["string","null"]},"screen_height":{"type":["integer","null"],"format":"int32"},"screen_width":{"type":["integer","null"],"format":"int32"},"session_replay_id":{"type":"string"},"timezone":{"type":["string","null"]},"url":{"type":["string","null"]},"user_agent":{"type":["string","null"]},"viewport_height":{"type":["integer","null"],"format":"int32"},"viewport_width":{"type":["integer","null"],"format":"int32"},"visitor_city":{"type":["string","null"]},"visitor_country":{"type":["string","null"]},"visitor_country_code":{"type":["string","null"]},"visitor_crawler_name":{"type":["string","null"]},"visitor_custom_data":{},"visitor_environment_id":{"type":"integer","format":"int32"},"visitor_first_seen":{"type":"string"},"visitor_id":{"type":"integer","format":"int32"},"visitor_is_crawler":{"type":"boolean"},"visitor_last_seen":{"type":"string"},"visitor_project_id":{"type":"integer","format":"int32"},"visitor_region":{"type":["string","null"]},"visitor_uuid":{"type":"string"}}},"SessionRequestLog":{"type":"object","required":["id","method","path","status_code","created_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"id":{"type":"integer","format":"int32"},"method":{"type":"string"},"path":{"type":"string"},"referrer":{"type":["string","null"]},"request_headers":{"type":["string","null"]},"response_headers":{"type":["string","null"]},"response_time_ms":{"type":["integer","null"],"format":"int32"},"status_code":{"type":"integer","format":"int32"},"user_agent":{"type":["string","null"]}}},"SessionSummary":{"type":"object","required":["session_id","started_at","duration_seconds","page_views","events_count","requests_count","is_bounced","is_engaged"],"properties":{"duration_seconds":{"type":"integer","format":"int64"},"ended_at":{"type":["string","null"],"format":"date-time","example":"2024-01-01T00:00:00"},"entry_path":{"type":["string","null"]},"events_count":{"type":"integer","format":"int64"},"exit_path":{"type":["string","null"]},"is_bounced":{"type":"boolean"},"is_engaged":{"type":"boolean"},"page_views":{"type":"integer","format":"int64"},"referrer":{"type":["string","null"]},"requests_count":{"type":"integer","format":"int64"},"session_id":{"type":"integer","format":"int32"},"started_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"}}},"SetFlagEnvironmentRequest":{"type":"object","properties":{"enabled":{"type":["boolean","null"],"description":"The kill switch. `false` makes the flag serve its default regardless of\nany override — and, once targeting exists, regardless of any rule."},"value":{"description":"Tri-state: absent leaves the override, `null` clears it (inherit the\nflag default), anything else sets it. Must match `value_type`."}}},"SetPreviewPasswordBody":{"type":"object","required":["password"],"properties":{"password":{"type":"string","description":"Plaintext password to protect the sandbox's preview URLs. Hashed\nserver-side with argon2id — we never persist or echo this back.\nMust be between 8 and 256 characters."}}},"SetPreviewPasswordResponse":{"type":"object","required":["preview_password_hint"],"properties":{"preview_password_hint":{"type":"string","description":"Last 4 chars of the password we just stored. Surface in the UI so\nusers can confirm which password is live without re-entering it."}}},"SetRequest":{"type":"object","description":"Request to set a value","required":["key","value"],"properties":{"ex":{"type":["integer","null"],"format":"int64","description":"Expire in seconds","example":3600},"key":{"type":"string","description":"The key to set","example":"user:123"},"nx":{"type":"boolean","description":"Only set if key does not exist"},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1},"px":{"type":["integer","null"],"format":"int64","description":"Expire in milliseconds"},"value":{"description":"The value to store (can be any JSON value)"},"xx":{"type":"boolean","description":"Only set if key exists"}}},"SetResponse":{"type":"object","description":"Response for set operation","required":["result"],"properties":{"result":{"type":"string","description":"Always \"OK\" on success","example":"OK"}}},"SettingsUpdateResponse":{"type":"object","description":"Response for successful settings update","required":["message"],"properties":{"message":{"type":"string"}}},"SetupDnsChallengeRequest":{"type":"object","description":"Request to setup DNS challenge records using a configured DNS provider","required":["dns_provider_id"],"properties":{"dns_provider_id":{"type":"integer","format":"int32","description":"The ID of the DNS provider to use for creating the TXT records"}}},"SetupDnsChallengeResponse":{"type":"object","description":"Response from DNS challenge setup operation","required":["success","records_created","total_records","results","message"],"properties":{"message":{"type":"string","description":"Human-readable summary message"},"records_created":{"type":"integer","format":"int32","description":"Number of TXT records that were successfully created","minimum":0},"results":{"type":"array","items":{"$ref":"#/components/schemas/DnsChallengeRecordResult"},"description":"Results for each individual TXT record"},"success":{"type":"boolean","description":"Overall success status (true if all records were created)"},"total_records":{"type":"integer","format":"int32","description":"Total number of TXT records required for the challenge","minimum":0}}},"SetupDnsRequest":{"type":"object","description":"Request to setup DNS records using a configured DNS provider","required":["dns_provider_id"],"properties":{"dns_provider_id":{"type":"integer","format":"int32","description":"The ID of the DNS provider to use for creating records"}}},"SetupDnsResponse":{"type":"object","description":"Response from DNS setup operation","required":["success","records_created","total_records","results","message"],"properties":{"message":{"type":"string","description":"Human-readable summary message"},"records_created":{"type":"integer","format":"int32","description":"Number of records that were successfully created","minimum":0},"results":{"type":"array","items":{"$ref":"#/components/schemas/DnsRecordSetupResult"},"description":"Results for each individual record"},"success":{"type":"boolean","description":"Overall success status"},"total_records":{"type":"integer","format":"int32","description":"Total number of records attempted","minimum":0}}},"SiblingRef":{"type":"object","description":"A sibling project that shares the same `trace_id` and has opted in to\ncross-project trace sharing (`cross_project_trace_sharing = TRUE`).\n\nReturned by `CrossProjectTraceService::find_sibling_projects` and exposed\nby the Phase 1 `GET /otel/traces/cross-project/{trace_id}` endpoint.","required":["project_id","project_name","project_slug","first_seen"],"properties":{"first_seen":{"type":"string","format":"date-time"},"project_id":{"type":"integer","format":"int32"},"project_name":{"type":"string"},"project_slug":{"type":"string","description":"URL slug used to link into the sibling project's single-project trace view."}}},"SkillDefinitionResponse":{"type":"object","required":["id","slug","name","content","has_archive","created_at","updated_at"],"properties":{"content":{"type":"string"},"created_at":{"type":"string"},"description":{"type":["string","null"]},"has_archive":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"project_id":{"type":["integer","null"],"format":"int32"},"slug":{"type":"string"},"updated_at":{"type":"string"}}},"SlackConfig":{"type":"object","required":["webhook_url"],"properties":{"channel":{"type":["string","null"]},"webhook_url":{"type":"string"}}},"SlowQueriesResponse":{"type":"object","description":"Response envelope for the slow-queries list endpoint.","required":["queries","page","page_size","total_count"],"properties":{"page":{"type":"integer","format":"int32","description":"Current page number (1-based).","minimum":0},"page_size":{"type":"integer","format":"int32","description":"Number of rows per page used for this request.","minimum":0},"queries":{"type":"array","items":{"$ref":"#/components/schemas/SlowQueryRow"},"description":"Ordered list of query stats, slowest first by mean_exec_time_ms."},"total_count":{"type":"integer","format":"int64","description":"Total number of qualifying rows across all pages.","minimum":0}}},"SlowQueryRow":{"type":"object","description":"A single entry from `pg_stat_statements`, representing one normalized\nquery fingerprint and its aggregate execution stats.","required":["query","database","calls","total_exec_time_ms","mean_exec_time_ms","rows"],"properties":{"cache_hit_ratio":{"type":["number","null"],"format":"double","description":"Shared block cache hit ratio (0.0–1.0).\n`None` when total block accesses are zero (e.g. function-only queries)."},"calls":{"type":"integer","format":"int64","description":"Number of times this query was executed."},"database":{"type":"string","description":"Name of the database this query ran against. `(dropped database)`\nwhen the originating database no longer exists but\n`pg_stat_statements` still holds stats for it."},"mean_exec_time_ms":{"type":"number","format":"double","description":"Average wall-clock time per execution, in milliseconds."},"query":{"type":"string","description":"Normalized query text (parameter literals replaced with `$N`)."},"rows":{"type":"integer","format":"int64","description":"Total number of rows returned or affected."},"total_exec_time_ms":{"type":"number","format":"double","description":"Total wall-clock time spent executing this query, in milliseconds."}}},"SmartFilter":{"oneOf":[{"type":"object","description":"Match specific page path","required":["value","type"],"properties":{"type":{"type":"string","enum":["page_path"]},"value":{"type":"string","description":"Match specific page path"}}},{"type":"object","description":"Match specific hostname","required":["value","type"],"properties":{"type":{"type":"string","enum":["hostname"]},"value":{"type":"string","description":"Match specific hostname"}}},{"type":"object","description":"Match UTM source","required":["value","type"],"properties":{"type":{"type":"string","enum":["utm_source"]},"value":{"type":"string","description":"Match UTM source"}}},{"type":"object","description":"Match UTM campaign","required":["value","type"],"properties":{"type":{"type":"string","enum":["utm_campaign"]},"value":{"type":"string","description":"Match UTM campaign"}}},{"type":"object","description":"Match UTM medium","required":["value","type"],"properties":{"type":{"type":"string","enum":["utm_medium"]},"value":{"type":"string","description":"Match UTM medium"}}},{"type":"object","description":"Match referrer hostname","required":["value","type"],"properties":{"type":{"type":"string","enum":["referrer_hostname"]},"value":{"type":"string","description":"Match referrer hostname"}}},{"type":"object","description":"Match specific channel (organic, paid, direct, referral, etc.)","required":["value","type"],"properties":{"type":{"type":"string","enum":["channel"]},"value":{"type":"string","description":"Match specific channel (organic, paid, direct, referral, etc.)"}}},{"type":"object","description":"Match device type (mobile, desktop, tablet)","required":["value","type"],"properties":{"type":{"type":"string","enum":["device_type"]},"value":{"type":"string","description":"Match device type (mobile, desktop, tablet)"}}},{"type":"object","description":"Match browser","required":["value","type"],"properties":{"type":{"type":"string","enum":["browser"]},"value":{"type":"string","description":"Match browser"}}},{"type":"object","description":"Match operating system","required":["value","type"],"properties":{"type":{"type":"string","enum":["operating_system"]},"value":{"type":"string","description":"Match operating system"}}},{"type":"object","description":"Match language","required":["value","type"],"properties":{"type":{"type":"string","enum":["language"]},"value":{"type":"string","description":"Match language"}}},{"type":"object","description":"Match custom event_data by JSON path\nFormat: {\"path\": \"user.plan\", \"value\": \"premium\"}\nThis will match events where event_data->'user'->>'plan' = 'premium'","required":["value","type"],"properties":{"type":{"type":"string","enum":["custom_data"]},"value":{"type":"object","description":"Match custom event_data by JSON path\nFormat: {\"path\": \"user.plan\", \"value\": \"premium\"}\nThis will match events where event_data->'user'->>'plan' = 'premium'","required":["path","value"],"properties":{"path":{"type":"string"},"value":{"type":"string"}}}}}],"description":"Smart filter presets for common funnel patterns"},"SmokeTestResponse":{"type":"object","required":["passed","environment","cli_installed","cli_authenticated"],"properties":{"auth_info":{"type":["string","null"],"description":"Auth email / method"},"cli_authenticated":{"type":"boolean","description":"Claude CLI authenticated?"},"cli_installed":{"type":"boolean","description":"Claude CLI installed?"},"cli_version":{"type":["string","null"],"description":"Claude CLI version"},"detail":{"type":["string","null"],"description":"Full output for debugging"},"environment":{"type":"string","description":"Where the test ran: \"host\" or \"sandbox\""},"passed":{"type":"boolean","description":"Whether the smoke test passed"},"setup_hint":{"type":["string","null"],"description":"What the user needs to do if the test failed"}}},"SmtpCredentialsRequest":{"type":"object","description":"Generic SMTP credentials request body.\n\nWorks with any SMTP relay — AWS SES SMTP endpoints, Sendgrid, Mailgun,\nPostmark, or a self-hosted Postfix. Use this when you only have SMTP\ncredentials (i.e. you cannot create identities via the upstream API).","required":["host","port"],"properties":{"accept_invalid_certs":{"type":"boolean","description":"Accept self-signed certificates. Only safe for local testing."},"encryption":{"$ref":"#/components/schemas/SmtpEncryptionRoute","description":"TLS mode. Defaults to STARTTLS."},"host":{"type":"string","description":"SMTP host, e.g. `email-smtp.eu-west-1.amazonaws.com`.","example":"email-smtp.eu-west-1.amazonaws.com"},"password":{"type":["string","null"],"description":"SMTP password / API token. Required when `username` is set."},"port":{"type":"integer","format":"int32","description":"SMTP port (587 for STARTTLS, 465 for implicit TLS, 25/1025 for plain).","example":587,"minimum":0},"username":{"type":["string","null"],"description":"SMTP username. Leave empty for unauthenticated relays.","example":"AKIAIOSFODNN7EXAMPLE"}}},"SmtpEncryptionRoute":{"type":"string","description":"TLS mode for the SMTP relay.","enum":["starttls","tls","none"]},"SmtpResult":{"type":"object","description":"SMTP validation result","required":["can_connect_smtp","has_full_inbox","is_catch_all","is_deliverable","is_disabled"],"properties":{"can_connect_smtp":{"type":"boolean","description":"Whether we could connect to the SMTP server"},"error":{"type":["string","null"],"description":"Error message if SMTP check failed"},"has_full_inbox":{"type":"boolean","description":"Whether the mailbox appears to have a full inbox"},"is_catch_all":{"type":"boolean","description":"Whether this is a catch-all domain"},"is_deliverable":{"type":"boolean","description":"Whether the email is deliverable"},"is_disabled":{"type":"boolean","description":"Whether the mailbox is disabled"}}},"SourceArchiveUpload":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary"}}},"SourceBackupEntry":{"type":"object","description":"Entry in the source backup index. Covers both DB-tracked backups\n(have a row in `backups`) and S3-scan discoveries (raw S3 objects with\nno DB row — used for disaster-recovery from another Temps instance).","required":["id","backup_id","name","backup_type","created_at","location","metadata_location","source","state"],"properties":{"backup_id":{"type":"string","description":"UUID identifier from the DB row. Empty for S3-scan entries.","example":"550e8400-e29b-41d4-a716-446655440000"},"backup_type":{"type":"string","description":"Backup variant as recorded by the backup pipeline (e.g. \"full\").","example":"full"},"created_at":{"type":"string","description":"When the backup was created. For S3-scan entries this is the\nobject's LastModified time.","example":"2024-01-15T14:30:00.123Z"},"engine":{"type":["string","null"],"description":"Engine that produced the backup (\"postgres\", \"redis\", \"mongodb\",\n\"s3\", \"rustfs\"). Used by the UI to mark engine-compat with the\ntarget service.","example":"postgres"},"format":{"type":["string","null"],"description":"Storage format: \"walg\" for continuous-archive (PITR-capable),\n\"pg_dump\" for point-in-time dumps, \"\" for non-postgres.","example":"walg"},"id":{"type":"integer","format":"int32","description":"DB row id. Zero for S3-scan entries that have no DB row.","example":1},"location":{"type":"string","description":"Raw S3 URL / key where the backup sits. For Postgres WAL-G backups\nthis starts with `s3://`; for pg_dump-style backups it's the\nrelative object key.","example":"s3://bucket/external_services/postgres/svc-name/walg"},"metadata_location":{"type":"string","description":"Sidecar metadata.json location, if any. Empty when none.","example":""},"name":{"type":"string","description":"Human-friendly display name (\"postgres backup (svc-name)\" for DB\nrows, or a synthesized label derived from the S3 path for scans).","example":"postgres backup (postgres-n4ea)"},"origin_service_name":{"type":["string","null"],"description":"Name of the service that produced the backup. For S3-scan entries\nthis is parsed from the S3 path.","example":"postgres-n4ea"},"size_bytes":{"type":["integer","null"],"format":"int64","description":"Size of the backup in bytes, if known.","example":1024000},"source":{"type":"string","description":"Provenance: \"db\" for rows in this Temps, \"s3_scan\" for objects\ndiscovered by the S3 bucket walk (e.g., backups made by another\nTemps instance).","example":"db"},"state":{"type":"string","description":"Observed state (\"completed\", \"running\", \"failed\") — DB only.\nEmpty string for S3-scan entries.","example":"completed"}}},"SourceBackupIndexResponse":{"type":"object","description":"Response type for source backup index","required":["backups","last_updated"],"properties":{"backups":{"type":"array","items":{"$ref":"#/components/schemas/SourceBackupEntry"},"description":"List of backups in the source"},"last_updated":{"type":"string","description":"When the index was last updated","example":"2024-01-15T14:30:00.123Z"}}},"SourceBody":{"oneOf":[{"type":"object","required":["url","type"],"properties":{"depth":{"type":["integer","null"],"format":"int32","minimum":0},"git_connection_id":{"type":["integer","null"],"format":"int32"},"password":{"type":["string","null"]},"revision":{"type":["string","null"]},"type":{"type":"string","enum":["git"]},"url":{"type":"string"},"username":{"type":["string","null"]}}},{"type":"object","required":["url","type"],"properties":{"type":{"type":"string","enum":["tarball"]},"url":{"type":"string"}}}],"description":"Initial content to seed into the sandbox work dir. Mirrors the\n`@vercel/sandbox` `source` option. `type` is one of:\n- `git` — clone `url`; optionally check out `revision`\n- `tarball` — download `url` (must be tar or tar.gz) and extract\n\nFor private git repos, pass credentials one of two ways:\n1. **Inline (SDK-compatible):** `username` + `password`. GitHub\n tokens use `username: \"x-access-token\"`.\n2. **Stored connection (temps-native):** `git_connection_id`\n references a row in the caller's git provider connections. Temps\n resolves the token server-side and injects it safely.\n\n`git_connection_id` is mutually exclusive with `username`/`password`."},"SourceFileListResponse":{"type":"object","required":["source_files","total"],"properties":{"source_files":{"type":"array","items":{"$ref":"#/components/schemas/SourceFileResponse"}},"total":{"type":"integer","minimum":0}}},"SourceFileResponse":{"type":"object","required":["id","project_id","release","file_path","size_bytes","created_at"],"properties":{"checksum":{"type":["string","null"]},"created_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"file_path":{"type":"string"},"id":{"type":"integer","format":"int32"},"project_id":{"type":"integer","format":"int32"},"release":{"type":"string"},"size_bytes":{"type":"integer","format":"int64"}}},"SourceMapListResponse":{"type":"object","required":["source_maps","total"],"properties":{"source_maps":{"type":"array","items":{"$ref":"#/components/schemas/SourceMapResponse"}},"total":{"type":"integer","minimum":0}}},"SourceMapResponse":{"type":"object","required":["id","project_id","release","file_path","size_bytes","created_at"],"properties":{"checksum":{"type":["string","null"]},"created_at":{"type":"string","example":"2025-10-12T12:15:47.609192Z"},"dist":{"type":["string","null"]},"file_path":{"type":"string"},"id":{"type":"integer","format":"int32"},"project_id":{"type":"integer","format":"int32"},"release":{"type":"string"},"size_bytes":{"type":"integer","format":"int64"}}},"SourceType":{"type":"string","description":"Source type for project deployments\n\nDetermines where the deployment artifacts come from:\n- `Git`: Source code from a Git repository (traditional flow)\n- `DockerImage`: Pre-built Docker image from external registry\n- `StaticFiles`: Pre-built static files uploaded as a bundle\n- `UploadedSource`: Source archive uploaded without a Git repository\n- `Manual`: Flexible type that accepts any deployment method","enum":["git","docker_image","static_files","uploaded_source","manual"]},"SpanEvent":{"type":"object","description":"A span event (log-like annotation on a span).","required":["timestamp","name","attributes"],"properties":{"attributes":{"type":"object","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"name":{"type":"string"},"timestamp":{"type":"string","format":"date-time"}}},"SpanKind":{"type":"string","description":"Span kind.","enum":["UNSPECIFIED","INTERNAL","SERVER","CLIENT","PRODUCER","CONSUMER"]},"SpanRecord":{"type":"object","description":"A single trace span ready for storage.","required":["project_id","resource","trace_id","span_id","name","kind","start_time","end_time","duration_ms","status_code","status_message","attributes","events"],"properties":{"attributes":{"type":"object","description":"Raw key/value pairs exactly as reported by the instrumenting library.\nNumeric values are NOT guaranteed to share `duration_ms`'s unit — they\nmay be seconds, milliseconds, microseconds, or nanoseconds depending on\nthe exporter's own convention, and the unit is not labeled here.","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"deployment_id":{"type":["integer","null"],"format":"int32"},"duration_ms":{"type":"number","format":"double","description":"Span duration in milliseconds. The only field on this struct guaranteed\nto be in milliseconds."},"end_time":{"type":"string","format":"date-time"},"events":{"type":"array","items":{"$ref":"#/components/schemas/SpanEvent"}},"kind":{"$ref":"#/components/schemas/SpanKind"},"name":{"type":"string"},"parent_span_id":{"type":["string","null"]},"project_id":{"type":"integer","format":"int32"},"resource":{"$ref":"#/components/schemas/ResourceInfo"},"span_id":{"type":"string"},"start_time":{"type":"string","format":"date-time"},"status_code":{"$ref":"#/components/schemas/SpanStatusCode"},"status_message":{"type":"string"},"trace_id":{"type":"string"}}},"SpanRow":{"type":"object","required":["id","ts","trace_id","span_id","service","operation","attributes","attributes_truncated"],"properties":{"attributes":{},"attributes_truncated":{"type":"boolean"},"deployment_id":{"type":["integer","null"],"format":"int32"},"duration_ms":{"type":["number","null"],"format":"double"},"environment_id":{"type":["integer","null"],"format":"int32"},"id":{"type":"string"},"operation":{"type":"string"},"parent_span_id":{"type":["string","null"]},"service":{"type":"string"},"span_id":{"type":"string"},"status":{"type":["string","null"]},"trace_id":{"type":"string"},"ts":{"type":"string","format":"date-time"}}},"SpanStats":{"type":"object","description":"Latency and error statistics for one operation, i.e. one\n`(project, service, span name)` triple over the queried window.","required":["project_id","service_name","span_name","kind","count","error_count","error_rate","total_duration_ms","min_duration_ms","max_duration_ms","avg_duration_ms","stddev_duration_ms","p50_duration_ms","p95_duration_ms","p99_duration_ms","coefficient_of_variation","tail_ratio","last_seen"],"properties":{"avg_duration_ms":{"type":"number","format":"double"},"coefficient_of_variation":{"type":"number","format":"double","description":"`stddev / avg`, or `0` when `avg` is zero."},"count":{"type":"integer","format":"int64","description":"Number of spans aggregated."},"error_count":{"type":"integer","format":"int64"},"error_rate":{"type":"number","format":"double","description":"`error_count / count`, in `[0, 1]`."},"kind":{"$ref":"#/components/schemas/SpanKind","description":"The most common span kind for this operation."},"last_seen":{"type":"string","format":"date-time","description":"Start time of the most recent span in this group."},"max_duration_ms":{"type":"number","format":"double"},"min_duration_ms":{"type":"number","format":"double"},"p50_duration_ms":{"type":"number","format":"double"},"p95_duration_ms":{"type":"number","format":"double"},"p99_duration_ms":{"type":"number","format":"double"},"project_id":{"type":"integer","format":"int32"},"service_name":{"type":"string"},"span_name":{"type":"string","description":"The span name, which is the operation identity: `GET /api/checkout`,\n`SELECT carts`, `payments.charge`."},"stddev_duration_ms":{"type":"number","format":"double","description":"Sample standard deviation. `0` when the operation has a single sample."},"tail_ratio":{"type":"number","format":"double","description":"`p99 / p50`, or `0` when `p50` is zero."},"total_duration_ms":{"type":"number","format":"double","description":"`SUM(duration_ms)` — total wall-clock attributable to this operation."}}},"SpanStatsResponse":{"type":"object","description":"Response for `GET /otel/span-stats`.","required":["data","total","start_time","end_time"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/SpanStats"}},"end_time":{"type":"string","format":"date-time"},"start_time":{"type":"string","format":"date-time","description":"The window actually aggregated, echoed back because it is defaulted\nserver-side when the caller omits it."},"total":{"type":"integer","format":"int64","description":"Total number of distinct operations matching the filters, for pagination.","minimum":0}}},"SpanStatusCode":{"type":"string","description":"Span status code.","enum":["UNSET","OK","ERROR"]},"SpeedMetricsPayload":{"type":"object","description":"Speed metrics payload for recording web vitals","properties":{"cls":{"type":["number","null"],"format":"float","description":"Cumulative Layout Shift (score)"},"fcp":{"type":["number","null"],"format":"float","description":"First Contentful Paint (milliseconds)"},"fid":{"type":["number","null"],"format":"float","description":"First Input Delay (milliseconds)"},"inp":{"type":["number","null"],"format":"float","description":"Interaction to Next Paint (milliseconds)"},"language":{"type":["string","null"],"description":"Browser language"},"lcp":{"type":["number","null"],"format":"float","description":"Largest Contentful Paint (milliseconds)"},"pathname":{"type":["string","null"],"description":"Page pathname"},"query":{"type":["string","null"],"description":"Query string"},"screenHeight":{"type":["integer","null"],"format":"int32","description":"Screen height in pixels"},"screenWidth":{"type":["integer","null"],"format":"int32","description":"Screen width in pixels"},"ttfb":{"type":["number","null"],"format":"float","description":"Time to First Byte (milliseconds)"},"viewportHeight":{"type":["integer","null"],"format":"int32","description":"Viewport height in pixels"},"viewportWidth":{"type":["integer","null"],"format":"int32","description":"Viewport width in pixels"}}},"SpeedSegmentFilters":{"type":"object","description":"Optional segment filters for the performance read endpoints, mirroring\nanalytics' `VisitorSegmentFilters`. Each filter narrows results to samples\nmatching the dimension value, so metrics can be scoped to e.g. one page,\none browser, or one country. Geographic filters resolve via\n`ip_geolocations`; the rest live directly on `performance_metrics`.","properties":{"filter_browser":{"type":["string","null"],"description":"Browser name (matches `performance_metrics.browser`)"},"filter_city":{"type":["string","null"],"description":"Geolocation city (matches `ip_geolocations.city`)"},"filter_country":{"type":["string","null"],"description":"Geolocation country (matches `ip_geolocations.country`)"},"filter_operating_system":{"type":["string","null"],"description":"Operating system (matches `performance_metrics.operating_system`)"},"filter_path":{"type":["string","null"],"description":"Page pathname (matches `performance_metrics.pathname`)"},"filter_region":{"type":["string","null"],"description":"Geolocation region (matches `ip_geolocations.region`)"}}},"StaleSlot":{"type":"object","required":["slot_name","active","retained_bytes"],"properties":{"active":{"type":"boolean"},"retained_bytes":{"type":"integer","format":"int64"},"slot_name":{"type":"string"}}},"StartAnalysisRequest":{"type":"object","required":["error_group_id"],"properties":{"branch":{"type":["string","null"],"description":"Branch to clone instead of the project's main branch."},"error_group_id":{"type":"integer","format":"int32"},"max_turns":{"type":["integer","null"],"format":"int32","description":"Per-run turn cap applied to every phase (1–200). Only enforced for\nCLIs with a turn flag (Claude Code). `None` uses the provider's\nconfigured defaults."},"model":{"type":["string","null"],"description":"Model id for the chosen provider. `None` uses the provider's saved\ndefault model."},"provider":{"type":["string","null"],"description":"AI provider id (\"claude_cli\", \"codex_cli\", \"opencode\"). `None` uses\nthe platform default provider."},"user_context":{"type":["string","null"],"description":"Free-text notes for the model (extra context about the error, retry\nguidance, constraints). Included verbatim in the analysis prompt."}}},"StartPgUpgradeRequest":{"type":"object","required":["from_version","to_version","from_image","to_image"],"properties":{"from_image":{"type":"string","example":"postgres:16-bookworm"},"from_version":{"type":"string","example":"16"},"to_image":{"type":"string","example":"postgres:17-bookworm"},"to_version":{"type":"string","example":"17"}}},"StartRestoreRequest":{"allOf":[{"$ref":"#/components/schemas/RestoreRequestMode","description":"Requested restore mode. See `RestoreRequestMode`."},{"type":"object","properties":{"backup_engine":{"type":["string","null"],"description":"Engine of the backup when specified by `backup_location`\n(\"postgres\", \"redis\", \"mongodb\", \"s3\"). Ignored when `backup_id`\nis used — we infer from the DB row."},"backup_id":{"type":["integer","null"],"format":"int32","description":"DB id of the backup to restore from. Either `backup_id` or\n`backup_location` MUST be provided. Use `backup_id` when restoring\na backup this Temps instance recorded."},"backup_location":{"type":["string","null"],"description":"Raw S3 URL / key of the backup — used when restoring a backup\ndiscovered by S3 scan (i.e., produced by another Temps instance).\nRequires `backup_engine` and `s3_source_id` to also be set."},"s3_source_id":{"type":["integer","null"],"format":"int32","description":"S3 source the `backup_location` lives in. Ignored when `backup_id`\nis used."}}}]},"StartUpdateRequest":{"type":"object","description":"Optional pin for the version to install.","properties":{"version":{"type":["string","null"],"description":"Release tag to install (e.g. `v0.2.0`). Omit to take the newest release\non the channel this install already tracks."}}},"StartUpdateResponse":{"type":"object","description":"Acknowledgement that an update was accepted and is running.","required":["current_version","estimated_restart_secs","restart_mode","message"],"properties":{"current_version":{"type":"string","description":"Version the server is running as it accepts this request."},"estimated_restart_secs":{"type":"integer","format":"int64","description":"How long to allow for the server to come back before treating the\nrestart as failed. `0` when nothing restarts.","minimum":0},"message":{"type":"string"},"restart_mode":{"$ref":"#/components/schemas/SelfUpdateRestartMode","description":"`automatic` (temps restarts itself) or `manual` (installed only)."}}},"StatResponse":{"type":"object","required":["path","exists","is_dir","is_file","size"],"properties":{"exists":{"type":"boolean"},"is_dir":{"type":"boolean"},"is_file":{"type":"boolean"},"path":{"type":"string"},"size":{"type":"integer","format":"int64","minimum":0}}},"StaticBundleResponse":{"type":"object","required":["id","project_id","blob_path","content_type","size_bytes","uploaded_at","created_at"],"properties":{"blob_path":{"type":"string"},"checksum":{"type":["string","null"]},"content_type":{"type":"string"},"created_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"format":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"metadata":{},"original_filename":{"type":["string","null"]},"project_id":{"type":"integer","format":"int32"},"size_bytes":{"type":"integer","format":"int64"},"uploaded_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"}}},"StaticParams":{"type":"object","description":"Static threshold detector: compare the aggregated `value` against `threshold`.","required":["comparator","threshold"],"properties":{"comparator":{"$ref":"#/components/schemas/Comparator","description":"How `value` is compared against `threshold`."},"threshold":{"type":"number","format":"double","description":"The threshold the aggregated value is compared against."}}},"StaticPresetConfig":{"type":"object","description":"Configuration for static site presets (Vite, Next.js, Docusaurus, etc.)\nThese presets build static sites that are served via a web server","properties":{"buildCommand":{"type":["string","null"],"description":"Custom build command (overrides preset default)","example":"npm run build:production"},"buildContext":{"type":["string","null"],"description":"Custom build context path (relative to repository root)\nUseful for monorepo setups where the app is in a subdirectory","example":"./apps/frontend"},"installCommand":{"type":["string","null"],"description":"Custom install command (overrides auto-detected package manager)","example":"npm ci"},"outputDir":{"type":["string","null"],"description":"Custom output directory (overrides preset default)\nCommon values: \"dist\", \"build\", \".next\", \"out\"","example":"dist"}}},"StatsFilters":{"type":"object","description":"Filters for statistics queries","properties":{"client_ip":{"type":["string","null"]},"deployment_id":{"type":["integer","null"],"format":"int32"},"device_type":{"type":["string","null"]},"environment_id":{"type":["integer","null"],"format":"int32"},"has_project":{"type":["boolean","null"],"description":"When true, only count requests that matched a project (project_id IS NOT NULL).\nUsed by the health dashboard so totals match the per-project cards."},"host":{"type":["string","null"]},"is_bot":{"type":["boolean","null"]},"method":{"type":["string","null"]},"project_id":{"type":["integer","null"],"format":"int32"},"request_source":{"type":["string","null"]},"routing_status":{"type":["string","null"]},"status_code":{"type":["integer","null"],"format":"int32"},"status_code_class":{"type":["string","null"],"description":"Filter by status code class (e.g. \"2xx\", \"3xx\", \"4xx\", \"5xx\")"}}},"StatusBucket":{"type":"object","required":["bucket_start","status","total_checks","operational_count","degraded_count","down_count","uptime_percentage"],"properties":{"avg_response_time_ms":{"type":["number","null"],"format":"double"},"bucket_start":{"type":"string","format":"date-time"},"degraded_count":{"type":"integer","format":"int64"},"down_count":{"type":"integer","format":"int64"},"max_response_time_ms":{"type":["number","null"],"format":"double"},"min_response_time_ms":{"type":["number","null"],"format":"double"},"operational_count":{"type":"integer","format":"int64"},"p50_response_time_ms":{"type":["number","null"],"format":"double"},"p95_response_time_ms":{"type":["number","null"],"format":"double"},"p99_response_time_ms":{"type":["number","null"],"format":"double"},"status":{"type":"string"},"total_checks":{"type":"integer","format":"int64"},"uptime_percentage":{"type":"number","format":"double"}}},"StatusBucketedResponse":{"type":"object","required":["monitor_id","interval","buckets"],"properties":{"buckets":{"type":"array","items":{"$ref":"#/components/schemas/StatusBucket"}},"interval":{"type":"string"},"monitor_id":{"type":"integer","format":"int32"}}},"StatusCodeCount":{"type":"object","required":["status_code","count","percentage"],"properties":{"count":{"type":"integer","format":"int64"},"percentage":{"type":"number","format":"double"},"status_code":{"type":"integer","format":"int32"}}},"StatusCodesQuery":{"type":"object","required":["start_date","end_date","project_id"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"StatusPageOverview":{"type":"object","required":["status","monitors","recent_incidents"],"properties":{"monitors":{"type":"array","items":{"$ref":"#/components/schemas/MonitorStatus"}},"recent_incidents":{"type":"array","items":{"$ref":"#/components/schemas/IncidentResponse"}},"status":{"type":"string"}}},"StepConversionResponse":{"type":"object","required":["step_id","step_name","step_order","completions","conversion_rate","drop_off_rate","average_time_to_complete_seconds"],"properties":{"average_time_to_complete_seconds":{"type":"number","format":"double"},"completions":{"type":"integer","format":"int64","minimum":0},"conversion_rate":{"type":"number","format":"double"},"drop_off_rate":{"type":"number","format":"double"},"step_id":{"type":"integer","format":"int32"},"step_name":{"type":"string"},"step_order":{"type":"integer","format":"int32"}}},"StepResourceType":{"type":"string","description":"What kind of resource a migration step operates on","enum":["project","environment","deployment","environment-variable","service","domain","git-link","other"]},"StepResult":{"type":"object","description":"Result of executing a single migration step","required":["step_id","step_title","success","skipped","message","created_resources","duration_seconds"],"properties":{"created_resources":{"type":"array","items":{"$ref":"#/components/schemas/CreatedResource"},"description":"Resources created by this step"},"duration_seconds":{"type":"number","format":"double","description":"Duration of this step"},"message":{"type":"string","description":"Human-readable message about what happened"},"skipped":{"type":"boolean","description":"Whether this step was skipped"},"step_id":{"type":"string","description":"Step ID (matches `MigrationStep.id`)"},"step_title":{"type":"string","description":"Step title (for display)"},"success":{"type":"boolean","description":"Whether this step succeeded"}}},"StepUpResponse":{"type":"object","required":["expires_at"],"properties":{"expires_at":{"type":"string","format":"date-time","description":"ISO 8601 timestamp after which sensitive actions require verification\nagain."}}},"StopSequence":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]},"StorageQuota":{"type":"object","description":"Quota usage information for a project.","required":["project_id","metrics_bytes","traces_bytes","logs_bytes","total_bytes","limit_bytes","usage_pct"],"properties":{"limit_bytes":{"type":"integer","format":"int64","minimum":0},"logs_bytes":{"type":"integer","format":"int64","minimum":0},"metrics_bytes":{"type":"integer","format":"int64","minimum":0},"project_id":{"type":"integer","format":"int32"},"total_bytes":{"type":"integer","format":"int64","minimum":0},"traces_bytes":{"type":"integer","format":"int64","minimum":0},"usage_pct":{"type":"number","format":"double"}}},"StripeConfig":{"type":"object","properties":{"include_unpriced_charges":{"type":"boolean","description":"When an allowlist is set, should we still ingest charges that\nlack a price reference (e.g. standalone `charge.succeeded` without\na subscription)? Default true — charges don't belong to a SKU."},"metered_mode":{"$ref":"#/components/schemas/MeteredMode","description":"How to compute MRR for metered / tiered / hybrid subscriptions."},"price_allowlist":{"type":"array","items":{"type":"string"},"description":"Only events tagged with one of these Stripe price IDs are ingested.\nEmpty = accept all prices."},"product_allowlist":{"type":"array","items":{"type":"string"},"description":"Only events tagged with one of these Stripe product IDs are\ningested. Empty = accept all products. Combined with\n`price_allowlist` via OR — if either list has a match, accept."}}},"SupervisorKind":{"type":"string","description":"What (if anything) will restart the process after it exits.","enum":["systemd","launchd","container","none"]},"SyncedRepositoryListQuery":{"type":"object","properties":{"direction":{"type":["string","null"]},"git_provider_connection_id":{"type":["integer","null"],"format":"int32"},"language":{"type":["string","null"]},"owner":{"type":["string","null"]},"page":{"type":["integer","null"],"format":"int64","minimum":0},"per_page":{"type":["integer","null"],"format":"int64","minimum":0},"private":{"type":["boolean","null"]},"search":{"type":["string","null"]},"sort":{"type":["string","null"]}}},"SyntaxResult":{"type":"object","description":"Syntax validation result","required":["is_valid_syntax"],"properties":{"domain":{"type":["string","null"],"description":"The domain part of the email","example":"gmail.com"},"is_valid_syntax":{"type":"boolean","description":"Whether the email syntax is valid"},"suggestion":{"type":["string","null"],"description":"Suggested email correction if available"},"username":{"type":["string","null"],"description":"The username part of the email","example":"someone"}}},"TagInfo":{"type":"object","required":["name","commit_sha"],"properties":{"commit_sha":{"type":"string"},"name":{"type":"string"}}},"TagListResponse":{"type":"object","required":["tags"],"properties":{"tags":{"type":"array","items":{"$ref":"#/components/schemas/TagInfo"}}}},"TailLogsRequest":{"type":"object","required":["project_id","service","env"],"properties":{"env":{"type":"string"},"external_service_id":{"type":["integer","null"],"format":"int32","description":"When set, tail an imported/managed external service's logs instead of\na project's (`project_id` is ignored in this mode)."},"levels":{"type":"array","items":{"type":"string"}},"project_id":{"type":"integer","format":"int32","description":"Project ID (integer, as used by the rest of the platform)"},"service":{"type":"string"},"text":{"type":["string","null"]}}},"TargetRecommendation":{"type":"object","description":"The temps/Hetzner target sizing and savings estimate","required":["server_type","vcpus","memory_gb","monthly_eur","fits_single_node","sizing_basis","rationale"],"properties":{"fits_single_node":{"type":"boolean","description":"Whether the workloads fit a single recommended server. When `false`,\nthe rationale explains the multi-node option (temps worker nodes)."},"memory_gb":{"type":"integer","format":"int32","description":"Memory (GB) of the recommended server"},"monthly_eur":{"type":"number","format":"double","description":"Estimated monthly price of the recommended server in EUR"},"monthly_savings_usd":{"type":["number","null"],"format":"double","description":"Estimated monthly savings in USD (current cost minus target cost,\ntreating EUR≈USD for the rough comparison — disclaimed in `notes`).\n`None` when the current cost is unknown."},"rationale":{"type":"string","description":"Human-readable recommendation summary"},"server_type":{"type":"string","description":"Recommended Hetzner server type (e.g. \"cpx32\")"},"sizing_basis":{"type":"string","description":"What the sizing was based on, e.g. \"2× measured usage + temps\nplatform overhead\" or \"resource requests (no metrics available)\""},"vcpus":{"type":"integer","format":"int32","description":"vCPUs of the recommended server"},"yearly_savings_usd":{"type":["number","null"],"format":"double","description":"`monthly_savings_usd × 12`"}}},"TeamListResponse":{"type":"object","required":["teams","total","page","page_size"],"properties":{"page":{"type":"integer","format":"int64","minimum":0},"page_size":{"type":"integer","format":"int64","minimum":0},"teams":{"type":"array","items":{"$ref":"#/components/schemas/TeamResponse"}},"total":{"type":"integer","format":"int64","minimum":0}}},"TeamMemberResponse":{"type":"object","required":["id","team_id","user_id","role","added_by","created_at","updated_at"],"properties":{"added_by":{"type":"integer","format":"int32"},"created_at":{"type":"string","format":"date-time","example":"2026-07-30T12:15:47.609192Z"},"id":{"type":"integer","format":"int32"},"role":{"$ref":"#/components/schemas/TeamRole","description":"The source of this member's project-scoped permissions, intersected\nwith `project_team_access.role`."},"team_id":{"type":"integer","format":"int32"},"updated_at":{"type":"string","format":"date-time","example":"2026-07-30T12:15:47.609192Z"},"user_email":{"type":["string","null"],"description":"The member's email, joined from `users`."},"user_id":{"type":"integer","format":"int32"},"user_name":{"type":["string","null"],"description":"The member's display name, joined from `users`. `None` if the\nreferenced user no longer exists."}}},"TeamResponse":{"type":"object","required":["id","name","slug","created_by","created_at","updated_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2026-07-30T12:15:47.609192Z"},"created_by":{"type":"integer","format":"int32"},"description":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"name":{"type":"string"},"slug":{"type":"string"},"updated_at":{"type":"string","format":"date-time","example":"2026-07-30T12:15:47.609192Z"}}},"TeamRole":{"type":"string","description":"Role a user holds within a team, or that a team holds on a project.\n\nNamed `TeamRole` rather than `Role` to keep it distinct from\n`temps_auth::permissions::Role`, which is the instance-wide role\n(Admin/User/…) attached to a session. The two are orthogonal: the\ninstance-wide role decides whether you may touch a resource *kind* at\nall, `TeamRole` decides what you may do *within a project* you have\nteam access to. See `temps_teams::fixed_role_permissions` for the\nproject-scoped permission set each variant maps to.\n\nStored as a `varchar(32)` rather than a Postgres enum so the role set\ncan evolve in pure migration code without a schema-level enum\nalteration blocking a downgrade.","enum":["owner","admin","deployer","viewer"]},"TemplateResponse":{"type":"object","description":"Response type for a single template","required":["slug","name","git","preset","tags","features","services","env_vars","is_featured"],"properties":{"description":{"type":["string","null"],"description":"Short description"},"env_vars":{"type":"array","items":{"$ref":"#/components/schemas/EnvVarTemplateResponse"},"description":"Environment variables template"},"exposed_port":{"type":["integer","null"],"format":"int32","description":"Container port the prebuilt image listens on (image deploys only)."},"features":{"type":"array","items":{"type":"string"},"description":"Feature highlights"},"git":{"$ref":"#/components/schemas/GitRefResponse","description":"Git repository reference"},"health_check_path":{"type":["string","null"],"description":"HTTP health-check path probed after the container starts (image deploys)."},"image":{"type":["string","null"],"description":"Prebuilt Docker image reference. When set, the one-click deploy pulls and\nruns this image directly (no build); when absent it builds from `git`."},"image_url":{"type":["string","null"],"description":"URL to template image/icon"},"is_featured":{"type":"boolean","description":"Whether the template is featured/promoted"},"name":{"type":"string","description":"Display name"},"preset":{"type":"string","description":"Framework/preset to use"},"screenshot_url":{"type":["string","null"],"description":"URL to a wide screenshot/banner preview of the deployed template.\nAbsent for templates that don't have one captured yet."},"services":{"type":"array","items":{"type":"string"},"description":"Required external services"},"slug":{"type":"string","description":"Unique identifier for the template (used in URLs)"},"tags":{"type":"array","items":{"type":"string"},"description":"Tags/categories for filtering"}}},"TestEmailRequest":{"type":"object","description":"Request body for testing an email provider","required":["from"],"properties":{"from":{"type":"string","description":"Sender email address (must be verified with the provider)","example":"test@example.com"},"from_name":{"type":["string","null"],"description":"Sender display name","example":"My App"}}},"TestEmailResponse":{"type":"object","description":"Response for test email endpoint","required":["success","sent_to"],"properties":{"error":{"type":["string","null"],"description":"Error message if the test failed"},"provider_message_id":{"type":["string","null"],"description":"Provider message ID if successful"},"sent_to":{"type":"string","description":"The email address the test was sent to","example":"user@example.com"},"success":{"type":"boolean","description":"Whether the test email was sent successfully"}}},"TestProviderKeyRequest":{"type":"object","required":["provider","api_key"],"properties":{"api_key":{"type":"string","description":"The raw API key to test"},"base_url":{"type":["string","null"],"description":"Optional custom base URL"},"provider":{"type":"string","description":"Provider ID: \"openai\", \"anthropic\", \"xai\", \"gemini\""}}},"TestProviderKeyResponse":{"type":"object","required":["success","provider","latency_ms"],"properties":{"error":{"type":["string","null"],"description":"Error message if the test failed"},"latency_ms":{"type":"integer","format":"int64","description":"Response time in milliseconds","minimum":0},"provider":{"type":"string"},"success":{"type":"boolean"}}},"TestProviderResponse":{"type":"object","required":["success"],"properties":{"message":{"type":["string","null"]},"success":{"type":"boolean"}}},"TimeBucketStats":{"type":"object","description":"Time bucket statistics response","required":["bucket","request_count","avg_response_time_ms","error_count","total_request_bytes","total_response_bytes"],"properties":{"avg_response_time_ms":{"type":"number","format":"double","description":"Average response time in milliseconds"},"bucket":{"type":"string","description":"Bucket timestamp in RFC3339 format","example":"2025-10-23T12:00:00Z"},"error_count":{"type":"integer","format":"int64","description":"Number of errors (status >= 400)"},"request_count":{"type":"integer","format":"int64","description":"Total number of requests in this bucket"},"total_request_bytes":{"type":"integer","format":"int64","description":"Total request bytes"},"total_response_bytes":{"type":"integer","format":"int64","description":"Total response bytes"}}},"TimeBucketStatsResponse":{"type":"object","description":"Response for time bucket stats","required":["stats","start_time","end_time","bucket_interval"],"properties":{"bucket_interval":{"type":"string"},"end_time":{"type":"string"},"start_time":{"type":"string"},"stats":{"type":"array","items":{"$ref":"#/components/schemas/TimeBucketStats"}}}},"TimeseriesBucket":{"type":"object","required":["bucket","request_count","input_tokens","output_tokens","avg_latency_ms"],"properties":{"avg_latency_ms":{"type":"number","format":"double"},"bucket":{"type":"string","description":"ISO 8601 timestamp"},"input_tokens":{"type":"integer","format":"int64"},"output_tokens":{"type":"integer","format":"int64"},"request_count":{"type":"integer","format":"int64"}}},"TimeseriesQueryParams":{"type":"object","properties":{"bucket":{"type":["string","null"],"description":"Bucket size: \"hour\", \"day\", \"week\" (defaults to \"day\")"},"conversation_id":{"type":["string","null"],"description":"Filter by conversation ID"},"from":{"type":["string","null"],"description":"ISO 8601 start time (defaults to 24h ago)"},"model":{"type":["string","null"],"description":"Filter by model name"},"provider":{"type":["string","null"],"description":"Filter by provider name"},"tags":{"type":["string","null"],"description":"Filter by tags (comma-separated, AND logic)"},"to":{"type":["string","null"],"description":"ISO 8601 end time (defaults to now)"},"user_id":{"type":["integer","null"],"format":"int32","description":"Filter by user ID"}}},"TlsMode":{"type":"string","enum":["None","Starttls","Tls"]},"TodayStatsResponse":{"type":"object","description":"Today's stats response","required":["total_requests","date"],"properties":{"date":{"type":"string","description":"Date for which stats are returned","example":"2025-10-23"},"total_requests":{"type":"integer","format":"int64","description":"Total requests today"}}},"ToggleAiDataAccessRequest":{"type":"object","required":["enabled"],"properties":{"enabled":{"type":"boolean","description":"Whether the AI assistant may read row data from this service.","example":false}}},"ToggleDeploymentMetricsRequest":{"type":"object","description":"Request body to toggle OTLP metric ingestion for a deployment.","required":["enabled"],"properties":{"enabled":{"type":"boolean","description":"Whether to enable (`true`) or disable (`false`) metric ingestion."},"path":{"type":["string","null"],"description":"Prometheus scrape path (optional, defaults to `/metrics`)."},"port":{"type":["integer","null"],"format":"int32","description":"Prometheus scrape port (optional).","minimum":0}}},"ToggleServiceMetricsRequest":{"type":"object","description":"Request body to toggle metric collection for an external service.","required":["enabled"],"properties":{"enabled":{"type":"boolean","description":"Whether to enable (`true`) or disable (`false`) metric collection."}}},"TokenRenewalRequest":{"type":"object","required":["refresh_token"],"properties":{"refresh_token":{"type":"string"}}},"ToolCallEvent":{"type":"object","description":"Payload for the `tool_call` SSE event: the model is about to run a tool.\nSerialized as compact single-line JSON onto one `data:` line.","required":["id","name","arguments"],"properties":{"arguments":{"type":"string","description":"The raw JSON-args string the model emitted."},"id":{"type":"string"},"name":{"type":"string"}}},"ToolInfo":{"type":"object","description":"One persisted tool invocation + its result, attached to an assistant message.","required":["id","name","arguments"],"properties":{"arguments":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"},"result":{"type":["string","null"]}}},"ToolResultEvent":{"type":"object","description":"Payload for the `tool_result` SSE event: a tool finished running. Serialized\nas compact single-line JSON; `content` is JSON-string-escaped so it stays on\none `data:` line even when long.","required":["id","name","content"],"properties":{"content":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"}}},"TopModelsQueryParams":{"type":"object","properties":{"from":{"type":["string","null"],"description":"ISO 8601 start time (defaults to 24h ago)"},"limit":{"type":["integer","null"],"format":"int64","description":"Max results (defaults to 10)","minimum":0},"tags":{"type":["string","null"],"description":"Filter by tags (comma-separated, AND logic)"},"to":{"type":["string","null"],"description":"ISO 8601 end time (defaults to now)"},"user_id":{"type":["integer","null"],"format":"int32","description":"Filter by user ID"}}},"TraceProjectRef":{"type":"object","description":"All projects that contributed spans to a trace, including their sharing flag.\n\nReturned by `CrossProjectTraceService::find_trace_projects`.","required":["project_id","project_name","project_slug","first_seen","sharing"],"properties":{"first_seen":{"type":"string","format":"date-time"},"project_id":{"type":"integer","format":"int32"},"project_name":{"type":"string"},"project_slug":{"type":"string","description":"URL slug used to link into the project's single-project trace view."},"sharing":{"type":"boolean","description":"Whether this project has `cross_project_trace_sharing = true`."}}},"TraceSummariesResponse":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/TraceSummary"}},"total":{"type":["integer","null"],"format":"int64","description":"Total traces matching the filters, ignoring pagination. Omitted when\nthe request passed `include_total=false`, in which case the caller\nasked not to pay for the count — treat its absence as \"unknown\", not\nas zero.","minimum":0}}},"TraceSummary":{"type":"object","description":"A trace summary for the list view — one row per trace, aggregated from spans.","required":["trace_id","root_span_name","service_name","kind","status_code","start_time","duration_ms","span_count","error_count"],"properties":{"deployment_environment":{"type":["string","null"],"description":"The deployment environment from the root span's resource attributes (e.g. \"production\")."},"duration_ms":{"type":"number","format":"double"},"error_count":{"type":"integer","format":"int64"},"kind":{"$ref":"#/components/schemas/SpanKind"},"root_span_name":{"type":"string"},"service_name":{"type":"string"},"span_count":{"type":"integer","format":"int64"},"start_time":{"type":"string","format":"date-time"},"status_code":{"$ref":"#/components/schemas/SpanStatusCode"},"trace_id":{"type":"string"}}},"TracesResponse":{"type":"object","required":["data","count"],"properties":{"count":{"type":"integer","minimum":0},"data":{"type":"array","items":{"$ref":"#/components/schemas/SpanRecord"}}}},"TrackedLinkResponse":{"type":"object","description":"Tracked link with click count","required":["link_index","original_url","click_count"],"properties":{"click_count":{"type":"integer","format":"int32"},"link_index":{"type":"integer","format":"int32"},"original_url":{"type":"string"}}},"TrackingEventResponse":{"type":"object","description":"Email tracking event","required":["id","email_id","event_type","created_at"],"properties":{"created_at":{"type":"string"},"email_id":{"type":"string"},"event_type":{"type":"string"},"id":{"type":"integer","format":"int64"},"ip_address":{"type":["string","null"]},"link_index":{"type":["integer","null"],"format":"int32"},"link_url":{"type":["string","null"]},"user_agent":{"type":["string","null"]}}},"TriggerAgentRequest":{"type":"object","properties":{"trigger_source_id":{"type":["integer","null"],"format":"int32"},"trigger_source_type":{"type":["string","null"]},"user_context":{"type":["string","null"],"description":"Optional context from the user (e.g. a research topic, bug description, or instructions)."}}},"TriggerDigestResponse":{"type":"object","required":["success","message"],"properties":{"message":{"type":"string"},"success":{"type":"boolean"}}},"TriggerPipelinePayload":{"type":"object","properties":{"branch":{"type":["string","null"]},"commit":{"type":["string","null"]},"environment_id":{"type":["integer","null"],"format":"int32","description":"Optional environment ID - if not provided, will use the project's preview environment"},"tag":{"type":["string","null"]}}},"TriggerPipelineResponse":{"type":"object","required":["message","project_id","environment_id"],"properties":{"branch":{"type":["string","null"]},"commit":{"type":["string","null"]},"environment_id":{"type":"integer","format":"int32"},"message":{"type":"string"},"project_id":{"type":"integer","format":"int32"},"tag":{"type":["string","null"]}}},"TriggerScanRequest":{"type":"object","required":["environment_id"],"properties":{"environment_id":{"type":"integer","format":"int32","description":"Environment ID to scan (uses the current deployment for this environment)","example":1}}},"TriggerScanResponse":{"type":"object","required":["scan_id","status","message"],"properties":{"message":{"type":"string"},"scan_id":{"type":"integer","format":"int32"},"status":{"type":"string"}}},"TtlRequest":{"type":"object","description":"Request to get TTL for a key","required":["key"],"properties":{"key":{"type":"string","description":"The key to check TTL for","example":"session:abc"},"project_id":{"type":["integer","null"],"format":"int32","description":"Project ID (required for API key/session auth, optional for deployment tokens)","example":1}}},"TtlResponse":{"type":"object","description":"Response for TTL operation","required":["ttl"],"properties":{"ttl":{"type":"integer","format":"int64","description":"TTL in seconds, -1 if no expiration, -2 if key doesn't exist","example":3600}}},"TxtRecord":{"type":"object","required":["name","value"],"properties":{"name":{"type":"string"},"value":{"type":"string"}}},"UiManifest":{"type":"object","description":"Describes the plugin's embedded UI bundle.","required":["entry_js"],"properties":{"css":{"type":"array","items":{"type":"string"},"description":"CSS files to load"},"entry_js":{"type":"string","description":"JavaScript entry point filename relative to the bundle root"},"routes":{"type":"array","items":{"$ref":"#/components/schemas/UiRoute"},"description":"Client-side routes the plugin handles"}}},"UiRoute":{"type":"object","description":"A client-side route provided by the plugin UI.","required":["path","title"],"properties":{"path":{"type":"string","description":"Route path pattern (e.g., \"/my-plugin\", \"/my-plugin/:id\")"},"title":{"type":"string","description":"Page title for breadcrumbs"}}},"UndrainNodeResponse":{"type":"object","description":"Response after undraining (reactivating) a node.","required":["id","name","status","message"],"properties":{"id":{"type":"integer","format":"int32"},"message":{"type":"string"},"name":{"type":"string"},"status":{"type":"string"}}},"UnifiedTrace":{"type":"object","description":"Merged cross-project trace result (Phase 2 unified waterfall).\n\nSpans are sorted by `start_time ASC`. At most 20 projects and 10,000\nspans total are included; `truncated` / `truncated_projects` signal when\nthe caps were hit.","required":["trace_id","projects","spans","start_time","end_time","total_duration_ms","span_count","error_count","has_redacted_spans","truncated","truncated_projects"],"properties":{"end_time":{"type":"string","format":"date-time"},"error_count":{"type":"integer","minimum":0},"has_redacted_spans":{"type":"boolean","description":"`true` when at least one project has `cross_project_trace_sharing = false`\nand its spans were therefore excluded from the result set."},"projects":{"type":"array","items":{"$ref":"#/components/schemas/ProjectRef"},"description":"Projects that contributed spans to this result set."},"span_count":{"type":"integer","minimum":0},"spans":{"type":"array","items":{"$ref":"#/components/schemas/AnnotatedSpan"},"description":"Annotated, merged span list sorted by `start_time ASC`."},"start_time":{"type":"string","format":"date-time"},"total_duration_ms":{"type":"number","format":"double","description":"Trace wall-clock duration in milliseconds (`end_time – start_time`)."},"trace_id":{"type":"string"},"truncated":{"type":"boolean","description":"`true` when the 20-project or 10,000-span cap was hit."},"truncated_projects":{"type":"array","items":{"type":"integer","format":"int32"},"description":"project_ids excluded due to truncation (most-recent first_seen dropped first)."}}},"UniqueCountsQuery":{"type":"object","description":"Query parameters for unique counts over time frame","required":["start_date","end_date"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32","description":"Optional deployment filter"},"end_date":{"type":"string","format":"date-time","description":"End date for the query range"},"environment_id":{"type":["integer","null"],"format":"int32","description":"Optional environment filter"},"metric":{"type":"string","description":"Metric to count: \"sessions\" (unique sessions), \"visitors\" (unique visitors),\n\"returning_visitors\" (visitors seen before the range), or \"page_views\"\n(total page views) (default: \"sessions\")"},"start_date":{"type":"string","format":"date-time","description":"Start date for the query range"}}},"UniqueCountsResponse":{"type":"object","required":["count"],"properties":{"count":{"type":"integer","format":"int64"}}},"UnsupportedFeature":{"type":"object","description":"A feature from the source platform that cannot be migrated","required":["feature","reason"],"properties":{"alternative":{"type":["string","null"],"description":"Suggested alternative in Temps (if any)"},"feature":{"type":"string","description":"Feature name (e.g., \"Edge Middleware\", \"Serverless Functions\", \"Cron Jobs\")"},"reason":{"type":"string","description":"Why it can't be migrated"}}},"UpdateAdminGateRequest":{"type":"object","required":["allowed_ips","allowed_hosts","trust_forwarded_for"],"properties":{"allowed_hosts":{"type":"array","items":{"type":"string"}},"allowed_ips":{"type":"array","items":{"type":"string"}},"trust_forwarded_for":{"type":"boolean"}}},"UpdateAiProviderRequest":{"type":"object","description":"Body for `PATCH /settings/ai-providers/{provider_id}` — updates\nprovider-scoped settings (just the default model for now) without\ntouching the credential. Keeping credentials out of this shape means\nthe UI can auto-save model changes on select, without forcing the user\nto re-paste their token or config file.\nName-spaced schema name avoids an OpenAPI collision with\n`temps-notifications::UpdateProviderRequest`, which has different fields.\nBoth are exposed as `utoipa::ToSchema`; without the override the merged\nOpenAPI doc would silently shadow one struct with the other and break\ngenerated CLI/web clients.","properties":{"default_model":{"type":["string","null"],"description":"New default model id. `None` or an empty string clears the stored\nvalue so the CLI falls back to its own default."},"max_turns_analysis":{"type":["integer","null"],"format":"int32","description":"Default max turns for the autofixer analysis phase (1–200). `0`\nclears the stored value (built-in default applies); omitted/`None`\nleaves the current value unchanged — so a PATCH that only updates\n`default_model` doesn't wipe the turn settings."},"max_turns_feedback":{"type":["integer","null"],"format":"int32","description":"Default max turns for autofixer feedback rounds (1–200). `0` clears;\nomitted leaves unchanged."},"max_turns_fix":{"type":["integer","null"],"format":"int32","description":"Default max turns for the autofixer fix phase (1–200). `0` clears;\nomitted leaves unchanged."}}},"UpdateAiProviderResponse":{"type":"object","required":["provider_id"],"properties":{"default_model":{"type":["string","null"]},"max_turns_analysis":{"type":["integer","null"],"format":"int32"},"max_turns_feedback":{"type":["integer","null"],"format":"int32"},"max_turns_fix":{"type":["integer","null"],"format":"int32"},"provider_id":{"type":"string"}}},"UpdateAlertRuleRequest":{"type":"object","properties":{"cooldown_minutes":{"type":["integer","null"],"format":"int32"},"enabled":{"type":["boolean","null"]},"environment_filter":{"type":["integer","null"],"format":"int32"},"error_level_filter":{"type":["string","null"]},"name":{"type":["string","null"]},"notification_priority":{"type":["string","null"]},"trigger_config":{},"trigger_type":{"type":["string","null"]}}},"UpdateApiKeyRequest":{"type":"object","properties":{"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"is_active":{"type":["boolean","null"]},"name":{"type":["string","null"]},"permissions":{"type":["array","null"],"items":{"type":"string"},"example":["projects:read","deployments:read"]}}},"UpdateAutomaticDeployRequest":{"type":"object","required":["automatic_deploy"],"properties":{"automatic_deploy":{"type":"boolean"}}},"UpdateBackupScheduleRequest":{"type":"object","description":"Request body for updating an existing backup schedule via `PATCH /api/backups/schedules/{id}`.\n\nAll fields are optional; only present fields are updated. Absent fields\nleave the corresponding column unchanged.","properties":{"description":{"type":["string","null"],"description":"New human-readable description. Pass an empty string `\"\"` to clear."},"enabled":{"type":["boolean","null"],"description":"Enable or disable the schedule. Skipped when `None`."},"include_control_plane":{"type":["boolean","null"],"description":"Toggle whether the control-plane backup is produced on every run."},"max_runtime_secs":{"type":["integer","null"],"format":"int64","description":"Per-schedule wall-clock timeout override (seconds).\n\n- `None` (field absent) — leave current value unchanged\n- `Some(None)` (field present, JSON `null`) — clear override; fall back to engine default\n- `Some(Some(n))` — set to `n` seconds (must be >= 60)"},"name":{"type":["string","null"],"description":"New schedule name. Skipped when `None`. Must not be empty if provided."},"retention_period":{"type":["integer","null"],"format":"int32","description":"Days to retain backups produced by this schedule. Must be >= 1."},"schedule_expression":{"type":["string","null"],"description":"New cron expression. When changed, `next_run` is recomputed."},"tags":{"type":["array","null"],"items":{"type":"string"},"description":"Replace the full tag list. Skipped when `None`."},"target_all_services":{"type":["boolean","null"],"description":"Toggle between \"back up every database\" (`true`) and \"back up only\nthe explicit list\" (`false`). When set to `true`, the server clears\nthe explicit membership rows for this schedule."}}},"UpdateBlobRequest":{"type":"object","description":"Request to update Blob service configuration","properties":{"docker_image":{"type":["string","null"],"description":"Docker image to use (e.g., \"rustfs/rustfs:1.0.0-alpha.98\")","example":"rustfs/rustfs:1.0.0-alpha.98"}}},"UpdateBlobResponse":{"type":"object","description":"Response after updating Blob service","required":["success","message","status"],"properties":{"message":{"type":"string","description":"Human-readable message","example":"Blob service updated successfully"},"status":{"$ref":"#/components/schemas/BlobStatusResponse","description":"Current status"},"success":{"type":"boolean","description":"Whether the operation succeeded","example":true}}},"UpdateCapabilityResponse":{"type":"object","description":"Whether this install can apply a release update on request, and how the last\nattempt went.\n\nDeliberately answerable even when the answer is \"no\": an operator who cannot\nuse the button still needs to know *why* and what to run instead, so this\nnever 404s or returns an empty body when the feature is unavailable.","required":["can_apply","allowed","manual_command","current_version","channel","channel_is_pinned","supervisor","restart_mode","binary_path","phase"],"properties":{"allowed":{"type":"boolean","description":"Whether the *caller* holds `platform:update`. Distinct from `can_apply`,\nwhich describes the server: the console shows the action only when both\nare true, so a reader is never offered a button that would 403."},"binary_path":{"type":"string","description":"Binary that would be replaced."},"blocker":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SelfUpdateBlocker","description":"Machine-readable reason `can_apply` is false (`disabled_by_flag`,\n`disabled_by_setting`, `container`, `no_supervisor`, `binary_not_writable`,\n`unsupported_platform`, `in_progress`)."}]},"can_apply":{"type":"boolean","description":"True only when a request would actually download, install and restart."},"caveat":{"type":["string","null"],"description":"Non-blocking warning to show with the confirmation (split topology)."},"channel":{"type":"string","description":"Channel actually tracked, after applying the configured override or\nfalling back to inference from the running version tag."},"channel_is_pinned":{"type":"boolean","description":"True when `channel` was set explicitly in settings rather than inferred."},"current_version":{"type":"string","description":"Version tag of the running binary. Always present — the version page\nneeds it whether or not an update exists."},"last_attempt":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SelfUpdateAttempt","description":"Most recent attempt, including one resolved during this boot — this is\nhow the console reports the outcome of an update that restarted it."}]},"manual_command":{"type":"string","description":"The equivalent command to run by hand. Always present."},"phase":{"$ref":"#/components/schemas/SelfUpdatePhase","description":"Phase of an in-flight attempt: `idle` when none is running."},"phase_error":{"type":["string","null"],"description":"Failure detail while `phase` is `failed`."},"reason":{"type":["string","null"],"description":"Operator-facing explanation of `blocker`."},"restart_mode":{"$ref":"#/components/schemas/SelfUpdateRestartMode","description":"`automatic` when applying an update also restarts temps; `manual` when\nit only installs the binary and the operator restarts on their own\nschedule. Lets the console set expectations before the click."},"supervisor":{"$ref":"#/components/schemas/SupervisorKind","description":"What would restart the process: `systemd`, `launchd`, `container`, `none`."}}},"UpdateCloudflareProviderRequest":{"type":"object","required":["config"],"properties":{"config":{"$ref":"#/components/schemas/CloudflareConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":["string","null"]}}},"UpdateConfigBody":{"type":"object","properties":{"config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ProviderConfig","description":"Typed provider configuration. Setting `config` to `null` clears\nthe stored config back to the accept-everything default. The\nconfig's `provider` tag must match the integration's provider."}]}}},"UpdateCustomDomainRequest":{"type":"object","properties":{"branch":{"type":["string","null"]},"domain":{"type":["string","null"]},"environment_id":{"type":["integer","null"],"format":"int32"},"redirect_to":{"type":["string","null"]},"service_name":{"type":["string","null"],"description":"Docker Compose service name this domain routes to (empty string clears it)"},"status_code":{"type":["integer","null"],"format":"int32"}}},"UpdateDashboardRequest":{"type":"object","properties":{"layout":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DashboardLayout"}]},"name":{"type":["string","null"]}}},"UpdateDeploymentConfigRequest":{"type":"object","properties":{"automaticDeploy":{"type":["boolean","null"]},"cpuLimit":{"type":["integer","null"],"format":"int32"},"cpuRequest":{"type":["integer","null"],"format":"int32"},"crossArchitectureBuilds":{"type":["boolean","null"],"description":"Build one image per architecture the eligible nodes run. Off by\ndefault; environments inherit this and may override it. Cross-builds\nare emulated on the control plane and substantially slower, so they are\nopted into rather than triggered by cluster topology."},"exposedPort":{"type":["integer","null"],"format":"int32"},"memoryLimit":{"type":["integer","null"],"format":"int32"},"memoryRequest":{"type":["integer","null"],"format":"int32"},"performanceMetricsEnabled":{"type":["boolean","null"]},"replicas":{"type":["integer","null"],"format":"int32"},"security":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SecurityConfig"}]},"sessionRecordingEnabled":{"type":["boolean","null"]}}},"UpdateDeploymentTokenRequest":{"type":"object","properties":{"expires_at":{"type":["string","null"],"format":"date-time","example":"2024-12-31T23:59:59Z"},"is_active":{"type":["boolean","null"]},"name":{"type":["string","null"]},"permissions":{"type":["array","null"],"items":{"type":"string"},"example":["visitors:enrich","emails:send"]}}},"UpdateDnsProviderRequest":{"type":"object","description":"Request to update a DNS provider","properties":{"credentials":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DnsProviderCredentials","description":"New credentials"}]},"description":{"type":["string","null"],"description":"New description"},"is_active":{"type":["boolean","null"],"description":"Active status"},"name":{"type":["string","null"],"description":"New name"}}},"UpdateEmailProviderRequest":{"type":"object","description":"Request body for `PATCH /email-providers/{id}`.\n\nAll fields are optional. Omit any field to leave it unchanged. The\n`provider_type` is immutable — to switch providers, delete the row and\ncreate a new one. For credentials, supplying any credential variant\nre-encrypts the stored blob; omitting them preserves the existing secret\n(so operators can rename without re-typing passwords).","properties":{"is_active":{"type":["boolean","null"]},"name":{"type":["string","null"],"example":"My AWS SES"},"region":{"type":["string","null"],"example":"us-east-1"},"scaleway_credentials":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ScalewayCredentialsRequest"}]},"ses_credentials":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SesCredentialsRequest"}]},"smtp_credentials":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SmtpCredentialsRequest"}]},"sns_topic_arn":{"type":["string","null"],"description":"Rotate or clear the exact SNS topic allowed for this SES provider.\nOmit to preserve it, send `null` to clear it, or send a string to set it."}}},"UpdateEnvironmentSettingsRequest":{"type":"object","properties":{"anti_affinity":{"type":["boolean","null"],"description":"Anti-affinity: spread replicas across different nodes.\nWhen enabled, the scheduler avoids placing two replicas of the same\nenvironment on the same node. Defaults to `true`."},"attack_mode":{"type":["boolean","null"],"description":"Per-environment CAPTCHA attack-mode override (tri-state):\n- absent → leave the current override unchanged\n- JSON `null` → clear the override (inherit the project-level setting)\n- `true`/`false` → override the project setting for this environment"},"automatic_deploy":{"type":["boolean","null"],"description":"Enable/disable automatic deployments for this environment"},"branch":{"type":["string","null"]},"cpu_limit":{"type":["integer","null"],"format":"int32","description":"Maximum (limit) CPU in microcores. Send JSON `null` to clear → \"no limit\".\nAbsent leaves the current value unchanged."},"cpu_request":{"type":["integer","null"],"format":"int32","description":"Minimum (request) CPU in microcores. Send JSON `null` to clear (no request).\nAbsent leaves the current value unchanged."},"cross_architecture_builds":{"type":["boolean","null"],"description":"Build one image per architecture the eligible nodes run (overrides the\nproject-level setting). Off by default: cross-architecture builds are\nemulated on the control plane and substantially slower, so they are\nopted into per environment rather than triggered by cluster topology."},"exposed_port":{"type":["integer","null"],"format":"int32","description":"Port exposed by the container (overrides project-level port for this environment)\n\nPriority order for port resolution:\n1. Image EXPOSE directive (auto-detected from built image)\n2. This environment-level exposed_port (overrides project setting)\n3. Project-level exposed_port (fallback)\n4. Default: 3000","example":8080},"force_https":{"type":["boolean","null"],"description":"Per-environment HTTP→HTTPS redirect override (tri-state):\n- absent → leave the current override unchanged\n- JSON `null` → clear the override (inherit the proxy default, which\n redirects only when the host has an active TLS certificate)\n- `true` → always redirect plain HTTP to HTTPS for this environment,\n even when no local certificate exists (TLS terminated upstream)\n- `false` → never redirect this environment, even when a certificate does\n exist\n\nRequests under `/.well-known/acme-challenge/` are never redirected\nregardless of this setting, so ACME HTTP-01 validation always completes."},"idle_timeout_seconds":{"type":["integer","null"],"format":"int32","description":"Seconds of inactivity before stopping containers (60-86400). Default: 300."},"memory_limit":{"type":["integer","null"],"format":"int32","description":"Maximum (limit) memory in MB. Send JSON `null` to clear → \"no limit\".\nAbsent leaves the current value unchanged."},"memory_request":{"type":["integer","null"],"format":"int32","description":"Minimum (request) memory in MB. Send JSON `null` to clear (no request).\nAbsent leaves the current value unchanged."},"on_demand":{"type":["boolean","null"],"description":"Enable on-demand mode (scale-to-zero). Containers are stopped after\nidle_timeout_seconds of no traffic and started on the next request."},"password":{"type":["string","null"],"description":"Set a password to protect this environment. The proxy will show an HTML\npassword form before allowing access. The password is bcrypt-hashed\nserver-side and never stored in plaintext.\nSend an empty string to remove password protection."},"performance_metrics_enabled":{"type":["boolean","null"],"description":"Enable/disable performance metrics collection"},"protected":{"type":["boolean","null"],"description":"When true, git pushes do NOT auto-deploy to this environment.\nDeployments must be promoted from another environment."},"replicas":{"type":["integer","null"],"format":"int32"},"security":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/SecurityConfig","description":"Security configuration for this environment (overrides project-level settings)"}]},"session_recording_enabled":{"type":["boolean","null"],"description":"Enable/disable session recording"},"target_labels":{"description":"Label selector for node-based scheduling (overrides project-level setting).\nSame key with array value -> OR, different keys -> AND.\nExample: `{\"region\": [\"us\", \"asia\"], \"gpu\": \"true\"}`"},"target_nodes":{"type":["array","null"],"items":{"type":"integer","format":"int32"},"description":"Optional list of node IDs to deploy to (overrides project-level setting)"},"wake_timeout_seconds":{"type":["integer","null"],"format":"int32","description":"Max seconds to wait for containers to start on wake (5-120). Default: 30."}}},"UpdateEnvironmentSubdomainRequest":{"type":"object","description":"Request to rename an environment's auto-managed subdomain.\n\nThe subdomain is the host label inserted in front of the platform's\npreview domain (e.g. `myapp` in `myapp.preview.temps.sh`). Renaming\nreplaces the previous subdomain entirely — the old hostname stops\nresolving immediately after this request succeeds.","required":["subdomain"],"properties":{"subdomain":{"type":"string","description":"New subdomain label. Must be a DNS-safe slug (lowercase letters,\ndigits, and hyphens, 1-63 characters). The value is slugified\nserver-side, so casing and disallowed characters are normalized.","example":"myapp"}}},"UpdateEnvironmentVariableRequest":{"type":"object","required":["key","environment_ids"],"properties":{"environment_ids":{"type":"array","items":{"type":"integer","format":"int32"}},"include_in_preview":{"type":"boolean"},"is_secret":{"type":["boolean","null"],"description":"Optional secret-flag transition.\n- `Some(true)` promotes a regular var to a secret.\n- `Some(false)` is rejected if the row is already secret (one-way flag).\n- `None` (omitted) leaves the flag unchanged."},"key":{"type":"string"},"value":{"type":["string","null"],"description":"New plaintext value. `None` (omitted) keeps the existing ciphertext,\nwhich is the only way to edit a secret env var without re-typing its\nvalue (e.g. changing which environments it applies to)."}}},"UpdateErrorGroupRequest":{"type":"object","required":["status"],"properties":{"assigned_to":{"type":["string","null"]},"status":{"type":"string"}}},"UpdateExternalServiceRequest":{"type":"object","required":["parameters"],"properties":{"docker_image":{"type":["string","null"],"description":"Docker image to use for the service (e.g., \"gotempsh/postgres-walg:18-bookworm\", \"timescale/timescaledb-ha:pg18\")\nWhen provided, the service will be recreated with the new image while preserving data"},"parameters":{"type":"object","additionalProperties":{},"propertyNames":{"type":"string"}}}},"UpdateFlagRequest":{"type":"object","properties":{"client_visible":{"type":["boolean","null"]},"default_value":{"description":"Must match the flag's existing `value_type`."},"description":{"type":["string","null"],"description":"Tri-state: absent leaves it, `null` clears it, a string sets it."}}},"UpdateGitSettingsRequest":{"type":"object","required":["main_branch","repo_owner","repo_name","directory"],"properties":{"directory":{"type":"string"},"git_provider_connection_id":{"type":["integer","null"],"format":"int32"},"git_url":{"type":["string","null"],"description":"Git clone URL for public repositories"},"is_public_repo":{"type":["boolean","null"],"description":"Whether this is a public repository (no git provider connection needed)"},"main_branch":{"type":"string"},"preset":{"type":["string","null"]},"preset_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PresetConfigSchema","description":"Preset-specific configuration (e.g., Dockerfile path for Docker preset)\n\nExample for Dockerfile preset:\n```json\n{\n \"dockerfilePath\": \"docker/Dockerfile\",\n \"buildContext\": \"./api\"\n}\n```"}]},"repo_name":{"type":"string"},"repo_owner":{"type":"string"}}},"UpdateIncidentStatusRequest":{"type":"object","required":["status","message"],"properties":{"message":{"type":"string"},"status":{"type":"string"}}},"UpdateIpAccessControlRequest":{"type":"object","description":"Request to update an IP access control rule","properties":{"action":{"type":["string","null"],"description":"Optional new action"},"ip_address":{"type":["string","null"],"description":"Optional new IP address"},"reason":{"type":["string","null"],"description":"Optional new reason"}}},"UpdateKvRequest":{"type":"object","description":"Request to update KV service configuration","properties":{"docker_image":{"type":["string","null"],"description":"Docker image to use (e.g., \"gotempsh/redis-walg:8-bookworm\")","example":"gotempsh/redis-walg:8-bookworm"}}},"UpdateKvResponse":{"type":"object","description":"Response after updating KV service","required":["success","message","status"],"properties":{"message":{"type":"string","description":"Status message","example":"KV service updated successfully"},"status":{"$ref":"#/components/schemas/KvStatusResponse","description":"Current service status"},"success":{"type":"boolean","description":"Whether the operation succeeded"}}},"UpdateManagedDomainApiRequest":{"type":"object","description":"Request to update a managed domain's settings.","properties":{"auto_manage":{"type":["boolean","null"],"description":"Toggle automatic DNS management for this domain."},"generated_hostname_mode":{"type":["string","null"],"description":"`\"standard\"` or `\"flat\"`. Persisted as-is; switching to `\"flat\"` does not\nrecompute existing hostnames — use the apply endpoint for that."},"sync_generated_records":{"type":["boolean","null"],"description":"Toggle DNS record sync for this domain."}}},"UpdateMcpRequest":{"type":"object","required":["config"],"properties":{"config":{"type":"object"},"description":{"type":["string","null"]},"name":{"type":["string","null"]}}},"UpdateMemberRoleRequest":{"type":"object","description":"The new fixed role for an existing membership.","required":["role"],"properties":{"role":{"$ref":"#/components/schemas/TeamRole"}}},"UpdateMetricAlertRequest":{"type":"object","properties":{"aggregation":{"type":["string","null"]},"detection_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/DetectionConfig","description":"Replaces the detector wholesale when present (absent = leave unchanged)."}]},"dynamic_alerts":{"type":["boolean","null"],"description":"Toggles per-series (\"dynamic\") alerting (absent = leave unchanged)."},"enabled":{"type":["boolean","null"]},"for_duration_secs":{"type":["integer","null"],"format":"int32"},"group_by":{"type":["array","null"],"items":{"type":"string"},"description":"Replaces the group_by keys wholesale when present (absent = leave unchanged)."},"grouped_notification_threshold":{"type":["integer","null"],"format":"int32","description":"Updates the notification-grouping threshold (absent = leave unchanged)."},"label_filters":{"type":["array","null"],"items":{"type":"array","items":false,"prefixItems":[{"type":"string"},{"type":"string"}]},"description":"Replaces the label filters wholesale when present (absent = leave unchanged)."},"max_series":{"type":["integer","null"],"format":"int32","description":"Updates the dynamic-alerting cardinality cap (absent = leave unchanged)."},"metric_name":{"type":["string","null"]},"name":{"type":["string","null"]},"severity":{"type":["string","null"]},"window_secs":{"type":["integer","null"],"format":"int32"}}},"UpdateNotificationEmailProviderRequest":{"type":"object","required":["config"],"properties":{"config":{"$ref":"#/components/schemas/EmailConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":["string","null"]}}},"UpdateOidcProviderRequest":{"type":"object","properties":{"client_id":{"type":["string","null"]},"client_secret":{"type":["string","null"]},"default_role":{"type":["string","null"]},"enabled":{"type":["boolean","null"]},"group_claim":{"type":["string","null"]},"issuer_url":{"type":["string","null"]},"jit_provisioning":{"type":["boolean","null"]},"name":{"type":["string","null"]},"role_claim":{"type":["string","null"]},"scopes":{"type":["string","null"]},"template":{"type":["string","null"]},"trust_idp_email":{"type":["boolean","null"]}}},"UpdatePreferencesRequest":{"type":"object","required":["preferences"],"properties":{"preferences":{"$ref":"#/components/schemas/NotificationPreferencesResponse"}}},"UpdateProjectSecretRequest":{"type":"object","description":"Request to update a project secret. The `value` field is optional — omit it\nto rotate only the environment scoping / preview flag without touching the\nciphertext.","properties":{"environment_ids":{"type":"array","items":{"type":"integer","format":"int32"}},"include_in_preview":{"type":"boolean"},"value":{"type":["string","null"],"description":"New plaintext value, <= 1 MiB. Omit to keep the existing value."}}},"UpdateProjectSettingsRequest":{"type":"object","properties":{"ai_alert_summaries_enabled":{"type":["boolean","null"],"description":"Opt in to AI summarization of metric alert notifications (ADR-021)."},"ai_debug_chat_enabled":{"type":["boolean","null"],"description":"Opt in to AI debugging chat, e.g. on deployment failures (ADR-023)."},"ai_write_actions_enabled":{"type":["boolean","null"],"description":"Opt in to AI propose-then-confirm write capability."},"attack_mode":{"type":["boolean","null"],"description":"Enable/disable attack mode (CAPTCHA protection) for all project environments"},"cross_project_trace_sharing":{"type":["boolean","null"],"description":"ADR-027 Phase 3 opt-out: set to false to suppress this project's traces\nfrom appearing in cross-project discovery results. Default true (consistent\nwith the OSS global-observability model). Omit to leave unchanged."},"directory":{"type":["string","null"]},"enable_preview_environments":{"type":["boolean","null"],"description":"Enable automatic preview environment creation for each branch"},"error_source_context_enabled":{"type":["boolean","null"],"description":"Opt in to native error-tracking source context (source-file upload +\nsource code shown in stack traces)."},"error_source_root":{"type":["string","null"],"description":"Set the auto-capture source root (relative to the checkout). Send an\nempty string to clear it back to the build-context default. Omit to\nleave unchanged."},"git_provider_connection_id":{"type":["integer","null"],"format":"int32"},"main_branch":{"type":["string","null"]},"preset":{"type":["string","null"]},"preset_config":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PresetConfigSchema","description":"Preset-specific configuration (e.g., Dockerfile path for Docker preset)\n\nExample for Dockerfile preset:\n```json\n{\n \"dockerfilePath\": \"docker/Dockerfile\",\n \"buildContext\": \"./api\"\n}\n```"}]},"preview_envs_idle_timeout_seconds":{"type":["integer","null"],"format":"int32","description":"Idle timeout (seconds, 60..=86400) for on-demand preview environments."},"preview_envs_on_demand":{"type":["boolean","null"],"description":"When true, newly-created preview environments default to on-demand mode."},"preview_envs_wake_timeout_seconds":{"type":["integer","null"],"format":"int32","description":"Wake timeout (seconds, 5..=120) for on-demand preview environments."},"repo_name":{"type":["string","null"]},"repo_owner":{"type":["string","null"]},"slug":{"type":["string","null"]}}},"UpdateProviderCredentialsRequest":{"type":"object","description":"Partial-update payload for provider credentials. Every field is optional;\nonly the fields the user re-enters are applied. The server validates that\nthe fields supplied make sense for the provider's current auth_method\n(e.g. `app_id` + `private_key` only apply to GitHub Apps).","properties":{"app_id":{"type":["string","null"],"description":"Application ID (GitHub App integer as string; GitLab App string)."},"app_secret":{"type":["string","null"],"description":"GitLab App secret (not used by GitHub App — use `client_secret`)."},"client_id":{"type":["string","null"],"description":"OAuth client ID (GitLab OAuth, GitHub App)."},"client_secret":{"type":["string","null"],"description":"OAuth client secret (GitLab OAuth, GitHub App)."},"private_key":{"type":["string","null"],"description":"GitHub App private key (PEM)."},"redirect_uri":{"type":["string","null"],"description":"OAuth redirect URI (GitLab OAuth / GitLab App)."},"token":{"type":["string","null"],"description":"PAT for PAT-type providers."},"webhook_secret":{"type":["string","null"],"description":"GitHub App webhook secret."}}},"UpdateProviderKeyRequest":{"type":"object","properties":{"api_key":{"type":["string","null"]},"base_url":{"type":["string","null"],"description":"Double-Option: absent = leave unchanged, present-null = clear (revert to\nthe provider's default endpoint), present-value = set."},"default_model":{"type":["string","null"],"description":"Double-Option: absent = leave unchanged, present-null = clear the pinned\nmodel (revert to the per-provider default), present-value = set."},"display_name":{"type":["string","null"]},"is_active":{"type":["boolean","null"]}}},"UpdateProviderRequest":{"type":"object","properties":{"config":{},"enabled":{"type":["boolean","null"]},"name":{"type":["string","null"]}}},"UpdateRouteRequest":{"type":"object","required":["host","port","enabled"],"properties":{"enabled":{"type":"boolean"},"host":{"type":"string"},"port":{"type":"integer","format":"int32"},"route_type":{"type":["string","null"],"description":"Route type: \"http\" (default) matches on HTTP Host header,\n\"tls\" matches on TLS SNI hostname for TCP passthrough"}}},"UpdateS3SourceRequest":{"type":"object","properties":{"access_key_id":{"type":["string","null"],"description":"Optional new access key ID","example":"AKIAXXXXXXXXXXXXXXXX"},"bucket_name":{"type":["string","null"],"description":"Optional new bucket name"},"bucket_path":{"type":["string","null"],"description":"Optional new bucket path"},"endpoint":{"type":["string","null"],"description":"Optional new endpoint URL for S3-compatible services","example":"http://minio.example.com:9000"},"force_path_style":{"type":["boolean","null"],"description":"Optional new path-style addressing setting","example":true},"name":{"type":["string","null"],"description":"Optional new name for the source"},"region":{"type":["string","null"],"description":"Optional new region"},"secret_key":{"type":["string","null"],"description":"Optional new secret key"}}},"UpdateSecretBody":{"type":"object","required":["signing_secret"],"properties":{"signing_secret":{"type":"string","description":"New signing secret from the provider's dashboard. Encrypted at\nrest; never returned in any API response."}}},"UpdateSelfRequest":{"type":"object","properties":{"email":{"type":["string","null"],"example":"john.doe@example.com"},"name":{"type":["string","null"],"example":"John Doe"}}},"UpdateSessionDurationRequest":{"type":"object","required":["duration"],"properties":{"duration":{"type":"integer","format":"int32"}}},"UpdateSessionDurationResponse":{"type":"object","required":["message"],"properties":{"message":{"type":"string"}}},"UpdateSkillRequest":{"type":"object","properties":{"content":{"type":["string","null"]},"description":{"type":["string","null"]},"name":{"type":["string","null"]}}},"UpdateSlackProviderRequest":{"type":"object","required":["config"],"properties":{"config":{"$ref":"#/components/schemas/SlackConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":["string","null"]}}},"UpdateSpeedMetricsPayload":{"type":"object","description":"Update speed metrics payload for late-loading metrics","properties":{"cls":{"type":["number","null"],"format":"float","description":"Cumulative Layout Shift (score)"},"inp":{"type":["number","null"],"format":"float","description":"Interaction to Next Paint (milliseconds)"}}},"UpdateStatusResponse":{"type":"object","description":"Result of the background release-update check, driving the web console's\nupgrade banner. All optional fields are set together iff\n`update_available` is true.","required":["update_available","docs_url"],"properties":{"channel":{"type":["string","null"],"description":"Channel the install tracks: `stable` or `beta`."},"checked_at":{"type":["string","null"],"description":"When the check that found the update ran (ISO 8601, UTC)."},"current_version":{"type":["string","null"],"description":"Version tag of the running binary, e.g. `v0.1.0-beta.45`."},"docs_url":{"type":"string","description":"Docs page with upgrade instructions. Always present so the UI links\nthe same page regardless of update state."},"latest_version":{"type":["string","null"],"description":"Newest published tag on this install's channel."},"release_url":{"type":["string","null"],"description":"Release-notes page (GitHub release) for the newer version."},"update_available":{"type":"boolean","description":"True when a newer release than the running binary has been published\non this install's channel."}}},"UpdateTeamRequest":{"type":"object","properties":{"description":{"type":["string","null"]},"name":{"type":["string","null"]}}},"UpdateTokenRequest":{"type":"object","required":["access_token"],"properties":{"access_token":{"type":"string"},"refresh_token":{"type":["string","null"]}}},"UpdateTokenResponse":{"type":"object","required":["connection_id","message","is_active"],"properties":{"connection_id":{"type":"integer","format":"int32"},"is_active":{"type":"boolean"},"message":{"type":"string"}}},"UpdateUserRequest":{"type":"object","properties":{"email":{"type":["string","null"],"example":"john.doe@example.com"},"name":{"type":["string","null"],"example":"John Doe"}}},"UpdateWebhookProviderRequest":{"type":"object","required":["config"],"properties":{"config":{"$ref":"#/components/schemas/WebhookConfig"},"enabled":{"type":["boolean","null"]},"name":{"type":["string","null"]}}},"UpdateWebhookRequestBody":{"type":"object","properties":{"enabled":{"type":["boolean","null"],"description":"Whether the webhook is enabled"},"events":{"type":["array","null"],"items":{"type":"string"},"description":"Event types to subscribe to"},"secret":{"type":["string","null"],"description":"Secret for HMAC signature verification"},"url":{"type":["string","null"],"description":"Target URL for webhook delivery"}}},"UpgradeExternalServiceRequest":{"type":"object","required":["docker_image"],"properties":{"docker_image":{"type":"string","description":"Docker image to upgrade to (e.g., \"gotempsh/postgres-walg:18-bookworm\")\nThis will trigger pg_upgrade for PostgreSQL or equivalent upgrade procedures for other services","example":"gotempsh/postgres-walg:18-bookworm"}}},"UpgradeRequest":{"type":"object","required":["image"],"properties":{"image":{"type":"string","description":"Image reference to pull and run (e.g.\n`ghcr.io/gotempsh/temps-preview-gateway:latest`). Empty resets to default."}}},"UpsertAgentRequest":{"type":"object","properties":{"ai_model":{"type":["string","null"],"description":"Preferred model identifier for the CLI. `Some(\"\")` clears the stored value."},"ai_provider":{"type":["string","null"]},"ai_provider_key_id":{"type":["integer","null"],"format":"int32"},"api_key":{"type":["string","null"],"description":"Plain-text API key — will be encrypted before storage"},"branch_prefix":{"type":["string","null"]},"config_repo_branch":{"type":["string","null"],"description":"Branch of the config repo to use (default: \"main\")."},"config_repo_url":{"type":["string","null"],"description":"Private config repo containing .claude/ directory (skills, MCP, plugins)."},"cooldown_minutes":{"type":["integer","null"],"format":"int32"},"daily_budget_cents":{"type":["integer","null"],"format":"int32"},"deliverable":{"type":["string","null"]},"description":{"type":["string","null"]},"enabled":{"type":["boolean","null"]},"max_turns":{"type":["integer","null"],"format":"int32"},"mcp_servers_config":{"description":"MCP servers config (Claude Code settings.json mcpServers format).\nCredential-bearing legacy inline objects are write-only: normal reads\nmask them, and updates must omit this field to preserve existing values."},"name":{"type":["string","null"]},"prompt":{"type":["string","null"]},"sandbox_enabled":{"type":["boolean","null"]},"skills_config":{"description":"Skills config as JSON array."},"slug":{"type":["string","null"]},"timeout_seconds":{"type":["integer","null"],"format":"int32"},"tools_config":{"description":"Tools config as JSON array. Custom-tool webhook URLs and headers are\nwrite-only; omit this field on update to preserve them."},"trigger_config":{"description":"Trigger configuration JSON: { \"error\": { \"new_issue\": true, \"regression\": true }, \"manual\": true }"}}},"UpsertSecretRequest":{"type":"object","required":["name","value"],"properties":{"description":{"type":["string","null"]},"mount_path":{"type":["string","null"],"description":"Required for \"file\" type secrets — absolute path inside the sandbox"},"name":{"type":"string"},"secret_type":{"type":"string","description":"\"env\" (environment variable) or \"file\" (written to mount_path)"},"value":{"type":"string"}}},"UptimeDataPoint":{"type":"object","required":["timestamp","status"],"properties":{"error_message":{"type":["string","null"]},"response_time_ms":{"type":["integer","null"],"format":"int32"},"status":{"type":"string"},"timestamp":{"type":"string","format":"date-time"}}},"UptimeHistoryResponse":{"type":"object","required":["monitor_id","uptime_data"],"properties":{"monitor_id":{"type":"integer","format":"int32"},"uptime_data":{"type":"array","items":{"$ref":"#/components/schemas/UptimeDataPoint"}}}},"UsageFilter":{"type":"object","description":"Filters for querying AI usage data.\n\nCost bounds are expressed in microcents (the unit stored in\n`estimated_cost_microcents`). At most one of `gte`/`gt` and one of\n`lte`/`lt` is meaningful per query; if both are set the stricter wins\nnaturally because they are ANDead together.","properties":{"conversation_id":{"type":["string","null"]},"cost_gt":{"type":["integer","null"],"format":"int64","description":"Cost strictly greater-than, in microcents."},"cost_gte":{"type":["integer","null"],"format":"int64","description":"Cost greater-than-or-equal, in microcents."},"cost_lt":{"type":["integer","null"],"format":"int64","description":"Cost strictly less-than, in microcents."},"cost_lte":{"type":["integer","null"],"format":"int64","description":"Cost less-than-or-equal, in microcents."},"model":{"type":["string","null"]},"provider":{"type":["string","null"]},"status":{"type":["integer","null"],"format":"int32","description":"Filter by HTTP status code (exact match)."},"tags":{"type":["string","null"],"description":"Comma-separated tags to filter by (AND logic)."},"tokens_gt":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) strictly greater-than."},"tokens_gte":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) greater-than-or-equal."},"tokens_lt":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) strictly less-than."},"tokens_lte":{"type":["integer","null"],"format":"int64","description":"Total tokens (input + output) less-than-or-equal."},"user_id":{"type":["integer","null"],"format":"int32"}}},"UsageInfo":{"type":"object","required":["prompt_tokens","completion_tokens","total_tokens"],"properties":{"completion_tokens":{"type":"integer","format":"int64"},"prompt_tokens":{"type":"integer","format":"int64"},"total_tokens":{"type":"integer","format":"int64"}}},"UsageLogEntry":{"type":"object","required":["id","timestamp","provider","model","input_tokens","output_tokens","latency_ms","estimated_cost_microcents","status","is_streaming","is_byok","tags"],"properties":{"conversation_id":{"type":["string","null"]},"estimated_cost_microcents":{"type":"integer","format":"int64"},"id":{"type":"integer","format":"int64"},"input_tokens":{"type":"integer","format":"int64"},"is_byok":{"type":"boolean"},"is_streaming":{"type":"boolean"},"latency_ms":{"type":"integer","format":"int32"},"model":{"type":"string"},"output_tokens":{"type":"integer","format":"int64"},"provider":{"type":"string"},"request_id":{"type":["string","null"]},"status":{"type":"integer","format":"int32"},"tags":{"type":"array","items":{"type":"string"}},"timestamp":{"type":"string"},"trace_id":{"type":["string","null"]}}},"UsageLogPage":{"type":"object","description":"A page of recent usage log entries plus the total count for pagination.","required":["entries","total"],"properties":{"entries":{"type":"array","items":{"$ref":"#/components/schemas/UsageLogEntry"},"description":"The usage log entries for the requested page."},"total":{"type":"integer","format":"int64","description":"Total number of entries matching the filter (across all pages)."}}},"UsageQueryParams":{"type":"object","properties":{"conversation_id":{"type":["string","null"],"description":"Filter by conversation ID"},"from":{"type":["string","null"],"description":"ISO 8601 start time (defaults to 24h ago)"},"model":{"type":["string","null"],"description":"Filter by model name"},"provider":{"type":["string","null"],"description":"Filter by provider name"},"tags":{"type":["string","null"],"description":"Filter by tags (comma-separated, AND logic)"},"to":{"type":["string","null"],"description":"ISO 8601 end time (defaults to now)"},"user_id":{"type":["integer","null"],"format":"int32","description":"Filter by user ID"}}},"UsageSource":{"type":"string","description":"How the \"actual usage\" numbers were obtained","enum":["metrics-api","requests-only","unavailable"]},"UsageSummary":{"type":"object","required":["total_requests","total_input_tokens","total_output_tokens","total_tokens","avg_latency_ms","total_cost_microcents","error_count","streaming_count","byok_count"],"properties":{"avg_latency_ms":{"type":"number","format":"double"},"byok_count":{"type":"integer","format":"int64"},"error_count":{"type":"integer","format":"int64"},"streaming_count":{"type":"integer","format":"int64"},"total_cost_microcents":{"type":"integer","format":"int64"},"total_input_tokens":{"type":"integer","format":"int64"},"total_output_tokens":{"type":"integer","format":"int64"},"total_requests":{"type":"integer","format":"int64"},"total_tokens":{"type":"integer","format":"int64"}}},"UserResponse":{"type":"object","required":["id","username","name","avatar_url","mfa_enabled","role"],"properties":{"avatar_url":{"type":"string"},"email":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"mfa_enabled":{"type":"boolean"},"name":{"type":"string"},"role":{"type":"string","description":"User's role (e.g., \"admin\", \"user\", \"demo\")"},"username":{"type":"string"}}},"ValidateEmailRequest":{"type":"object","description":"Request body for validating an email address","required":["email"],"properties":{"email":{"type":"string","description":"Email address to validate","example":"someone@gmail.com"}},"additionalProperties":false},"ValidateEmailResponse":{"type":"object","description":"Complete email validation response","required":["email","is_reachable","syntax","mx","misc","smtp"],"properties":{"email":{"type":"string","description":"The email address that was validated","example":"someone@gmail.com"},"is_reachable":{"$ref":"#/components/schemas/ReachabilityStatus","description":"Overall reachability status: safe, risky, invalid, or unknown"},"misc":{"$ref":"#/components/schemas/MiscResult","description":"Miscellaneous validation result"},"mx":{"$ref":"#/components/schemas/MxResult","description":"MX record validation result"},"smtp":{"$ref":"#/components/schemas/SmtpResult","description":"SMTP validation result"},"syntax":{"$ref":"#/components/schemas/SyntaxResult","description":"Syntax validation result"}}},"ValidationLevel":{"type":"string","description":"Validation severity level","enum":["info","warning","error","critical"]},"ValidationReport":{"type":"object","description":"Complete validation report","required":["results","overall_status","summary"],"properties":{"overall_status":{"$ref":"#/components/schemas/ValidationStatus","description":"Overall status"},"results":{"type":"array","items":{"$ref":"#/components/schemas/ValidationResult"},"description":"All validation results"},"summary":{"$ref":"#/components/schemas/ValidationSummary","description":"Summary statistics"}}},"ValidationResponse":{"type":"object","required":["connection_id","is_valid","message"],"properties":{"connection_id":{"type":"integer","format":"int32"},"is_valid":{"type":"boolean"},"message":{"type":"string"}}},"ValidationResult":{"type":"object","description":"Result of a validation check","required":["rule_id","rule_name","level","passed","message","affected_resources"],"properties":{"affected_resources":{"type":"array","items":{"type":"string"},"description":"Affected resources/fields"},"level":{"$ref":"#/components/schemas/ValidationLevel","description":"Validation level"},"message":{"type":"string","description":"Message describing the result"},"passed":{"type":"boolean","description":"Whether the validation passed"},"remediation":{"type":["string","null"],"description":"Suggested remediation (if failed)"},"rule_id":{"type":"string","description":"Rule that was checked"},"rule_name":{"type":"string","description":"Human-readable rule name"}}},"ValidationStatus":{"type":"string","description":"Overall validation status","enum":["passed","passed-with-warnings","failed-with-warnings","failed"]},"ValidationSummary":{"type":"object","description":"Validation summary statistics","required":["total_count","passed_count","failed_count","info_count","warning_count","error_count","critical_count"],"properties":{"critical_count":{"type":"integer","description":"Critical-level results","minimum":0},"error_count":{"type":"integer","description":"Error-level results","minimum":0},"failed_count":{"type":"integer","description":"Validations that failed","minimum":0},"info_count":{"type":"integer","description":"Info-level results","minimum":0},"passed_count":{"type":"integer","description":"Validations that passed","minimum":0},"total_count":{"type":"integer","description":"Total validations run","minimum":0},"warning_count":{"type":"integer","description":"Warning-level results","minimum":0}}},"VerifyMfaRequest":{"type":"object","required":["code"],"properties":{"code":{"type":"string"}}},"VerifyStepUpRequest":{"type":"object","required":["code"],"properties":{"code":{"type":"string","description":"Current TOTP value or an unused recovery code."}}},"ViewItem":{"type":"object","required":["label","value"],"properties":{"label":{"type":"string","format":"date-time"},"value":{"type":"integer","format":"int64"}}},"ViewsOverTime":{"type":"object","required":["items","metric","present_index"],"properties":{"comparison_labels":{"type":["array","null"],"items":{"type":"string"}},"comparison_plot":{"type":["array","null"],"items":{"type":"integer","format":"int64"}},"full_intervals":{"type":["array","null"],"items":{"type":"string"}},"items":{"type":"array","items":{"$ref":"#/components/schemas/ViewItem"}},"metric":{"type":"string"},"present_index":{"type":"integer","minimum":0}}},"ViewsOverTimeQuery":{"type":"object","required":["start_date","end_date","project_id"],"properties":{"deployment_id":{"type":["integer","null"],"format":"int32"},"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"VisitorDetails":{"type":"object","required":["id","visitor_id","project_id","environment_id","first_seen","last_seen","is_crawler"],"properties":{"city":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"crawler_name":{"type":["string","null"]},"custom_data":{},"environment_id":{"type":"integer","format":"int32"},"first_channel":{"type":["string","null"],"description":"Marketing channel from the first visit (e.g. \"Organic Search\", \"Direct\")"},"first_referrer":{"type":["string","null"],"description":"Full referrer URL from the visitor's first session"},"first_referrer_hostname":{"type":["string","null"],"description":"Hostname extracted from first_referrer"},"first_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"id":{"type":"integer","format":"int32"},"ip_address":{"type":["string","null"]},"ip_address_id":{"type":["integer","null"],"format":"int32"},"is_crawler":{"type":"boolean"},"is_eu":{"type":["boolean","null"]},"last_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"latitude":{"type":["number","null"],"format":"double"},"longitude":{"type":["number","null"],"format":"double"},"project_id":{"type":"integer","format":"int32"},"region":{"type":["string","null"]},"timezone":{"type":["string","null"]},"user_agent":{"type":["string","null"]},"visitor_id":{"type":"string"}}},"VisitorFacetValue":{"type":"object","description":"A single facet value with its visitor count. Used to populate filter\ndropdowns on the visitors page (e.g. \"Germany — 1,234 visitors\").","required":["value","count"],"properties":{"code":{"type":["string","null"],"description":"Optional secondary code for the value. Currently only populated for\nthe `country` facet, where it carries the 2-letter ISO country code\nso the UI can render a flag without re-mapping."},"count":{"type":"integer","format":"int64","description":"Distinct visitor count matching this value in the current segment."},"value":{"type":"string","description":"The dimension value (e.g. \"United States\", \"Chrome\", \"google.com\").\n`None` is encoded as the literal string \"Direct\" for referrer and as\nthe empty string for the rest."}}},"VisitorFacets":{"type":"object","description":"All filter dropdown contents in one response. Each list is the top N\nvalues for that dimension within the current date range and segment\n(excluding the dimension being queried so the dropdown still shows\nalternatives when a value is already selected).","required":["country","region","city","channel","referrer"],"properties":{"channel":{"type":"array","items":{"$ref":"#/components/schemas/VisitorFacetValue"}},"city":{"type":"array","items":{"$ref":"#/components/schemas/VisitorFacetValue"}},"country":{"type":"array","items":{"$ref":"#/components/schemas/VisitorFacetValue"}},"referrer":{"type":"array","items":{"$ref":"#/components/schemas/VisitorFacetValue"}},"region":{"type":"array","items":{"$ref":"#/components/schemas/VisitorFacetValue"}}}},"VisitorFacetsQuery":{"allOf":[{"$ref":"#/components/schemas/VisitorSegmentFilters"},{"type":"object","required":["start_date","end_date","project_id"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"has_activity_only":{"type":["boolean","null"]},"include_crawlers":{"type":["boolean","null"]},"per_facet_limit":{"type":["integer","null"],"format":"int32","description":"Maximum number of values returned per dimension (default: 50, max: 200)."},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}}],"description":"Query parameters for the visitor-facets endpoint. Mirrors the shape of\n`VisitorsListQuery` so the same segment filters apply — facet counts are\nalways computed against the *currently filtered* visitor pool, minus the\ndimension being aggregated."},"VisitorInfo":{"type":"object","required":["id","visitor_id","project_id","environment_id","first_seen","last_seen","is_crawler"],"properties":{"city":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"crawler_name":{"type":["string","null"]},"current_page":{"type":["string","null"],"description":"Most recent page path visited by this visitor"},"custom_data":{},"environment_id":{"type":"integer","format":"int32"},"first_channel":{"type":["string","null"],"description":"Marketing channel from the first visit (e.g. \"Organic Search\", \"Direct\")"},"first_referrer":{"type":["string","null"],"description":"Full referrer URL from the visitor's first session"},"first_referrer_hostname":{"type":["string","null"],"description":"Hostname extracted from first_referrer"},"first_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"id":{"type":"integer","format":"int32"},"ip_address":{"type":["string","null"]},"ip_address_id":{"type":["integer","null"],"format":"int32"},"is_crawler":{"type":"boolean"},"is_eu":{"type":["boolean","null"]},"last_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"latitude":{"type":["number","null"],"format":"double"},"longitude":{"type":["number","null"],"format":"double"},"project_id":{"type":"integer","format":"int32"},"region":{"type":["string","null"]},"timezone":{"type":["string","null"]},"user_agent":{"type":["string","null"]},"visitor_id":{"type":"string"}}},"VisitorJourneyQuery":{"type":"object","required":["project_id"],"properties":{"limit_sessions":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"}}},"VisitorJourneyResponse":{"type":"object","description":"Complete visitor journey response","required":["visitor_id","total_sessions","total_events","sessions"],"properties":{"sessions":{"type":"array","items":{"$ref":"#/components/schemas/JourneySession"},"description":"Sessions with their events, ordered newest first"},"total_events":{"type":"integer","format":"int64","description":"Total number of events across all sessions"},"total_sessions":{"type":"integer","format":"int64","description":"Total number of sessions"},"visitor_id":{"type":"integer","format":"int32","description":"Visitor internal ID"}}},"VisitorLocationsQuery":{"type":"object","required":["start_date","end_date","project_id"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"granularity":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/LocationGranularity"}]},"limit":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}},"VisitorRecord":{"type":"object","required":["id","visitor_id","project_id","created_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"custom_data":{},"id":{"type":"integer","format":"int32"},"project_id":{"type":"integer","format":"int32"},"visitor_id":{"type":"string"}}},"VisitorSegmentFilters":{"type":"object","description":"Optional segment filters for [`VisitorsListQuery`]. Each filter narrows the\nresult set to visitors who match the given dimension value within the date\nrange. All filters resolve against `visitor` / `ip_geolocations` — by\ndesign we never touch the events hypertable here so filtering stays fast\nregardless of event volume.","properties":{"filter_channel":{"type":["string","null"],"description":"First-touch marketing channel (matches `visitor.first_channel`)"},"filter_city":{"type":["string","null"],"description":"Geolocation city (matches `ip_geolocations.city`)"},"filter_country":{"type":["string","null"],"description":"Geolocation country (matches `ip_geolocations.country`)"},"filter_referrer":{"type":["string","null"],"description":"First-touch referrer hostname (matches `visitor.first_referrer_hostname`)"},"filter_region":{"type":["string","null"],"description":"Geolocation region (matches `ip_geolocations.region`)"}}},"VisitorSessionsQuery":{"type":"object","required":["project_id"],"properties":{"environment_id":{"type":["integer","null"],"format":"int32"},"limit":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"}}},"VisitorSessionsResponse":{"type":"object","required":["visitor_id","sessions","total_sessions"],"properties":{"sessions":{"type":"array","items":{"$ref":"#/components/schemas/SessionSummary"}},"total_sessions":{"type":"integer","format":"int64"},"visitor_id":{"type":"string"}}},"VisitorStats":{"type":"object","required":["visitor_id","first_seen","last_seen","total_sessions","total_page_views","total_events","average_session_duration","bounce_rate","engagement_rate","top_pages","top_referrers","devices_used","locations"],"properties":{"average_session_duration":{"type":"number","format":"double"},"bounce_rate":{"type":"number","format":"double"},"devices_used":{"type":"array","items":{"type":"string"}},"engagement_rate":{"type":"number","format":"double"},"first_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"last_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"locations":{"type":"array","items":{"$ref":"#/components/schemas/LocationInfo"}},"top_pages":{"type":"array","items":{"$ref":"#/components/schemas/PageVisit"}},"top_referrers":{"type":"array","items":{"type":"string"}},"total_events":{"type":"integer","format":"int64"},"total_page_views":{"type":"integer","format":"int64"},"total_sessions":{"type":"integer","format":"int64"},"visitor_id":{"type":"integer","format":"int32"}}},"VisitorWithGeolocation":{"type":"object","required":["id","visitor_id","project_id","environment_id","first_seen","last_seen","is_crawler"],"properties":{"city":{"type":["string","null"]},"country":{"type":["string","null"]},"country_code":{"type":["string","null"]},"crawler_name":{"type":["string","null"]},"custom_data":{},"environment_id":{"type":"integer","format":"int32"},"first_channel":{"type":["string","null"],"description":"Marketing channel from the first visit (e.g. \"Organic Search\", \"Direct\")"},"first_referrer":{"type":["string","null"],"description":"Full referrer URL from the visitor's first session"},"first_referrer_hostname":{"type":["string","null"],"description":"Hostname extracted from first_referrer"},"first_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"id":{"type":"integer","format":"int32"},"ip_address":{"type":["string","null"]},"is_crawler":{"type":"boolean"},"is_eu":{"type":["boolean","null"]},"last_seen":{"type":"string","format":"date-time","example":"2024-01-01T00:00:00"},"latitude":{"type":["number","null"],"format":"double"},"longitude":{"type":["number","null"],"format":"double"},"project_id":{"type":"integer","format":"int32"},"region":{"type":["string","null"]},"timezone":{"type":["string","null"]},"user_agent":{"type":["string","null"]},"visitor_id":{"type":"string"}}},"VisitorsListQuery":{"allOf":[{"$ref":"#/components/schemas/VisitorSegmentFilters"},{"type":"object","required":["start_date","end_date","project_id"],"properties":{"end_date":{"type":"string","format":"date-time"},"environment_id":{"type":["integer","null"],"format":"int32"},"has_activity_only":{"type":["boolean","null"],"description":"Filter to only include visitors with recorded activity (events/sessions).\nWhen true, excludes \"ghost\" visitors that have no events."},"include_crawlers":{"type":["boolean","null"]},"limit":{"type":["integer","null"],"format":"int32"},"offset":{"type":["integer","null"],"format":"int32"},"project_id":{"type":"integer","format":"int32"},"start_date":{"type":"string","format":"date-time"}}}]},"VisitorsResponse":{"type":"object","required":["visitors","total_count","filtered_count"],"properties":{"filtered_count":{"type":"integer","format":"int64"},"total_count":{"type":"integer","format":"int64"},"visitors":{"type":"array","items":{"$ref":"#/components/schemas/VisitorInfo"}}}},"VolumeMount":{"type":"object","description":"Volume mount in deployment","required":["source","destination","read_only","type"],"properties":{"destination":{"type":"string","description":"Destination path in container"},"read_only":{"type":"boolean","description":"Read-only flag"},"source":{"type":"string","description":"Source (volume name or path)"},"type":{"$ref":"#/components/schemas/VolumeType","description":"Volume type"}}},"VolumeType":{"type":"string","description":"Volume type","enum":["bind","volume","tmpfs"]},"VulnerabilityResponse":{"type":"object","required":["id","scan_id","vulnerability_id","package_name","installed_version","severity","title","created_at"],"properties":{"class":{"type":["string","null"],"example":"os-pkgs"},"created_at":{"type":"string","example":"2025-12-08T12:15:47.609192Z"},"cvss_score":{"type":["number","null"],"format":"float"},"description":{"type":["string","null"]},"fixed_version":{"type":["string","null"]},"id":{"type":"integer","format":"int32"},"installed_version":{"type":"string"},"last_modified_date":{"type":["string","null"],"example":"2025-12-08T12:15:47.609192Z"},"package_name":{"type":"string"},"primary_url":{"type":["string","null"]},"published_date":{"type":["string","null"],"example":"2025-12-08T12:15:47.609192Z"},"references":{},"scan_id":{"type":"integer","format":"int32"},"severity":{"type":"string"},"target":{"type":["string","null"],"example":"alpine:3.18 (alpine 3.18.0)"},"title":{"type":"string"},"type":{"type":["string","null"],"example":"alpine"},"vulnerability_id":{"type":"string"}}},"WalWarning":{"oneOf":[{"type":"object","description":"`pg_wal` is significantly larger than `max_wal_size`.","required":["pg_wal_bytes","max_wal_size_bytes","ratio","kind"],"properties":{"kind":{"type":"string","enum":["wal_bloat"]},"max_wal_size_bytes":{"type":"integer","format":"int64"},"pg_wal_bytes":{"type":"integer","format":"int64"},"ratio":{"type":"number","format":"double"}}},{"type":"object","description":"A replication slot is holding WAL it's not consuming.","required":["slot_name","retained_bytes","active","kind"],"properties":{"active":{"type":"boolean"},"kind":{"type":"string","enum":["stale_slot"]},"retained_bytes":{"type":"integer","format":"int64"},"slot_name":{"type":"string"}}},{"type":"object","description":"`archive_status/*.ready` count exceeds threshold — `archive_command`\nis either failing or running slower than WAL generation.","required":["ready_count","kind"],"properties":{"kind":{"type":"string","enum":["archive_backlog"]},"ready_count":{"type":"integer","format":"int64"}}},{"type":"object","description":"`archive_mode = on` but `archive_command` is empty / `/bin/true`.\nWAL accumulates forever waiting for a destination that never accepts.","required":["kind"],"properties":{"kind":{"type":"string","enum":["archive_mode_without_command"]}}},{"type":"object","description":"Oldest WAL segment is older than `WAL_NOT_RECYCLED_AGE_SECS`.\nIndependent signal: something is blocking recycling even if total\nsize hasn't exploded yet.","required":["oldest_age_secs","kind"],"properties":{"kind":{"type":"string","enum":["wal_not_recycled"]},"oldest_age_secs":{"type":"integer","format":"int64"}}}],"description":"One actionable warning surfaced to the UI.\n\nEach variant carries the data needed to render a remediation hint without\nthe frontend re-querying anything."},"WalWarningSeverity":{"type":"string","enum":["warning","critical"]},"WebhookConfig":{"type":"object","description":"Configuration for a generic webhook notification provider","required":["url"],"properties":{"headers":{"type":"object","description":"Custom headers to include in the request (e.g., for authentication tokens)","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"},"example":{"Authorization":"Bearer your-token","X-Custom-Header":"custom-value"}},"method":{"type":"string","description":"HTTP method to use (POST, PUT, PATCH). Defaults to POST.","example":"POST"},"timeout_secs":{"type":"integer","format":"int64","description":"Request timeout in seconds. Defaults to 30.","example":30,"minimum":0},"url":{"type":"string","description":"The URL to send webhook requests to","example":"https://api.example.com/notifications"}}},"WebhookDeliveryResponse":{"type":"object","required":["id","webhook_id","event_type","event_id","payload","success","attempt_number","created_at"],"properties":{"attempt_number":{"type":"integer","format":"int32"},"created_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"delivered_at":{"type":["string","null"],"format":"date-time"},"error_message":{"type":["string","null"]},"event_id":{"type":"string"},"event_type":{"type":"string"},"id":{"type":"integer","format":"int32"},"payload":{"type":"string","description":"JSON payload that was sent to the webhook endpoint","example":{"event_type":"deployment.succeeded","data":{"deployment_id":123}}},"status_code":{"type":["integer","null"],"format":"int32"},"success":{"type":"boolean"},"webhook_id":{"type":"integer","format":"int32"}}},"WebhookResponse":{"type":"object","required":["id","project_id","url","events","enabled","has_secret","created_at","updated_at"],"properties":{"created_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"enabled":{"type":"boolean"},"events":{"type":"array","items":{"type":"string"}},"has_secret":{"type":"boolean"},"id":{"type":"integer","format":"int32"},"project_id":{"type":"integer","format":"int32"},"updated_at":{"type":"string","format":"date-time","example":"2025-10-12T12:15:47.609192Z"},"url":{"type":"string"}}},"WebhookTriggerRequest":{"allOf":[{"description":"Arbitrary JSON payload from the caller. Passed to the agent as user_context."}]},"WebhookTriggerResponse":{"type":"object","required":["run_id","status"],"properties":{"run_id":{"type":"integer","format":"int32"},"status":{"type":"string"}}},"WorkflowDryRunRequest":{"type":"object","required":["yaml"],"properties":{"cpu_limit":{"type":["number","null"],"format":"double","description":"Optional CPU override applied after parsing YAML (clamped server-side).\nWhen `Some`, this takes precedence over `cpu_limit` inside the YAML —\nlets the CLI pass `--cpu` without rewriting the YAML text."},"error_group_id":{"type":["integer","null"],"format":"int32","description":"Optional error group to link this dry-run to. When set, the executor's\n`load_error_context` path injects `{{error_type}}` / `{{error_message}}`\n/ `{{stack_trace}}` into the prompt — same behaviour as a committed\nworkflow triggered with `trigger_source_type = \"error_group\"`. Must\nbelong to `project_id` (handler enforces)."},"memory_limit_mb":{"type":["integer","null"],"format":"int64","description":"Optional memory override in MB (clamped server-side). Same precedence\nrule as `cpu_limit`.","minimum":0},"user_context":{"type":["string","null"],"description":"Optional context appended to the prompt (e.g. \"test against staging\nonly\"). Mirrors `TriggerAgentRequest.user_context`."},"yaml":{"type":"string","description":"Full WorkflowYamlConfig as YAML text. Server validates and re-serializes\nbefore storing on the run row."}}},"WorkloadDescriptor":{"type":"object","description":"Brief descriptor for discovered workloads (used in listing)","required":["id","workload_type","status","labels"],"properties":{"created_at":{"type":["string","null"],"format":"date-time","description":"Creation timestamp"},"id":{"$ref":"#/components/schemas/WorkloadId","description":"Unique ID in source system"},"image":{"type":["string","null"],"description":"Image/build reference (for containers)"},"labels":{"type":"object","description":"Labels/tags from source system","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}},"name":{"type":["string","null"],"description":"Workload name (if any)"},"status":{"$ref":"#/components/schemas/WorkloadStatus","description":"Current status"},"workload_type":{"$ref":"#/components/schemas/WorkloadType","description":"Workload type (container, function, static-site, etc.)"}}},"WorkloadId":{"type":"string","description":"Unique identifier for a workload in the source system"},"WorkloadStatus":{"type":"string","description":"Workload status in source system","enum":["running","paused","stopped","exited","failed","deployed","building","unknown"]},"WorkloadType":{"type":"string","description":"Workload type","enum":["container","function","static-site","server-side-app","worker","database","message-queue","cache","cron-job","other"]},"WriteFileBody":{"type":"object","required":["path","contents_b64"],"properties":{"contents_b64":{"type":"string","description":"File contents, base64-encoded. Required — lets callers ship binary\ndata over JSON without charset games."},"mode":{"type":["integer","null"],"format":"int32","description":"Unix permission mask (e.g. 0o644). Defaults to 0o644 when absent.","minimum":0},"path":{"type":"string","description":"Absolute path inside the sandbox. Must start with `/`."}},"additionalProperties":false},"WriteFilesBody":{"type":"object","required":["files"],"properties":{"files":{"type":"array","items":{"$ref":"#/components/schemas/WriteFileBody"},"description":"List of files to write. Each entry must include an absolute\n`path` and base64-encoded `contents_b64`. Empty list is a no-op."}},"additionalProperties":false},"WriteFilesResponse":{"type":"object","required":["written"],"properties":{"written":{"type":"integer","description":"Number of files successfully written before the first failure\n(if any). On full success this equals `files.len()`.","minimum":0}}},"ZoneListResponse":{"type":"object","description":"Zone list response","required":["zones"],"properties":{"zones":{"type":"array","items":{"$ref":"#/components/schemas/DnsZone"}}}}},"securitySchemes":{"bearer_auth":{"type":"http","scheme":"bearer","description":"Bearer token authentication. Use format: `Bearer `. Supports API keys (starting with `tk_`), CLI tokens, and session tokens."}}},"tags":[{"name":"Events","description":"Analytics events tracking endpoints"},{"name":"Metrics","description":"Analytics metrics collection endpoints including performance web vitals"},{"name":"Funnels","description":"Funnel management endpoints"},{"name":"Analytics","description":"Analytics and session replay management"},{"name":"Performance","description":"Performance metrics management"},{"name":"geo","description":"Geolocation API endpoints"},{"name":"Platform","description":"Platform information and compatibility"},{"name":"Teams","description":"Teams and project-scoped access"},{"name":"Git Providers","description":"Git provider management endpoints"},{"name":"Repositories","description":"Repository management endpoints"},{"name":"Public Repositories","description":"Endpoints for accessing public repositories without authentication. Supports GitHub and GitLab."},{"name":"Notification Providers","description":"Notification provider management endpoints"},{"name":"Notification Preferences","description":"User notification preferences and settings"},{"name":"DNS Providers","description":"DNS provider management endpoints"},{"name":"Internal DNS","description":"Per-node DNS resolver sync (ADR-011)"},{"name":"Domains","description":"Domain management endpoints"},{"name":"Email Providers","description":"Email provider management endpoints"},{"name":"Email Domains","description":"Email domain management and verification"},{"name":"Emails","description":"Email sending and retrieval"},{"name":"Email Tracking","description":"Email open and click tracking"},{"name":"Email Validation","description":"Email address validation and verification"},{"name":"Webhooks","description":"Webhook management endpoints"},{"name":"Webhook Deliveries","description":"Webhook delivery history and retry endpoints"},{"name":"External Services","description":"External service integration endpoints"},{"name":"External Services - Query","description":"Data querying and exploration endpoints"},{"name":"Metrics","description":"Time-series metrics and alert rule endpoints"},{"name":"KV Store","description":"Key-Value storage operations"},{"name":"KV Management","description":"KV service management operations"},{"name":"Blob","description":"Blob storage operations"},{"name":"Blob Management","description":"Blob service management operations"},{"name":"Feature Flags","description":"Runtime configuration that changes without a redeploy"},{"name":"Environments","description":"Environment management operations"},{"name":"Secrets","description":"File-mounted secrets (/run/secrets/)"},{"name":"Projects","description":"Project management endpoints"},{"name":"Presets","description":"Available deployment presets"},{"name":"Templates","description":"Project template endpoints"},{"name":"Custom Domains","description":"Custom domain management for projects"},{"name":"error-tracking","description":"Error tracking data fetching endpoints"},{"name":"Vulnerability Scans","description":"Vulnerability scan management endpoints"},{"name":"Agents","description":"Autonomous AI agents, autofixer (interactive AI debugging), skills/MCP definitions, and preview gateway management."},{"name":"Crons","description":"Cron jobs management API"},{"name":"Sandboxes","description":"Standalone sandbox API (`/v1/sandboxes/*`) for running isolated containers."},{"name":"Logs","description":"Log search, context, live tail, and retention management"},{"name":"Imports","description":"Import workloads from external sources"},{"name":"Status Page","description":"Status page and monitoring endpoints"},{"name":"OTel Ingest","description":"OTLP/HTTP ingest endpoints (protobuf)"},{"name":"OTel","description":"Query endpoints for the monitoring UI"},{"name":"GenAI","description":"GenAI agent activity tracing endpoints"},{"name":"Alarms","description":"Unified alarm history — list, summarise, acknowledge, resolve"},{"name":"Authentication","description":"Authentication and authorization endpoints"},{"name":"Users","description":"User management endpoints"},{"name":"Backups","description":"Backup management endpoints"},{"name":"Restore","description":"External service restore operations"},{"name":"Revenue","description":"Per-project revenue tracking integrations and analytics"},{"name":"Observability","description":"Unified observability event stream — runtime logs, requests, spans, errors, revenue"},{"name":"AI Gateway","description":"OpenAI-compatible chat, embeddings, and model endpoints"},{"name":"AI Gateway Admin","description":"Provider key management endpoints"},{"name":"AI Gateway Usage","description":"Usage analytics and reporting endpoints"},{"name":"AI Gateway Pricing","description":"Model pricing endpoints"},{"name":"API Keys","description":"API key management endpoints"},{"name":"Load Balancer","description":"Load balancer management endpoints"},{"name":"IP Access Control","description":"IP access control management endpoints"},{"name":"Files","description":"Static file serving endpoints"},{"name":"External Plugins","description":"External plugin management and discovery"}]} \ No newline at end of file +{ + "components": { + "schemas": { + "AcmeOrderResponse": { + "properties": { + "authorizations": {}, + "certificate_url": { + "type": [ + "string", + "null" + ] + }, + "challenge_validation": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/ChallengeValidationStatus", + "description": "Live challenge validation status fetched from Let's Encrypt" + } + ] + }, + "created_at": { + "format": "int64", + "type": "integer" + }, + "domain_id": { + "format": "int32", + "type": "integer" + }, + "email": { + "type": "string" + }, + "error": { + "type": [ + "string", + "null" + ] + }, + "error_type": { + "type": [ + "string", + "null" + ] + }, + "expires_at": { + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "finalize_url": { + "type": [ + "string", + "null" + ] + }, + "id": { + "format": "int32", + "type": "integer" + }, + "identifiers": {}, + "order_url": { + "type": "string" + }, + "status": { + "type": "string" + }, + "updated_at": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "id", + "order_url", + "domain_id", + "email", + "status", + "identifiers", + "created_at", + "updated_at" + ], + "type": "object" + }, + "ActivateProviderResponse": { + "properties": { + "default_provider": { + "type": "string" + } + }, + "required": [ + "default_provider" + ], + "type": "object" + }, + "ActiveVisitor": { + "properties": { + "current_page": { + "type": [ + "string", + "null" + ] + }, + "duration_seconds": { + "format": "int64", + "type": "integer" + }, + "event_count": { + "format": "int32", + "type": "integer" + }, + "is_active": { + "type": "boolean" + }, + "last_activity": { + "type": "string" + }, + "page_count": { + "format": "int32", + "type": "integer" + }, + "session_id": { + "type": "string" + }, + "session_start": { + "type": "string" + }, + "visitor_id": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "session_id", + "session_start", + "last_activity", + "page_count", + "event_count", + "duration_seconds", + "is_active" + ], + "type": "object" + }, + "ActiveVisitorsQuery": { + "properties": { + "deployment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + "type": "object" + }, + "ActiveVisitorsResponse": { + "properties": { + "active_visitors": { + "format": "int64", + "type": "integer" + }, + "window_minutes": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "active_visitors", + "window_minutes" + ], + "type": "object" + }, + "ActivityDay": { + "description": "Daily activity count for a single day", + "properties": { + "count": { + "description": "Number of deployments on this day", + "format": "int64", + "type": "integer" + }, + "date": { + "description": "Date in YYYY-MM-DD format", + "example": "2024-06-15", + "type": "string" + }, + "level": { + "description": "Intensity level (0-4) for visualization\n0: No activity, 1: Low (1-2), 2: Medium (3-5), 3: High (6-10), 4: Very High (11+)", + "example": 2, + "format": "int32", + "type": "integer" + } + }, + "required": [ + "date", + "count", + "level" + ], + "type": "object" + }, + "ActivityEvent": { + "description": "A single activity event for the real-time activity feed", + "properties": { + "browser": { + "description": "Browser", + "type": [ + "string", + "null" + ] + }, + "city": { + "description": "Visitor's city (from ip_geolocations)", + "type": [ + "string", + "null" + ] + }, + "country": { + "description": "Visitor's country (from ip_geolocations)", + "type": [ + "string", + "null" + ] + }, + "country_code": { + "description": "Visitor's country code (from ip_geolocations)", + "type": [ + "string", + "null" + ] + }, + "device_type": { + "description": "Device type", + "type": [ + "string", + "null" + ] + }, + "event_name": { + "description": "Event name (for custom events)", + "type": [ + "string", + "null" + ] + }, + "event_type": { + "description": "Event type: \"page_view\", \"custom\", etc.", + "type": "string" + }, + "id": { + "description": "Event ID", + "format": "int64", + "type": "integer" + }, + "is_crawler": { + "description": "Whether this event was from a crawler", + "type": "boolean" + }, + "latitude": { + "description": "Latitude", + "format": "double", + "type": [ + "number", + "null" + ] + }, + "longitude": { + "description": "Longitude", + "format": "double", + "type": [ + "number", + "null" + ] + }, + "operating_system": { + "description": "Operating system", + "type": [ + "string", + "null" + ] + }, + "page_path": { + "description": "Page path where the event happened", + "type": "string" + }, + "page_title": { + "description": "Page title", + "type": [ + "string", + "null" + ] + }, + "referrer": { + "description": "Referrer", + "type": [ + "string", + "null" + ] + }, + "timestamp": { + "description": "When the event occurred", + "format": "date-time", + "type": "string" + }, + "visitor_id": { + "description": "Visitor numeric ID", + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + "required": [ + "id", + "timestamp", + "event_type", + "page_path", + "is_crawler" + ], + "type": "object" + }, + "ActivityGraphQuery": { + "description": "Query parameters for activity graph endpoint", + "properties": { + "days": { + "description": "Number of days to include (default: 365 for last year)", + "format": "int32", + "type": "integer" + }, + "environment_id": { + "description": "Optional environment ID to filter activity", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "project_id": { + "description": "Optional project ID to filter activity", + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + "type": "object" + }, + "ActivityGraphResponse": { + "description": "Response for activity graph showing daily deployment activity", + "properties": { + "days": { + "description": "Array of daily activity counts", + "items": { + "$ref": "#/components/schemas/ActivityDay" + }, + "type": "array" + }, + "end_date": { + "description": "Date range end (YYYY-MM-DD)", + "example": "2024-12-31", + "type": "string" + }, + "start_date": { + "description": "Date range start (YYYY-MM-DD)", + "example": "2024-01-01", + "type": "string" + }, + "total_count": { + "description": "Total count of activities across all days", + "format": "int64", + "type": "integer" + } + }, + "required": [ + "days", + "total_count", + "start_date", + "end_date" + ], + "type": "object" + }, + "AddClusterMemberRequest": { + "description": "Request body for adding a single member to a running cluster.", + "properties": { + "node_id": { + "description": "Target worker node ID. Omit or null to run on the control plane.", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "role": { + "description": "Member role. Currently only `replica` is accepted at runtime —\nmonitor is a singleton, primary is elected by pg_auto_failover.", + "example": "replica", + "type": "string" + } + }, + "required": [ + "role" + ], + "type": "object" + }, + "AddContextRequest": { + "properties": { + "message": { + "type": "string" + } + }, + "required": [ + "message" + ], + "type": "object" + }, + "AddEnvironmentDomainRequest": { + "properties": { + "domain": { + "type": "string" + }, + "is_primary": { + "type": "boolean" + } + }, + "required": [ + "domain", + "is_primary" + ], + "type": "object" + }, + "AddEventsRequest": { + "properties": { + "events": { + "type": "string" + } + }, + "required": [ + "events" + ], + "type": "object" + }, + "AddEventsResponse": { + "properties": { + "event_count": { + "minimum": 0, + "type": "integer" + }, + "message": { + "type": "string" + } + }, + "required": [ + "event_count", + "message" + ], + "type": "object" + }, + "AddManagedDomainApiRequest": { + "description": "Request to add a managed domain", + "properties": { + "auto_manage": { + "type": "boolean" + }, + "domain": { + "example": "example.com", + "type": "string" + }, + "generated_hostname_mode": { + "description": "Generated hostname layout: `\"standard\"` (default) or `\"flat\"`.", + "type": [ + "string", + "null" + ] + }, + "sync_generated_records": { + "description": "Opt in to reconciling generated hostnames into this domain's DNS zone.", + "type": "boolean" + } + }, + "required": [ + "domain" + ], + "type": "object" + }, + "AdminGateResponse": { + "properties": { + "allowed_hosts": { + "description": "`Host` header values allowed. Empty = any host.", + "items": { + "type": "string" + }, + "type": "array" + }, + "allowed_ips": { + "description": "IPs / CIDRs allowed to reach the admin listener. Empty = any source.", + "items": { + "type": "string" + }, + "type": "array" + }, + "editable": { + "description": "True when the config is writable through this API. False when env\nvars are dictating the active config.", + "type": "boolean" + }, + "source": { + "$ref": "#/components/schemas/AdminGateSource", + "description": "Where the active config came from." + }, + "trust_forwarded_for": { + "description": "When true, the gate trusts `X-Forwarded-For` from loopback peers.", + "type": "boolean" + } + }, + "required": [ + "allowed_ips", + "allowed_hosts", + "trust_forwarded_for", + "source", + "editable" + ], + "type": "object" + }, + "AdminGateSource": { + "description": "Where the active gate configuration came from. Env-supplied configs are\nfrozen at the process level — the UI shows them read-only and refuses to\npersist DB writes. DB-supplied configs are editable at runtime.", + "enum": [ + "default", + "db", + "env" + ], + "type": "string" + }, + "AgentConfigResponse": { + "description": "Response DTO for a single agent — masks the encrypted API key.", + "properties": { + "ai_model": { + "description": "Preferred model for the CLI (e.g. \"sonnet\", \"gpt-5-codex\"). `None` means default.", + "type": [ + "string", + "null" + ] + }, + "ai_provider": { + "type": "string" + }, + "ai_provider_key_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "api_key_set": { + "description": "`true` if an API key is set; `false` otherwise.", + "type": "boolean" + }, + "branch_prefix": { + "type": "string" + }, + "config_repo_branch": { + "description": "Branch of the config repo to use.", + "type": [ + "string", + "null" + ] + }, + "config_repo_url": { + "description": "Private config repo containing .claude/ directory (skills, MCP, plugins).", + "type": [ + "string", + "null" + ] + }, + "cooldown_minutes": { + "format": "int32", + "type": "integer" + }, + "created_at": { + "type": "string" + }, + "daily_budget_cents": { + "format": "int32", + "type": "integer" + }, + "deliverable": { + "type": "string" + }, + "description": { + "type": [ + "string", + "null" + ] + }, + "enabled": { + "type": "boolean" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "max_turns": { + "format": "int32", + "type": "integer" + }, + "mcp_servers_config": { + "description": "MCP servers config (Claude Code settings.json mcpServers format).\nCredential-bearing legacy inline values are write-only and appear as\n`***`. Omit this field on update to preserve their stored values." + }, + "name": { + "type": "string" + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "prompt": { + "type": [ + "string", + "null" + ] + }, + "sandbox_enabled": { + "description": "None = use global sandbox setting, true = force on, false = force off", + "type": [ + "boolean", + "null" + ] + }, + "skills_config": { + "description": "Skills config as JSON array." + }, + "slug": { + "type": "string" + }, + "source": { + "type": "string" + }, + "timeout_seconds": { + "format": "int32", + "type": "integer" + }, + "tools_config": { + "description": "Tools config as JSON array. Legacy custom-tool webhook URLs and headers\nare write-only and appear as `***`. Omit this field on update to\npreserve their stored values." + }, + "trigger_config": {}, + "updated_at": { + "type": "string" + }, + "webhook_token": { + "description": "Secret token for the `X-Webhook-Token` header. Shown once when created,\nmasked with `***` prefix in subsequent reads.", + "type": [ + "string", + "null" + ] + }, + "webhook_url": { + "description": "Public webhook URL for triggering this agent externally.\nOnly set when `on: { webhook: true }` is configured.\nUsage: `POST {webhook_url}` with header `X-Webhook-Token: {webhook_token}`", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "id", + "project_id", + "slug", + "name", + "source", + "enabled", + "trigger_config", + "ai_provider", + "api_key_set", + "max_turns", + "timeout_seconds", + "daily_budget_cents", + "cooldown_minutes", + "branch_prefix", + "deliverable", + "created_at", + "updated_at" + ], + "type": "object" + }, + "AgentRunLogResponse": { + "properties": { + "created_at": { + "type": "string" + }, + "id": { + "format": "int64", + "type": "integer" + }, + "level": { + "type": "string" + }, + "message": { + "type": "string" + }, + "metadata": {}, + "run_id": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "id", + "run_id", + "level", + "message", + "created_at" + ], + "type": "object" + }, + "AgentRunResponse": { + "properties": { + "agent_name": { + "description": "Name of the agent that created this run, if available.", + "type": [ + "string", + "null" + ] + }, + "agent_slug": { + "description": "Slug of the agent that created this run, if available.", + "type": [ + "string", + "null" + ] + }, + "ai_model": { + "type": [ + "string", + "null" + ] + }, + "ai_output": { + "type": [ + "string", + "null" + ] + }, + "ai_provider": { + "description": "AI provider slug that executed this run (e.g. claude_cli, codex_cli, opencode).", + "type": [ + "string", + "null" + ] + }, + "ai_reasoning": { + "type": [ + "string", + "null" + ] + }, + "ai_session_id": { + "description": "Claude CLI session UUID for resuming conversations via `--resume`.", + "type": [ + "string", + "null" + ] + }, + "analysis": { + "description": "Report / analysis text produced by the agent (used for report/notification deliverables).", + "type": [ + "string", + "null" + ] + }, + "branch_name": { + "type": [ + "string", + "null" + ] + }, + "commit_sha": { + "type": [ + "string", + "null" + ] + }, + "completed_at": { + "type": [ + "string", + "null" + ] + }, + "config_id": { + "description": "Optional. NULL for ephemeral CLI runs (`source = \"cli_ephemeral\"`) and\nhistorical autofixer runs that pre-date the agent_id column.", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "created_at": { + "type": "string" + }, + "ephemeral_yaml": { + "description": "Full WorkflowYamlConfig as YAML text. Populated only when\n`source = \"cli_ephemeral\"`. Used by the web UI to show a \"View YAML\"\nmodal so the user can see exactly what the executor ran.", + "type": [ + "string", + "null" + ] + }, + "error_message": { + "type": [ + "string", + "null" + ] + }, + "estimated_cost_cents": { + "format": "int32", + "type": "integer" + }, + "files_changed": { + "format": "int32", + "type": "integer" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "phase": { + "description": "Autofixer phase: \"analyzing\", \"analyzed\", \"fixing\", \"fix_ready\", \"no_fix\",\n\"pr_created\", or NULL for non-autofixer runs.", + "type": [ + "string", + "null" + ] + }, + "pr_number": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "pr_url": { + "type": [ + "string", + "null" + ] + }, + "preview_url": { + "type": [ + "string", + "null" + ] + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "prompt_text": { + "description": "Final assembled prompt the AI CLI actually saw (trigger context block +\nYAML prompt, with error-group fields interpolated). Captured once per\nrun. `None` for pre-migration rows.", + "type": [ + "string", + "null" + ] + }, + "run_config": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/AutofixRunConfig", + "description": "Per-run AI options the user chose when starting an autofixer run\n(provider, model, max_turns, branch). NULL for generic agent runs\nand historical rows. Used to prefill the retry dialog." + } + ] + }, + "sandbox_enabled": { + "description": "Legacy field — all runs now execute in a sandbox. Kept for\nbackwards-compatible JSON shape; always `true`.", + "type": "boolean" + }, + "source": { + "description": "`committed` (the run's config lives in `project_agents`) or\n`cli_ephemeral` (the config was uploaded via the CLI for a one-off\ndry run; see `ephemeral_yaml`).", + "type": "string" + }, + "started_at": { + "type": [ + "string", + "null" + ] + }, + "status": { + "type": "string" + }, + "tokens_input": { + "format": "int32", + "type": "integer" + }, + "tokens_output": { + "format": "int32", + "type": "integer" + }, + "trigger_source_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "trigger_source_type": { + "type": [ + "string", + "null" + ] + }, + "trigger_type": { + "type": "string" + }, + "user_context": { + "description": "User-provided context for this run (e.g. webhook payload, manual instructions).", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "id", + "project_id", + "source", + "trigger_type", + "status", + "tokens_input", + "tokens_output", + "estimated_cost_cents", + "files_changed", + "created_at", + "sandbox_enabled" + ], + "type": "object" + }, + "AgentRunWithLogsResponse": { + "properties": { + "logs": { + "items": { + "$ref": "#/components/schemas/AgentRunLogResponse" + }, + "type": "array" + }, + "run": { + "$ref": "#/components/schemas/AgentRunResponse" + } + }, + "required": [ + "run", + "logs" + ], + "type": "object" + }, + "AgentSandboxSettings": { + "description": "Global agent sandbox settings. Controls whether agent runs are isolated\ninside Docker containers by default. Individual agents can override this.", + "properties": { + "api_key_encrypted": { + "default": null, + "description": "DEPRECATED: use `providers[default_provider].credentials_encrypted` instead.", + "type": [ + "string", + "null" + ] + }, + "auth_type": { + "default": "subscription", + "description": "DEPRECATED: use `providers[default_provider].auth_type` instead.", + "type": "string" + }, + "cpu_limit": { + "default": 4, + "description": "CPU limit in cores for sandbox containers", + "example": 4, + "format": "double", + "type": "number" + }, + "custom_image": { + "default": "", + "description": "Custom Docker image (only used when runtime is \"custom\").\nMust have git and claude CLI installed.", + "example": "", + "type": "string" + }, + "default_provider": { + "default": "claude_cli", + "description": "Default AI provider for agents: \"claude_cli\", \"opencode\", or \"codex_cli\".\nWorkspaces always use this provider — no per-session override.", + "example": "claude_cli", + "type": "string" + }, + "enabled": { + "default": true, + "description": "Sandbox is always enabled — the executor refuses to run any agent\noutside a sandboxed container. Field is retained so existing settings\nrows still deserialize, but it is ignored at runtime.", + "type": "boolean" + }, + "memory_limit_mb": { + "default": 8192, + "description": "Memory limit in MB for sandbox containers", + "example": 8192, + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "network_mode": { + "default": "full", + "description": "Network access level: \"full\" (unrestricted), \"restricted\" (Temps network only), \"none\" (no network)", + "example": "full", + "type": "string" + }, + "providers": { + "additionalProperties": { + "$ref": "#/components/schemas/ProviderConfig" + }, + "default": {}, + "description": "Per-provider auth + config. Keyed by provider id (e.g. `claude_cli`,\n`codex_cli`, `opencode`). Adding a new provider only requires a new\ncatalog entry on the Rust side — the JSON column stays migration-free.", + "propertyNames": { + "type": "string" + }, + "type": "object" + }, + "runtime": { + "default": "node", + "description": "Runtime preset: \"node\", \"bun\", \"python\", \"rust\", \"go\", \"full\", or \"custom\"", + "example": "node", + "type": "string" + }, + "sandbox_backend": { + "default": null, + "description": "Default isolation backend for sandboxes: \"docker\" (default) or\n\"firecracker\" (ADR-029; requires `temps firecracker setup`). Only\nconsulted when the Firecracker backend probes available — otherwise\nDocker is used regardless.", + "example": "docker", + "type": [ + "string", + "null" + ] + } + }, + "type": "object" + }, + "AgentSandboxSettingsMasked": { + "description": "Agent sandbox settings with masked per-provider credentials.\nEach provider entry reports only whether a credential is saved, not\nthe encrypted blob itself. Non-sensitive fields (auth_type, default_model,\nextra) are passed through so the UI can render provider-specific state.", + "properties": { + "api_key_saved": { + "type": "boolean" + }, + "auth_type": { + "type": "string" + }, + "cpu_limit": { + "format": "double", + "type": "number" + }, + "custom_image": { + "type": "string" + }, + "default_provider": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "memory_limit_mb": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "network_mode": { + "type": "string" + }, + "providers": { + "additionalProperties": { + "$ref": "#/components/schemas/ProviderConfigMasked" + }, + "propertyNames": { + "type": "string" + }, + "type": "object" + }, + "runtime": { + "type": "string" + }, + "sandbox_backend": { + "type": "string" + } + }, + "required": [ + "default_provider", + "providers", + "api_key_saved", + "auth_type", + "enabled", + "runtime", + "custom_image", + "cpu_limit", + "memory_limit_mb", + "network_mode", + "sandbox_backend" + ], + "type": "object" + }, + "AggregatedBucketItem": { + "properties": { + "count": { + "format": "int64", + "type": "integer" + }, + "timestamp": { + "type": "string" + } + }, + "required": [ + "timestamp", + "count" + ], + "type": "object" + }, + "AggregatedBucketsQuery": { + "description": "Query parameters for aggregated metrics by time bucket", + "properties": { + "aggregation_level": { + "$ref": "#/components/schemas/AggregationLevel", + "description": "Aggregation level: events, sessions, or visitors" + }, + "bucket_size": { + "description": "Time bucket size: \"1 hour\", \"1 day\", \"1 week\", etc. (default: \"1 hour\")", + "type": "string" + }, + "deployment_id": { + "description": "Optional deployment filter", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "end_date": { + "description": "End date for the query range", + "format": "date-time", + "type": "string" + }, + "environment_id": { + "description": "Optional environment filter", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "start_date": { + "description": "Start date for the query range", + "format": "date-time", + "type": "string" + } + }, + "required": [ + "start_date", + "end_date" + ], + "type": "object" + }, + "AggregatedBucketsResponse": { + "properties": { + "aggregation_level": { + "type": "string" + }, + "bucket_size": { + "type": "string" + }, + "items": { + "items": { + "$ref": "#/components/schemas/AggregatedBucketItem" + }, + "type": "array" + }, + "total": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "bucket_size", + "aggregation_level", + "items", + "total" + ], + "type": "object" + }, + "AggregationLevel": { + "enum": [ + "events", + "sessions", + "visitors" + ], + "type": "string" + }, + "AggregationTemporality": { + "description": "The aggregation temporality of a Sum/Histogram/ExponentialHistogram metric.\n\nMirrors OTel's `AggregationTemporality` proto enum: whether reported values\nare cumulative since the start of the series (Cumulative) or only the delta\nsince the previous report (Delta).", + "enum": [ + "unspecified", + "delta", + "cumulative" + ], + "type": "string" + }, + "AiAgentBreakdownResponse": { + "description": "Response wrapping the AI agent breakdown rows.", + "properties": { + "end_time": { + "type": "string" + }, + "items": { + "items": { + "$ref": "#/components/schemas/AiAgentBreakdownRow" + }, + "type": "array" + }, + "start_time": { + "type": "string" + } + }, + "required": [ + "items", + "start_time", + "end_time" + ], + "type": "object" + }, + "AiAgentBreakdownRow": { + "description": "One row in the AI-agent analytics breakdown. `agent` is the canonical\ncrawler name (e.g. `GPTBot`, `Claude-User`), `provider` is the vendor used\nfor grouping + logos. The UI mirrors the browsers card and ranks by\n`request_count`.", + "properties": { + "agent": { + "type": "string" + }, + "last_seen": { + "description": "Last-seen timestamp in RFC3339 format, or `None` if no rows matched.", + "example": "2026-05-29T12:00:00Z", + "type": [ + "string", + "null" + ] + }, + "provider": { + "type": "string" + }, + "purpose": { + "type": "string" + }, + "request_count": { + "format": "int64", + "type": "integer" + }, + "unique_ips": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "provider", + "agent", + "purpose", + "request_count", + "unique_ips" + ], + "type": "object" + }, + "AiAgentDescriptor": { + "description": "Static descriptor for one entry in the known-AI-agents taxonomy.", + "properties": { + "agent": { + "type": "string" + }, + "provider": { + "type": "string" + }, + "purpose": { + "type": "string" + } + }, + "required": [ + "provider", + "agent", + "purpose" + ], + "type": "object" + }, + "AiAgentPageRow": { + "description": "One row in the pages-by-agent breakdown. Returned by\n[`ProxyLogService::get_ai_agent_pages`] for a single named agent.\n`unique_ips` counts distinct client IPs that hit this path via that agent\n(same definition as the per-agent unique-IPs in [`AiAgentBreakdownRow`]).", + "properties": { + "last_seen": { + "description": "Last-seen timestamp in RFC3339 format, or `None` if no rows matched.", + "example": "2026-05-29T12:00:00Z", + "type": [ + "string", + "null" + ] + }, + "path": { + "type": "string" + }, + "request_count": { + "format": "int64", + "type": "integer" + }, + "unique_ips": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "path", + "request_count", + "unique_ips" + ], + "type": "object" + }, + "AiAgentPagesResponse": { + "description": "Response wrapping the per-agent pages breakdown rows.", + "properties": { + "agent": { + "description": "The agent name this breakdown is scoped to.", + "type": "string" + }, + "end_time": { + "type": "string" + }, + "items": { + "items": { + "$ref": "#/components/schemas/AiAgentPageRow" + }, + "type": "array" + }, + "start_time": { + "type": "string" + } + }, + "required": [ + "agent", + "items", + "start_time", + "end_time" + ], + "type": "object" + }, + "AiAgentTimelineResponse": { + "description": "Response wrapping the AI agent timeline rows.", + "properties": { + "bucket": { + "description": "Bucket interval used for the buckets (so the UI can label the x-axis).", + "example": "1 hour", + "type": "string" + }, + "end_time": { + "type": "string" + }, + "group_by": { + "description": "Echoes the grouping dimension actually applied.", + "example": "provider", + "type": "string" + }, + "items": { + "items": { + "$ref": "#/components/schemas/AiAgentTimelineRow" + }, + "type": "array" + }, + "start_time": { + "type": "string" + } + }, + "required": [ + "items", + "start_time", + "end_time", + "bucket", + "group_by" + ], + "type": "object" + }, + "AiAgentTimelineRow": { + "description": "One point in the AI-agent timeline: the request count for a single\n(`bucket`, `key`) pair, where `key` is a provider or agent name depending on\nthe requested grouping. The UI pivots these into one stacked series per\n`key` across the shared bucket x-axis.", + "properties": { + "bucket": { + "description": "Bucket start in RFC3339 format.", + "example": "2026-05-29T12:00:00Z", + "type": "string" + }, + "key": { + "description": "Provider or agent name this count belongs to.", + "example": "OpenAI", + "type": "string" + }, + "request_count": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "bucket", + "key", + "request_count" + ], + "type": "object" + }, + "AiChatLimitsSettings": { + "description": "Bounds on one AI chat turn.\n\nA turn is bounded by TIME rather than by a number of steps. A step count\nsays nothing about cost or about how long someone has been watching a\nspinner, and it cuts short exactly the long, productive turns the chat\nexists for. The user can already see each tool call and press Stop; the\ndeadline is what guarantees an *unattended* turn still ends.\n\nThe right value is a property of the model, which is why it is configurable\nrather than compiled in: a full alert-suggestion turn takes ~10 minutes\nagainst a slow local model and seconds against a hosted one.", + "properties": { + "turn_timeout_secs": { + "default": 900, + "description": "How long one turn may run before it is stopped and the partial answer\nreturned, in seconds. The user is told the turn was cut short.\n\nChecked between steps, not mid-call: a model round already in flight\nfinishes, so a turn can overrun by up to one round. Against a slow\nself-hosted model that is a minute or two. Aborting mid-stream would cut\nthe answer off in the middle of a sentence and throw away work already\npaid for, which is worse than a late stop.", + "example": 900, + "format": "int32", + "maximum": 3600, + "minimum": 30, + "type": "integer" + } + }, + "type": "object" + }, + "AiConfigSettings": { + "description": "Global AI configuration settings. Controls the default config repo\ncontaining `.claude/` directory (skills, MCP servers, plugins) that\ngets overlaid into every agent sandbox.", + "properties": { + "config_repo": { + "default": "", + "description": "Global config repo URL in \"owner/repo\" format (e.g. \"myorg/claude-config\").\nCloned at agent run time and overlaid into the sandbox's `.claude/` directory.", + "example": "", + "type": "string" + }, + "config_repo_branch": { + "default": "main", + "description": "Branch of the config repo to use.", + "example": "main", + "type": "string" + } + }, + "type": "object" + }, + "AiDataAccessResponse": { + "properties": { + "enabled": { + "description": "Whether the AI assistant may read row data from this service", + "example": false, + "type": "boolean" + }, + "service_id": { + "description": "Service id", + "format": "int32", + "type": "integer" + } + }, + "required": [ + "service_id", + "enabled" + ], + "type": "object" + }, + "AiPageBreakdownResponse": { + "description": "Response wrapping the AI page breakdown rows.", + "properties": { + "end_time": { + "type": "string" + }, + "items": { + "items": { + "$ref": "#/components/schemas/AiPageBreakdownRow" + }, + "type": "array" + }, + "start_time": { + "type": "string" + } + }, + "required": [ + "items", + "start_time", + "end_time" + ], + "type": "object" + }, + "AiPageBreakdownRow": { + "description": "One row in the AI-crawled-pages breakdown. `agent_count` is the number of\n*distinct* AI agents that hit this path, so the UI can show both how heavily\nand how broadly a page is being crawled.", + "properties": { + "agent_count": { + "format": "int64", + "type": "integer" + }, + "last_seen": { + "description": "Last-seen timestamp in RFC3339 format, or `None` if no rows matched.", + "example": "2026-05-29T12:00:00Z", + "type": [ + "string", + "null" + ] + }, + "path": { + "type": "string" + }, + "request_count": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "path", + "request_count", + "agent_count" + ], + "type": "object" + }, + "AiStatusBreakdownResponse": { + "description": "Response wrapping the AI status breakdown rows.", + "properties": { + "end_time": { + "type": "string" + }, + "items": { + "items": { + "$ref": "#/components/schemas/AiStatusBreakdownRow" + }, + "type": "array" + }, + "start_time": { + "type": "string" + } + }, + "required": [ + "items", + "start_time", + "end_time" + ], + "type": "object" + }, + "AiStatusBreakdownRow": { + "description": "One row in the AI-agent HTTP status breakdown: the request count for a\nstatus class (`2xx`/`3xx`/`4xx`/`5xx`/`other`) across crawler traffic.", + "properties": { + "request_count": { + "format": "int64", + "type": "integer" + }, + "status_class": { + "description": "Status class label.", + "example": "2xx", + "type": "string" + } + }, + "required": [ + "status_class", + "request_count" + ], + "type": "object" + }, + "AlarmListResponse": { + "description": "Paginated list of alarms.", + "properties": { + "items": { + "items": { + "$ref": "#/components/schemas/AlarmResponse" + }, + "type": "array" + }, + "page": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "page_size": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "total": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "items", + "total", + "page", + "page_size" + ], + "type": "object" + }, + "AlarmResponse": { + "description": "Full alarm representation returned by list/summary endpoints.", + "properties": { + "acknowledged_at": { + "description": "ISO-8601 UTC timestamp when the alarm was acknowledged, if any.", + "type": [ + "string", + "null" + ] + }, + "acknowledged_by": { + "description": "User ID who acknowledged the alarm, if any.", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "alarm_type": { + "type": "string" + }, + "container_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "created_at": { + "description": "ISO-8601 UTC timestamp when the row was created.", + "type": "string" + }, + "deployment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "fired_at": { + "description": "ISO-8601 UTC timestamp when the alarm fired.", + "type": "string" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "message": { + "type": [ + "string", + "null" + ] + }, + "metadata": { + "description": "Arbitrary JSON metadata attached by the alarm source." + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "resolved_at": { + "description": "ISO-8601 UTC timestamp when the alarm was resolved, if any.", + "type": [ + "string", + "null" + ] + }, + "service_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "severity": { + "type": "string" + }, + "status": { + "type": "string" + }, + "title": { + "type": "string" + }, + "updated_at": { + "description": "ISO-8601 UTC timestamp when the row was last updated.", + "type": "string" + } + }, + "required": [ + "id", + "project_id", + "alarm_type", + "severity", + "status", + "title", + "fired_at", + "created_at", + "updated_at" + ], + "type": "object" + }, + "AlarmSummaryResponse": { + "description": "Re-export AlarmSummary for the OpenAPI schema.", + "properties": { + "acknowledged": { + "format": "int32", + "minimum": 0, + "type": "integer" + }, + "by_type": { + "additionalProperties": { + "format": "int32", + "minimum": 0, + "type": "integer" + }, + "propertyNames": { + "type": "string" + }, + "type": "object" + }, + "critical": { + "format": "int32", + "minimum": 0, + "type": "integer" + }, + "firing": { + "format": "int32", + "minimum": 0, + "type": "integer" + }, + "total_active": { + "format": "int32", + "minimum": 0, + "type": "integer" + }, + "warning": { + "format": "int32", + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "total_active", + "firing", + "acknowledged", + "critical", + "warning", + "by_type" + ], + "type": "object" + }, + "AlertRuleResponse": { + "properties": { + "cooldown_minutes": { + "format": "int32", + "type": "integer" + }, + "created_at": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "environment_filter": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "error_level_filter": { + "type": [ + "string", + "null" + ] + }, + "id": { + "format": "int32", + "type": "integer" + }, + "name": { + "type": "string" + }, + "notification_priority": { + "type": "string" + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "trigger_config": {}, + "trigger_type": { + "type": "string" + }, + "updated_at": { + "type": "string" + } + }, + "required": [ + "id", + "project_id", + "name", + "trigger_type", + "trigger_config", + "notification_priority", + "cooldown_minutes", + "enabled", + "created_at", + "updated_at" + ], + "type": "object" + }, + "AllocEntry": { + "description": "Wire-format allocation. `null` in the JSON when the node hasn't been\nallocated yet — workers should treat that as \"single-host mode, do\nnot bring up the overlay\".", + "properties": { + "bridge_address": { + "type": "string" + }, + "compute_cidr": { + "type": "string" + }, + "node_id": { + "description": "Stable v5 UUID derived from the database node id.", + "type": "string" + }, + "underlay_address": { + "type": "string" + } + }, + "required": [ + "node_id", + "compute_cidr", + "bridge_address", + "underlay_address" + ], + "type": "object" + }, + "AnalyticsSessionEventsResponse": { + "properties": { + "events": { + "items": { + "$ref": "#/components/schemas/SessionEvent" + }, + "type": "array" + }, + "session_id": { + "type": "string" + }, + "total_events": { + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "session_id", + "events", + "total_events" + ], + "type": "object" + }, + "AnnotatedSpan": { + "description": "A single span annotated with the project that originally stored it.\nUsed in `UnifiedTrace` to let the UI colour-code spans by project.", + "properties": { + "project_id": { + "description": "The project that stored this span (same as `span.project_id`).", + "format": "int32", + "type": "integer" + }, + "project_name": { + "description": "Human-readable project name for waterfall colour-coding and legend.", + "type": "string" + }, + "span": { + "$ref": "#/components/schemas/SpanRecord", + "description": "Original span data verbatim from storage." + } + }, + "required": [ + "project_id", + "project_name", + "span" + ], + "type": "object" + }, + "AnomalyAlgorithm": { + "description": "Anomaly baseline algorithm. Adding one (e.g. a new robust variant) is a\ncode-only enum addition — no migration, since it lives inside the blob.", + "enum": [ + "robust", + "basic", + "agile", + "ewma" + ], + "type": "string" + }, + "AnomalyParams": { + "description": "Seasonal anomaly-band detector parameters (stub — not yet evaluated).", + "properties": { + "algorithm": { + "$ref": "#/components/schemas/AnomalyAlgorithm", + "description": "Baseline model. `robust` is the default (seasonal, stable, flags level\nshifts); `ewma`/`agile` adopt level shifts; `basic` is non-seasonal." + }, + "baseline_lookback_days": { + "description": "How far back to build the baseline. `None` = an evaluator default.", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "deviations": { + "description": "Band width in robust standard deviations (Datadog's `bounds`).", + "format": "double", + "type": "number" + }, + "direction": { + "$ref": "#/components/schemas/Direction", + "description": "Which side(s) of the band a deviation must be on to count." + }, + "pct_anomalous": { + "description": "Fraction (0..=1) of points in the window that must be anomalous to fire.", + "format": "double", + "type": "number" + }, + "seasonality": { + "$ref": "#/components/schemas/Seasonality", + "description": "Seasonality model for the baseline." + } + }, + "type": "object" + }, + "AnomalyPreviewPointResponse": { + "properties": { + "breaching": { + "type": "boolean" + }, + "bucket": { + "example": "2025-10-12T12:15:47Z", + "type": "string" + }, + "lower": { + "description": "Lower edge of the expected band at this point.", + "format": "double", + "type": "number" + }, + "upper": { + "description": "Upper edge of the expected band at this point.", + "format": "double", + "type": "number" + }, + "value": { + "format": "double", + "type": "number" + } + }, + "required": [ + "bucket", + "value", + "lower", + "upper", + "breaching" + ], + "type": "object" + }, + "AnomalyPreviewRequest": { + "properties": { + "aggregation": { + "description": "One of `avg|sum|min|max|count|rate|p50|p90|p95|p99`.", + "type": "string" + }, + "detection_config": { + "$ref": "#/components/schemas/DetectionConfig", + "description": "The detector to backtest. `static` and `anomaly` are supported — the\nkinds the evaluator actually runs." + }, + "end_time": { + "description": "RFC 3339; defaults to now.", + "example": "2025-10-12T12:15:47Z", + "type": [ + "string", + "null" + ] + }, + "metric_name": { + "type": "string" + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "start_time": { + "description": "RFC 3339; defaults to 7 days before `end_time`.", + "example": "2025-10-12T12:15:47Z", + "type": [ + "string", + "null" + ] + }, + "window_secs": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "project_id", + "metric_name", + "aggregation", + "window_secs", + "detection_config" + ], + "type": "object" + }, + "AnomalyPreviewResponse": { + "properties": { + "baseline_samples": { + "description": "Baseline sample count (drives the `sufficient` flag).", + "format": "int64", + "type": "integer" + }, + "breach_count": { + "description": "How many points in the range would have fired.", + "format": "int64", + "type": "integer" + }, + "points": { + "items": { + "$ref": "#/components/schemas/AnomalyPreviewPointResponse" + }, + "type": "array" + }, + "sufficient": { + "description": "Whether the baseline had enough history for a trustworthy band.", + "type": "boolean" + } + }, + "required": [ + "points", + "breach_count", + "baseline_samples", + "sufficient" + ], + "type": "object" + }, + "ApiKeyListResponse": { + "properties": { + "api_keys": { + "items": { + "$ref": "#/components/schemas/ApiKeyResponse" + }, + "type": "array" + }, + "total": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "api_keys", + "total" + ], + "type": "object" + }, + "ApiKeyResponse": { + "properties": { + "created_at": { + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "expires_at": { + "example": "2024-12-31T23:59:59Z", + "format": "date-time", + "type": [ + "string", + "null" + ] + }, + "id": { + "format": "int32", + "type": "integer" + }, + "is_active": { + "type": "boolean" + }, + "key_prefix": { + "type": "string" + }, + "last_used_at": { + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": [ + "string", + "null" + ] + }, + "name": { + "type": "string" + }, + "permissions": { + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + }, + "role_type": { + "type": "string" + } + }, + "required": [ + "id", + "name", + "key_prefix", + "role_type", + "is_active", + "created_at" + ], + "type": "object" + }, + "AppSettings": { + "description": "Application settings stored in the database\nAll fields have sensible defaults for easy onboarding", + "properties": { + "agent_sandbox": { + "default": { + "api_key_encrypted": null, + "auth_type": "subscription", + "cpu_limit": 4, + "custom_image": "", + "default_provider": "claude_cli", + "enabled": true, + "memory_limit_mb": 8192, + "network_mode": "full", + "providers": {}, + "runtime": "node", + "sandbox_backend": null + }, + "oneOf": [ + { + "$ref": "#/components/schemas/AgentSandboxSettings" + } + ] + }, + "ai_chat_limits": { + "default": { + "turn_timeout_secs": 900 + }, + "oneOf": [ + { + "$ref": "#/components/schemas/AiChatLimitsSettings", + "description": "Limits on a single AI chat turn. Operator-tunable because the right\nvalue depends on the model: a turn against a slow self-hosted model can\nlegitimately take ten minutes, while a hosted one finishes in seconds\nand a shorter ceiling keeps costs predictable." + } + ] + }, + "ai_config": { + "default": { + "config_repo": "", + "config_repo_branch": "main" + }, + "oneOf": [ + { + "$ref": "#/components/schemas/AiConfigSettings" + } + ] + }, + "build_limits": { + "default": { + "cpu_limit_cores": 0, + "max_concurrent": 2, + "memory_limit_mb": 0 + }, + "oneOf": [ + { + "$ref": "#/components/schemas/BuildLimitsSettings", + "description": "Build-time resource limits applied on the control plane to prevent\n`docker build` from saturating host CPU/RAM. Worker nodes are\nintentionally NOT subject to these limits (each worker is dedicated\nhardware that already has its own per-host headroom)." + } + ] + }, + "cluster_dns": { + "default": { + "enabled": false + }, + "oneOf": [ + { + "$ref": "#/components/schemas/ClusterDnsSettings", + "description": "Cluster-DNS resolver settings (ADR-024, experimental beta). Off by\ndefault — see `ClusterDnsSettings` for the incident background and\ntrade-offs. Must be explicitly enabled by operators who need\n`*.temps.local` service-to-service resolution inside containers." + } + ] + }, + "console_version": { + "default": null, + "description": "Binary version tag (e.g. \"v0.1.0\") of the *console* process\n(`temps serve`, role=all or role=console) that last started. Written\non console startup; read by the standalone `temps proxy` to detect\nversion skew during a rolling upgrade (ADR-017 Phase 3). `None` on\ninstalls that never ran a console build carrying this field.\n\nThis is informational state written by the binary itself — NOT an\noperator-tunable setting. It is intentionally absent from\n`AppSettingsResponse` and the PATCH path so an operator cannot\naccidentally overwrite the self-recorded value.", + "type": [ + "string", + "null" + ] + }, + "container_logs": { + "default": { + "max_file": 3, + "max_size": "50m", + "service_max_file": 3, + "service_max_size": "20m" + }, + "oneOf": [ + { + "$ref": "#/components/schemas/ContainerLogSettings" + } + ] + }, + "disk_space_alert": { + "default": { + "check_interval_seconds": 300, + "enabled": true, + "monitor_path": null, + "threshold_percent": 80 + }, + "oneOf": [ + { + "$ref": "#/components/schemas/DiskSpaceAlertSettings" + } + ] + }, + "dns_provider": { + "default": { + "cloudflare_api_key": null, + "provider": "manual" + }, + "oneOf": [ + { + "$ref": "#/components/schemas/DnsProviderSettings" + } + ] + }, + "docker_registry": { + "default": { + "ca_certificate": null, + "enabled": false, + "password": null, + "registry_url": null, + "tls_verify": true, + "username": null + }, + "oneOf": [ + { + "$ref": "#/components/schemas/DockerRegistrySettings" + } + ] + }, + "edge_target": { + "default": null, + "description": "Public edge target that generated DNS records point at when a managed\ndomain opts into automatic record sync. An IPv4/IPv6 address produces an\n`A`/`AAAA` record; anything else is treated as a `CNAME` target. `None`\ndisables DNS record sync regardless of per-domain opt-in.", + "type": [ + "string", + "null" + ] + }, + "external_url": { + "default": null, + "type": [ + "string", + "null" + ] + }, + "insecure_tls": { + "default": false, + "description": "Skip TLS certificate verification on outbound HTTP clients built by the\nserver (deployer, agent, remote service client). Strictly opt-in for\noperators running self-signed control plane / worker certs on a trusted\ninternal network. Worker→control-plane traffic that traverses the public\ninternet must keep this `false` — otherwise a MitM steals the join token.", + "type": "boolean" + }, + "internal_url": { + "default": null, + "description": "URL that service containers use to reach the Temps API from *inside*\nthe Docker network (OTLP metrics ingest, agent callbacks, etc.). On\nDocker Desktop this defaults to `http://host.docker.internal:`;\non Linux it requires the `host.docker.internal:host-gateway` host\nmapping (which Temps adds to provisioned containers). Distinct from\n`external_url`, which is the public-facing address.", + "type": [ + "string", + "null" + ] + }, + "letsencrypt": { + "default": { + "email": null, + "environment": "production" + }, + "oneOf": [ + { + "$ref": "#/components/schemas/LetsEncryptSettings" + } + ] + }, + "monitoring": { + "default": { + "clickhouse_url": null, + "enabled": false, + "retention_daily_years": 2, + "retention_hourly_days": 90, + "retention_raw_days": 7, + "scrape_interval_secs": 30, + "store": "timescale_db" + }, + "oneOf": [ + { + "$ref": "#/components/schemas/MonitoringSettings", + "description": "Metrics observability settings. Controls the MetricsStore backend,\nscrape interval, and tiered retention windows." + } + ] + }, + "multi_node": { + "default": { + "cluster_ca_cert_pem": null, + "cluster_ca_key_encrypted": null, + "join_token_hash": null, + "legacy_shared_token_enabled": true, + "node_cpu_alert_percent": 90, + "node_disk_alert_percent": 90, + "node_memory_alert_percent": 90, + "private_address": null, + "require_mtls": false + }, + "oneOf": [ + { + "$ref": "#/components/schemas/MultiNodeSettings" + } + ] + }, + "observability_compression": { + "default": { + "otel_spans_after_hours": 24, + "proxy_logs_after_hours": 24 + }, + "oneOf": [ + { + "$ref": "#/components/schemas/ObservabilityCompressionSettings", + "description": "TimescaleDB compression delays for immutable observability data.\nChanges are applied at runtime by the Settings API." + } + ] + }, + "observability_retention": { + "default": { + "otel_logs_days": 90, + "otel_metrics_days": 90, + "otel_spans_days": 90, + "proxy_logs_days": 30 + }, + "oneOf": [ + { + "$ref": "#/components/schemas/ObservabilityRetentionSettings", + "description": "Retention windows for raw proxy and OpenTelemetry telemetry.\nTimescaleDB policies are updated at runtime by the Settings API." + } + ] + }, + "on_demand_tls": { + "default": { + "deployment_url_mode": "http", + "enabled": false, + "hourly_cap": 10, + "max_concurrent": 3, + "zone": null + }, + "oneOf": [ + { + "$ref": "#/components/schemas/OnDemandTlsSettings" + } + ] + }, + "preview_domain": { + "default": "localho.st", + "type": "string" + }, + "preview_gateway": { + "default": { + "auto_upgrade": true, + "host_port": 8090, + "image": "ghcr.io/gotempsh/temps-preview-gateway:latest" + }, + "oneOf": [ + { + "$ref": "#/components/schemas/PreviewGatewaySettings" + } + ] + }, + "rate_limiting": { + "default": { + "blacklist_ips": [], + "enabled": false, + "max_requests_per_hour": 1000, + "max_requests_per_minute": 60, + "whitelist_ips": [] + }, + "oneOf": [ + { + "$ref": "#/components/schemas/RateLimitSettings" + } + ] + }, + "require_mfa_for_admins": { + "default": false, + "description": "When `true`, any user holding the `Admin` role must have MFA enrolled\n(`users.mfa_enabled = true`) to complete a **password** login. Users\nwithout MFA enrolled are rejected with a typed error instructing them\nto enroll before retrying. This only gates the password-login path\n(`AuthService::login`) -- SSO/OIDC logins are handled by a separate\ncode path (`OidcService::resolve_user` + `oidc_handler`) and are\nintentionally unaffected, since federating identity to a\nproperly-hardened IdP is itself an acceptable alternative to local\nTOTP MFA. Modeled as a settings row (not an env var) per CLAUDE.md so\nan operator can flip it at runtime via the Settings API without\nrestarting the binary.", + "type": "boolean" + }, + "screenshots": { + "default": { + "enabled": false, + "provider": "local", + "url": "" + }, + "oneOf": [ + { + "$ref": "#/components/schemas/ScreenshotSettings" + } + ] + }, + "security_headers": { + "default": { + "content_security_policy": "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self'; frame-ancestors 'self'", + "enabled": false, + "permissions_policy": "geolocation=(), microphone=(), camera=()", + "preset": "moderate", + "referrer_policy": "strict-origin-when-cross-origin", + "strict_transport_security": "max-age=31536000; includeSubDomains", + "x_content_type_options": "nosniff", + "x_frame_options": "SAMEORIGIN", + "x_xss_protection": "1; mode=block" + }, + "oneOf": [ + { + "$ref": "#/components/schemas/SecurityHeadersSettings" + } + ] + }, + "setup_complete": { + "default": false, + "description": "Set to `true` by `temps setup` (all modes) once initial configuration\nhas been applied. The web onboarding wizard reads this from the server\nand skips itself when true, preventing the \"Configure Base Domain\" wall\nfrom appearing on installs that were already configured via the CLI.", + "type": "boolean" + } + }, + "type": "object" + }, + "AppSettingsResponse": { + "description": "Safe response for application settings that masks sensitive fields", + "properties": { + "agent_sandbox": { + "$ref": "#/components/schemas/AgentSandboxSettingsMasked" + }, + "ai_chat_limits": { + "$ref": "#/components/schemas/AiChatLimitsSettings", + "description": "Per-turn limits for the AI chat. No sensitive content." + }, + "ai_config": { + "$ref": "#/components/schemas/AiConfigSettings" + }, + "build_limits": { + "$ref": "#/components/schemas/BuildLimitsSettings", + "description": "Build-time resource limits (control-plane only). No sensitive content,\npassed through as-is." + }, + "cluster_dns": { + "$ref": "#/components/schemas/ClusterDnsSettings", + "description": "Cluster-DNS resolver settings (ADR-024, experimental beta). No masking\nneeded — `enabled` is a plain bool with no sensitive content. Passed\nthrough as-is so the settings UI can read and toggle the flag." + }, + "container_logs": { + "$ref": "#/components/schemas/ContainerLogSettings" + }, + "disk_space_alert": { + "$ref": "#/components/schemas/DiskSpaceAlertSettings" + }, + "dns_provider": { + "$ref": "#/components/schemas/DnsProviderSettingsMasked" + }, + "docker_registry": { + "$ref": "#/components/schemas/DockerRegistrySettingsMasked" + }, + "edge_target": { + "description": "Public edge target that synced DNS records point at (IP → A/AAAA, else CNAME).", + "type": [ + "string", + "null" + ] + }, + "effective_metrics_store": { + "$ref": "#/components/schemas/MetricsStoreKind", + "description": "The storage backend the runtime is **actually** using for metrics,\nafter reconciling the `monitoring.store` toggle with the server's\n`TEMPS_CLICKHOUSE_*` configuration. When `monitoring.store` is\n`click_house` but those env vars are not fully set, the runtime falls\nback to TimescaleDB — in that case this reports `timescale_db` even\nthough `monitoring.store` says `click_house`. The UI shows this as the\neffective backend and warns when it diverges from the configured store." + }, + "effective_observability_store": { + "$ref": "#/components/schemas/MetricsStoreKind", + "description": "Storage backend actually used for proxy logs, OTel spans, and OTel\nmetrics. OTel logs remain TimescaleDB-backed. Unlike resource metrics,\nthese domains switch to ClickHouse whenever the server-level ClickHouse\nconnection is configured; they do not use the monitoring store toggle." + }, + "external_url": { + "type": [ + "string", + "null" + ] + }, + "insecure_tls": { + "type": "boolean" + }, + "internal_url": { + "type": [ + "string", + "null" + ] + }, + "letsencrypt": { + "$ref": "#/components/schemas/LetsEncryptSettings" + }, + "monitored_services_count": { + "description": "Number of enabled, running services the MetricsScraper currently\nincludes. Used for the lightweight storage estimate in the UI.", + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "monitoring": { + "$ref": "#/components/schemas/MonitoringSettingsMasked" + }, + "multi_node": { + "$ref": "#/components/schemas/MultiNodeSettingsMasked" + }, + "observability_compression": { + "$ref": "#/components/schemas/ObservabilityCompressionSettings", + "description": "TimescaleDB compression delays for immutable proxy logs and OTel spans." + }, + "observability_retention": { + "$ref": "#/components/schemas/ObservabilityRetentionSettings", + "description": "Retention windows for raw proxy logs and OpenTelemetry data." + }, + "preview_domain": { + "type": "string" + }, + "preview_gateway": { + "$ref": "#/components/schemas/PreviewGatewaySettingsMasked" + }, + "rate_limiting": { + "$ref": "#/components/schemas/RateLimitSettings" + }, + "require_mfa_for_admins": { + "description": "When enabled, Admin-role accounts without MFA enrolled are rejected\nat password login (bherila/temps#32). SSO/OIDC logins are unaffected.", + "type": "boolean" + }, + "screenshots": { + "$ref": "#/components/schemas/ScreenshotSettings" + }, + "security_headers": { + "$ref": "#/components/schemas/SecurityHeadersSettings" + }, + "setup_complete": { + "description": "Whether `temps setup` has been run at least once. The web onboarding\nwizard checks this field on load and skips itself when true.", + "type": "boolean" + } + }, + "required": [ + "preview_domain", + "screenshots", + "letsencrypt", + "dns_provider", + "security_headers", + "rate_limiting", + "docker_registry", + "disk_space_alert", + "container_logs", + "agent_sandbox", + "ai_config", + "preview_gateway", + "multi_node", + "monitoring", + "observability_compression", + "observability_retention", + "effective_metrics_store", + "effective_observability_store", + "insecure_tls", + "setup_complete", + "require_mfa_for_admins", + "cluster_dns", + "build_limits", + "ai_chat_limits" + ], + "type": "object" + }, + "ApplyHostnameModeRequest": { + "description": "Request to apply a hostname mode (recompute + optional DNS sync).", + "properties": { + "mode": { + "description": "Target mode to apply: `\"standard\"` or `\"flat\"`.", + "type": "string" + }, + "sync_dns": { + "description": "Also reconcile the provider's DNS zone for the affected hostnames.", + "type": "boolean" + } + }, + "required": [ + "mode" + ], + "type": "object" + }, + "ArchiveFlagResponse": { + "properties": { + "archived_at": { + "type": [ + "string", + "null" + ] + }, + "key": { + "type": "string" + } + }, + "required": [ + "key" + ], + "type": "object" + }, + "ArchiveMode": { + "enum": [ + "off", + "on", + "always", + "unknown" + ], + "type": "string" + }, + "AssignRoleRequest": { + "properties": { + "role_type": { + "type": "string" + }, + "user_id": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "user_id", + "role_type" + ], + "type": "object" + }, + "AttachScheduleServicesRequest": { + "description": "Body for `POST /api/backups/schedules/{id}/services` — attach external\nservices to a backup schedule. Idempotent.", + "properties": { + "service_ids": { + "description": "External service ids to attach. Duplicates are de-duplicated server-side.", + "items": { + "format": "int32", + "type": "integer" + }, + "type": "array" + } + }, + "required": [ + "service_ids" + ], + "type": "object" + }, + "AttachScheduleServicesResponse": { + "description": "Response for `POST /api/backups/schedules/{id}/services`.", + "properties": { + "inserted": { + "description": "Number of rows actually inserted (excludes rows skipped by\n`ON CONFLICT DO NOTHING`).", + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "total_attached": { + "description": "Total number of services now attached to the schedule.", + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "inserted", + "total_attached" + ], + "type": "object" + }, + "AuditLogIpInfo": { + "description": "IP address information in audit log", + "properties": { + "city": { + "description": "City name", + "example": "San Francisco", + "type": [ + "string", + "null" + ] + }, + "country": { + "description": "Country code", + "example": "US", + "type": [ + "string", + "null" + ] + }, + "ip": { + "description": "IP address", + "example": "192.168.1.1", + "type": "string" + }, + "latitude": { + "description": "Latitude", + "example": 37.7749, + "format": "double", + "type": [ + "number", + "null" + ] + }, + "longitude": { + "description": "Longitude", + "example": 122.4194, + "format": "double", + "type": [ + "number", + "null" + ] + } + }, + "required": [ + "ip" + ], + "type": "object" + }, + "AuditLogResponse": { + "description": "Response type for audit log entries", + "properties": { + "audit_date": { + "description": "When the action occurred", + "example": 11932193, + "format": "int64", + "type": "integer" + }, + "data": { + "description": "Additional context about the action" + }, + "id": { + "description": "Unique identifier for the audit log entry", + "format": "int32", + "type": "integer" + }, + "ip_address": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/AuditLogIpInfo", + "description": "IP address details" + } + ] + }, + "operation_type": { + "description": "The type of action that was performed", + "example": "USER_LOGIN", + "type": "string" + }, + "user": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/AuditLogUserInfo", + "description": "User details who performed the action" + } + ] + }, + "user_id": { + "description": "The user who performed the action (`null` when that account has\nsince been deleted; `data` retains the original actor context)", + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + "required": [ + "id", + "operation_type", + "audit_date" + ], + "type": "object" + }, + "AuditLogUserInfo": { + "description": "User information in audit log", + "properties": { + "email": { + "description": "User's email", + "example": "john.doe@example.com", + "type": "string" + }, + "id": { + "description": "User ID", + "format": "int32", + "type": "integer" + }, + "name": { + "description": "User's name", + "example": "John Doe", + "type": "string" + } + }, + "required": [ + "id", + "name", + "email" + ], + "type": "object" + }, + "AuthFlavorDto": { + "description": "One auth flavor surfaced to the UI. Mirrors `AuthFlavor` in the catalog\nbut without the seed-path / env-var fields the frontend doesn't need\n(those are server-side only — exposing them just bloats the response).", + "properties": { + "description": { + "type": "string" + }, + "env_var": { + "description": "For `api_key` format: the env var name that will be set inside the\nsandbox. Useful for showing the user \"we'll set OPENAI_API_KEY\" so\nthey know what their key controls.", + "type": [ + "string", + "null" + ] + }, + "format": { + "description": "`api_key`, `oauth_token`, or `config_file` — drives which input UI\nthe settings page renders (single-line vs. multi-line textarea).", + "type": "string" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + } + }, + "required": [ + "id", + "label", + "description", + "format" + ], + "type": "object" + }, + "AuthResponse": { + "properties": { + "message": { + "type": "string" + }, + "mfa_required": { + "type": "boolean" + }, + "success": { + "type": "boolean" + }, + "user_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + "required": [ + "success", + "message", + "mfa_required" + ], + "type": "object" + }, + "AuthStatusResponse": { + "properties": { + "cli_token": { + "type": [ + "string", + "null" + ] + }, + "status": { + "type": "string" + } + }, + "required": [ + "status" + ], + "type": "object" + }, + "AuthTokenResponse": { + "properties": { + "access_token": { + "type": "string" + }, + "expires_at": { + "format": "int64", + "type": "integer" + }, + "refresh_token": { + "type": "string" + } + }, + "required": [ + "access_token", + "refresh_token", + "expires_at" + ], + "type": "object" + }, + "AutoWatchParams": { + "description": "Auto-watch (Watchdog-style) detector parameters (stub — not evaluated).", + "properties": { + "direction": { + "$ref": "#/components/schemas/Direction", + "description": "The engine self-tunes the band; the user supplies only the direction." + } + }, + "type": "object" + }, + "AutofixRunConfig": { + "description": "User-chosen per-run options, persisted as JSON in `agent_runs.run_config`.\nEvery field is optional — unset fields fall back to the provider defaults\nin settings, then to built-in defaults.", + "properties": { + "branch": { + "default": null, + "description": "Branch to clone instead of the project's main branch.", + "type": [ + "string", + "null" + ] + }, + "max_turns": { + "default": null, + "description": "Per-run turn cap applied to every phase of this run. Only enforced\nfor CLIs with a turn flag (Claude Code); Codex/OpenCode run to\ncompletion. `None` uses the provider's per-phase defaults.", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "model": { + "default": null, + "description": "Model id for the chosen provider. `None` uses the provider's saved\ndefault model, or the CLI's own default.", + "type": [ + "string", + "null" + ] + }, + "provider": { + "default": null, + "description": "AI provider id (\"claude_cli\", \"codex_cli\", \"opencode\"). `None` uses\nthe platform default provider from agent sandbox settings.", + "type": [ + "string", + "null" + ] + } + }, + "type": "object" + }, + "AutofixerRunResponse": { + "properties": { + "ai_model": { + "type": [ + "string", + "null" + ] + }, + "ai_output": { + "type": [ + "string", + "null" + ] + }, + "ai_provider": { + "description": "AI provider slug this run executes with (e.g. claude_cli, codex_cli).", + "type": [ + "string", + "null" + ] + }, + "analysis": { + "type": [ + "string", + "null" + ] + }, + "branch_name": { + "type": [ + "string", + "null" + ] + }, + "completed_at": { + "type": [ + "string", + "null" + ] + }, + "created_at": { + "type": "string" + }, + "error_message": { + "type": [ + "string", + "null" + ] + }, + "files_changed": { + "format": "int32", + "type": "integer" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "phase": { + "type": [ + "string", + "null" + ] + }, + "pr_number": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "pr_url": { + "type": [ + "string", + "null" + ] + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "run_config": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/AutofixRunConfig", + "description": "Per-run options the run was started with; used to prefill the\nretry / start-over dialog." + } + ] + }, + "started_at": { + "type": [ + "string", + "null" + ] + }, + "status": { + "type": "string" + }, + "tokens_input": { + "format": "int32", + "type": "integer" + }, + "tokens_output": { + "format": "int32", + "type": "integer" + }, + "trigger_source_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "user_context": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "id", + "project_id", + "status", + "tokens_input", + "tokens_output", + "files_changed", + "created_at" + ], + "type": "object" + }, + "AutofixerRunWithLogsResponse": { + "properties": { + "logs": { + "items": { + "$ref": "#/components/schemas/AgentRunLogResponse" + }, + "type": "array" + }, + "run": { + "$ref": "#/components/schemas/AutofixerRunResponse" + } + }, + "required": [ + "run", + "logs" + ], + "type": "object" + }, + "AvailableContainerInfo": { + "description": "Available Docker container that can be imported as a service", + "properties": { + "container_id": { + "description": "Container ID or name", + "example": "abc123def456", + "type": "string" + }, + "container_name": { + "description": "Container display name", + "example": "my-postgres", + "type": "string" + }, + "exposed_ports": { + "description": "Exposed ports (e.g., [5432] for PostgreSQL, [6379] for Redis)", + "items": { + "format": "int32", + "minimum": 0, + "type": "integer" + }, + "type": "array" + }, + "image": { + "description": "Docker image name (e.g., \"gotempsh/postgres-walg:18-bookworm\")", + "example": "gotempsh/postgres-walg:18-bookworm", + "type": "string" + }, + "is_running": { + "description": "Whether the container is currently running", + "example": true, + "type": "boolean" + }, + "service_type": { + "$ref": "#/components/schemas/ServiceTypeRoute", + "description": "Service type this container represents" + }, + "version": { + "description": "Extracted version from image", + "example": "18", + "type": "string" + } + }, + "required": [ + "container_id", + "container_name", + "image", + "version", + "service_type", + "is_running" + ], + "type": "object" + }, + "AvailablePermissions": { + "description": "Response containing all available permissions for frontend validation", + "properties": { + "permissions": { + "description": "All available permissions in the system", + "items": { + "$ref": "#/components/schemas/PermissionInfo" + }, + "type": "array" + }, + "roles": { + "description": "All available roles", + "items": { + "$ref": "#/components/schemas/RoleInfo" + }, + "type": "array" + } + }, + "required": [ + "permissions", + "roles" + ], + "type": "object" + }, + "BackupAlertListResponse": { + "description": "Response body for the list-backup-alerts endpoint.", + "properties": { + "alerts": { + "description": "All currently open (unresolved) alerts, newest first.", + "items": { + "$ref": "#/components/schemas/BackupAlertResponse" + }, + "type": "array" + } + }, + "required": [ + "alerts" + ], + "type": "object" + }, + "BackupAlertResponse": { + "description": "A single open backup alert surfaced in the UI banner.\n\nAlerts are auto-opened by the watcher and auto-resolved when the triggering\ncondition clears. No manual dismiss is required or supported.\n\nThe optional `schedule_s3_source_id` field is included so the UI can\ndeep-link an `overdue_schedule` alert to the S3 source detail page that\nhosts the schedule. `stalled_job` alerts no longer carry a deep-link\ntarget — the alert message text contains the backup id for display.", + "properties": { + "id": { + "description": "Database id of the alert row.", + "format": "int64", + "type": "integer" + }, + "kind": { + "description": "`\"overdue_schedule\"` or `\"stalled_job\"`.", + "type": "string" + }, + "message": { + "description": "Human-readable description of the alert condition.", + "type": "string" + }, + "opened_at": { + "description": "RFC 3339 timestamp when the alert was opened.", + "example": "2026-05-15T10:00:00Z", + "type": "string" + }, + "schedule_id": { + "description": "FK to `backup_schedules.id`. Set for `overdue_schedule` alerts.", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "schedule_name": { + "description": "Human-readable name of the linked schedule, if applicable.", + "type": [ + "string", + "null" + ] + }, + "schedule_s3_source_id": { + "description": "FK to `backup_schedules.s3_source_id`. The UI uses this to deep-link\nthe alert to the S3 source detail page that hosts the schedule.\nSet for `overdue_schedule` alerts.", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "severity": { + "description": "`\"warning\"` or `\"critical\"`.", + "type": "string" + } + }, + "required": [ + "id", + "kind", + "severity", + "message", + "opened_at" + ], + "type": "object" + }, + "BackupResponse": { + "description": "Response type for backup", + "properties": { + "attempts": { + "description": "How many times this job has been claimed and run. `null` for legacy\nbackups with no `backup_jobs` row.", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "backup_id": { + "type": "string" + }, + "backup_type": { + "type": "string" + }, + "checksum": { + "type": [ + "string", + "null" + ] + }, + "completed_at": { + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "compression_type": { + "type": "string" + }, + "created_by": { + "format": "int32", + "type": "integer" + }, + "current_step": { + "description": "Name of the engine step currently executing (e.g., `\"walg_push\"`).\n`null` when no `backup_jobs` row exists for this backup (legacy rows\npre-dating ADR-014), or when the job has not yet completed its first step.", + "type": [ + "string", + "null" + ] + }, + "error_message": { + "type": [ + "string", + "null" + ] + }, + "expires_at": { + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "external_service": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/ExternalServiceSummary", + "description": "External service that owns this backup (Redis, Postgres, etc.).\n`null` for control-plane backups (the Temps server's own database)." + } + ] + }, + "file_count": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "id": { + "format": "int32", + "type": "integer" + }, + "live_size_bytes": { + "description": "Best-effort partial size while a backup is still running, computed\nby listing the S3 prefix. Null when the backup is finished\n(`size_bytes` is authoritative in that case).", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "max_attempts": { + "description": "Maximum attempts before the job is permanently failed. `null` for\nlegacy backups.", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "max_runtime_secs": { + "description": "Resolved wall-clock timeout for this backup job (seconds). `null` for\nlegacy backups. Derived from the three-tier resolution order:\ncaller override → schedule override → engine default.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "metadata": {}, + "name": { + "type": "string" + }, + "s3_location": { + "type": "string" + }, + "s3_source_id": { + "format": "int32", + "type": "integer" + }, + "schedule_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "size_bytes": { + "description": "Final size of the backup once completed. Null while running.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "started_at": { + "format": "int64", + "type": "integer" + }, + "state": { + "type": "string" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "backup_id", + "backup_type", + "state", + "started_at", + "s3_source_id", + "s3_location", + "metadata", + "compression_type", + "created_by", + "tags" + ], + "type": "object" + }, + "BackupScheduleResponse": { + "description": "Response type for backup schedule", + "properties": { + "backup_type": { + "type": "string" + }, + "created_at": { + "format": "int64", + "type": "integer" + }, + "description": { + "type": [ + "string", + "null" + ] + }, + "enabled": { + "type": "boolean" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "include_control_plane": { + "description": "When `true`, every run also produces a `control_plane` backup\n(Temps's own Postgres). When `false`, only the external service\nfan-out happens.", + "type": "boolean" + }, + "last_run": { + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "max_runtime_secs": { + "description": "Per-schedule wall-clock timeout override for backup jobs (seconds).\n`null` means the engine-family default is used. See\n`temps_backup_core::timeouts::default_max_runtime_secs`.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "name": { + "type": "string" + }, + "next_run": { + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "retention_period": { + "format": "int32", + "type": "integer" + }, + "s3_source_id": { + "format": "int32", + "type": "integer" + }, + "schedule_expression": { + "example": "0 0 * * *", + "type": "string" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "target_all_services": { + "description": "When `true`, the schedule auto-includes every external service on\nthe host (and any future ones). When `false`, the schedule only\ntargets services attached via `backup_schedule_services`.", + "type": "boolean" + }, + "updated_at": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "id", + "name", + "backup_type", + "retention_period", + "s3_source_id", + "schedule_expression", + "enabled", + "created_at", + "updated_at", + "tags", + "target_all_services", + "include_control_plane" + ], + "type": "object" + }, + "BitbucketAuthInput": { + "description": "Authentication input for a Bitbucket Cloud provider. Use `access_token` for\na Repository or Workspace Access Token (PAT), or `username` + `app_password`\nfor App Password (HTTP Basic) authentication.", + "oneOf": [ + { + "description": "Personal / Workspace / Repository Access Token.", + "properties": { + "token": { + "description": "The Bitbucket access token value.", + "type": "string" + }, + "type": { + "enum": [ + "access_token" + ], + "type": "string" + } + }, + "required": [ + "token", + "type" + ], + "type": "object" + }, + { + "description": "HTTP Basic / App Password authentication.", + "properties": { + "password": { + "description": "App password generated in Bitbucket security settings.", + "type": "string" + }, + "type": { + "enum": [ + "app_password" + ], + "type": "string" + }, + "username": { + "description": "Bitbucket account username.", + "type": "string" + } + }, + "required": [ + "username", + "password", + "type" + ], + "type": "object" + } + ] + }, + "BlobResponse": { + "description": "Response after uploading a blob", + "properties": { + "contentType": { + "description": "Content type of the blob", + "example": "image/png", + "type": "string" + }, + "pathname": { + "description": "Original pathname", + "example": "images/avatar-abc123.png", + "type": "string" + }, + "size": { + "description": "Size in bytes", + "example": 12345, + "format": "int64", + "type": "integer" + }, + "uploadedAt": { + "description": "Upload timestamp", + "example": "2025-01-03T12:00:00Z", + "format": "date-time", + "type": "string" + }, + "url": { + "description": "URL path to access the blob", + "example": "/api/blob/123/images/avatar-abc123.png", + "type": "string" + } + }, + "required": [ + "url", + "pathname", + "contentType", + "size", + "uploadedAt" + ], + "type": "object" + }, + "BlobStatusResponse": { + "description": "Response for Blob service status", + "properties": { + "docker_image": { + "description": "Docker image being used", + "example": "ghcr.io/rustfs/rustfs:0.5.0", + "type": [ + "string", + "null" + ] + }, + "enabled": { + "description": "Whether the Blob service is enabled", + "example": true, + "type": "boolean" + }, + "healthy": { + "description": "Whether the service is healthy", + "example": true, + "type": "boolean" + }, + "version": { + "description": "Current version (if running)", + "example": "0.5.0", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "enabled", + "healthy" + ], + "type": "object" + }, + "BranchInfo": { + "properties": { + "commit_sha": { + "type": "string" + }, + "name": { + "type": "string" + }, + "protected": { + "type": "boolean" + } + }, + "required": [ + "name", + "commit_sha", + "protected" + ], + "type": "object" + }, + "BranchListResponse": { + "properties": { + "branches": { + "items": { + "$ref": "#/components/schemas/BranchInfo" + }, + "type": "array" + } + }, + "required": [ + "branches" + ], + "type": "object" + }, + "BrowserCount": { + "properties": { + "browser": { + "type": "string" + }, + "count": { + "format": "int64", + "type": "integer" + }, + "percentage": { + "format": "double", + "type": "number" + } + }, + "required": [ + "browser", + "count", + "percentage" + ], + "type": "object" + }, + "BrowsersQuery": { + "properties": { + "end_date": { + "format": "date-time", + "type": "string" + }, + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "limit": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "start_date": { + "format": "date-time", + "type": "string" + } + }, + "required": [ + "start_date", + "end_date", + "project_id" + ], + "type": "object" + }, + "BuildConfiguration": { + "description": "Build configuration (for building images from source)", + "properties": { + "args": { + "additionalProperties": { + "type": "string" + }, + "description": "Build arguments", + "propertyNames": { + "type": "string" + }, + "type": "object" + }, + "context": { + "description": "Build context (Dockerfile path or buildpack)", + "type": "string" + }, + "dockerfile": { + "description": "Dockerfile path (relative to context)", + "type": [ + "string", + "null" + ] + }, + "target": { + "description": "Target stage (for multi-stage builds)", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "context", + "args" + ], + "type": "object" + }, + "BuildLimitsSettings": { + "description": "Control-plane build resource limits.\n\nCaps how many builds run concurrently AND how much CPU/memory each build\nis allowed to consume. A single global semaphore in the deployer crate\ngates every `DockerRuntime::build_image` call to `max_concurrent`. When\nthe semaphore is full, additional builds queue and wait — they do not\nfail. Per-build CPU/memory caps are forwarded to Docker via\n`BuildImageOptions { memory, cpuquota, cpuperiod }`.\n\n`cpu_limit_cores = 0.0` or `memory_limit_mb = 0` means \"no explicit cap\"\n— fall back to the legacy 50%-of-host heuristic for backwards\ncompatibility with operators who never visit the settings page.", + "properties": { + "cpu_limit_cores": { + "default": 0, + "description": "CPU cores allowed per build (float, e.g. 2.0 = 2 cores, 0.5 = half\na core). 0 means \"use the legacy 50%-of-host default\".", + "example": 2, + "format": "float", + "minimum": 0, + "type": "number" + }, + "max_concurrent": { + "default": 2, + "description": "Maximum number of `docker build` operations allowed to run at the\nsame time on the control plane. Additional builds queue. Min 1.", + "example": 2, + "format": "int32", + "minimum": 1, + "type": "integer" + }, + "memory_limit_mb": { + "default": 0, + "description": "Memory allowed per build, in megabytes. 0 means \"use the legacy\n50%-of-host default\". Docker enforces this as a hard cap — builds\nthat exceed it OOM-kill.", + "example": 2048, + "format": "int32", + "minimum": 0, + "type": "integer" + } + }, + "type": "object" + }, + "CancelBackupResponse": { + "description": "Response body for cancel endpoints.", + "properties": { + "cancelled": { + "description": "Number of rows that were actually flipped to `failed`. `0` is a valid\nsuccess and means the backup was already terminal — the call is\nidempotent.", + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "cancelled" + ], + "type": "object" + }, + "CertStatusResponse": { + "description": "Current on-demand cert status for a single hostname (ADR-018 §5). Backs\n`GET /domains/by-host/{hostname}/cert-status`.", + "properties": { + "backoff_until": { + "description": "On-demand negative-cache deadline (epoch millis), when in backoff.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "hostname": { + "description": "SNI hostname.", + "type": "string" + }, + "last_attempt": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/OnDemandCertAttemptResponse", + "description": "The most recent on-demand issuance attempt for this hostname, if any." + } + ] + }, + "status": { + "description": "Current cert lifecycle status from the `domains` row, when one exists.", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "hostname" + ], + "type": "object" + }, + "ChallengeConfig": { + "description": "Challenge configuration (future feature)\nFor CAPTCHA, JS challenges, proof-of-work, etc.", + "properties": { + "challengeType": { + "description": "Challenge type: \"captcha\", \"js_challenge\", \"proof_of_work\"", + "type": "string" + }, + "difficulty": { + "description": "Challenge difficulty level (1-10)", + "format": "int32", + "minimum": 0, + "type": "integer" + }, + "protectedPaths": { + "description": "Paths that require challenges", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "challengeType", + "difficulty" + ], + "type": "object" + }, + "ChallengeError": { + "properties": { + "detail": { + "description": "Human-readable error description", + "type": "string" + }, + "status": { + "description": "HTTP status code", + "format": "int32", + "type": "integer" + }, + "type": { + "description": "Error type (e.g., \"urn:ietf:params:acme:error:unauthorized\")", + "type": "string" + } + }, + "required": [ + "type", + "detail", + "status" + ], + "type": "object" + }, + "ChallengeValidationStatus": { + "properties": { + "error": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/ChallengeError", + "description": "Error details if validation failed" + } + ] + }, + "status": { + "description": "Challenge status (e.g., \"pending\", \"valid\", \"invalid\")", + "type": "string" + }, + "token": { + "description": "Challenge token", + "type": "string" + }, + "type": { + "description": "Challenge type (e.g., \"dns-01\", \"http-01\")", + "type": "string" + }, + "url": { + "description": "Challenge validation URL", + "type": "string" + }, + "validated": { + "description": "When the challenge was validated (if successful)", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "type", + "url", + "status", + "token" + ], + "type": "object" + }, + "ChangePasswordRequest": { + "properties": { + "current_password": { + "example": "current_password_value", + "type": "string" + }, + "mfa_code": { + "description": "TOTP code (or recovery code). Required iff the user has MFA enabled.", + "example": "123456", + "type": [ + "string", + "null" + ] + }, + "new_password": { + "example": "new_password_value", + "type": "string" + }, + "revoke_other_sessions": { + "description": "When true, every session OTHER than the one making this request is\nrevoked. Defaults to false; the UI surfaces this as a checkbox.", + "type": "boolean" + } + }, + "required": [ + "current_password", + "new_password" + ], + "type": "object" + }, + "ChangeProjectSourceRequest": { + "description": "Change a project's source type to a Git-less type (docker_image /\nstatic_files / manual). Switching TO `git` is done via the Git settings\nendpoint (which also supplies the repository + provider connection).", + "properties": { + "source_type": { + "$ref": "#/components/schemas/SourceType" + } + }, + "required": [ + "source_type" + ], + "type": "object" + }, + "ChatCompletionChoice": { + "properties": { + "finish_reason": { + "type": [ + "string", + "null" + ] + }, + "index": { + "format": "int32", + "type": "integer" + }, + "message": { + "$ref": "#/components/schemas/ChatMessage" + } + }, + "required": [ + "index", + "message" + ], + "type": "object" + }, + "ChatCompletionRequest": { + "allOf": [ + { + "additionalProperties": {}, + "description": "Tolerates extra SDK fields (stream_options, logprobs, etc.)", + "propertyNames": { + "type": "string" + }, + "type": [ + "object", + "null" + ] + }, + { + "properties": { + "frequency_penalty": { + "format": "double", + "type": [ + "number", + "null" + ] + }, + "max_tokens": { + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "messages": { + "items": { + "$ref": "#/components/schemas/ChatMessage" + }, + "type": "array" + }, + "model": { + "type": "string" + }, + "n": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "presence_penalty": { + "format": "double", + "type": [ + "number", + "null" + ] + }, + "response_format": {}, + "seed": { + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "stop": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/StopSequence" + } + ] + }, + "stream": { + "type": "boolean" + }, + "temperature": { + "format": "double", + "type": [ + "number", + "null" + ] + }, + "tool_choice": {}, + "tools": { + "items": {}, + "type": [ + "array", + "null" + ] + }, + "top_p": { + "format": "double", + "type": [ + "number", + "null" + ] + }, + "user": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "model", + "messages" + ], + "type": "object" + } + ], + "description": "OpenAI-compatible chat completion request.\nUses `deny_unknown_fields = false` (serde default) so that SDK-specific\nfields like `stream_options`, `logprobs`, `top_logprobs`, `logit_bias`,\n`parallel_tool_calls`, etc. are silently accepted without breaking." + }, + "ChatCompletionResponse": { + "properties": { + "choices": { + "items": { + "$ref": "#/components/schemas/ChatCompletionChoice" + }, + "type": "array" + }, + "created": { + "format": "int64", + "type": "integer" + }, + "id": { + "type": "string" + }, + "model": { + "type": "string" + }, + "object": { + "type": "string" + }, + "usage": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/UsageInfo" + } + ] + } + }, + "required": [ + "id", + "object", + "created", + "model", + "choices" + ], + "type": "object" + }, + "ChatMessage": { + "properties": { + "content": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/MessageContent" + } + ] + }, + "name": { + "type": [ + "string", + "null" + ] + }, + "role": { + "type": "string" + }, + "tool_call_id": { + "type": [ + "string", + "null" + ] + }, + "tool_calls": { + "items": {}, + "type": [ + "array", + "null" + ] + } + }, + "required": [ + "role" + ], + "type": "object" + }, + "ChatReadinessResponse": { + "description": "What still has to be true before an AI chat can run a turn in this project.\n\nThe three gates are independent and fail for different reasons with different\nfixes, so they are reported separately rather than collapsed into one boolean:\nan instance admin configures a provider (instance-wide), while the two toggles\nare per-project. Collapsing them would leave the user with \"AI unavailable\"\nand no idea which of three places to go.", + "properties": { + "ai_configured": { + "description": "An AI provider is configured on this instance. Fixed in\nSettings → AI Providers; instance-wide, not per project.", + "type": "boolean" + }, + "chat_enabled": { + "description": "The per-project read-only chat toggle is on (the default).", + "type": "boolean" + }, + "write_actions_enabled": { + "description": "The per-project write-actions opt-in is on. Required for any flow where\nthe assistant *proposes* changes; irrelevant for read-only questions.", + "type": "boolean" + } + }, + "required": [ + "ai_configured", + "chat_enabled", + "write_actions_enabled" + ], + "type": "object" + }, + "ChildBackupEntryResponse": { + "description": "A single child backup entry in the `GET /backups/{id}/children` response.\n\nEach entry corresponds to one `external_service_backups` row joined with\n`external_services`, providing service metadata without a second request.", + "properties": { + "backup_type": { + "description": "Backup variant (e.g. \"full\", \"incremental\").", + "type": "string" + }, + "compression_type": { + "description": "Compression algorithm used (e.g. \"gzip\", \"lz4\").", + "type": "string" + }, + "error_message": { + "description": "Engine-reported error message when `state = \"failed\"`.", + "type": [ + "string", + "null" + ] + }, + "finished_at": { + "description": "When the child backup finished, if known.", + "example": "2025-01-15T14:35:00.456Z", + "type": [ + "string", + "null" + ] + }, + "id": { + "description": "Row ID from `external_service_backups`.", + "format": "int32", + "type": "integer" + }, + "s3_location": { + "description": "Object key or `s3://` URL where the backup data lives.", + "type": "string" + }, + "service_id": { + "description": "FK to `external_services.id`.", + "format": "int32", + "type": "integer" + }, + "service_name": { + "description": "Human-readable name of the external service (e.g. \"redis-prod\").", + "type": "string" + }, + "service_type": { + "description": "Service type string (e.g. \"postgres\", \"redis\", \"mongodb\", \"s3\").", + "example": "postgres", + "type": "string" + }, + "size_bytes": { + "description": "Size of the child backup in bytes, if available.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "started_at": { + "description": "When the child backup started (RFC 3339).", + "example": "2025-01-15T14:30:00.123Z", + "type": "string" + }, + "state": { + "description": "Current state: \"pending\" | \"running\" | \"completed\" | \"failed\".", + "type": "string" + } + }, + "required": [ + "id", + "service_id", + "service_name", + "service_type", + "state", + "backup_type", + "started_at", + "s3_location", + "compression_type" + ], + "type": "object" + }, + "ChildBackupListResponse": { + "description": "Response body for `GET /backups/{id}/children`.\n\nReturns an empty `children` list (not 404) when the parent backup has no\nchild records (e.g. control-plane backups).", + "properties": { + "children": { + "description": "Zero or more child backup entries ordered by `external_service_backups.id` ASC.", + "items": { + "$ref": "#/components/schemas/ChildBackupEntryResponse" + }, + "type": "array" + } + }, + "required": [ + "children" + ], + "type": "object" + }, + "CleanupExpiredBackupsRequest": { + "properties": { + "expected_backup_ids": { + "description": "Exact candidates returned by the dry run. Execution fails if the\nretention selection has changed since preview.", + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + } + }, + "type": "object" + }, + "CliDeviceApproveRequest": { + "properties": { + "user_code": { + "type": "string" + } + }, + "required": [ + "user_code" + ], + "type": "object" + }, + "CliDeviceApproveResponse": { + "properties": { + "status": { + "type": "string" + }, + "user_code": { + "type": "string" + } + }, + "required": [ + "user_code", + "status" + ], + "type": "object" + }, + "CliDeviceLookupResponse": { + "properties": { + "client_name": { + "type": [ + "string", + "null" + ] + }, + "expires_at": { + "format": "date-time", + "type": "string" + }, + "requested_ip": { + "type": [ + "string", + "null" + ] + }, + "status": { + "description": "`pending` | `approved` | `denied` | `expired`.", + "type": "string" + }, + "user_code": { + "type": "string" + } + }, + "required": [ + "user_code", + "status", + "expires_at" + ], + "type": "object" + }, + "CliDevicePollRequest": { + "properties": { + "device_code": { + "type": "string" + } + }, + "required": [ + "device_code" + ], + "type": "object" + }, + "CliDevicePollResponse": { + "oneOf": [ + { + "description": "Still waiting on the user to approve in the browser.", + "properties": { + "status": { + "enum": [ + "authorization_pending" + ], + "type": "string" + } + }, + "required": [ + "status" + ], + "type": "object" + }, + { + "description": "CLI is polling faster than the server-suggested interval.", + "properties": { + "status": { + "enum": [ + "slow_down" + ], + "type": "string" + } + }, + "required": [ + "status" + ], + "type": "object" + }, + { + "description": "User denied the request in the browser.", + "properties": { + "status": { + "enum": [ + "access_denied" + ], + "type": "string" + } + }, + "required": [ + "status" + ], + "type": "object" + }, + { + "description": "The session has expired without approval.", + "properties": { + "status": { + "enum": [ + "expired_token" + ], + "type": "string" + } + }, + "required": [ + "status" + ], + "type": "object" + }, + { + "description": "The session was approved; this is the only response that carries\nthe API key. The key is returned exactly once and then cleared\nfrom the session row.", + "properties": { + "api_key": { + "type": "string" + }, + "email": { + "type": "string" + }, + "expires_at": { + "format": "date-time", + "type": [ + "string", + "null" + ] + }, + "key_prefix": { + "type": "string" + }, + "role": { + "type": "string" + }, + "status": { + "enum": [ + "approved" + ], + "type": "string" + }, + "user_id": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "user_id", + "email", + "role", + "api_key", + "key_prefix", + "status" + ], + "type": "object" + } + ] + }, + "CliDeviceStartRequest": { + "properties": { + "client_name": { + "description": "Friendly hostname / client identifier shown in the browser approval\nscreen. Sanitized before display.", + "example": "dviejo-mac.local", + "type": [ + "string", + "null" + ] + } + }, + "type": "object" + }, + "CliDeviceStartResponse": { + "properties": { + "device_code": { + "description": "Opaque secret the CLI polls with. Never display to a human.", + "type": "string" + }, + "expires_in": { + "description": "Seconds until the device_code expires.", + "format": "int64", + "type": "integer" + }, + "interval": { + "description": "Suggested polling interval, in seconds.", + "format": "int64", + "type": "integer" + }, + "user_code": { + "description": "Short human-readable code the user types into the browser.", + "example": "ABCD-1234", + "type": "string" + }, + "verification_uri": { + "description": "Base verification URL — the CLI may display this when the\npre-filled URL is too long to be useful.", + "example": "https://temps.example.com/cli-login", + "type": "string" + }, + "verification_uri_complete": { + "description": "`verification_uri` with `user_code` pre-filled. Open this directly.", + "example": "https://temps.example.com/cli-login/ABCD-1234", + "type": "string" + } + }, + "required": [ + "device_code", + "user_code", + "verification_uri", + "verification_uri_complete", + "expires_in", + "interval" + ], + "type": "object" + }, + "CliLoginRequest": { + "properties": { + "password": { + "type": "string" + }, + "username": { + "type": "string" + } + }, + "required": [ + "username", + "password" + ], + "type": "object" + }, + "CloudProvider": { + "description": "Cloud provider detected from node metadata", + "enum": [ + "aws", + "gcp", + "azure", + "hetzner", + "digitalocean", + "other" + ], + "type": "string" + }, + "CloudflareConfig": { + "description": "Configuration for a Cloudflare Email Sending notification provider.\n\nNotifications are delivered through Cloudflare's transactional Email Sending\nAPI. Only the account, token, sender and recipients are configured here —\nsubject and body are derived from each notification.", + "properties": { + "account_id": { + "description": "Cloudflare account id that owns the Email Sending configuration.", + "example": "023e105f4ecef8ad9ca31a8372d0c353", + "type": "string" + }, + "api_token": { + "description": "Cloudflare API token with the Email Sending permission. Encrypted at\nrest and masked in normal API responses.", + "type": "string" + }, + "from_address": { + "description": "Verified sender address (must belong to a domain enabled for Cloudflare\nEmail Sending).", + "example": "welcome@infracf.example.com", + "type": "string" + }, + "from_name": { + "description": "Optional human-friendly sender name shown in the recipient's inbox.", + "type": [ + "string", + "null" + ] + }, + "to_addresses": { + "description": "Recipients that should receive the notification.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "account_id", + "api_token", + "from_address", + "to_addresses" + ], + "type": "object" + }, + "ClusterCapacity": { + "description": "Total cluster capacity (sum of node allocatable resources)", + "properties": { + "cpu_millis": { + "description": "Total allocatable CPU in millicores", + "format": "int64", + "type": "integer" + }, + "memory_mb": { + "description": "Total allocatable memory in MB", + "format": "int64", + "type": "integer" + }, + "node_count": { + "description": "Number of nodes", + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "node_count", + "cpu_millis", + "memory_mb" + ], + "type": "object" + }, + "ClusterDnsSettings": { + "description": "Cluster-DNS resolver settings (ADR-024, experimental beta).\n\nWhen `enabled`, the Temps control plane starts a Hickory DNS resolver and\ninjects it as the first nameserver into every deployed container via\n`HostConfig.Dns` — giving containers the ability to resolve `*.temps.local`\nFQDNs for service-to-service communication. Worker nodes pick this flag up\nfrom the `/api/internal/nodes/{id}/network/peers` wire response and gate\ntheir own per-node resolver the same way.\n\n**Default: `false` (disabled).**\n\nWhy disabled by default: a production incident showed that when the injected\nHickory resolver was slow or transiently unresponsive for a non-`*.temps.local`\n(external) hostname, glibc's resolver cycled through all three nameservers\n(`172.20.0.1`, `1.1.1.1`, `8.8.8.8`) at ~5 s timeout × 2 attempts each,\ncausing 22–27 s delays for outbound TCP connections. Disabling the injection\nrestores Docker's embedded DNS as the sole resolver, eliminating that failure\nmode. Operators running single/multi-node installs that depend on\n`*.temps.local` resolution must explicitly opt in by setting `enabled: true`.\n\n`bool` defaults to `false` in Rust and JSON (`#[serde(default)]`), so the\nsafe-off behaviour is automatic for new installs and legacy settings rows.", + "properties": { + "enabled": { + "default": false, + "description": "Master switch. When `false` (default), no custom DNS is injected into\ncontainers — they use Docker's embedded DNS which forwards to the host's\nown `resolv.conf`. When `true`, the control-plane Hickory resolver is\nstarted and its bridge IP is injected as the first nameserver so\n`*.temps.local` FQDNs resolve inside containers.", + "example": false, + "type": "boolean" + } + }, + "type": "object" + }, + "ClusterHealthReportResponse": { + "description": "Response body for `GET /external-services/{id}/cluster-health`.", + "properties": { + "checked_at": { + "description": "ISO-8601 wall-clock when the report was generated.", + "example": "2025-10-12T12:15:47.609192Z", + "type": "string" + }, + "members": { + "items": { + "$ref": "#/components/schemas/ClusterMemberHealthResponse" + }, + "type": "array" + }, + "monitor_error": { + "description": "Set when the monitor itself was unreachable. UI shows a banner.", + "type": [ + "string", + "null" + ] + }, + "monitor_response_ms": { + "description": "Round-trip to query the monitor (ms).", + "format": "int64", + "type": "integer" + } + }, + "required": [ + "checked_at", + "monitor_response_ms", + "members" + ], + "type": "object" + }, + "ClusterMemberHealthResponse": { + "description": "One row in the cluster Members table — see `GET /external-services/{id}/cluster-health`.", + "properties": { + "candidate_priority": { + "format": "int32", + "type": "integer" + }, + "goal_state": { + "description": "What the monitor *wants* the node to be. Differs from\n`reported_state` mid-transition (failover, demotion, etc.).", + "type": "string" + }, + "health": { + "description": "pg_auto_failover liveness signal: `1` healthy, `0` unknown\n(no recent report), `-1` unhealthy.", + "format": "int32", + "type": "integer" + }, + "nodehost": { + "type": "string" + }, + "nodename": { + "type": "string" + }, + "nodeport": { + "format": "int32", + "type": "integer" + }, + "replay_lag_ms": { + "description": "`replay_lag` from `pg_stat_replication`, in milliseconds.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "replication_quorum": { + "type": "boolean" + }, + "reported_state": { + "description": "What the node *last told the monitor* it was. Stale during outages.", + "type": "string" + }, + "seconds_since_report": { + "description": "Wall-clock seconds since the node last reported in.", + "format": "int64", + "type": "integer" + }, + "sync_state": { + "description": "`sync` / `quorum` / `async` for secondaries; `null` for the primary.", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "nodename", + "nodehost", + "nodeport", + "reported_state", + "goal_state", + "health", + "seconds_since_report", + "candidate_priority", + "replication_quorum" + ], + "type": "object" + }, + "ClusterMemberRequest": { + "description": "Request spec for a single cluster member.", + "properties": { + "node_id": { + "description": "Target worker node ID. Omit or null to run on the control plane.", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "role": { + "description": "Service-type-specific role (e.g., \"monitor\", \"primary\", \"replica\")", + "example": "primary", + "type": "string" + } + }, + "required": [ + "role" + ], + "type": "object" + }, + "CmdBody": { + "properties": { + "args": { + "description": "Arguments to pass to the binary. Defaults to empty.", + "items": { + "type": "string" + }, + "type": "array" + }, + "command": { + "description": "Binary name (argv[0]) — e.g. `\"ls\"`, `\"node\"`. The SDK sends this\nseparately from `args`.", + "type": "string" + }, + "cwd": { + "description": "Working directory override.", + "type": [ + "string", + "null" + ] + }, + "env": { + "additionalProperties": { + "type": "string" + }, + "description": "Extra env vars.", + "propertyNames": { + "type": "string" + }, + "type": "object" + }, + "sudo": { + "description": "When true, the SDK runs the command privileged. We ignore it today\n— the underlying provider always runs as the sandbox's own user.", + "type": "boolean" + }, + "wait": { + "description": "When true, the response is an `application/x-ndjson` stream where\nthe first line is the running-command envelope and the second line\nis the finished-command envelope with `exitCode`.", + "type": "boolean" + } + }, + "required": [ + "command" + ], + "type": "object" + }, + "CmdInner": { + "description": "Inner `command` object — matches the SDK's zod validator exactly.\n`exitCode` is `null` until the command terminates; `startedAt` is Unix\nepoch milliseconds.", + "properties": { + "args": { + "items": { + "type": "string" + }, + "type": "array" + }, + "cwd": { + "type": "string" + }, + "exitCode": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "sandboxId": { + "type": "string" + }, + "startedAt": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "id", + "name", + "args", + "cwd", + "sandboxId", + "startedAt" + ], + "type": "object" + }, + "CmdKillBody": { + "description": "SDK-shaped kill body. The SDK sends `{signal: AbortSignal}` but only\nuses the signal for HTTP request abortion client-side; there's no\nsignal name on the wire.", + "properties": { + "force": { + "description": "Optional: when true, SIGKILL instead of SIGTERM.", + "type": "boolean" + } + }, + "type": "object" + }, + "CmdResponse": { + "description": "`@vercel/sandbox` envelope: `{ command: {...} }`.", + "properties": { + "command": { + "$ref": "#/components/schemas/CmdInner" + } + }, + "required": [ + "command" + ], + "type": "object" + }, + "CommitExistsResponse": { + "properties": { + "commit": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/CommitInfo", + "description": "Commit metadata when the requested SHA exists." + } + ] + }, + "commit_sha": { + "type": [ + "string", + "null" + ] + }, + "exists": { + "type": "boolean" + } + }, + "required": [ + "exists" + ], + "type": "object" + }, + "CommitInfo": { + "properties": { + "author": { + "description": "Author name", + "type": "string" + }, + "author_email": { + "description": "Author email", + "type": "string" + }, + "date": { + "description": "Commit date in ISO 8601 format", + "example": "2025-10-12T12:15:47.609192Z", + "format": "date-time", + "type": "string" + }, + "message": { + "description": "Commit message", + "type": "string" + }, + "sha": { + "description": "Commit SHA hash", + "type": "string" + } + }, + "required": [ + "sha", + "message", + "author", + "author_email", + "date" + ], + "type": "object" + }, + "CommitListResponse": { + "properties": { + "commits": { + "items": { + "$ref": "#/components/schemas/CommitInfo" + }, + "type": "array" + } + }, + "required": [ + "commits" + ], + "type": "object" + }, + "Comparator": { + "description": "Comparator for static/forecast threshold detectors. Serializes to the\nkeyword forms `gt|gte|lt|lte` (NOT the SQL operators used by\n`temps-monitoring::compare`).", + "enum": [ + "gt", + "gte", + "lt", + "lte" + ], + "type": "string" + }, + "ComposePublicPort": { + "description": "A port that should be exposed publicly through the proxy for a compose service.", + "properties": { + "port": { + "description": "Container port to expose (e.g. 8123)", + "format": "int32", + "minimum": 0, + "type": "integer" + }, + "service": { + "description": "Compose service name (e.g. \"web\", \"clickhouse\")", + "type": "string" + } + }, + "required": [ + "service", + "port" + ], + "type": "object" + }, + "ConnectionListQuery": { + "properties": { + "direction": { + "type": [ + "string", + "null" + ] + }, + "page": { + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "per_page": { + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "sort": { + "type": [ + "string", + "null" + ] + } + }, + "type": "object" + }, + "ConnectionListResponse": { + "properties": { + "connections": { + "items": { + "$ref": "#/components/schemas/ConnectionResponse" + }, + "type": "array" + }, + "page": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "per_page": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "total_count": { + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "connections", + "total_count", + "page", + "per_page" + ], + "type": "object" + }, + "ConnectionResponse": { + "properties": { + "account_name": { + "type": "string" + }, + "account_type": { + "type": "string" + }, + "consecutive_health_failures": { + "format": "int32", + "type": "integer" + }, + "created_at": { + "format": "date-time", + "type": "string" + }, + "health_message": { + "description": "Human-readable reason when health_status is \"unhealthy\"; null otherwise.", + "type": [ + "string", + "null" + ] + }, + "health_status": { + "description": "Current health status: \"healthy\", \"unhealthy\", or \"unknown\".", + "type": "string" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "installation_id": { + "type": [ + "string", + "null" + ] + }, + "is_active": { + "type": "boolean" + }, + "is_expired": { + "type": "boolean" + }, + "last_health_check_at": { + "format": "date-time", + "type": [ + "string", + "null" + ] + }, + "last_synced_at": { + "format": "date-time", + "type": [ + "string", + "null" + ] + }, + "provider_id": { + "format": "int32", + "type": "integer" + }, + "synced_repository_count": { + "description": "Running count of repositories persisted by the current (or most\nrecent) sync. Resets to 0 when a new sync begins; useful for showing\nlive progress on large syncs.", + "format": "int32", + "type": "integer" + }, + "syncing": { + "type": "boolean" + }, + "updated_at": { + "format": "date-time", + "type": "string" + }, + "user_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + "required": [ + "id", + "provider_id", + "account_name", + "account_type", + "is_active", + "is_expired", + "syncing", + "synced_repository_count", + "health_status", + "consecutive_health_failures", + "created_at", + "updated_at" + ], + "type": "object" + }, + "ConnectionTestResult": { + "description": "Connection test result", + "properties": { + "message": { + "type": "string" + }, + "success": { + "type": "boolean" + } + }, + "required": [ + "success", + "message" + ], + "type": "object" + }, + "ConsoleEventPayload": { + "description": "Payload for server-side event ingestion via the console API.\n\nThe app backend reads the encrypted `_temps_visitor_id` and `_temps_sid`\ncookie values from the user's request and forwards them here.\nTemps decrypts them server-side to resolve visitor/session identity.", + "properties": { + "deployment_id": { + "description": "Deployment ID to attribute the event to", + "format": "int32", + "type": "integer" + }, + "environment_id": { + "description": "Environment ID to attribute the event to", + "format": "int32", + "type": "integer" + }, + "event_data": { + "description": "Arbitrary JSON event data" + }, + "event_name": { + "description": "Event name (e.g. \"purchase\", \"signup\", custom event names)", + "type": "string" + }, + "request_path": { + "description": "Page path context (defaults to \"/\")", + "type": "string" + }, + "request_query": { + "description": "Query string context", + "type": "string" + }, + "session_id": { + "description": "Encrypted `_temps_sid` cookie value from the user's browser", + "type": [ + "string", + "null" + ] + }, + "visitor_id": { + "description": "Encrypted `_temps_visitor_id` cookie value from the user's browser", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "event_name", + "environment_id", + "deployment_id" + ], + "type": "object" + }, + "ContainerActionResponse": { + "description": "Response indicating success of container state change", + "properties": { + "action": { + "type": "string" + }, + "container_id": { + "type": "string" + }, + "container_name": { + "type": "string" + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + }, + "required": [ + "container_id", + "container_name", + "action", + "status", + "message" + ], + "type": "object" + }, + "ContainerDetailResponse": { + "description": "Detailed container information with environment variables and metrics", + "properties": { + "container_id": { + "type": "string" + }, + "container_name": { + "type": "string" + }, + "container_port": { + "description": "Port inside the container", + "format": "int32", + "type": "integer" + }, + "cpu_limit_cores": { + "description": "CPU limit in whole cores (e.g. 1.0). None when no limit is configured.", + "format": "double", + "type": [ + "number", + "null" + ] + }, + "created_at": { + "example": "2025-10-12T12:15:47.609192Z", + "type": "string" + }, + "deployed_at": { + "example": "2025-10-12T12:15:47.609192Z", + "type": "string" + }, + "deployment_id": { + "format": "int32", + "type": "integer" + }, + "environment_variables": { + "description": "Environment variables (sensitive values masked)", + "items": { + "$ref": "#/components/schemas/EnvVarResponse" + }, + "type": "array" + }, + "error_message": { + "description": "Free-form error string from Docker's container state on exit.", + "type": [ + "string", + "null" + ] + }, + "exit_code": { + "description": "Process exit code reported by Docker. None while still running.", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "exit_reason": { + "description": "Human-readable reason the container exited.", + "type": [ + "string", + "null" + ] + }, + "finished_at": { + "description": "When the container exited (Docker's FinishedAt). None while running.", + "example": "2025-10-12T12:16:47.609192Z", + "type": [ + "string", + "null" + ] + }, + "host_port": { + "description": "Port on the host machine", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "id": { + "format": "int32", + "type": "integer" + }, + "image_name": { + "type": "string" + }, + "oom_killed": { + "description": "True when Docker's OOM killer terminated the container.", + "type": [ + "boolean", + "null" + ] + }, + "ready_at": { + "example": "2025-10-12T12:16:47.609192Z", + "type": [ + "string", + "null" + ] + }, + "resource_limits": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/ResourceLimitsResponse", + "description": "Resource limits" + } + ] + }, + "restart_count": { + "description": "Container restart count from Docker", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "service_name": { + "description": "Compose service name (e.g. \"web\", \"redis\"). None for single-container deployments.", + "type": [ + "string", + "null" + ] + }, + "service_url": { + "description": "Per-service URL for compose deployments", + "type": [ + "string", + "null" + ] + }, + "started_at": { + "description": "When the container's main process most recently started.", + "example": "2025-10-12T12:15:50.000000Z", + "type": [ + "string", + "null" + ] + }, + "status": { + "type": "string" + } + }, + "required": [ + "id", + "container_id", + "container_name", + "image_name", + "status", + "deployment_id", + "created_at", + "deployed_at", + "container_port", + "environment_variables" + ], + "type": "object" + }, + "ContainerEnvironmentVariableValueResponse": { + "properties": { + "value": { + "type": "string" + } + }, + "required": [ + "value" + ], + "type": "object" + }, + "ContainerInfoResponse": { + "properties": { + "container_id": { + "type": "string" + }, + "container_name": { + "type": "string" + }, + "cpu_limit_cores": { + "description": "CPU limit in whole cores (e.g. 1.0). None when no limit is configured.", + "format": "double", + "type": [ + "number", + "null" + ] + }, + "created_at": { + "example": "2025-10-12T12:15:47.609192Z", + "type": "string" + }, + "error_message": { + "description": "Free-form error string from Docker's container state on exit.", + "type": [ + "string", + "null" + ] + }, + "exit_code": { + "description": "Process exit code reported by Docker. None while still running.", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "exit_reason": { + "description": "Human-readable reason the container exited (e.g. \"OOMKilled\",\n\"Killed by SIGKILL (exit code 137)\", \"Exit code 1\"). None while running.", + "type": [ + "string", + "null" + ] + }, + "finished_at": { + "description": "When the container exited (Docker's FinishedAt). None while running.", + "example": "2025-10-12T12:16:47.609192Z", + "type": [ + "string", + "null" + ] + }, + "image_name": { + "type": "string" + }, + "node_name": { + "description": "Node name where this container is running. None for local (single-node) deployments.", + "type": [ + "string", + "null" + ] + }, + "oom_killed": { + "description": "True when Docker's OOM killer terminated the container.", + "type": [ + "boolean", + "null" + ] + }, + "restart_count": { + "description": "Container restart count from Docker. The UI shows a chip when this is\n> 0 so a crash loop is visible without opening detail.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "service_name": { + "description": "Compose service name (e.g. \"web\", \"redis\"). None for single-container deployments.", + "type": [ + "string", + "null" + ] + }, + "service_url": { + "description": "Per-service URL for compose deployments (e.g. \"https://web-myapp.localho.st\")", + "type": [ + "string", + "null" + ] + }, + "started_at": { + "description": "When the container's main process most recently started. The UI uses\nthis for the uptime label so the count resets when a container is\nrestarted in place. None for containers that never started.", + "example": "2025-10-12T12:15:50.000000Z", + "type": [ + "string", + "null" + ] + }, + "status": { + "type": "string" + } + }, + "required": [ + "container_id", + "container_name", + "image_name", + "status", + "created_at" + ], + "type": "object" + }, + "ContainerInventoryItem": { + "description": "A container reported by the agent during heartbeat reconciliation.", + "properties": { + "container_id": { + "description": "Docker container ID", + "type": "string" + }, + "container_name": { + "description": "Docker container name", + "type": "string" + } + }, + "required": [ + "container_id", + "container_name" + ], + "type": "object" + }, + "ContainerListResponse": { + "properties": { + "containers": { + "items": { + "$ref": "#/components/schemas/ContainerInfoResponse" + }, + "type": "array" + }, + "total": { + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "containers", + "total" + ], + "type": "object" + }, + "ContainerLogSettings": { + "description": "Docker container log rotation settings\nControls the `--log-opt max-size` and `--log-opt max-file` for containers", + "properties": { + "max_file": { + "default": 3, + "description": "Maximum number of rotated log files to keep (e.g., 3 means up to 3 x max_size total)", + "example": 3, + "format": "int32", + "minimum": 0, + "type": "integer" + }, + "max_size": { + "default": "50m", + "description": "Maximum size of each log file (e.g., \"50m\", \"100m\", \"1g\")\nDocker default is unlimited; we default to \"50m\" to prevent disk exhaustion", + "example": "50m", + "type": "string" + }, + "service_max_file": { + "default": 3, + "description": "Maximum rotated log files for external service containers", + "example": 3, + "format": "int32", + "minimum": 0, + "type": "integer" + }, + "service_max_size": { + "default": "20m", + "description": "Maximum size for external service container logs (postgres, redis, etc.)\nDefaults to \"20m\" since services are typically less verbose than app containers", + "example": "20m", + "type": "string" + } + }, + "type": "object" + }, + "ContainerLogsQuery": { + "properties": { + "container_name": { + "description": "Optional container name to get logs from (if deployment has multiple containers)", + "type": [ + "string", + "null" + ] + }, + "end_date": { + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "follow": { + "description": "Follow log output in real-time (default: true for backward compatibility)", + "type": "boolean" + }, + "start_date": { + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "tail": { + "type": [ + "string", + "null" + ] + }, + "timestamps": { + "description": "Include timestamps in log output (default: false)", + "type": "boolean" + } + }, + "type": "object" + }, + "ContainerMetricHistoryPoint": { + "description": "One bucketed data point of a container resource metric time series.", + "properties": { + "time": { + "description": "Bucket timestamp (ISO 8601 with `Z` suffix).", + "example": "2025-10-12T12:15:00+00:00", + "type": "string" + }, + "value": { + "description": "Averaged metric value for the bucket.", + "format": "double", + "type": "number" + } + }, + "required": [ + "time", + "value" + ], + "type": "object" + }, + "ContainerMetricsHistoryQuery": { + "description": "Query parameters for the container metrics history endpoint.", + "properties": { + "metric": { + "description": "Dotted metric name, e.g. `container.cpu_percent` or\n`container.memory_used_bytes`.", + "type": "string" + }, + "range": { + "description": "Time window: `1h`, `6h`, `24h`, or `7d` (defaults to `1h`).", + "type": "string" + } + }, + "required": [ + "metric" + ], + "type": "object" + }, + "ContainerMetricsResponse": { + "description": "Container resource metrics (CPU, memory usage)", + "properties": { + "container_id": { + "type": "string" + }, + "container_name": { + "type": "string" + }, + "cpu_limit_cores": { + "description": "CPU limit in whole cores (e.g. 1.0). None = no limit.", + "format": "double", + "type": [ + "number", + "null" + ] + }, + "cpu_percent": { + "description": "CPU usage as a multi-core percentage (Docker convention: 200 = 2 cores\nfully pinned). Divide by 100 to get cores used.", + "format": "double", + "type": "number" + }, + "memory_bytes": { + "description": "Memory usage in bytes", + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "memory_limit_bytes": { + "description": "Memory limit in bytes (if set)", + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "memory_percent": { + "description": "Memory usage percentage (0-100) if limit is set", + "format": "double", + "type": [ + "number", + "null" + ] + }, + "network_rx_bytes": { + "description": "Network bytes received", + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "network_tx_bytes": { + "description": "Network bytes transmitted", + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "timestamp": { + "description": "Timestamp of metrics collection", + "example": "2025-10-12T12:15:47.609192Z", + "type": "string" + } + }, + "required": [ + "container_id", + "container_name", + "cpu_percent", + "memory_bytes", + "network_rx_bytes", + "network_tx_bytes", + "timestamp" + ], + "type": "object" + }, + "ContainerResponse": { + "properties": { + "can_contain_containers": { + "description": "Can this container hold other containers?", + "example": true, + "type": "boolean" + }, + "can_contain_entities": { + "description": "Can this container hold entities (tables, collections, etc.)?", + "example": false, + "type": "boolean" + }, + "child_container_type": { + "description": "Type of child containers (if can_contain_containers is true)", + "example": "schema", + "type": [ + "string", + "null" + ] + }, + "container_type": { + "description": "Container type (database, schema, keyspace, bucket, etc.)", + "example": "database", + "type": "string" + }, + "entity_count_hint": { + "description": "Hint for UI on expected entity count (small = sidebar, large = pagination)", + "example": "large", + "type": [ + "string", + "null" + ] + }, + "entity_type_label": { + "description": "Label for entity type (if can_contain_entities is true)", + "example": "table", + "type": [ + "string", + "null" + ] + }, + "metadata": { + "description": "Additional metadata" + }, + "name": { + "description": "Container name", + "example": "mydb", + "type": "string" + } + }, + "required": [ + "name", + "container_type", + "can_contain_containers", + "can_contain_entities", + "metadata" + ], + "type": "object" + }, + "ContainerRuntimeInfo": { + "description": "Snapshot of a container's lifecycle state from `docker inspect`.\n`restart_count` and `oom_killed` are the load-bearing fields when\ndiagnosing crash loops — the kernel OOM killer never reaches the\napplication's logs, so seeing `oom_killed=true` is the only signal\nthat a memory limit was the cause.", + "properties": { + "container_id": { + "description": "Container Docker id, when present. None = container does not exist\n(was never created or was removed externally).", + "type": [ + "string", + "null" + ] + }, + "container_name": { + "description": "Stable name of the Docker container (e.g. `postgres-mydb`).", + "type": "string" + }, + "exit_code": { + "description": "Last container exit code, when known. Non-zero = unclean stop.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "finished_at": { + "description": "ISO-8601 timestamp of the most recent termination, when known.", + "type": [ + "string", + "null" + ] + }, + "image": { + "description": "Currently-effective Docker image (e.g. `gotempsh/postgres-walg:18-bookworm`).", + "type": [ + "string", + "null" + ] + }, + "oom_killed": { + "description": "True when the container's last termination was caused by the\nkernel OOM killer. Set if the user enabled hard memory limits\nand the working set exceeded them.", + "type": [ + "boolean", + "null" + ] + }, + "resource_limits": { + "$ref": "#/components/schemas/ServiceResourceLimits", + "description": "Currently-applied resource limits read off the container's\n`HostConfig`. Compare this against the user-configured limits to\ndetect drift (an old container that never picked up new caps)." + }, + "restart_count": { + "description": "Total restarts since the container was created. Useful for\ndetecting crash loops — a steady stream means something is killing\nthe container repeatedly (frequently OOM).", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "role": { + "description": "`service_members.role` for cluster members; \"standalone\" otherwise.", + "type": "string" + }, + "started_at": { + "description": "ISO-8601 timestamp of when the container last started. None when\nit has never started (i.e. created but never run).", + "type": [ + "string", + "null" + ] + }, + "status": { + "description": "Bollard container state (\"running\", \"exited\", \"dead\", etc.). None\nwhen the container does not exist.", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "role", + "container_name", + "resource_limits" + ], + "type": "object" + }, + "ContainerStatsSample": { + "description": "Live resource usage sample for a single container.\n\n`cpu_percent` is computed by Docker's standard formula:\n ((cpu_delta / system_delta) * online_cpus) * 100\n`memory_percent` is `(memory_usage / memory_limit) * 100` — when no\nmemory limit is set the limit reported by Docker is the host's total\nRAM, so a 5% reading means \"5% of host RAM\", not \"5% of allocated\".", + "properties": { + "container_name": { + "type": "string" + }, + "cpu_percent": { + "description": "CPU usage as a percentage. `None` when the container is not running\n(Docker returns no usable counters).", + "format": "double", + "type": [ + "number", + "null" + ] + }, + "memory_limit_bytes": { + "description": "Memory limit in bytes (host RAM if no limit set).", + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "memory_percent": { + "description": "Memory usage as a percentage of `memory_limit_bytes`.", + "format": "double", + "type": [ + "number", + "null" + ] + }, + "memory_usage_bytes": { + "description": "Resident memory usage in bytes.", + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "online_cpus": { + "description": "Number of cores Docker observed at sample time. Used by the UI\nto label \"x/y cores\" instead of just a percent.", + "format": "int32", + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "role": { + "type": "string" + } + }, + "required": [ + "role", + "container_name" + ], + "type": "object" + }, + "ContentPart": { + "properties": { + "image_url": {}, + "text": { + "type": [ + "string", + "null" + ] + }, + "type": { + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + }, + "ContextLine": { + "description": "A line in context response", + "properties": { + "fields": {}, + "is_match": { + "description": "Whether this line matched the original search", + "type": "boolean" + }, + "level": { + "$ref": "#/components/schemas/LogLevel" + }, + "line_offset": { + "format": "int32", + "type": "integer" + }, + "message": { + "type": "string" + }, + "timestamp": { + "type": "string" + } + }, + "required": [ + "timestamp", + "level", + "message", + "line_offset", + "is_match" + ], + "type": "object" + }, + "ContextLogsRequest": { + "properties": { + "chunk_id": { + "type": "string" + }, + "line_offset": { + "format": "int32", + "type": "integer" + }, + "lines": { + "description": "Number of context lines before and after (default: 25)", + "format": "int32", + "minimum": 0, + "type": [ + "integer", + "null" + ] + } + }, + "required": [ + "chunk_id", + "line_offset" + ], + "type": "object" + }, + "ContextLogsResponse": { + "properties": { + "lines": { + "items": { + "$ref": "#/components/schemas/ContextLine" + }, + "type": "array" + }, + "target_index": { + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "lines", + "target_index" + ], + "type": "object" + }, + "ConversationDetailResponse": { + "allOf": [ + { + "$ref": "#/components/schemas/ConversationResponse" + }, + { + "properties": { + "messages": { + "description": "Turns oldest-first. The `system` seed message is omitted (internal).", + "items": { + "$ref": "#/components/schemas/MessageResponse" + }, + "type": "array" + } + }, + "required": [ + "messages" + ], + "type": "object" + } + ] + }, + "ConversationResponse": { + "properties": { + "context_id": { + "type": "string" + }, + "context_type": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "last_activity_at": { + "type": "string" + }, + "public_id": { + "type": "string" + }, + "status": { + "type": "string" + }, + "title": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "public_id", + "context_type", + "context_id", + "status", + "created_at", + "last_activity_at" + ], + "type": "object" + }, + "ConversationSummary": { + "description": "A conversation summary grouping related AI invocations.", + "properties": { + "avg_latency_ms": { + "format": "double", + "type": "number" + }, + "conversation_id": { + "type": "string" + }, + "first_at": { + "type": "string" + }, + "last_at": { + "type": "string" + }, + "message_count": { + "format": "int64", + "type": "integer" + }, + "models_used": { + "items": { + "type": "string" + }, + "type": "array" + }, + "total_cost_microcents": { + "format": "int64", + "type": "integer" + }, + "total_input_tokens": { + "format": "int64", + "type": "integer" + }, + "total_output_tokens": { + "format": "int64", + "type": "integer" + }, + "total_tokens": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "conversation_id", + "message_count", + "total_input_tokens", + "total_output_tokens", + "total_tokens", + "total_cost_microcents", + "avg_latency_ms", + "models_used", + "first_at", + "last_at" + ], + "type": "object" + }, + "ConversationsQueryParams": { + "properties": { + "from": { + "description": "ISO 8601 start time (defaults to 24h ago)", + "type": [ + "string", + "null" + ] + }, + "limit": { + "description": "Max results (defaults to 50, max 100)", + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "model": { + "description": "Filter by model name", + "type": [ + "string", + "null" + ] + }, + "tags": { + "description": "Filter by tags (comma-separated, AND logic)", + "type": [ + "string", + "null" + ] + }, + "to": { + "description": "ISO 8601 end time (defaults to now)", + "type": [ + "string", + "null" + ] + }, + "user_id": { + "description": "Filter by user ID", + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + "type": "object" + }, + "CopyBlobRequest": { + "description": "Request to copy a blob", + "properties": { + "fromUrl": { + "description": "Source blob URL or pathname", + "example": "/api/blob/10/images/avatar.png", + "type": "string" + }, + "projectId": { + "description": "Project ID (required for API key/session auth, optional for deployment tokens)", + "example": 1, + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "toPathname": { + "description": "Destination pathname", + "example": "images/avatar-copy.png", + "type": "string" + } + }, + "required": [ + "fromUrl", + "toPathname" + ], + "type": "object" + }, + "CostAnalysis": { + "description": "Full cluster cost + rightsizing analysis attached to an import plan.", + "properties": { + "actual_usage": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/ResourceFootprint", + "description": "Measured usage from the metrics API (`metrics.k8s.io`).\n`None` when metrics-server is not installed." + } + ] + }, + "capacity": { + "$ref": "#/components/schemas/ClusterCapacity", + "description": "Total cluster capacity (sum of node allocatable resources)" + }, + "control_plane_monthly_usd": { + "description": "Managed control-plane fee included in `current_monthly_usd` (EKS/GKE\ncharge ~$73/mo per cluster). `None` when not applicable/unknown.", + "format": "double", + "type": [ + "number", + "null" + ] + }, + "current_monthly_usd": { + "description": "Estimated total infrastructure cost per month in USD (compute nodes +\ncontrol-plane fee). `None` when no node could be priced.", + "format": "double", + "type": [ + "number", + "null" + ] + }, + "nodes": { + "description": "Per-node inventory with price estimates where the instance type is known", + "items": { + "$ref": "#/components/schemas/NodeCostInfo" + }, + "type": "array" + }, + "notes": { + "description": "Honesty notes: what could not be measured, which numbers are\nestimates, and any assumptions made. Always shown to the user.", + "items": { + "type": "string" + }, + "type": "array" + }, + "overprovisioning": { + "$ref": "#/components/schemas/OverprovisioningAssessment", + "description": "Requests-vs-capacity-vs-usage assessment" + }, + "provider": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/CloudProvider", + "description": "Detected cloud provider (from node `providerID` prefixes)" + } + ] + }, + "recommendation": { + "$ref": "#/components/schemas/TargetRecommendation", + "description": "The temps/Hetzner target sizing and savings estimate" + }, + "requested": { + "$ref": "#/components/schemas/ResourceFootprint", + "description": "Sum of pod resource *requests* across running pods — what the\nscheduler has reserved, i.e. what the cluster is sized for." + }, + "usage_source": { + "$ref": "#/components/schemas/UsageSource", + "description": "How the usage numbers were obtained (drives UI wording)" + } + }, + "required": [ + "nodes", + "capacity", + "requested", + "usage_source", + "overprovisioning", + "recommendation", + "notes" + ], + "type": "object" + }, + "CreateAlertRuleRequest": { + "properties": { + "cooldown_minutes": { + "description": "Minimum minutes between notifications for same rule+group", + "format": "int32", + "type": "integer" + }, + "enabled": { + "type": "boolean" + }, + "environment_filter": { + "description": "Optional environment ID to filter alerts", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "error_level_filter": { + "description": "Optional error type/level filter", + "type": [ + "string", + "null" + ] + }, + "name": { + "type": "string" + }, + "notification_priority": { + "description": "Notification priority: Low, Normal, High, Critical", + "type": "string" + }, + "trigger_config": { + "description": "Trigger-specific configuration (e.g., {\"count\": 100, \"window_minutes\": 60} for frequency)" + }, + "trigger_type": { + "description": "Trigger type: new_issue, regression, frequency, new_user, user_count, status_change", + "type": "string" + } + }, + "required": [ + "name", + "trigger_type" + ], + "type": "object" + }, + "CreateApiKeyRequest": { + "properties": { + "expires_at": { + "example": "2024-12-31T23:59:59Z", + "format": "date-time", + "type": [ + "string", + "null" + ] + }, + "name": { + "type": "string" + }, + "permissions": { + "example": [ + "projects:read", + "deployments:read" + ], + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + }, + "role_type": { + "example": "admin", + "type": "string" + } + }, + "required": [ + "name", + "role_type" + ], + "type": "object" + }, + "CreateApiKeyResponse": { + "properties": { + "api_key": { + "type": "string" + }, + "created_at": { + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "expires_at": { + "example": "2024-12-31T23:59:59Z", + "format": "date-time", + "type": [ + "string", + "null" + ] + }, + "id": { + "format": "int32", + "type": "integer" + }, + "key_prefix": { + "type": "string" + }, + "name": { + "type": "string" + }, + "permissions": { + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + }, + "role_type": { + "type": "string" + } + }, + "required": [ + "id", + "name", + "key_prefix", + "role_type", + "api_key", + "created_at" + ], + "type": "object" + }, + "CreateBackupScheduleRequest": { + "properties": { + "backup_type": { + "type": "string" + }, + "description": { + "type": [ + "string", + "null" + ] + }, + "enabled": { + "type": "boolean" + }, + "include_control_plane": { + "description": "When `true` (default), every run also produces a `control_plane`\nbackup of Temps's own database. Operators who use Temps purely as\na backup orchestrator for external DBs can set this to `false` to\nkeep the run history focused on those services.", + "type": [ + "boolean", + "null" + ] + }, + "max_runtime_secs": { + "description": "Optional wall-clock timeout override for jobs created by this schedule\n(seconds). When set, overrides the engine-family default. `null` means\n\"use engine default.\" The per-job `max_runtime_secs` in\n`EnqueueJobParams` can still override this for ad-hoc triggers.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "name": { + "type": "string" + }, + "retention_period": { + "format": "int32", + "type": "integer" + }, + "s3_source_id": { + "description": "Optional S3 source. If omitted, the current default S3 source is used.", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "schedule_expression": { + "type": "string" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "target_all_services": { + "description": "When `true` (default), the schedule backs up every external service\non the host — including databases created in the future. When\n`false`, the schedule backs up only the services explicitly attached\nvia `POST /backups/schedules/{id}/services`. Omit to use the default.", + "type": [ + "boolean", + "null" + ] + } + }, + "required": [ + "name", + "backup_type", + "retention_period", + "schedule_expression", + "enabled", + "tags" + ], + "type": "object" + }, + "CreateBitbucketRequest": { + "properties": { + "auth": { + "$ref": "#/components/schemas/BitbucketAuthInput", + "description": "Authentication credentials — either an access token or an app password." + }, + "name": { + "description": "Display name for this provider.", + "type": "string" + } + }, + "required": [ + "name", + "auth" + ], + "type": "object" + }, + "CreateCloudflareProviderRequest": { + "properties": { + "config": { + "$ref": "#/components/schemas/CloudflareConfig" + }, + "enabled": { + "type": [ + "boolean", + "null" + ] + }, + "name": { + "type": "string" + } + }, + "required": [ + "name", + "config" + ], + "type": "object" + }, + "CreateConversationRequest": { + "properties": { + "context_id": { + "description": "The entity id (ints stringified).", + "type": "string" + }, + "context_type": { + "description": "e.g. `\"deployment\"`.", + "type": "string" + } + }, + "required": [ + "context_type", + "context_id" + ], + "type": "object" + }, + "CreateDSNRequest": { + "properties": { + "base_url": { + "type": [ + "string", + "null" + ] + }, + "deployment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "name": { + "type": [ + "string", + "null" + ] + } + }, + "type": "object" + }, + "CreateDashboardRequest": { + "properties": { + "layout": { + "$ref": "#/components/schemas/DashboardLayout" + }, + "name": { + "type": "string" + }, + "project_id": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "project_id", + "name", + "layout" + ], + "type": "object" + }, + "CreateDeploymentTokenRequest": { + "properties": { + "deployment_id": { + "description": "Optional deployment ID - if set, token is scoped to a specific deployment", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "environment_id": { + "description": "Optional environment ID - if not set, token applies to all environments", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "expires_at": { + "example": "2024-12-31T23:59:59Z", + "format": "date-time", + "type": [ + "string", + "null" + ] + }, + "name": { + "type": "string" + }, + "permissions": { + "description": "List of permissions (e.g., [\"visitors:enrich\", \"emails:send\"])\nIf not provided, defaults to full access", + "example": [ + "visitors:enrich", + "emails:send" + ], + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "CreateDeploymentTokenResponse": { + "properties": { + "created_at": { + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "deployment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "expires_at": { + "example": "2024-12-31T23:59:59Z", + "format": "date-time", + "type": [ + "string", + "null" + ] + }, + "id": { + "format": "int32", + "type": "integer" + }, + "name": { + "type": "string" + }, + "permissions": { + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "token": { + "description": "The full token value - only returned on creation", + "type": "string" + }, + "token_prefix": { + "type": "string" + } + }, + "required": [ + "id", + "project_id", + "name", + "token_prefix", + "token", + "created_at" + ], + "type": "object" + }, + "CreateDnsProviderRequest": { + "description": "Request to create a new DNS provider", + "properties": { + "credentials": { + "$ref": "#/components/schemas/DnsProviderCredentials", + "description": "Provider credentials" + }, + "description": { + "description": "Optional description", + "type": [ + "string", + "null" + ] + }, + "name": { + "description": "User-friendly name", + "example": "My Cloudflare", + "type": "string" + }, + "provider_type": { + "$ref": "#/components/schemas/DnsProviderType", + "description": "Provider type" + } + }, + "required": [ + "name", + "provider_type", + "credentials" + ], + "type": "object" + }, + "CreateDomainRequest": { + "properties": { + "challenge_type": { + "description": "Challenge type for Let's Encrypt validation. Options: \"http-01\" (default) or \"dns-01\"", + "type": "string" + }, + "domain": { + "type": "string" + } + }, + "required": [ + "domain" + ], + "type": "object" + }, + "CreateEmailDomainRequest": { + "properties": { + "domain": { + "description": "Domain name (e.g., \"updates.example.com\")", + "example": "updates.example.com", + "type": "string" + }, + "provider_id": { + "description": "Provider ID to use for this domain", + "format": "int32", + "type": "integer" + } + }, + "required": [ + "provider_id", + "domain" + ], + "type": "object" + }, + "CreateEmailProviderRequest": { + "properties": { + "name": { + "description": "User-friendly name for the provider", + "example": "My AWS SES", + "type": "string" + }, + "provider_type": { + "$ref": "#/components/schemas/EmailProviderTypeRoute", + "description": "Provider type" + }, + "region": { + "description": "Cloud region. For SMTP this is informational only — the host/port carry the real routing.", + "example": "us-east-1", + "type": "string" + }, + "scaleway_credentials": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/ScalewayCredentialsRequest", + "description": "Scaleway credentials (required if provider_type is scaleway)" + } + ] + }, + "ses_credentials": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/SesCredentialsRequest", + "description": "AWS SES credentials (required if provider_type is ses)" + } + ] + }, + "smtp_credentials": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/SmtpCredentialsRequest", + "description": "Generic SMTP credentials (required if provider_type is smtp). Use when\nyou only have SMTP creds and want to import an already-set-up domain." + } + ] + }, + "sns_topic_arn": { + "description": "Exact SNS topic allowed to deliver SES events for this provider.", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "name", + "provider_type", + "region" + ], + "type": "object" + }, + "CreateEnvironmentRequest": { + "properties": { + "branch": { + "type": "string" + }, + "name": { + "type": "string" + }, + "set_as_preview": { + "description": "If true, set this environment as the preview environment for the project", + "type": "boolean" + } + }, + "required": [ + "name", + "branch" + ], + "type": "object" + }, + "CreateEnvironmentVariableRequest": { + "properties": { + "environment_ids": { + "items": { + "format": "int32", + "type": "integer" + }, + "type": "array" + }, + "include_in_preview": { + "description": "Include this environment variable in preview environments (default: true)", + "type": "boolean" + }, + "is_secret": { + "description": "When true the variable is treated as write-only: never returned in\nplaintext from the API, masked in the UI, and updates that omit the\nvalue preserve the existing ciphertext. The flag is one-way — secret\nvars cannot be demoted back to regular vars.", + "type": "boolean" + }, + "key": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "key", + "value", + "environment_ids" + ], + "type": "object" + }, + "CreateExternalServiceRequest": { + "properties": { + "members": { + "description": "Cluster member specifications. Required when topology is \"cluster\".", + "items": { + "$ref": "#/components/schemas/ClusterMemberRequest" + }, + "type": "array" + }, + "name": { + "type": "string" + }, + "node_id": { + "description": "Target node ID for the service. Omit or null to run on the control plane.", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "parameters": { + "additionalProperties": {}, + "propertyNames": { + "type": "string" + }, + "type": "object" + }, + "service_type": { + "$ref": "#/components/schemas/ServiceTypeRoute" + }, + "topology": { + "description": "Service topology: \"standalone\" (default) or \"cluster\" (HA multi-member).", + "example": "standalone", + "type": "string" + }, + "version": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "name", + "service_type", + "parameters" + ], + "type": "object" + }, + "CreateFlagRequest": { + "properties": { + "client_visible": { + "description": "Whether the flag may be exposed on the unauthenticated same-origin\nevaluation endpoint. Defaults to `false`: flags are server-only unless\nexplicitly opted in, because targeting rules can encode business logic.", + "type": "boolean" + }, + "default_value": { + "description": "Served whenever evaluation cannot do better. Must match `value_type`.\n\nLeft unannotated so utoipa emits a free-form schema: a bool flag's\ndefault is `false`, not an object, and `value_type = Object` would tell\nevery generated client otherwise." + }, + "description": { + "type": [ + "string", + "null" + ] + }, + "key": { + "description": "Stable key used in application code. Immutable after create.", + "example": "checkout.v2", + "type": "string" + }, + "value_type": { + "$ref": "#/components/schemas/FlagValueType", + "description": "Fixed at create: retyping would invalidate every stored value and every\ncall site." + } + }, + "required": [ + "key", + "value_type", + "default_value" + ], + "type": "object" + }, + "CreateFunnelRequest": { + "properties": { + "description": { + "type": [ + "string", + "null" + ] + }, + "name": { + "type": "string" + }, + "steps": { + "items": { + "$ref": "#/components/schemas/CreateFunnelStep" + }, + "type": "array" + } + }, + "required": [ + "name", + "steps" + ], + "type": "object" + }, + "CreateFunnelResponse": { + "properties": { + "funnel_id": { + "format": "int32", + "type": "integer" + }, + "message": { + "type": "string" + } + }, + "required": [ + "funnel_id", + "message" + ], + "type": "object" + }, + "CreateFunnelStep": { + "properties": { + "event_filter": { + "items": { + "$ref": "#/components/schemas/SmartFilter" + }, + "type": "array" + }, + "event_name": { + "type": "string" + } + }, + "required": [ + "event_name" + ], + "type": "object" + }, + "CreateGenericRequest": { + "properties": { + "base_url": { + "description": "Optional base URL of the git host for display purposes (no API is called).", + "type": [ + "string", + "null" + ] + }, + "clone_url": { + "description": "HTTPS clone URL for the repository, e.g. `https://git.example.com/org/repo.git`.", + "type": "string" + }, + "name": { + "description": "Display name for this provider.", + "type": "string" + }, + "token": { + "description": "Access token or password. Omit (or set to `null`) for public repositories.", + "type": [ + "string", + "null" + ] + }, + "token_username": { + "description": "HTTP Basic username used with the token. Defaults to `x-access-token` when\nabsent or empty. Ignored for public (unauthenticated) repositories.", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "name", + "clone_url" + ], + "type": "object" + }, + "CreateGitHubPATRequest": { + "properties": { + "name": { + "type": "string" + }, + "token": { + "type": "string" + } + }, + "required": [ + "name", + "token" + ], + "type": "object" + }, + "CreateGitLabOAuthRequest": { + "properties": { + "base_url": { + "type": [ + "string", + "null" + ] + }, + "client_id": { + "type": "string" + }, + "client_secret": { + "type": "string" + }, + "name": { + "type": "string" + }, + "redirect_uri": { + "type": "string" + } + }, + "required": [ + "name", + "client_id", + "client_secret", + "redirect_uri" + ], + "type": "object" + }, + "CreateGitLabPATRequest": { + "properties": { + "base_url": { + "type": [ + "string", + "null" + ] + }, + "name": { + "type": "string" + }, + "token": { + "type": "string" + } + }, + "required": [ + "name", + "token" + ], + "type": "object" + }, + "CreateGiteaPATRequest": { + "properties": { + "base_url": { + "description": "HTTPS base URL of the Gitea instance, e.g. `https://git.example.com`.", + "type": "string" + }, + "name": { + "description": "Display name for this provider.", + "type": "string" + }, + "token": { + "description": "Personal access token issued by the Gitea instance.", + "type": "string" + } + }, + "required": [ + "name", + "token", + "base_url" + ], + "type": "object" + }, + "CreateIncidentRequest": { + "properties": { + "description": { + "type": [ + "string", + "null" + ] + }, + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "monitor_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "severity": { + "type": "string" + }, + "title": { + "type": "string" + } + }, + "required": [ + "title", + "severity" + ], + "type": "object" + }, + "CreateIntegrationBody": { + "properties": { + "provider": { + "description": "Registered provider name, e.g. \"stripe\".", + "type": "string" + }, + "signing_secret": { + "description": "Signing secret from the provider's dashboard.", + "type": "string" + } + }, + "required": [ + "provider", + "signing_secret" + ], + "type": "object" + }, + "CreateIpAccessControlRequest": { + "description": "Request to create an IP access control rule", + "properties": { + "action": { + "description": "Action to take: \"block\" or \"allow\"", + "example": "block", + "type": "string" + }, + "ip_address": { + "description": "IP address in CIDR notation (e.g., \"192.168.1.1\" or \"10.0.0.0/24\")", + "example": "192.168.1.100", + "type": "string" + }, + "reason": { + "description": "Optional reason for the action", + "example": "Malicious activity detected", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "ip_address", + "action" + ], + "type": "object" + }, + "CreateMcpRequest": { + "properties": { + "config": { + "type": "object" + }, + "description": { + "type": [ + "string", + "null" + ] + }, + "name": { + "type": "string" + }, + "slug": { + "type": "string" + } + }, + "required": [ + "slug", + "name", + "config" + ], + "type": "object" + }, + "CreateMetricAlertRequest": { + "properties": { + "aggregation": { + "description": "One of `avg|sum|min|max|count|rate|p50|p90|p95|p99`.", + "type": "string" + }, + "detection_config": { + "$ref": "#/components/schemas/DetectionConfig", + "description": "The detector: a discriminated union keyed by `kind`. Today only\n`{ \"kind\": \"static\", \"comparator\": \"gt\", \"threshold\": 500 }` is evaluable." + }, + "dynamic_alerts": { + "description": "When true (and `group_by` is set) fire one independent alarm per breaching\nseries. Static detectors only. Default false.", + "type": "boolean" + }, + "enabled": { + "type": "boolean" + }, + "for_duration_secs": { + "format": "int32", + "type": "integer" + }, + "group_by": { + "description": "Label keys to break the metric down by, e.g. `[\"endpoint\",\"region\"]`. Empty\n(the default) = one aggregate stream. Max 2 keys; keys must match\n`[a-zA-Z0-9_.:-]`.", + "items": { + "type": "string" + }, + "type": "array" + }, + "grouped_notification_threshold": { + "description": "When more than this many series transition to firing in the same tick, only\nthe first gets the expensive chart/AI enrichment. Range 1–1000, default 5.", + "format": "int32", + "type": "integer" + }, + "label_filters": { + "description": "AND-combined label equality filters: `[[\"key\",\"value\"],…]`. Empty = no\nfiltering (the default). Max 10 pairs; keys must match `[a-zA-Z0-9_.:-]`;\nvalues capped at 500 characters.", + "items": { + "items": false, + "prefixItems": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "type": "array" + }, + "type": "array" + }, + "max_series": { + "description": "Cardinality cap for dynamic alerting: at most this many series (top by\n`|value|`). Range 1–100, default 20.", + "format": "int32", + "type": "integer" + }, + "metric_name": { + "type": "string" + }, + "name": { + "type": "string" + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "severity": { + "description": "One of `info|warning|critical`.", + "type": "string" + }, + "window_secs": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "project_id", + "name", + "metric_name", + "aggregation", + "detection_config", + "window_secs", + "for_duration_secs", + "severity", + "enabled" + ], + "type": "object" + }, + "CreateMonitorRequest": { + "properties": { + "check_interval_seconds": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "check_path": { + "type": [ + "string", + "null" + ] + }, + "environment_id": { + "format": "int32", + "type": "integer" + }, + "monitor_type": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "name", + "monitor_type", + "environment_id" + ], + "type": "object" + }, + "CreateNotificationEmailProviderRequest": { + "properties": { + "config": { + "$ref": "#/components/schemas/EmailConfig" + }, + "enabled": { + "type": [ + "boolean", + "null" + ] + }, + "name": { + "type": "string" + } + }, + "required": [ + "name", + "config" + ], + "type": "object" + }, + "CreateOidcProviderRequest": { + "properties": { + "client_id": { + "type": "string" + }, + "client_secret": { + "type": "string" + }, + "default_role": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "group_claim": { + "type": "string" + }, + "issuer_url": { + "type": "string" + }, + "jit_provisioning": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "role_claim": { + "type": "string" + }, + "scopes": { + "type": "string" + }, + "template": { + "type": "string" + }, + "trust_idp_email": { + "description": "Defaults false. Set to true only for IdPs where an admin\ncontrols user provisioning (corporate Okta, Azure AD) and\nself-signup of arbitrary emails is not possible — see the\n`trust_idp_email` field on `oidc_providers::Model` for the\nsecurity tradeoff this enables.", + "type": "boolean" + } + }, + "required": [ + "name", + "issuer_url", + "client_id", + "client_secret" + ], + "type": "object" + }, + "CreateOidcRoleMappingRequest": { + "properties": { + "idp_group": { + "type": "string" + }, + "priority": { + "format": "int32", + "type": "integer" + }, + "role": { + "type": "string" + } + }, + "required": [ + "priority", + "idp_group", + "role" + ], + "type": "object" + }, + "CreatePlanRequest": { + "description": "Request to create an import plan", + "properties": { + "credentials": { + "$ref": "#/components/schemas/ImportCredentials", + "description": "Platform credentials (required for cloud platforms like Vercel, Railway)" + }, + "repository_id": { + "description": "Optional repository ID to associate with the import\nIf provided, preset will be detected from the repository", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "source": { + "$ref": "#/components/schemas/ImportSource", + "description": "Source to import from" + }, + "workload_id": { + "$ref": "#/components/schemas/WorkloadId", + "description": "Workload ID to import" + } + }, + "required": [ + "source", + "workload_id" + ], + "type": "object" + }, + "CreatePlanResponse": { + "description": "Response with created plan", + "properties": { + "can_execute": { + "description": "Whether the plan can be executed", + "type": "boolean" + }, + "plan": { + "$ref": "#/components/schemas/ImportPlan", + "description": "Generated import plan" + }, + "session_id": { + "description": "Session ID for tracking", + "type": "string" + }, + "validation": { + "$ref": "#/components/schemas/ValidationReport", + "description": "Validation report" + } + }, + "required": [ + "session_id", + "plan", + "validation", + "can_execute" + ], + "type": "object" + }, + "CreatePrResponse": { + "properties": { + "branch_name": { + "type": "string" + }, + "pr_number": { + "format": "int32", + "type": "integer" + }, + "pr_url": { + "type": "string" + }, + "run": { + "$ref": "#/components/schemas/AutofixerRunResponse" + } + }, + "required": [ + "run", + "pr_url", + "pr_number", + "branch_name" + ], + "type": "object" + }, + "CreateProjectAccessRequest": { + "properties": { + "role": { + "$ref": "#/components/schemas/TeamRole" + }, + "team_id": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "team_id", + "role" + ], + "type": "object" + }, + "CreateProjectFromTemplateRequest": { + "description": "Request to create a project from a template\n\nSupports two deploy modes:\n * **Fork mode** — when `git_provider_connection_id` is set, the template\n repo is cloned into a new repository under the user's Git account and the\n project tracks that fork (git-push deploys, automatic deploy on push).\n * **One-click public-repo mode** — when `git_provider_connection_id` is\n omitted, the project deploys directly from the template's public source\n repository (no fork, no Git account required). This is the activation\n path: a brand-new user with no Git provider connected can still deploy a\n demo in one click. `repository_name` / `repository_owner` are ignored in\n this mode, and automatic-deploy-on-push is unavailable (there is no fork\n to receive webhooks).", + "properties": { + "automatic_deploy": { + "description": "Enable automatic deployment on push (defaults to true). Only honoured in\nfork mode; public-repo deploys cannot receive push webhooks.", + "type": "boolean" + }, + "environment_variables": { + "description": "Environment variables to set (key-value pairs)", + "items": { + "$ref": "#/components/schemas/EnvVarInput" + }, + "type": "array" + }, + "git_provider_connection_id": { + "description": "Git provider connection ID. When omitted, the project deploys directly\nfrom the template's public source repository instead of forking it.", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "private": { + "description": "Whether to make the repository private (defaults to true)", + "type": "boolean" + }, + "project_name": { + "description": "Name for the new project", + "type": "string" + }, + "repository_name": { + "description": "Name for the new repository to create. Required in fork mode; ignored in\none-click public-repo mode.", + "type": [ + "string", + "null" + ] + }, + "repository_owner": { + "description": "Owner/organization for the new repository (defaults to authenticated user)", + "type": [ + "string", + "null" + ] + }, + "storage_service_ids": { + "description": "External storage service IDs to attach to the project", + "items": { + "format": "int32", + "type": "integer" + }, + "type": "array" + }, + "template_slug": { + "description": "Template slug to use as the base", + "type": "string" + } + }, + "required": [ + "template_slug", + "project_name" + ], + "type": "object" + }, + "CreateProjectFromTemplateResponse": { + "description": "Response after creating a project from template", + "properties": { + "message": { + "description": "Message with additional info", + "type": "string" + }, + "project_id": { + "description": "ID of the created project", + "format": "int32", + "type": "integer" + }, + "project_name": { + "description": "Name of the created project", + "type": "string" + }, + "project_slug": { + "description": "Slug of the created project", + "type": "string" + }, + "repository_url": { + "description": "URL of the created repository", + "type": "string" + }, + "template_slug": { + "description": "Template that was used", + "type": "string" + } + }, + "required": [ + "project_id", + "project_slug", + "project_name", + "repository_url", + "template_slug", + "message" + ], + "type": "object" + }, + "CreateProjectRequest": { + "properties": { + "automatic_deploy": { + "type": [ + "boolean", + "null" + ] + }, + "build_command": { + "type": [ + "string", + "null" + ] + }, + "custom_domain": { + "type": [ + "string", + "null" + ] + }, + "directory": { + "type": "string" + }, + "environment_variables": { + "items": { + "items": false, + "prefixItems": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "type": "array" + }, + "type": [ + "array", + "null" + ] + }, + "exposed_port": { + "description": "Port exposed by the container (fallback when image has no EXPOSE directive)\n\nPriority order for port resolution:\n1. Image EXPOSE directive (auto-detected from built image)\n2. Environment-level exposed_port (overrides this value per environment)\n3. This project-level exposed_port (fallback)\n4. Default: 3000\n\nOnly set this if your image doesn't use EXPOSE directive.", + "example": 8080, + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "git_provider_connection_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "git_url": { + "type": [ + "string", + "null" + ] + }, + "install_command": { + "type": [ + "string", + "null" + ] + }, + "is_on_demand": { + "type": [ + "boolean", + "null" + ] + }, + "is_public_repo": { + "type": [ + "boolean", + "null" + ] + }, + "is_web_app": { + "type": [ + "boolean", + "null" + ] + }, + "main_branch": { + "type": "string" + }, + "name": { + "type": "string" + }, + "output_dir": { + "type": [ + "string", + "null" + ] + }, + "performance_metrics_enabled": { + "type": "boolean" + }, + "preset": { + "type": "string" + }, + "preset_config": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/PresetConfigSchema", + "description": "Preset-specific configuration\n\nDifferent presets accept different configuration options:\n- **Dockerfile preset**: Accepts `DockerfilePresetConfig` with `dockerfile_path` and `build_context`\n- **Nixpacks preset**: Accepts ordered `providers` (for example `[\"...\", \"python\"]`)\n and optional inline `nixpacksConfig` TOML\n- **Static presets** (Vite, Next.js, etc.): Accept `StaticPresetConfig` with build commands and output dir\n\nExample for Dockerfile preset:\n```json\n{\n \"dockerfilePath\": \"docker/Dockerfile\",\n \"buildContext\": \"./api\"\n}\n```" + } + ] + }, + "project_type": { + "type": [ + "string", + "null" + ] + }, + "repo_name": { + "type": [ + "string", + "null" + ] + }, + "repo_owner": { + "type": [ + "string", + "null" + ] + }, + "source_type": { + "$ref": "#/components/schemas/SourceType", + "description": "Source type for deployments\n\nDetermines how the project is deployed:\n- **git** (default): Traditional Git-based deployments - source code is pulled, built, and deployed\n- **docker_image**: Deploy pre-built Docker images from external registries (DockerHub, GHCR, etc.)\n- **static_files**: Deploy pre-built static files uploaded as tar.gz or zip bundles\n\nFor `docker_image` and `static_files` source types, `repo_name` and `repo_owner` are optional." + }, + "storage_service_ids": { + "items": { + "format": "int32", + "type": "integer" + }, + "type": "array" + }, + "use_default_wildcard": { + "type": [ + "boolean", + "null" + ] + } + }, + "required": [ + "name", + "directory", + "main_branch", + "preset", + "storage_service_ids" + ], + "type": "object" + }, + "CreateProjectSecretRequest": { + "description": "Request to create a new project secret.\n\nProject secrets are mounted into the container as files under\n`/run/secrets/` (mode 0400, tmpfs) instead of as environment variables.\nValues are always encrypted at rest and never returned in plaintext from\nthe API after create. Distinct from agent secrets (global `/settings/secrets`).", + "properties": { + "environment_ids": { + "items": { + "format": "int32", + "type": "integer" + }, + "type": "array" + }, + "include_in_preview": { + "description": "Include this secret in preview environments.", + "type": "boolean" + }, + "key": { + "description": "Identifier for the secret. Becomes the filename at `/run/secrets/`.\nMust start with a letter or underscore and contain only A-Z, a-z, 0-9, _.", + "type": "string" + }, + "value": { + "description": "Plaintext value, <= 1 MiB.", + "type": "string" + } + }, + "required": [ + "key", + "value" + ], + "type": "object" + }, + "CreateProviderKeyRequest": { + "properties": { + "api_key": { + "type": "string" + }, + "base_url": { + "type": [ + "string", + "null" + ] + }, + "default_model": { + "description": "Optional model id to pin for this provider (e.g. \"gpt-4o-mini\").", + "type": [ + "string", + "null" + ] + }, + "display_name": { + "type": "string" + }, + "provider": { + "type": "string" + } + }, + "required": [ + "provider", + "display_name", + "api_key" + ], + "type": "object" + }, + "CreateProviderRequest": { + "properties": { + "config": {}, + "enabled": { + "type": [ + "boolean", + "null" + ] + }, + "name": { + "type": "string" + }, + "provider_type": { + "type": "string" + } + }, + "required": [ + "name", + "provider_type", + "config" + ], + "type": "object" + }, + "CreateRouteRequest": { + "properties": { + "domain": { + "type": "string" + }, + "host": { + "type": "string" + }, + "port": { + "format": "int32", + "type": "integer" + }, + "route_type": { + "description": "Route type: \"http\" (default) matches on HTTP Host header,\n\"tls\" matches on TLS SNI hostname for TCP passthrough", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "domain", + "host", + "port" + ], + "type": "object" + }, + "CreateS3SourceRequest": { + "properties": { + "access_key_id": { + "type": "string" + }, + "bucket_name": { + "type": "string" + }, + "bucket_path": { + "type": "string" + }, + "endpoint": { + "description": "Optional endpoint URL for S3-compatible services like MinIO", + "example": "http://minio.example.com:9000", + "type": [ + "string", + "null" + ] + }, + "force_path_style": { + "description": "Whether to use path-style addressing (default: true)", + "example": true, + "type": [ + "boolean", + "null" + ] + }, + "is_default": { + "description": "When true, make this the default source (will swap out any existing default).\nThe very first S3 source is always created as default regardless of this flag.", + "example": false, + "type": [ + "boolean", + "null" + ] + }, + "name": { + "type": "string" + }, + "region": { + "type": "string" + }, + "secret_key": { + "type": "string" + } + }, + "required": [ + "name", + "bucket_name", + "bucket_path", + "access_key_id", + "secret_key", + "region" + ], + "type": "object" + }, + "CreateSandboxBody": { + "properties": { + "_runtime": { + "type": [ + "string", + "null" + ] + }, + "backend": { + "description": "Isolation backend: `\"docker\"` (default) or `\"firecracker\"` (ADR-029,\nhardware-virtualized microVM — requires a host provisioned with\n`temps firecracker setup`). Omit for the platform default; existing\nclients are unaffected. Requesting an unavailable backend fails with\n400 rather than silently downgrading isolation.", + "type": [ + "string", + "null" + ] + }, + "cpu_limit": { + "format": "double", + "type": [ + "number", + "null" + ] + }, + "disk_size_mb": { + "description": "Root disk size in MB (Firecracker only; Docker ignores it). Omit for\nthe platform default (1 GiB).", + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "env": { + "additionalProperties": { + "type": "string" + }, + "description": "Extra env vars baked into the container on create.", + "propertyNames": { + "type": "string" + }, + "type": "object" + }, + "image": { + "description": "Docker image override. `null` uses the platform default.", + "type": [ + "string", + "null" + ] + }, + "memory_limit_mb": { + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "name": { + "type": [ + "string", + "null" + ] + }, + "networkPolicy": {}, + "pids_limit": { + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "ports": { + "description": "Ports the sandbox will listen on. Each port becomes a `routes[]`\nentry in the create/get response so `@vercel/sandbox`'s\n`sandbox.domain(port)` can resolve it client-side without an\nextra round-trip.", + "items": { + "format": "int32", + "minimum": 0, + "type": "integer" + }, + "type": "array" + }, + "preview_password": { + "description": "Optional preview-URL password. When set, every preview URL served\nfor this sandbox is gated behind a login form. 8–256 characters.\nOmit to leave preview URLs open (the sandbox ID remains the only\ngate). The plaintext is never returned; only the last-4 hint is\nsurfaced in `SandboxResponse.preview_password_hint`.", + "type": [ + "string", + "null" + ] + }, + "projectId": { + "type": [ + "string", + "null" + ] + }, + "resources": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/ResourcesBody", + "description": "`@vercel/sandbox`'s nested resources object. When present, its\n`memory` / `vcpus` populate `memory_limit_mb` / `cpu_limit` if those\nweren't sent directly." + } + ] + }, + "source": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/SourceBody", + "description": "Optional initial content to seed into the work dir. Clones a\nrepo or extracts a tarball after the sandbox is created." + } + ] + }, + "timeout": { + "description": "Idle timeout as sent by `@vercel/sandbox` (milliseconds). Converted\nto seconds when `timeout_secs` is absent.", + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "timeout_secs": { + "description": "Idle timeout in seconds (temps-native). Clamped to `[60, 86400]`.", + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + } + }, + "type": "object" + }, + "CreateSkillRequest": { + "properties": { + "content": { + "type": "string" + }, + "description": { + "type": [ + "string", + "null" + ] + }, + "name": { + "type": "string" + }, + "slug": { + "type": "string" + } + }, + "required": [ + "slug", + "name", + "content" + ], + "type": "object" + }, + "CreateSlackProviderRequest": { + "properties": { + "config": { + "$ref": "#/components/schemas/SlackConfig" + }, + "enabled": { + "type": [ + "boolean", + "null" + ] + }, + "name": { + "type": "string" + } + }, + "required": [ + "name", + "config" + ], + "type": "object" + }, + "CreateTeamMemberRequest": { + "properties": { + "role": { + "$ref": "#/components/schemas/TeamRole" + }, + "user_id": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "user_id", + "role" + ], + "type": "object" + }, + "CreateTeamRequest": { + "properties": { + "description": { + "type": [ + "string", + "null" + ] + }, + "name": { + "type": "string" + }, + "slug": { + "type": "string" + } + }, + "required": [ + "name", + "slug" + ], + "type": "object" + }, + "CreateUserRequest": { + "properties": { + "email": { + "type": [ + "string", + "null" + ] + }, + "password": { + "type": [ + "string", + "null" + ] + }, + "roles": { + "items": { + "type": "string" + }, + "type": "array" + }, + "username": { + "type": "string" + } + }, + "required": [ + "username", + "roles" + ], + "type": "object" + }, + "CreateWebhookProviderRequest": { + "properties": { + "config": { + "$ref": "#/components/schemas/WebhookConfig" + }, + "enabled": { + "type": [ + "boolean", + "null" + ] + }, + "name": { + "type": "string" + } + }, + "required": [ + "name", + "config" + ], + "type": "object" + }, + "CreateWebhookRequestBody": { + "properties": { + "enabled": { + "default": true, + "description": "Whether the webhook is enabled", + "type": [ + "boolean", + "null" + ] + }, + "events": { + "description": "Event types to subscribe to", + "example": [ + "deployment.created", + "deployment.succeeded" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "secret": { + "description": "Secret for HMAC signature verification (optional)", + "type": [ + "string", + "null" + ] + }, + "url": { + "description": "Target URL for webhook delivery", + "example": "https://example.com/webhook", + "type": "string" + } + }, + "required": [ + "url", + "events" + ], + "type": "object" + }, + "CreatedResource": { + "description": "Resource created during import (for rollback / audit)", + "properties": { + "resource_id": { + "description": "Resource ID", + "format": "int32", + "type": "integer" + }, + "resource_name": { + "description": "Resource name", + "type": "string" + }, + "resource_type": { + "description": "Resource type (project, environment, deployment, service, domain, etc.)", + "type": "string" + } + }, + "required": [ + "resource_type", + "resource_id", + "resource_name" + ], + "type": "object" + }, + "CronExecutionInfo": { + "properties": { + "cron_id": { + "format": "int32", + "type": "integer" + }, + "error_message": { + "type": [ + "string", + "null" + ] + }, + "executed_at": { + "type": "string" + }, + "headers": { + "type": "string" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "response_time_ms": { + "format": "int32", + "type": "integer" + }, + "status_code": { + "format": "int32", + "type": "integer" + }, + "url": { + "type": "string" + } + }, + "required": [ + "id", + "cron_id", + "executed_at", + "url", + "status_code", + "headers", + "response_time_ms" + ], + "type": "object" + }, + "CronInfo": { + "properties": { + "created_at": { + "type": "string" + }, + "deleted_at": { + "type": [ + "string", + "null" + ] + }, + "environment_id": { + "format": "int32", + "type": "integer" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "next_run": { + "type": [ + "string", + "null" + ] + }, + "path": { + "type": "string" + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "schedule": { + "type": "string" + }, + "updated_at": { + "type": "string" + } + }, + "required": [ + "id", + "project_id", + "environment_id", + "path", + "schedule", + "created_at", + "updated_at" + ], + "type": "object" + }, + "CrossProjectSiblingRef": { + "description": "A sibling project that shares the same `trace_id`, returned by the\nPhase 1 cross-project banner endpoint.", + "properties": { + "first_seen": { + "description": "ISO 8601 timestamp (UTC, `Z` suffix) of first span ingest for this\n`(trace_id, project_id)` pair.", + "format": "date-time", + "type": "string" + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "project_name": { + "type": "string" + }, + "project_slug": { + "description": "URL slug used to link into the sibling project's single-project trace view.", + "type": "string" + } + }, + "required": [ + "project_id", + "project_name", + "project_slug", + "first_seen" + ], + "type": "object" + }, + "CrossProjectTraceResponse": { + "description": "Response body for `GET /otel/traces/cross-project/{trace_id}`.\n\nAn empty `siblings` vec is the normal single-project case — never 404.", + "properties": { + "siblings": { + "description": "Projects other than the caller's that hold spans for this trace,\nordered by `first_seen ASC`.", + "items": { + "$ref": "#/components/schemas/CrossProjectSiblingRef" + }, + "type": "array" + }, + "trace_id": { + "description": "The trace_id that was queried (echoed back for client convenience).", + "type": "string" + } + }, + "required": [ + "trace_id", + "siblings" + ], + "type": "object" + }, + "CurrentStatusResponse": { + "properties": { + "avg_response_time_ms": { + "format": "double", + "type": [ + "number", + "null" + ] + }, + "current_status": { + "type": "string" + }, + "last_check_at": { + "format": "date-time", + "type": [ + "string", + "null" + ] + }, + "monitor_id": { + "format": "int32", + "type": "integer" + }, + "uptime_percentage": { + "format": "double", + "type": "number" + } + }, + "required": [ + "monitor_id", + "current_status", + "uptime_percentage" + ], + "type": "object" + }, + "CustomDomainRequest": { + "properties": { + "branch": { + "type": [ + "string", + "null" + ] + }, + "domain": { + "type": "string" + }, + "environment_id": { + "format": "int32", + "type": "integer" + }, + "redirect_to": { + "type": [ + "string", + "null" + ] + }, + "service_name": { + "description": "Docker Compose service name this domain routes to (only for docker-compose projects)", + "type": [ + "string", + "null" + ] + }, + "status_code": { + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + "required": [ + "domain", + "environment_id" + ], + "type": "object" + }, + "CustomDomainResponse": { + "properties": { + "branch": { + "type": [ + "string", + "null" + ] + }, + "created_at": { + "format": "int64", + "type": "integer" + }, + "domain": { + "type": "string" + }, + "domain_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "environment": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/DomainEnvironmentResponse" + } + ] + }, + "expiration_time": { + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "id": { + "format": "int32", + "type": "integer" + }, + "last_renewed": { + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "message": { + "type": [ + "string", + "null" + ] + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "redirect_to": { + "type": [ + "string", + "null" + ] + }, + "service_name": { + "description": "Docker Compose service name this domain routes to", + "type": [ + "string", + "null" + ] + }, + "status": { + "type": "string" + }, + "status_code": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "updated_at": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "id", + "project_id", + "domain", + "status", + "created_at", + "updated_at" + ], + "type": "object" + }, + "CustomerMovementResponse": { + "properties": { + "bucket": { + "format": "date-time", + "type": "string" + }, + "churned_customers": { + "format": "int64", + "type": "integer" + }, + "new_customers": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "bucket", + "new_customers", + "churned_customers" + ], + "type": "object" + }, + "DashboardLayout": { + "description": "The typed layout persisted (as JSONB) in `metric_dashboards.layout`.", + "properties": { + "sections": { + "description": "Ordered sections that make up the dashboard.", + "items": { + "$ref": "#/components/schemas/DashboardSection" + }, + "type": "array" + } + }, + "required": [ + "sections" + ], + "type": "object" + }, + "DashboardProjectsAnalyticsQuery": { + "description": "Query parameters for batch dashboard analytics", + "properties": { + "end_date": { + "description": "End date for the query range", + "format": "date-time", + "type": "string" + }, + "project_ids": { + "description": "Comma-separated list of project IDs", + "type": "string" + }, + "start_date": { + "description": "Start date for the query range", + "format": "date-time", + "type": "string" + } + }, + "required": [ + "project_ids", + "start_date", + "end_date" + ], + "type": "object" + }, + "DashboardProjectsAnalyticsResponse": { + "description": "Batch response for dashboard project analytics", + "properties": { + "projects": { + "additionalProperties": { + "$ref": "#/components/schemas/ProjectDashboardAnalytics" + }, + "description": "Map of project_id -> analytics data", + "propertyNames": { + "type": "string" + }, + "type": "object" + } + }, + "required": [ + "projects" + ], + "type": "object" + }, + "DashboardSection": { + "description": "A titled group of tiles within a dashboard.", + "properties": { + "id": { + "description": "Stable client-generated section id.", + "type": "string" + }, + "tiles": { + "description": "Tiles rendered within this section.", + "items": { + "$ref": "#/components/schemas/DashboardTile" + }, + "type": "array" + }, + "title": { + "description": "Section heading.", + "type": "string" + } + }, + "required": [ + "id", + "title", + "tiles" + ], + "type": "object" + }, + "DashboardTile": { + "description": "A single metric tile within a dashboard section.", + "properties": { + "aggregation": { + "description": "Aggregation applied per bucket: one of\n`avg|sum|min|max|count|rate|p50|p90|p95|p99`.", + "type": "string" + }, + "group_by": { + "description": "Label keys to break the metric down by (group-by / multi-series view).\nEmpty = single aggregated series (current behavior). Max 2 keys — more\ndimensions are unreadable in a chart (ADR-026 Phase 2). Each key must\nmatch `[a-zA-Z0-9_.:-]`. Wired directly to `MetricQuery.group_by` by\nthe tile query path (separate frontend task).", + "items": { + "type": "string" + }, + "type": "array" + }, + "id": { + "description": "Stable client-generated tile id (used as a React key / for reordering).", + "type": "string" + }, + "label_filters": { + "description": "AND-combined label equality filters: `[[\"key\",\"value\"],…]`. Empty = no\nfiltering. Max 10 pairs; keys must match `[a-zA-Z0-9_.:-]`; values\ncapped at 500 characters. Not yet wired into the tile query path\n(Phase 1 ADR-026 — field round-trips and validates; query wiring is\na separate frontend task).", + "items": { + "items": false, + "prefixItems": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "type": "array" + }, + "type": "array" + }, + "metric_name": { + "description": "The metric name to chart (e.g. `http.server.duration`).", + "type": "string" + }, + "title": { + "description": "Optional display title; falls back to the metric name in the UI.", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "id", + "metric_name", + "aggregation" + ], + "type": "object" + }, + "DataImplication": { + "description": "A specific data implication the user needs to understand", + "properties": { + "message": { + "description": "Human-readable description of what could happen", + "type": "string" + }, + "recommended_action": { + "description": "What the user should do about it (if anything)", + "type": [ + "string", + "null" + ] + }, + "severity": { + "$ref": "#/components/schemas/DataImplicationSeverity", + "description": "Severity of this implication" + } + }, + "required": [ + "severity", + "message" + ], + "type": "object" + }, + "DataImplicationSeverity": { + "description": "Severity of a data implication", + "enum": [ + "info", + "warning", + "data-not-migrated", + "potential-data-loss" + ], + "type": "string" + }, + "DatabaseMetricsResponse": { + "description": "Response for the per-database metrics breakdown.", + "properties": { + "databases": { + "description": "One entry per database, sorted by the first metric descending\n(largest first) so the biggest database leads the table.", + "items": { + "$ref": "#/components/schemas/DatabaseMetricsRow" + }, + "type": "array" + } + }, + "required": [ + "databases" + ], + "type": "object" + }, + "DatabaseMetricsRow": { + "description": "Per-database metric values for a Postgres service.\n\nA Postgres instance can host many databases (some unrelated to this\nservice). The collector records per-`datname` series; this groups the\nlatest value of each requested metric by database so the UI can render a\n\"Databases\" breakdown table instead of one collapsed number.", + "properties": { + "database": { + "description": "Database name (`datname`).", + "type": "string" + }, + "metrics": { + "additionalProperties": { + "format": "double", + "type": "number" + }, + "description": "Latest value of each requested metric for this database\n(e.g. `{\"pg.database_size_bytes\": 7943871, \"pg.cache_hit_ratio\": 0.99}`).", + "propertyNames": { + "type": "string" + }, + "type": "object" + } + }, + "required": [ + "database", + "metrics" + ], + "type": "object" + }, + "DelRequest": { + "description": "Request to delete keys", + "properties": { + "keys": { + "description": "The key(s) to delete", + "example": [ + "user:123", + "user:456" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "project_id": { + "description": "Project ID (required for API key/session auth, optional for deployment tokens)", + "example": 1, + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + "required": [ + "keys" + ], + "type": "object" + }, + "DelResponse": { + "description": "Response for delete operation", + "properties": { + "deleted": { + "description": "Number of keys deleted", + "example": 2, + "format": "int64", + "type": "integer" + } + }, + "required": [ + "deleted" + ], + "type": "object" + }, + "DeleteBlobRequest": { + "description": "Request to delete blobs", + "properties": { + "pathnames": { + "description": "Pathnames to delete (relative to project)", + "example": [ + "images/avatar.png", + "documents/file.pdf" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "projectId": { + "description": "Project ID (required for API key/session auth, optional for deployment tokens)", + "example": 1, + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + "required": [ + "pathnames" + ], + "type": "object" + }, + "DeleteBlobResponse": { + "description": "Response after deleting blobs", + "properties": { + "deleted": { + "description": "Number of blobs deleted", + "example": 2, + "format": "int64", + "type": "integer" + } + }, + "required": [ + "deleted" + ], + "type": "object" + }, + "DeleteResponse": { + "properties": { + "deleted": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "deleted" + ], + "type": "object" + }, + "DeployFromImageRequest": { + "properties": { + "external_image_id": { + "description": "External image ID (if already registered). If provided without image_ref,\nthe image reference will be fetched from the registered external image.", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "health_check_path": { + "description": "Optional HTTP health-check path override (e.g. \"/api/healthz\").\nImage deploys can't read `.temps.yaml`, so this sets the path the deployer\nprobes after the container starts and the path the environment's uptime\nmonitor checks. Must start with '/'. When omitted, defaults to \"/\".", + "example": "/api/healthz", + "type": [ + "string", + "null" + ] + }, + "image_ref": { + "description": "Docker image reference (e.g., \"ghcr.io/org/app:v1.0\")\nRequired if external_image_id is not provided", + "example": "ghcr.io/myorg/myapp:v1.0", + "type": [ + "string", + "null" + ] + }, + "metadata": { + "description": "Optional deployment metadata" + } + }, + "type": "object" + }, + "DeployFromImageUploadQuery": { + "description": "Query parameters for deploying from an uploaded image tarball", + "properties": { + "health_check_path": { + "description": "Optional HTTP health-check path override (e.g. \"/api/healthz\").\nMust start with '/'. When omitted, defaults to \"/\".", + "example": "/api/healthz", + "type": [ + "string", + "null" + ] + }, + "tag": { + "description": "Tag to apply to the imported image (e.g., \"myapp:v1.0\")\nIf not provided, a unique tag will be generated", + "example": "myapp:v1.0", + "type": [ + "string", + "null" + ] + } + }, + "type": "object" + }, + "DeployFromStaticRequest": { + "properties": { + "health_check_path": { + "description": "Optional HTTP health-check path override (e.g. \"/api/healthz\").\nStatic deploys can't read `.temps.yaml`, so this sets the path the deployer\nprobes after the container starts and the path the environment's uptime\nmonitor checks. Must start with '/'. When omitted, defaults to \"/\".", + "example": "/api/healthz", + "type": [ + "string", + "null" + ] + }, + "metadata": { + "description": "Optional deployment metadata" + }, + "static_bundle_id": { + "description": "Static bundle ID (required)", + "format": "int32", + "type": "integer" + } + }, + "required": [ + "static_bundle_id" + ], + "type": "object" + }, + "DeploymentConfig": { + "description": "Deployment configuration shared between projects and environments\n\nThis configuration can be set at the project level (as defaults) and\noverridden at the environment level for specific deployments.\n\nNote: Environment variables are managed separately and are not part of this config.", + "properties": { + "antiAffinity": { + "description": "Anti-affinity: spread replicas across different nodes.\n\nWhen enabled, the scheduler avoids placing two replicas of the same\nenvironment on the same node. If there are fewer eligible nodes than\nreplicas, remaining replicas wrap around (best-effort spreading).\n\nDefaults to `true` — replicas spread by default.", + "type": "boolean" + }, + "automaticDeploy": { + "description": "Enable automatic deployments on git push.\n`None` = inherit from project config; `Some(true/false)` = explicit override.\nStored as JSONB so absent key → `None` (inherit), never silently defaults to false.", + "type": [ + "boolean", + "null" + ] + }, + "containerExecEnabled": { + "description": "Enable container exec/shell access (disabled by default for security)", + "type": "boolean" + }, + "cpuLimit": { + "description": "CPU limit in microcores, where 1_000_000 = 1 full CPU core\n(e.g., 2_000_000 = 2 CPUs). NOT millicores. `None` = uncapped.", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "cpuRequest": { + "description": "CPU request in microcores, where 1_000_000 = 1 full CPU core\n(e.g., 100_000 = 0.1 CPU, 500_000 = 0.5 CPU, 2_000_000 = 2 CPUs).\nNOT millicores — the deployer formats this as `{n}u` and converts\n`n / 1_000_000` cores into Docker nano_cpus.", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "crossArchitectureBuilds": { + "description": "Build one image per architecture the eligible nodes run.\n\n`None`/`false` (the default) builds exactly once, on the control\nplane's native platform — byte-for-byte the behaviour of a\nsingle-architecture cluster. When enabled and the nodes this\ndeployment could land on span more than one architecture, the build\njob produces one image per architecture; the non-native ones go\nthrough the daemon's `platform` option, which requires QEMU binfmt\nhandlers registered on the control plane.\n\n**Opt-in on purpose.** Cross-architecture builds are emulated and\nsubstantially slower, and deriving them from cluster topology would\nmean a single node joining silently changes build behaviour for every\ndeployment in the cluster. It also keeps the decision on operator\nconfig rather than on a value each node reports about itself.\n\n`Option` so an environment inherits the project's setting\n(`None`) or overrides it, matching `automatic_deploy`.", + "type": [ + "boolean", + "null" + ] + }, + "exposedPort": { + "description": "Port exposed by the container\nIf not specified, will be auto-detected from Docker image or default to 3000", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "idleTimeoutSeconds": { + "description": "Seconds of inactivity before containers are stopped in on-demand mode.\nOnly used when `on_demand` is true. Min: 60, Max: 86400 (24h).\nDefault: 300 (5 minutes).", + "format": "int32", + "type": "integer" + }, + "memoryLimit": { + "description": "Memory limit in megabytes. Three-state semantics:\n- `None` → inherit the parent layer (env inherits project, project\n inherits the seeded default); used by the settings UI's \"Use default\".\n- `Some(0)` → explicit **uncapped**: stop inheriting and run with no\n memory limit. This is the deliberate escape hatch for dedicated\n workloads, distinct from `None`.\n- `Some(n)` → hard cap of `n` MB.\n\n`merge`/resolution keep `Some(0)` as a present value (it wins precedence\nover a parent cap), and the deployer collapses it to \"no limit\" before\ntalking to Docker.", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "memoryRequest": { + "description": "Memory request in megabytes (e.g., 128 = 128MB)", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "onDemand": { + "description": "Enable on-demand mode (scale-to-zero).\nWhen enabled, containers are stopped after `idle_timeout_seconds` of no traffic\nand automatically started when a new request arrives.", + "type": "boolean" + }, + "performanceMetricsEnabled": { + "description": "Enable performance metrics collection (speed insights)", + "type": "boolean" + }, + "replicas": { + "description": "Number of replicas/instances to run\nDefaults to 1 replica", + "format": "int32", + "type": "integer" + }, + "security": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/SecurityConfig", + "description": "Security configuration (headers, rate limiting, attack mode, etc.)\nThese settings inherit and override from parent level (Environment > Project > Global)" + } + ] + }, + "sessionRecordingEnabled": { + "description": "Enable session recording for analytics", + "type": "boolean" + }, + "targetLabels": { + "description": "Label selector for node-based scheduling. Replicas are only deployed to\nnodes whose labels match the selector.\n\nMatching rules:\n- **Same key, array value** → OR: node must match any value\n- **Different keys** → AND: node must satisfy all keys\n\nExample: `{\"region\": [\"us\", \"asia\"], \"gpu\": \"true\"}`\n→ (region=us OR region=asia) AND gpu=true\n\nApplied after `target_nodes` filtering (they stack)." + }, + "targetNodes": { + "description": "Optional list of node IDs to deploy to. When set, replicas are distributed\nonly across these nodes (round-robin). When None, the scheduler distributes\nacross all active nodes (or deploys locally if no nodes exist).", + "items": { + "format": "int32", + "type": "integer" + }, + "type": [ + "array", + "null" + ] + }, + "wakeTimeoutSeconds": { + "description": "Max seconds to wait for containers to start when waking from on-demand sleep.\nRequests return 503 if exceeded. Default: 30.", + "format": "int32", + "type": "integer" + } + }, + "type": "object" + }, + "DeploymentConfigSnapshot": { + "description": "Deployment configuration snapshot for deployments\n\nThis extends DeploymentConfig with environment variables to capture\nthe complete state of a deployment at the time it was created.", + "properties": { + "automaticDeploy": { + "description": "Enable automatic deployments on git push", + "type": "boolean" + }, + "containerExecEnabled": { + "description": "Enable container exec/shell access", + "type": "boolean" + }, + "cpuLimit": { + "description": "CPU limit in millicores", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "cpuRequest": { + "description": "CPU request in millicores", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "environmentVariables": { + "additionalProperties": { + "type": "string" + }, + "description": "Environment variables used for this deployment", + "propertyNames": { + "type": "string" + }, + "type": "object" + }, + "exposedPort": { + "description": "Port exposed by the container", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "memoryLimit": { + "description": "Memory limit in megabytes", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "memoryRequest": { + "description": "Memory request in megabytes", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "performanceMetricsEnabled": { + "description": "Enable performance metrics collection", + "type": "boolean" + }, + "replicas": { + "description": "Number of replicas", + "format": "int32", + "type": "integer" + }, + "sessionRecordingEnabled": { + "description": "Enable session recording", + "type": "boolean" + } + }, + "type": "object" + }, + "DeploymentConfiguration": { + "description": "Deployment-level configuration", + "properties": { + "build": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/BuildConfiguration", + "description": "Build configuration (if building from source)" + } + ] + }, + "command": { + "description": "Command override", + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + }, + "entrypoint": { + "description": "Entrypoint override", + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + }, + "env_vars": { + "description": "Environment variables", + "items": { + "$ref": "#/components/schemas/EnvironmentVariable" + }, + "type": "array" + }, + "git": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/GitSourcePlan", + "description": "Where the application's source code lives, when the source platform\nbuilds from a git repository. Execution uses this to link the temps\nproject to the same repository so the real deployment pipeline can\nclone and build it." + } + ] + }, + "health_check": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/HealthCheckConfiguration", + "description": "Health check configuration" + } + ] + }, + "image": { + "description": "Image to deploy", + "type": "string" + }, + "network": { + "$ref": "#/components/schemas/NetworkConfiguration", + "description": "Network configuration" + }, + "ports": { + "description": "Port mappings", + "items": { + "$ref": "#/components/schemas/PortMapping" + }, + "type": "array" + }, + "resources": { + "$ref": "#/components/schemas/ResourceLimits", + "description": "Resource limits" + }, + "strategy": { + "$ref": "#/components/schemas/DeploymentStrategy", + "description": "Deployment strategy" + }, + "volumes": { + "description": "Volume mounts", + "items": { + "$ref": "#/components/schemas/VolumeMount" + }, + "type": "array" + }, + "working_dir": { + "description": "Working directory", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "image", + "strategy", + "env_vars", + "ports", + "volumes", + "network", + "resources" + ], + "type": "object" + }, + "DeploymentContainerLogContentResponse": { + "description": "A single captured container-log dump, including its full text content.", + "properties": { + "captured_at": { + "format": "int64", + "type": "integer" + }, + "container_name": { + "type": "string" + }, + "content": { + "description": "The captured plain-text log content.", + "type": "string" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "service_name": { + "type": [ + "string", + "null" + ] + }, + "size_bytes": { + "format": "int64", + "type": "integer" + }, + "truncated": { + "type": "boolean" + } + }, + "required": [ + "id", + "container_name", + "size_bytes", + "truncated", + "captured_at", + "content" + ], + "type": "object" + }, + "DeploymentContainerLogResponse": { + "description": "Metadata for one captured (historical) container-log dump. Listed on the\ndeployment detail page so a user can pick which past container's logs to read.", + "properties": { + "captured_at": { + "description": "Unix epoch milliseconds of when the logs were captured (just before\nteardown). Matches the timestamp convention used by `DeploymentResponse`.", + "format": "int64", + "type": "integer" + }, + "container_id": { + "type": "string" + }, + "container_name": { + "type": "string" + }, + "deployment_id": { + "format": "int32", + "type": "integer" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "node_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "service_name": { + "type": [ + "string", + "null" + ] + }, + "size_bytes": { + "format": "int64", + "type": "integer" + }, + "truncated": { + "type": "boolean" + } + }, + "required": [ + "id", + "deployment_id", + "container_id", + "container_name", + "size_bytes", + "truncated", + "captured_at" + ], + "type": "object" + }, + "DeploymentContainerLogsListResponse": { + "description": "The list of captured container-log dumps for a deployment.", + "properties": { + "logs": { + "items": { + "$ref": "#/components/schemas/DeploymentContainerLogResponse" + }, + "type": "array" + } + }, + "required": [ + "logs" + ], + "type": "object" + }, + "DeploymentEnvironmentResponse": { + "properties": { + "domains": { + "items": { + "type": "string" + }, + "type": "array" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "name": { + "type": "string" + }, + "slug": { + "type": "string" + } + }, + "required": [ + "id", + "name", + "slug", + "domains" + ], + "type": "object" + }, + "DeploymentJobResponse": { + "properties": { + "created_at": { + "format": "int64", + "type": "integer" + }, + "dependencies": {}, + "deployment_id": { + "format": "int32", + "type": "integer" + }, + "description": { + "type": [ + "string", + "null" + ] + }, + "error_message": { + "type": [ + "string", + "null" + ] + }, + "execution_order": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "finished_at": { + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "id": { + "format": "int32", + "type": "integer" + }, + "job_config": { + "description": "Internal workflow configuration is intentionally redacted. It can\ncontain legacy plaintext secrets or encrypted secret envelopes." + }, + "job_id": { + "type": "string" + }, + "job_type": { + "type": "string" + }, + "log_id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "outputs": {}, + "started_at": { + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "status": { + "type": "string" + }, + "updated_at": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "id", + "deployment_id", + "job_id", + "job_type", + "name", + "status", + "created_at", + "updated_at", + "log_id" + ], + "type": "object" + }, + "DeploymentJobsResponse": { + "properties": { + "jobs": { + "items": { + "$ref": "#/components/schemas/DeploymentJobResponse" + }, + "type": "array" + }, + "total": { + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "jobs", + "total" + ], + "type": "object" + }, + "DeploymentListResponse": { + "properties": { + "deployments": { + "items": { + "$ref": "#/components/schemas/DeploymentResponse" + }, + "type": "array" + }, + "page": { + "format": "int64", + "type": "integer" + }, + "per_page": { + "format": "int64", + "type": "integer" + }, + "total": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "deployments", + "total", + "page", + "per_page" + ], + "type": "object" + }, + "DeploymentMetadata": { + "description": "Deployment metadata - typed information about the deployment", + "properties": { + "buildDurationMs": { + "description": "Build duration in milliseconds", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "builder": { + "description": "Docker builder used (e.g., \"nixpacks\", \"dockerfile\")", + "type": [ + "string", + "null" + ] + }, + "deploymentDurationMs": { + "description": "Deployment duration in milliseconds", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "deploymentSourceType": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/SourceType", + "description": "Source type for THIS specific deployment (for Manual/flexible projects)\nThis allows Manual projects to have deployments via different methods\n(docker_image, static_files, or git) while keeping per-deployment tracking" + } + ] + }, + "dockerfilePath": { + "description": "Dockerfile path if using Dockerfile builder", + "type": [ + "string", + "null" + ] + }, + "externalImageId": { + "description": "External image ID (reference to external_images table)", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "externalImageRef": { + "description": "External Docker image reference (for docker_image source type)\ne.g., \"ghcr.io/org/app:v1.0\" or \"docker.io/myapp:sha-abc123\"", + "type": [ + "string", + "null" + ] + }, + "fileCount": { + "description": "Number of files in the build output", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "gitPushEvent": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/GitPushEvent", + "description": "Git push event that triggered this deployment (if from webhook)" + } + ] + }, + "healthCheckPath": { + "description": "Explicit deploy-time HTTP health-check path override.\nImage/static deploys can't read `.temps.yaml`, so this lets the deploy\nrequest set a custom path (e.g. \"/api/healthz\"). When present it takes\npriority over any `.temps.yaml` `health.path` value. Always starts with '/'.", + "type": [ + "string", + "null" + ] + }, + "imageSizeBytes": { + "description": "Total size of the built image in bytes", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "imageUploadedLocally": { + "description": "Whether the image was uploaded directly (via docker save/load) rather than pulled from registry\nWhen true, the PullExternalImageJob is skipped since the image is already loaded locally", + "type": "boolean" + }, + "isRollback": { + "description": "Whether this is a rollback deployment", + "type": "boolean" + }, + "labels": { + "description": "Custom labels/tags for the deployment", + "items": { + "type": "string" + }, + "type": "array" + }, + "rolledBackFromId": { + "description": "ID of the deployment this was rolled back from (if applicable)", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "staticBundleContentType": { + "description": "Static bundle content type (for proper extraction: application/gzip or application/zip)", + "type": [ + "string", + "null" + ] + }, + "staticBundleId": { + "description": "Static bundle ID (reference to static_bundles table, for static_files source type)", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "staticBundlePath": { + "description": "Static bundle path in blob storage (for static_files source type)", + "type": [ + "string", + "null" + ] + }, + "uploadedImageId": { + "description": "Docker image ID of the locally uploaded image (sha256:...)\nUsed to verify the image exists before deployment", + "type": [ + "string", + "null" + ] + } + }, + "type": "object" + }, + "DeploymentResponse": { + "properties": { + "branch": { + "type": [ + "string", + "null" + ] + }, + "cancelled_reason": { + "type": [ + "string", + "null" + ] + }, + "commit_author": { + "type": [ + "string", + "null" + ] + }, + "commit_date": { + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "commit_hash": { + "type": [ + "string", + "null" + ] + }, + "commit_message": { + "type": [ + "string", + "null" + ] + }, + "created_at": { + "format": "int64", + "type": "integer" + }, + "deployment_config": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/DeploymentConfigSnapshot", + "description": "Deployment configuration snapshot (CPU, memory, replicas, environment variables, etc.)" + } + ] + }, + "environment": { + "$ref": "#/components/schemas/DeploymentEnvironmentResponse" + }, + "environment_id": { + "format": "int32", + "type": "integer" + }, + "finished_at": { + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "id": { + "format": "int32", + "type": "integer" + }, + "is_current": { + "type": "boolean" + }, + "metadata": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/DeploymentMetadata", + "description": "Deployment metadata (build info, git event, etc.)" + } + ] + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "screenshot_location": { + "type": [ + "string", + "null" + ] + }, + "started_at": { + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "status": { + "type": "string" + }, + "tag": { + "type": [ + "string", + "null" + ] + }, + "url": { + "type": "string" + } + }, + "required": [ + "id", + "project_id", + "environment_id", + "environment", + "status", + "url", + "created_at", + "is_current" + ], + "type": "object" + }, + "DeploymentStateResponse": { + "properties": { + "id": { + "format": "int32", + "type": "integer" + }, + "message": { + "type": "string" + }, + "state": { + "type": "string" + } + }, + "required": [ + "id", + "state", + "message" + ], + "type": "object" + }, + "DeploymentStrategy": { + "description": "Deployment strategy", + "enum": [ + "replace", + "blue-green", + "rolling" + ], + "type": "string" + }, + "DeploymentTokenListResponse": { + "properties": { + "tokens": { + "items": { + "$ref": "#/components/schemas/DeploymentTokenResponse" + }, + "type": "array" + }, + "total": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "tokens", + "total" + ], + "type": "object" + }, + "DeploymentTokenResponse": { + "properties": { + "created_at": { + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": "string" + }, + "created_by": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "deployment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "expires_at": { + "example": "2024-12-31T23:59:59Z", + "format": "date-time", + "type": [ + "string", + "null" + ] + }, + "id": { + "format": "int32", + "type": "integer" + }, + "is_active": { + "type": "boolean" + }, + "last_used_at": { + "example": "2024-01-01T00:00:00Z", + "format": "date-time", + "type": [ + "string", + "null" + ] + }, + "name": { + "type": "string" + }, + "permissions": { + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "token_prefix": { + "type": "string" + } + }, + "required": [ + "id", + "project_id", + "name", + "token_prefix", + "is_active", + "created_at" + ], + "type": "object" + }, + "DetectionConfig": { + "description": "The typed detector definition stored (as jsonb) in\n`metric_alert_rules.detection_config`.\n\nToday only [`DetectionConfig::Static`] is evaluable; the other variants are\nschema-present (so the SDK/UI and storage are already future-shaped) but\nrejected by [`DetectionConfig::validate`] until their evaluator lands. Each is\nthen enabled code-only, with no schema migration.", + "oneOf": [ + { + "allOf": [ + { + "$ref": "#/components/schemas/StaticParams", + "description": "v0 (shipping): static threshold comparison of the aggregated value." + }, + { + "properties": { + "kind": { + "enum": [ + "static" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "type": "object" + } + ], + "description": "v0 (shipping): static threshold comparison of the aggregated value." + }, + { + "allOf": [ + { + "$ref": "#/components/schemas/AnomalyParams", + "description": "Seasonal anomaly band (basic/agile/robust/ewma share this variant — the\nalgorithm is a field, not a new kind). Creation rejected until evaluated." + }, + { + "properties": { + "kind": { + "enum": [ + "anomaly" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "type": "object" + } + ], + "description": "Seasonal anomaly band (basic/agile/robust/ewma share this variant — the\nalgorithm is a field, not a new kind). Creation rejected until evaluated." + }, + { + "allOf": [ + { + "$ref": "#/components/schemas/ForecastParams", + "description": "Predict a future threshold breach (capacity planning). Stub." + }, + { + "properties": { + "kind": { + "enum": [ + "forecast" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "type": "object" + } + ], + "description": "Predict a future threshold breach (capacity planning). Stub." + }, + { + "allOf": [ + { + "$ref": "#/components/schemas/OutlierParams", + "description": "Cross-series population outlier (one host misbehaving vs its peers). Stub." + }, + { + "properties": { + "kind": { + "enum": [ + "outlier" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "type": "object" + } + ], + "description": "Cross-series population outlier (one host misbehaving vs its peers). Stub." + }, + { + "allOf": [ + { + "$ref": "#/components/schemas/AutoWatchParams", + "description": "Watchdog-style self-tuning auto-watch (engine picks bounds). Stub." + }, + { + "properties": { + "kind": { + "enum": [ + "auto_watch" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "type": "object" + } + ], + "description": "Watchdog-style self-tuning auto-watch (engine picks bounds). Stub." + } + ] + }, + "DeviceCount": { + "properties": { + "count": { + "format": "int64", + "type": "integer" + }, + "device_type": { + "type": "string" + }, + "percentage": { + "format": "double", + "type": "number" + } + }, + "required": [ + "device_type", + "count", + "percentage" + ], + "type": "object" + }, + "DigestSections": { + "description": "Sections that can be included in the weekly digest\nNote: `#[serde(default)]` allows backward compatibility when deserializing\nold data that may have `security` and `resources` fields instead of `projects`", + "properties": { + "deployments": { + "default": true, + "type": "boolean" + }, + "errors": { + "default": true, + "type": "boolean" + }, + "funnels": { + "default": true, + "type": "boolean" + }, + "performance": { + "default": true, + "type": "boolean" + }, + "projects": { + "default": true, + "type": "boolean" + } + }, + "type": "object" + }, + "Direction": { + "description": "Which side(s) of an anomaly band count as a deviation.", + "enum": [ + "both", + "above", + "below" + ], + "type": "string" + }, + "DisableBlobResponse": { + "description": "Response after disabling Blob service", + "properties": { + "message": { + "description": "Human-readable message", + "example": "Blob service disabled successfully", + "type": "string" + }, + "success": { + "description": "Whether the operation succeeded", + "example": true, + "type": "boolean" + } + }, + "required": [ + "success", + "message" + ], + "type": "object" + }, + "DisableKvResponse": { + "description": "Response after disabling KV service", + "properties": { + "message": { + "description": "Status message", + "example": "KV service disabled successfully", + "type": "string" + }, + "success": { + "description": "Whether the service was successfully disabled", + "type": "boolean" + } + }, + "required": [ + "success", + "message" + ], + "type": "object" + }, + "DisableMfaRequest": { + "properties": { + "code": { + "type": "string" + } + }, + "required": [ + "code" + ], + "type": "object" + }, + "DiscoverRequest": { + "description": "Request to discover workloads", + "properties": { + "credentials": { + "$ref": "#/components/schemas/ImportCredentials", + "description": "Platform credentials (required for cloud platforms like Vercel, Railway)" + }, + "selector": { + "$ref": "#/components/schemas/ImportSelector", + "description": "Optional selector to filter workloads" + }, + "source": { + "$ref": "#/components/schemas/ImportSource", + "description": "Source to discover from" + } + }, + "required": [ + "source" + ], + "type": "object" + }, + "DiscoverResponse": { + "description": "Response with discovered workloads", + "properties": { + "workloads": { + "description": "Discovered workloads", + "items": { + "$ref": "#/components/schemas/WorkloadDescriptor" + }, + "type": "array" + } + }, + "required": [ + "workloads" + ], + "type": "object" + }, + "DiskInfo": { + "description": "Disk space information for a single disk/partition", + "properties": { + "available_bytes": { + "description": "Available space in bytes", + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "file_system": { + "description": "File system type (e.g., \"ext4\", \"apfs\")", + "type": "string" + }, + "mount_point": { + "description": "Mount point of the disk", + "type": "string" + }, + "total_bytes": { + "description": "Total space in bytes", + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "usage_percent": { + "description": "Usage percentage (0-100)", + "format": "double", + "type": "number" + }, + "used_bytes": { + "description": "Used space in bytes", + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "mount_point", + "total_bytes", + "used_bytes", + "available_bytes", + "usage_percent", + "file_system" + ], + "type": "object" + }, + "DiskSpaceAlert": { + "description": "Alert for a disk that exceeds the threshold", + "properties": { + "available_bytes": { + "description": "Available space in bytes", + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "available_human": { + "description": "Human-readable available space", + "type": "string" + }, + "mount_point": { + "description": "Mount point of the disk", + "type": "string" + }, + "threshold_percent": { + "description": "Configured threshold percentage", + "format": "int32", + "minimum": 0, + "type": "integer" + }, + "usage_percent": { + "description": "Current usage percentage", + "format": "double", + "type": "number" + } + }, + "required": [ + "mount_point", + "usage_percent", + "threshold_percent", + "available_bytes", + "available_human" + ], + "type": "object" + }, + "DiskSpaceAlertSettings": { + "description": "Disk space alert settings for monitoring disk usage", + "properties": { + "check_interval_seconds": { + "default": 300, + "description": "Interval in seconds between disk space checks", + "example": 300, + "format": "int64", + "minimum": 60, + "type": "integer" + }, + "enabled": { + "default": true, + "description": "Whether disk space alerts are enabled", + "type": "boolean" + }, + "monitor_path": { + "default": null, + "description": "Restrict monitoring to the disk backing this path. When unset (the\ndefault), every mounted writable volume is monitored — including\ndedicated volumes such as `/var/lib/docker`.", + "type": [ + "string", + "null" + ] + }, + "threshold_percent": { + "default": 80, + "description": "Threshold percentage (0-100) at which to trigger alerts", + "example": 80, + "format": "int32", + "maximum": 100, + "minimum": 0, + "type": "integer" + } + }, + "type": "object" + }, + "DiskSpaceCheckResult": { + "description": "Result of a disk space check", + "properties": { + "alerts": { + "description": "Disks that meet or exceed the threshold", + "items": { + "$ref": "#/components/schemas/DiskSpaceAlert" + }, + "type": "array" + }, + "checked_at": { + "description": "Timestamp of the check (ISO 8601, UTC)", + "example": "2026-05-28T12:15:47.609192Z", + "format": "date-time", + "type": "string" + }, + "disks": { + "description": "List of all monitored disks", + "items": { + "$ref": "#/components/schemas/DiskInfo" + }, + "type": "array" + }, + "enabled": { + "description": "Whether disk space monitoring is enabled in settings", + "type": "boolean" + }, + "threshold_percent": { + "description": "Configured alert threshold percentage (0-100)", + "format": "int32", + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "checked_at", + "enabled", + "threshold_percent", + "disks", + "alerts" + ], + "type": "object" + }, + "DnsAckRequest": { + "properties": { + "applied_generation": { + "description": "Highest generation the agent has actually applied locally.", + "format": "int64", + "type": "integer" + } + }, + "required": [ + "applied_generation" + ], + "type": "object" + }, + "DnsAckResponse": { + "properties": { + "applied_generation": { + "format": "int64", + "type": "integer" + }, + "node_id": { + "format": "int32", + "type": "integer" + }, + "server_generation": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "node_id", + "applied_generation", + "server_generation" + ], + "type": "object" + }, + "DnsChallengeRecordResult": { + "description": "Result of a single DNS TXT record creation for ACME challenge", + "properties": { + "message": { + "description": "Human-readable message about the operation", + "type": "string" + }, + "name": { + "description": "TXT record name (e.g., \"_acme-challenge.example.com\")", + "example": "_acme-challenge.example.com", + "type": "string" + }, + "success": { + "description": "Whether the record was created successfully", + "type": "boolean" + }, + "value": { + "description": "TXT record value (the ACME challenge token)", + "example": "abc123...", + "type": "string" + } + }, + "required": [ + "name", + "value", + "success", + "message" + ], + "type": "object" + }, + "DnsChangesResponse": { + "properties": { + "full_snapshot": { + "description": "`true` ⇒ replace the local zone with `records`. `false` ⇒ merge\n`records` into the existing zone (and remove `removed_ids`).", + "type": "boolean" + }, + "generation": { + "description": "Highest generation included in this response. Agent ACKs this back.", + "format": "int64", + "type": "integer" + }, + "records": { + "items": { + "$ref": "#/components/schemas/EndpointDto" + }, + "type": "array" + }, + "removed_ids": { + "description": "IDs the agent should remove from its zone. Always empty in the v1\nprotocol — the resolver reconciles by name on snapshot mode. Kept\nin the wire format so a future tombstone-based protocol doesn't\nrequire a breaking change.", + "items": { + "format": "int64", + "type": "integer" + }, + "type": "array" + } + }, + "required": [ + "generation", + "full_snapshot", + "records", + "removed_ids" + ], + "type": "object" + }, + "DnsCompletionResponse": { + "properties": { + "domain": { + "type": "string" + }, + "status": { + "type": "string" + } + }, + "required": [ + "domain", + "status" + ], + "type": "object" + }, + "DnsLookupError": { + "description": "Error response for DNS lookup failures", + "properties": { + "domain": { + "description": "Domain name that failed", + "example": "nonexistent.com", + "type": "string" + }, + "error": { + "description": "Error message", + "example": "DNS lookup failed: domain not found", + "type": "string" + } + }, + "required": [ + "error", + "domain" + ], + "type": "object" + }, + "DnsLookupRequest": { + "description": "Request to lookup DNS A records for a domain", + "properties": { + "domain": { + "description": "Domain name to lookup", + "example": "example.com", + "type": "string" + } + }, + "required": [ + "domain" + ], + "type": "object" + }, + "DnsLookupResponse": { + "description": "Response containing DNS A records", + "properties": { + "count": { + "description": "Number of records found", + "example": 1, + "minimum": 0, + "type": "integer" + }, + "dns_servers": { + "description": "DNS servers used for the lookup", + "example": [ + "8.8.8.8", + "8.8.4.4" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "domain": { + "description": "Domain name that was queried", + "example": "example.com", + "type": "string" + }, + "records": { + "description": "List of A record IP addresses", + "example": [ + "93.184.216.34" + ], + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "domain", + "records", + "count", + "dns_servers" + ], + "type": "object" + }, + "DnsProviderCredentials": { + "description": "DNS provider credentials (API-facing)", + "oneOf": [ + { + "properties": { + "account_id": { + "type": [ + "string", + "null" + ] + }, + "api_token": { + "example": "your-api-token", + "type": "string" + }, + "type": { + "enum": [ + "cloudflare" + ], + "type": "string" + } + }, + "required": [ + "api_token", + "type" + ], + "type": "object" + }, + { + "properties": { + "api_key": { + "example": "your-api-key", + "type": "string" + }, + "api_user": { + "example": "your-username", + "type": "string" + }, + "client_ip": { + "type": [ + "string", + "null" + ] + }, + "sandbox": { + "type": "boolean" + }, + "type": { + "enum": [ + "namecheap" + ], + "type": "string" + } + }, + "required": [ + "api_user", + "api_key", + "type" + ], + "type": "object" + }, + { + "properties": { + "access_key_id": { + "example": "AKIAIOSFODNN7EXAMPLE", + "type": "string" + }, + "region": { + "example": "us-east-1", + "type": [ + "string", + "null" + ] + }, + "secret_access_key": { + "example": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "type": "string" + }, + "session_token": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "route53" + ], + "type": "string" + } + }, + "required": [ + "access_key_id", + "secret_access_key", + "type" + ], + "type": "object" + }, + { + "properties": { + "api_token": { + "example": "dop_v1_your-token", + "type": "string" + }, + "type": { + "enum": [ + "digitalocean" + ], + "type": "string" + } + }, + "required": [ + "api_token", + "type" + ], + "type": "object" + }, + { + "properties": { + "private_key": { + "example": "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----", + "type": "string" + }, + "project_id": { + "example": "my-gcp-project", + "type": "string" + }, + "service_account_email": { + "example": "dns-admin@myproject.iam.gserviceaccount.com", + "type": "string" + }, + "type": { + "enum": [ + "gcp" + ], + "type": "string" + } + }, + "required": [ + "service_account_email", + "private_key", + "project_id", + "type" + ], + "type": "object" + }, + { + "properties": { + "client_id": { + "example": "00000000-0000-0000-0000-000000000000", + "type": "string" + }, + "client_secret": { + "type": "string" + }, + "resource_group": { + "example": "my-resource-group", + "type": "string" + }, + "subscription_id": { + "example": "00000000-0000-0000-0000-000000000000", + "type": "string" + }, + "tenant_id": { + "example": "00000000-0000-0000-0000-000000000000", + "type": "string" + }, + "type": { + "enum": [ + "azure" + ], + "type": "string" + } + }, + "required": [ + "tenant_id", + "client_id", + "client_secret", + "subscription_id", + "resource_group", + "type" + ], + "type": "object" + }, + { + "description": "Pebble challtestsrv mock DNS (LOCAL DEV/TEST ONLY)", + "properties": { + "management_url": { + "example": "http://localhost:8055", + "type": "string" + }, + "type": { + "enum": [ + "pebble" + ], + "type": "string" + } + }, + "required": [ + "management_url", + "type" + ], + "type": "object" + } + ] + }, + "DnsProviderResponse": { + "description": "DNS provider response", + "properties": { + "created_at": { + "type": "string" + }, + "credentials": { + "description": "Masked credentials for display" + }, + "description": { + "type": [ + "string", + "null" + ] + }, + "flat_hostnames_supported": { + "description": "Whether this provider benefits from the flat hostname mode (e.g. Cloudflare\nUniversal SSL). The UI surfaces/recommends the Flat toggle when true.", + "type": "boolean" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "is_active": { + "type": "boolean" + }, + "last_error": { + "type": [ + "string", + "null" + ] + }, + "last_used_at": { + "type": [ + "string", + "null" + ] + }, + "name": { + "type": "string" + }, + "provider_type": { + "type": "string" + }, + "updated_at": { + "type": "string" + } + }, + "required": [ + "id", + "name", + "provider_type", + "credentials", + "is_active", + "flat_hostnames_supported", + "created_at", + "updated_at" + ], + "type": "object" + }, + "DnsProviderSettings": { + "properties": { + "cloudflare_api_key": { + "default": null, + "type": [ + "string", + "null" + ] + }, + "provider": { + "default": "manual", + "type": "string" + } + }, + "type": "object" + }, + "DnsProviderSettingsMasked": { + "description": "DNS provider settings with masked sensitive fields", + "properties": { + "cloudflare_api_key": { + "type": [ + "string", + "null" + ] + }, + "provider": { + "type": "string" + } + }, + "required": [ + "provider" + ], + "type": "object" + }, + "DnsProviderType": { + "description": "Supported DNS provider types", + "enum": [ + "cloudflare", + "namecheap", + "route53", + "digitalocean", + "gcp", + "azure", + "manual", + "pebble" + ], + "type": "string" + }, + "DnsRecord": { + "description": "A DNS record", + "properties": { + "content": { + "$ref": "#/components/schemas/DnsRecordContent", + "description": "Record content" + }, + "fqdn": { + "description": "Fully qualified domain name", + "example": "www.example.com", + "type": "string" + }, + "id": { + "description": "Provider-specific record ID (if exists)", + "example": "abc123", + "type": [ + "string", + "null" + ] + }, + "metadata": { + "additionalProperties": { + "type": "string" + }, + "description": "Provider-specific metadata", + "propertyNames": { + "type": "string" + }, + "type": "object" + }, + "name": { + "description": "Record name (without zone, e.g., \"www\" or \"@\" for root)", + "example": "www", + "type": "string" + }, + "proxied": { + "description": "Whether this record is proxied (Cloudflare-specific)", + "type": "boolean" + }, + "ttl": { + "description": "Time to live in seconds", + "example": 300, + "format": "int32", + "minimum": 0, + "type": "integer" + }, + "zone": { + "description": "Zone/domain this record belongs to", + "example": "example.com", + "type": "string" + } + }, + "required": [ + "zone", + "name", + "fqdn", + "content", + "ttl" + ], + "type": "object" + }, + "DnsRecordChange": { + "description": "A single DNS record change the Cloudflare sync would make.", + "properties": { + "action": { + "description": "`\"create\"`, `\"update\"`, or `\"delete\"`.", + "type": "string" + }, + "name": { + "type": "string" + }, + "record_type": { + "description": "Record type, e.g. `\"A\"` or `\"CNAME\"`.", + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "action", + "name", + "record_type", + "value" + ], + "type": "object" + }, + "DnsRecordContent": { + "description": "DNS record content - varies by record type", + "oneOf": [ + { + "description": "A record - IPv4 address (as string, e.g., \"192.0.2.1\")", + "properties": { + "type": { + "enum": [ + "A" + ], + "type": "string" + }, + "value": { + "description": "A record - IPv4 address (as string, e.g., \"192.0.2.1\")", + "properties": { + "address": { + "example": "192.0.2.1", + "type": "string" + } + }, + "required": [ + "address" + ], + "type": "object" + } + }, + "required": [ + "value", + "type" + ], + "type": "object" + }, + { + "description": "AAAA record - IPv6 address (as string, e.g., \"2001:db8::1\")", + "properties": { + "type": { + "enum": [ + "AAAA" + ], + "type": "string" + }, + "value": { + "description": "AAAA record - IPv6 address (as string, e.g., \"2001:db8::1\")", + "properties": { + "address": { + "example": "2001:db8::1", + "type": "string" + } + }, + "required": [ + "address" + ], + "type": "object" + } + }, + "required": [ + "value", + "type" + ], + "type": "object" + }, + { + "description": "CNAME record - canonical name", + "properties": { + "type": { + "enum": [ + "CNAME" + ], + "type": "string" + }, + "value": { + "description": "CNAME record - canonical name", + "properties": { + "target": { + "type": "string" + } + }, + "required": [ + "target" + ], + "type": "object" + } + }, + "required": [ + "value", + "type" + ], + "type": "object" + }, + { + "description": "TXT record - text content", + "properties": { + "type": { + "enum": [ + "TXT" + ], + "type": "string" + }, + "value": { + "description": "TXT record - text content", + "properties": { + "content": { + "type": "string" + } + }, + "required": [ + "content" + ], + "type": "object" + } + }, + "required": [ + "value", + "type" + ], + "type": "object" + }, + { + "description": "MX record - mail exchange", + "properties": { + "type": { + "enum": [ + "MX" + ], + "type": "string" + }, + "value": { + "description": "MX record - mail exchange", + "properties": { + "priority": { + "format": "int32", + "minimum": 0, + "type": "integer" + }, + "target": { + "type": "string" + } + }, + "required": [ + "priority", + "target" + ], + "type": "object" + } + }, + "required": [ + "value", + "type" + ], + "type": "object" + }, + { + "description": "NS record - nameserver", + "properties": { + "type": { + "enum": [ + "NS" + ], + "type": "string" + }, + "value": { + "description": "NS record - nameserver", + "properties": { + "nameserver": { + "type": "string" + } + }, + "required": [ + "nameserver" + ], + "type": "object" + } + }, + "required": [ + "value", + "type" + ], + "type": "object" + }, + { + "description": "SRV record - service", + "properties": { + "type": { + "enum": [ + "SRV" + ], + "type": "string" + }, + "value": { + "description": "SRV record - service", + "properties": { + "port": { + "format": "int32", + "minimum": 0, + "type": "integer" + }, + "priority": { + "format": "int32", + "minimum": 0, + "type": "integer" + }, + "target": { + "type": "string" + }, + "weight": { + "format": "int32", + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "priority", + "weight", + "port", + "target" + ], + "type": "object" + } + }, + "required": [ + "value", + "type" + ], + "type": "object" + }, + { + "description": "CAA record - certification authority authorization", + "properties": { + "type": { + "enum": [ + "CAA" + ], + "type": "string" + }, + "value": { + "description": "CAA record - certification authority authorization", + "properties": { + "flags": { + "format": "int32", + "minimum": 0, + "type": "integer" + }, + "tag": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "flags", + "tag", + "value" + ], + "type": "object" + } + }, + "required": [ + "value", + "type" + ], + "type": "object" + }, + { + "description": "PTR record - pointer", + "properties": { + "type": { + "enum": [ + "PTR" + ], + "type": "string" + }, + "value": { + "description": "PTR record - pointer", + "properties": { + "target": { + "type": "string" + } + }, + "required": [ + "target" + ], + "type": "object" + } + }, + "required": [ + "value", + "type" + ], + "type": "object" + } + ] + }, + "DnsRecordResponse": { + "properties": { + "name": { + "description": "DNS record name (host)", + "example": "temps._domainkey.example.com", + "type": "string" + }, + "priority": { + "description": "Priority (for MX records)", + "example": "10", + "format": "int32", + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "record_type": { + "description": "Record type: TXT, CNAME, MX", + "example": "TXT", + "type": "string" + }, + "status": { + "$ref": "#/components/schemas/DnsRecordStatusResponse", + "description": "Verification status: unknown, verified, pending, failed" + }, + "value": { + "description": "DNS record value", + "example": "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3...", + "type": "string" + } + }, + "required": [ + "record_type", + "name", + "value", + "status" + ], + "type": "object" + }, + "DnsRecordSetupResult": { + "description": "Result of a single DNS record creation", + "properties": { + "automatic": { + "description": "Whether the operation was automatic or manual", + "type": "boolean" + }, + "message": { + "description": "Human-readable message", + "type": "string" + }, + "name": { + "description": "Record name", + "type": "string" + }, + "record_type": { + "description": "Record type (TXT, CNAME, MX)", + "type": "string" + }, + "success": { + "description": "Whether the record was created successfully", + "type": "boolean" + } + }, + "required": [ + "record_type", + "name", + "success", + "automatic", + "message" + ], + "type": "object" + }, + "DnsRecordStatusResponse": { + "description": "DNS record verification status", + "enum": [ + "unknown", + "verified", + "pending", + "failed" + ], + "type": "string" + }, + "DnsZone": { + "description": "A DNS zone (domain managed by the provider)", + "properties": { + "id": { + "description": "Provider-specific zone ID", + "example": "zone123", + "type": "string" + }, + "metadata": { + "additionalProperties": { + "type": "string" + }, + "description": "Provider-specific metadata", + "propertyNames": { + "type": "string" + }, + "type": "object" + }, + "name": { + "description": "Zone name (domain)", + "example": "example.com", + "type": "string" + }, + "nameservers": { + "description": "Nameservers for this zone", + "items": { + "type": "string" + }, + "type": "array" + }, + "status": { + "description": "Zone status", + "example": "active", + "type": "string" + } + }, + "required": [ + "id", + "name", + "status", + "nameservers" + ], + "type": "object" + }, + "DockerComposePresetConfig": { + "description": "Configuration for Docker Compose deployments.", + "properties": { + "composeOverride": { + "description": "User-provided docker-compose.override.yml content.", + "type": [ + "string", + "null" + ] + }, + "composePath": { + "description": "Path to the Compose file relative to the project directory.", + "type": [ + "string", + "null" + ] + }, + "publicPorts": { + "description": "Compose service ports that should be publicly routed.", + "items": { + "$ref": "#/components/schemas/ComposePublicPort" + }, + "type": "array" + } + }, + "type": "object" + }, + "DockerRegistrySettings": { + "properties": { + "ca_certificate": { + "default": null, + "type": [ + "string", + "null" + ] + }, + "enabled": { + "default": false, + "type": "boolean" + }, + "password": { + "default": null, + "type": [ + "string", + "null" + ] + }, + "registry_url": { + "default": null, + "type": [ + "string", + "null" + ] + }, + "tls_verify": { + "default": true, + "type": "boolean" + }, + "username": { + "default": null, + "type": [ + "string", + "null" + ] + } + }, + "type": "object" + }, + "DockerRegistrySettingsMasked": { + "description": "Docker registry settings with masked sensitive fields", + "properties": { + "ca_certificate": { + "type": [ + "string", + "null" + ] + }, + "enabled": { + "type": "boolean" + }, + "password": { + "type": [ + "string", + "null" + ] + }, + "registry_url": { + "type": [ + "string", + "null" + ] + }, + "tls_verify": { + "type": "boolean" + }, + "username": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "enabled", + "tls_verify" + ], + "type": "object" + }, + "DockerfilePresetConfig": { + "description": "Configuration for Dockerfile preset\nAllows customizing the Dockerfile path and build context for Docker-based deployments", + "properties": { + "buildContext": { + "description": "Custom build context path (relative to repository root)\nIf not specified, uses the project's directory setting", + "example": "./api", + "type": [ + "string", + "null" + ] + }, + "dockerfilePath": { + "description": "Custom Dockerfile path (relative to build context)\nIf not specified, defaults to \"Dockerfile\" in the build context", + "example": "docker/Dockerfile", + "type": [ + "string", + "null" + ] + }, + "variant": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/DockerfileVariant", + "description": "Catalog variant. Normally omitted; `custom` selects the generated\nDockerfile compatibility preset." + } + ] + } + }, + "type": "object" + }, + "DockerfileVariant": { + "description": "Catalog variant persisted under the canonical Dockerfile preset.\n\nExisting rows predate this discriminator and therefore deserialize as\n[`DockerfileVariant::File`].", + "enum": [ + "file", + "custom" + ], + "type": "string" + }, + "DomainAction": { + "description": "What to do with a domain during migration", + "enum": [ + "import", + "skip" + ], + "type": "string" + }, + "DomainChallengeResponse": { + "properties": { + "domain": { + "type": "string" + }, + "status": { + "type": "string" + }, + "txt_records": { + "description": "Array of TXT records to add to DNS. For wildcards, multiple records are required.", + "items": { + "$ref": "#/components/schemas/TxtRecord" + }, + "type": "array" + } + }, + "required": [ + "domain", + "txt_records", + "status" + ], + "type": "object" + }, + "DomainEnvironmentResponse": { + "properties": { + "id": { + "format": "int32", + "type": "integer" + }, + "name": { + "type": "string" + }, + "slug": { + "type": "string" + } + }, + "required": [ + "id", + "name", + "slug" + ], + "type": "object" + }, + "DomainError": { + "properties": { + "code": { + "type": "string" + }, + "details": { + "type": [ + "string", + "null" + ] + }, + "message": { + "type": "string" + } + }, + "required": [ + "message", + "code" + ], + "type": "object" + }, + "DomainPlan": { + "description": "Plan for migrating a single custom domain", + "properties": { + "action": { + "$ref": "#/components/schemas/DomainAction", + "description": "What to do with this domain" + }, + "action_description": { + "description": "Human-readable explanation", + "type": "string" + }, + "domain": { + "description": "Full domain name", + "type": "string" + }, + "environment": { + "description": "Which environment to associate with (\"production\")", + "type": "string" + }, + "redirect_to": { + "description": "Redirect target (if this is a redirect domain)", + "type": [ + "string", + "null" + ] + }, + "replacement": { + "description": "The temps-side address that replaces this domain when it is skipped.\n\nSource-generated domains (sslip.io / traefik.me / platform subdomains)\nembed the source server's IP and would keep pointing at the old\nmachine — this tells the user where the app will be reachable on\ntemps instead.", + "type": [ + "string", + "null" + ] + }, + "status_code": { + "description": "Redirect status code", + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + "required": [ + "domain", + "environment", + "action", + "action_description" + ], + "type": "object" + }, + "DomainResponse": { + "properties": { + "certificate": { + "description": "The PEM-encoded certificate chain (can be displayed in browser or downloaded)", + "type": [ + "string", + "null" + ] + }, + "created_at": { + "format": "int64", + "type": "integer" + }, + "dns_challenge_token": { + "type": [ + "string", + "null" + ] + }, + "dns_challenge_value": { + "type": [ + "string", + "null" + ] + }, + "domain": { + "type": "string" + }, + "expiration_time": { + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "id": { + "format": "int32", + "type": "integer" + }, + "is_wildcard": { + "type": "boolean" + }, + "last_error": { + "type": [ + "string", + "null" + ] + }, + "last_error_type": { + "type": [ + "string", + "null" + ] + }, + "last_renewed": { + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "on_demand_backoff_until": { + "description": "On-demand TLS negative-cache deadline (epoch millis), when this hostname's\non-demand HTTP-01 issuance is in backoff after a failure (ADR-018 §4).\n`None` means no active backoff.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "status": { + "type": "string" + }, + "updated_at": { + "format": "int64", + "type": "integer" + }, + "verification_method": { + "type": "string" + } + }, + "required": [ + "id", + "domain", + "status", + "is_wildcard", + "verification_method", + "created_at", + "updated_at" + ], + "type": "object" + }, + "DrainNodeResponse": { + "properties": { + "affected_environments": { + "minimum": 0, + "type": "integer" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "message": { + "type": "string" + }, + "name": { + "type": "string" + }, + "status": { + "type": "string" + } + }, + "required": [ + "id", + "name", + "status", + "affected_environments", + "message" + ], + "type": "object" + }, + "DrainStatusResponse": { + "description": "Progress of a node drain operation.", + "properties": { + "can_remove": { + "description": "Can the node be safely removed?", + "type": "boolean" + }, + "drain_complete": { + "description": "Whether the drain is complete (all containers migrated)", + "type": "boolean" + }, + "message": { + "type": "string" + }, + "node_id": { + "format": "int32", + "type": "integer" + }, + "node_name": { + "type": "string" + }, + "remaining_containers": { + "description": "Number of containers still on this node", + "minimum": 0, + "type": "integer" + }, + "status": { + "type": "string" + } + }, + "required": [ + "node_id", + "node_name", + "status", + "remaining_containers", + "drain_complete", + "can_remove", + "message" + ], + "type": "object" + }, + "DropArchiveUpload": { + "properties": { + "file": { + "format": "binary", + "type": "string" + } + }, + "required": [ + "file" + ], + "type": "object" + }, + "DropInspectionResponse": { + "properties": { + "candidates": { + "items": { + "$ref": "#/components/schemas/DropPresetCandidate" + }, + "type": "array" + }, + "suggestedName": { + "type": "string" + } + }, + "required": [ + "suggestedName", + "candidates" + ], + "type": "object" + }, + "DropOffPoint": { + "description": "Drop-off point: pages where visitors leave the site", + "properties": { + "exit_count": { + "description": "Number of exits from this page", + "format": "int64", + "type": "integer" + }, + "exit_rate": { + "description": "Exit rate for this page (exit_count / total_views)", + "format": "double", + "type": "number" + }, + "page_path": { + "description": "The page path where visitors drop off", + "type": "string" + }, + "total_views": { + "description": "Total views of this page", + "format": "int64", + "type": "integer" + } + }, + "required": [ + "page_path", + "exit_count", + "total_views", + "exit_rate" + ], + "type": "object" + }, + "DropPresetCandidate": { + "properties": { + "confidence": { + "type": "string" + }, + "directory": { + "type": "string" + }, + "isStatic": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "preset": { + "type": "string" + }, + "reason": { + "type": "string" + } + }, + "required": [ + "directory", + "preset", + "label", + "confidence", + "reason", + "isStatic" + ], + "type": "object" + }, + "EmailConfig": { + "properties": { + "accept_invalid_certs": { + "type": "boolean" + }, + "from_address": { + "type": "string" + }, + "from_name": { + "type": [ + "string", + "null" + ] + }, + "password": { + "type": "string" + }, + "smtp_host": { + "type": "string" + }, + "smtp_port": { + "format": "int32", + "minimum": 0, + "type": "integer" + }, + "starttls_required": { + "type": "boolean" + }, + "tls_mode": { + "$ref": "#/components/schemas/TlsMode" + }, + "to_addresses": { + "items": { + "type": "string" + }, + "type": "array" + }, + "username": { + "type": "string" + } + }, + "required": [ + "smtp_host", + "smtp_port", + "username", + "password", + "from_address", + "to_addresses" + ], + "type": "object" + }, + "EmailDomainResponse": { + "properties": { + "created_at": { + "example": "2025-12-03T10:30:00Z", + "type": "string" + }, + "domain": { + "example": "updates.example.com", + "type": "string" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "last_verified_at": { + "type": [ + "string", + "null" + ] + }, + "provider_id": { + "format": "int32", + "type": "integer" + }, + "status": { + "example": "verified", + "type": "string" + }, + "updated_at": { + "example": "2025-12-03T10:30:00Z", + "type": "string" + }, + "verification_error": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "id", + "provider_id", + "domain", + "status", + "created_at", + "updated_at" + ], + "type": "object" + }, + "EmailDomainWithDnsResponse": { + "properties": { + "dns_records": { + "items": { + "$ref": "#/components/schemas/DnsRecordResponse" + }, + "type": "array" + }, + "domain": { + "$ref": "#/components/schemas/EmailDomainResponse" + } + }, + "required": [ + "domain", + "dns_records" + ], + "type": "object" + }, + "EmailProviderResponse": { + "properties": { + "created_at": { + "example": "2025-12-03T10:30:00Z", + "type": "string" + }, + "credentials": { + "description": "Masked credentials for display" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "is_active": { + "type": "boolean" + }, + "name": { + "example": "My AWS SES", + "type": "string" + }, + "provider_type": { + "$ref": "#/components/schemas/EmailProviderTypeRoute" + }, + "region": { + "example": "us-east-1", + "type": "string" + }, + "sns_topic_arn": { + "type": [ + "string", + "null" + ] + }, + "updated_at": { + "example": "2025-12-03T10:30:00Z", + "type": "string" + } + }, + "required": [ + "id", + "name", + "provider_type", + "region", + "is_active", + "credentials", + "created_at", + "updated_at" + ], + "type": "object" + }, + "EmailProviderTypeRoute": { + "enum": [ + "ses", + "scaleway", + "smtp" + ], + "type": "string" + }, + "EmailRequest": { + "description": "Request body carrying just an email address (password-reset request).", + "properties": { + "email": { + "type": "string" + } + }, + "required": [ + "email" + ], + "type": "object" + }, + "EmailResponse": { + "properties": { + "bcc_addresses": { + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + }, + "cc_addresses": { + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + }, + "click_count": { + "description": "Number of times links in the email were clicked", + "format": "int32", + "type": "integer" + }, + "created_at": { + "example": "2025-12-03T10:30:00Z", + "type": "string" + }, + "domain_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "error_message": { + "type": [ + "string", + "null" + ] + }, + "first_clicked_at": { + "description": "When a link was first clicked", + "type": [ + "string", + "null" + ] + }, + "first_opened_at": { + "description": "When the email was first opened", + "type": [ + "string", + "null" + ] + }, + "from_address": { + "example": "hello@updates.example.com", + "type": "string" + }, + "from_name": { + "type": [ + "string", + "null" + ] + }, + "headers": { + "additionalProperties": { + "type": "string" + }, + "propertyNames": { + "type": "string" + }, + "type": [ + "object", + "null" + ] + }, + "html_body": { + "type": [ + "string", + "null" + ] + }, + "id": { + "example": "550e8400-e29b-41d4-a716-446655440000", + "type": "string" + }, + "open_count": { + "description": "Number of times the email was opened", + "format": "int32", + "type": "integer" + }, + "project_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "provider_message_id": { + "type": [ + "string", + "null" + ] + }, + "reply_to": { + "type": [ + "string", + "null" + ] + }, + "sent_at": { + "type": [ + "string", + "null" + ] + }, + "status": { + "example": "sent", + "type": "string" + }, + "subject": { + "type": "string" + }, + "tags": { + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + }, + "text_body": { + "type": [ + "string", + "null" + ] + }, + "to_addresses": { + "items": { + "type": "string" + }, + "type": "array" + }, + "track_clicks": { + "description": "Whether click tracking is enabled", + "type": "boolean" + }, + "track_opens": { + "description": "Whether open tracking is enabled", + "type": "boolean" + }, + "tracked_html_body": { + "description": "The final HTML sent to the provider (with tracking pixel and rewritten links)", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "id", + "from_address", + "to_addresses", + "subject", + "status", + "created_at", + "track_opens", + "track_clicks", + "open_count", + "click_count" + ], + "type": "object" + }, + "EmailStatsResponse": { + "properties": { + "captured": { + "description": "Emails captured without sending (Mailhog mode - no provider configured)", + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "failed": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "queued": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "sent": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "total": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "total", + "sent", + "failed", + "queued", + "captured" + ], + "type": "object" + }, + "EmailStatusResponse": { + "properties": { + "email_configured": { + "type": "boolean" + }, + "oidc_providers": { + "items": { + "$ref": "#/components/schemas/OidcProviderSummary" + }, + "type": "array" + }, + "password_reset_available": { + "type": "boolean" + } + }, + "required": [ + "email_configured", + "password_reset_available", + "oidc_providers" + ], + "type": "object" + }, + "EmailTrackingResponse": { + "description": "Email tracking summary", + "properties": { + "click_count": { + "format": "int32", + "type": "integer" + }, + "email_id": { + "type": "string" + }, + "first_clicked_at": { + "type": [ + "string", + "null" + ] + }, + "first_opened_at": { + "type": [ + "string", + "null" + ] + }, + "links": { + "items": { + "$ref": "#/components/schemas/TrackedLinkResponse" + }, + "type": "array" + }, + "open_count": { + "format": "int32", + "type": "integer" + }, + "track_clicks": { + "type": "boolean" + }, + "track_opens": { + "type": "boolean" + }, + "unique_clicks": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "unique_opens": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "email_id", + "track_opens", + "track_clicks", + "open_count", + "click_count", + "unique_opens", + "unique_clicks", + "links" + ], + "type": "object" + }, + "EmailTrackingSetupResponse": { + "description": "Result of the one-click AWS-side event-tracking setup.", + "properties": { + "event_destination_attached": { + "description": "The SESv2 event destination (bounce/complaint/delivery) is attached\nto the `temps-tracking` configuration set.", + "type": "boolean" + }, + "subscription_requested": { + "description": "The webhook subscription was requested; SNS confirms it\nasynchronously through the webhook itself.", + "type": "boolean" + }, + "topic_arn": { + "example": "arn:aws:sns:us-east-1:123456789012:temps-email-events-1", + "type": "string" + }, + "webhook_url": { + "type": "string" + } + }, + "required": [ + "topic_arn", + "webhook_url", + "subscription_requested", + "event_destination_attached" + ], + "type": "object" + }, + "EmailTrackingStatusResponse": { + "description": "Live status of the SES event-tracking pipeline for one provider.", + "properties": { + "last_event_at": { + "description": "Most recent delivered/bounced/complained event recorded for an email\nsent through this provider. `null` means no provider feedback has\narrived yet.", + "example": "2026-07-18T10:31:00Z", + "type": [ + "string", + "null" + ] + }, + "sns_topic_arn": { + "type": [ + "string", + "null" + ] + }, + "subscription_confirmed_at": { + "description": "When the SNS subscription for the current topic was confirmed.\n`null` with a topic set usually means the subscription is still\npending — most often because the endpoint was subscribed before the\ntopic ARN was saved here.", + "example": "2026-07-18T10:30:00Z", + "type": [ + "string", + "null" + ] + }, + "supports_event_tracking": { + "description": "Only SES providers support SNS event tracking.", + "type": "boolean" + }, + "webhook_url": { + "description": "Public webhook endpoint SNS must deliver events to.", + "example": "https://temps.example.com/api/t/webhook/ses", + "type": "string" + } + }, + "required": [ + "webhook_url", + "supports_event_tracking" + ], + "type": "object" + }, + "EmbeddingData": { + "properties": { + "embedding": { + "items": { + "format": "double", + "type": "number" + }, + "type": "array" + }, + "index": { + "format": "int32", + "type": "integer" + }, + "object": { + "type": "string" + } + }, + "required": [ + "object", + "embedding", + "index" + ], + "type": "object" + }, + "EmbeddingInput": { + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ] + }, + "EmbeddingRequest": { + "properties": { + "dimensions": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "encoding_format": { + "type": [ + "string", + "null" + ] + }, + "input": { + "$ref": "#/components/schemas/EmbeddingInput" + }, + "model": { + "type": "string" + } + }, + "required": [ + "model", + "input" + ], + "type": "object" + }, + "EmbeddingResponse": { + "properties": { + "data": { + "items": { + "$ref": "#/components/schemas/EmbeddingData" + }, + "type": "array" + }, + "model": { + "type": "string" + }, + "object": { + "type": "string" + }, + "usage": { + "$ref": "#/components/schemas/EmbeddingUsage" + } + }, + "required": [ + "object", + "data", + "model", + "usage" + ], + "type": "object" + }, + "EmbeddingUsage": { + "properties": { + "prompt_tokens": { + "format": "int64", + "type": "integer" + }, + "total_tokens": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "prompt_tokens", + "total_tokens" + ], + "type": "object" + }, + "EnableBlobRequest": { + "description": "Request to enable Blob service", + "properties": { + "docker_image": { + "description": "Docker image to use (optional, defaults to RustFS)", + "example": "ghcr.io/rustfs/rustfs:0.5.0", + "type": [ + "string", + "null" + ] + }, + "root_password": { + "description": "Root password for S3 access", + "type": [ + "string", + "null" + ] + }, + "root_user": { + "description": "Root user for S3 access", + "type": [ + "string", + "null" + ] + } + }, + "type": "object" + }, + "EnableBlobResponse": { + "description": "Response after enabling Blob service", + "properties": { + "message": { + "description": "Human-readable message", + "example": "Blob service enabled successfully", + "type": "string" + }, + "status": { + "$ref": "#/components/schemas/BlobStatusResponse", + "description": "Current status" + }, + "success": { + "description": "Whether the operation succeeded", + "example": true, + "type": "boolean" + } + }, + "required": [ + "success", + "message", + "status" + ], + "type": "object" + }, + "EnableKvRequest": { + "description": "Request to enable the KV service", + "properties": { + "docker_image": { + "description": "Docker image to use (optional, uses default if not provided)", + "example": "gotempsh/redis-walg:8-bookworm", + "type": [ + "string", + "null" + ] + }, + "max_memory": { + "description": "Maximum memory allocation (e.g., \"256mb\", \"1gb\")", + "example": "256mb", + "type": [ + "string", + "null" + ] + }, + "persistence": { + "description": "Enable data persistence", + "type": "boolean" + } + }, + "type": "object" + }, + "EnableKvResponse": { + "description": "Response after enabling KV service", + "properties": { + "message": { + "description": "Status message", + "example": "KV service enabled successfully", + "type": "string" + }, + "status": { + "$ref": "#/components/schemas/KvStatusResponse", + "description": "Current service status" + }, + "success": { + "description": "Whether the service was successfully enabled", + "type": "boolean" + } + }, + "required": [ + "success", + "message", + "status" + ], + "type": "object" + }, + "EnablePgStatStatementsResponse": { + "description": "Response for the enable pg_stat_statements endpoint.", + "properties": { + "message": { + "description": "Human-readable message confirming the action.", + "type": "string" + } + }, + "required": [ + "message" + ], + "type": "object" + }, + "EndpointDto": { + "description": "One DNS record on the wire. Mirrors `service_endpoints::Model` but\nkeeps the API stable across entity evolution. `target_ip` is a string\n(v4 or v6 literal, or CNAME target hostname) parsed by the resolver.", + "properties": { + "fqdn": { + "type": "string" + }, + "generation": { + "format": "int64", + "type": "integer" + }, + "id": { + "format": "int64", + "type": "integer" + }, + "node_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "owner_id": { + "format": "int64", + "type": "integer" + }, + "owner_kind": { + "type": "string" + }, + "record_type": { + "type": "string" + }, + "target_ip": { + "type": [ + "string", + "null" + ] + }, + "target_port": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "ttl": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "id", + "fqdn", + "record_type", + "ttl", + "owner_kind", + "owner_id", + "generation" + ], + "type": "object" + }, + "EnqueuedJob": { + "description": "A single job that was successfully enqueued during a fan-out run.", + "properties": { + "backup_id": { + "description": "FK to `backups.id` for this job.", + "format": "int32", + "type": "integer" + }, + "engine": { + "description": "Engine key (e.g. `\"control_plane\"`, `\"redis\"`, `\"postgres_pgdump\"`).", + "type": "string" + }, + "job_id": { + "description": "FK to `backup_jobs.id` for this job.", + "format": "int64", + "type": "integer" + }, + "target_service_id": { + "description": "FK to `external_services.id` when this is an external-service job.\n`None` for the control-plane job.", + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + "required": [ + "backup_id", + "job_id", + "engine" + ], + "type": "object" + }, + "EnrichVisitorRequest": { + "properties": { + "custom_data": { + "type": "object" + } + }, + "required": [ + "custom_data" + ], + "type": "object" + }, + "EnrichVisitorResponse": { + "properties": { + "message": { + "type": "string" + }, + "success": { + "type": "boolean" + }, + "visitor_id": { + "type": "string" + } + }, + "required": [ + "success", + "visitor_id", + "message" + ], + "type": "object" + }, + "EnrollmentTokenInfo": { + "properties": { + "bound_node_name": { + "type": [ + "string", + "null" + ] + }, + "created_at": { + "type": "string" + }, + "expires_at": { + "type": "string" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "max_uses": { + "format": "int32", + "type": "integer" + }, + "used_count": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "id", + "expires_at", + "used_count", + "max_uses", + "created_at" + ], + "type": "object" + }, + "EnrollmentTokenListResponse": { + "properties": { + "tokens": { + "items": { + "$ref": "#/components/schemas/EnrollmentTokenInfo" + }, + "type": "array" + } + }, + "required": [ + "tokens" + ], + "type": "object" + }, + "EntityInfoResponse": { + "properties": { + "container_path": { + "description": "Full container path", + "example": [ + "mydb", + "public" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "entity": { + "description": "Entity name", + "example": "users", + "type": "string" + }, + "entity_type": { + "description": "Entity type", + "example": "table", + "type": "string" + }, + "fields": { + "description": "Field definitions", + "items": { + "$ref": "#/components/schemas/FieldResponse" + }, + "type": "array" + }, + "metadata": { + "description": "Additional metadata (content_type, last_modified, etag, etc.)" + }, + "row_count": { + "description": "Approximate row count (for tables/collections)", + "example": 1234, + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "size_bytes": { + "description": "Size in bytes (for objects/files)", + "example": 1048576, + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "sort_schema": { + "description": "JSON Schema for sort options (if supported)" + } + }, + "required": [ + "container_path", + "entity", + "entity_type", + "fields" + ], + "type": "object" + }, + "EntityResponse": { + "properties": { + "entity_type": { + "description": "Entity type (table, view, collection, etc.)", + "example": "table", + "type": "string" + }, + "name": { + "description": "Entity name (table/collection)", + "example": "users", + "type": "string" + }, + "row_count": { + "description": "Approximate row count", + "example": 1234, + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "size_bytes": { + "description": "Size in bytes (for files/objects)", + "example": 1048576, + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + } + }, + "required": [ + "name", + "entity_type" + ], + "type": "object" + }, + "EnvVarInput": { + "description": "Input for environment variable", + "properties": { + "name": { + "description": "Variable name", + "type": "string" + }, + "value": { + "description": "Variable value", + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "EnvVarIntegrationInfo": { + "properties": { + "service_id": { + "format": "int32", + "type": "integer" + }, + "service_name": { + "type": "string" + }, + "service_slug": { + "type": [ + "string", + "null" + ] + }, + "service_type": { + "type": "string" + }, + "service_updated_at": { + "type": "string" + } + }, + "required": [ + "service_id", + "service_name", + "service_type", + "service_updated_at" + ], + "type": "object" + }, + "EnvVarResponse": { + "description": "Environment variable with masked sensitive values", + "properties": { + "is_masked": { + "description": "Whether this is a sensitive/masked value", + "type": "boolean" + }, + "key": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "key", + "value", + "is_masked" + ], + "type": "object" + }, + "EnvVarTemplateResponse": { + "description": "Environment variable template response", + "properties": { + "default": { + "description": "Default value if not provided by user", + "type": [ + "string", + "null" + ] + }, + "default_generator": { + "description": "Frontend-side generator hint for the default value\n(e.g. `app_url`, `random_secret`, `random_hex_32`)", + "type": [ + "string", + "null" + ] + }, + "description": { + "description": "Description of what this variable is used for", + "type": [ + "string", + "null" + ] + }, + "example": { + "description": "Example value for documentation", + "type": [ + "string", + "null" + ] + }, + "name": { + "description": "Name of the environment variable", + "type": "string" + }, + "required": { + "description": "Whether this variable is required", + "type": "boolean" + } + }, + "required": [ + "name", + "required" + ], + "type": "object" + }, + "EnvironmentConfiguration": { + "description": "Environment-level configuration", + "properties": { + "name": { + "description": "Environment name", + "type": "string" + }, + "resources": { + "$ref": "#/components/schemas/ResourceLimits", + "description": "Resource limits for environment" + }, + "subdomain": { + "description": "Proposed subdomain", + "type": "string" + } + }, + "required": [ + "name", + "subdomain", + "resources" + ], + "type": "object" + }, + "EnvironmentDomainResponse": { + "properties": { + "created_at": { + "format": "int64", + "type": "integer" + }, + "domain": { + "type": "string" + }, + "environment_id": { + "format": "int32", + "type": "integer" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "url": { + "description": "Full URL for this domain (e.g., https://buildtolearndev-production.example.com)", + "example": "https://buildtolearndev-production.example.com", + "type": "string" + } + }, + "required": [ + "id", + "environment_id", + "domain", + "created_at", + "url" + ], + "type": "object" + }, + "EnvironmentInfo": { + "properties": { + "current_deployment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "id": { + "format": "int32", + "type": "integer" + }, + "main_url": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "id", + "name", + "main_url" + ], + "type": "object" + }, + "EnvironmentResponse": { + "properties": { + "attack_mode": { + "description": "Per-environment CAPTCHA attack-mode override.\n`null` means inherit the project-level `attack_mode`; `true`/`false`\nexplicitly enable/disable the challenge for this environment. Always\nserialized (NOT skipped) so the UI can distinguish `null` from `false`.", + "type": [ + "boolean", + "null" + ] + }, + "branch": { + "type": [ + "string", + "null" + ] + }, + "created_at": { + "format": "int64", + "type": "integer" + }, + "current_deployment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "deployment_config": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/DeploymentConfig", + "description": "Deployment configuration for this environment (overrides project-level config)" + } + ] + }, + "estimated_sleep_at": { + "description": "Estimated time (epoch millis) when the environment will go to sleep\nbased on last activity + idle timeout. NULL when sleeping or on-demand disabled.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "force_https": { + "description": "Per-environment HTTP→HTTPS redirect override.\n`null` means inherit the proxy default (redirect only when the host has\nan active TLS certificate); `true` always redirects plain HTTP for this\nenvironment, `false` never does. Always serialized (NOT skipped) so the\nUI can distinguish `null` from `false`.", + "type": [ + "boolean", + "null" + ] + }, + "id": { + "format": "int32", + "type": "integer" + }, + "is_preview": { + "description": "Indicates if this is a preview environment (auto-created per branch)\nFor preview environments, 'branch' contains the feature branch name", + "type": "boolean" + }, + "last_activity_at": { + "description": "Last proxied request timestamp (epoch millis) for on-demand environments.\nNULL when on-demand is disabled or no traffic has been received yet.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "main_url": { + "type": "string" + }, + "name": { + "type": "string" + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "protected": { + "description": "When true, git pushes do NOT auto-deploy to this environment.\nDeployments must be promoted from another environment.", + "type": "boolean" + }, + "sleeping": { + "description": "When true, the environment's containers are currently stopped due to\ninactivity (on-demand mode) and will start on the next request.", + "type": "boolean" + }, + "slug": { + "type": "string" + }, + "subdomain": { + "description": "The host label stored for this environment (e.g.\n`myproject-production`). This is the prefix that is combined with the\nplatform's preview domain at request time to produce `main_url`. Edit\nthis via the rename-subdomain endpoint, not the full URL.", + "type": "string" + }, + "updated_at": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "id", + "project_id", + "name", + "slug", + "main_url", + "subdomain", + "created_at", + "updated_at", + "is_preview", + "protected", + "sleeping" + ], + "type": "object" + }, + "EnvironmentVariable": { + "description": "Environment variable", + "properties": { + "is_secret": { + "description": "Whether this is a secret (should be encrypted)", + "type": "boolean" + }, + "key": { + "description": "Variable name", + "type": "string" + }, + "source_description": { + "description": "Where this env var originates from (for traceability)", + "type": [ + "string", + "null" + ] + }, + "value": { + "description": "Variable value (may be redacted for secrets)", + "type": "string" + } + }, + "required": [ + "key", + "value", + "is_secret" + ], + "type": "object" + }, + "EnvironmentVariableInfo": { + "properties": { + "name": { + "type": "string" + }, + "sensitive": { + "description": "Whether this variable contains sensitive data (passwords, keys, tokens)", + "example": false, + "type": "boolean" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value", + "sensitive" + ], + "type": "object" + }, + "EnvironmentVariableResponse": { + "properties": { + "created_at": { + "format": "int64", + "type": "integer" + }, + "environments": { + "items": { + "$ref": "#/components/schemas/EnvironmentInfo" + }, + "type": "array" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "include_in_preview": { + "description": "Include this environment variable in preview environments", + "type": "boolean" + }, + "is_secret": { + "description": "Whether the variable is a write-only secret. Secrets always have\n`value: None` in responses.", + "type": "boolean" + }, + "key": { + "type": "string" + }, + "updated_at": { + "format": "int64", + "type": "integer" + }, + "value": { + "description": "Plaintext value for non-secret vars (or `\"***\"` mask for list responses).\n`None` for secret vars — secrets are write-only.", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "id", + "key", + "created_at", + "updated_at", + "environments", + "include_in_preview", + "is_secret" + ], + "type": "object" + }, + "EnvironmentVariableValueResponse": { + "properties": { + "value": { + "type": "string" + } + }, + "required": [ + "value" + ], + "type": "object" + }, + "ErrorDashboardStatsQuery": { + "properties": { + "compare_to_previous": { + "type": [ + "boolean", + "null" + ] + }, + "end_time": { + "format": "date-time", + "type": "string" + }, + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "start_time": { + "format": "date-time", + "type": "string" + } + }, + "required": [ + "start_time", + "end_time" + ], + "type": "object" + }, + "ErrorDashboardStatsResponse": { + "properties": { + "comparison_end_time": { + "format": "date-time", + "type": [ + "string", + "null" + ] + }, + "comparison_start_time": { + "format": "date-time", + "type": [ + "string", + "null" + ] + }, + "end_time": { + "format": "date-time", + "type": "string" + }, + "error_groups": { + "format": "int64", + "type": "integer" + }, + "error_groups_previous_period": { + "format": "int64", + "type": "integer" + }, + "start_time": { + "format": "date-time", + "type": "string" + }, + "total_errors": { + "format": "int64", + "type": "integer" + }, + "total_errors_change_percent": { + "format": "double", + "type": "number" + }, + "total_errors_previous_period": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "total_errors", + "total_errors_previous_period", + "total_errors_change_percent", + "error_groups", + "error_groups_previous_period", + "start_time", + "end_time" + ], + "type": "object" + }, + "ErrorEventResponse": { + "properties": { + "created_at": { + "type": "string" + }, + "data": { + "description": "Full error event data (contains raw Sentry event or custom error data)" + }, + "error_group_id": { + "format": "int32", + "type": "integer" + }, + "id": { + "format": "int64", + "type": "integer" + }, + "source": { + "description": "Source of the error event (e.g., \"sentry\", \"custom\", \"bugsnag\")", + "type": [ + "string", + "null" + ] + }, + "timestamp": { + "type": "string" + } + }, + "required": [ + "id", + "error_group_id", + "timestamp", + "created_at" + ], + "type": "object" + }, + "ErrorGroupResponse": { + "properties": { + "assigned_to": { + "type": [ + "string", + "null" + ] + }, + "created_at": { + "type": "string" + }, + "deployment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "error_type": { + "type": "string" + }, + "first_seen": { + "type": "string" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "last_seen": { + "type": "string" + }, + "message_template": { + "type": [ + "string", + "null" + ] + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "status": { + "type": "string" + }, + "title": { + "type": "string" + }, + "total_count": { + "format": "int32", + "type": "integer" + }, + "updated_at": { + "type": "string" + }, + "visitor_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + "required": [ + "id", + "title", + "error_type", + "first_seen", + "last_seen", + "total_count", + "status", + "project_id", + "created_at", + "updated_at" + ], + "type": "object" + }, + "ErrorGroupStatsResponse": { + "properties": { + "ignored_groups": { + "format": "int64", + "type": "integer" + }, + "resolved_groups": { + "format": "int64", + "type": "integer" + }, + "total_groups": { + "format": "int64", + "type": "integer" + }, + "unresolved_groups": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "total_groups", + "unresolved_groups", + "resolved_groups", + "ignored_groups" + ], + "type": "object" + }, + "ErrorResponse": { + "properties": { + "details": { + "type": [ + "string", + "null" + ] + }, + "error": { + "type": "string" + } + }, + "required": [ + "error" + ], + "type": "object" + }, + "ErrorRow": { + "properties": { + "deployment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "error_class": { + "type": "string" + }, + "error_group_id": { + "format": "int32", + "type": "integer" + }, + "fingerprint": { + "type": "string" + }, + "id": { + "format": "int64", + "type": "integer" + }, + "message": { + "type": [ + "string", + "null" + ] + }, + "stacktrace_preview": {}, + "stacktrace_truncated": { + "type": "boolean" + }, + "trace_id": { + "type": [ + "string", + "null" + ] + }, + "ts": { + "format": "date-time", + "type": "string" + } + }, + "required": [ + "id", + "ts", + "error_group_id", + "fingerprint", + "error_class", + "stacktrace_preview", + "stacktrace_truncated" + ], + "type": "object" + }, + "ErrorTimeSeriesDataResponse": { + "properties": { + "count": { + "format": "int64", + "type": "integer" + }, + "timestamp": { + "type": "string" + } + }, + "required": [ + "timestamp", + "count" + ], + "type": "object" + }, + "ErrorTimeSeriesQuery": { + "properties": { + "bucket": { + "description": "Time bucket size (e.g., \"1h\", \"15m\", \"1d\", \"1 hour\", \"30 minutes\")", + "example": "1h", + "type": "string" + }, + "end_time": { + "format": "date-time", + "type": "string" + }, + "start_time": { + "format": "date-time", + "type": "string" + } + }, + "required": [ + "start_time", + "end_time" + ], + "type": "object" + }, + "EventActivityBucket": { + "description": "Time bucket data point for event activity graph", + "properties": { + "count": { + "description": "Number of event occurrences in this bucket", + "format": "int64", + "type": "integer" + }, + "timestamp": { + "description": "Timestamp for this bucket (ISO 8601)", + "type": "string" + }, + "unique_visitors": { + "description": "Number of unique visitors in this bucket", + "format": "int64", + "type": "integer" + } + }, + "required": [ + "timestamp", + "count", + "unique_visitors" + ], + "type": "object" + }, + "EventBreakdown": { + "enum": [ + "country", + "region", + "city" + ], + "type": "string" + }, + "EventBrowserStats": { + "description": "Browser stats for an event", + "properties": { + "browser": { + "description": "Browser name", + "type": "string" + }, + "count": { + "description": "Number of event occurrences from this browser", + "format": "int64", + "type": "integer" + }, + "percentage": { + "description": "Percentage of total events", + "format": "double", + "type": "number" + } + }, + "required": [ + "browser", + "count", + "percentage" + ], + "type": "object" + }, + "EventCount": { + "properties": { + "count": { + "format": "int64", + "type": "integer" + }, + "event_name": { + "type": "string" + }, + "percentage": { + "format": "double", + "type": "number" + } + }, + "required": [ + "event_name", + "count", + "percentage" + ], + "type": "object" + }, + "EventCountryStats": { + "description": "Country stats for an event", + "properties": { + "count": { + "description": "Number of event occurrences from this country", + "format": "int64", + "type": "integer" + }, + "country": { + "description": "Country name", + "type": "string" + }, + "country_code": { + "description": "ISO country code (2-letter)", + "type": [ + "string", + "null" + ] + }, + "percentage": { + "description": "Percentage of total events", + "format": "double", + "type": "number" + } + }, + "required": [ + "country", + "count", + "percentage" + ], + "type": "object" + }, + "EventDetailQuery": { + "description": "Query parameters for event detail analytics", + "properties": { + "bucket_interval": { + "description": "Bucket interval for time series: 'hour', 'day', 'week', 'month' (default: auto)", + "type": [ + "string", + "null" + ] + }, + "end_date": { + "format": "date-time", + "type": "string" + }, + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "event_name": { + "description": "The specific event name to get details for", + "type": "string" + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "start_date": { + "format": "date-time", + "type": "string" + } + }, + "required": [ + "event_name", + "project_id", + "start_date", + "end_date" + ], + "type": "object" + }, + "EventDetailResponse": { + "description": "Summary response for a specific event's analytics", + "properties": { + "activity_over_time": { + "description": "Time series data for event activity graph", + "items": { + "$ref": "#/components/schemas/EventActivityBucket" + }, + "type": "array" + }, + "browsers": { + "description": "Browser distribution of visitors who triggered this event", + "items": { + "$ref": "#/components/schemas/EventBrowserStats" + }, + "type": "array" + }, + "bucket_interval": { + "description": "Bucket interval used for time series ('hour', 'day', etc.)", + "type": "string" + }, + "countries": { + "description": "Geographic distribution of visitors who triggered this event", + "items": { + "$ref": "#/components/schemas/EventCountryStats" + }, + "type": "array" + }, + "event_name": { + "description": "The event name being analyzed", + "type": "string" + }, + "referrers": { + "description": "Top referrer hostnames for visitors who triggered this event", + "items": { + "$ref": "#/components/schemas/EventReferrerStats" + }, + "type": "array" + }, + "total_count": { + "description": "Total number of times this event was triggered in the date range", + "format": "int64", + "type": "integer" + }, + "unique_sessions": { + "description": "Number of unique sessions where this event occurred", + "format": "int64", + "type": "integer" + }, + "unique_visitors": { + "description": "Number of unique visitors who triggered this event", + "format": "int64", + "type": "integer" + } + }, + "required": [ + "event_name", + "total_count", + "unique_visitors", + "unique_sessions", + "activity_over_time", + "referrers", + "countries", + "browsers", + "bucket_interval" + ], + "type": "object" + }, + "EventEntriesQuery": { + "description": "Query parameters for the raw event entries list", + "properties": { + "end_date": { + "format": "date-time", + "type": "string" + }, + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "event_name": { + "description": "The specific event name to list occurrences for", + "type": "string" + }, + "page": { + "description": "Page number (1-based, default: 1)", + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "per_page": { + "description": "Items per page (default: 20, max: 100)", + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "start_date": { + "format": "date-time", + "type": "string" + } + }, + "required": [ + "event_name", + "project_id", + "start_date", + "end_date" + ], + "type": "object" + }, + "EventEntriesResponse": { + "description": "Paginated response for raw event entries", + "properties": { + "entries": { + "description": "Individual event occurrences, most recent first", + "items": { + "$ref": "#/components/schemas/EventEntryInfo" + }, + "type": "array" + }, + "event_name": { + "description": "The event name", + "type": "string" + }, + "page": { + "description": "Current page number", + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "per_page": { + "description": "Items per page", + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "total_count": { + "description": "Total number of occurrences of this event in the date range", + "format": "int64", + "type": "integer" + } + }, + "required": [ + "event_name", + "total_count", + "page", + "per_page", + "entries" + ], + "type": "object" + }, + "EventEntryInfo": { + "description": "A single raw occurrence of an event, including its custom JSON properties", + "properties": { + "browser": { + "description": "Browser name", + "type": [ + "string", + "null" + ] + }, + "city": { + "description": "City of the visitor at the time of the event", + "type": [ + "string", + "null" + ] + }, + "country": { + "description": "Country of the visitor at the time of the event", + "type": [ + "string", + "null" + ] + }, + "country_code": { + "description": "ISO country code (2-letter)", + "type": [ + "string", + "null" + ] + }, + "device_type": { + "description": "Device type (Desktop, Mobile, Tablet)", + "type": [ + "string", + "null" + ] + }, + "href": { + "description": "Full URL where the event was triggered", + "type": "string" + }, + "id": { + "description": "Event row ID", + "format": "int64", + "type": "integer" + }, + "page_path": { + "description": "Page path where the event was triggered", + "type": "string" + }, + "props": { + "description": "Custom event properties as JSON (null when the event carried no data)", + "type": [ + "object", + "null" + ] + }, + "session_id": { + "description": "Session ID the event belongs to (if any)", + "type": [ + "string", + "null" + ] + }, + "timestamp": { + "description": "When the event occurred", + "format": "date-time", + "type": "string" + }, + "visitor_id": { + "description": "Visitor numeric ID (if known)", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "visitor_uuid": { + "description": "Visitor UUID (if known)", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "id", + "timestamp", + "page_path", + "href" + ], + "type": "object" + }, + "EventKind": { + "description": "Tag enum for filter parameters and routing. Matches the variant\ndiscriminator used by `ObservabilityEvent`.", + "enum": [ + "request", + "span", + "error", + "revenue" + ], + "type": "string" + }, + "EventMetricsPayload": { + "properties": { + "cls": { + "description": "Cumulative Layout Shift (score)", + "format": "float", + "type": [ + "number", + "null" + ] + }, + "event_data": {}, + "event_name": { + "type": "string" + }, + "fcp": { + "description": "First Contentful Paint (milliseconds)", + "format": "float", + "type": [ + "number", + "null" + ] + }, + "fid": { + "description": "First Input Delay (milliseconds)", + "format": "float", + "type": [ + "number", + "null" + ] + }, + "inp": { + "description": "Interaction to Next Paint (milliseconds)", + "format": "float", + "type": [ + "number", + "null" + ] + }, + "language": { + "type": [ + "string", + "null" + ] + }, + "lcp": { + "description": "Largest Contentful Paint (milliseconds)", + "format": "float", + "type": [ + "number", + "null" + ] + }, + "page_title": { + "type": [ + "string", + "null" + ] + }, + "referrer": { + "description": "Referrer URL (falls back to Referer header if not provided)", + "type": [ + "string", + "null" + ] + }, + "request_path": { + "type": "string" + }, + "request_query": { + "type": "string" + }, + "screen_height": { + "format": "int32", + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "screen_width": { + "format": "int32", + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "ttfb": { + "description": "Time to First Byte (milliseconds)", + "format": "float", + "type": [ + "number", + "null" + ] + }, + "viewport_height": { + "format": "int32", + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "viewport_width": { + "format": "int32", + "minimum": 0, + "type": [ + "integer", + "null" + ] + } + }, + "required": [ + "event_name", + "event_data", + "request_path", + "request_query" + ], + "type": "object" + }, + "EventReferrerStats": { + "description": "Referrer stats for an event", + "properties": { + "count": { + "description": "Number of event occurrences from this referrer", + "format": "int64", + "type": "integer" + }, + "percentage": { + "description": "Percentage of total events", + "format": "double", + "type": "number" + }, + "referrer": { + "description": "Referrer hostname or \"Direct\"", + "type": "string" + } + }, + "required": [ + "referrer", + "count", + "percentage" + ], + "type": "object" + }, + "EventTimeline": { + "properties": { + "count": { + "format": "int64", + "type": "integer" + }, + "date": { + "format": "date-time", + "type": "string" + } + }, + "required": [ + "date", + "count" + ], + "type": "object" + }, + "EventTimelineQuery": { + "properties": { + "aggregation_level": { + "$ref": "#/components/schemas/AggregationLevel", + "description": "Aggregation level: events (raw count), sessions (unique sessions), or visitors (unique visitors)" + }, + "bucket_size": { + "description": "Bucket size: hour, day, or week (auto-detected if not specified)", + "type": [ + "string", + "null" + ] + }, + "end_date": { + "format": "date-time", + "type": "string" + }, + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "event_name": { + "type": [ + "string", + "null" + ] + }, + "start_date": { + "format": "date-time", + "type": "string" + } + }, + "required": [ + "start_date", + "end_date" + ], + "type": "object" + }, + "EventType": { + "properties": { + "count": { + "format": "int64", + "type": "integer" + }, + "name": { + "type": "string" + } + }, + "required": [ + "name", + "count" + ], + "type": "object" + }, + "EventTypeBreakdown": { + "properties": { + "count": { + "format": "int64", + "type": "integer" + }, + "event_type": { + "type": "string" + }, + "percentage": { + "format": "double", + "type": "number" + } + }, + "required": [ + "event_type", + "count", + "percentage" + ], + "type": "object" + }, + "EventTypeBreakdownQuery": { + "properties": { + "aggregation_level": { + "$ref": "#/components/schemas/AggregationLevel", + "description": "Aggregation level: events (raw count), sessions (unique sessions), or visitors (unique visitors)" + }, + "end_date": { + "format": "date-time", + "type": "string" + }, + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "start_date": { + "format": "date-time", + "type": "string" + } + }, + "required": [ + "start_date", + "end_date" + ], + "type": "object" + }, + "EventTypeResponse": { + "properties": { + "category": { + "type": "string" + }, + "description": { + "type": "string" + }, + "event_type": { + "type": "string" + } + }, + "required": [ + "event_type", + "description", + "category" + ], + "type": "object" + }, + "EventTypesResponse": { + "properties": { + "events": { + "items": { + "$ref": "#/components/schemas/EventType" + }, + "type": "array" + }, + "page": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "page_size": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "total": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "events", + "total", + "page", + "page_size" + ], + "type": "object" + }, + "EventVisitorInfo": { + "description": "A visitor who triggered a specific event", + "properties": { + "browser": { + "description": "Browser name", + "type": [ + "string", + "null" + ] + }, + "city": { + "description": "Visitor's city", + "type": [ + "string", + "null" + ] + }, + "country": { + "description": "Visitor's country", + "type": [ + "string", + "null" + ] + }, + "country_code": { + "description": "Visitor's country code", + "type": [ + "string", + "null" + ] + }, + "device_type": { + "description": "Device type (Desktop, Mobile, Tablet)", + "type": [ + "string", + "null" + ] + }, + "event_count": { + "description": "Number of times this visitor triggered the event", + "format": "int64", + "type": "integer" + }, + "first_triggered": { + "description": "When the visitor first triggered the event in the date range", + "format": "date-time", + "type": "string" + }, + "last_triggered": { + "description": "When the visitor last triggered the event in the date range", + "format": "date-time", + "type": "string" + }, + "referrer_hostname": { + "description": "Referrer hostname for the event", + "type": [ + "string", + "null" + ] + }, + "visitor_id": { + "description": "Visitor numeric ID", + "format": "int32", + "type": "integer" + }, + "visitor_uuid": { + "description": "Visitor UUID", + "type": "string" + } + }, + "required": [ + "visitor_id", + "visitor_uuid", + "event_count", + "first_triggered", + "last_triggered" + ], + "type": "object" + }, + "EventVisitorsQuery": { + "description": "Query parameters for event visitors list", + "properties": { + "end_date": { + "format": "date-time", + "type": "string" + }, + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "event_name": { + "description": "The specific event name to list visitors for", + "type": "string" + }, + "page": { + "description": "Page number (1-based, default: 1)", + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "per_page": { + "description": "Items per page (default: 20, max: 100)", + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "start_date": { + "format": "date-time", + "type": "string" + } + }, + "required": [ + "event_name", + "project_id", + "start_date", + "end_date" + ], + "type": "object" + }, + "EventVisitorsResponse": { + "description": "Paginated response for event visitors", + "properties": { + "event_name": { + "description": "The event name", + "type": "string" + }, + "page": { + "description": "Current page number", + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "per_page": { + "description": "Items per page", + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "total_count": { + "description": "Total number of unique visitors who triggered this event", + "format": "int64", + "type": "integer" + }, + "visitors": { + "description": "Individual visitors who triggered this event", + "items": { + "$ref": "#/components/schemas/EventVisitorInfo" + }, + "type": "array" + } + }, + "required": [ + "event_name", + "total_count", + "page", + "per_page", + "visitors" + ], + "type": "object" + }, + "EventsCountQuery": { + "properties": { + "aggregation_level": { + "$ref": "#/components/schemas/AggregationLevel", + "description": "Aggregation level: events (raw count), sessions (unique sessions), or visitors (unique visitors)" + }, + "custom_events_only": { + "description": "Only return custom events, excluding system events like page_view, page_leave, heartbeat (default: true)", + "type": [ + "boolean", + "null" + ] + }, + "end_date": { + "format": "date-time", + "type": "string" + }, + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "limit": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "start_date": { + "format": "date-time", + "type": "string" + } + }, + "required": [ + "start_date", + "end_date" + ], + "type": "object" + }, + "EventsResponse": { + "properties": { + "applied_kinds": { + "description": "Echo of the kinds filter actually applied (server-resolved). Useful\nfor clients that pass `kinds=` empty and want to know what they got.", + "items": { + "$ref": "#/components/schemas/EventKind" + }, + "type": "array" + }, + "events": { + "items": { + "$ref": "#/components/schemas/ObservabilityEvent" + }, + "type": "array" + } + }, + "required": [ + "events", + "applied_kinds" + ], + "type": "object" + }, + "ExecBody": { + "additionalProperties": false, + "properties": { + "cmd": { + "items": { + "type": "string" + }, + "type": "array" + }, + "cwd": { + "type": [ + "string", + "null" + ] + }, + "env": { + "additionalProperties": { + "type": "string" + }, + "propertyNames": { + "type": "string" + }, + "type": "object" + } + }, + "required": [ + "cmd" + ], + "type": "object" + }, + "ExecDetachedResponse": { + "properties": { + "job_id": { + "type": "string" + } + }, + "required": [ + "job_id" + ], + "type": "object" + }, + "ExecResponse": { + "properties": { + "exit_code": { + "format": "int32", + "type": "integer" + }, + "stderr": { + "type": "string" + }, + "stdout": { + "type": "string" + } + }, + "required": [ + "exit_code", + "stdout", + "stderr" + ], + "type": "object" + }, + "ExecuteImportRequest": { + "description": "Request to execute an import", + "properties": { + "directory": { + "description": "Project directory", + "example": ".", + "type": "string" + }, + "dry_run": { + "description": "Dry run mode (don't create resources)", + "type": [ + "boolean", + "null" + ] + }, + "main_branch": { + "description": "Main branch name", + "example": "main", + "type": "string" + }, + "preset": { + "description": "Preset to use for the project (e.g., \"nextjs\", \"express\", \"docker\")", + "type": "string" + }, + "project_name": { + "description": "Project name to use (overrides the name from the plan)", + "example": "my-app", + "type": "string" + }, + "session_id": { + "description": "Session ID from plan creation", + "type": "string" + } + }, + "required": [ + "session_id", + "project_name", + "preset", + "directory", + "main_branch" + ], + "type": "object" + }, + "ExecuteImportResponse": { + "description": "Response from import execution", + "properties": { + "deployment_id": { + "description": "Created deployment ID (if completed)", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "environment_id": { + "description": "Created environment ID (if completed)", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "project_id": { + "description": "Created project ID (if completed)", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "session_id": { + "description": "Session ID", + "type": "string" + }, + "status": { + "$ref": "#/components/schemas/ImportExecutionStatus", + "description": "Execution status" + }, + "step_results": { + "description": "Per-step results (in execution order)", + "items": { + "$ref": "#/components/schemas/StepResult" + }, + "type": "array" + } + }, + "required": [ + "session_id", + "status", + "step_results" + ], + "type": "object" + }, + "ExecuteOperationRequest": { + "properties": { + "operation": { + "type": "string" + } + }, + "required": [ + "operation" + ], + "type": "object" + }, + "ExpireRequest": { + "description": "Request to set expiration on a key", + "properties": { + "key": { + "description": "The key to set expiration on", + "example": "session:abc", + "type": "string" + }, + "project_id": { + "description": "Project ID (required for API key/session auth, optional for deployment tokens)", + "example": 1, + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "seconds": { + "description": "Expiration time in seconds", + "example": 3600, + "format": "int64", + "type": "integer" + } + }, + "required": [ + "key", + "seconds" + ], + "type": "object" + }, + "ExpireResponse": { + "description": "Response for expire operation", + "properties": { + "success": { + "description": "True if expiration was set, false if key doesn't exist", + "type": "boolean" + } + }, + "required": [ + "success" + ], + "type": "object" + }, + "ExplorerSupportResponse": { + "properties": { + "capabilities": { + "description": "Capabilities supported by this service", + "example": [ + "sql" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "filter_schema": { + "description": "JSON Schema for filter format with embedded UI hints (if supported)" + }, + "hierarchy": { + "description": "Hierarchy levels (describes the navigation structure)", + "items": { + "$ref": "#/components/schemas/HierarchyLevel" + }, + "type": "array" + }, + "reason": { + "description": "Reason why explorer is not supported (if applicable)", + "type": [ + "string", + "null" + ] + }, + "service_type": { + "description": "Service type", + "example": "postgres", + "type": "string" + }, + "supported": { + "description": "Whether the service supports query explorer functionality", + "example": true, + "type": "boolean" + } + }, + "required": [ + "supported", + "service_type", + "capabilities", + "hierarchy" + ], + "type": "object" + }, + "ExtendTimeoutBody": { + "properties": { + "duration": { + "description": "`@vercel/sandbox`-compatible alternative — duration in milliseconds.\nUsed when `extra_secs` is absent.", + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "extra_secs": { + "description": "Extra seconds to add to the existing `expires_at` (temps-native).", + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + } + }, + "type": "object" + }, + "ExternalImageResponse": { + "properties": { + "created_at": { + "example": "2025-10-12T12:15:47.609192Z", + "format": "date-time", + "type": "string" + }, + "digest": { + "type": [ + "string", + "null" + ] + }, + "id": { + "format": "int32", + "type": "integer" + }, + "image_ref": { + "type": "string" + }, + "metadata": {}, + "project_id": { + "format": "int32", + "type": "integer" + }, + "pushed_at": { + "example": "2025-10-12T12:15:47.609192Z", + "format": "date-time", + "type": "string" + }, + "size_bytes": { + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "tag": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "id", + "project_id", + "image_ref", + "pushed_at", + "created_at" + ], + "type": "object" + }, + "ExternalServiceBackupResponse": { + "description": "Response type for external service backup", + "properties": { + "backup_id": { + "format": "int32", + "type": "integer" + }, + "backup_type": { + "type": "string" + }, + "checksum": { + "type": [ + "string", + "null" + ] + }, + "compression_type": { + "type": "string" + }, + "created_by": { + "format": "int32", + "type": "integer" + }, + "error_message": { + "type": [ + "string", + "null" + ] + }, + "expires_at": { + "example": "2025-02-15T14:30:00.123Z", + "type": [ + "string", + "null" + ] + }, + "finished_at": { + "example": "2025-01-15T14:35:00.456Z", + "type": [ + "string", + "null" + ] + }, + "id": { + "format": "int32", + "type": "integer" + }, + "metadata": {}, + "s3_location": { + "type": "string" + }, + "service_id": { + "format": "int32", + "type": "integer" + }, + "size_bytes": { + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "started_at": { + "example": "2025-01-15T14:30:00.123Z", + "type": "string" + }, + "state": { + "type": "string" + } + }, + "required": [ + "id", + "service_id", + "backup_id", + "backup_type", + "state", + "started_at", + "s3_location", + "metadata", + "compression_type", + "created_by" + ], + "type": "object" + }, + "ExternalServiceDetails": { + "properties": { + "current_parameters": { + "additionalProperties": { + "type": "string" + }, + "propertyNames": { + "type": "string" + }, + "type": [ + "object", + "null" + ] + }, + "parameter_schema": {}, + "sensitive_parameters": { + "description": "Parameter names whose values are masked in `current_parameters` and\nmay be fetched only through the audited reveal endpoint.", + "items": { + "type": "string" + }, + "type": "array" + }, + "service": { + "$ref": "#/components/schemas/ExternalServiceInfo" + } + }, + "required": [ + "service", + "sensitive_parameters" + ], + "type": "object" + }, + "ExternalServiceInfo": { + "properties": { + "connection_info": { + "type": [ + "string", + "null" + ] + }, + "created_at": { + "type": "string" + }, + "error_message": { + "description": "Error message from failed initialization.", + "type": [ + "string", + "null" + ] + }, + "id": { + "format": "int32", + "type": "integer" + }, + "members": { + "description": "Cluster members (empty for standalone services).", + "items": { + "$ref": "#/components/schemas/ServiceMemberInfo" + }, + "type": "array" + }, + "metrics_enabled": { + "description": "Whether metric collection is enabled for this service. The UI uses this\nto decide whether to poll the monitoring endpoints.", + "type": "boolean" + }, + "name": { + "type": "string" + }, + "node_id": { + "description": "Node ID where the service runs. Null means control plane (local).", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "service_type": { + "$ref": "#/components/schemas/ServiceTypeRoute" + }, + "status": { + "type": "string" + }, + "topology": { + "description": "Service topology: \"standalone\" (single container) or \"cluster\" (HA multi-member).", + "example": "standalone", + "type": "string" + }, + "updated_at": { + "type": "string" + }, + "version": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "id", + "name", + "service_type", + "status", + "created_at", + "updated_at", + "topology" + ], + "type": "object" + }, + "ExternalServiceSummary": { + "description": "Summary of the external service that owns a backup. Only populated for\nexternal-service backups (Redis, Postgres, etc.); absent for control-plane\nbackups.", + "properties": { + "id": { + "description": "Database id of the external service.", + "format": "int32", + "type": "integer" + }, + "name": { + "description": "Human-readable service name (e.g. \"redis-prod\").", + "type": "string" + }, + "service_type": { + "description": "Service type string (e.g. \"postgres\", \"redis\", \"mongodb\").", + "example": "postgres", + "type": "string" + } + }, + "required": [ + "id", + "name", + "service_type" + ], + "type": "object" + }, + "FieldResponse": { + "properties": { + "field_type": { + "description": "Field type (Int32, String, Timestamp, etc.)", + "example": "Int64", + "type": "string" + }, + "name": { + "description": "Field name", + "example": "id", + "type": "string" + }, + "nullable": { + "description": "Whether the field is nullable", + "example": false, + "type": "boolean" + } + }, + "required": [ + "name", + "field_type", + "nullable" + ], + "type": "object" + }, + "FiringSeriesEntry": { + "description": "A single currently-firing series for a dynamic alert rule, snapshotted from\nthe evaluator's in-memory per-series firing map at read time (ADR-026 Phase 3).", + "properties": { + "alarm_id": { + "description": "The open alarm's id, when one was created (absent if suppressed).", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "series_key": { + "description": "The series' label pairs, e.g. `[[\"endpoint\",\"/checkout\"],[\"region\",\"eu-west\"]]`.", + "items": { + "items": false, + "prefixItems": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "type": "array" + }, + "type": "array" + }, + "series_label": { + "description": "The human-readable joined label, e.g. `endpoint=/checkout, region=eu-west`.", + "type": "string" + } + }, + "required": [ + "series_key", + "series_label" + ], + "type": "object" + }, + "FlagEnvironmentResponse": { + "properties": { + "enabled": { + "type": "boolean" + }, + "environment_id": { + "format": "int32", + "type": "integer" + }, + "value": {} + }, + "required": [ + "environment_id", + "enabled" + ], + "type": "object" + }, + "FlagListResponse": { + "description": "Note the absence of `salt`: it is never exposed. Publishing the bucketing\nsalt would let a client predict, and self-select into, a rollout cohort.", + "properties": { + "flags": { + "items": { + "$ref": "#/components/schemas/FlagResponse" + }, + "type": "array" + }, + "page": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "page_size": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "total": { + "description": "Total flags matching the filter, across all pages.", + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "total_pages": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "flags", + "total", + "page", + "page_size", + "total_pages" + ], + "type": "object" + }, + "FlagResponse": { + "properties": { + "archived_at": { + "type": [ + "string", + "null" + ] + }, + "client_visible": { + "type": "boolean" + }, + "created_at": { + "type": "string" + }, + "default_value": {}, + "description": { + "type": [ + "string", + "null" + ] + }, + "environments": { + "description": "Per-environment overrides. Empty means the flag inherits its default\neverywhere.", + "items": { + "$ref": "#/components/schemas/FlagEnvironmentResponse" + }, + "type": "array" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "key": { + "type": "string" + }, + "last_evaluated_at": { + "description": "When an app last actually evaluated this flag. `None` means never seen,\nwhich is a real answer rather than missing data.", + "type": [ + "string", + "null" + ] + }, + "updated_at": { + "type": "string" + }, + "value_type": { + "type": "string" + } + }, + "required": [ + "id", + "key", + "value_type", + "default_value", + "client_visible", + "created_at", + "updated_at", + "environments" + ], + "type": "object" + }, + "FlagSnapshot": { + "description": "A single flag, already resolved down to one environment. This is what the\nevaluator sees and what the SDK caches in memory.", + "properties": { + "default_value": { + "description": "Served whenever evaluation cannot do better. Genuinely polymorphic by\ndesign — the surrounding struct carries the type." + }, + "enabled": { + "description": "False means the kill switch is engaged for this environment.", + "type": "boolean" + }, + "environment_value": { + "description": "`None` means \"inherit `default_value`\"." + }, + "key": { + "type": "string" + }, + "value_type": { + "$ref": "#/components/schemas/FlagValueType" + } + }, + "required": [ + "key", + "value_type", + "default_value", + "enabled" + ], + "type": "object" + }, + "FlagSnapshotResponse": { + "properties": { + "environment_id": { + "format": "int32", + "type": "integer" + }, + "flags": { + "description": "Flags collapsed to what the evaluator needs, sorted by key so the\nserialized form — and therefore the ETag — is stable.", + "items": { + "$ref": "#/components/schemas/FlagSnapshot" + }, + "type": "array" + } + }, + "required": [ + "environment_id", + "flags" + ], + "type": "object" + }, + "FlagValueType": { + "description": "The declared type of a flag's value. Fixed at create time.", + "enum": [ + "bool", + "string", + "number", + "json" + ], + "type": "string" + }, + "ForecastAlgorithm": { + "description": "Forecast model family.", + "enum": [ + "linear", + "seasonal" + ], + "type": "string" + }, + "ForecastParams": { + "description": "Forecast detector parameters (stub — not yet evaluated).", + "properties": { + "algorithm": { + "$ref": "#/components/schemas/ForecastAlgorithm" + }, + "comparator": { + "$ref": "#/components/schemas/Comparator", + "description": "Comparator + threshold the *forecast* is checked against." + }, + "deviations": { + "format": "double", + "type": "number" + }, + "forecast_horizon_secs": { + "description": "How far ahead to project before checking the breach condition.", + "format": "int32", + "type": "integer" + }, + "threshold": { + "format": "double", + "type": "number" + } + }, + "required": [ + "forecast_horizon_secs", + "comparator", + "threshold" + ], + "type": "object" + }, + "FullError": { + "properties": { + "data": { + "description": "Full JSONB blob from `error_events.data` — stack trace, breadcrumbs,\nrequest context, everything. Schema is documented per source SDK." + }, + "deployment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "error_class": { + "type": "string" + }, + "error_group_id": { + "format": "int32", + "type": "integer" + }, + "fingerprint": { + "type": "string" + }, + "id": { + "format": "int64", + "type": "integer" + }, + "message": { + "type": [ + "string", + "null" + ] + }, + "trace_id": { + "type": [ + "string", + "null" + ] + }, + "ts": { + "format": "date-time", + "type": "string" + } + }, + "required": [ + "id", + "ts", + "error_group_id", + "fingerprint", + "error_class" + ], + "type": "object" + }, + "FullEvent": { + "description": "One un-truncated row, returned by the `/full/{type}/{id}` endpoint when\nthe user clicks \"Show full\". Same shape as the list rows, but with the\nraw heavy fields restored (no truncation flags) so the side panel can\nrender the long form.", + "oneOf": [ + { + "allOf": [ + { + "$ref": "#/components/schemas/FullRequest" + }, + { + "properties": { + "type": { + "enum": [ + "request" + ], + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + } + ] + }, + { + "allOf": [ + { + "$ref": "#/components/schemas/FullError" + }, + { + "properties": { + "type": { + "enum": [ + "error" + ], + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + } + ] + }, + { + "allOf": [ + { + "$ref": "#/components/schemas/RevenueRow" + }, + { + "properties": { + "type": { + "enum": [ + "revenue" + ], + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + } + ] + }, + { + "allOf": [ + { + "$ref": "#/components/schemas/SpanRow", + "description": "`SpanRow.attributes` is the truncated form; re-fetching returns\nthe same shape so the panel has a stable contract." + }, + { + "properties": { + "type": { + "enum": [ + "span" + ], + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + } + ], + "description": "`SpanRow.attributes` is the truncated form; re-fetching returns\nthe same shape so the panel has a stable contract." + } + ] + }, + "FullRequest": { + "properties": { + "client_ip": { + "type": [ + "string", + "null" + ] + }, + "deployment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "error_group_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "host": { + "type": "string" + }, + "id": { + "description": "The request's unique `request_id` — same identity the list rows carry\n(backend-agnostic; ClickHouse rows have no serial PK).", + "type": "string" + }, + "latency_ms": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "method": { + "type": "string" + }, + "path": { + "type": "string" + }, + "referrer": { + "type": [ + "string", + "null" + ] + }, + "request_headers": {}, + "response_headers": {}, + "status": { + "format": "int32", + "type": "integer" + }, + "trace_id": { + "type": [ + "string", + "null" + ] + }, + "ts": { + "format": "date-time", + "type": "string" + }, + "user_agent": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "id", + "ts", + "method", + "host", + "path", + "status" + ], + "type": "object" + }, + "FunnelMetricsResponse": { + "properties": { + "average_completion_time_seconds": { + "format": "double", + "type": "number" + }, + "funnel_id": { + "format": "int32", + "type": "integer" + }, + "funnel_name": { + "type": "string" + }, + "overall_conversion_rate": { + "format": "double", + "type": "number" + }, + "step_conversions": { + "items": { + "$ref": "#/components/schemas/StepConversionResponse" + }, + "type": "array" + }, + "total_entries": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "funnel_id", + "funnel_name", + "total_entries", + "step_conversions", + "overall_conversion_rate", + "average_completion_time_seconds" + ], + "type": "object" + }, + "FunnelResponse": { + "properties": { + "created_at": { + "type": "string" + }, + "description": { + "type": [ + "string", + "null" + ] + }, + "id": { + "format": "int32", + "type": "integer" + }, + "is_active": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "updated_at": { + "type": "string" + } + }, + "required": [ + "id", + "name", + "is_active", + "created_at", + "updated_at" + ], + "type": "object" + }, + "GatewayStatus": { + "description": "Detailed gateway container status surfaced to the settings UI.", + "properties": { + "auto_upgrade": { + "description": "True if `auto_upgrade` is enabled in settings.", + "type": "boolean" + }, + "container_name": { + "description": "Container name.", + "type": "string" + }, + "drift": { + "description": "True when `image != expected_image` and the container is present.", + "type": "boolean" + }, + "expected_image": { + "description": "The image the supervisor *expects* (from settings/constant). If this\ndiffers from `image`, the UI shows a \"drift\" badge.", + "type": "string" + }, + "health": { + "description": "Higher-level health label: \"running\" | \"restarting\" | \"crash_looping\"\n| \"stopped\" | \"missing\". UI should prefer this over `running`.", + "type": "string" + }, + "host_port": { + "description": "Host port that the container's :8080 is published on.", + "format": "int32", + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "image": { + "description": "Image reference the container was created with (e.g.\n`ghcr.io/gotempsh/temps-preview-gateway:latest`).", + "type": [ + "string", + "null" + ] + }, + "image_digest": { + "description": "Image digest if available (e.g. `sha256:…`).", + "type": [ + "string", + "null" + ] + }, + "last_error": { + "description": "Error string Docker recorded for the container (e.g. startup failure).", + "type": [ + "string", + "null" + ] + }, + "last_exit_code": { + "description": "Exit code of the last run, if the container is not currently running.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "network": { + "description": "Network the container is attached to (should be `temps-sandbox-net`).", + "type": [ + "string", + "null" + ] + }, + "present": { + "description": "Whether the container exists at all.", + "type": "boolean" + }, + "restart_count": { + "description": "Number of times Docker has restarted the container.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "running": { + "description": "Whether the container is currently running.", + "type": "boolean" + }, + "started_at": { + "description": "ISO 8601 timestamp the container was started at, if running.", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "present", + "running", + "health", + "container_name", + "expected_image", + "drift", + "auto_upgrade" + ], + "type": "object" + }, + "GenAiEvent": { + "description": "A GenAI-related event extracted from span events.\n\nCovers `gen_ai.client.inference.operation.details` and `gen_ai.evaluation.result`\nevents per the OTel GenAI semantic conventions.", + "properties": { + "attributes": { + "additionalProperties": { + "type": "string" + }, + "description": "All event attributes.", + "propertyNames": { + "type": "string" + }, + "type": "object" + }, + "event_name": { + "type": "string" + }, + "span_id": { + "type": "string" + }, + "timestamp": { + "format": "date-time", + "type": "string" + }, + "trace_id": { + "type": "string" + } + }, + "required": [ + "span_id", + "trace_id", + "event_name", + "timestamp", + "attributes" + ], + "type": "object" + }, + "GenAiSpanDetail": { + "description": "A single GenAI span with extracted semantic convention fields.\n\nFields are aligned with the OpenTelemetry GenAI Semantic Conventions spec:\n", + "properties": { + "agent_description": { + "description": "Agent description from `gen_ai.agent.description`.", + "type": [ + "string", + "null" + ] + }, + "agent_id": { + "description": "Agent identifier from `gen_ai.agent.id`.", + "type": [ + "string", + "null" + ] + }, + "agent_name": { + "description": "Agent name from `gen_ai.agent.name`.", + "type": [ + "string", + "null" + ] + }, + "agent_version": { + "description": "Agent version from `gen_ai.agent.version`.", + "type": [ + "string", + "null" + ] + }, + "attributes": { + "additionalProperties": { + "type": "string" + }, + "description": "All span attributes for extensibility.", + "propertyNames": { + "type": "string" + }, + "type": "object" + }, + "aws_bedrock_guardrail_id": { + "description": "AWS Bedrock guardrail ID from `aws.bedrock.guardrail.id`.", + "type": [ + "string", + "null" + ] + }, + "aws_bedrock_knowledge_base_id": { + "description": "AWS Bedrock knowledge base ID from `aws.bedrock.knowledge_base.id`.", + "type": [ + "string", + "null" + ] + }, + "azure_resource_provider_namespace": { + "description": "Azure resource provider namespace from `azure.resource_provider.namespace`.", + "type": [ + "string", + "null" + ] + }, + "cache_creation_input_tokens": { + "description": "Tokens written to provider cache from `gen_ai.usage.cache_creation.input_tokens`.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "cache_read_input_tokens": { + "description": "Tokens served from provider cache from `gen_ai.usage.cache_read.input_tokens`.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "conversation_id": { + "description": "Unique conversation/session/thread ID from `gen_ai.conversation.id`.", + "type": [ + "string", + "null" + ] + }, + "data_source_id": { + "description": "Data source identifier from `gen_ai.data_source.id`.", + "type": [ + "string", + "null" + ] + }, + "duration_ms": { + "format": "double", + "type": "number" + }, + "embeddings_dimension_count": { + "description": "Output embedding dimensions from `gen_ai.embeddings.dimension.count`.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "error_type": { + "description": "Error type from `error.type` when the span status is ERROR.", + "type": [ + "string", + "null" + ] + }, + "gen_ai_model": { + "description": "The requested model from `gen_ai.request.model`.", + "type": [ + "string", + "null" + ] + }, + "gen_ai_operation": { + "description": "The operation type from `gen_ai.operation.name` (e.g. \"chat\", \"embeddings\", \"execute_tool\").", + "type": [ + "string", + "null" + ] + }, + "gen_ai_response_model": { + "description": "The model that actually generated the response from `gen_ai.response.model`.", + "type": [ + "string", + "null" + ] + }, + "gen_ai_system": { + "description": "The GenAI provider from `gen_ai.provider.name` (falls back to deprecated `gen_ai.system`).", + "type": [ + "string", + "null" + ] + }, + "input_messages": { + "description": "Chat history input from `gen_ai.input.messages` (opt-in, JSON string).", + "type": [ + "string", + "null" + ] + }, + "input_tokens": { + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "kind": { + "$ref": "#/components/schemas/SpanKind" + }, + "name": { + "type": "string" + }, + "openai_api_type": { + "description": "OpenAI API type from `openai.api.type` (chat_completions, responses).", + "type": [ + "string", + "null" + ] + }, + "openai_request_service_tier": { + "description": "Requested service tier from `openai.request.service_tier`.", + "type": [ + "string", + "null" + ] + }, + "openai_response_service_tier": { + "description": "Actual service tier from `openai.response.service_tier`.", + "type": [ + "string", + "null" + ] + }, + "openai_system_fingerprint": { + "description": "System fingerprint from `openai.response.system_fingerprint`.", + "type": [ + "string", + "null" + ] + }, + "output_messages": { + "description": "Model output from `gen_ai.output.messages` (opt-in, JSON string).", + "type": [ + "string", + "null" + ] + }, + "output_tokens": { + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "output_type": { + "description": "Output content type from `gen_ai.output.type` (text, json, image, speech).", + "type": [ + "string", + "null" + ] + }, + "parent_span_id": { + "type": [ + "string", + "null" + ] + }, + "request_choice_count": { + "description": "Number of choices requested from `gen_ai.request.choice.count`.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "request_encoding_formats": { + "description": "Requested encoding formats from `gen_ai.request.encoding_formats`.", + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + }, + "request_frequency_penalty": { + "description": "Frequency penalty from `gen_ai.request.frequency_penalty`.", + "format": "double", + "type": [ + "number", + "null" + ] + }, + "request_max_tokens": { + "description": "Max tokens from `gen_ai.request.max_tokens`.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "request_presence_penalty": { + "description": "Presence penalty from `gen_ai.request.presence_penalty`.", + "format": "double", + "type": [ + "number", + "null" + ] + }, + "request_seed": { + "description": "Seed for reproducibility from `gen_ai.request.seed`.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "request_stop_sequences": { + "description": "Stop sequences from `gen_ai.request.stop_sequences`.", + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + }, + "request_temperature": { + "description": "Temperature setting from `gen_ai.request.temperature`.", + "format": "double", + "type": [ + "number", + "null" + ] + }, + "request_top_k": { + "description": "Top-k setting from `gen_ai.request.top_k`.", + "format": "double", + "type": [ + "number", + "null" + ] + }, + "request_top_p": { + "description": "Top-p setting from `gen_ai.request.top_p`.", + "format": "double", + "type": [ + "number", + "null" + ] + }, + "response_finish_reasons": { + "description": "Reasons the model stopped from `gen_ai.response.finish_reasons` (e.g. [\"stop\"]).", + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + }, + "response_id": { + "description": "Unique completion ID from `gen_ai.response.id` (e.g. \"chatcmpl-123\").", + "type": [ + "string", + "null" + ] + }, + "retrieval_documents": { + "description": "Retrieved documents from `gen_ai.retrieval.documents` (opt-in, JSON string).", + "type": [ + "string", + "null" + ] + }, + "retrieval_query_text": { + "description": "Retrieval query text from `gen_ai.retrieval.query.text` (opt-in).", + "type": [ + "string", + "null" + ] + }, + "server_address": { + "description": "GenAI server address from `server.address`.", + "type": [ + "string", + "null" + ] + }, + "server_port": { + "description": "GenAI server port from `server.port`.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "span_id": { + "type": "string" + }, + "start_time": { + "format": "date-time", + "type": "string" + }, + "status_code": { + "$ref": "#/components/schemas/SpanStatusCode" + }, + "system_instructions": { + "description": "System instructions from `gen_ai.system_instructions` (opt-in, JSON string).", + "type": [ + "string", + "null" + ] + }, + "tool_call_arguments": { + "description": "Tool call arguments from `gen_ai.tool.call.arguments` (opt-in, JSON string).", + "type": [ + "string", + "null" + ] + }, + "tool_call_id": { + "description": "Tool call ID from `gen_ai.tool.call.id`.", + "type": [ + "string", + "null" + ] + }, + "tool_call_result": { + "description": "Tool call result from `gen_ai.tool.call.result` (opt-in, JSON string).", + "type": [ + "string", + "null" + ] + }, + "tool_definitions": { + "description": "Tool definitions from `gen_ai.tool.definitions` (opt-in, JSON string).", + "type": [ + "string", + "null" + ] + }, + "tool_description": { + "description": "Tool description from `gen_ai.tool.description`.", + "type": [ + "string", + "null" + ] + }, + "tool_name": { + "description": "Tool name from `gen_ai.tool.name`.", + "type": [ + "string", + "null" + ] + }, + "tool_type": { + "description": "Tool type from `gen_ai.tool.type` (function, extension, datastore).", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "span_id", + "name", + "kind", + "start_time", + "duration_ms", + "status_code", + "attributes" + ], + "type": "object" + }, + "GenAiTraceDetailResponse": { + "properties": { + "event_count": { + "minimum": 0, + "type": "integer" + }, + "events": { + "items": { + "$ref": "#/components/schemas/GenAiEvent" + }, + "type": "array" + }, + "span_count": { + "minimum": 0, + "type": "integer" + }, + "spans": { + "items": { + "$ref": "#/components/schemas/GenAiSpanDetail" + }, + "type": "array" + }, + "trace_id": { + "type": "string" + } + }, + "required": [ + "trace_id", + "spans", + "span_count", + "events", + "event_count" + ], + "type": "object" + }, + "GenAiTraceSummariesResponse": { + "properties": { + "data": { + "items": { + "$ref": "#/components/schemas/GenAiTraceSummary" + }, + "type": "array" + }, + "total": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "data", + "total" + ], + "type": "object" + }, + "GenAiTraceSummary": { + "description": "Summary of a GenAI conversation — aggregated from OTel spans with `gen_ai.*` attributes.", + "properties": { + "duration_ms": { + "format": "double", + "type": "number" + }, + "error_count": { + "format": "int64", + "type": "integer" + }, + "gen_ai_model": { + "description": "The requested model from `gen_ai.request.model`.", + "type": [ + "string", + "null" + ] + }, + "gen_ai_operation": { + "description": "The operation type from `gen_ai.operation.name` (e.g. \"chat\", \"embeddings\").", + "type": [ + "string", + "null" + ] + }, + "gen_ai_system": { + "description": "The GenAI provider (e.g. \"openai\", \"anthropic\") from `gen_ai.provider.name`.", + "type": [ + "string", + "null" + ] + }, + "root_span_name": { + "type": "string" + }, + "service_name": { + "type": "string" + }, + "span_count": { + "format": "int64", + "type": "integer" + }, + "start_time": { + "format": "date-time", + "type": "string" + }, + "total_cache_creation_input_tokens": { + "description": "Total cache-creation input tokens across all spans.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "total_cache_read_input_tokens": { + "description": "Total cache-read input tokens across all spans.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "total_input_tokens": { + "description": "Total input tokens across all spans in this trace.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "total_output_tokens": { + "description": "Total output tokens across all spans in this trace.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "trace_id": { + "type": "string" + } + }, + "required": [ + "trace_id", + "root_span_name", + "service_name", + "start_time", + "duration_ms", + "span_count", + "error_count" + ], + "type": "object" + }, + "GeneralStatsQuery": { + "properties": { + "end_date": { + "format": "date-time", + "type": "string" + }, + "start_date": { + "format": "date-time", + "type": "string" + } + }, + "required": [ + "start_date", + "end_date" + ], + "type": "object" + }, + "GeneralStatsResponse": { + "properties": { + "avg_bounce_rate": { + "format": "double", + "type": "number" + }, + "avg_engagement_rate": { + "format": "double", + "type": "number" + }, + "page_views_trend_percentage": { + "description": "Percentage change in page views vs previous period", + "format": "double", + "type": [ + "number", + "null" + ] + }, + "previous_page_views": { + "description": "Previous period page views", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "previous_unique_visitors": { + "description": "Previous period unique visitors (same duration, shifted back)", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "project_breakdown": { + "items": { + "$ref": "#/components/schemas/ProjectStatsBreakdown" + }, + "type": "array" + }, + "total_events": { + "format": "int64", + "type": "integer" + }, + "total_page_views": { + "format": "int64", + "type": "integer" + }, + "total_projects": { + "format": "int64", + "type": "integer" + }, + "total_unique_visitors": { + "format": "int64", + "type": "integer" + }, + "total_visits": { + "format": "int64", + "type": "integer" + }, + "visitors_trend_percentage": { + "description": "Percentage change in unique visitors vs previous period", + "format": "double", + "type": [ + "number", + "null" + ] + } + }, + "required": [ + "total_unique_visitors", + "total_visits", + "total_page_views", + "total_events", + "total_projects", + "avg_bounce_rate", + "avg_engagement_rate", + "project_breakdown" + ], + "type": "object" + }, + "GenerateDockerfileRequest": { + "description": "Request body for generating a Dockerfile from a preset", + "properties": { + "build_command": { + "description": "Custom build command (overrides preset default)", + "example": "npm run build", + "type": [ + "string", + "null" + ] + }, + "install_command": { + "description": "Custom install command (overrides preset default)", + "example": "npm ci", + "type": [ + "string", + "null" + ] + }, + "output_dir": { + "description": "Output directory for static builds", + "example": "dist", + "type": [ + "string", + "null" + ] + }, + "package_manager": { + "description": "Package manager used by the project (npm, yarn, pnpm, bun)\nIf not provided, defaults to npm", + "example": "npm", + "type": [ + "string", + "null" + ] + }, + "project_name": { + "description": "Project name/slug used for container naming", + "example": "my-app", + "type": [ + "string", + "null" + ] + }, + "use_buildkit": { + "description": "Whether to use BuildKit cache mounts for faster builds", + "type": "boolean" + } + }, + "type": "object" + }, + "GenerateDockerfileResponse": { + "description": "Response containing a generated Dockerfile and build arguments", + "properties": { + "build_args": { + "additionalProperties": { + "type": "string" + }, + "description": "Build arguments to pass to `docker build --build-arg KEY=VALUE`", + "propertyNames": { + "type": "string" + }, + "type": "object" + }, + "dockerfile": { + "description": "The generated Dockerfile content", + "type": "string" + }, + "preset": { + "description": "The preset slug used for generation", + "type": "string" + } + }, + "required": [ + "dockerfile", + "build_args", + "preset" + ], + "type": "object" + }, + "GenerateJoinTokenResponse": { + "description": "Response returned when a join token is generated (plaintext shown once)", + "properties": { + "message": { + "type": "string" + }, + "token": { + "description": "The plaintext join token — shown only once, save it now", + "type": "string" + } + }, + "required": [ + "token", + "message" + ], + "type": "object" + }, + "GeoLocationResponse": { + "description": "Response containing geolocation information for an IP address", + "properties": { + "city": { + "description": "City name", + "example": "Mountain View", + "type": [ + "string", + "null" + ] + }, + "country": { + "description": "Country name", + "example": "United States", + "type": [ + "string", + "null" + ] + }, + "country_code": { + "description": "ISO country code (2 letters)", + "example": "US", + "type": [ + "string", + "null" + ] + }, + "ip": { + "description": "IP address that was geolocated", + "example": "8.8.8.8", + "type": "string" + }, + "is_eu": { + "description": "Whether the IP is in the European Union", + "example": false, + "type": "boolean" + }, + "latitude": { + "description": "Latitude coordinate", + "example": 37.386, + "format": "double", + "type": [ + "number", + "null" + ] + }, + "longitude": { + "description": "Longitude coordinate", + "example": -122.0838, + "format": "double", + "type": [ + "number", + "null" + ] + }, + "region": { + "description": "Region/state name", + "example": "California", + "type": [ + "string", + "null" + ] + }, + "timezone": { + "description": "Timezone identifier", + "example": "America/Los_Angeles", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "ip", + "is_eu" + ], + "type": "object" + }, + "GeoRestrictionsConfig": { + "description": "Geographic restrictions configuration (future feature)", + "properties": { + "allowedCountries": { + "description": "Allow traffic only from specific countries", + "items": { + "type": "string" + }, + "type": "array" + }, + "blockedCountries": { + "description": "Block traffic from specific countries (ISO 3166-1 alpha-2 codes)", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "GetDeploymentsParams": { + "properties": { + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "page": { + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "per_page": { + "format": "int64", + "type": [ + "integer", + "null" + ] + } + }, + "type": "object" + }, + "GetEnvironmentVariablesQuery": { + "properties": { + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "service_id": { + "description": "Required by integration-value reveals to bind the plaintext response to\nthe exact service displayed by the client.", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "var_id": { + "description": "Exact manual env-var row to reveal. Required by the dashboard so\nduplicate keys on disjoint environments cannot cross-reveal.", + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + "type": "object" + }, + "GetFunnelMetricsQuery": { + "properties": { + "country_code": { + "type": [ + "string", + "null" + ] + }, + "end_date": { + "format": "date-time", + "type": [ + "string", + "null" + ] + }, + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "start_date": { + "format": "date-time", + "type": [ + "string", + "null" + ] + } + }, + "type": "object" + }, + "GetOrCreateDSNRequest": { + "properties": { + "base_url": { + "type": [ + "string", + "null" + ] + }, + "deployment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + "type": "object" + }, + "GetProjectSecretsQuery": { + "properties": { + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + "type": "object" + }, + "GetProjectSessionReplaysQuery": { + "properties": { + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "page": { + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "per_page": { + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "project_id": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "project_id" + ], + "type": "object" + }, + "GetProjectSessionReplaysResponse": { + "properties": { + "page": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "per_page": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "sessions": { + "items": { + "$ref": "#/components/schemas/SessionReplayWithVisitorDto" + }, + "type": "array" + }, + "total_count": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "sessions", + "page", + "per_page", + "total_count" + ], + "type": "object" + }, + "GetRequest": { + "description": "Request to get a value by key", + "properties": { + "key": { + "description": "The key to retrieve", + "example": "user:123", + "type": "string" + }, + "project_id": { + "description": "Project ID (required for API key/session auth, optional for deployment tokens)", + "example": 1, + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + "required": [ + "key" + ], + "type": "object" + }, + "GetResponse": { + "description": "Response for get operation", + "properties": { + "value": { + "description": "The value, or null if not found" + } + }, + "type": "object" + }, + "GetSessionReplayResponse": { + "properties": { + "session": { + "$ref": "#/components/schemas/SessionReplayWithVisitorDto" + } + }, + "required": [ + "session" + ], + "type": "object" + }, + "GetUniqueEventsQuery": { + "properties": { + "page": { + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "page_size": { + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + } + }, + "type": "object" + }, + "GetVisitorSessionsQuery": { + "properties": { + "page": { + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "per_page": { + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + } + }, + "type": "object" + }, + "GetVisitorSessionsResponse": { + "properties": { + "page": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "per_page": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "sessions": { + "items": { + "$ref": "#/components/schemas/SessionReplayWithVisitorDto" + }, + "type": "array" + }, + "total_count": { + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "sessions", + "page", + "per_page", + "total_count" + ], + "type": "object" + }, + "GitPushEvent": { + "description": "Git push event information that triggered the deployment", + "properties": { + "branch": { + "description": "Branch that was pushed", + "type": "string" + }, + "commit": { + "description": "Commit SHA", + "type": "string" + }, + "owner": { + "description": "Repository owner/organization", + "type": "string" + }, + "repo": { + "description": "Repository name", + "type": "string" + } + }, + "required": [ + "repo", + "owner", + "branch", + "commit" + ], + "type": "object" + }, + "GitRefResponse": { + "description": "Git repository reference response", + "properties": { + "path": { + "description": "Path within the repository (for monorepos)", + "type": [ + "string", + "null" + ] + }, + "ref": { + "description": "Git reference (branch, tag, or commit)", + "type": "string" + }, + "url": { + "description": "Git repository URL", + "type": "string" + } + }, + "required": [ + "url", + "ref" + ], + "type": "object" + }, + "GitSourcePlan": { + "description": "Git repository the source platform deploys from", + "properties": { + "branch": { + "description": "Branch the source platform deploys", + "type": "string" + }, + "clone_url": { + "description": "Full clone URL, e.g. `https://github.com/owner/repo.git`", + "type": [ + "string", + "null" + ] + }, + "is_public": { + "description": "True when the repository is public (no credentials on the source\nplatform) — the project can then build without a git provider\nconnection.", + "type": "boolean" + }, + "owner": { + "description": "Repository owner (organization or user)", + "type": "string" + }, + "repo": { + "description": "Repository name", + "type": "string" + } + }, + "required": [ + "owner", + "repo", + "branch", + "is_public" + ], + "type": "object" + }, + "GlobalConversationResponse": { + "description": "A conversation in the unified cross-project switcher: carries the project it\nbelongs to (name/slug) so the UI can show where the chat was started and\nlink back to the source.", + "properties": { + "context_id": { + "type": "string" + }, + "context_type": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "last_activity_at": { + "type": "string" + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "project_name": { + "type": [ + "string", + "null" + ] + }, + "project_slug": { + "type": [ + "string", + "null" + ] + }, + "public_id": { + "type": "string" + }, + "status": { + "type": "string" + }, + "title": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "public_id", + "project_id", + "context_type", + "context_id", + "status", + "created_at", + "last_activity_at" + ], + "type": "object" + }, + "GlobalEventStatsResponse": { + "properties": { + "bounce_rate": { + "format": "double", + "type": [ + "number", + "null" + ] + }, + "bounced": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "click_rate": { + "format": "double", + "type": [ + "number", + "null" + ] + }, + "clicked": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "complained": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "delivered": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "open_rate": { + "format": "double", + "type": [ + "number", + "null" + ] + }, + "opened": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "delivered", + "opened", + "clicked", + "bounced", + "complained" + ], + "type": "object" + }, + "GlobalMrrResponse": { + "properties": { + "change_percentage": { + "description": "Percentage change vs 24h ago. Null when previous MRR is zero\n(no baseline to compare against).", + "format": "double", + "type": [ + "number", + "null" + ] + }, + "currency": { + "type": "string" + }, + "current_mrr_minor": { + "format": "int64", + "type": "integer" + }, + "previous_mrr_minor": { + "description": "MRR 24h before now, reconstructed from the event log.", + "format": "int64", + "type": "integer" + } + }, + "required": [ + "currency", + "current_mrr_minor", + "previous_mrr_minor" + ], + "type": "object" + }, + "GlobalRecentEventResponse": { + "properties": { + "amount_minor": { + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "currency": { + "type": [ + "string", + "null" + ] + }, + "customer_ref": { + "type": [ + "string", + "null" + ] + }, + "event_type": { + "type": "string" + }, + "id": { + "format": "int64", + "type": "integer" + }, + "mrr_minor": { + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "occurred_at": { + "format": "date-time", + "type": "string" + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "project_name": { + "type": "string" + } + }, + "required": [ + "id", + "project_id", + "project_name", + "occurred_at", + "event_type" + ], + "type": "object" + }, + "GlobalRevenueSummaryResponse": { + "properties": { + "active_customers": { + "format": "int64", + "type": "integer" + }, + "active_subscriptions": { + "format": "int64", + "type": "integer" + }, + "currency": { + "type": "string" + }, + "current_mrr_minor": { + "format": "int64", + "type": "integer" + }, + "paid_all_time_minor": { + "format": "int64", + "type": "integer" + }, + "paid_last_30d_minor": { + "format": "int64", + "type": "integer" + }, + "refunded_all_time_minor": { + "format": "int64", + "type": "integer" + }, + "refunded_last_30d_minor": { + "format": "int64", + "type": "integer" + }, + "transactions_last_30d": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "currency", + "current_mrr_minor", + "paid_last_30d_minor", + "refunded_last_30d_minor", + "paid_all_time_minor", + "refunded_all_time_minor", + "active_subscriptions", + "active_customers", + "transactions_last_30d" + ], + "type": "object" + }, + "GroupedPageMetric": { + "properties": { + "cls": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "country_code": { + "description": "ISO 3166-1 alpha-2 code of the group's country. Populated for the\ngeographic dimensions (country/region/city) so clients can match map\ngeometries without name-based lookups; null otherwise.", + "type": [ + "string", + "null" + ] + }, + "events": { + "format": "int64", + "type": "integer" + }, + "fcp": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "group_key": { + "type": "string" + }, + "inp": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "lcp": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "ttfb": { + "format": "float", + "type": [ + "number", + "null" + ] + } + }, + "required": [ + "group_key", + "events" + ], + "type": "object" + }, + "GroupedPageMetricsQuery": { + "allOf": [ + { + "$ref": "#/components/schemas/SpeedSegmentFilters", + "description": "Segment filters — same shape as `PerformanceMetricsQuery`." + }, + { + "properties": { + "deployment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "device_type": { + "description": "Device type filter: \"desktop\" or \"mobile\"", + "type": [ + "string", + "null" + ] + }, + "end_date": { + "format": "date-time", + "type": "string" + }, + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "group_by": { + "type": "string" + }, + "include_bots": { + "description": "Include crawler/datacenter (bot) samples. Defaults to false.", + "type": [ + "boolean", + "null" + ] + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "start_date": { + "format": "date-time", + "type": "string" + } + }, + "required": [ + "start_date", + "end_date", + "project_id", + "group_by" + ], + "type": "object" + } + ] + }, + "GroupedPageMetricsResponse": { + "properties": { + "grouped_by": { + "type": "string" + }, + "groups": { + "items": { + "$ref": "#/components/schemas/GroupedPageMetric" + }, + "type": "array" + }, + "total_events": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "groups", + "total_events", + "grouped_by" + ], + "type": "object" + }, + "HasAnalyticsEventsResponse": { + "properties": { + "has_events": { + "type": "boolean" + } + }, + "required": [ + "has_events" + ], + "type": "object" + }, + "HasErrorGroupsResponse": { + "properties": { + "has_error_groups": { + "type": "boolean" + } + }, + "required": [ + "has_error_groups" + ], + "type": "object" + }, + "HasEventsQuery": { + "properties": { + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "project_id": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "project_id" + ], + "type": "object" + }, + "HasEventsResponse": { + "properties": { + "has_events": { + "type": "boolean" + } + }, + "required": [ + "has_events" + ], + "type": "object" + }, + "HasMetricsQuery": { + "properties": { + "project_id": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "project_id" + ], + "type": "object" + }, + "HasMetricsResponse": { + "properties": { + "has_metrics": { + "type": "boolean" + } + }, + "required": [ + "has_metrics" + ], + "type": "object" + }, + "HealthCheckConfiguration": { + "description": "Health check configuration", + "properties": { + "http_path": { + "description": "HTTP path to check (if applicable)", + "type": [ + "string", + "null" + ] + }, + "interval": { + "description": "Interval between checks (seconds)", + "format": "int32", + "minimum": 0, + "type": "integer" + }, + "port": { + "description": "Port to check", + "format": "int32", + "minimum": 0, + "type": "integer" + }, + "retries": { + "description": "Number of retries before marking unhealthy", + "format": "int32", + "minimum": 0, + "type": "integer" + }, + "timeout": { + "description": "Timeout for each check (seconds)", + "format": "int32", + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "port", + "interval", + "timeout", + "retries" + ], + "type": "object" + }, + "HealthCheckEntryResponse": { + "properties": { + "checked_at": { + "description": "ISO 8601 timestamp of when the probe ran.", + "example": "2026-04-22T11:30:00Z", + "type": "string" + }, + "error_message": { + "description": "Present only when the probe failed or was degraded.", + "type": [ + "string", + "null" + ] + }, + "response_time_ms": { + "description": "TCP connect latency in milliseconds.", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "status": { + "description": "\"operational\" | \"degraded\" | \"down\"", + "example": "operational", + "type": "string" + } + }, + "required": [ + "checked_at", + "status" + ], + "type": "object" + }, + "HealthResponse": { + "properties": { + "summaries": { + "items": { + "$ref": "#/components/schemas/HealthSummary" + }, + "type": "array" + } + }, + "required": [ + "summaries" + ], + "type": "object" + }, + "HealthStatus": { + "description": "Overall health status.", + "enum": [ + "healthy", + "degraded", + "down", + "unknown" + ], + "type": "string" + }, + "HealthSummary": { + "description": "Pre-computed health summary for a project environment.", + "properties": { + "computed_at": { + "format": "date-time", + "type": "string" + }, + "cpu_usage_pct": { + "format": "double", + "type": "number" + }, + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "error_rate": { + "format": "double", + "type": "number" + }, + "last_deploy_at": { + "format": "date-time", + "type": [ + "string", + "null" + ] + }, + "last_deploy_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "memory_usage_pct": { + "format": "double", + "type": "number" + }, + "p95_latency_ms": { + "format": "double", + "type": "number" + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "service_name": { + "type": "string" + }, + "status": { + "$ref": "#/components/schemas/HealthStatus" + }, + "uptime_pct": { + "format": "double", + "type": "number" + } + }, + "required": [ + "project_id", + "service_name", + "status", + "uptime_pct", + "error_rate", + "p95_latency_ms", + "cpu_usage_pct", + "memory_usage_pct", + "computed_at" + ], + "type": "object" + }, + "HeartbeatApiRequest": { + "properties": { + "architecture": { + "description": "Container platform of this node's Docker daemon (`linux/amd64`,\n`linux/arm64`), read from `docker info` by the agent. Absent from\npre-multi-arch agents; the stored value is then left untouched.", + "type": [ + "string", + "null" + ] + }, + "capacity": { + "description": "Resource capacity/usage info as JSON (cpu_usage, memory_usage, etc.)" + }, + "containers": { + "description": "Container inventory for reconciliation (sent on first heartbeat after agent startup).\nEach entry has `container_id` and `container_name` of temps-managed containers.", + "items": { + "$ref": "#/components/schemas/ContainerInventoryItem" + }, + "type": [ + "array", + "null" + ] + }, + "labels": { + "description": "Updated node labels for scheduling (allows runtime label changes)." + } + }, + "type": "object" + }, + "HeartbeatResponse": { + "properties": { + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + }, + "required": [ + "status", + "message" + ], + "type": "object" + }, + "HierarchyLevel": { + "description": "Describes a level in the data source hierarchy", + "properties": { + "can_list_containers": { + "description": "Can list containers at this level?", + "example": true, + "type": "boolean" + }, + "can_list_entities": { + "description": "Can list entities at this level?", + "example": false, + "type": "boolean" + }, + "container_type": { + "description": "Type of container at this level", + "example": "database", + "type": "string" + }, + "level": { + "description": "Level number (0 = root)", + "example": 0, + "format": "int32", + "minimum": 0, + "type": "integer" + }, + "name": { + "description": "Human-readable name for this level", + "example": "root", + "type": "string" + } + }, + "required": [ + "level", + "name", + "container_type", + "can_list_containers", + "can_list_entities" + ], + "type": "object" + }, + "HistogramSummary": { + "description": "An explicit-bucket histogram aggregated over a time bucket.\n\nCarries the reduced scalars (count/sum/min/max) plus the explicit bucket\nlayout — `bounds` (the upper bounds) and `bucket_counts` (observation counts,\nsummed element-wise across the window; length is `bounds.len() + 1`, the last\nentry being the +Inf overflow bucket). With these, a caller can reconstruct\nany quantile (e.g. p95) via cumulative-count interpolation.", + "properties": { + "bounds": { + "description": "Explicit bucket upper bounds (OTLP `explicit_bounds`), ascending.", + "items": { + "format": "double", + "type": "number" + }, + "type": "array" + }, + "bucket_counts": { + "description": "Per-bucket observation counts summed element-wise across the window.\nLength is `bounds.len() + 1` (the trailing element is the +Inf bucket).", + "items": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "type": "array" + }, + "count": { + "description": "Total observation count summed across the bucket window.", + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "max": { + "description": "Maximum observed value, when reported by the producer.", + "format": "double", + "type": [ + "number", + "null" + ] + }, + "min": { + "description": "Minimum observed value, when reported by the producer.", + "format": "double", + "type": [ + "number", + "null" + ] + }, + "sum": { + "description": "Sum of observed values across the bucket window.", + "format": "double", + "type": "number" + } + }, + "required": [ + "count", + "sum", + "bounds", + "bucket_counts" + ], + "type": "object" + }, + "HostnameChange": { + "description": "A single generated-hostname change in a flatten preview/apply.", + "properties": { + "id": { + "description": "Row id of the affected record.", + "format": "int32", + "type": "integer" + }, + "kind": { + "description": "`\"deployment\"` or `\"environment\"`.", + "type": "string" + }, + "new": { + "type": "string" + }, + "old": { + "type": "string" + } + }, + "required": [ + "kind", + "id", + "old", + "new" + ], + "type": "object" + }, + "HostnamePreviewResponse": { + "description": "Combined preview of a hostname-mode change.", + "properties": { + "dns_changes": { + "items": { + "$ref": "#/components/schemas/DnsRecordChange" + }, + "type": "array" + }, + "hostname_changes": { + "items": { + "$ref": "#/components/schemas/HostnameChange" + }, + "type": "array" + }, + "total": { + "minimum": 0, + "type": "integer" + }, + "zone_access_ok": { + "description": "Whether the provider token can manage this zone (None if not checked).", + "type": [ + "boolean", + "null" + ] + } + }, + "required": [ + "hostname_changes", + "dns_changes", + "total" + ], + "type": "object" + }, + "HourlyPageSessions": { + "properties": { + "avg_duration_seconds": { + "format": "double", + "type": "number" + }, + "event_count": { + "format": "int64", + "type": "integer" + }, + "session_count": { + "format": "int64", + "type": "integer" + }, + "timestamp": { + "type": "string" + } + }, + "required": [ + "timestamp", + "session_count", + "event_count", + "avg_duration_seconds" + ], + "type": "object" + }, + "HourlyVisitsQuery": { + "properties": { + "aggregation_level": { + "$ref": "#/components/schemas/AggregationLevel", + "description": "Aggregation level: events (page views), sessions (unique sessions), or visitors (unique visitors)" + }, + "end_date": { + "format": "date-time", + "type": "string" + }, + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "start_date": { + "format": "date-time", + "type": "string" + } + }, + "required": [ + "start_date", + "end_date" + ], + "type": "object" + }, + "HttpChallengeDebugResponse": { + "properties": { + "challenge_exists": { + "type": "boolean" + }, + "challenge_token": { + "type": [ + "string", + "null" + ] + }, + "challenge_url": { + "description": "The full URL that Let's Encrypt will try to access to validate the challenge", + "type": [ + "string", + "null" + ] + }, + "dns_a_records": { + "description": "IPv4 addresses the domain points to", + "items": { + "type": "string" + }, + "type": "array" + }, + "dns_aaaa_records": { + "description": "IPv6 addresses the domain points to", + "items": { + "type": "string" + }, + "type": "array" + }, + "dns_error": { + "description": "Any DNS resolution errors", + "type": [ + "string", + "null" + ] + }, + "domain": { + "type": "string" + }, + "validation_url": { + "description": "The ACME validation URL (internal to ACME protocol)", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "domain", + "challenge_exists", + "dns_a_records", + "dns_aaaa_records" + ], + "type": "object" + }, + "ImportCredentials": { + "description": "Platform-specific credentials for accessing the source system.\n\nFor platforms like Vercel and Railway, this contains the API token.\nFor self-hosted platforms like Coolify and Dokploy, this also contains\nthe `base_url` of the instance.\n\nLocal importers (Docker) can use `ImportCredentials::none()`.", + "properties": { + "base_url": { + "description": "Base URL override (for self-hosted platforms like Coolify, Dokploy)\n\nExample: `https://coolify.example.com`", + "type": [ + "string", + "null" + ] + }, + "extra": { + "additionalProperties": { + "type": "string" + }, + "description": "Additional platform-specific parameters", + "propertyNames": { + "type": "string" + }, + "type": "object" + }, + "team_id": { + "description": "Team or organization ID (for platforms with team scoping like Vercel)", + "type": [ + "string", + "null" + ] + }, + "token": { + "description": "API token / bearer token for the source platform", + "type": [ + "string", + "null" + ] + } + }, + "type": "object" + }, + "ImportExecutionStatus": { + "description": "Import execution status", + "enum": [ + "pending", + "inprogress", + "completed", + "failed" + ], + "type": "string" + }, + "ImportExternalServiceRequest": { + "description": "Request to import a Docker container as a managed service", + "properties": { + "container_id": { + "description": "Container ID or name to import", + "example": "abc123def456", + "type": "string" + }, + "name": { + "description": "Name to register the service as in Temps", + "example": "production-database", + "type": "string" + }, + "parameters": { + "additionalProperties": {}, + "description": "Service configuration parameters", + "propertyNames": { + "type": "string" + }, + "type": "object" + }, + "service_type": { + "$ref": "#/components/schemas/ServiceTypeRoute", + "description": "Service type" + }, + "version": { + "description": "Optional version override", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "name", + "service_type", + "parameters", + "container_id" + ], + "type": "object" + }, + "ImportOutcomeResponse": { + "properties": { + "errors": { + "items": { + "$ref": "#/components/schemas/ImportRowErrorResponse" + }, + "type": "array" + }, + "inserted": { + "minimum": 0, + "type": "integer" + }, + "rows_read": { + "minimum": 0, + "type": "integer" + }, + "skipped_invalid": { + "minimum": 0, + "type": "integer" + }, + "skipped_stale": { + "minimum": 0, + "type": "integer" + }, + "updated": { + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "rows_read", + "inserted", + "updated", + "skipped_stale", + "skipped_invalid", + "errors" + ], + "type": "object" + }, + "ImportPlan": { + "description": "Complete import plan describing all operations to onboard a workload.\n\nThe plan is generated from a snapshot and presented to the user for review\nbefore any resources are created. Users can modify individual items\n(skip services, change actions) before approving execution.", + "properties": { + "additional_deployments": { + "description": "Additional deployments (workers, cron jobs, etc.)", + "items": { + "$ref": "#/components/schemas/DeploymentConfiguration" + }, + "type": "array" + }, + "cost_analysis": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/CostAnalysis", + "description": "Cost, overprovisioning, and savings analysis. Populated by importers\nthat can observe the whole source cluster (currently Kubernetes);\n`None` for container/platform imports." + } + ] + }, + "deployment": { + "$ref": "#/components/schemas/DeploymentConfiguration", + "description": "Primary deployment configuration" + }, + "domains": { + "description": "Custom domains to migrate", + "items": { + "$ref": "#/components/schemas/DomainPlan" + }, + "type": "array" + }, + "environment": { + "$ref": "#/components/schemas/EnvironmentConfiguration", + "description": "Environment configuration" + }, + "metadata": { + "$ref": "#/components/schemas/PlanMetadata", + "description": "Plan metadata" + }, + "project": { + "$ref": "#/components/schemas/ProjectConfiguration", + "description": "Project configuration" + }, + "services": { + "description": "Services to migrate (databases, caches, blob stores)\n\nEach service has an `action` field the user can change before execution.", + "items": { + "$ref": "#/components/schemas/ServicePlan" + }, + "type": "array" + }, + "source": { + "description": "Source system this plan was generated from", + "type": "string" + }, + "source_id": { + "description": "Source workload / project ID in the source system", + "type": "string" + }, + "steps": { + "description": "Ordered list of migration steps that will be executed.\n\nThis is the human-readable execution plan. Each step describes what\nwill happen, what risks are involved, and what the user should verify.\nSteps are executed in order. If a step fails, execution stops and\nalready-created resources are reported for manual cleanup.", + "items": { + "$ref": "#/components/schemas/MigrationStep" + }, + "type": "array" + }, + "summary": { + "$ref": "#/components/schemas/MigrationSummary", + "description": "Human-readable summary of the entire migration" + }, + "version": { + "description": "Plan version for compatibility tracking", + "type": "string" + } + }, + "required": [ + "version", + "source", + "source_id", + "project", + "environment", + "deployment", + "summary", + "metadata" + ], + "type": "object" + }, + "ImportRowErrorResponse": { + "properties": { + "reason": { + "type": "string" + }, + "row": { + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "row", + "reason" + ], + "type": "object" + }, + "ImportSelector": { + "description": "Selector for discovering workloads", + "properties": { + "label_filter": { + "additionalProperties": { + "type": "string" + }, + "description": "Filter by labels/tags", + "propertyNames": { + "type": "string" + }, + "type": [ + "object", + "null" + ] + }, + "limit": { + "description": "Limit number of results", + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "name_pattern": { + "description": "Filter by name pattern (glob/regex)", + "type": [ + "string", + "null" + ] + }, + "status_filter": { + "description": "Filter by status (running, stopped, deployed, etc.)", + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + }, + "workload_type_filter": { + "description": "Filter by workload type (container, function, static-site, etc.)", + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + } + }, + "type": "object" + }, + "ImportSource": { + "description": "Import source identifier", + "enum": [ + "docker", + "coolify", + "dokploy", + "vercel", + "netlify", + "railway", + "render", + "fly", + "kubernetes", + "caprover", + "portainer", + "kamal", + "custom" + ], + "type": "string" + }, + "ImportSourceCapabilities": { + "description": "Source capabilities", + "properties": { + "requires_credentials": { + "description": "Whether this source requires API credentials (token, base URL)", + "type": "boolean" + }, + "supports_build": { + "type": "boolean" + }, + "supports_cost_analysis": { + "description": "Supports cluster cost + overprovisioning analysis in the plan", + "type": "boolean" + }, + "supports_domains": { + "description": "Supports custom domain migration", + "type": "boolean" + }, + "supports_health_checks": { + "type": "boolean" + }, + "supports_networks": { + "type": "boolean" + }, + "supports_project_snapshot": { + "description": "Supports full project-level snapshots", + "type": "boolean" + }, + "supports_resource_limits": { + "type": "boolean" + }, + "supports_services": { + "description": "Supports service migration (databases, caches, etc.)", + "type": "boolean" + }, + "supports_volumes": { + "type": "boolean" + } + }, + "required": [ + "supports_volumes", + "supports_networks", + "supports_health_checks", + "supports_resource_limits", + "supports_build", + "supports_services", + "supports_domains", + "supports_project_snapshot", + "supports_cost_analysis", + "requires_credentials" + ], + "type": "object" + }, + "ImportSourceInfo": { + "description": "Information about an import source", + "properties": { + "available": { + "description": "Whether the source is currently available", + "type": "boolean" + }, + "capabilities": { + "$ref": "#/components/schemas/ImportSourceCapabilities", + "description": "Capabilities" + }, + "name": { + "description": "Human-readable name", + "type": "string" + }, + "source": { + "$ref": "#/components/schemas/ImportSource", + "description": "Source identifier" + }, + "version": { + "description": "Source version", + "type": "string" + } + }, + "required": [ + "source", + "name", + "version", + "available", + "capabilities" + ], + "type": "object" + }, + "ImportStatusResponse": { + "description": "Response with import status", + "properties": { + "created_at": { + "description": "Created at timestamp", + "format": "date-time", + "type": "string" + }, + "deployment_id": { + "description": "Created deployment ID", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "environment_id": { + "description": "Created environment ID", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "errors": { + "description": "Errors (if any)", + "items": { + "type": "string" + }, + "type": "array" + }, + "plan": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/ImportPlan", + "description": "Import plan" + } + ] + }, + "project_id": { + "description": "Created project ID", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "session_id": { + "description": "Session ID", + "type": "string" + }, + "status": { + "$ref": "#/components/schemas/ImportExecutionStatus", + "description": "Current status" + }, + "updated_at": { + "description": "Updated at timestamp", + "format": "date-time", + "type": "string" + }, + "validation": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/ValidationReport", + "description": "Validation report" + } + ] + }, + "warnings": { + "description": "Warnings (if any)", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "session_id", + "status", + "errors", + "warnings", + "created_at", + "updated_at" + ], + "type": "object" + }, + "IncidentBucket": { + "properties": { + "active_incidents": { + "format": "int64", + "type": "integer" + }, + "avg_resolution_time_minutes": { + "format": "double", + "type": [ + "number", + "null" + ] + }, + "bucket_start": { + "format": "date-time", + "type": "string" + }, + "critical_incidents": { + "format": "int64", + "type": "integer" + }, + "major_incidents": { + "format": "int64", + "type": "integer" + }, + "minor_incidents": { + "format": "int64", + "type": "integer" + }, + "resolved_incidents": { + "format": "int64", + "type": "integer" + }, + "total_incidents": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "bucket_start", + "total_incidents", + "minor_incidents", + "major_incidents", + "critical_incidents", + "resolved_incidents", + "active_incidents" + ], + "type": "object" + }, + "IncidentBucketedResponse": { + "properties": { + "buckets": { + "items": { + "$ref": "#/components/schemas/IncidentBucket" + }, + "type": "array" + }, + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "interval": { + "type": "string" + }, + "project_id": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "project_id", + "interval", + "buckets" + ], + "type": "object" + }, + "IncidentResponse": { + "properties": { + "created_at": { + "format": "date-time", + "type": "string" + }, + "description": { + "type": [ + "string", + "null" + ] + }, + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "id": { + "format": "int32", + "type": "integer" + }, + "monitor_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "resolved_at": { + "format": "date-time", + "type": [ + "string", + "null" + ] + }, + "severity": { + "type": "string" + }, + "started_at": { + "format": "date-time", + "type": "string" + }, + "status": { + "type": "string" + }, + "title": { + "type": "string" + }, + "updated_at": { + "format": "date-time", + "type": "string" + } + }, + "required": [ + "id", + "project_id", + "title", + "severity", + "status", + "started_at", + "created_at", + "updated_at" + ], + "type": "object" + }, + "IncidentUpdateResponse": { + "properties": { + "created_at": { + "format": "date-time", + "type": "string" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "incident_id": { + "format": "int32", + "type": "integer" + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + }, + "required": [ + "id", + "incident_id", + "status", + "message", + "created_at" + ], + "type": "object" + }, + "IncrRequest": { + "description": "Request to increment a value", + "properties": { + "amount": { + "description": "Amount to increment by (default: 1)", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "key": { + "description": "The key to increment", + "example": "counter", + "type": "string" + }, + "project_id": { + "description": "Project ID (required for API key/session auth, optional for deployment tokens)", + "example": 1, + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + "required": [ + "key" + ], + "type": "object" + }, + "IncrResponse": { + "description": "Response for increment operation", + "properties": { + "value": { + "description": "New value after increment", + "example": 42, + "format": "int64", + "type": "integer" + } + }, + "required": [ + "value" + ], + "type": "object" + }, + "InitAuthResponse": { + "properties": { + "auth_url": { + "type": "string" + }, + "session_token": { + "type": "string" + } + }, + "required": [ + "auth_url", + "session_token" + ], + "type": "object" + }, + "Insight": { + "description": "An anomaly insight.", + "properties": { + "anomaly_ids": { + "items": { + "format": "int64", + "type": "integer" + }, + "type": "array" + }, + "correlated_deploy_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "created_at": { + "format": "date-time", + "type": "string" + }, + "description": { + "type": "string" + }, + "environment": { + "type": [ + "string", + "null" + ] + }, + "id": { + "format": "int64", + "type": "integer" + }, + "metric_name": { + "type": [ + "string", + "null" + ] + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "resolved_at": { + "format": "date-time", + "type": [ + "string", + "null" + ] + }, + "service_name": { + "type": "string" + }, + "severity": { + "$ref": "#/components/schemas/InsightSeverity" + }, + "started_at": { + "format": "date-time", + "type": "string" + }, + "status": { + "$ref": "#/components/schemas/InsightStatus" + }, + "title": { + "type": "string" + }, + "updated_at": { + "format": "date-time", + "type": "string" + } + }, + "required": [ + "id", + "project_id", + "service_name", + "severity", + "status", + "title", + "description", + "anomaly_ids", + "started_at", + "created_at", + "updated_at" + ], + "type": "object" + }, + "InsightSeverity": { + "description": "Severity of an anomaly insight.", + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "type": "string" + }, + "InsightStatus": { + "description": "Status of an insight.", + "enum": [ + "active", + "resolved" + ], + "type": "string" + }, + "InsightsResponse": { + "properties": { + "count": { + "minimum": 0, + "type": "integer" + }, + "data": { + "items": { + "$ref": "#/components/schemas/Insight" + }, + "type": "array" + } + }, + "required": [ + "data", + "count" + ], + "type": "object" + }, + "IntegrationResponse": { + "properties": { + "config": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/ProviderConfig", + "description": "Typed provider config — allowlist and metered-billing mode. Null\nwhen the operator hasn't configured one yet (accept everything)." + } + ] + }, + "created_at": { + "format": "date-time", + "type": "string" + }, + "has_secret": { + "type": "boolean" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "last_event_at": { + "format": "date-time", + "type": [ + "string", + "null" + ] + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "provider": { + "type": "string" + }, + "status": { + "type": "string" + }, + "webhook_path": { + "description": "Relative path the UI can display and copy. The frontend builds\nthe full URL by prefixing its own origin.", + "type": "string" + }, + "webhook_path_token": { + "description": "Unguessable token embedded in the public webhook URL. The full\nURL is `{api_origin}/webhooks/revenue/{provider}/{webhook_path_token}`.", + "type": "string" + } + }, + "required": [ + "id", + "project_id", + "provider", + "webhook_path_token", + "webhook_path", + "status", + "has_secret", + "created_at" + ], + "type": "object" + }, + "IpAccessControlQuery": { + "description": "Query parameters for listing IP access control rules", + "properties": { + "action": { + "description": "Filter by action (\"block\" or \"allow\")", + "type": [ + "string", + "null" + ] + } + }, + "type": "object" + }, + "IpAccessControlResponse": { + "description": "Response model for IP access control rules", + "properties": { + "action": { + "type": "string" + }, + "created_at": { + "example": "2025-10-12T12:15:47.609Z", + "type": "string" + }, + "created_by": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "id": { + "format": "int32", + "type": "integer" + }, + "ip_address": { + "type": "string" + }, + "reason": { + "type": [ + "string", + "null" + ] + }, + "updated_at": { + "example": "2025-10-12T12:15:47.609Z", + "type": "string" + } + }, + "required": [ + "id", + "ip_address", + "action", + "created_at", + "updated_at" + ], + "type": "object" + }, + "JobStatusResponse": { + "description": "Snapshot of a background job. `status` is one of \"running\" | \"exited\"\n| \"failed\"; `exit_code` is populated only when `status == \"exited\"`.", + "properties": { + "exit_code": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "reason": { + "type": [ + "string", + "null" + ] + }, + "status": { + "type": "string" + }, + "stderr": { + "type": "string" + }, + "stdout": { + "type": "string" + } + }, + "required": [ + "status", + "stdout", + "stderr" + ], + "type": "object" + }, + "JobSummaryResponse": { + "description": "Row in the jobs list. Omits stdout/stderr so a noisy dev server doesn't\nbloat the list payload — callers drill into `GET /jobs/{id}` for the\nfull buffer.", + "properties": { + "cmd": { + "type": "string" + }, + "exit_code": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "id": { + "type": "string" + }, + "reason": { + "type": [ + "string", + "null" + ] + }, + "started_at": { + "type": "string" + }, + "status": { + "type": "string" + } + }, + "required": [ + "id", + "status", + "cmd", + "started_at" + ], + "type": "object" + }, + "JoinTokenStatusResponse": { + "description": "Response for join token status check", + "properties": { + "has_token": { + "description": "Whether a join token has been configured", + "type": "boolean" + } + }, + "required": [ + "has_token" + ], + "type": "object" + }, + "JourneyEvent": { + "description": "A single event in the visitor journey timeline", + "properties": { + "event_data": { + "description": "Custom event properties (for custom events)" + }, + "event_name": { + "description": "Resolved event name (event_name for custom events, event_type for system events)", + "type": "string" + }, + "event_type": { + "description": "Event type: \"page_view\", \"page_leave\", \"custom\", \"web_vitals\"", + "type": "string" + }, + "id": { + "description": "Event ID", + "format": "int64", + "type": "integer" + }, + "is_bounce": { + "description": "Whether this was a bounce", + "type": "boolean" + }, + "is_entry": { + "description": "Whether this is the entry page of the session", + "type": "boolean" + }, + "is_exit": { + "description": "Whether this is the exit page of the session", + "type": "boolean" + }, + "occurred_at": { + "description": "When the event occurred", + "format": "date-time", + "type": "string" + }, + "page_path": { + "description": "Page path where the event happened", + "type": [ + "string", + "null" + ] + }, + "page_title": { + "description": "Page title (if available)", + "type": [ + "string", + "null" + ] + }, + "referrer": { + "description": "Referrer URL for this event", + "type": [ + "string", + "null" + ] + }, + "scroll_depth": { + "description": "Scroll depth percentage (0-100)", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "session_page_number": { + "description": "Page number within the session (1-indexed)", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "time_on_page": { + "description": "Time spent on page in seconds (computed, not from column)", + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + "required": [ + "id", + "event_type", + "event_name", + "occurred_at", + "is_entry", + "is_exit", + "is_bounce" + ], + "type": "object" + }, + "JourneySession": { + "description": "A session within the visitor journey, grouping events", + "properties": { + "channel": { + "description": "Traffic source: channel (e.g. \"organic\", \"direct\", \"social\")", + "type": [ + "string", + "null" + ] + }, + "duration_seconds": { + "description": "Session duration in seconds", + "format": "int64", + "type": "integer" + }, + "ended_at": { + "description": "When the session ended", + "format": "date-time", + "type": [ + "string", + "null" + ] + }, + "entry_path": { + "description": "Entry page path", + "type": [ + "string", + "null" + ] + }, + "events": { + "description": "Events within this session, ordered chronologically", + "items": { + "$ref": "#/components/schemas/JourneyEvent" + }, + "type": "array" + }, + "events_count": { + "description": "Total events in this session", + "format": "int64", + "type": "integer" + }, + "exit_path": { + "description": "Exit page path", + "type": [ + "string", + "null" + ] + }, + "is_bounced": { + "description": "Whether the session was a bounce", + "type": "boolean" + }, + "is_engaged": { + "description": "Whether the visitor was engaged (had non-pageview events)", + "type": "boolean" + }, + "page_views": { + "description": "Number of page views in this session", + "format": "int64", + "type": "integer" + }, + "referrer": { + "description": "Traffic source: referrer URL", + "type": [ + "string", + "null" + ] + }, + "referrer_hostname": { + "description": "Traffic source: referrer hostname", + "type": [ + "string", + "null" + ] + }, + "session_id": { + "description": "Session internal ID", + "format": "int32", + "type": "integer" + }, + "started_at": { + "description": "When the session started", + "format": "date-time", + "type": "string" + }, + "utm_campaign": { + "description": "UTM campaign parameter", + "type": [ + "string", + "null" + ] + }, + "utm_medium": { + "description": "UTM medium parameter", + "type": [ + "string", + "null" + ] + }, + "utm_source": { + "description": "UTM source parameter", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "session_id", + "started_at", + "duration_seconds", + "page_views", + "events_count", + "is_bounced", + "is_engaged", + "events" + ], + "type": "object" + }, + "KeysRequest": { + "description": "Request to get keys matching a pattern", + "properties": { + "pattern": { + "description": "Pattern to match (supports * and ? wildcards)", + "example": "user:*", + "type": "string" + }, + "project_id": { + "description": "Project ID (required for API key/session auth, optional for deployment tokens)", + "example": 1, + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + "required": [ + "pattern" + ], + "type": "object" + }, + "KeysResponse": { + "description": "Response for keys operation", + "properties": { + "keys": { + "description": "List of matching keys", + "example": [ + "user:1", + "user:2", + "user:3" + ], + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "keys" + ], + "type": "object" + }, + "KillJobBody": { + "additionalProperties": false, + "properties": { + "force": { + "description": "When true, sends SIGKILL immediately. Defaults to SIGTERM so the\nprocess gets a chance to flush (mirrors `Command.kill()` in\n`@vercel/sandbox`, which also accepts a signal override).", + "type": "boolean" + } + }, + "type": "object" + }, + "KnownAiAgentsResponse": { + "description": "Response listing every AI agent the detector knows about.", + "properties": { + "items": { + "items": { + "$ref": "#/components/schemas/AiAgentDescriptor" + }, + "type": "array" + } + }, + "required": [ + "items" + ], + "type": "object" + }, + "KvStatusResponse": { + "description": "Response for KV service status", + "properties": { + "docker_image": { + "description": "Docker image being used", + "example": "gotempsh/redis-walg:8-bookworm", + "type": [ + "string", + "null" + ] + }, + "enabled": { + "description": "Whether the KV service is enabled", + "type": "boolean" + }, + "healthy": { + "description": "Whether the underlying Redis service is healthy", + "type": "boolean" + }, + "version": { + "description": "Service version", + "example": "7.2", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "enabled", + "healthy" + ], + "type": "object" + }, + "LemonSqueezyConfig": { + "properties": { + "product_allowlist": { + "items": { + "type": "string" + }, + "type": "array" + }, + "variant_allowlist": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "LetsEncryptSettings": { + "properties": { + "email": { + "default": null, + "type": [ + "string", + "null" + ] + }, + "environment": { + "default": "production", + "type": "string" + } + }, + "type": "object" + }, + "LineContext": { + "description": "Raw surrounding lines for a single match (grep -C style).", + "properties": { + "after": { + "description": "Lines immediately after the match, oldest-first.", + "items": { + "$ref": "#/components/schemas/ContextLine" + }, + "type": "array" + }, + "before": { + "description": "Lines immediately before the match, oldest-first.", + "items": { + "$ref": "#/components/schemas/ContextLine" + }, + "type": "array" + } + }, + "required": [ + "before", + "after" + ], + "type": "object" + }, + "LinkServiceRequest": { + "properties": { + "project_id": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "project_id" + ], + "type": "object" + }, + "ListAgentsResponse": { + "properties": { + "items": { + "items": { + "$ref": "#/components/schemas/AgentConfigResponse" + }, + "type": "array" + }, + "total": { + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "items", + "total" + ], + "type": "object" + }, + "ListApiKeysQuery": { + "properties": { + "page": { + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "page_size": { + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + } + }, + "type": "object" + }, + "ListAuditLogsQuery": { + "description": "Query parameters for listing audit logs.\n\nEvery field is optional — omitting one means \"don't filter on it\". Deriving\n`IntoParams` makes utoipa render them as optional query params with the\ncorrect types; the previous hand-written `params((\"operation_type\", Query,\n…))` tuples defaulted every param to `required: true, type: string`, which\nmisled both API clients and the AI `describe_api`/`call_api` tools into\nthinking all filters were mandatory.", + "properties": { + "from": { + "description": "Start timestamp (milliseconds since epoch)", + "format": "date-time", + "type": [ + "string", + "null" + ] + }, + "limit": { + "description": "Maximum number of logs to return", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "offset": { + "description": "Number of logs to skip", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "operation_type": { + "description": "Filter logs by operation type (omit for all)", + "type": [ + "string", + "null" + ] + }, + "to": { + "description": "End timestamp (milliseconds since epoch)", + "format": "date-time", + "type": [ + "string", + "null" + ] + }, + "user_id": { + "description": "Filter logs by user ID (omit for all users)", + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + "type": "object" + }, + "ListBlobsQuery": { + "description": "Query parameters for listing blobs", + "properties": { + "cursor": { + "description": "Continuation token for pagination", + "type": [ + "string", + "null" + ] + }, + "limit": { + "description": "Maximum number of items to return", + "example": 100, + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "prefix": { + "description": "Prefix to filter by", + "example": "images/", + "type": [ + "string", + "null" + ] + }, + "project_id": { + "description": "Project ID (required for API key/session auth, optional for deployment tokens)", + "example": 1, + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + "type": "object" + }, + "ListBlobsResponse": { + "description": "Response for listing blobs", + "properties": { + "blobs": { + "description": "List of blobs", + "items": { + "$ref": "#/components/schemas/BlobResponse" + }, + "type": "array" + }, + "cursor": { + "description": "Continuation token for next page", + "type": [ + "string", + "null" + ] + }, + "hasMore": { + "description": "Whether there are more results", + "example": false, + "type": "boolean" + } + }, + "required": [ + "blobs", + "hasMore" + ], + "type": "object" + }, + "ListCustomDomainsResponse": { + "properties": { + "domains": { + "items": { + "$ref": "#/components/schemas/CustomDomainResponse" + }, + "type": "array" + }, + "total": { + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "domains", + "total" + ], + "type": "object" + }, + "ListDeploymentTokensQuery": { + "properties": { + "page": { + "example": 1, + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "page_size": { + "example": 20, + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + } + }, + "type": "object" + }, + "ListDomainsResponse": { + "properties": { + "domains": { + "items": { + "$ref": "#/components/schemas/DomainResponse" + }, + "type": "array" + }, + "page": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "page_size": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "total": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "domains", + "total", + "page", + "page_size" + ], + "type": "object" + }, + "ListEntitiesQuery": { + "properties": { + "limit": { + "description": "Maximum number of entities to return", + "example": 100, + "minimum": 0, + "type": "integer" + }, + "token": { + "description": "Continuation token for pagination (backend-specific)", + "type": [ + "string", + "null" + ] + } + }, + "type": "object" + }, + "ListErrorEventsQuery": { + "properties": { + "page": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "page_size": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + "type": "object" + }, + "ListErrorGroupsQuery": { + "properties": { + "end_date": { + "format": "date-time", + "type": [ + "string", + "null" + ] + }, + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "page": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "page_size": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "sort_by": { + "type": [ + "string", + "null" + ] + }, + "sort_order": { + "type": "string" + }, + "start_date": { + "format": "date-time", + "type": [ + "string", + "null" + ] + }, + "status": { + "type": [ + "string", + "null" + ] + } + }, + "type": "object" + }, + "ListJobsResponse": { + "properties": { + "items": { + "items": { + "$ref": "#/components/schemas/JobSummaryResponse" + }, + "type": "array" + } + }, + "required": [ + "items" + ], + "type": "object" + }, + "ListMcpsResponse": { + "description": "Concrete list wrapper for MCP server definitions (utoipa requires non-generic types).", + "properties": { + "items": { + "items": { + "$ref": "#/components/schemas/McpDefinitionResponse" + }, + "type": "array" + }, + "total": { + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "items", + "total" + ], + "type": "object" + }, + "ListOnDemandCertsResponse": { + "description": "Paginated list of on-demand cert attempts (ADR-018 §5 console \"Certificates\"\nsurface). Joined with current `domains.status`, newest first.", + "properties": { + "certs": { + "items": { + "$ref": "#/components/schemas/OnDemandCertRow" + }, + "type": "array" + }, + "page": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "page_size": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "total": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "certs", + "total", + "page", + "page_size" + ], + "type": "object" + }, + "ListOrdersResponse": { + "properties": { + "orders": { + "items": { + "$ref": "#/components/schemas/AcmeOrderResponse" + }, + "type": "array" + } + }, + "required": [ + "orders" + ], + "type": "object" + }, + "ListPresetsResponse": { + "properties": { + "presets": { + "items": { + "$ref": "#/components/schemas/PresetResponse" + }, + "type": "array" + }, + "total": { + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "presets", + "total" + ], + "type": "object" + }, + "ListRunsResponse": { + "properties": { + "items": { + "items": { + "$ref": "#/components/schemas/AgentRunResponse" + }, + "type": "array" + }, + "page": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "page_size": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "total": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "items", + "total", + "page", + "page_size" + ], + "type": "object" + }, + "ListSandboxesResponse": { + "description": "SDK list response: `{ sandboxes: [...], pagination: {...} }`.", + "properties": { + "pagination": { + "$ref": "#/components/schemas/Pagination" + }, + "sandboxes": { + "items": { + "$ref": "#/components/schemas/SandboxInner" + }, + "type": "array" + } + }, + "required": [ + "sandboxes", + "pagination" + ], + "type": "object" + }, + "ListScansQuery": { + "properties": { + "page": { + "example": 1, + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "page_size": { + "example": 20, + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + } + }, + "type": "object" + }, + "ListSecretsResponse": { + "properties": { + "items": { + "items": { + "$ref": "#/components/schemas/SecretResponse" + }, + "type": "array" + }, + "total": { + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "items", + "total" + ], + "type": "object" + }, + "ListSkillsResponse": { + "description": "Concrete list wrapper for skill definitions (utoipa requires non-generic types).", + "properties": { + "items": { + "items": { + "$ref": "#/components/schemas/SkillDefinitionResponse" + }, + "type": "array" + }, + "total": { + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "items", + "total" + ], + "type": "object" + }, + "ListTagsResponse": { + "description": "Response for listing tags", + "properties": { + "tags": { + "description": "List of available tags", + "items": { + "type": "string" + }, + "type": "array" + }, + "total": { + "description": "Total number of tags", + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "tags", + "total" + ], + "type": "object" + }, + "ListTemplatesQuery": { + "description": "Query parameters for listing templates", + "properties": { + "featured": { + "description": "Only return featured templates", + "type": [ + "boolean", + "null" + ] + }, + "tag": { + "description": "Filter templates by tag", + "type": [ + "string", + "null" + ] + } + }, + "type": "object" + }, + "ListTemplatesResponse": { + "description": "Response for listing templates", + "properties": { + "templates": { + "description": "List of templates", + "items": { + "$ref": "#/components/schemas/TemplateResponse" + }, + "type": "array" + }, + "total": { + "description": "Total number of templates", + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "templates", + "total" + ], + "type": "object" + }, + "ListVulnerabilitiesQuery": { + "properties": { + "page": { + "example": 1, + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "page_size": { + "example": 20, + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "severity": { + "example": "CRITICAL", + "type": [ + "string", + "null" + ] + } + }, + "type": "object" + }, + "LiveVisitorInfo": { + "properties": { + "city": { + "type": [ + "string", + "null" + ] + }, + "country": { + "type": [ + "string", + "null" + ] + }, + "country_code": { + "type": [ + "string", + "null" + ] + }, + "crawler_name": { + "type": [ + "string", + "null" + ] + }, + "current_page": { + "description": "Most recent page path visited by this visitor", + "type": [ + "string", + "null" + ] + }, + "custom_data": {}, + "environment_id": { + "format": "int32", + "type": "integer" + }, + "first_channel": { + "description": "Marketing channel from the first visit (e.g. \"Organic Search\", \"Direct\")", + "type": [ + "string", + "null" + ] + }, + "first_referrer": { + "description": "Full referrer URL from the visitor's first session", + "type": [ + "string", + "null" + ] + }, + "first_referrer_hostname": { + "description": "Hostname extracted from first_referrer", + "type": [ + "string", + "null" + ] + }, + "first_seen": { + "example": "2024-01-01T00:00:00", + "format": "date-time", + "type": "string" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "ip_address": { + "type": [ + "string", + "null" + ] + }, + "ip_address_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "is_crawler": { + "type": "boolean" + }, + "is_eu": { + "type": [ + "boolean", + "null" + ] + }, + "last_seen": { + "example": "2024-01-01T00:00:00", + "format": "date-time", + "type": "string" + }, + "latitude": { + "format": "double", + "type": [ + "number", + "null" + ] + }, + "longitude": { + "format": "double", + "type": [ + "number", + "null" + ] + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "region": { + "type": [ + "string", + "null" + ] + }, + "timezone": { + "type": [ + "string", + "null" + ] + }, + "user_agent": { + "type": [ + "string", + "null" + ] + }, + "visitor_id": { + "type": "string" + } + }, + "required": [ + "id", + "visitor_id", + "project_id", + "environment_id", + "first_seen", + "last_seen", + "is_crawler" + ], + "type": "object" + }, + "LiveVisitorsListResponse": { + "properties": { + "total_count": { + "format": "int64", + "type": "integer" + }, + "visitors": { + "items": { + "$ref": "#/components/schemas/LiveVisitorInfo" + }, + "type": "array" + }, + "window_minutes": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "total_count", + "visitors", + "window_minutes" + ], + "type": "object" + }, + "LocationCount": { + "properties": { + "count": { + "format": "int64", + "type": "integer" + }, + "location": { + "type": "string" + }, + "percentage": { + "format": "double", + "type": "number" + } + }, + "required": [ + "location", + "count", + "percentage" + ], + "type": "object" + }, + "LocationGranularity": { + "enum": [ + "country", + "region", + "city" + ], + "type": "string" + }, + "LocationInfo": { + "properties": { + "city": { + "type": [ + "string", + "null" + ] + }, + "country": { + "type": [ + "string", + "null" + ] + }, + "region": { + "type": [ + "string", + "null" + ] + } + }, + "type": "object" + }, + "LogLevel": { + "description": "Normalized log level", + "enum": [ + "TRACE", + "DEBUG", + "INFO", + "WARN", + "ERROR" + ], + "type": "string" + }, + "LogRecord": { + "description": "A single log record ready for storage.", + "properties": { + "attributes": { + "additionalProperties": { + "type": "string" + }, + "propertyNames": { + "type": "string" + }, + "type": "object" + }, + "body": { + "type": "string" + }, + "deployment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "observed_timestamp": { + "format": "date-time", + "type": "string" + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "resource": { + "$ref": "#/components/schemas/ResourceInfo" + }, + "severity": { + "$ref": "#/components/schemas/LogSeverity" + }, + "severity_text": { + "type": "string" + }, + "span_id": { + "type": [ + "string", + "null" + ] + }, + "timestamp": { + "format": "date-time", + "type": "string" + }, + "trace_id": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "project_id", + "resource", + "timestamp", + "observed_timestamp", + "severity", + "severity_text", + "body", + "attributes" + ], + "type": "object" + }, + "LogSearchLine": { + "description": "A single line in search results", + "properties": { + "chunk_id": { + "type": "string" + }, + "container_id": { + "description": "Container this line came from — lets the UI tag/group lines by container\nin a combined (\"show all\") multi-container view.", + "type": "string" + }, + "context": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/LineContext", + "description": "Raw surrounding lines (grep -C). `None` unless `context_lines > 0` was\nrequested. Overlapping windows between nearby matches are merged: the\nshared neighbors appear on the earlier match only, so the frontend can\nrender one continuous block without duplicated lines." + } + ] + }, + "deploy_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "fields": {}, + "level": { + "$ref": "#/components/schemas/LogLevel" + }, + "line_offset": { + "format": "int32", + "type": "integer" + }, + "message": { + "type": "string" + }, + "node_id": { + "description": "Worker node the line came from (`None` = control-plane-local).", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "node_name": { + "description": "Human-readable node name for display.", + "type": [ + "string", + "null" + ] + }, + "service": { + "type": "string" + }, + "timestamp": { + "type": "string" + } + }, + "required": [ + "timestamp", + "level", + "service", + "message", + "chunk_id", + "line_offset" + ], + "type": "object" + }, + "LogSeverity": { + "description": "Log severity level (simplified from OTel's 24 levels).", + "enum": [ + "TRACE", + "DEBUG", + "INFO", + "WARN", + "ERROR", + "FATAL" + ], + "type": "string" + }, + "LogSource": { + "description": "A distinct log source (container) seen in the queried scope. Used to populate\nthe history filter dropdowns with the *full* set of containers/nodes for the\nproject + env + deployment + time window — independent of the active\ncontainer/node/service filter, so the user can switch between them.", + "properties": { + "container_id": { + "type": "string" + }, + "node_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "node_name": { + "type": [ + "string", + "null" + ] + }, + "service": { + "type": "string" + } + }, + "required": [ + "container_id", + "service" + ], + "type": "object" + }, + "LogStream": { + "description": "Log output stream", + "enum": [ + "stdout", + "stderr" + ], + "type": "string" + }, + "LoginRequest": { + "properties": { + "email": { + "type": "string" + }, + "password": { + "type": "string" + } + }, + "required": [ + "email", + "password" + ], + "type": "object" + }, + "LogsQuery": { + "properties": { + "tail": { + "description": "Number of lines to return from the tail. Defaults to 200, capped at 2000.", + "minimum": 0, + "type": [ + "integer", + "null" + ] + } + }, + "type": "object" + }, + "LogsResponse": { + "properties": { + "count": { + "minimum": 0, + "type": "integer" + }, + "data": { + "items": { + "$ref": "#/components/schemas/LogRecord" + }, + "type": "array" + } + }, + "required": [ + "data", + "count" + ], + "type": "object" + }, + "ManagedDomainResponse": { + "description": "Managed domain response", + "properties": { + "auto_manage": { + "type": "boolean" + }, + "created_at": { + "type": "string" + }, + "domain": { + "type": "string" + }, + "generated_hostname_mode": { + "description": "Generated hostname layout: `\"standard\"` or `\"flat\"`.", + "type": "string" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "provider_id": { + "format": "int32", + "type": "integer" + }, + "sync_generated_records": { + "description": "Whether generated hostnames are reconciled into the provider's DNS zone.", + "type": "boolean" + }, + "updated_at": { + "type": "string" + }, + "verification_error": { + "type": [ + "string", + "null" + ] + }, + "verified": { + "type": "boolean" + }, + "verified_at": { + "type": [ + "string", + "null" + ] + }, + "zone_access_error": { + "description": "Detail for a failed zone-access check.", + "type": [ + "string", + "null" + ] + }, + "zone_access_ok": { + "description": "Last token zone-access check: `Some(true)`/`Some(false)`/`None` (unchecked).", + "type": [ + "boolean", + "null" + ] + }, + "zone_id": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "id", + "provider_id", + "domain", + "auto_manage", + "verified", + "generated_hostname_mode", + "sync_generated_records", + "created_at", + "updated_at" + ], + "type": "object" + }, + "ManualAction": { + "description": "A manual action the user must perform outside of the automated migration", + "properties": { + "description": { + "description": "Human-readable description", + "type": "string" + }, + "reason": { + "description": "Why this can't be automated", + "type": "string" + }, + "timing": { + "$ref": "#/components/schemas/ManualActionTiming", + "description": "When this action needs to happen" + } + }, + "required": [ + "timing", + "description", + "reason" + ], + "type": "object" + }, + "ManualActionTiming": { + "description": "When a manual action needs to happen relative to migration", + "enum": [ + "before-migration", + "after-migration", + "within-hours" + ], + "type": "string" + }, + "McpDefinitionResponse": { + "properties": { + "config": { + "type": "object" + }, + "created_at": { + "type": "string" + }, + "description": { + "type": [ + "string", + "null" + ] + }, + "id": { + "format": "int32", + "type": "integer" + }, + "name": { + "type": "string" + }, + "project_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "slug": { + "type": "string" + }, + "updated_at": { + "type": "string" + } + }, + "required": [ + "id", + "slug", + "name", + "config", + "created_at", + "updated_at" + ], + "type": "object" + }, + "MessageContent": { + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "$ref": "#/components/schemas/ContentPart" + }, + "type": "array" + } + ] + }, + "MessagePart": { + "description": "One ordered segment of an assistant turn: a chunk of prose, or a tool\ninvocation. Mirrors the `metadata.parts` persisted by the chat service.", + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "text" + ], + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "type": "object" + }, + { + "properties": { + "tool": { + "$ref": "#/components/schemas/ToolInfo" + }, + "type": { + "enum": [ + "tool" + ], + "type": "string" + } + }, + "required": [ + "tool", + "type" + ], + "type": "object" + } + ] + }, + "MessageResponse": { + "properties": { + "content": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "parts": { + "description": "Ordered render segments (text / tool, in the order they occurred) so a\nreloaded chat shows the same interleaving as the live stream. Absent for\nolder messages persisted before parts were tracked; the client then falls\nback to `tools` (rendered first) + `content`.", + "items": { + "$ref": "#/components/schemas/MessagePart" + }, + "type": [ + "array", + "null" + ] + }, + "role": { + "type": "string" + }, + "tools": { + "description": "Tools the assistant ran on this turn (persisted in message metadata), so\nthe chat replays its tool work after a reload. Absent for plain turns.", + "items": { + "$ref": "#/components/schemas/ToolInfo" + }, + "type": [ + "array", + "null" + ] + } + }, + "required": [ + "role", + "content", + "created_at" + ], + "type": "object" + }, + "MeteredMode": { + "description": "How to treat metered-billing subscriptions when computing MRR.\n\n* `DeriveFromInvoices` (default): ignore the subscription row's\n `mrr_minor` for metered items and rely on the per-invoice\n [`NormalizedEventType::MrrRealized`] events instead. Correct for\n pure-metered, hybrid, tiered, and flat — recommended.\n* `UseSubscription`: trust whatever MRR the subscription parser\n returns (0 for metered). Legacy behavior.\n* `Ignore`: drop metered subscriptions from MRR entirely.", + "enum": [ + "derive_from_invoices", + "use_subscription", + "ignore" + ], + "type": "string" + }, + "MetricAggregation": { + "description": "The aggregation applied when reducing raw metric points into a time bucket.\n\nStore-neutral: every storage backend (ClickHouse today, TimescaleDB later)\nmust be able to satisfy this contract. `Quantile(q)` carries the requested\nquantile in `[0.0, 1.0]` (e.g. `0.95` for p95).", + "oneOf": [ + { + "description": "Arithmetic mean of the scalar value in each bucket. The default.", + "enum": [ + "avg" + ], + "type": "string" + }, + { + "description": "Sum of the scalar value in each bucket.", + "enum": [ + "sum" + ], + "type": "string" + }, + { + "description": "Minimum scalar value in each bucket.", + "enum": [ + "min" + ], + "type": "string" + }, + { + "description": "Maximum scalar value in each bucket.", + "enum": [ + "max" + ], + "type": "string" + }, + { + "description": "Number of points in each bucket.", + "enum": [ + "count" + ], + "type": "string" + }, + { + "description": "Per-second rate of change of a cumulative monotonic counter, computed as\n`(max - min) / window_seconds` within each bucket. Non-monotonic series\nfall back to a simple delta.", + "enum": [ + "rate_per_sec" + ], + "type": "string" + }, + { + "description": "A quantile of the scalar value in each bucket. The carried `f64` is the\nrequested quantile in `[0.0, 1.0]`.", + "properties": { + "quantile": { + "description": "A quantile of the scalar value in each bucket. The carried `f64` is the\nrequested quantile in `[0.0, 1.0]`.", + "format": "double", + "type": "number" + } + }, + "required": [ + "quantile" + ], + "type": "object" + } + ] + }, + "MetricBucket": { + "description": "A time-bucketed metric aggregate for chart display.\n\nStore-neutral response contract. The legacy scalar fields\n(`avg_value`/`min_value`/`max_value`/`count`) are always populated for chart\nback-compat. The richer fields describe the explicitly-requested\n[`MetricAggregation`] (`value`), optional `quantiles`, an optional\n`histogram_summary`, and a `series_key` identifying the label-set when the\nquery used `group_by`.", + "properties": { + "avg_value": { + "format": "double", + "type": "number" + }, + "bucket": { + "format": "date-time", + "type": "string" + }, + "count": { + "format": "int64", + "type": "integer" + }, + "histogram_summary": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/HistogramSummary", + "description": "A reduced histogram summary when the bucketed metric is a histogram." + } + ] + }, + "max_value": { + "format": "double", + "type": "number" + }, + "min_value": { + "format": "double", + "type": "number" + }, + "quantiles": { + "description": "Computed quantile/value pairs `(quantile, value)` when the query asked for\nquantile aggregation; otherwise empty.", + "items": { + "items": false, + "prefixItems": [ + { + "format": "double", + "type": "number" + }, + { + "format": "double", + "type": "number" + } + ], + "type": "array" + }, + "type": "array" + }, + "series_key": { + "description": "The label-set this bucket belongs to, as ordered `(key, value)` pairs,\nwhen the query grouped by labels. Empty/`None` = the single ungrouped\naggregate stream.", + "items": { + "items": false, + "prefixItems": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "type": "array" + }, + "type": [ + "array", + "null" + ] + }, + "value": { + "description": "The value of the requested [`MetricAggregation`] for this bucket. For the\ndefault `Avg` aggregation this equals `avg_value`. `#[serde(default)]` so\npre-existing payloads (which only carried avg/min/max/count) still parse.", + "format": "double", + "type": "number" + } + }, + "required": [ + "bucket", + "avg_value", + "min_value", + "max_value", + "count" + ], + "type": "object" + }, + "MetricDataPoint": { + "description": "A single `(timestamp, value)` data point in a metric series.", + "properties": { + "time": { + "description": "ISO 8601 timestamp with `Z` suffix.", + "type": "string" + }, + "value": { + "description": "Metric value at this bucket.", + "format": "double", + "type": "number" + } + }, + "required": [ + "time", + "value" + ], + "type": "object" + }, + "MetricType": { + "description": "The type of an OTel metric.", + "enum": [ + "gauge", + "sum", + "histogram", + "exponential_histogram", + "summary" + ], + "type": "string" + }, + "MetricsOverTimeResponse": { + "properties": { + "cls": { + "items": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "type": "array" + }, + "cls_p75": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "cls_p90": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "cls_p95": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "cls_p99": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "fcp": { + "items": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "type": "array" + }, + "fcp_p75": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "fcp_p90": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "fcp_p95": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "fcp_p99": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "fid": { + "items": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "type": "array" + }, + "fid_p75": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "fid_p90": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "fid_p95": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "fid_p99": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "inp": { + "items": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "type": "array" + }, + "inp_p75": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "inp_p90": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "inp_p95": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "inp_p99": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "lcp": { + "items": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "type": "array" + }, + "lcp_p75": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "lcp_p90": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "lcp_p95": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "lcp_p99": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "timestamps": { + "items": { + "type": "string" + }, + "type": "array" + }, + "ttfb": { + "items": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "type": "array" + }, + "ttfb_p75": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "ttfb_p90": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "ttfb_p95": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "ttfb_p99": { + "format": "float", + "type": [ + "number", + "null" + ] + } + }, + "required": [ + "timestamps", + "ttfb", + "lcp", + "fid", + "fcp", + "cls", + "inp" + ], + "type": "object" + }, + "MetricsQuery": { + "properties": { + "deployment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "end_date": { + "format": "date-time", + "type": "string" + }, + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "start_date": { + "format": "date-time", + "type": "string" + } + }, + "required": [ + "start_date", + "end_date", + "project_id" + ], + "type": "object" + }, + "MetricsRangeQuery": { + "description": "Query params for range metric queries.", + "properties": { + "metric": { + "description": "Metric name, e.g. `\"pg.connections_active\"`.", + "type": "string" + }, + "percentile": { + "description": "Optional histogram percentile (0–100). When provided, the endpoint\nfetches histogram buckets and computes the requested quantile.", + "format": "double", + "type": [ + "number", + "null" + ] + }, + "range": { + "description": "Time window: `\"1h\"` | `\"6h\"` | `\"24h\"` | `\"7d\"`.", + "type": "string" + } + }, + "required": [ + "metric" + ], + "type": "object" + }, + "MetricsStatusResponse": { + "description": "Freshness status: when metrics were last received for this service.", + "properties": { + "last_received_at": { + "description": "ISO 8601 timestamp of the most recent metric row, or null if none yet.", + "type": [ + "string", + "null" + ] + } + }, + "type": "object" + }, + "MetricsStoreKind": { + "description": "Which storage backend to use for the MetricsStore.", + "enum": [ + "timescale_db", + "click_house" + ], + "type": "string" + }, + "MetricsSummaryResponse": { + "properties": { + "active_customers": { + "format": "int64", + "type": "integer" + }, + "active_subscriptions": { + "format": "int64", + "type": "integer" + }, + "arpu_minor": { + "format": "int64", + "type": "integer" + }, + "churned_last_30d": { + "format": "int64", + "type": "integer" + }, + "currency": { + "type": "string" + }, + "current_arr_minor": { + "format": "int64", + "type": "integer" + }, + "current_mrr_minor": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "currency", + "current_mrr_minor", + "current_arr_minor", + "active_subscriptions", + "active_customers", + "churned_last_30d", + "arpu_minor" + ], + "type": "object" + }, + "MfaRequiredResponse": { + "properties": { + "requires_mfa": { + "type": "boolean" + }, + "session_token": { + "type": "string" + } + }, + "required": [ + "requires_mfa", + "session_token" + ], + "type": "object" + }, + "MfaSetupResponse": { + "properties": { + "qr_code": { + "type": "string" + }, + "recovery_codes": { + "items": { + "type": "string" + }, + "type": "array" + }, + "secret_key": { + "type": "string" + } + }, + "required": [ + "secret_key", + "qr_code", + "recovery_codes" + ], + "type": "object" + }, + "MfaVerificationRequest": { + "properties": { + "code": { + "type": "string" + } + }, + "required": [ + "code" + ], + "type": "object" + }, + "MigrationStep": { + "description": "A single step in the migration execution plan.\n\nSteps are presented to the user before execution so they know exactly\nwhat will happen. During execution, each step runs in order and reports\nits outcome before proceeding to the next.", + "properties": { + "data_implications": { + "description": "Data implications — what could go wrong or what the user needs to know", + "items": { + "$ref": "#/components/schemas/DataImplication" + }, + "type": "array" + }, + "description": { + "description": "Detailed description of what this step does", + "type": "string" + }, + "estimated_duration": { + "description": "Estimated duration hint (e.g., \"< 1 second\", \"10-30 seconds\")", + "type": [ + "string", + "null" + ] + }, + "id": { + "description": "Machine-readable step identifier (e.g., \"create-project\", \"create-service-postgres\")", + "type": "string" + }, + "order": { + "description": "Step number (1-based, for display)", + "minimum": 0, + "type": "integer" + }, + "post_conditions": { + "description": "Things the user should verify AFTER this step completes", + "items": { + "type": "string" + }, + "type": "array" + }, + "pre_conditions": { + "description": "Things the user should verify BEFORE this step runs", + "items": { + "type": "string" + }, + "type": "array" + }, + "resource_type": { + "$ref": "#/components/schemas/StepResourceType", + "description": "What kind of resource this step creates/modifies" + }, + "reversible": { + "description": "Whether this step is reversible (can be cleaned up on failure)", + "type": "boolean" + }, + "risk": { + "$ref": "#/components/schemas/RiskLevel", + "description": "Risk level for this step" + }, + "skippable": { + "description": "Whether this step can be skipped by the user", + "type": "boolean" + }, + "skipped": { + "description": "Whether the user has chosen to skip this step (set during review)", + "type": "boolean" + }, + "title": { + "description": "Human-readable title (e.g., \"Create project 'my-app'\")", + "type": "string" + } + }, + "required": [ + "order", + "id", + "title", + "description", + "resource_type", + "risk", + "skippable", + "reversible" + ], + "type": "object" + }, + "MigrationSummary": { + "description": "Human-readable summary of the entire migration plan", + "properties": { + "critical_warnings": { + "description": "Critical warnings that must be acknowledged before proceeding.\nThese are the most important things the user needs to know.", + "items": { + "type": "string" + }, + "type": "array" + }, + "headline": { + "description": "One-line summary (e.g., \"Migrate 'my-app' from Vercel with 1 database, 2 domains\")", + "type": "string" + }, + "manual_actions_required": { + "description": "Manual actions the user must perform (before or after migration)", + "items": { + "$ref": "#/components/schemas/ManualAction" + }, + "type": "array" + }, + "overall_risk": { + "$ref": "#/components/schemas/RiskLevel", + "description": "Overall risk assessment for the migration" + }, + "resource_counts": { + "$ref": "#/components/schemas/ResourceCounts", + "description": "Resource counts for quick overview" + }, + "unsupported_features": { + "description": "Features from the source platform that cannot be migrated", + "items": { + "$ref": "#/components/schemas/UnsupportedFeature" + }, + "type": "array" + } + }, + "required": [ + "headline", + "overall_risk", + "resource_counts" + ], + "type": "object" + }, + "MintEnrollmentTokenRequest": { + "properties": { + "bound_node_name": { + "description": "Optional: restrict the token to register one specific node name.", + "type": [ + "string", + "null" + ] + }, + "max_uses": { + "description": "Maximum registrations this token may authorize (default 1).", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "ttl_secs": { + "description": "Time-to-live in seconds (default 3600 = 1h).", + "format": "int64", + "type": [ + "integer", + "null" + ] + } + }, + "type": "object" + }, + "MintEnrollmentTokenResponse": { + "properties": { + "ca_fingerprint": { + "description": "SHA-256 fingerprint of the cluster CA (if mTLS is set up). Pass it to the\nworker as `temps join --ca-fingerprint ` to verify the CA on join.", + "type": [ + "string", + "null" + ] + }, + "expires_at": { + "type": "string" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "max_uses": { + "format": "int32", + "type": "integer" + }, + "message": { + "type": "string" + }, + "token": { + "description": "The plaintext enrollment token — shown only once, save it now.", + "type": "string" + } + }, + "required": [ + "id", + "token", + "expires_at", + "max_uses", + "message" + ], + "type": "object" + }, + "MiscResult": { + "description": "Miscellaneous validation result", + "properties": { + "gravatar_url": { + "description": "Gravatar URL if available", + "type": [ + "string", + "null" + ] + }, + "is_b2c": { + "description": "Whether the email provider is a B2C (consumer) email provider", + "type": "boolean" + }, + "is_disposable": { + "description": "Whether the email is from a disposable email provider", + "type": "boolean" + }, + "is_role_account": { + "description": "Whether the email is a role-based account (e.g., admin@, info@)", + "type": "boolean" + } + }, + "required": [ + "is_disposable", + "is_role_account", + "is_b2c" + ], + "type": "object" + }, + "MkdirBody": { + "additionalProperties": false, + "properties": { + "path": { + "type": "string" + } + }, + "required": [ + "path" + ], + "type": "object" + }, + "ModelInfo": { + "properties": { + "id": { + "type": "string" + }, + "object": { + "type": "string" + }, + "owned_by": { + "type": "string" + } + }, + "required": [ + "id", + "object", + "owned_by" + ], + "type": "object" + }, + "ModelListResponse": { + "properties": { + "data": { + "items": { + "$ref": "#/components/schemas/ModelInfo" + }, + "type": "array" + }, + "object": { + "type": "string" + } + }, + "required": [ + "object", + "data" + ], + "type": "object" + }, + "ModelPricing": { + "description": "Pricing for a single model, all values in USD per 1M tokens.\nFields are optional because not every provider supports every pricing tier.", + "properties": { + "batch_input_per_million": { + "description": "Batch API input cost per 1M tokens (if provider offers batch pricing)", + "format": "double", + "type": [ + "number", + "null" + ] + }, + "batch_output_per_million": { + "description": "Batch API output cost per 1M tokens", + "format": "double", + "type": [ + "number", + "null" + ] + }, + "cache_hit_per_million": { + "description": "Cache hit / refresh cost per 1M tokens", + "format": "double", + "type": [ + "number", + "null" + ] + }, + "cache_write_1h_per_million": { + "description": "1-hour cache write cost per 1M tokens", + "format": "double", + "type": [ + "number", + "null" + ] + }, + "cache_write_5m_per_million": { + "description": "5-minute cache write cost per 1M tokens (Anthropic-style prompt caching)", + "format": "double", + "type": [ + "number", + "null" + ] + }, + "deprecated": { + "description": "Whether the model is deprecated", + "type": "boolean" + }, + "display_name": { + "description": "Human-readable model name (e.g. \"Claude Sonnet 4.6\")", + "type": "string" + }, + "input_per_million": { + "description": "Base input token cost per 1M tokens", + "format": "double", + "type": "number" + }, + "model": { + "description": "Model identifier (e.g. \"gpt-5.4\", \"claude-sonnet-4-6\")", + "type": "string" + }, + "output_per_million": { + "description": "Output token cost per 1M tokens", + "format": "double", + "type": "number" + }, + "provider": { + "description": "Provider ID (e.g. \"openai\", \"anthropic\")", + "type": "string" + } + }, + "required": [ + "model", + "display_name", + "provider", + "input_per_million", + "output_per_million" + ], + "type": "object" + }, + "ModelUsage": { + "properties": { + "avg_latency_ms": { + "format": "double", + "type": "number" + }, + "input_tokens": { + "format": "int64", + "type": "integer" + }, + "model": { + "type": "string" + }, + "output_tokens": { + "format": "int64", + "type": "integer" + }, + "provider": { + "type": "string" + }, + "request_count": { + "format": "int64", + "type": "integer" + }, + "total_tokens": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "model", + "provider", + "request_count", + "input_tokens", + "output_tokens", + "total_tokens", + "avg_latency_ms" + ], + "type": "object" + }, + "MonitorResponse": { + "properties": { + "check_interval_seconds": { + "format": "int32", + "type": "integer" + }, + "check_path": { + "type": [ + "string", + "null" + ] + }, + "created_at": { + "format": "date-time", + "type": "string" + }, + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "id": { + "format": "int32", + "type": "integer" + }, + "is_active": { + "type": "boolean" + }, + "monitor_type": { + "type": "string" + }, + "monitor_url": { + "type": "string" + }, + "name": { + "type": "string" + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "updated_at": { + "format": "date-time", + "type": "string" + } + }, + "required": [ + "id", + "project_id", + "name", + "monitor_type", + "monitor_url", + "check_interval_seconds", + "is_active", + "created_at", + "updated_at" + ], + "type": "object" + }, + "MonitorStatus": { + "properties": { + "avg_response_time_ms": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "current_status": { + "type": "string" + }, + "monitor": { + "$ref": "#/components/schemas/MonitorResponse" + }, + "uptime_percentage": { + "format": "double", + "type": "number" + } + }, + "required": [ + "monitor", + "current_status", + "uptime_percentage" + ], + "type": "object" + }, + "MonitoringSettings": { + "description": "Global metrics observability configuration.\n\nControls whether the MetricsScraper and AlertEvaluator background tasks\nare active, which storage backend they write to, and how long data is kept\nat each retention tier.", + "properties": { + "clickhouse_url": { + "default": null, + "description": "ClickHouse DSN (legacy, optional). The runtime metrics store is built\nfrom the `TEMPS_CLICKHOUSE_*` env vars, never from this field; it is\nretained for compatibility and operator reference only.\nExample: `\"http://localhost:8123\"`.", + "type": [ + "string", + "null" + ] + }, + "enabled": { + "default": false, + "description": "Enable or disable all metrics collection (scraping + alerting).\nDefaults to `false` so new installs don't write to TimescaleDB until\nan operator explicitly enables the feature.", + "type": "boolean" + }, + "retention_daily_years": { + "default": 2, + "description": "How many years of daily-aggregate data to keep (converted to days internally).", + "example": 2, + "format": "int32", + "maximum": 10, + "minimum": 1, + "type": "integer" + }, + "retention_hourly_days": { + "default": 90, + "description": "How many days of hourly-aggregate data to keep.", + "example": 90, + "format": "int32", + "minimum": 1, + "type": "integer" + }, + "retention_raw_days": { + "default": 7, + "description": "How many days of raw (30 s resolution) metric data to keep.", + "example": 7, + "format": "int32", + "minimum": 1, + "type": "integer" + }, + "scrape_interval_secs": { + "default": 30, + "description": "How often the MetricsScraper collects data from all sources, in seconds.\nMinimum effective value is 10 s; values below that are clamped at runtime.", + "example": 30, + "format": "int64", + "minimum": 10, + "type": "integer" + }, + "store": { + "default": "timescale_db", + "oneOf": [ + { + "$ref": "#/components/schemas/MetricsStoreKind", + "description": "Storage backend for metric data." + } + ] + } + }, + "type": "object" + }, + "MonitoringSettingsMasked": { + "description": "Monitoring settings with the ClickHouse DSN masked.\n\n`clickhouse_url` can embed credentials (`http://user:pass@host`), so it is\nreported only as a boolean (`clickhouse_url_set`) rather than echoed back —\nconsistent with how the DNS API key and Docker registry password are masked.", + "properties": { + "clickhouse_url_set": { + "description": "True when a ClickHouse DSN is configured. The DSN itself is never\nreturned over HTTP because it may contain credentials.", + "type": "boolean" + }, + "enabled": { + "type": "boolean" + }, + "retention_daily_years": { + "format": "int32", + "minimum": 0, + "type": "integer" + }, + "retention_hourly_days": { + "format": "int32", + "minimum": 0, + "type": "integer" + }, + "retention_raw_days": { + "format": "int32", + "minimum": 0, + "type": "integer" + }, + "scrape_interval_secs": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "store": { + "$ref": "#/components/schemas/MetricsStoreKind" + } + }, + "required": [ + "enabled", + "store", + "scrape_interval_secs", + "retention_raw_days", + "retention_hourly_days", + "retention_daily_years", + "clickhouse_url_set" + ], + "type": "object" + }, + "MrrBucketResponse": { + "properties": { + "bucket": { + "format": "date-time", + "type": "string" + }, + "charge_count": { + "format": "int64", + "type": "integer" + }, + "charge_total_minor": { + "format": "int64", + "type": "integer" + }, + "mrr_minor": { + "format": "int64", + "type": "integer" + }, + "refund_total_minor": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "bucket", + "mrr_minor", + "charge_total_minor", + "refund_total_minor", + "charge_count" + ], + "type": "object" + }, + "MultiNodeSettings": { + "description": "Multi-node cluster settings", + "properties": { + "cluster_ca_cert_pem": { + "default": null, + "description": "Per-cluster CA certificate (PEM) for multi-node mTLS (ADR-020 WS-2.1).\nPublic — distributed to nodes as the trust root and used by the control\nplane as the root for verifying agent server certs. Minted lazily on the\nfirst CSR-bearing registration.", + "type": [ + "string", + "null" + ] + }, + "cluster_ca_key_encrypted": { + "default": null, + "description": "Per-cluster CA private key, AES-256-GCM ciphertext (EncryptionService).\nSECRET — never returned over HTTP (elided in the masked response).", + "type": [ + "string", + "null" + ] + }, + "join_token_hash": { + "default": null, + "description": "SHA-256 hash of the join token (never store plaintext)", + "type": [ + "string", + "null" + ] + }, + "legacy_shared_token_enabled": { + "default": true, + "description": "Whether the legacy single shared join token is still accepted for node\nregistration (ADR-020 WS-1.1). Defaults to `true` so existing clusters\nkeep working on upgrade; fresh installs should set it `false` and rely on\nshort-lived, single-use enrollment tokens instead.", + "type": "boolean" + }, + "node_cpu_alert_percent": { + "default": 90, + "description": "CPU-usage percent above which a worker node raises a resource alert\n(ADR-020 / monitoring). `None` disables CPU alerting. Default 90.", + "format": "double", + "type": [ + "number", + "null" + ] + }, + "node_disk_alert_percent": { + "default": 90, + "description": "Disk-usage percent above which a worker node raises a resource alert.\n`None` disables disk alerting. Default 90.", + "format": "double", + "type": [ + "number", + "null" + ] + }, + "node_memory_alert_percent": { + "default": 90, + "description": "Memory-usage percent above which a worker node raises a resource alert.\n`None` disables memory alerting. Default 90.", + "format": "double", + "type": [ + "number", + "null" + ] + }, + "private_address": { + "default": null, + "description": "Private/WireGuard IP address of the control plane node.\nUsed by remote worker nodes to reach services (databases, etc.) running on the control plane.\nSet via `--private-address` or `TEMPS_PRIVATE_ADDRESS`.", + "type": [ + "string", + "null" + ] + }, + "require_mtls": { + "default": false, + "description": "Whether to enforce multi-node mTLS (ADR-020 WS-2.1). When `false`\n(default), the control plane ignores join-time CSRs and nodes keep\nserving plaintext HTTP — zero behavior change. When `true`, the CP signs\nnode CSRs, nodes serve mutual TLS, and every CP→agent call uses the\ncluster client cert. Observe-then-enforce: flip this on only once all\nworkers have re-enrolled with certs.", + "type": "boolean" + } + }, + "type": "object" + }, + "MultiNodeSettingsMasked": { + "description": "Multi-node settings with `join_token_hash` elided.", + "properties": { + "cluster_ca_fingerprint": { + "description": "SHA-256 fingerprint of the cluster CA certificate (public — operators can\nverify it out of band; the CA private key is never exposed).", + "type": [ + "string", + "null" + ] + }, + "has_join_token": { + "type": "boolean" + }, + "legacy_shared_token_enabled": { + "description": "Whether the deprecated shared join token is still accepted.", + "type": "boolean" + }, + "node_cpu_alert_percent": { + "description": "Node resource-alert thresholds (percent); `None` = that alert disabled.", + "format": "double", + "type": [ + "number", + "null" + ] + }, + "node_disk_alert_percent": { + "format": "double", + "type": [ + "number", + "null" + ] + }, + "node_memory_alert_percent": { + "format": "double", + "type": [ + "number", + "null" + ] + }, + "private_address": { + "type": [ + "string", + "null" + ] + }, + "require_mtls": { + "description": "Whether control-plane↔agent mutual TLS is enforced.", + "type": "boolean" + } + }, + "required": [ + "has_join_token", + "require_mtls", + "legacy_shared_token_enabled" + ], + "type": "object" + }, + "MxResult": { + "description": "MX (Mail Exchange) validation result", + "properties": { + "accepts_mail": { + "description": "Whether the domain accepts mail", + "type": "boolean" + }, + "error": { + "description": "Error message if MX lookup failed", + "type": [ + "string", + "null" + ] + }, + "records": { + "description": "List of MX records for the domain", + "example": [ + "alt1.gmail-smtp-in.l.google.com.", + "gmail-smtp-in.l.google.com." + ], + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "accepts_mail", + "records" + ], + "type": "object" + }, + "NavEntry": { + "description": "A navigation entry that the plugin contributes to the Temps UI.", + "properties": { + "icon": { + "description": "Lucide icon name (e.g., \"puzzle\", \"database\", \"activity\")", + "type": "string" + }, + "label": { + "description": "Display label in the sidebar", + "type": "string" + }, + "order": { + "description": "Sort order within the section (lower = higher in list)", + "format": "int32", + "minimum": 0, + "type": "integer" + }, + "path": { + "description": "Client-side route path (e.g., \"/my-plugin\")", + "type": "string" + }, + "section": { + "$ref": "#/components/schemas/NavSection", + "description": "Which sidebar section this entry belongs to" + } + }, + "required": [ + "label", + "icon", + "section", + "path", + "order" + ], + "type": "object" + }, + "NavSection": { + "description": "Where the plugin's nav entry appears in the Temps UI sidebar.", + "enum": [ + "platform", + "settings", + "project" + ], + "type": "string" + }, + "NetworkConfiguration": { + "description": "Network configuration", + "properties": { + "dns_servers": { + "description": "DNS servers", + "items": { + "type": "string" + }, + "type": "array" + }, + "hostname": { + "description": "Hostname", + "type": [ + "string", + "null" + ] + }, + "mode": { + "$ref": "#/components/schemas/NetworkMode", + "description": "Network mode" + } + }, + "required": [ + "mode", + "dns_servers" + ], + "type": "object" + }, + "NetworkMode": { + "description": "Network mode", + "oneOf": [ + { + "enum": [ + "bridge" + ], + "type": "string" + }, + { + "enum": [ + "host" + ], + "type": "string" + }, + { + "enum": [ + "none" + ], + "type": "string" + }, + { + "properties": { + "custom": { + "type": "string" + } + }, + "required": [ + "custom" + ], + "type": "object" + } + ] + }, + "NixpacksPresetConfig": { + "description": "Configuration for Nixpacks preset\nNixpacks provider and inline build-plan configuration.", + "properties": { + "nixpacksConfig": { + "description": "Optional inline nixpacks.toml contents.", + "type": [ + "string", + "null" + ] + }, + "providers": { + "description": "Ordered Nixpacks providers. Empty means repository config or auto-detect;\ninclude `...` to combine auto-detection with explicit providers.", + "items": { + "$ref": "#/components/schemas/NixpacksProvider" + }, + "type": "array" + } + }, + "type": "object" + }, + "NixpacksProvider": { + "description": "A Nixpacks build provider.\n\n`Auto` serializes as the native Nixpacks `...` marker, which includes the\nprovider detected from the project alongside any explicitly listed\nproviders.", + "enum": [ + "...", + "node", + "python", + "rust", + "go", + "java", + "php", + "ruby", + "deno", + "elixir", + "csharp", + "fsharp", + "dart", + "swift", + "zig", + "scala", + "haskell", + "clojure", + "crystal", + "cobol", + "gleam", + "lunatic", + "scheme", + "static" + ], + "type": "string" + }, + "NodeContainerListResponse": { + "properties": { + "containers": { + "items": { + "$ref": "#/components/schemas/NodeContainerResponse" + }, + "type": "array" + }, + "total": { + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "containers", + "total" + ], + "type": "object" + }, + "NodeContainerResponse": { + "description": "A container running on a specific node, enriched with project/environment context.", + "properties": { + "container_id": { + "type": "string" + }, + "container_name": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "deployment_id": { + "format": "int32", + "type": "integer" + }, + "environment_id": { + "format": "int32", + "type": "integer" + }, + "environment_name": { + "type": "string" + }, + "image_name": { + "type": "string" + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "project_name": { + "type": "string" + }, + "status": { + "type": "string" + } + }, + "required": [ + "container_id", + "container_name", + "image_name", + "status", + "created_at", + "deployment_id", + "project_id", + "project_name", + "environment_id", + "environment_name" + ], + "type": "object" + }, + "NodeCostInfo": { + "description": "One cluster node with capacity and (when priceable) a cost estimate", + "properties": { + "cpu_millis": { + "description": "CPU capacity in millicores", + "format": "int64", + "type": "integer" + }, + "instance_type": { + "description": "Instance type from `node.kubernetes.io/instance-type` (e.g. \"m5.xlarge\")", + "type": [ + "string", + "null" + ] + }, + "memory_mb": { + "description": "Memory capacity in MB", + "format": "int64", + "type": "integer" + }, + "monthly_usd": { + "description": "Estimated on-demand monthly price in USD. `None` when the instance\ntype is unknown or not in the price table.", + "format": "double", + "type": [ + "number", + "null" + ] + }, + "name": { + "description": "Node name", + "type": "string" + }, + "region": { + "description": "Region from `topology.kubernetes.io/region`", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "name", + "cpu_millis", + "memory_mb" + ], + "type": "object" + }, + "NodeInfoResponse": { + "properties": { + "address": { + "type": "string" + }, + "architecture": { + "description": "Container platform this node runs (`linux/amd64`, `linux/arm64`).\n`None` until an agent that reports it has heartbeated.", + "type": [ + "string", + "null" + ] + }, + "capacity": { + "description": "Resource capacity/usage metrics from the latest heartbeat" + }, + "created_at": { + "type": "string" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "labels": {}, + "last_heartbeat": { + "type": [ + "string", + "null" + ] + }, + "name": { + "type": "string" + }, + "private_address": { + "type": "string" + }, + "role": { + "type": "string" + }, + "status": { + "type": "string" + } + }, + "required": [ + "id", + "name", + "address", + "private_address", + "role", + "status", + "labels", + "capacity", + "created_at" + ], + "type": "object" + }, + "NodeListResponse": { + "properties": { + "nodes": { + "items": { + "$ref": "#/components/schemas/NodeInfoResponse" + }, + "type": "array" + }, + "total": { + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "nodes", + "total" + ], + "type": "object" + }, + "NotificationPreferencesResponse": { + "properties": { + "backup_failures_enabled": { + "type": "boolean" + }, + "backup_successes_enabled": { + "type": "boolean" + }, + "batch_similar_notifications": { + "type": "boolean" + }, + "build_errors_enabled": { + "type": "boolean" + }, + "deployment_failures_enabled": { + "type": "boolean" + }, + "digest_sections": { + "$ref": "#/components/schemas/DigestSections" + }, + "digest_send_day": { + "type": "string" + }, + "digest_send_time": { + "type": "string" + }, + "dns_changes_enabled": { + "type": "boolean" + }, + "domain_expiration_enabled": { + "type": "boolean" + }, + "email_enabled": { + "type": "boolean" + }, + "error_threshold": { + "format": "int32", + "type": "integer" + }, + "error_time_window": { + "format": "int32", + "type": "integer" + }, + "load_balancer_issues_enabled": { + "type": "boolean" + }, + "minimum_severity": { + "type": "string" + }, + "retention_policy_violations_enabled": { + "type": "boolean" + }, + "route_downtime_enabled": { + "type": "boolean" + }, + "runtime_errors_enabled": { + "type": "boolean" + }, + "s3_connection_issues_enabled": { + "type": "boolean" + }, + "slack_enabled": { + "type": "boolean" + }, + "ssl_days_before_expiration": { + "format": "int32", + "type": "integer" + }, + "ssl_expiration_enabled": { + "type": "boolean" + }, + "weekly_digest_enabled": { + "type": "boolean" + } + }, + "required": [ + "email_enabled", + "slack_enabled", + "batch_similar_notifications", + "minimum_severity", + "deployment_failures_enabled", + "build_errors_enabled", + "runtime_errors_enabled", + "error_threshold", + "error_time_window", + "ssl_expiration_enabled", + "ssl_days_before_expiration", + "domain_expiration_enabled", + "dns_changes_enabled", + "backup_failures_enabled", + "backup_successes_enabled", + "s3_connection_issues_enabled", + "retention_policy_violations_enabled", + "route_downtime_enabled", + "load_balancer_issues_enabled", + "weekly_digest_enabled", + "digest_send_day", + "digest_send_time", + "digest_sections" + ], + "type": "object" + }, + "NotificationProviderResponse": { + "properties": { + "config": {}, + "created_at": { + "format": "int64", + "type": "integer" + }, + "enabled": { + "type": "boolean" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "name": { + "type": "string" + }, + "provider_type": { + "type": "string" + }, + "updated_at": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "id", + "name", + "provider_type", + "config", + "enabled", + "created_at", + "updated_at" + ], + "type": "object" + }, + "ObservabilityCompressionSettings": { + "description": "TimescaleDB compression policy configuration for append-only observability\ntables. Values are expressed in hours so operators can choose sub-day\nwindows while keeping the API representation unambiguous.", + "properties": { + "otel_spans_after_hours": { + "default": 24, + "description": "Compress OpenTelemetry span chunks after this many hours. Defaults to\n24 hours.", + "example": 24, + "format": "int32", + "maximum": 2160, + "minimum": 1, + "type": "integer" + }, + "proxy_logs_after_hours": { + "default": 24, + "description": "Compress proxy-log chunks after this many hours. Defaults to 24 hours.", + "example": 24, + "format": "int32", + "maximum": 720, + "minimum": 1, + "type": "integer" + } + }, + "type": "object" + }, + "ObservabilityEvent": { + "description": "Discriminated union of every row that can appear in the Observe list.\n\nSerializes to `{ \"type\": \"request\" | \"span\" | ... , ...rest }` so the UI\ncan switch on `event.type` without ambiguity.\n\n**No `Log` variant**: runtime stdout/stderr lines live on a dedicated\nLogs page rather than Observe. Logs are too high-volume to interleave\nwith business signals (requests, errors, revenue) without dominating\nthe timeline, and they have their own retention/storage constraints\n(TimescaleDB hypertable + chunked file/S3 store) that don't compose\nwith the merge service's per-kind LIMIT strategy.", + "oneOf": [ + { + "allOf": [ + { + "$ref": "#/components/schemas/RequestRow" + }, + { + "properties": { + "type": { + "enum": [ + "request" + ], + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + } + ] + }, + { + "allOf": [ + { + "$ref": "#/components/schemas/SpanRow" + }, + { + "properties": { + "type": { + "enum": [ + "span" + ], + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + } + ] + }, + { + "allOf": [ + { + "$ref": "#/components/schemas/ErrorRow" + }, + { + "properties": { + "type": { + "enum": [ + "error" + ], + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + } + ] + }, + { + "allOf": [ + { + "$ref": "#/components/schemas/RevenueRow" + }, + { + "properties": { + "type": { + "enum": [ + "revenue" + ], + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + } + ] + } + ] + }, + "ObservabilityRetentionSettings": { + "description": "Retention policy configuration for raw observability tables. Values are in\ndays. The Settings API applies them to TimescaleDB; ClickHouse-backed proxy\nlogs and spans retain their storage-level per-row TTL behavior.", + "properties": { + "otel_logs_days": { + "default": 90, + "description": "Retain OpenTelemetry log events for this many days.", + "example": 90, + "format": "int32", + "maximum": 3650, + "minimum": 1, + "type": "integer" + }, + "otel_metrics_days": { + "default": 90, + "description": "Retain OpenTelemetry metric points for this many days.", + "example": 90, + "format": "int32", + "maximum": 3650, + "minimum": 1, + "type": "integer" + }, + "otel_spans_days": { + "default": 90, + "description": "Retain OpenTelemetry spans (traces) for this many days.", + "example": 90, + "format": "int32", + "maximum": 3650, + "minimum": 1, + "type": "integer" + }, + "proxy_logs_days": { + "default": 30, + "description": "Retain proxy request logs for this many days.", + "example": 30, + "format": "int32", + "maximum": 3650, + "minimum": 1, + "type": "integer" + } + }, + "type": "object" + }, + "OidcProviderResponse": { + "properties": { + "client_id": { + "type": "string" + }, + "client_secret": { + "description": "Always masked — the secret is never returned after creation.", + "type": "string" + }, + "default_role": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "group_claim": { + "type": "string" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "issuer_url": { + "type": "string" + }, + "jit_provisioning": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "role_claim": { + "type": "string" + }, + "scopes": { + "type": "string" + }, + "template": { + "type": "string" + }, + "trust_idp_email": { + "description": "When true, the resolver skips the `email_verified` claim gate\nduring SSO login. Only safe for IdPs where an admin controls\nuser provisioning — see `oidc_providers::Model::trust_idp_email`.", + "type": "boolean" + } + }, + "required": [ + "id", + "name", + "issuer_url", + "client_id", + "client_secret", + "scopes", + "jit_provisioning", + "enabled", + "template", + "group_claim", + "role_claim", + "default_role", + "trust_idp_email" + ], + "type": "object" + }, + "OidcProviderSummary": { + "properties": { + "name": { + "type": "string" + }, + "slug": { + "description": "Stable opaque slug — use this as the path parameter when initiating\nOIDC login (`/auth/oidc/login/{slug}`). The integer database ID is\nintentionally omitted from this public endpoint to prevent provider\nenumeration.", + "type": "string" + }, + "template": { + "description": "The template the provider was created from — e.g. `keycloak`,\n`okta`, `auth0`, `google`, `azure-ad`, or `generic`. Surfaced on\nthe public login endpoint so the unauthenticated login page can\nrender the right brand logo on the \"Sign in with X\" button.\nNever sensitive — the template name is part of the provider's\npublic identity, not configuration.", + "type": "string" + } + }, + "required": [ + "slug", + "name", + "template" + ], + "type": "object" + }, + "OidcProviderUserResponse": { + "description": "A user that has logged in via a given OIDC provider. Used by the\nadmin \"Users for provider\" panel — the `oidc_subject` is the\nIdP-side identifier we matched on, useful when diagnosing why a\nuser can or can't log in.", + "properties": { + "created_at": { + "example": "2024-01-15T14:30:00Z", + "format": "date-time", + "type": "string" + }, + "email": { + "type": "string" + }, + "email_verified": { + "type": "boolean" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "mfa_enabled": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "oidc_subject": { + "type": [ + "string", + "null" + ] + }, + "updated_at": { + "example": "2024-01-15T14:30:00Z", + "format": "date-time", + "type": "string" + } + }, + "required": [ + "id", + "name", + "email", + "email_verified", + "mfa_enabled", + "created_at", + "updated_at" + ], + "type": "object" + }, + "OidcProvidersListResponse": { + "properties": { + "providers": { + "items": { + "$ref": "#/components/schemas/OidcProviderSummary" + }, + "type": "array" + } + }, + "required": [ + "providers" + ], + "type": "object" + }, + "OidcRoleMappingResponse": { + "properties": { + "id": { + "format": "int32", + "type": "integer" + }, + "idp_group": { + "type": "string" + }, + "priority": { + "format": "int32", + "type": "integer" + }, + "provider_id": { + "format": "int32", + "type": "integer" + }, + "role": { + "type": "string" + } + }, + "required": [ + "id", + "provider_id", + "priority", + "idp_group", + "role" + ], + "type": "object" + }, + "OidcTestConnectionResponse": { + "properties": { + "message": { + "type": "string" + }, + "success": { + "type": "boolean" + } + }, + "required": [ + "success", + "message" + ], + "type": "object" + }, + "OnDemandCertAttemptResponse": { + "description": "A single on-demand HTTP-01 issuance attempt from the append-only\n`on_demand_cert_attempts` audit log. Carries the full forensic detail for one\nattempt; the current cert state lives on the enclosing row's domain fields.\n\nContains no private-key or certificate material — only audit metadata — so it\nis safe to return without masking.", + "properties": { + "acme_request_sent": { + "description": "Did we reach the Let's Encrypt API?", + "type": [ + "boolean", + "null" + ] + }, + "acme_response_status": { + "description": "HTTP status or ACME error type returned by Let's Encrypt, when known.", + "type": [ + "string", + "null" + ] + }, + "challenge_served": { + "description": "Did the proxy serve the `/.well-known/acme-challenge/` request?", + "type": [ + "boolean", + "null" + ] + }, + "created_at": { + "description": "When the attempt was recorded (epoch millis).", + "format": "int64", + "type": "integer" + }, + "duration_ms": { + "description": "End-to-end issuance duration in milliseconds (0/None for skipped).", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "error_category": { + "description": "Coarse error category for UI labelling: `\"rate_limited\"`, `\"dns_failure\"`,\n`\"acme_order_expired\"`, `\"challenge_mismatch\"`, `\"timeout\"`, `\"internal\"`.", + "type": [ + "string", + "null" + ] + }, + "error_chain": { + "description": "Full `Display` chain of the error (all `source()` levels), when failed.", + "type": [ + "string", + "null" + ] + }, + "hostname": { + "description": "SNI hostname that triggered the attempt.", + "type": "string" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "outcome": { + "description": "Final outcome: `\"issued\"`, `\"failed\"`, `\"skipped_duplicate\"`,\n`\"skipped_gate\"`, `\"skipped_rate_limit\"`, or `\"skipped_no_route\"`.", + "type": "string" + }, + "trigger": { + "description": "What triggered the attempt (always `\"tls_callback\"` today).", + "type": "string" + } + }, + "required": [ + "id", + "hostname", + "trigger", + "outcome", + "created_at" + ], + "type": "object" + }, + "OnDemandCertRow": { + "description": "One row of the on-demand certificates list: the most-recent attempt for a\nhostname plus the current authoritative cert state from its `domains` row.", + "properties": { + "attempt": { + "$ref": "#/components/schemas/OnDemandCertAttemptResponse", + "description": "The audit record for the attempt this row represents (newest first in\nthe list)." + }, + "backoff_until": { + "description": "On-demand negative-cache deadline (epoch millis), when in backoff.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "expiration_time": { + "description": "Certificate expiration (epoch millis), when an active cert exists.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "hostname": { + "description": "SNI hostname.", + "type": "string" + }, + "status": { + "description": "Current cert lifecycle status from the `domains` row, when one exists:\n`on_demand_pending`, `on_demand_issuing`, `active`, `on_demand_failed`,\netc. `None` when no `domains` row exists yet for this hostname.", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "hostname", + "attempt" + ], + "type": "object" + }, + "OnDemandTlsSettings": { + "description": "On-demand (lazy) HTTP-01 TLS issuance settings (ADR-018).\n\nWhen `enabled`, the proxy's `certificate_callback` triggers ACME HTTP-01\nissuance for allowlisted, STABLE hostnames (per-environment aliases and the\nconsole host) that have no active cert, rather than silently failing the\nhandshake. Ephemeral per-deployment hostnames are NEVER certed (ADR §2).\n\nOff by default — operators opt in explicitly, except QuickStart (`sslip.io`)\ninstalls where `temps setup` auto-enables it and derives `zone`.", + "properties": { + "deployment_url_mode": { + "default": "http", + "description": "How ephemeral per-deployment hostnames behave when they have no cert\n(they are NEVER certed — see ADR §2). One of:\n - `\"http\"` (default): serve plain HTTP on :80.\n - `\"redirect_to_env\"`: 308-redirect to the stable per-environment URL,\n which IS certed.", + "example": "http", + "type": "string" + }, + "enabled": { + "default": false, + "description": "Master switch. When `false` (default) the proxy's on-demand cert gate\nrejects every SNI and no issuance is ever triggered.", + "example": false, + "type": "boolean" + }, + "hourly_cap": { + "default": 10, + "description": "Global cap on total on-demand issuances per hour across all hostnames\n(ADR §4 Layer 3). The operator's self-imposed safety net, separate from\nthe Let's Encrypt rate limit.", + "example": 10, + "format": "int32", + "minimum": 1, + "type": "integer" + }, + "max_concurrent": { + "default": 3, + "description": "Maximum number of ACME issuance flows allowed to run simultaneously\n(the concurrent-issuance semaphore, ADR §4 Layer 1). Min 1.", + "example": 3, + "format": "int32", + "minimum": 1, + "type": "integer" + }, + "zone": { + "default": null, + "description": "Zone suffix for the allowlist gate. A hostname passes the gate only if\nit is a direct subdomain of this zone (e.g. zone `1.2.3.4.sslip.io`\nadmits `myapp.1.2.3.4.sslip.io` but not `deep.sub.1.2.3.4.sslip.io`).\n`None` (default) means \"auto-derive from `external_url`\"; if no zone can\nbe derived the gate rejects all SNI, disabling the feature.", + "example": "1.2.3.4.sslip.io", + "type": [ + "string", + "null" + ] + } + }, + "type": "object" + }, + "OpenAiError": { + "properties": { + "code": { + "type": [ + "string", + "null" + ] + }, + "message": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "required": [ + "message", + "type" + ], + "type": "object" + }, + "OpenAiErrorResponse": { + "properties": { + "error": { + "$ref": "#/components/schemas/OpenAiError" + } + }, + "required": [ + "error" + ], + "type": "object" + }, + "OperatingSystemCount": { + "properties": { + "count": { + "format": "int64", + "type": "integer" + }, + "operating_system": { + "type": "string" + }, + "percentage": { + "format": "double", + "type": "number" + } + }, + "required": [ + "operating_system", + "count", + "percentage" + ], + "type": "object" + }, + "OperationResultResponse": { + "properties": { + "data": {}, + "executed_at": { + "example": "2025-10-12T12:15:47.609192Z", + "format": "date-time", + "type": "string" + }, + "message": { + "type": "string" + }, + "operation": { + "type": "string" + }, + "success": { + "type": "boolean" + } + }, + "required": [ + "operation", + "success", + "message", + "executed_at" + ], + "type": "object" + }, + "OperationResultsResponse": { + "properties": { + "deployment_id": { + "type": "string" + }, + "operations": { + "items": { + "$ref": "#/components/schemas/OperationResultResponse" + }, + "type": "array" + } + }, + "required": [ + "deployment_id", + "operations" + ], + "type": "object" + }, + "OtelDashboardResponse": { + "properties": { + "created_at": { + "example": "2025-10-12T12:15:47.609192Z", + "type": "string" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "layout": { + "$ref": "#/components/schemas/DashboardLayout" + }, + "name": { + "type": "string" + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "updated_at": { + "example": "2025-10-12T12:15:47.609192Z", + "type": "string" + } + }, + "required": [ + "id", + "project_id", + "name", + "layout", + "created_at", + "updated_at" + ], + "type": "object" + }, + "OtelDashboardsResponse": { + "properties": { + "data": { + "items": { + "$ref": "#/components/schemas/OtelDashboardResponse" + }, + "type": "array" + }, + "total": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "data", + "total" + ], + "type": "object" + }, + "OtelMetricAlertRuleResponse": { + "properties": { + "aggregation": { + "type": "string" + }, + "created_at": { + "example": "2025-10-12T12:15:47.609192Z", + "type": "string" + }, + "detection_config": { + "$ref": "#/components/schemas/DetectionConfig", + "description": "The typed detector definition (discriminated union keyed by `kind`)." + }, + "detection_kind": { + "description": "Coarse detector discriminator: `static|anomaly|forecast|outlier|auto_watch`.", + "type": "string" + }, + "dynamic_alerts": { + "description": "Whether per-series (\"dynamic\") alerting is enabled for this rule.", + "type": "boolean" + }, + "enabled": { + "type": "boolean" + }, + "firing_series": { + "description": "Currently-firing series for a dynamic rule, snapshotted from the evaluator's\nin-memory firing map at read time. Empty for static/aggregate rules or when\nnothing is firing.", + "items": { + "$ref": "#/components/schemas/FiringSeriesEntry" + }, + "type": "array" + }, + "for_duration_secs": { + "format": "int32", + "type": "integer" + }, + "group_by": { + "description": "Label keys the rule breaks the metric down by. Empty = one aggregate stream.", + "items": { + "type": "string" + }, + "type": "array" + }, + "grouped_notification_threshold": { + "description": "Notification-grouping threshold: when more than this many series fire in the\nsame tick, only the first gets chart/AI enrichment (1–1000).", + "format": "int32", + "type": "integer" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "label_filters": { + "description": "AND-combined label equality filters applied when evaluating this rule.\nEmpty = no filtering (matches all series).", + "items": { + "items": false, + "prefixItems": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "type": "array" + }, + "type": "array" + }, + "last_dropped_series_count": { + "description": "Number of series dropped by the cardinality cap on the latest dynamic tick\n(0 when nothing was dropped or for static/aggregate rules). Lets a UI warn\n\"N series were dropped this tick\" without reading server logs.", + "format": "int32", + "type": "integer" + }, + "last_evaluated_at": { + "example": "2025-10-12T12:15:47.609192Z", + "type": [ + "string", + "null" + ] + }, + "last_state": { + "description": "One of `ok|firing|unknown`.", + "type": "string" + }, + "last_value": { + "format": "double", + "type": [ + "number", + "null" + ] + }, + "max_series": { + "description": "Cardinality cap for dynamic alerting (1–100).", + "format": "int32", + "type": "integer" + }, + "metric_name": { + "type": "string" + }, + "name": { + "type": "string" + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "series_states": { + "additionalProperties": { + "$ref": "#/components/schemas/SeriesStateEntry" + }, + "description": "Full per-series state snapshot persisted after the latest dynamic-rule tick,\nkeyed by the human-readable series label (`endpoint=/checkout`). Empty for\nstatic/aggregate rules. Unlike `firing_series` (a live in-memory snapshot),\nthis is decoded from the persisted `series_states` jsonb column, so an\nexternal consumer that only reads the rule row still sees per-series detail.", + "propertyNames": { + "type": "string" + }, + "type": "object" + }, + "severity": { + "type": "string" + }, + "updated_at": { + "example": "2025-10-12T12:15:47.609192Z", + "type": "string" + }, + "window_secs": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "id", + "project_id", + "name", + "metric_name", + "aggregation", + "detection_kind", + "detection_config", + "window_secs", + "for_duration_secs", + "severity", + "enabled", + "last_state", + "label_filters", + "group_by", + "dynamic_alerts", + "max_series", + "grouped_notification_threshold", + "last_dropped_series_count", + "series_states", + "created_at", + "updated_at" + ], + "type": "object" + }, + "OtelMetricAlertsResponse": { + "properties": { + "data": { + "items": { + "$ref": "#/components/schemas/OtelMetricAlertRuleResponse" + }, + "type": "array" + }, + "total": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "data", + "total" + ], + "type": "object" + }, + "OtelMetricLabelKeysResponse": { + "properties": { + "keys": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "keys" + ], + "type": "object" + }, + "OtelMetricLabelValuesResponse": { + "properties": { + "values": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "values" + ], + "type": "object" + }, + "OtelMetricNamesResponse": { + "properties": { + "names": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "names" + ], + "type": "object" + }, + "OtelMetricsResponse": { + "properties": { + "count": { + "minimum": 0, + "type": "integer" + }, + "data": { + "items": { + "$ref": "#/components/schemas/MetricBucket" + }, + "type": "array" + } + }, + "required": [ + "data", + "count" + ], + "type": "object" + }, + "OutlierAlgorithm": { + "description": "Outlier detection algorithm.", + "enum": [ + "dbscan", + "scaled_dbscan", + "mad", + "scaled_mad" + ], + "type": "string" + }, + "OutlierParams": { + "description": "Outlier (cross-series population) detector parameters (stub — not evaluated).", + "properties": { + "algorithm": { + "$ref": "#/components/schemas/OutlierAlgorithm" + }, + "peer_group_key": { + "description": "Label key defining the peer population compared across series (e.g. `host`).", + "type": "string" + }, + "tolerance": { + "description": "Sensitivity; higher tolerates larger spread before flagging.", + "format": "double", + "type": "number" + } + }, + "required": [ + "peer_group_key" + ], + "type": "object" + }, + "OverprovisioningAssessment": { + "description": "Requests-vs-capacity-vs-usage assessment", + "properties": { + "cpu_request_inflation_ratio": { + "description": "Ratio of requested CPU to measured CPU usage (e.g. 40.0 = requests\nreserve 40× what the workloads actually use). `None` without metrics.", + "format": "double", + "type": [ + "number", + "null" + ] + }, + "cpu_requested_pct": { + "description": "Requested CPU as % of cluster capacity", + "format": "double", + "type": [ + "number", + "null" + ] + }, + "cpu_utilization_pct": { + "description": "Measured CPU usage as % of cluster capacity (`None` without metrics)", + "format": "double", + "type": [ + "number", + "null" + ] + }, + "explanation": { + "description": "Human-readable explanation of the verdict, e.g. \"Cluster capacity is\n8 vCPU but measured usage is 0.3 vCPU (3.7%) — severely overprovisioned\"", + "type": "string" + }, + "memory_request_inflation_ratio": { + "description": "Ratio of requested memory to measured memory usage", + "format": "double", + "type": [ + "number", + "null" + ] + }, + "memory_requested_pct": { + "description": "Requested memory as % of cluster capacity", + "format": "double", + "type": [ + "number", + "null" + ] + }, + "memory_utilization_pct": { + "description": "Measured memory usage as % of cluster capacity (`None` without metrics)", + "format": "double", + "type": [ + "number", + "null" + ] + }, + "verdict": { + "$ref": "#/components/schemas/OverprovisioningVerdict", + "description": "Overall verdict" + } + }, + "required": [ + "verdict", + "explanation" + ], + "type": "object" + }, + "OverprovisioningVerdict": { + "description": "Overall overprovisioning verdict", + "enum": [ + "severe", + "moderate", + "reasonable", + "unknown" + ], + "type": "string" + }, + "PageActivityBucket": { + "description": "Time bucket data point for page activity graph", + "properties": { + "avg_time_seconds": { + "description": "Average time on page in seconds", + "format": "double", + "type": "number" + }, + "page_views": { + "description": "Number of page views in this bucket", + "format": "int64", + "type": "integer" + }, + "timestamp": { + "description": "Timestamp for this bucket (ISO 8601)", + "type": "string" + }, + "visitors": { + "description": "Number of unique visitors in this bucket", + "format": "int64", + "type": "integer" + } + }, + "required": [ + "timestamp", + "visitors", + "page_views", + "avg_time_seconds" + ], + "type": "object" + }, + "PageCountryStats": { + "description": "Geographic distribution of visitors for a page", + "properties": { + "country": { + "description": "Country name", + "type": "string" + }, + "country_code": { + "description": "ISO country code (2-letter)", + "type": [ + "string", + "null" + ] + }, + "page_views": { + "description": "Number of page views from this country", + "format": "int64", + "type": "integer" + }, + "percentage": { + "description": "Percentage of total visitors", + "format": "double", + "type": "number" + }, + "visitors": { + "description": "Number of unique visitors from this country", + "format": "int64", + "type": "integer" + } + }, + "required": [ + "country", + "visitors", + "page_views", + "percentage" + ], + "type": "object" + }, + "PageFlowEntry": { + "description": "A single page with its entry/exit/bounce statistics", + "properties": { + "avg_time_on_page": { + "description": "Average time spent on this page in seconds", + "format": "double", + "type": [ + "number", + "null" + ] + }, + "bounce_count": { + "description": "Number of times visitors bounced on this page", + "format": "int64", + "type": "integer" + }, + "bounce_rate": { + "description": "Bounce rate: bounce_count / entry_count (only meaningful for entry pages)", + "format": "double", + "type": "number" + }, + "entry_count": { + "description": "Number of times this page was the entry page of a session", + "format": "int64", + "type": "integer" + }, + "entry_rate": { + "description": "Entry rate: entry_count / total_views", + "format": "double", + "type": "number" + }, + "exit_count": { + "description": "Number of times this page was the exit page of a session", + "format": "int64", + "type": "integer" + }, + "exit_rate": { + "description": "Exit rate: exit_count / total_views", + "format": "double", + "type": "number" + }, + "page_path": { + "description": "The page path (e.g. \"/pricing\", \"/docs/getting-started\")", + "type": "string" + }, + "total_views": { + "description": "Total page views for this page", + "format": "int64", + "type": "integer" + } + }, + "required": [ + "page_path", + "entry_count", + "exit_count", + "bounce_count", + "total_views", + "entry_rate", + "exit_rate", + "bounce_rate" + ], + "type": "object" + }, + "PageFlowQuery": { + "description": "Query parameters for page flow analytics", + "properties": { + "end_date": { + "format": "date-time", + "type": "string" + }, + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "limit": { + "description": "Maximum number of entry/exit pages to return (default: 20)", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "min_views_for_dropoff": { + "description": "Minimum views for drop-off analysis (default: 5)", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "start_date": { + "format": "date-time", + "type": "string" + }, + "transitions_limit": { + "description": "Maximum number of transitions to return (default: 50)", + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + "required": [ + "project_id", + "start_date", + "end_date" + ], + "type": "object" + }, + "PageFlowResponse": { + "description": "Complete page flow analytics response", + "properties": { + "drop_off_points": { + "description": "Top drop-off points (highest exit rates with meaningful traffic)", + "items": { + "$ref": "#/components/schemas/DropOffPoint" + }, + "type": "array" + }, + "top_entry_pages": { + "description": "Top entry pages (where visitors land), sorted by entry_count DESC", + "items": { + "$ref": "#/components/schemas/PageFlowEntry" + }, + "type": "array" + }, + "top_exit_pages": { + "description": "Top exit pages (where visitors leave), sorted by exit_count DESC", + "items": { + "$ref": "#/components/schemas/PageFlowEntry" + }, + "type": "array" + }, + "total_pages": { + "description": "Total unique pages seen in the period", + "format": "int64", + "type": "integer" + }, + "total_sessions": { + "description": "Total sessions in the period", + "format": "int64", + "type": "integer" + }, + "transitions": { + "description": "Page-to-page transitions (most common navigation paths)", + "items": { + "$ref": "#/components/schemas/PageTransition" + }, + "type": "array" + } + }, + "required": [ + "top_entry_pages", + "top_exit_pages", + "drop_off_points", + "transitions", + "total_pages", + "total_sessions" + ], + "type": "object" + }, + "PageHourlySessionsQuery": { + "description": "Query parameters for page hourly sessions endpoint", + "properties": { + "bucket_interval": { + "type": [ + "string", + "null" + ] + }, + "end_time": { + "format": "date-time", + "type": "string" + }, + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "page_path": { + "type": "string" + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "start_time": { + "format": "date-time", + "type": "string" + } + }, + "required": [ + "page_path", + "project_id", + "start_time", + "end_time" + ], + "type": "object" + }, + "PageHourlySessionsResponse": { + "properties": { + "hourly_data": { + "items": { + "$ref": "#/components/schemas/HourlyPageSessions" + }, + "type": "array" + }, + "hours": { + "format": "int32", + "type": "integer" + }, + "page_path": { + "type": "string" + }, + "total_sessions": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "page_path", + "hourly_data", + "total_sessions", + "hours" + ], + "type": "object" + }, + "PagePathDetailQuery": { + "description": "Query parameters for page path detail analytics", + "properties": { + "bucket_interval": { + "description": "Bucket interval for time series: 'hour', 'day', 'week', 'month' (default: auto)", + "type": [ + "string", + "null" + ] + }, + "end_date": { + "format": "date-time", + "type": "string" + }, + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "page_path": { + "description": "The specific page path to get details for (URL-encoded)", + "type": "string" + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "start_date": { + "format": "date-time", + "type": "string" + } + }, + "required": [ + "page_path", + "project_id", + "start_date", + "end_date" + ], + "type": "object" + }, + "PagePathDetailResponse": { + "description": "Detailed analytics response for a specific page path", + "properties": { + "activity_over_time": { + "description": "Time series data for activity graph", + "items": { + "$ref": "#/components/schemas/PageActivityBucket" + }, + "type": "array" + }, + "avg_time_on_page": { + "description": "Average time on page in seconds", + "format": "double", + "type": "number" + }, + "bounce_rate": { + "description": "Bounce rate percentage (0-100)", + "format": "double", + "type": "number" + }, + "bucket_interval": { + "description": "Bucket interval used for time series ('hour', 'day', etc.)", + "type": "string" + }, + "countries": { + "description": "Geographic distribution of visitors", + "items": { + "$ref": "#/components/schemas/PageCountryStats" + }, + "type": "array" + }, + "entry_rate": { + "description": "Entry rate - percentage of sessions that started on this page", + "format": "double", + "type": "number" + }, + "exit_rate": { + "description": "Exit rate - percentage of sessions that ended on this page", + "format": "double", + "type": "number" + }, + "page_path": { + "description": "The page path being analyzed", + "type": "string" + }, + "referrers": { + "description": "Top referrers to this page", + "items": { + "$ref": "#/components/schemas/PageReferrerStats" + }, + "type": "array" + }, + "total_page_views": { + "description": "Total page views in the date range", + "format": "int64", + "type": "integer" + }, + "unique_visitors": { + "description": "Total unique visitors to this page in the date range", + "format": "int64", + "type": "integer" + } + }, + "required": [ + "page_path", + "unique_visitors", + "total_page_views", + "avg_time_on_page", + "bounce_rate", + "entry_rate", + "exit_rate", + "activity_over_time", + "countries", + "referrers", + "bucket_interval" + ], + "type": "object" + }, + "PagePathInfo": { + "properties": { + "avg_time_seconds": { + "format": "double", + "type": [ + "number", + "null" + ] + }, + "first_seen": { + "type": "string" + }, + "last_seen": { + "type": "string" + }, + "page_path": { + "type": "string" + }, + "page_view_count": { + "format": "int64", + "type": "integer" + }, + "session_count": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "page_path", + "session_count", + "page_view_count", + "first_seen", + "last_seen" + ], + "type": "object" + }, + "PagePathSparkline": { + "properties": { + "page_path": { + "type": "string" + }, + "points": { + "items": { + "$ref": "#/components/schemas/PagePathSparklinePoint" + }, + "type": "array" + } + }, + "required": [ + "page_path", + "points" + ], + "type": "object" + }, + "PagePathSparklinePoint": { + "properties": { + "session_count": { + "format": "int64", + "type": "integer" + }, + "timestamp": { + "type": "string" + } + }, + "required": [ + "timestamp", + "session_count" + ], + "type": "object" + }, + "PagePathVisitorsQuery": { + "description": "Query parameters for page path visitors", + "properties": { + "end_date": { + "format": "date-time", + "type": "string" + }, + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "page": { + "description": "Page number (1-based, default: 1)", + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "page_path": { + "description": "The specific page path to get visitors for", + "type": "string" + }, + "per_page": { + "description": "Items per page (default: 50, max: 100)", + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "start_date": { + "format": "date-time", + "type": "string" + } + }, + "required": [ + "page_path", + "project_id", + "start_date", + "end_date" + ], + "type": "object" + }, + "PagePathVisitorsResponse": { + "description": "Response for page path visitors endpoint", + "properties": { + "page": { + "description": "Current page number", + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "page_path": { + "description": "The page path", + "type": "string" + }, + "per_page": { + "description": "Items per page", + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "sessions": { + "description": "Individual visitor sessions", + "items": { + "$ref": "#/components/schemas/PageVisitorSession" + }, + "type": "array" + }, + "total_count": { + "description": "Total number of visitor sessions matching the query", + "format": "int64", + "type": "integer" + } + }, + "required": [ + "page_path", + "total_count", + "page", + "per_page", + "sessions" + ], + "type": "object" + }, + "PagePathsQuery": { + "properties": { + "end_date": { + "format": "date-time", + "type": [ + "string", + "null" + ] + }, + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "limit": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "start_date": { + "format": "date-time", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "project_id" + ], + "type": "object" + }, + "PagePathsResponse": { + "properties": { + "page_paths": { + "items": { + "$ref": "#/components/schemas/PagePathInfo" + }, + "type": "array" + }, + "total_count": { + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "page_paths", + "total_count" + ], + "type": "object" + }, + "PagePathsSparklineQuery": { + "description": "Query parameters for batch page paths sparkline endpoint", + "properties": { + "end_time": { + "format": "date-time", + "type": "string" + }, + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "page_paths": { + "description": "Comma-separated list of page paths", + "type": "string" + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "start_time": { + "format": "date-time", + "type": "string" + } + }, + "required": [ + "project_id", + "start_time", + "end_time", + "page_paths" + ], + "type": "object" + }, + "PagePathsSparklineResponse": { + "properties": { + "sparklines": { + "items": { + "$ref": "#/components/schemas/PagePathSparkline" + }, + "type": "array" + } + }, + "required": [ + "sparklines" + ], + "type": "object" + }, + "PageReferrerStats": { + "description": "Referrer source for the page", + "properties": { + "percentage": { + "description": "Percentage of total visits", + "format": "double", + "type": "number" + }, + "referrer": { + "description": "Referrer URL or domain", + "type": "string" + }, + "visits": { + "description": "Number of visits from this referrer", + "format": "int64", + "type": "integer" + } + }, + "required": [ + "referrer", + "visits", + "percentage" + ], + "type": "object" + }, + "PageSessionComparison": { + "properties": { + "avg_duration_seconds": { + "format": "double", + "type": "number" + }, + "date": { + "type": "string" + }, + "event_count": { + "format": "int64", + "type": "integer" + }, + "page_path": { + "type": "string" + }, + "session_count": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "page_path", + "date", + "session_count", + "event_count", + "avg_duration_seconds" + ], + "type": "object" + }, + "PageSessionStats": { + "properties": { + "avg_page_views_per_session": { + "format": "double", + "type": "number" + }, + "avg_time_seconds": { + "format": "double", + "type": "number" + }, + "max_time_seconds": { + "format": "double", + "type": "number" + }, + "min_time_seconds": { + "format": "double", + "type": "number" + }, + "page_path": { + "type": "string" + }, + "total_page_views": { + "format": "int64", + "type": "integer" + }, + "total_sessions": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "page_path", + "total_sessions", + "avg_time_seconds", + "min_time_seconds", + "max_time_seconds", + "total_page_views", + "avg_page_views_per_session" + ], + "type": "object" + }, + "PageSessionStatsQuery": { + "properties": { + "end_date": { + "format": "date-time", + "type": "string" + }, + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "page_path": { + "type": "string" + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "start_date": { + "format": "date-time", + "type": "string" + } + }, + "required": [ + "page_path", + "project_id", + "start_date", + "end_date" + ], + "type": "object" + }, + "PageTransition": { + "description": "A page-to-page transition with count", + "properties": { + "from_page": { + "description": "The source page path", + "type": "string" + }, + "percentage": { + "description": "Percentage of transitions from the source page that go to this destination", + "format": "double", + "type": "number" + }, + "to_page": { + "description": "The destination page path", + "type": "string" + }, + "transition_count": { + "description": "Number of times this transition occurred", + "format": "int64", + "type": "integer" + } + }, + "required": [ + "from_page", + "to_page", + "transition_count", + "percentage" + ], + "type": "object" + }, + "PageVisit": { + "properties": { + "path": { + "type": "string" + }, + "visits": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "path", + "visits" + ], + "type": "object" + }, + "PageVisitorSession": { + "description": "Individual visitor session that viewed a specific page", + "properties": { + "browser": { + "description": "Browser name", + "type": [ + "string", + "null" + ] + }, + "city": { + "description": "Visitor's city", + "type": [ + "string", + "null" + ] + }, + "country": { + "description": "Visitor's country", + "type": [ + "string", + "null" + ] + }, + "country_code": { + "description": "Visitor's country code", + "type": [ + "string", + "null" + ] + }, + "device_type": { + "description": "Device type (Desktop, Mobile, Tablet)", + "type": [ + "string", + "null" + ] + }, + "is_bounce": { + "description": "Whether this was a bounce", + "type": "boolean" + }, + "is_entry": { + "description": "Whether this was the entry page for the session", + "type": "boolean" + }, + "is_exit": { + "description": "Whether this was the exit page for the session", + "type": "boolean" + }, + "operating_system": { + "description": "Operating system", + "type": [ + "string", + "null" + ] + }, + "referrer": { + "description": "Referrer URL", + "type": [ + "string", + "null" + ] + }, + "session_id": { + "description": "Session ID", + "type": [ + "string", + "null" + ] + }, + "session_page_number": { + "description": "Page number in session flow", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "time_on_page": { + "description": "Time spent on this page in seconds", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "viewed_at": { + "description": "When the page was viewed", + "format": "date-time", + "type": "string" + }, + "visitor_id": { + "description": "Visitor numeric ID", + "format": "int32", + "type": "integer" + }, + "visitor_uuid": { + "description": "Visitor UUID", + "type": "string" + } + }, + "required": [ + "visitor_id", + "visitor_uuid", + "viewed_at", + "is_entry", + "is_exit", + "is_bounce" + ], + "type": "object" + }, + "PagesComparisonResponse": { + "properties": { + "comparisons": { + "items": { + "$ref": "#/components/schemas/PageSessionComparison" + }, + "type": "array" + }, + "page_paths": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "comparisons", + "page_paths" + ], + "type": "object" + }, + "PaginatedEmailsResponse": { + "properties": { + "data": { + "items": { + "$ref": "#/components/schemas/EmailResponse" + }, + "type": "array" + }, + "page": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "page_size": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "total": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "data", + "total", + "page", + "page_size" + ], + "type": "object" + }, + "PaginatedEntitiesResponse": { + "properties": { + "count": { + "description": "Number of entities returned", + "minimum": 0, + "type": "integer" + }, + "entities": { + "description": "List of entities", + "items": { + "$ref": "#/components/schemas/EntityResponse" + }, + "type": "array" + }, + "has_more": { + "description": "Whether there are more entities available", + "type": "boolean" + }, + "limit": { + "description": "Limit used for this request", + "minimum": 0, + "type": "integer" + }, + "next_token": { + "description": "Continuation token for next page (S3, etc.)", + "type": [ + "string", + "null" + ] + }, + "total": { + "description": "Total number of entities (if available)", + "minimum": 0, + "type": [ + "integer", + "null" + ] + } + }, + "required": [ + "entities", + "count", + "limit", + "has_more" + ], + "type": "object" + }, + "PaginatedErrorEventsResponse": { + "properties": { + "data": { + "items": { + "$ref": "#/components/schemas/ErrorEventResponse" + }, + "type": "array" + }, + "pagination": { + "$ref": "#/components/schemas/PaginationMeta" + } + }, + "required": [ + "data", + "pagination" + ], + "type": "object" + }, + "PaginatedErrorGroupsResponse": { + "properties": { + "data": { + "items": { + "$ref": "#/components/schemas/ErrorGroupResponse" + }, + "type": "array" + }, + "pagination": { + "$ref": "#/components/schemas/PaginationMeta" + } + }, + "required": [ + "data", + "pagination" + ], + "type": "object" + }, + "PaginatedEventsResponse": { + "properties": { + "events": { + "items": { + "$ref": "#/components/schemas/TrackingEventResponse" + }, + "type": "array" + }, + "page": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "page_size": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "total": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "events", + "total", + "page", + "page_size" + ], + "type": "object" + }, + "PaginatedExternalImagesResponse": { + "properties": { + "data": { + "items": { + "$ref": "#/components/schemas/ExternalImageResponse" + }, + "type": "array" + }, + "page": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "page_size": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "total": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "data", + "total", + "page", + "page_size" + ], + "type": "object" + }, + "PaginatedProjectList": { + "properties": { + "page": { + "format": "int64", + "type": "integer" + }, + "per_page": { + "format": "int64", + "type": "integer" + }, + "projects": { + "items": { + "$ref": "#/components/schemas/ProjectResponse" + }, + "type": "array" + }, + "total": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "projects", + "total", + "page", + "per_page" + ], + "type": "object" + }, + "PaginatedStaticBundlesResponse": { + "properties": { + "data": { + "items": { + "$ref": "#/components/schemas/StaticBundleResponse" + }, + "type": "array" + }, + "page": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "page_size": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "total": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "data", + "total", + "page", + "page_size" + ], + "type": "object" + }, + "Pagination": { + "description": "SDK pagination cursor. We use opaque page numbers internally but\nexpose `count`/`next`/`prev` the way `@vercel/sandbox` expects.", + "properties": { + "count": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "next": { + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "prev": { + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + } + }, + "required": [ + "count" + ], + "type": "object" + }, + "PaginationMeta": { + "properties": { + "page": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "page_size": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "total_count": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "total_pages": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "page", + "page_size", + "total_count", + "total_pages" + ], + "type": "object" + }, + "PaginationParams": { + "properties": { + "page": { + "format": "int64", + "type": "integer" + }, + "per_page": { + "format": "int64", + "type": "integer" + } + }, + "type": "object" + }, + "PasswordProtectionConfig": { + "description": "Password protection configuration\n\nWhen enabled, the proxy shows an HTML password form before allowing access.\nAfter the user enters the correct password, an HMAC-signed cookie is set\nso subsequent requests pass through without re-entering the password.", + "properties": { + "enabled": { + "description": "Whether password protection is enabled", + "type": "boolean" + }, + "passwordHash": { + "description": "The bcrypt-hashed password (never stored or returned in plaintext)", + "type": "string" + } + }, + "required": [ + "enabled", + "passwordHash" + ], + "type": "object" + }, + "PatchSettingsRequest": { + "properties": { + "auto_upgrade": { + "type": [ + "boolean", + "null" + ] + }, + "host_port": { + "format": "int32", + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "image": { + "type": [ + "string", + "null" + ] + } + }, + "type": "object" + }, + "PathVisitors": { + "properties": { + "name": { + "type": "string" + }, + "percentage": { + "format": "double", + "type": "number" + }, + "visitors": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "name", + "visitors", + "percentage" + ], + "type": "object" + }, + "PathVisitorsAnalyticsQuery": { + "properties": { + "deployment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "end_date": { + "format": "date-time", + "type": "string" + }, + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "limit": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "start_date": { + "format": "date-time", + "type": "string" + } + }, + "required": [ + "start_date", + "end_date", + "project_id" + ], + "type": "object" + }, + "PathVisitorsResponse": { + "properties": { + "results": { + "items": { + "$ref": "#/components/schemas/PathVisitors" + }, + "type": "array" + } + }, + "required": [ + "results" + ], + "type": "object" + }, + "PeerEntry": { + "description": "Wire-format peer entry. Matches `temps_network::config::Peer` but\nuses strings on the wire to keep the API stable across underlying\ntype evolution.", + "properties": { + "compute_cidr": { + "description": "Per-node CIDR (e.g. `\"172.20.5.0/24\"`).", + "type": "string" + }, + "node_id": { + "description": "Stable v5 UUID derived from the database node id. Workers use\nthis as the kernel-layer identifier when calling\n`NetworkManager::reconcile_peers`.", + "type": "string" + }, + "underlay_address": { + "description": "Address the local node should use to reach this peer over the\nunderlay (private VPC IP for same-DC, public IP for cross-DC).", + "type": "string" + } + }, + "required": [ + "node_id", + "compute_cidr", + "underlay_address" + ], + "type": "object" + }, + "PeerListResponse": { + "description": "Response body for `GET /internal/nodes/{node_id}/network/peers`.", + "properties": { + "alloc": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/AllocEntry", + "description": "Caller's own allocation, or `null` if multi-host networking has\nnot been enabled for this node yet." + } + ] + }, + "cluster_dns_enabled": { + "description": "Whether the cluster-DNS resolver is enabled on this control plane\n(`AppSettings.cluster_dns.enabled`). Workers should start their\nper-node resolver and write `overlay_bridge_address` only when this\nis `true`. Always serialized (never `skip_serializing_if`) so older\nand newer version skew degrades to the safe default of `false`.", + "type": "boolean" + }, + "peers": { + "description": "All other nodes with a `compute_cidr` set, excluding the caller.", + "items": { + "$ref": "#/components/schemas/PeerEntry" + }, + "type": "array" + } + }, + "required": [ + "peers", + "cluster_dns_enabled" + ], + "type": "object" + }, + "PendingActionResponse": { + "description": "A proposed AI write action awaiting human confirmation.", + "properties": { + "confirmed_at": { + "type": [ + "string", + "null" + ] + }, + "created_at": { + "type": "string" + }, + "error": { + "type": [ + "string", + "null" + ] + }, + "executed_at": { + "type": [ + "string", + "null" + ] + }, + "method": { + "type": "string" + }, + "operation_id": { + "type": "string" + }, + "params": { + "description": "The flat params to be replayed at execute time (shown pre-execution for review)." + }, + "plan_public_id": { + "description": "Set when this action is one step of a multi-step plan (chained actions);\nall steps of the plan share this id. Absent for standalone single actions.", + "type": [ + "string", + "null" + ] + }, + "public_id": { + "type": "string" + }, + "required_permission": { + "type": [ + "string", + "null" + ] + }, + "result": {}, + "status": { + "type": "string" + }, + "step_index": { + "description": "0-based order of this step within its plan (0 for standalone actions).", + "format": "int32", + "type": "integer" + }, + "summary": { + "type": "string" + } + }, + "required": [ + "public_id", + "operation_id", + "method", + "summary", + "status", + "step_index", + "params", + "created_at" + ], + "type": "object" + }, + "PerformanceMetricsQuery": { + "allOf": [ + { + "$ref": "#/components/schemas/SpeedSegmentFilters", + "description": "Segment filters (filter_path, filter_country, filter_region,\nfilter_city, filter_browser, filter_operating_system) — flattened so\neach remains a top-level query string param." + }, + { + "properties": { + "deployment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "device_type": { + "description": "Device type filter: \"desktop\" or \"mobile\"", + "type": [ + "string", + "null" + ] + }, + "end_date": { + "format": "date-time", + "type": "string" + }, + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "include_bots": { + "description": "Include crawler/datacenter (bot) samples. Defaults to false — bots\nare excluded from the read view but always stored at ingest.", + "type": [ + "boolean", + "null" + ] + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "start_date": { + "format": "date-time", + "type": "string" + } + }, + "required": [ + "start_date", + "end_date", + "project_id" + ], + "type": "object" + } + ] + }, + "PerformanceMetricsResponse": { + "properties": { + "cls": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "cls_p75": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "cls_p90": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "cls_p95": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "cls_p99": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "fcp": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "fcp_p75": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "fcp_p90": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "fcp_p95": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "fcp_p99": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "fid": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "fid_p75": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "fid_p90": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "fid_p95": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "fid_p99": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "inp": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "inp_p75": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "inp_p90": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "inp_p95": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "inp_p99": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "lcp": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "lcp_p75": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "lcp_p90": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "lcp_p95": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "lcp_p99": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "ttfb": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "ttfb_p75": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "ttfb_p90": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "ttfb_p95": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "ttfb_p99": { + "format": "float", + "type": [ + "number", + "null" + ] + } + }, + "type": "object" + }, + "PermissionInfo": { + "description": "Information about a single permission", + "properties": { + "category": { + "description": "Category of the permission (e.g., \"Projects\", \"Deployments\")", + "type": "string" + }, + "description": { + "description": "Human-readable description of the permission", + "type": "string" + }, + "name": { + "description": "The permission identifier (e.g., \"projects:read\")", + "type": "string" + } + }, + "required": [ + "name", + "description", + "category" + ], + "type": "object" + }, + "PgUpgradeLogResponse": { + "properties": { + "content": { + "type": "string" + }, + "log_id": { + "type": "string" + } + }, + "required": [ + "log_id", + "content" + ], + "type": "object" + }, + "PgUpgradeResponse": { + "properties": { + "attempt": { + "format": "int32", + "type": "integer" + }, + "created_at": { + "type": "string" + }, + "error_message": { + "type": [ + "string", + "null" + ] + }, + "finished_at": { + "type": [ + "string", + "null" + ] + }, + "from_image": { + "type": "string" + }, + "from_version": { + "type": "string" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "log_id": { + "type": "string" + }, + "phase": { + "type": "string" + }, + "pre_upgrade_backup_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "rollback_volume_name": { + "type": [ + "string", + "null" + ] + }, + "service_id": { + "format": "int32", + "type": "integer" + }, + "started_at": { + "type": [ + "string", + "null" + ] + }, + "status": { + "type": "string" + }, + "to_image": { + "type": "string" + }, + "to_version": { + "type": "string" + } + }, + "required": [ + "id", + "service_id", + "from_version", + "to_version", + "from_image", + "to_image", + "status", + "phase", + "log_id", + "attempt", + "created_at" + ], + "type": "object" + }, + "PipelineStats": { + "description": "Internal pipeline statistics for self-observability.", + "properties": { + "ingest_errors": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "logs_dropped": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "logs_received": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "logs_stored_db": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "logs_stored_s3": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "metrics_dropped": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "metrics_received": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "metrics_stored": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "spans_dropped": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "spans_received": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "spans_stored": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "metrics_received", + "metrics_stored", + "metrics_dropped", + "spans_received", + "spans_stored", + "spans_dropped", + "logs_received", + "logs_stored_db", + "logs_stored_s3", + "logs_dropped", + "ingest_errors" + ], + "type": "object" + }, + "PipelineStatsResponse": { + "properties": { + "stats": { + "$ref": "#/components/schemas/PipelineStats" + } + }, + "required": [ + "stats" + ], + "type": "object" + }, + "PlanComplexity": { + "description": "Plan complexity indicator", + "enum": [ + "low", + "medium", + "high" + ], + "type": "string" + }, + "PlanMetadata": { + "description": "Plan metadata", + "properties": { + "complexity": { + "$ref": "#/components/schemas/PlanComplexity", + "description": "Estimated complexity (low, medium, high)" + }, + "generated_at": { + "description": "When the plan was generated", + "format": "date-time", + "type": "string" + }, + "generator_version": { + "description": "Generator (importer) version", + "type": "string" + }, + "warnings": { + "description": "Warnings detected during planning", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "generated_at", + "generator_version", + "complexity", + "warnings" + ], + "type": "object" + }, + "PlanSourceBackup": { + "properties": { + "created_at": { + "type": [ + "string", + "null" + ] + }, + "format": { + "description": "\"walg\", \"pg_dump\", \"unknown\".", + "type": "string" + }, + "id": { + "description": "DB id, absent for orphan (S3-scan) backups.", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "location": { + "description": "Resolved S3 location the orchestrator will actually use.", + "type": "string" + }, + "location_was_resolved": { + "description": "True when the original row's `s3_location` was empty and we resolved\na location by probing S3. The UI shows this as a warning.", + "type": "boolean" + }, + "origin_service_name": { + "description": "Service that originally produced the backup, if known.", + "type": [ + "string", + "null" + ] + }, + "size_bytes": { + "format": "int64", + "type": [ + "integer", + "null" + ] + } + }, + "required": [ + "location", + "location_was_resolved", + "format" + ], + "type": "object" + }, + "PlanTarget": { + "properties": { + "container": { + "description": "Expected Docker container name.", + "type": "string" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "name": { + "type": "string" + } + }, + "required": [ + "id", + "name", + "container" + ], + "type": "object" + }, + "PlatformInfo": { + "description": "Platform compatibility information", + "properties": { + "architecture": { + "description": "System architecture (e.g., \"x86_64\", \"aarch64\")", + "type": "string" + }, + "os_type": { + "description": "Operating system type (e.g., \"linux\", \"windows\", \"darwin\")", + "type": "string" + }, + "platforms": { + "description": "List of supported platforms in \"os/arch\" format (e.g., [\"linux/amd64\"])", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "os_type", + "architecture", + "platforms" + ], + "type": "object" + }, + "PluginManifest": { + "description": "The complete plugin manifest — the handshake contract.", + "properties": { + "description": { + "description": "Short description of what the plugin does", + "type": [ + "string", + "null" + ] + }, + "display_name": { + "description": "Human-readable display name", + "type": [ + "string", + "null" + ] + }, + "events": { + "description": "Platform event types the plugin subscribes to.\n\nWhen specified, Temps will POST matching events to the plugin's\n`/_events` endpoint. Uses dot-notation event names matching the\nwebhook event types (e.g., \"deployment.succeeded\", \"project.created\").\n\nAvailable events:\n- `deployment.created`, `deployment.succeeded`, `deployment.failed`,\n `deployment.cancelled`, `deployment.ready`\n- `project.created`, `project.deleted`\n- `domain.created`, `domain.provisioned`", + "items": { + "type": "string" + }, + "type": "array" + }, + "health_path": { + "description": "Health check endpoint path (relative to plugin root)", + "type": "string" + }, + "name": { + "description": "Unique plugin identifier (kebab-case, e.g., \"backup-manager\")", + "type": "string" + }, + "nav": { + "description": "Navigation entries for the UI sidebar", + "items": { + "$ref": "#/components/schemas/NavEntry" + }, + "type": "array" + }, + "requires_db": { + "description": "Whether the plugin needs database access", + "type": "boolean" + }, + "ui": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/UiManifest", + "description": "UI bundle manifest (if the plugin has a UI)" + } + ] + }, + "version": { + "description": "SemVer version string", + "type": "string" + } + }, + "required": [ + "name", + "version" + ], + "type": "object" + }, + "PortMapping": { + "description": "Port mapping", + "properties": { + "container_port": { + "description": "Container port", + "format": "int32", + "minimum": 0, + "type": "integer" + }, + "host_port": { + "description": "Host port (optional - can be assigned dynamically)", + "format": "int32", + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "is_primary": { + "description": "Whether this is the primary HTTP port", + "type": "boolean" + }, + "protocol": { + "$ref": "#/components/schemas/Protocol", + "description": "Protocol (tcp, udp)" + } + }, + "required": [ + "container_port", + "protocol", + "is_primary" + ], + "type": "object" + }, + "PostgresWalHealth": { + "properties": { + "archive_backlog": { + "description": "Number of `archive_status/*.ready` files — un-shipped WAL segments.", + "format": "int64", + "type": "integer" + }, + "archive_command": { + "description": "The literal `archive_command` setting. May be empty or `/bin/true`\nwhen archiving is effectively disabled despite `archive_mode = on`.", + "type": [ + "string", + "null" + ] + }, + "archive_mode": { + "$ref": "#/components/schemas/ArchiveMode" + }, + "archiver_failed_count": { + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "archiver_last_failed_at": { + "format": "date-time", + "type": [ + "string", + "null" + ] + }, + "max_wal_size_bytes": { + "description": "`max_wal_size` setting in bytes (parsed from `pg_settings`).", + "format": "int64", + "type": "integer" + }, + "oldest_wal_age_secs": { + "description": "Age of the oldest WAL file in `pg_wal/` (seconds).", + "format": "int64", + "type": "integer" + }, + "pg_wal_bytes": { + "description": "Total size of files under `pg_wal/`, from `pg_ls_waldir()`.", + "format": "int64", + "type": "integer" + }, + "probed_at": { + "description": "When the snapshot was taken.", + "format": "date-time", + "type": "string" + }, + "stale_slots": { + "items": { + "$ref": "#/components/schemas/StaleSlot" + }, + "type": "array" + }, + "warnings": { + "description": "Computed warnings, ordered by severity (critical first).", + "items": { + "$ref": "#/components/schemas/WalWarning" + }, + "type": "array" + } + }, + "required": [ + "probed_at", + "pg_wal_bytes", + "max_wal_size_bytes", + "archive_mode", + "archive_backlog", + "stale_slots", + "oldest_wal_age_secs", + "warnings" + ], + "type": "object" + }, + "PresetConfigSchema": { + "description": "Union type for preset configurations\nUse the appropriate configuration type based on your preset", + "oneOf": [ + { + "$ref": "#/components/schemas/DockerfilePresetConfig", + "description": "Configuration for Dockerfile preset" + }, + { + "$ref": "#/components/schemas/DockerComposePresetConfig", + "description": "Configuration for Docker Compose" + }, + { + "$ref": "#/components/schemas/NixpacksPresetConfig", + "description": "Configuration for Nixpacks provider selection and inline build plan" + }, + { + "$ref": "#/components/schemas/StaticPresetConfig", + "description": "Configuration for static site presets (Vite, Next.js, etc.)" + } + ] + }, + "PresetInfo": { + "description": "Detected preset information", + "properties": { + "compose_files": { + "description": "Compose file paths found in the repository (only for docker-compose preset)", + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + }, + "exposed_port": { + "description": "Default exposed port for this preset", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "icon_url": { + "description": "Icon URL for this preset", + "type": [ + "string", + "null" + ] + }, + "path": { + "description": "Path where preset was detected (empty for root)", + "type": "string" + }, + "preset": { + "description": "Preset slug (e.g., \"nextjs\", \"fastapi\")", + "type": "string" + }, + "preset_label": { + "description": "Human-readable preset label", + "type": "string" + }, + "project_type": { + "description": "Project type (e.g., \"frontend\", \"backend\", \"fullstack\")", + "type": "string" + } + }, + "required": [ + "path", + "preset", + "preset_label", + "project_type" + ], + "type": "object" + }, + "PresetResponse": { + "properties": { + "default_port": { + "description": "Default port the application listens on (None for static sites)", + "example": 3000, + "format": "int32", + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "description": { + "description": "Description of what this preset does", + "type": "string" + }, + "icon_url": { + "description": "Icon URL for the preset", + "type": "string" + }, + "label": { + "description": "Display name/label for the preset", + "type": "string" + }, + "project_type": { + "description": "Project type (server or static)", + "type": "string" + }, + "slug": { + "description": "Unique identifier slug for the preset", + "type": "string" + } + }, + "required": [ + "slug", + "label", + "icon_url", + "project_type", + "description" + ], + "type": "object" + }, + "PreviewGatewaySettings": { + "description": "Workspace preview gateway settings.\n\nThe preview gateway is a single shared Docker container that lives on the\n`temps-sandbox-net` network and routes requests to workspace sandbox dev\nservers based on the `Host` header (`ws--.`).\n`temps serve` reconciles this container on startup; these settings let an\noperator override the image, host port, and auto-upgrade behavior.", + "properties": { + "auto_upgrade": { + "default": true, + "description": "When true (default), the supervisor will pull and apply the image\npinned in the Temps binary on every startup. When false, the\ncurrently-running image is left alone — operators upgrade manually\nfrom the settings UI.", + "example": true, + "type": "boolean" + }, + "host_port": { + "default": 8090, + "description": "Host port to publish the gateway on (always bound to 127.0.0.1).\nPingora forwards `ws-*` traffic to this port after authenticating.", + "example": 8090, + "format": "int32", + "minimum": 0, + "type": "integer" + }, + "image": { + "default": "ghcr.io/gotempsh/temps-preview-gateway:latest", + "description": "Docker image reference for the gateway. Pinned per Temps release.\nOperators can override this to test a custom build.", + "example": "ghcr.io/gotempsh/temps-preview-gateway:latest", + "type": "string" + }, + "shared_secret": { + "default": "", + "description": "Shared secret the host-side Pingora sends on every forwarded preview\nrequest via `X-Temps-Preview-Token`; the gateway rejects requests\nwithout it. Auto-generated on first boot, persisted in DB so the\nsecret is stable across `temps serve` restarts regardless of cwd,\n`TEMPS_DATA_DIR`, or data-dir changes. MUST be masked (`***`) in any\nAPI response — never expose it over HTTP.", + "example": "", + "type": "string" + } + }, + "type": "object" + }, + "PreviewGatewaySettingsMasked": { + "description": "Preview gateway settings with `shared_secret` elided.", + "properties": { + "auto_upgrade": { + "type": "boolean" + }, + "host_port": { + "format": "int32", + "minimum": 0, + "type": "integer" + }, + "image": { + "type": "string" + }, + "shared_secret_set": { + "type": "boolean" + } + }, + "required": [ + "image", + "host_port", + "auto_upgrade", + "shared_secret_set" + ], + "type": "object" + }, + "PreviewGatewaySettingsResponse": { + "properties": { + "auto_upgrade": { + "type": "boolean" + }, + "default_host_port": { + "description": "The compile-time default host port.", + "format": "int32", + "minimum": 0, + "type": "integer" + }, + "default_image": { + "description": "The compile-time default image — exposed so the UI can offer a\n\"Reset to default\" link without round-tripping.", + "type": "string" + }, + "host_port": { + "format": "int32", + "minimum": 0, + "type": "integer" + }, + "image": { + "type": "string" + } + }, + "required": [ + "image", + "host_port", + "auto_upgrade", + "default_image", + "default_host_port" + ], + "type": "object" + }, + "PreviewShareLinkBody": { + "description": "Request body for minting a preview share link.", + "properties": { + "path": { + "description": "Path the recipient lands on. Must be same-origin (start with a single\n`/`); anything else is replaced with `/` so a share link can never be\nturned into an open redirect.", + "type": [ + "string", + "null" + ] + }, + "port": { + "description": "Port inside the sandbox the preview serves on.", + "format": "int32", + "minimum": 0, + "type": "integer" + }, + "ttl_seconds": { + "description": "How long the link stays usable, in seconds. Clamped to 24 hours.\nDefaults to one hour — long enough to send to a reviewer, short enough\nthat a link pasted in a ticket does not stay live indefinitely.", + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + } + }, + "required": [ + "port" + ], + "type": "object" + }, + "PreviewShareLinkResponse": { + "properties": { + "expires_at": { + "description": "Unix seconds after which the link stops working.", + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "url": { + "description": "The full link. Its fragment contains the grant and must be treated as a\ncredential; URL fragments are not sent to servers or in Referer headers.", + "type": "string" + } + }, + "required": [ + "url", + "expires_at" + ], + "type": "object" + }, + "PricingResponse": { + "properties": { + "models": { + "items": { + "$ref": "#/components/schemas/ModelPricing" + }, + "type": "array" + } + }, + "required": [ + "models" + ], + "type": "object" + }, + "ProblemDetails": { + "description": "Representation of a Problem error to return to the client.\nFollows RFC 7807 - Problem Details for HTTP APIs", + "example": { + "additional_info": "Custom field with additional details", + "detail": "The server encountered an unexpected condition", + "instance": "/account/12345/msgs/abc", + "title": "Internal Server Error", + "type": "https://example.com/probs/out-of-memory" + }, + "properties": { + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem", + "example": "The server encountered an unexpected condition", + "type": [ + "string", + "null" + ] + }, + "extensions": { + "additionalProperties": true, + "description": "Additional properties of the problem", + "type": "object" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem", + "example": "/account/12345/msgs/abc", + "type": [ + "string", + "null" + ] + }, + "title": { + "description": "A short, human-readable summary of the problem type", + "example": "Internal Server Error", + "type": "string" + }, + "type": { + "description": "A URI reference that identifies the problem type", + "example": "https://example.com/probs/out-of-memory", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "title", + "extensions" + ], + "type": "object" + }, + "ProjectAccessResponse": { + "properties": { + "created_at": { + "example": "2026-07-30T12:15:47.609192Z", + "format": "date-time", + "type": "string" + }, + "granted_by": { + "format": "int32", + "type": "integer" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "role": { + "$ref": "#/components/schemas/TeamRole" + }, + "team_id": { + "format": "int32", + "type": "integer" + }, + "updated_at": { + "example": "2026-07-30T12:15:47.609192Z", + "format": "date-time", + "type": "string" + } + }, + "required": [ + "id", + "project_id", + "team_id", + "role", + "granted_by", + "created_at", + "updated_at" + ], + "type": "object" + }, + "ProjectConfiguration": { + "description": "Project-level configuration", + "properties": { + "is_web_app": { + "description": "Whether this is a web application", + "type": "boolean" + }, + "name": { + "description": "Proposed project name", + "type": "string" + }, + "project_type": { + "$ref": "#/components/schemas/ProjectType", + "description": "Project type" + }, + "slug": { + "description": "Proposed slug (URL-safe identifier)", + "type": "string" + } + }, + "required": [ + "name", + "slug", + "project_type", + "is_web_app" + ], + "type": "object" + }, + "ProjectDSNResponse": { + "properties": { + "created_at": { + "type": "string" + }, + "deployment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "dsn": { + "type": "string" + }, + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "event_count": { + "format": "int64", + "type": "integer" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "is_active": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "public_key": { + "type": "string" + } + }, + "required": [ + "id", + "project_id", + "name", + "public_key", + "dsn", + "created_at", + "is_active", + "event_count" + ], + "type": "object" + }, + "ProjectDashboardAnalytics": { + "description": "Analytics data for a single project in the dashboard batch response", + "properties": { + "hourly_visits": { + "description": "Hourly sparkline data points", + "items": { + "$ref": "#/components/schemas/EventTimeline" + }, + "type": "array" + }, + "previous_unique_visitors": { + "description": "Unique visitor count in the previous period (same duration, shifted back)", + "format": "int64", + "type": "integer" + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "trend_percentage": { + "description": "Percentage change from previous period (positive = growth, negative = decline)\nNull when previous period had zero visitors (no baseline to compare)", + "format": "double", + "type": [ + "number", + "null" + ] + }, + "unique_visitors": { + "description": "Unique visitor count in the current time range", + "format": "int64", + "type": "integer" + } + }, + "required": [ + "project_id", + "unique_visitors", + "previous_unique_visitors", + "hourly_visits" + ], + "type": "object" + }, + "ProjectHealthSummary": { + "description": "Health summary for a single project (last 1 hour)", + "properties": { + "avg_response_time_ms": { + "description": "Average response time in ms", + "format": "double", + "type": "number" + }, + "error_rate": { + "description": "Error rate as a percentage (0-100)", + "format": "double", + "type": "number" + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "status": { + "description": "Health status: \"healthy\", \"degraded\", \"down\", \"unknown\"", + "type": "string" + }, + "total_errors": { + "description": "Total server errors (status >= 500) in the period", + "format": "int64", + "type": "integer" + }, + "total_requests": { + "description": "Total requests in the period", + "format": "int64", + "type": "integer" + } + }, + "required": [ + "project_id", + "total_requests", + "total_errors", + "avg_response_time_ms", + "error_rate", + "status" + ], + "type": "object" + }, + "ProjectInfo": { + "properties": { + "created_at": { + "example": "2025-10-12T12:15:47.609192Z", + "type": "string" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "slug": { + "type": "string" + } + }, + "required": [ + "id", + "slug", + "created_at" + ], + "type": "object" + }, + "ProjectMonitorHealth": { + "description": "Health summary for a single project based on its production monitors", + "properties": { + "project_id": { + "format": "int32", + "type": "integer" + }, + "status": { + "description": "Overall status: \"operational\", \"degraded\", \"down\", or \"no_monitors\"", + "type": "string" + } + }, + "required": [ + "project_id", + "status" + ], + "type": "object" + }, + "ProjectPresetResponse": { + "properties": { + "composeFiles": { + "description": "Compose file paths found in the repository (only for docker-compose preset)", + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + }, + "exposedPort": { + "description": "Default exposed port for this preset (e.g., 3000 for Next.js, 8000 for FastAPI)", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "iconUrl": { + "description": "Icon URL for the preset", + "type": [ + "string", + "null" + ] + }, + "path": { + "type": "string" + }, + "preset": { + "type": "string" + }, + "presetLabel": { + "type": "string" + }, + "projectType": { + "description": "Project type category (e.g., \"frontend\", \"backend\", \"fullstack\")", + "type": "string" + } + }, + "required": [ + "path", + "preset", + "presetLabel", + "projectType" + ], + "type": "object" + }, + "ProjectQuery": { + "properties": { + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "project_id": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "project_id" + ], + "type": "object" + }, + "ProjectRef": { + "description": "A lightweight project descriptor included in `UnifiedTrace`.", + "properties": { + "project_id": { + "format": "int32", + "type": "integer" + }, + "project_name": { + "type": "string" + }, + "project_slug": { + "description": "URL slug used to link a span back into its owning project's trace view.", + "type": "string" + } + }, + "required": [ + "project_id", + "project_name", + "project_slug" + ], + "type": "object" + }, + "ProjectResponse": { + "properties": { + "ai_alert_summaries_enabled": { + "description": "Opt-in to AI summarization of metric alert notifications (NULL/false = off).", + "type": [ + "boolean", + "null" + ] + }, + "ai_debug_chat_enabled": { + "description": "Opt-in to AI debugging chat, e.g. on deployment failures (NULL/false = off).", + "type": [ + "boolean", + "null" + ] + }, + "ai_write_actions_enabled": { + "description": "Opt-in to AI propose-then-confirm write capability (false = off).", + "type": "boolean" + }, + "attack_mode": { + "description": "Attack mode - when enabled, requires CAPTCHA verification for all project environments", + "type": "boolean" + }, + "created_at": { + "format": "int64", + "type": "integer" + }, + "cross_project_trace_sharing": { + "description": "ADR-027 Phase 3 opt-out: when false, this project's traces are suppressed\nfrom cross-project discovery results. Default true (consistent with the\nOSS global-observability model where any OtelRead holder can query any\nproject's telemetry).", + "type": "boolean" + }, + "deployment_config": { + "$ref": "#/components/schemas/DeploymentConfig", + "description": "Deployment configuration (resources, autoscaling, features)" + }, + "directory": { + "type": "string" + }, + "enable_preview_environments": { + "description": "Enable automatic preview environment creation for each branch", + "type": "boolean" + }, + "error_source_context_enabled": { + "description": "Opt-in to native error-tracking source context (false = off). When on,\nTemps stores uploaded source files and shows source code in stack traces.", + "type": "boolean" + }, + "error_source_root": { + "description": "Where auto-capture reads source from (relative to the checkout). Null =\nthe deployment's Docker build context.", + "type": [ + "string", + "null" + ] + }, + "git_provider_connection_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "git_url": { + "description": "Git clone URL for the repository (used for public repos without a provider connection)", + "type": [ + "string", + "null" + ] + }, + "gitlab_webhook_id": { + "description": "GitLab webhook ID installed on the connected repository.\n`null` when no GitLab webhook is installed (not connected to GitLab,\nor webhook was removed / never created).", + "example": 42, + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "id": { + "format": "int32", + "type": "integer" + }, + "last_deployment": { + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "main_branch": { + "type": "string" + }, + "name": { + "type": "string" + }, + "preset": { + "type": [ + "string", + "null" + ] + }, + "preset_config": { + "description": "Preset-specific configuration (Dockerfile path, build context, etc.)" + }, + "preview_envs_idle_timeout_seconds": { + "description": "Idle timeout (seconds) for on-demand preview environments.", + "format": "int32", + "type": "integer" + }, + "preview_envs_on_demand": { + "description": "When true, newly-created preview environments default to on-demand mode\n(containers stop after the configured idle timeout to save resources).", + "type": "boolean" + }, + "preview_envs_wake_timeout_seconds": { + "description": "Wake timeout (seconds) for on-demand preview environments.", + "format": "int32", + "type": "integer" + }, + "repo_name": { + "type": [ + "string", + "null" + ] + }, + "repo_owner": { + "type": [ + "string", + "null" + ] + }, + "slug": { + "type": "string" + }, + "source_type": { + "$ref": "#/components/schemas/SourceType", + "description": "Source type for deployments (git, docker_image, or static_files)" + }, + "updated_at": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "id", + "slug", + "name", + "directory", + "main_branch", + "created_at", + "updated_at", + "deployment_config", + "attack_mode", + "ai_write_actions_enabled", + "error_source_context_enabled", + "enable_preview_environments", + "preview_envs_on_demand", + "preview_envs_idle_timeout_seconds", + "preview_envs_wake_timeout_seconds", + "source_type", + "cross_project_trace_sharing" + ], + "type": "object" + }, + "ProjectSecretEnvironmentInfo": { + "properties": { + "id": { + "format": "int32", + "type": "integer" + }, + "main_url": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "id", + "name", + "main_url" + ], + "type": "object" + }, + "ProjectSecretResponse": { + "description": "Project secret metadata. There is deliberately no `value` field — secret\nplaintext is never returned after creation. Callers that need the value\nmust read it from the mounted file inside the container.", + "properties": { + "created_at": { + "format": "int64", + "type": "integer" + }, + "environments": { + "items": { + "$ref": "#/components/schemas/ProjectSecretEnvironmentInfo" + }, + "type": "array" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "include_in_preview": { + "type": "boolean" + }, + "key": { + "type": "string" + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "updated_at": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "id", + "project_id", + "key", + "include_in_preview", + "created_at", + "updated_at", + "environments" + ], + "type": "object" + }, + "ProjectServiceInfo": { + "properties": { + "id": { + "format": "int32", + "type": "integer" + }, + "project": { + "$ref": "#/components/schemas/ProjectInfo" + }, + "service": { + "$ref": "#/components/schemas/ExternalServiceInfo" + } + }, + "required": [ + "id", + "project", + "service" + ], + "type": "object" + }, + "ProjectStatisticsResponse": { + "properties": { + "total_count": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "total_count" + ], + "type": "object" + }, + "ProjectStatsBreakdown": { + "properties": { + "bounce_rate": { + "format": "double", + "type": "number" + }, + "engagement_rate": { + "format": "double", + "type": "number" + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "project_name": { + "type": [ + "string", + "null" + ] + }, + "total_page_views": { + "format": "int64", + "type": "integer" + }, + "total_visits": { + "format": "int64", + "type": "integer" + }, + "unique_visitors": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "project_id", + "unique_visitors", + "total_visits", + "total_page_views", + "bounce_rate", + "engagement_rate" + ], + "type": "object" + }, + "ProjectType": { + "description": "Project type enumeration", + "enum": [ + "static", + "docker", + "buildpack", + "git" + ], + "type": "string" + }, + "ProjectUsageInfoResponse": { + "properties": { + "connection_id": { + "format": "int32", + "type": "integer" + }, + "connection_name": { + "type": "string" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "name": { + "type": "string" + }, + "slug": { + "type": "string" + } + }, + "required": [ + "id", + "name", + "slug", + "connection_id", + "connection_name" + ], + "type": "object" + }, + "ProjectsHealthResponse": { + "description": "Batch health summary response", + "properties": { + "projects": { + "additionalProperties": { + "$ref": "#/components/schemas/ProjectHealthSummary" + }, + "description": "Health summaries keyed by project ID", + "propertyNames": { + "type": "string" + }, + "type": "object" + } + }, + "required": [ + "projects" + ], + "type": "object" + }, + "ProjectsMonitorHealthResponse": { + "description": "Batch response for projects health", + "properties": { + "projects": { + "additionalProperties": { + "$ref": "#/components/schemas/ProjectMonitorHealth" + }, + "propertyNames": { + "type": "string" + }, + "type": "object" + } + }, + "required": [ + "projects" + ], + "type": "object" + }, + "PromoteDeploymentRequest": { + "properties": { + "target_environment_id": { + "description": "Target environment ID to promote the deployment to", + "format": "int32", + "type": "integer" + } + }, + "required": [ + "target_environment_id" + ], + "type": "object" + }, + "PropertyBreakdownItem": { + "properties": { + "count": { + "format": "int64", + "type": "integer" + }, + "percentage": { + "format": "double", + "type": "number" + }, + "value": { + "type": "string" + } + }, + "required": [ + "value", + "count", + "percentage" + ], + "type": "object" + }, + "PropertyBreakdownQuery": { + "description": "Query parameters for property breakdown (group by column)", + "properties": { + "aggregation_level": { + "$ref": "#/components/schemas/AggregationLevel", + "description": "Aggregation level" + }, + "deployment_id": { + "description": "Optional deployment filter", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "end_date": { + "description": "End date for the query range", + "format": "date-time", + "type": "string" + }, + "environment_id": { + "description": "Optional environment filter", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "event_name": { + "description": "Optional event name filter (e.g., \"page_view\", \"click\")", + "type": [ + "string", + "null" + ] + }, + "filter_browser": { + "description": "Filter by browser name (for browser version drill-downs)", + "type": [ + "string", + "null" + ] + }, + "filter_channel": { + "description": "Filter by channel name (for channel -> referrer drill-downs)", + "type": [ + "string", + "null" + ] + }, + "filter_country": { + "description": "Filter by country (for region/city drill-downs). Requires geolocation join.", + "type": [ + "string", + "null" + ] + }, + "filter_os": { + "description": "Filter by operating system name (for OS version drill-downs)", + "type": [ + "string", + "null" + ] + }, + "filter_referrer": { + "description": "Filter by referrer hostname (for referrer -> pages drill-downs)", + "type": [ + "string", + "null" + ] + }, + "filter_region": { + "description": "Filter by region (for city drill-downs). Requires geolocation join.", + "type": [ + "string", + "null" + ] + }, + "group_by": { + "$ref": "#/components/schemas/PropertyColumn", + "description": "Property column to group by" + }, + "limit": { + "description": "Maximum number of results to return (default: 20, max: 100)", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "start_date": { + "description": "Start date for the query range", + "format": "date-time", + "type": "string" + } + }, + "required": [ + "start_date", + "end_date", + "group_by" + ], + "type": "object" + }, + "PropertyBreakdownResponse": { + "properties": { + "items": { + "items": { + "$ref": "#/components/schemas/PropertyBreakdownItem" + }, + "type": "array" + }, + "property": { + "type": "string" + }, + "total": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "property", + "items", + "total" + ], + "type": "object" + }, + "PropertyColumn": { + "enum": [ + "channel", + "device_type", + "browser", + "browser_version", + "operating_system", + "operating_system_version", + "utm_source", + "utm_medium", + "utm_campaign", + "utm_term", + "utm_content", + "referrer_hostname", + "language", + "event_type", + "event_name", + "page_path", + "pathname", + "country", + "region", + "city" + ], + "type": "string" + }, + "PropertyTimelineItem": { + "properties": { + "count": { + "format": "int64", + "type": "integer" + }, + "timestamp": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "timestamp", + "value", + "count" + ], + "type": "object" + }, + "PropertyTimelineQuery": { + "description": "Query parameters for property timeline (group by column over time)", + "properties": { + "aggregation_level": { + "$ref": "#/components/schemas/AggregationLevel", + "description": "Aggregation level" + }, + "bucket_size": { + "description": "Time bucket size: \"hour\", \"day\", \"week\", \"month\" (default: auto-detect)", + "type": [ + "string", + "null" + ] + }, + "deployment_id": { + "description": "Optional deployment filter", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "end_date": { + "description": "End date for the query range", + "format": "date-time", + "type": "string" + }, + "environment_id": { + "description": "Optional environment filter", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "event_name": { + "description": "Optional event name filter", + "type": [ + "string", + "null" + ] + }, + "group_by": { + "$ref": "#/components/schemas/PropertyColumn", + "description": "Property column to group by" + }, + "start_date": { + "description": "Start date for the query range", + "format": "date-time", + "type": "string" + } + }, + "required": [ + "start_date", + "end_date", + "group_by" + ], + "type": "object" + }, + "PropertyTimelineResponse": { + "properties": { + "bucket_size": { + "type": "string" + }, + "items": { + "items": { + "$ref": "#/components/schemas/PropertyTimelineItem" + }, + "type": "array" + }, + "property": { + "type": "string" + } + }, + "required": [ + "property", + "bucket_size", + "items" + ], + "type": "object" + }, + "Protocol": { + "description": "Network protocol", + "enum": [ + "tcp", + "udp" + ], + "type": "string" + }, + "ProviderCatalogDto": { + "description": "One catalog entry rendered for the settings UI.", + "properties": { + "auth_command": { + "type": "string" + }, + "auth_flavors": { + "items": { + "$ref": "#/components/schemas/AuthFlavorDto" + }, + "type": "array" + }, + "credential_saved": { + "description": "True when a credential is currently saved for this provider in the\nsettings JSON. Lets the UI render \"Configured\" badges without the\nfrontend having to inspect the encrypted blob.", + "type": "boolean" + }, + "current_auth_type": { + "description": "Currently saved auth flavor id (when `credential_saved` is true).\n`None` when no credential is saved yet.", + "type": [ + "string", + "null" + ] + }, + "default_model": { + "description": "Currently saved default model id for this provider, if one was\npicked. `None` means \"use the CLI's own default\" — the UI renders\nthat as \"Use provider default\".", + "type": [ + "string", + "null" + ] + }, + "id": { + "type": "string" + }, + "install_command": { + "type": "string" + }, + "max_turns_analysis": { + "description": "Default max turns for the autofixer analysis phase. `None` = built-in\ndefault (10). Only enforced for CLIs with a turn flag (Claude Code).", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "max_turns_feedback": { + "description": "Default max turns for autofixer feedback rounds. `None` = built-in\ndefault (10).", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "max_turns_fix": { + "description": "Default max turns for the autofixer fix phase. `None` = built-in\ndefault (20).", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "models": { + "description": "Model ids this provider accepts, in display order. The first entry is\nthe recommended default. Empty when the provider doesn't expose model\nselection (e.g. OpenCode), which the UI uses to hide the dropdown.", + "items": { + "type": "string" + }, + "type": "array" + }, + "name": { + "type": "string" + }, + "supports_max_turns": { + "description": "True when this provider's CLI supports enforcing a turn cap. False\nfor Codex/OpenCode, which run to completion — the UI labels their\nmax-turns inputs accordingly.", + "type": "boolean" + } + }, + "required": [ + "id", + "name", + "install_command", + "auth_command", + "auth_flavors", + "models", + "credential_saved", + "supports_max_turns" + ], + "type": "object" + }, + "ProviderCatalogResponse": { + "properties": { + "default_provider": { + "description": "Active provider id from `agent_sandbox.default_provider`. The settings\nUI uses this to highlight which card is the active one.", + "type": "string" + }, + "providers": { + "items": { + "$ref": "#/components/schemas/ProviderCatalogDto" + }, + "type": "array" + } + }, + "required": [ + "default_provider", + "providers" + ], + "type": "object" + }, + "ProviderConfig": { + "description": "Provider-specific integration settings persisted in\n`revenue_integrations.config`.\n\nThe tag is the lowercase provider name, so adding a new provider\nmeans adding a new variant and the existing rows are untouched.\nOld rows (pre-config) and rows with `NULL` config are treated as\n\"accept all events, no filtering\" via [`ProviderConfig::default_for`].", + "oneOf": [ + { + "allOf": [ + { + "$ref": "#/components/schemas/StripeConfig" + }, + { + "properties": { + "provider": { + "enum": [ + "stripe" + ], + "type": "string" + } + }, + "required": [ + "provider" + ], + "type": "object" + } + ] + }, + { + "allOf": [ + { + "$ref": "#/components/schemas/LemonSqueezyConfig" + }, + { + "properties": { + "provider": { + "enum": [ + "lemon_squeezy" + ], + "type": "string" + } + }, + "required": [ + "provider" + ], + "type": "object" + } + ] + } + ] + }, + "ProviderConfigMasked": { + "properties": { + "auth_type": { + "type": "string" + }, + "credential_saved": { + "description": "True if a credential is stored for this provider. The encrypted blob\nis never returned over HTTP.", + "type": "boolean" + }, + "default_model": { + "type": [ + "string", + "null" + ] + }, + "extra": {} + }, + "required": [ + "auth_type", + "credential_saved", + "extra" + ], + "type": "object" + }, + "ProviderDeletionCheckResponse": { + "properties": { + "can_delete": { + "type": "boolean" + }, + "message": { + "type": "string" + }, + "projects_in_use": { + "items": { + "$ref": "#/components/schemas/ProjectUsageInfoResponse" + }, + "type": "array" + } + }, + "required": [ + "can_delete", + "projects_in_use", + "message" + ], + "type": "object" + }, + "ProviderDescriptor": { + "properties": { + "display_name": { + "type": "string" + }, + "name": { + "type": "string" + }, + "recommended_events": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "name", + "display_name", + "recommended_events" + ], + "type": "object" + }, + "ProviderKeyResponse": { + "properties": { + "api_key_masked": { + "description": "Masked API key (only last 4 chars visible)", + "type": "string" + }, + "base_url": { + "type": [ + "string", + "null" + ] + }, + "created_at": { + "type": "string" + }, + "default_model": { + "description": "Model id this provider serves (NULL → per-provider default).", + "type": [ + "string", + "null" + ] + }, + "display_name": { + "type": "string" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "is_active": { + "type": "boolean" + }, + "provider": { + "type": "string" + }, + "updated_at": { + "type": "string" + } + }, + "required": [ + "id", + "provider", + "display_name", + "api_key_masked", + "is_active", + "created_at", + "updated_at" + ], + "type": "object" + }, + "ProviderMetadata": { + "properties": { + "color": { + "example": "#336791", + "type": "string" + }, + "description": { + "example": "Relational database management system", + "type": "string" + }, + "display_name": { + "example": "PostgreSQL", + "type": "string" + }, + "icon_url": { + "example": "https://cdn.simpleicons.org/postgresql", + "type": "string" + }, + "service_type": { + "$ref": "#/components/schemas/ServiceTypeRoute" + } + }, + "required": [ + "service_type", + "display_name", + "description", + "icon_url", + "color" + ], + "type": "object" + }, + "ProviderResponse": { + "properties": { + "auth_method": { + "type": "string" + }, + "base_url": { + "type": [ + "string", + "null" + ] + }, + "created_at": { + "format": "date-time", + "type": "string" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "is_active": { + "type": "boolean" + }, + "is_default": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "provider_type": { + "type": "string" + }, + "updated_at": { + "format": "date-time", + "type": "string" + } + }, + "required": [ + "id", + "name", + "provider_type", + "auth_method", + "is_active", + "is_default", + "created_at", + "updated_at" + ], + "type": "object" + }, + "ProviderUsage": { + "properties": { + "avg_latency_ms": { + "format": "double", + "type": "number" + }, + "error_count": { + "format": "int64", + "type": "integer" + }, + "input_tokens": { + "format": "int64", + "type": "integer" + }, + "output_tokens": { + "format": "int64", + "type": "integer" + }, + "provider": { + "type": "string" + }, + "request_count": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "provider", + "request_count", + "input_tokens", + "output_tokens", + "avg_latency_ms", + "error_count" + ], + "type": "object" + }, + "ProvisionResponse": { + "oneOf": [ + { + "allOf": [ + { + "$ref": "#/components/schemas/DomainError" + }, + { + "properties": { + "type": { + "enum": [ + "error" + ], + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + } + ] + }, + { + "allOf": [ + { + "$ref": "#/components/schemas/DomainResponse" + }, + { + "properties": { + "type": { + "enum": [ + "complete" + ], + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + } + ] + }, + { + "allOf": [ + { + "$ref": "#/components/schemas/DomainChallengeResponse" + }, + { + "properties": { + "type": { + "enum": [ + "pending" + ], + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + } + ] + } + ] + }, + "ProxyLogResponse": { + "description": "Response model for proxy logs", + "properties": { + "bot_name": { + "type": [ + "string", + "null" + ] + }, + "browser": { + "type": [ + "string", + "null" + ] + }, + "browser_version": { + "type": [ + "string", + "null" + ] + }, + "cache_status": { + "type": [ + "string", + "null" + ] + }, + "client_ip": { + "type": [ + "string", + "null" + ] + }, + "container_id": { + "type": [ + "string", + "null" + ] + }, + "deployment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "device_type": { + "type": [ + "string", + "null" + ] + }, + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "error_message": { + "type": [ + "string", + "null" + ] + }, + "host": { + "type": "string" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "ip_geolocation_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "is_bot": { + "type": [ + "boolean", + "null" + ] + }, + "is_system_request": { + "type": "boolean" + }, + "method": { + "type": "string" + }, + "operating_system": { + "type": [ + "string", + "null" + ] + }, + "path": { + "type": "string" + }, + "project_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "query_string": { + "type": [ + "string", + "null" + ] + }, + "referrer": { + "type": [ + "string", + "null" + ] + }, + "request_id": { + "type": "string" + }, + "request_size_bytes": { + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "request_source": { + "type": "string" + }, + "response_size_bytes": { + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "response_time_ms": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "routing_status": { + "type": "string" + }, + "session_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "status_code": { + "format": "int32", + "type": "integer" + }, + "timestamp": { + "type": "string" + }, + "upstream_host": { + "type": [ + "string", + "null" + ] + }, + "user_agent": { + "type": [ + "string", + "null" + ] + }, + "visitor_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + "required": [ + "id", + "timestamp", + "method", + "path", + "host", + "status_code", + "request_source", + "is_system_request", + "routing_status", + "request_id" + ], + "type": "object" + }, + "ProxyLogsPaginatedResponse": { + "description": "Paginated response for proxy logs", + "properties": { + "logs": { + "items": { + "$ref": "#/components/schemas/ProxyLogResponse" + }, + "type": "array" + }, + "page": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "page_size": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "total": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "total_pages": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "logs", + "total", + "page", + "page_size", + "total_pages" + ], + "type": "object" + }, + "PublicHostnameStrategy": { + "description": "Public hostname generation mode for Temps-managed preview routes.\n\nThe mode is stored per managed domain (`dns_managed_domains.generated_hostname_mode`)\nrather than globally, so a provider such as Cloudflare can offer the flat layout\nrequired by its Universal SSL wildcard cert without changing every domain's behaviour.", + "enum": [ + "standard", + "flat" + ], + "type": "string" + }, + "PublicPresetResponse": { + "description": "Response for preset detection", + "properties": { + "branch": { + "description": "Branch name where presets were detected", + "type": "string" + }, + "presets": { + "description": "List of detected presets", + "items": { + "$ref": "#/components/schemas/PresetInfo" + }, + "type": "array" + } + }, + "required": [ + "branch", + "presets" + ], + "type": "object" + }, + "PublicRepositoryInfo": { + "description": "Public repository information", + "properties": { + "default_branch": { + "description": "Default branch name", + "type": "string" + }, + "description": { + "description": "Repository description", + "type": [ + "string", + "null" + ] + }, + "forks": { + "description": "Fork count", + "format": "int32", + "type": "integer" + }, + "full_name": { + "description": "Full repository name (owner/repo)", + "type": "string" + }, + "language": { + "description": "Primary programming language", + "type": [ + "string", + "null" + ] + }, + "name": { + "description": "Repository name", + "type": "string" + }, + "owner": { + "description": "Repository owner", + "type": "string" + }, + "stars": { + "description": "Star count", + "format": "int32", + "type": "integer" + } + }, + "required": [ + "owner", + "name", + "full_name", + "default_branch", + "stars", + "forks" + ], + "type": "object" + }, + "PurgeLogsRequest": { + "properties": { + "before": { + "description": "Delete all logs before this timestamp (ISO 8601)", + "type": "string" + } + }, + "required": [ + "before" + ], + "type": "object" + }, + "PushImageRequest": { + "description": "Request to push an external image", + "properties": { + "image_ref": { + "type": "string" + }, + "metadata": {} + }, + "required": [ + "image_ref" + ], + "type": "object" + }, + "PushedExternalImageResponse": { + "description": "Response for in-memory external image operations (legacy push flow).\n\nRenamed to avoid shadowing the richer database-backed `ExternalImageResponse`\nin `handlers/remote_deployments.rs`. The two types serve different routes\n(`/images` ephemeral push vs `/external-images` registered images).", + "properties": { + "digest": { + "type": [ + "string", + "null" + ] + }, + "id": { + "type": "string" + }, + "image_ref": { + "type": "string" + }, + "pushed_at": { + "example": "2025-10-12T12:15:47.609192Z", + "format": "date-time", + "type": "string" + }, + "size": { + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + } + }, + "required": [ + "id", + "image_ref", + "pushed_at" + ], + "type": "object" + }, + "QueryDataRequest": { + "properties": { + "filters": { + "description": "JSON filters (backend-specific format)" + }, + "limit": { + "description": "Maximum number of rows to return", + "example": 100, + "minimum": 0, + "type": "integer" + }, + "offset": { + "description": "Number of rows to skip", + "example": 0, + "minimum": 0, + "type": "integer" + }, + "sort_by": { + "description": "Sort by field name", + "type": [ + "string", + "null" + ] + }, + "sort_order": { + "description": "Sort order (asc/desc)", + "type": [ + "string", + "null" + ] + } + }, + "type": "object" + }, + "QueryDataResponse": { + "properties": { + "execution_time_ms": { + "description": "Query execution time in milliseconds", + "example": 45, + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "fields": { + "description": "Field definitions", + "items": { + "$ref": "#/components/schemas/FieldResponse" + }, + "type": "array" + }, + "returned_count": { + "description": "Number of rows returned in this response", + "example": 100, + "minimum": 0, + "type": "integer" + }, + "rows": { + "description": "Data rows (array of JSON objects)", + "items": {}, + "type": "array" + }, + "total_count": { + "description": "Total number of rows matching the query (before limit/offset)", + "example": 1234, + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "truncated": { + "description": "Whether rows were dropped from this response to stay inside the byte budget.\n\n`returned_count` is always the number of rows actually present, so a truncated page is still internally consistent — but a caller comparing it against the requested limit would otherwise conclude the table simply ended. Reported explicitly so a partial page is never mistaken for a complete one, by a human, a script, or a model reading a tool result.", + "example": false, + "type": "boolean" + } + }, + "required": [ + "fields", + "rows", + "total_count", + "returned_count", + "execution_time_ms", + "truncated" + ], + "type": "object" + }, + "QuotaResponse": { + "properties": { + "quota": { + "$ref": "#/components/schemas/StorageQuota" + } + }, + "required": [ + "quota" + ], + "type": "object" + }, + "RateLimitConfig": { + "description": "Rate limiting configuration (subset of global RateLimitSettings)", + "properties": { + "blacklistIps": { + "description": "Blacklist specific IPs for this project/environment", + "items": { + "type": "string" + }, + "type": "array" + }, + "maxRequestsPerHour": { + "description": "Override rate limit per hour", + "format": "int32", + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "maxRequestsPerMinute": { + "description": "Override rate limit per minute", + "format": "int32", + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "whitelistIps": { + "description": "Whitelist specific IPs for this project/environment", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "RateLimitSettings": { + "properties": { + "blacklist_ips": { + "default": [], + "items": { + "type": "string" + }, + "type": "array" + }, + "enabled": { + "default": false, + "type": "boolean" + }, + "max_requests_per_hour": { + "default": 1000, + "format": "int32", + "minimum": 0, + "type": "integer" + }, + "max_requests_per_minute": { + "default": 60, + "format": "int32", + "minimum": 0, + "type": "integer" + }, + "whitelist_ips": { + "default": [], + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "ReachabilityStatus": { + "description": "Email reachability status", + "enum": [ + "safe", + "risky", + "invalid", + "unknown" + ], + "type": "string" + }, + "ReadFileResponse": { + "properties": { + "contents_b64": { + "description": "File contents, base64-encoded. Symmetric with `WriteFileBody`.", + "type": "string" + }, + "path": { + "type": "string" + }, + "size": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "path", + "contents_b64", + "size" + ], + "type": "object" + }, + "ReadRowsQuery": { + "description": "Query-string form of [`QueryDataRequest`] for the read-only `GET` rows\nendpoint.\n\nThe `POST` variant exists because filters are arbitrary backend-specific\nJSON. Reading rows is nonetheless a *read*, and the AI agent's tool index\nis GET-only by construction, so the same capability has to be reachable\nwithout a body. `filter` therefore carries the JSON as a string.", + "properties": { + "filter": { + "description": "Backend-specific filter, JSON-encoded. Fetch the expected shape from\nthe `filter_schema` field of the explorer-support endpoint — e.g.\n`{\"where\":\"created_at > now() - interval '7 days'\"}` for SQL sources.", + "type": [ + "string", + "null" + ] + }, + "limit": { + "description": "Maximum number of rows to return", + "example": 100, + "minimum": 0, + "type": "integer" + }, + "offset": { + "description": "Number of rows to skip", + "example": 0, + "minimum": 0, + "type": "integer" + }, + "sort_by": { + "description": "Sort by field name", + "type": [ + "string", + "null" + ] + }, + "sort_order": { + "description": "Sort order (asc/desc)", + "type": [ + "string", + "null" + ] + } + }, + "type": "object" + }, + "RecentActivityQuery": { + "description": "Query parameters for recent activity endpoint", + "properties": { + "environment_id": { + "description": "Environment ID (optional)", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "limit": { + "description": "Max number of events to return (default: 50, max: 100)", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "project_id": { + "description": "Project ID", + "format": "int32", + "type": "integer" + }, + "since_id": { + "description": "Return events with ID greater than this (for cursor-based polling)", + "format": "int64", + "type": [ + "integer", + "null" + ] + } + }, + "required": [ + "project_id" + ], + "type": "object" + }, + "RecentActivityResponse": { + "description": "Response for recent activity events endpoint", + "properties": { + "count": { + "description": "Total events returned", + "minimum": 0, + "type": "integer" + }, + "events": { + "description": "Recent events, newest first", + "items": { + "$ref": "#/components/schemas/ActivityEvent" + }, + "type": "array" + } + }, + "required": [ + "events", + "count" + ], + "type": "object" + }, + "RecentEventResponse": { + "properties": { + "amount_minor": { + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "currency": { + "type": [ + "string", + "null" + ] + }, + "customer_ref": { + "type": [ + "string", + "null" + ] + }, + "event_type": { + "type": "string" + }, + "mrr_minor": { + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "occurred_at": { + "format": "date-time", + "type": "string" + } + }, + "required": [ + "occurred_at", + "event_type" + ], + "type": "object" + }, + "RecentQueryParams": { + "properties": { + "conversation_id": { + "description": "Filter by conversation ID", + "type": [ + "string", + "null" + ] + }, + "cost_gt": { + "description": "Cost strictly greater-than, in microcents", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "cost_gte": { + "description": "Cost greater-than-or-equal, in microcents", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "cost_lt": { + "description": "Cost strictly less-than, in microcents", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "cost_lte": { + "description": "Cost less-than-or-equal, in microcents", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "limit": { + "description": "Page size (defaults to 20, max 50)", + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "model": { + "description": "Filter by model name", + "type": [ + "string", + "null" + ] + }, + "offset": { + "description": "Number of results to skip for pagination (defaults to 0)", + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "provider": { + "description": "Filter by provider name", + "type": [ + "string", + "null" + ] + }, + "status": { + "description": "Filter by HTTP status code (exact match)", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "tags": { + "description": "Filter by tags (comma-separated, AND logic)", + "type": [ + "string", + "null" + ] + }, + "tokens_gt": { + "description": "Total tokens (input + output) strictly greater-than", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "tokens_gte": { + "description": "Total tokens (input + output) greater-than-or-equal", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "tokens_lt": { + "description": "Total tokens (input + output) strictly less-than", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "tokens_lte": { + "description": "Total tokens (input + output) less-than-or-equal", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "user_id": { + "description": "Filter by user ID", + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + "type": "object" + }, + "RecordExposureRequest": { + "description": "Keys a running app actually evaluated since its last report.", + "properties": { + "keys": { + "description": "Flag keys evaluated since the last report. Unknown keys are ignored.", + "example": [ + "checkout.v2", + "api.rate_limit" + ], + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "keys" + ], + "type": "object" + }, + "RecordExposureResponse": { + "properties": { + "recorded": { + "description": "How many keys were accepted for processing.\n\nDeliberately not the number of rows updated: echoing that back would\nlet a caller post a single candidate key and read the result as \"this\nflag exists\", turning the endpoint into an existence oracle.", + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "recorded" + ], + "type": "object" + }, + "RecordListResponse": { + "description": "Record list response", + "properties": { + "records": { + "items": { + "$ref": "#/components/schemas/DnsRecord" + }, + "type": "array" + } + }, + "required": [ + "records" + ], + "type": "object" + }, + "RecoveryTarget": { + "description": "Engine-specific recovery target for PITR.\n\nPostgres honors all variants; Redis/Mongo/S3 will likely reject non-Time\nvariants or define their own semantics when they grow PITR support.", + "oneOf": [ + { + "description": "Recover to a specific timestamp.", + "properties": { + "kind": { + "enum": [ + "time" + ], + "type": "string" + }, + "time": { + "format": "date-time", + "type": "string" + } + }, + "required": [ + "time", + "kind" + ], + "type": "object" + }, + { + "description": "Recover to a specific transaction id (Postgres).", + "properties": { + "kind": { + "enum": [ + "xid" + ], + "type": "string" + }, + "xid": { + "type": "string" + } + }, + "required": [ + "xid", + "kind" + ], + "type": "object" + }, + { + "description": "Recover to a specific log sequence number (Postgres).", + "properties": { + "kind": { + "enum": [ + "lsn" + ], + "type": "string" + }, + "lsn": { + "type": "string" + } + }, + "required": [ + "lsn", + "kind" + ], + "type": "object" + }, + { + "description": "Recover to a named restore point created via `pg_create_restore_point` (Postgres).", + "properties": { + "kind": { + "enum": [ + "name" + ], + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "name", + "kind" + ], + "type": "object" + } + ] + }, + "ReferrerCount": { + "properties": { + "count": { + "format": "int64", + "type": "integer" + }, + "percentage": { + "format": "double", + "type": "number" + }, + "referrer": { + "type": "string" + } + }, + "required": [ + "referrer", + "count", + "percentage" + ], + "type": "object" + }, + "ReferrersAnalyticsQuery": { + "properties": { + "end_date": { + "format": "date-time", + "type": "string" + }, + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "start_date": { + "format": "date-time", + "type": "string" + } + }, + "required": [ + "start_date", + "end_date", + "project_id" + ], + "type": "object" + }, + "RegenerateDSNRequest": { + "properties": { + "base_url": { + "type": [ + "string", + "null" + ] + } + }, + "type": "object" + }, + "RegisterImageRequest": { + "properties": { + "digest": { + "description": "Image digest (sha256:...)", + "example": "sha256:abc123def456", + "type": [ + "string", + "null" + ] + }, + "image_ref": { + "description": "Docker image reference (e.g., \"ghcr.io/org/app:v1.0\")", + "example": "ghcr.io/myorg/myapp:v1.0", + "type": "string" + }, + "metadata": { + "description": "Additional metadata" + }, + "tag": { + "description": "Image tag", + "example": "v1.0", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "image_ref" + ], + "type": "object" + }, + "RegisterNodeApiRequest": { + "properties": { + "address": { + "description": "Node's reachable address (e.g., \"10.100.0.2\" or \"192.168.1.50\")", + "type": "string" + }, + "architecture": { + "description": "Container platform of this node's Docker daemon (`linux/amd64`,\n`linux/arm64`). Optional: agents older than multi-arch support omit it\nand the value is learned from the first heartbeat instead.", + "type": [ + "string", + "null" + ] + }, + "csr_pem": { + "description": "Node-generated certificate signing request (PEM) for multi-node mTLS\n(ADR-020 WS-2.1). When present, the control plane signs it with the\ncluster CA and returns the leaf + CA cert. Optional — token-only nodes\n(legacy / edge) still register without one.", + "type": [ + "string", + "null" + ] + }, + "edge_public_key": { + "description": "X25519 public key for ECIES certificate encryption (base64-encoded, edge nodes only)", + "type": [ + "string", + "null" + ] + }, + "join_token": { + "description": "Join token to authorize this registration (must match the token generated in Settings)", + "type": [ + "string", + "null" + ] + }, + "labels": { + "description": "Labels for scheduling (e.g., {\"region\": \"us-east\", \"gpu\": \"true\"})" + }, + "name": { + "description": "Unique name for this node", + "type": "string" + }, + "prior_token": { + "description": "The node's *current* token, supplied to prove possession when\nre-registering (changing the identity of) a node that already exists.\nOptional; only needed to rebind a still-live node. (ADR-020 WS-1.2.)", + "type": [ + "string", + "null" + ] + }, + "private_address": { + "description": "Private/WireGuard address for inter-node communication", + "type": "string" + }, + "public_endpoint": { + "description": "Public endpoint for WireGuard (e.g., \"203.0.113.1:51820\")", + "type": [ + "string", + "null" + ] + }, + "role": { + "description": "Node role (default: \"worker\")", + "type": [ + "string", + "null" + ] + }, + "token": { + "description": "Registration token (plaintext, will be hashed before storage)", + "type": "string" + }, + "wg_public_key": { + "description": "WireGuard public key", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "name", + "token", + "address", + "private_address" + ], + "type": "object" + }, + "RegisterNodeResponse": { + "properties": { + "ca_cert_pem": { + "description": "The cluster CA certificate (PEM) the node pins as its trust root.\nPresent only when a `csr_pem` was supplied. (ADR-020 WS-2.1.)", + "type": [ + "string", + "null" + ] + }, + "cert_pem": { + "description": "The signed per-node leaf certificate (PEM) the agent serves as its TLS\nserver cert. Present only when a `csr_pem` was supplied. (ADR-020 WS-2.1.)", + "type": [ + "string", + "null" + ] + }, + "id": { + "format": "int32", + "type": "integer" + }, + "message": { + "type": "string" + }, + "name": { + "type": "string" + }, + "status": { + "type": "string" + } + }, + "required": [ + "id", + "name", + "status", + "message" + ], + "type": "object" + }, + "RegisterRequest": { + "properties": { + "email": { + "type": "string" + }, + "name": { + "type": "string" + }, + "password": { + "type": "string" + } + }, + "required": [ + "email", + "password", + "name" + ], + "type": "object" + }, + "ReinstallWebhookResponse": { + "description": "Response for `POST /projects/{project_id}/gitlab/reinstall-webhook`", + "properties": { + "hook_id": { + "description": "The new GitLab hook ID that was installed.", + "format": "int32", + "type": "integer" + }, + "message": { + "description": "Human-readable status message.", + "type": "string" + } + }, + "required": [ + "hook_id", + "message" + ], + "type": "object" + }, + "ReleaseListResponse": { + "properties": { + "releases": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "releases" + ], + "type": "object" + }, + "ReloadResponse": { + "description": "Response from the reload endpoint.", + "properties": { + "loaded": { + "description": "Number of plugins successfully loaded after reload", + "minimum": 0, + "type": "integer" + }, + "message": { + "description": "Human-readable status message", + "type": "string" + }, + "plugins": { + "description": "Names of loaded plugins", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "loaded", + "plugins", + "message" + ], + "type": "object" + }, + "RemoteDeploymentResponse": { + "properties": { + "created_at": { + "example": "2025-10-12T12:15:47.609192Z", + "format": "date-time", + "type": "string" + }, + "environment_id": { + "format": "int32", + "type": "integer" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "slug": { + "type": "string" + }, + "source_type": { + "type": "string" + }, + "state": { + "type": "string" + } + }, + "required": [ + "id", + "project_id", + "environment_id", + "slug", + "state", + "source_type", + "created_at" + ], + "type": "object" + }, + "RemoveNodeResponse": { + "properties": { + "id": { + "format": "int32", + "type": "integer" + }, + "message": { + "type": "string" + } + }, + "required": [ + "id", + "message" + ], + "type": "object" + }, + "RenameConversationRequest": { + "properties": { + "title": { + "description": "New human-facing title. Trimmed; must be non-empty after trimming.", + "type": "string" + } + }, + "required": [ + "title" + ], + "type": "object" + }, + "RepositoryListQuery": { + "properties": { + "direction": { + "type": [ + "string", + "null" + ] + }, + "language": { + "type": [ + "string", + "null" + ] + }, + "owner": { + "type": [ + "string", + "null" + ] + }, + "page": { + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "per_page": { + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "private": { + "type": [ + "boolean", + "null" + ] + }, + "search": { + "type": [ + "string", + "null" + ] + }, + "sort": { + "type": [ + "string", + "null" + ] + } + }, + "type": "object" + }, + "RepositoryListResponse": { + "properties": { + "repositories": { + "items": { + "$ref": "#/components/schemas/RepositoryResponse" + }, + "type": "array" + }, + "total_count": { + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "repositories", + "total_count" + ], + "type": "object" + }, + "RepositoryPresetResponse": { + "properties": { + "calculated_at": { + "format": "date-time", + "type": "string" + }, + "name": { + "type": "string" + }, + "owner": { + "type": "string" + }, + "presets": { + "items": { + "$ref": "#/components/schemas/ProjectPresetResponse" + }, + "type": "array" + }, + "repository_id": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "repository_id", + "owner", + "name", + "presets", + "calculated_at" + ], + "type": "object" + }, + "RepositoryResponse": { + "properties": { + "clone_url": { + "description": "HTTPS clone URL (e.g., https://github.com/owner/repo.git)", + "type": [ + "string", + "null" + ] + }, + "created_at": { + "format": "date-time", + "type": "string" + }, + "default_branch": { + "type": "string" + }, + "description": { + "type": [ + "string", + "null" + ] + }, + "full_name": { + "type": "string" + }, + "git_provider_connection_id": { + "description": "ID of the git provider connection this repository was synced from.", + "format": "int32", + "type": "integer" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "language": { + "type": [ + "string", + "null" + ] + }, + "name": { + "type": "string" + }, + "owner": { + "type": "string" + }, + "preset": { + "items": { + "$ref": "#/components/schemas/ProjectPresetResponse" + }, + "type": [ + "array", + "null" + ] + }, + "private": { + "type": "boolean" + }, + "pushed_at": { + "format": "date-time", + "type": "string" + }, + "ssh_url": { + "description": "SSH clone URL (e.g., git@github.com:owner/repo.git)", + "type": [ + "string", + "null" + ] + }, + "updated_at": { + "format": "date-time", + "type": "string" + } + }, + "required": [ + "id", + "owner", + "name", + "full_name", + "private", + "default_branch", + "created_at", + "updated_at", + "pushed_at", + "git_provider_connection_id" + ], + "type": "object" + }, + "RepositorySyncStartedResponse": { + "description": "Returned by `POST /git-connections/{id}/sync` to acknowledge that a\nsync has been kicked off in the background. Clients should poll the\nconnection's `syncing` and `synced_repository_count` fields to track\nprogress rather than waiting on this response.", + "properties": { + "connection_id": { + "format": "int32", + "type": "integer" + }, + "started_at": { + "format": "date-time", + "type": "string" + }, + "syncing": { + "type": "boolean" + } + }, + "required": [ + "connection_id", + "syncing", + "started_at" + ], + "type": "object" + }, + "RequestRow": { + "properties": { + "client_ip": { + "type": [ + "string", + "null" + ] + }, + "country": { + "type": [ + "string", + "null" + ] + }, + "deployment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "error_group_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "headers_truncated": { + "type": "boolean" + }, + "host": { + "type": "string" + }, + "id": { + "description": "The request's unique `request_id` (assigned by the proxy). Used as the\nrow identity instead of the storage PK because the ClickHouse backend\nhas no serial id (rows come back with `id = 0`) while `request_id` is\nunique and present on both backends.", + "type": "string" + }, + "latency_ms": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "method": { + "type": "string" + }, + "path": { + "type": "string" + }, + "query_string": { + "type": [ + "string", + "null" + ] + }, + "referrer": { + "type": [ + "string", + "null" + ] + }, + "request_headers": {}, + "response_headers": {}, + "status": { + "format": "int32", + "type": "integer" + }, + "trace_id": { + "type": [ + "string", + "null" + ] + }, + "ts": { + "format": "date-time", + "type": "string" + }, + "user_agent": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "id", + "ts", + "method", + "host", + "path", + "status", + "request_headers", + "response_headers", + "headers_truncated" + ], + "type": "object" + }, + "ResetPasswordRequest": { + "properties": { + "new_password": { + "type": "string" + }, + "token": { + "type": "string" + } + }, + "required": [ + "token", + "new_password" + ], + "type": "object" + }, + "ResetPgStatStatementsRequest": { + "description": "Explicit confirmation required for the destructive statistics reset.\n\nRequiring JSON makes the endpoint non-simple for browsers, preventing a\ndeployed same-site application from triggering it with a plain HTML form.", + "properties": { + "confirm": { + "description": "Must be `true` to acknowledge the global, irreversible reset.", + "type": "boolean" + } + }, + "required": [ + "confirm" + ], + "type": "object" + }, + "ResetPgStatStatementsResponse": { + "description": "Response for the pg_stat_statements reset endpoint.", + "properties": { + "message": { + "description": "Human-readable message confirming the destructive action.", + "type": "string" + } + }, + "required": [ + "message" + ], + "type": "object" + }, + "ResizeSandboxBody": { + "additionalProperties": false, + "properties": { + "disk_size_mb": { + "description": "New root disk size in MB. Grow-only; must exceed the current size.", + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "disk_size_mb" + ], + "type": "object" + }, + "ResolvedEnvVarResponse": { + "description": "One entry in the computed env-var view that merges manual and integration\nsources and tags each result with its origin. `value_preview` is always\nmasked — plaintext must be fetched per-key via the existing reveal endpoint,\nwhich is audit-logged.", + "properties": { + "environments": { + "description": "Environments this var applies to. For integration-sourced vars this\nreflects every environment of the project (integrations are global).", + "items": { + "$ref": "#/components/schemas/EnvironmentInfo" + }, + "type": "array" + }, + "include_in_preview": { + "description": "Whether the var would be auto-applied to preview environments.\nIntegration vars always surface in preview; manual vars follow the flag.", + "type": "boolean" + }, + "key": { + "type": "string" + }, + "source": { + "$ref": "#/components/schemas/ResolvedEnvVarSource" + }, + "value_preview": { + "description": "Masked or truncated preview. Never the raw value.", + "type": "string" + } + }, + "required": [ + "key", + "value_preview", + "source", + "environments", + "include_in_preview" + ], + "type": "object" + }, + "ResolvedEnvVarSource": { + "description": "Where a resolved env var comes from. Integration-sourced vars may be\n\"shadowed\" by a manual entry with the same key, in which case the response\ncarries `Manual` with `overrides_service` populated so the UI can still show\nthe integration icon.", + "oneOf": [ + { + "description": "Manually-defined env var. If `overrides_service` is set, this key would\notherwise have been supplied by an integration — the UI should show the\nintegration icon plus an \"overridden\" indicator.", + "properties": { + "overrides_service": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/EnvVarIntegrationInfo" + } + ] + }, + "type": { + "enum": [ + "manual" + ], + "type": "string" + }, + "var_id": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "var_id", + "type" + ], + "type": "object" + }, + { + "description": "Supplied by a linked external service (Postgres, Redis, S3, etc.).", + "properties": { + "service": { + "$ref": "#/components/schemas/EnvVarIntegrationInfo" + }, + "type": { + "enum": [ + "integration" + ], + "type": "string" + } + }, + "required": [ + "service", + "type" + ], + "type": "object" + } + ] + }, + "ResourceCounts": { + "description": "Quick count of resources involved in the migration", + "properties": { + "deployments": { + "minimum": 0, + "type": "integer" + }, + "domains": { + "minimum": 0, + "type": "integer" + }, + "environment_variables": { + "minimum": 0, + "type": "integer" + }, + "environments": { + "minimum": 0, + "type": "integer" + }, + "projects": { + "minimum": 0, + "type": "integer" + }, + "services": { + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "projects", + "environments", + "deployments", + "environment_variables", + "services", + "domains" + ], + "type": "object" + }, + "ResourceFootprint": { + "description": "A CPU + memory footprint (requests or measured usage)", + "properties": { + "cpu_millis": { + "description": "CPU in millicores", + "format": "int64", + "type": "integer" + }, + "memory_mb": { + "description": "Memory in MB", + "format": "int64", + "type": "integer" + } + }, + "required": [ + "cpu_millis", + "memory_mb" + ], + "type": "object" + }, + "ResourceInfo": { + "description": "Resource attributes extracted from OTel resource descriptors.", + "properties": { + "attributes": { + "type": "object" + }, + "deployment_environment": { + "type": [ + "string", + "null" + ] + }, + "service_name": { + "type": "string" + }, + "service_version": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "service_name", + "attributes" + ], + "type": "object" + }, + "ResourceLimitApplyResult": { + "description": "Per-container outcome of a live `docker update` call. Surfaced from the\nPATCH /resources endpoint so the UI can tell the operator whether the\nnew caps are already in effect or whether they only apply on next\nrecreate (e.g., container was missing).", + "properties": { + "container_name": { + "type": "string" + }, + "error": { + "description": "Populated only when `outcome == \"failed\"`.", + "type": [ + "string", + "null" + ] + }, + "outcome": { + "description": "One of:\n- \"applied\" — Docker accepted the update; caps are live now.\n- \"missing\" — container does not exist; caps stored, will apply on next start.\n- \"stopped\" — container exists but isn't running; Docker still\n accepts the update (the new caps apply on next start).\n- \"failed\" — `docker update` returned an error (see `error`).", + "type": "string" + }, + "role": { + "description": "`service_members.role` for cluster members; \"standalone\" otherwise.", + "type": "string" + } + }, + "required": [ + "role", + "container_name", + "outcome" + ], + "type": "object" + }, + "ResourceLimits": { + "description": "Resource limits and requests", + "properties": { + "cpu_limit": { + "description": "CPU limit (millicores)", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "cpu_request": { + "description": "CPU request (millicores)", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "memory_limit": { + "description": "Memory limit (MB)", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "memory_request": { + "description": "Memory request (MB)", + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + "type": "object" + }, + "ResourceLimitsResponse": { + "description": "Container resource limits", + "properties": { + "cpu_limit": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "cpu_request": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "memory_limit": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "memory_request": { + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + "type": "object" + }, + "ResourceLimitsUpdateResponse": { + "description": "Response from PATCH /external-services/{id}/resources.", + "properties": { + "applied": { + "description": "Per-container result of trying to apply the limits live.", + "items": { + "$ref": "#/components/schemas/ResourceLimitApplyResult" + }, + "type": "array" + }, + "limits": { + "$ref": "#/components/schemas/ServiceResourceLimits", + "description": "The limits that were persisted to the encrypted config." + } + }, + "required": [ + "limits", + "applied" + ], + "type": "object" + }, + "ResourcesBody": { + "description": "Nested `resources: { memory, vcpus }` as sent by `@vercel/sandbox`.\n`memory` is in MB, `vcpus` is fractional CPU count.", + "properties": { + "memory": { + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "vcpus": { + "format": "double", + "type": [ + "number", + "null" + ] + } + }, + "type": "object" + }, + "RestoreCapabilities": { + "description": "Capabilities a service exposes for the generic restore framework.\n\nEach engine overrides `ExternalService::restore_capabilities` to declare\nwhat it supports. The handler layer uses this to validate requests and\nthe UI uses it to conditionally show options (e.g., PITR picker).", + "properties": { + "earliest_pitr_time": { + "description": "Earliest recoverable timestamp, if `pitr` is true. Derived from\nengine-specific archive metadata (e.g., `pg_stat_archiver`).", + "format": "date-time", + "type": [ + "string", + "null" + ] + }, + "latest_pitr_time": { + "description": "Latest recoverable timestamp, if `pitr` is true.", + "format": "date-time", + "type": [ + "string", + "null" + ] + }, + "pitr": { + "description": "Point-in-time recovery using engine-specific continuous archives\n(WAL for Postgres, AOF for Redis, oplog for MongoDB, object versions for S3).", + "type": "boolean" + }, + "restore_in_place": { + "description": "Restore a backup onto the same running service (destructive).", + "type": "boolean" + }, + "restore_to_new_service": { + "description": "Restore a backup into a freshly provisioned service.", + "type": "boolean" + } + }, + "required": [ + "restore_in_place", + "restore_to_new_service", + "pitr" + ], + "type": "object" + }, + "RestoreCapabilitiesResponse": { + "allOf": [ + { + "$ref": "#/components/schemas/RestoreCapabilities", + "description": "Trait-declared capabilities." + }, + { + "properties": { + "suggested_new_service_name": { + "description": "Suggested name for the new service when creating a clone. Safe to\npre-fill into the UI dialog; the user can edit before submitting.", + "type": "string" + } + }, + "required": [ + "suggested_new_service_name" + ], + "type": "object" + } + ] + }, + "RestorePlan": { + "description": "Preview of a restore operation. Answers \"what will happen if I click\nstart?\" with engine-level specificity so the user can confirm before\ncommitting to a destructive action.", + "properties": { + "destructive": { + "description": "Whether any step overwrites existing data on the target service.", + "type": "boolean" + }, + "engine": { + "description": "Target engine (\"postgres\", etc.).", + "type": "string" + }, + "errors": { + "description": "Blocking problems. The UI disables the Start button when non-empty.", + "items": { + "type": "string" + }, + "type": "array" + }, + "mode": { + "description": "Echo of the requested mode for the UI.", + "type": "string" + }, + "source_backup": { + "$ref": "#/components/schemas/PlanSourceBackup", + "description": "Backup we'll read from." + }, + "steps": { + "description": "Ordered list of human-readable actions the orchestrator will take.", + "items": { + "type": "string" + }, + "type": "array" + }, + "strategy": { + "description": "How the restore will be performed: \"walg_restore\", \"pg_dump_restore\",\nor \"unsupported\".", + "type": "string" + }, + "target_service": { + "$ref": "#/components/schemas/PlanTarget", + "description": "Service we'll operate on (or provision a sibling of)." + }, + "warnings": { + "description": "Non-blocking caveats the user should see (cross-service, empty\nlocation that will be auto-resolved, missing engine metadata, ...).", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "engine", + "target_service", + "source_backup", + "strategy", + "steps", + "warnings", + "errors", + "destructive", + "mode" + ], + "type": "object" + }, + "RestoreRequestMode": { + "description": "What the caller wants to do. Mirrors `externalsvc::RestoreMode` but\nflattened for JSON over the wire.", + "oneOf": [ + { + "description": "Restore the backup onto the existing service (destructive).", + "properties": { + "mode": { + "enum": [ + "in_place" + ], + "type": "string" + } + }, + "required": [ + "mode" + ], + "type": "object" + }, + { + "description": "Provision a new service and restore into it.", + "properties": { + "mode": { + "enum": [ + "new_service" + ], + "type": "string" + }, + "name": { + "description": "Name for the new service. Orchestrator auto-suggests\n`{source}-restore-{yyyymmdd-hhmm}` if caller omits, but we require\nan explicit value at the API boundary.", + "type": "string" + }, + "parameter_overrides": { + "description": "Optional parameter overrides (port, docker_image, database)." + } + }, + "required": [ + "name", + "mode" + ], + "type": "object" + }, + { + "description": "Point-in-time recovery. Only valid on WAL-G backups (Postgres).", + "properties": { + "mode": { + "enum": [ + "pitr" + ], + "type": "string" + }, + "new_service_name": { + "description": "Required when `to_new_service` is true.", + "type": [ + "string", + "null" + ] + }, + "target": { + "$ref": "#/components/schemas/RecoveryTarget", + "description": "Recovery target kind + value." + }, + "to_new_service": { + "description": "Whether PITR restores in place or creates a new service.", + "type": "boolean" + } + }, + "required": [ + "to_new_service", + "target", + "mode" + ], + "type": "object" + } + ] + }, + "RestoreRunView": { + "properties": { + "created_at": { + "type": "string" + }, + "error_message": { + "type": [ + "string", + "null" + ] + }, + "finished_at": { + "type": [ + "string", + "null" + ] + }, + "id": { + "format": "int32", + "type": "integer" + }, + "mode": { + "type": "string" + }, + "phase": { + "type": "string" + }, + "recovery_target": {}, + "source_backup_id": { + "format": "int32", + "type": "integer" + }, + "source_service_id": { + "format": "int32", + "type": "integer" + }, + "started_at": { + "type": [ + "string", + "null" + ] + }, + "status": { + "type": "string" + }, + "target_service_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "target_service_name": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "id", + "source_backup_id", + "source_service_id", + "mode", + "status", + "phase", + "created_at" + ], + "type": "object" + }, + "RetentionCleanupFailure": { + "properties": { + "backup_id": { + "type": "string" + }, + "deleted_objects": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "partial": { + "type": "boolean" + }, + "reason": { + "type": "string" + } + }, + "required": [ + "backup_id", + "reason", + "partial", + "deleted_objects" + ], + "type": "object" + }, + "RetentionCleanupReport": { + "properties": { + "candidate_backup_ids": { + "description": "Capped sample of backups selected by the retention policy.", + "items": { + "type": "string" + }, + "type": "array" + }, + "candidate_backup_ids_truncated": { + "type": "boolean" + }, + "deleted": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "deleted_backup_ids": { + "description": "Capped sample of deleted backup UUIDs for audit attribution.", + "items": { + "type": "string" + }, + "type": "array" + }, + "deleted_backup_ids_truncated": { + "type": "boolean" + }, + "dry_run": { + "description": "True when this report is a non-destructive preview.", + "type": "boolean" + }, + "expired": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "failed": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "failures": { + "description": "Capped diagnostic sample; `failed` remains the authoritative total.", + "items": { + "$ref": "#/components/schemas/RetentionCleanupFailure" + }, + "type": "array" + }, + "partially_deleted_backup_ids": { + "items": { + "type": "string" + }, + "type": "array" + }, + "partially_deleted_backup_ids_truncated": { + "type": "boolean" + }, + "schedule_id": { + "description": "Schedule scope, or `None` when every schedule was considered.", + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + "required": [ + "dry_run", + "expired", + "deleted", + "failed", + "failures", + "deleted_backup_ids", + "deleted_backup_ids_truncated", + "partially_deleted_backup_ids", + "partially_deleted_backup_ids_truncated", + "candidate_backup_ids", + "candidate_backup_ids_truncated" + ], + "type": "object" + }, + "RetryClusterRequest": { + "description": "Request body for retrying a failed cluster initialization.", + "properties": { + "members": { + "description": "Cluster member specifications (same format as create).\nIf omitted, the original member configuration is reconstructed from\nthe preserved service_members records.", + "items": { + "$ref": "#/components/schemas/ClusterMemberRequest" + }, + "type": "array" + } + }, + "type": "object" + }, + "RevenueRow": { + "properties": { + "amount_minor": { + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "currency": { + "type": [ + "string", + "null" + ] + }, + "customer_ref": { + "type": [ + "string", + "null" + ] + }, + "deployment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "event_type": { + "type": "string" + }, + "id": { + "format": "int64", + "type": "integer" + }, + "provider": { + "type": "string" + }, + "trace_id": { + "type": [ + "string", + "null" + ] + }, + "ts": { + "format": "date-time", + "type": "string" + } + }, + "required": [ + "id", + "ts", + "provider", + "event_type" + ], + "type": "object" + }, + "RiskLevel": { + "description": "Risk level for a migration step", + "enum": [ + "none", + "low", + "medium", + "high", + "critical" + ], + "type": "string" + }, + "RoleInfo": { + "description": "Information about a role", + "properties": { + "description": { + "description": "Human-readable description of the role", + "type": "string" + }, + "name": { + "description": "The role identifier (e.g., \"admin\")", + "type": "string" + }, + "permissions": { + "description": "Permissions included in this role", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "name", + "description", + "permissions" + ], + "type": "object" + }, + "RootfsCacheEntry": { + "description": "A cached rootfs image (Firecracker backend). Digest-keyed build artifact\nshared by all VMs created from the same image.", + "properties": { + "bytes": { + "description": "Actual on-disk size in bytes (sparse-aware).", + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "digest": { + "description": "Image digest this rootfs was built from (the cache key).", + "type": "string" + }, + "referenced_by": { + "description": "IDs of live sandboxes whose per-VM disk was cloned from this entry.\nEmpty means the entry is reclaimable — no sandbox needs it.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "digest", + "bytes", + "referenced_by" + ], + "type": "object" + }, + "RootfsGcReport": { + "description": "Outcome of a rootfs garbage-collection pass.", + "properties": { + "freed_bytes": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "removed_digests": { + "description": "Digests of cache entries removed because no sandbox referenced them.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "removed_digests", + "freed_bytes" + ], + "type": "object" + }, + "RootfsReport": { + "description": "Snapshot of a backend's rootfs storage for the management API. Backends\nwithout a rootfs concept (Docker, local) return an empty report.", + "properties": { + "cache": { + "items": { + "$ref": "#/components/schemas/RootfsCacheEntry" + }, + "type": "array" + }, + "cache_bytes": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "vm_bytes": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "vms": { + "items": { + "$ref": "#/components/schemas/RootfsVmEntry" + }, + "type": "array" + } + }, + "required": [ + "cache_bytes", + "cache", + "vm_bytes", + "vms" + ], + "type": "object" + }, + "RootfsVmEntry": { + "description": "A per-sandbox rootfs disk (Firecracker backend). One per non-destroyed\nsandbox — the authoritative storage, independent of the cache.", + "properties": { + "bytes": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "running": { + "type": "boolean" + }, + "sandbox_name": { + "type": "string" + } + }, + "required": [ + "sandbox_name", + "bytes", + "running" + ], + "type": "object" + }, + "RouteRefreshResponse": { + "properties": { + "message": { + "description": "Human-readable message", + "type": "string" + }, + "route_count": { + "description": "Number of routes loaded", + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "route_count", + "message" + ], + "type": "object" + }, + "RouteResponse": { + "properties": { + "created_at": { + "format": "int64", + "type": "integer" + }, + "domain": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "host": { + "type": "string" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "port": { + "format": "int32", + "type": "integer" + }, + "route_type": { + "description": "Route type: \"http\" or \"tls\"", + "type": "string" + }, + "updated_at": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "id", + "domain", + "host", + "port", + "enabled", + "route_type", + "created_at", + "updated_at" + ], + "type": "object" + }, + "RouteRole": { + "properties": { + "created_at": { + "example": "1683900000000", + "format": "int64", + "type": "integer" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "name": { + "type": "string" + }, + "updated_at": { + "example": "1683900000000", + "format": "int64", + "type": "integer" + } + }, + "required": [ + "id", + "name", + "created_at", + "updated_at" + ], + "type": "object" + }, + "RouteUser": { + "properties": { + "created_at": { + "example": "1683900000000", + "format": "int64", + "type": "integer" + }, + "deleted_at": { + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "email": { + "type": "string" + }, + "email_verified": { + "type": "boolean" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "image": { + "type": "string" + }, + "mfa_enabled": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "updated_at": { + "example": "1683900000000", + "format": "int64", + "type": "integer" + }, + "username": { + "type": "string" + } + }, + "required": [ + "id", + "name", + "username", + "email", + "image", + "mfa_enabled", + "email_verified", + "created_at", + "updated_at" + ], + "type": "object" + }, + "RouteUserWithRoles": { + "properties": { + "roles": { + "items": { + "$ref": "#/components/schemas/RouteRole" + }, + "type": "array" + }, + "user": { + "$ref": "#/components/schemas/RouteUser" + } + }, + "required": [ + "user", + "roles" + ], + "type": "object" + }, + "RunBackupRequest": { + "properties": { + "backup_type": { + "description": "Type of backup to perform", + "example": "full", + "type": "string" + } + }, + "required": [ + "backup_type" + ], + "type": "object" + }, + "RunExternalServiceBackupRequest": { + "properties": { + "backup_type": { + "description": "Type of backup to perform (e.g., \"full\", \"incremental\")", + "example": "full", + "type": [ + "string", + "null" + ] + }, + "s3_source_id": { + "description": "ID of the S3 source to store the backup. If omitted, the current default S3 source is used.", + "example": 1, + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + "type": "object" + }, + "S3ConnectionTestResponse": { + "description": "Response body for an S3 connection test.", + "properties": { + "message": { + "description": "Human-readable message (success confirmation or error detail).", + "type": "string" + }, + "ok": { + "description": "Whether the connection and credentials worked.", + "type": "boolean" + } + }, + "required": [ + "ok", + "message" + ], + "type": "object" + }, + "S3CredentialsResponse": { + "description": "S3 credentials distributed to agents for backup/restore operations.", + "properties": { + "access_key_id": { + "type": "string" + }, + "bucket_name": { + "type": "string" + }, + "endpoint": { + "type": [ + "string", + "null" + ] + }, + "force_path_style": { + "type": "boolean" + }, + "region": { + "type": "string" + }, + "secret_key": { + "type": "string" + } + }, + "required": [ + "access_key_id", + "secret_key", + "region", + "bucket_name", + "force_path_style" + ], + "type": "object" + }, + "S3SourceResponse": { + "description": "Response type for S3 source", + "properties": { + "access_key_id": { + "example": "AKIAXXXXXXXXXXXXXXXX", + "type": "string" + }, + "bucket_name": { + "type": "string" + }, + "bucket_path": { + "type": "string" + }, + "created_at": { + "format": "int64", + "type": "integer" + }, + "endpoint": { + "example": "http://minio.example.com:9000", + "type": [ + "string", + "null" + ] + }, + "force_path_style": { + "type": [ + "boolean", + "null" + ] + }, + "id": { + "format": "int32", + "type": "integer" + }, + "is_default": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "region": { + "type": "string" + }, + "secret_key": { + "type": "string", + "writeOnly": true + }, + "updated_at": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "id", + "name", + "bucket_name", + "bucket_path", + "access_key_id", + "secret_key", + "region", + "is_default", + "created_at", + "updated_at" + ], + "type": "object" + }, + "SandboxDomainResponse": { + "properties": { + "url": { + "type": "string" + } + }, + "required": [ + "url" + ], + "type": "object" + }, + "SandboxEvent": { + "description": "One entry in a sandbox's operations timeline.", + "properties": { + "at": { + "description": "Unix epoch milliseconds.", + "format": "int64", + "type": "integer" + }, + "detail": { + "description": "Optional structured context (shape depends on `event_type`)." + }, + "event_type": { + "description": "Machine-readable operation (`created`, `stopped`, `resumed`,\n`restarted`, `timeout_extended`, `resized`, `preview_password_set`,\n`preview_password_cleared`, `preview_share_link_created`, `source_seeded`,\n`destroyed`).", + "type": "string" + } + }, + "required": [ + "event_type", + "at" + ], + "type": "object" + }, + "SandboxEventsResponse": { + "properties": { + "events": { + "items": { + "$ref": "#/components/schemas/SandboxEvent" + }, + "type": "array" + } + }, + "required": [ + "events" + ], + "type": "object" + }, + "SandboxInner": { + "description": "Inner `sandbox` object in `@vercel/sandbox` responses. Strict shape —\nthe SDK's zod validator rejects missing required fields.", + "properties": { + "agent_run_id": { + "description": "Agent run this sandbox executes (autofixer / workflow agent).\n`None` for sandboxes created via this API.", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "backend": { + "description": "Isolation backend: \"docker\" | \"firecracker\". `None` on legacy rows\ncreated before the backend was recorded.", + "type": [ + "string", + "null" + ] + }, + "createdAt": { + "format": "int64", + "type": "integer" + }, + "cwd": { + "type": "string" + }, + "disk_size_mb": { + "description": "Configured root disk size in MB (Firecracker). `None` when unknown or\nthe default.", + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "id": { + "type": "string" + }, + "image": { + "type": [ + "string", + "null" + ] + }, + "memory": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "name": { + "type": "string" + }, + "preview_password_hint": { + "type": [ + "string", + "null" + ] + }, + "preview_url_template": { + "type": "string" + }, + "region": { + "type": "string" + }, + "requestedAt": { + "description": "Creation time as Unix epoch milliseconds.", + "format": "int64", + "type": "integer" + }, + "runtime": { + "type": "string" + }, + "status": { + "type": "string" + }, + "timeout": { + "description": "Idle timeout in milliseconds (SDK convention).", + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "updatedAt": { + "format": "int64", + "type": "integer" + }, + "vcpus": { + "format": "double", + "type": "number" + } + }, + "required": [ + "id", + "memory", + "vcpus", + "region", + "runtime", + "timeout", + "status", + "requestedAt", + "createdAt", + "updatedAt", + "cwd", + "name", + "preview_url_template" + ], + "type": "object" + }, + "SandboxResponse": { + "description": "`@vercel/sandbox` wraps every single-sandbox response as\n`{ sandbox: {...}, routes: [...] }`. The SDK reads both.", + "properties": { + "routes": { + "items": { + "$ref": "#/components/schemas/SandboxRoute" + }, + "type": "array" + }, + "sandbox": { + "$ref": "#/components/schemas/SandboxInner" + } + }, + "required": [ + "sandbox", + "routes" + ], + "type": "object" + }, + "SandboxRoute": { + "description": "A single preview route, one per declared port. We don't know ports\nupfront, so we surface an empty array by default — SDK clients use\ntheir own port when calling `sandbox.domain(port)`.", + "properties": { + "port": { + "format": "int32", + "minimum": 0, + "type": "integer" + }, + "subdomain": { + "type": "string" + }, + "url": { + "type": "string" + } + }, + "required": [ + "url", + "subdomain", + "port" + ], + "type": "object" + }, + "SandboxStatusResponse": { + "properties": { + "docker_available": { + "type": "boolean" + }, + "error": { + "type": [ + "string", + "null" + ] + }, + "firecracker_available": { + "type": "boolean" + }, + "image_name": { + "type": "string" + }, + "image_ready": { + "type": "boolean" + } + }, + "required": [ + "docker_available", + "image_ready", + "image_name", + "firecracker_available" + ], + "type": "object" + }, + "SaveAgentTokenRequest": { + "properties": { + "token": { + "description": "The OAuth token from `claude setup-token` or an API key.\nWill be encrypted before storage.", + "type": "string" + } + }, + "required": [ + "token" + ], + "type": "object" + }, + "SaveAgentTokenResponse": { + "properties": { + "saved": { + "type": "boolean" + } + }, + "required": [ + "saved" + ], + "type": "object" + }, + "SaveCredentialRequest": { + "properties": { + "auth_type": { + "description": "Auth flavor id (must match one of the provider's catalog entries).", + "type": "string" + }, + "credential": { + "description": "Plaintext credential body (API key, OAuth token, or full config file\ncontents). Encrypted with `EncryptionService` before being persisted\ninside the `agent_sandbox.providers` JSON map.", + "type": "string" + } + }, + "required": [ + "auth_type", + "credential" + ], + "type": "object" + }, + "SaveCredentialResponse": { + "properties": { + "auth_type": { + "type": "string" + }, + "provider_id": { + "type": "string" + }, + "saved": { + "type": "boolean" + } + }, + "required": [ + "saved", + "provider_id", + "auth_type" + ], + "type": "object" + }, + "ScalewayCredentialsRequest": { + "properties": { + "api_key": { + "example": "scw-secret-key-12345", + "type": "string" + }, + "project_id": { + "example": "12345678-1234-1234-1234-123456789012", + "type": "string" + } + }, + "required": [ + "api_key", + "project_id" + ], + "type": "object" + }, + "ScanResponse": { + "properties": { + "branch": { + "type": [ + "string", + "null" + ] + }, + "commit_hash": { + "type": [ + "string", + "null" + ] + }, + "completed_at": { + "example": "2025-12-08T12:15:47.609192Z", + "type": [ + "string", + "null" + ] + }, + "created_at": { + "example": "2025-12-08T12:15:47.609192Z", + "type": "string" + }, + "critical_count": { + "format": "int32", + "type": "integer" + }, + "deployment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "error_message": { + "type": [ + "string", + "null" + ] + }, + "high_count": { + "format": "int32", + "type": "integer" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "low_count": { + "format": "int32", + "type": "integer" + }, + "medium_count": { + "format": "int32", + "type": "integer" + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "scanner_type": { + "type": "string" + }, + "scanner_version": { + "type": [ + "string", + "null" + ] + }, + "started_at": { + "example": "2025-12-08T12:15:47.609192Z", + "type": "string" + }, + "status": { + "type": "string" + }, + "total_count": { + "format": "int32", + "type": "integer" + }, + "unknown_count": { + "format": "int32", + "type": "integer" + }, + "updated_at": { + "example": "2025-12-08T12:15:47.609192Z", + "type": "string" + } + }, + "required": [ + "id", + "project_id", + "scanner_type", + "status", + "total_count", + "critical_count", + "high_count", + "medium_count", + "low_count", + "unknown_count", + "started_at", + "created_at", + "updated_at" + ], + "type": "object" + }, + "ScheduleRunEntry": { + "description": "A single run-history entry for the schedule detail page (deliverable 1).\n\nCombines one `backups` row with the most-recent `backup_jobs` row for that\nbackup via a lateral JOIN. Fields from `backup_jobs` are `None` for legacy\nbackup rows that pre-date ADR-014.", + "properties": { + "attempts": { + "description": "Number of claim-and-run attempts so far. `None` for legacy rows.", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "backup_id": { + "description": "DB id of the `backups` row.", + "format": "int32", + "type": "integer" + }, + "backup_uuid": { + "description": "UUID string (`backups.backup_id`).", + "type": "string" + }, + "current_step": { + "description": "Last completed step reported by the engine (e.g. `\"upload\"`).\n`None` when no step has been persisted yet.", + "type": [ + "string", + "null" + ] + }, + "error_message": { + "description": "Engine-reported error message when `state = \"failed\"`.", + "type": [ + "string", + "null" + ] + }, + "finished_at": { + "description": "When the backup finished, if known.", + "type": [ + "string", + "null" + ] + }, + "job_id": { + "description": "Most recent `backup_jobs.id` for this backup. `None` for legacy rows.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "s3_location": { + "description": "S3 object key or URL where the backup data lives.", + "type": "string" + }, + "size_bytes": { + "description": "Final size in bytes once completed. `None` while running.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "started_at": { + "description": "When the backup was started (ISO 8601 / RFC 3339).", + "type": "string" + }, + "state": { + "description": "Current state: `\"pending\"`, `\"running\"`, `\"completed\"`, `\"failed\"`.", + "type": "string" + } + }, + "required": [ + "backup_id", + "backup_uuid", + "state", + "started_at", + "s3_location" + ], + "type": "object" + }, + "ScheduleRunJobEntry": { + "description": "A single job entry inside an expanded schedule run, returned by\n[`BackupService::list_schedule_run_jobs`].", + "properties": { + "backup_id": { + "description": "`backups.id` for this job.", + "format": "int32", + "type": "integer" + }, + "backup_uuid": { + "description": "`backups.backup_id` UUID string.", + "type": "string" + }, + "engine": { + "description": "Engine key (e.g. `\"control_plane\"`, `\"redis\"`).", + "type": "string" + }, + "error_message": { + "description": "Engine-reported error message when `state = \"failed\"`.", + "type": [ + "string", + "null" + ] + }, + "finished_at": { + "description": "When this child backup finished, if known.", + "type": [ + "string", + "null" + ] + }, + "s3_source_id": { + "description": "FK to `s3_sources.id` — needed for the backup detail link.", + "format": "int32", + "type": "integer" + }, + "service_id": { + "description": "`external_services.id` — `NULL` for the control-plane job.", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "service_name": { + "description": "Name of the external service, or `\"control plane\"` for the\ncontrol-plane job.", + "type": "string" + }, + "size_bytes": { + "description": "Size in bytes once completed; `None` while running.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "started_at": { + "description": "When this child backup started (ISO 8601 / RFC 3339).", + "type": "string" + }, + "state": { + "description": "Current state of this child backup.", + "type": "string" + } + }, + "required": [ + "backup_id", + "backup_uuid", + "engine", + "service_name", + "state", + "started_at", + "s3_source_id" + ], + "type": "object" + }, + "ScheduleRunListResponse": { + "description": "Paginated run-history response for a backup schedule (deliverable 1).", + "properties": { + "page": { + "description": "Current page (1-based).", + "format": "int64", + "type": "integer" + }, + "page_size": { + "description": "Number of items per page (clamped to 1–100).", + "format": "int64", + "type": "integer" + }, + "runs": { + "description": "Run entries, newest first.", + "items": { + "$ref": "#/components/schemas/ScheduleRunEntry" + }, + "type": "array" + }, + "total": { + "description": "Total number of runs across all pages.", + "format": "int64", + "type": "integer" + } + }, + "required": [ + "runs", + "total", + "page", + "page_size" + ], + "type": "object" + }, + "ScheduleRunResponse": { + "description": "HTTP response body for `POST /api/backups/schedules/{id}/run` (fan-out).", + "properties": { + "jobs": { + "description": "All jobs that were enqueued in this fan-out.", + "items": { + "$ref": "#/components/schemas/EnqueuedJob" + }, + "type": "array" + }, + "schedule_run_id": { + "description": "The `schedule_runs.id` of the newly created run.", + "format": "int64", + "type": "integer" + } + }, + "required": [ + "schedule_run_id", + "jobs" + ], + "type": "object" + }, + "ScheduleRunSummary": { + "description": "Summary of one scheduler tick (or one \"Run now\" click), returned by\n[`BackupService::list_schedule_runs`].\n\nThe `aggregate_state` is computed at read time from child backup counts:\n- `\"running\"` — at least one child is `\"pending\"` or `\"running\"`.\n- `\"failed\"` — at least one child is `\"failed\"` and none are running.\n- `\"completed\"` — all children are `\"completed\"`.", + "properties": { + "aggregate_state": { + "description": "Aggregate state computed from child counts (see struct docs).", + "type": "string" + }, + "completed_jobs": { + "description": "Number of children in `state = \"completed\"`.", + "format": "int64", + "type": "integer" + }, + "failed_jobs": { + "description": "Number of children in `state = \"failed\"`.", + "format": "int64", + "type": "integer" + }, + "finished_at": { + "description": "When all children reached a terminal state. `None` while any child is\nstill `\"pending\"` or `\"running\"`.", + "type": [ + "string", + "null" + ] + }, + "pending_jobs": { + "description": "Number of children in `state = \"pending\"`.", + "format": "int64", + "type": "integer" + }, + "run_id": { + "description": "`schedule_runs.id` for this tick.", + "format": "int64", + "type": "integer" + }, + "running_jobs": { + "description": "Number of children in `state = \"running\"`.", + "format": "int64", + "type": "integer" + }, + "schedule_id": { + "description": "FK to `backup_schedules.id`.", + "format": "int32", + "type": "integer" + }, + "started_at": { + "description": "When the fan-out started (ISO 8601 / RFC 3339).", + "type": "string" + }, + "total_jobs": { + "description": "Total number of child backup jobs in this run.", + "format": "int64", + "type": "integer" + }, + "triggered_by": { + "description": "How the run was triggered: `\"cron\"` or `\"manual\"`.", + "type": "string" + } + }, + "required": [ + "run_id", + "schedule_id", + "triggered_by", + "started_at", + "aggregate_state", + "total_jobs", + "completed_jobs", + "failed_jobs", + "running_jobs", + "pending_jobs" + ], + "type": "object" + }, + "ScheduleRunSummaryList": { + "description": "Paginated list of schedule run summaries returned by the new\n[`BackupService::list_schedule_runs`].", + "properties": { + "page": { + "description": "Current page (1-based).", + "format": "int64", + "type": "integer" + }, + "page_size": { + "description": "Number of items per page.", + "format": "int64", + "type": "integer" + }, + "runs": { + "description": "Run summaries, newest first. Includes synthetic single-job rows for\nlegacy `backups` rows that have `schedule_id` set but no\n`schedule_run_id` (pre-fan-out history).", + "items": { + "$ref": "#/components/schemas/ScheduleRunSummary" + }, + "type": "array" + }, + "total": { + "description": "Total number of run entries across all pages.", + "format": "int64", + "type": "integer" + } + }, + "required": [ + "runs", + "total", + "page", + "page_size" + ], + "type": "object" + }, + "ScreenshotSettings": { + "properties": { + "enabled": { + "default": false, + "type": "boolean" + }, + "provider": { + "default": "local", + "type": "string" + }, + "url": { + "default": "", + "type": "string" + } + }, + "type": "object" + }, + "SearchLogsRequest": { + "properties": { + "container_ids": { + "description": "Filter to specific containers (Docker container IDs). Empty = all\ncontainers. Drives \"filter by container / show all\" in a project's\nhistory, which spans multiple deployments and containers.", + "items": { + "type": "string" + }, + "type": "array" + }, + "context_lines": { + "description": "grep -C: number of raw context lines to include before and after each\nmatch (0 = none, default). Clamped to 50 server-side. The surrounding\nlines ignore the level/text filters — they are the actual adjacent log\nlines, merged across overlapping matches.", + "format": "int32", + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "cursor": { + "description": "Pagination cursor", + "type": [ + "string", + "null" + ] + }, + "deploy_id": { + "description": "Filter by deployment ID (deployments.id)", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "end_time": { + "description": "End of time range (ISO 8601). Defaults to now.", + "type": [ + "string", + "null" + ] + }, + "envs": { + "description": "Filter by environments", + "items": { + "type": "string" + }, + "type": "array" + }, + "external_service_id": { + "description": "When set, search an imported/managed external service's logs instead\nof a project's. `project_id` is ignored in this mode.", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "levels": { + "description": "Filter by log levels", + "items": { + "type": "string" + }, + "type": "array" + }, + "node_ids": { + "description": "Filter to specific worker nodes (node_id). Empty = all nodes, including\ncontrol-plane-local logs.", + "items": { + "format": "int32", + "type": "integer" + }, + "type": "array" + }, + "page_size": { + "description": "Page size (default: 100, max: 500)", + "format": "int32", + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "project_id": { + "description": "Project ID (integer, as used by the rest of the platform)", + "format": "int32", + "type": "integer" + }, + "services": { + "description": "Filter by services", + "items": { + "type": "string" + }, + "type": "array" + }, + "start_time": { + "description": "Start of time range (ISO 8601). Defaults to 1 hour ago.", + "type": [ + "string", + "null" + ] + }, + "text": { + "description": "Full text search query", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "project_id" + ], + "type": "object" + }, + "SearchLogsResponse": { + "properties": { + "available_sources": { + "description": "Distinct containers/nodes/services available in the queried scope, for\nthe filter dropdowns. Populated on the first page (no cursor).", + "items": { + "$ref": "#/components/schemas/LogSource" + }, + "type": "array" + }, + "lines": { + "items": { + "$ref": "#/components/schemas/LogSearchLine" + }, + "type": "array" + }, + "next_cursor": { + "type": [ + "string", + "null" + ] + }, + "search_mode": { + "$ref": "#/components/schemas/SearchMode" + }, + "total_scanned": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "lines", + "search_mode", + "total_scanned" + ], + "type": "object" + }, + "SearchMode": { + "description": "Search execution mode", + "enum": [ + "index", + "archive" + ], + "type": "string" + }, + "Seasonality": { + "description": "Seasonality model for an anomaly baseline.", + "enum": [ + "none", + "hourly", + "daily", + "weekly" + ], + "type": "string" + }, + "SecretResponse": { + "properties": { + "created_at": { + "type": "string" + }, + "description": { + "type": [ + "string", + "null" + ] + }, + "id": { + "format": "int32", + "type": "integer" + }, + "mount_path": { + "type": [ + "string", + "null" + ] + }, + "name": { + "type": "string" + }, + "secret_type": { + "type": "string" + }, + "updated_at": { + "type": "string" + }, + "value": { + "description": "Always masked in responses", + "type": "string" + } + }, + "required": [ + "id", + "name", + "secret_type", + "value", + "created_at", + "updated_at" + ], + "type": "object" + }, + "SecurityConfig": { + "description": "Security configuration for projects and environments\n\nThis configuration can be set at three levels:\n1. Global (in settings table) - applies to all projects\n2. Project level - overrides global settings for specific project\n3. Environment level - overrides project settings for specific environment\n\nThe inheritance chain: Environment > Project > Global", + "properties": { + "attackMode": { + "description": "Attack mode configuration (future: \"off\", \"challenge\", \"block\")\nPlaceholder for DDoS protection, bot detection, etc.", + "type": [ + "string", + "null" + ] + }, + "challengeConfig": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/ChallengeConfig", + "description": "Challenge configuration (future: CAPTCHA, JS challenge, etc.)" + } + ] + }, + "enabled": { + "description": "Enable/disable security features at this level\nIf None, inherits from parent level", + "type": [ + "boolean", + "null" + ] + }, + "geoRestrictions": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/GeoRestrictionsConfig", + "description": "Geographic restrictions (future: country blocking, etc.)" + } + ] + }, + "headers": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/SecurityHeadersConfig", + "description": "Security headers configuration" + } + ] + }, + "passwordProtection": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/PasswordProtectionConfig", + "description": "Password protection: shows an HTML password form before allowing access" + } + ] + }, + "rateLimiting": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/RateLimitConfig", + "description": "Rate limiting configuration" + } + ] + } + }, + "type": "object" + }, + "SecurityHeadersConfig": { + "description": "Security headers configuration (subset of global SecurityHeadersSettings)", + "properties": { + "contentSecurityPolicy": { + "description": "Custom CSP (only used if preset is \"custom\")", + "type": [ + "string", + "null" + ] + }, + "preset": { + "description": "Use a preset: \"strict\", \"moderate\", \"permissive\", \"disabled\", \"custom\"", + "type": [ + "string", + "null" + ] + }, + "referrerPolicy": { + "description": "Referrer-Policy override", + "type": [ + "string", + "null" + ] + }, + "strictTransportSecurity": { + "description": "HSTS override", + "type": [ + "string", + "null" + ] + }, + "xFrameOptions": { + "description": "X-Frame-Options override", + "type": [ + "string", + "null" + ] + } + }, + "type": "object" + }, + "SecurityHeadersSettings": { + "properties": { + "content_security_policy": { + "default": "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self'; frame-ancestors 'self'", + "type": [ + "string", + "null" + ] + }, + "enabled": { + "default": false, + "type": "boolean" + }, + "permissions_policy": { + "default": "geolocation=(), microphone=(), camera=()", + "type": [ + "string", + "null" + ] + }, + "preset": { + "default": "moderate", + "type": "string" + }, + "referrer_policy": { + "default": "strict-origin-when-cross-origin", + "type": "string" + }, + "strict_transport_security": { + "default": "max-age=31536000; includeSubDomains", + "type": "string" + }, + "x_content_type_options": { + "default": "nosniff", + "type": "string" + }, + "x_frame_options": { + "default": "SAMEORIGIN", + "type": "string" + }, + "x_xss_protection": { + "default": "1; mode=block", + "type": "string" + } + }, + "type": "object" + }, + "SendEmailRequestBody": { + "properties": { + "bcc": { + "description": "BCC recipients", + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + }, + "cc": { + "description": "CC recipients", + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + }, + "from": { + "description": "Sender email address (domain will be auto-extracted for lookup)", + "example": "hello@updates.example.com", + "type": "string" + }, + "from_name": { + "description": "Sender display name", + "example": "My App", + "type": [ + "string", + "null" + ] + }, + "headers": { + "additionalProperties": { + "type": "string" + }, + "description": "Custom headers", + "propertyNames": { + "type": "string" + }, + "type": [ + "object", + "null" + ] + }, + "html": { + "description": "HTML body content", + "example": "

Hello World

", + "type": [ + "string", + "null" + ] + }, + "reply_to": { + "description": "Reply-to address", + "type": [ + "string", + "null" + ] + }, + "subject": { + "description": "Email subject", + "example": "Welcome to our platform!", + "type": "string" + }, + "tags": { + "description": "Tags for categorization", + "example": [ + "welcome", + "onboarding" + ], + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + }, + "text": { + "description": "Plain text body content", + "example": "Hello World", + "type": [ + "string", + "null" + ] + }, + "to": { + "description": "Recipient email addresses", + "example": [ + "user@example.com" + ], + "items": { + "type": "string" + }, + "type": "array" + }, + "track_clicks": { + "description": "Enable click tracking (link rewriting). Defaults to false.", + "type": [ + "boolean", + "null" + ] + }, + "track_opens": { + "description": "Enable open tracking (tracking pixel injection). Defaults to false.", + "type": [ + "boolean", + "null" + ] + } + }, + "required": [ + "from", + "to", + "subject" + ], + "type": "object" + }, + "SendEmailResponseBody": { + "properties": { + "id": { + "description": "Email ID", + "example": "550e8400-e29b-41d4-a716-446655440000", + "type": "string" + }, + "provider_message_id": { + "description": "Provider message ID", + "type": [ + "string", + "null" + ] + }, + "status": { + "description": "Email status", + "example": "sent", + "type": "string" + } + }, + "required": [ + "id", + "status" + ], + "type": "object" + }, + "SendMessageRequest": { + "properties": { + "content": { + "type": "string" + }, + "page_context": { + "description": "Optional, client-supplied description of the page/entity the user is\ncurrently viewing (e.g. a trace in a project). Injected into the model's\nview of this turn only — never stored or shown in history. Capped server\nside; oversized values are ignored rather than rejected.", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "content" + ], + "type": "object" + }, + "SensitiveConfigValueResponse": { + "properties": { + "value": { + "type": "string" + } + }, + "required": [ + "value" + ], + "type": "object" + }, + "SensitiveMcpConfigValueResponse": { + "properties": { + "value": { + "type": "string" + } + }, + "required": [ + "value" + ], + "type": "object" + }, + "SensitiveValueResponse": { + "properties": { + "value": { + "type": "string" + } + }, + "required": [ + "value" + ], + "type": "object" + }, + "SentryChunkUploadResponse": { + "properties": { + "accept": { + "items": { + "type": "string" + }, + "type": "array" + }, + "chunkSize": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "chunksPerRequest": { + "format": "int32", + "minimum": 0, + "type": "integer" + }, + "compression": { + "items": { + "type": "string" + }, + "type": "array" + }, + "concurrency": { + "format": "int32", + "minimum": 0, + "type": "integer" + }, + "hashAlgorithm": { + "type": "string" + }, + "maxFileSize": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "maxRequestSize": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "url": { + "type": "string" + } + }, + "required": [ + "url", + "chunkSize", + "chunksPerRequest", + "maxFileSize", + "maxRequestSize", + "concurrency", + "hashAlgorithm", + "compression", + "accept" + ], + "type": "object" + }, + "SentryCreateReleaseRequest": { + "properties": { + "projects": { + "description": "Project slugs this release belongs to", + "items": { + "type": "string" + }, + "type": "array" + }, + "version": { + "description": "Release version identifier", + "type": "string" + } + }, + "required": [ + "version" + ], + "type": "object" + }, + "SentryEventRequest": { + "properties": { + "event_id": { + "type": [ + "string", + "null" + ] + }, + "message": { + "type": [ + "string", + "null" + ] + }, + "platform": { + "type": [ + "string", + "null" + ] + }, + "timestamp": { + "type": [ + "string", + "null" + ] + } + }, + "type": "object" + }, + "SentryEventResponse": { + "properties": { + "id": { + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "SentryReleaseFileResponse": { + "properties": { + "dateCreated": { + "type": "string" + }, + "dist": { + "type": [ + "string", + "null" + ] + }, + "headers": {}, + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "sha1": { + "type": "string" + }, + "size": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "id", + "name", + "headers", + "size", + "sha1", + "dateCreated" + ], + "type": "object" + }, + "SentryReleaseProjectRef": { + "properties": { + "name": { + "type": "string" + }, + "slug": { + "type": "string" + } + }, + "required": [ + "name", + "slug" + ], + "type": "object" + }, + "SentryReleaseResponse": { + "properties": { + "dateCreated": { + "type": "string" + }, + "dateReleased": { + "type": [ + "string", + "null" + ] + }, + "projects": { + "items": { + "$ref": "#/components/schemas/SentryReleaseProjectRef" + }, + "type": "array" + }, + "shortVersion": { + "type": "string" + }, + "version": { + "type": "string" + } + }, + "required": [ + "version", + "dateCreated", + "shortVersion", + "projects" + ], + "type": "object" + }, + "SeriesStateEntry": { + "description": "One series' persisted state snapshot for a dynamic rule (ADR-026 follow-up):\nthe state after the latest tick, the value evaluated this tick, and the open\nalarm id (when firing). Serialized into the `series_states` jsonb column keyed\nby the human-readable [`series_label`]; the alert response decodes it back.", + "properties": { + "alarm_id": { + "description": "The open alarm's id when the series is firing; `null` when ok.", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "state": { + "description": "`firing` or `ok` for this series after the latest tick.", + "type": "string" + }, + "value": { + "description": "The value the rule evaluated for this series this tick.", + "format": "double", + "type": "number" + } + }, + "required": [ + "state", + "value" + ], + "type": "object" + }, + "ServiceAccessInfo": { + "description": "Response containing information about how the service is being accessed", + "properties": { + "access_mode": { + "description": "Mode of access: \"local\", \"direct\", \"nat\", or \"cloudflare_tunnel\"", + "type": "string" + }, + "can_create_domains": { + "description": "Whether domain creation is allowed in this mode", + "type": "boolean" + }, + "domain_creation_error": { + "description": "Error message if domain creation is not allowed", + "type": [ + "string", + "null" + ] + }, + "private_ip": { + "description": "Server's private/local IP address (always returned if available)", + "type": [ + "string", + "null" + ] + }, + "public_ip": { + "description": "Server's public IP address (always returned if available)", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "access_mode", + "can_create_domains" + ], + "type": "object" + }, + "ServiceAction": { + "description": "What to do with a service during migration", + "enum": [ + "create", + "link-external", + "skip" + ], + "type": "string" + }, + "ServiceAlertRuleResponse": { + "description": "Wire representation of a monitoring alert rule.\n\nRegistered under a domain-prefixed OpenAPI schema name to avoid colliding\nwith `temps-error-tracking`'s unrelated `AlertRuleResponse` (utoipa keys\nschemas by their bare struct name, so without `as = ...` the last crate to\nregister would silently shadow this one in the merged spec / generated SDK).", + "properties": { + "comparator": { + "type": "string" + }, + "deployment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "enabled": { + "type": "boolean" + }, + "for_duration_secs": { + "format": "int32", + "type": "integer" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "metric_name": { + "type": "string" + }, + "name": { + "type": "string" + }, + "service_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "severity": { + "type": "string" + }, + "silenced_until": { + "type": [ + "string", + "null" + ] + }, + "threshold": { + "format": "double", + "type": "number" + } + }, + "required": [ + "id", + "name", + "metric_name", + "threshold", + "comparator", + "severity", + "for_duration_secs", + "enabled" + ], + "type": "object" + }, + "ServiceBackupEntryResponse": { + "description": "A single backup entry in the per-service backup list.", + "properties": { + "backup_id": { + "description": "UUID string assigned at backup creation time.", + "type": "string" + }, + "backup_type": { + "description": "Backup variant (e.g. \"full\", \"incremental\").", + "type": "string" + }, + "compression_type": { + "description": "Compression algorithm used (e.g. \"gzip\").", + "type": "string" + }, + "error_message": { + "description": "Engine-reported error message, populated when `state = \"failed\"`.", + "type": [ + "string", + "null" + ] + }, + "external_service_backup_id": { + "description": "Row ID from `external_service_backups`.", + "format": "int32", + "type": "integer" + }, + "finished_at": { + "description": "ISO 8601 timestamp when the backup finished, if known.", + "example": "2025-01-15T14:35:00Z", + "type": [ + "string", + "null" + ] + }, + "id": { + "description": "Row ID from the `backups` table.", + "format": "int32", + "type": "integer" + }, + "name": { + "description": "Human-friendly display name.", + "type": "string" + }, + "s3_location": { + "description": "Object key or `s3://` URL for the backup data.", + "type": "string" + }, + "s3_source_id": { + "description": "FK to `s3_sources.id`.", + "format": "int32", + "type": "integer" + }, + "s3_source_name": { + "description": "Human-readable name of the S3 source.", + "type": "string" + }, + "size_bytes": { + "description": "Size of the backup in bytes, if available.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "started_at": { + "description": "ISO 8601 timestamp when the backup started.", + "example": "2025-01-15T14:30:00Z", + "type": "string" + }, + "state": { + "description": "Current state: \"completed\", \"running\", \"failed\".", + "type": "string" + } + }, + "required": [ + "id", + "backup_id", + "name", + "state", + "backup_type", + "started_at", + "s3_location", + "compression_type", + "s3_source_id", + "s3_source_name", + "external_service_backup_id" + ], + "type": "object" + }, + "ServiceBackupListResponse": { + "description": "Paginated list of backups for a specific external service.\n\nReturned by `GET /backups/external-services/{service_id}/backups`.", + "properties": { + "backups": { + "description": "Backups belonging to this service, newest first.", + "items": { + "$ref": "#/components/schemas/ServiceBackupEntryResponse" + }, + "type": "array" + }, + "page": { + "description": "Current page (1-based).", + "format": "int64", + "type": "integer" + }, + "page_size": { + "description": "Number of items per page.", + "format": "int64", + "type": "integer" + }, + "total": { + "description": "Total number of backups for this service across all pages.", + "format": "int64", + "type": "integer" + } + }, + "required": [ + "backups", + "total", + "page", + "page_size" + ], + "type": "object" + }, + "ServiceCreateAlertRuleRequest": { + "description": "Request body for creating an alert rule on an external service.\n\nDomain-prefixed schema name — see [`AlertRuleResponse`] for why.", + "properties": { + "comparator": { + "description": "One of `>`, `<`, `>=`, `<=`.", + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "for_duration_secs": { + "description": "Seconds the breach must persist before the alarm fires (0 = immediate).", + "format": "int32", + "type": "integer" + }, + "metric_name": { + "type": "string" + }, + "name": { + "type": "string" + }, + "severity": { + "description": "`\"warning\"` or `\"critical\"`.", + "type": "string" + }, + "threshold": { + "format": "double", + "type": "number" + } + }, + "required": [ + "name", + "metric_name", + "threshold", + "comparator", + "severity" + ], + "type": "object" + }, + "ServiceHealthResponse": { + "properties": { + "consecutive_failures": { + "description": "Consecutive failed probes. Alert fires at 3.", + "format": "int32", + "type": "integer" + }, + "last_checked_at": { + "type": [ + "string", + "null" + ] + }, + "last_error": { + "type": [ + "string", + "null" + ] + }, + "recent_checks": { + "description": "Most recent checks, newest-first (capped at `limit`).", + "items": { + "$ref": "#/components/schemas/HealthCheckEntryResponse" + }, + "type": "array" + }, + "response_time_ms": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "service_id": { + "format": "int32", + "type": "integer" + }, + "status": { + "description": "Current health. `null` if the service has not been probed yet.", + "example": "operational", + "type": [ + "string", + "null" + ] + }, + "uptime_24h_percent": { + "description": "Uptime percentage over the last 24 hours (0.0 — 100.0).\n`null` when there is not enough history.", + "format": "double", + "type": [ + "number", + "null" + ] + } + }, + "required": [ + "service_id", + "consecutive_failures", + "recent_checks" + ], + "type": "object" + }, + "ServiceHealthStatusBatchResponse": { + "properties": { + "statuses": { + "items": { + "$ref": "#/components/schemas/ServiceHealthStatusEntryResponse" + }, + "type": "array" + } + }, + "required": [ + "statuses" + ], + "type": "object" + }, + "ServiceHealthStatusEntryResponse": { + "properties": { + "consecutive_failures": { + "format": "int32", + "type": "integer" + }, + "last_checked_at": { + "type": [ + "string", + "null" + ] + }, + "service_id": { + "format": "int32", + "type": "integer" + }, + "status": { + "description": "\"operational\" | \"degraded\" | \"down\". `null` when the service has not\nbeen probed yet.", + "example": "operational", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "service_id", + "consecutive_failures" + ], + "type": "object" + }, + "ServiceMemberInfo": { + "description": "Public info about a cluster member.", + "properties": { + "compute_ip": { + "description": "Container's IP on the `temps-overlay` multi-host network. Populated\nby the lifecycle hook (ADR-011 Phase 3); `None` on single-host\nclusters where the overlay isn't attached.", + "type": [ + "string", + "null" + ] + }, + "container_name": { + "type": "string" + }, + "hostname": { + "type": [ + "string", + "null" + ] + }, + "id": { + "format": "int32", + "type": "integer" + }, + "live_state": { + "description": "Live FSM state from the pg_auto_failover monitor (`primary`,\n`secondary`, `catchingup`, `report_lsn`, …). `None` when the\nmonitor is unreachable, the service is not a cluster, or the row\nis the monitor itself.\n\n**The UI must render the role badge from this field**, falling\nback to `role` only when `live_state` is null. `role` is now\nconfig-only (`monitor` or `replica`); flipping the badge to\n\"primary\" when the monitor elects a new one used to require a\nreconciler that lagged ~5s behind real failovers — and during\nthat window the UI showed two primaries. `live_state` is read\ndirectly from the monitor on every list, so it can never lag.", + "type": [ + "string", + "null" + ] + }, + "node_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "ordinal": { + "format": "int32", + "type": "integer" + }, + "port": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "provisioning_error": { + "description": "Most recent provisioning failure message, when `status='failed'`.\nSet by the background task so the UI can show *why* the new\nreplica didn't come up.", + "type": [ + "string", + "null" + ] + }, + "provisioning_step": { + "description": "Last-attempted phase of the async `add_cluster_member` background\ntask (e.g. `validating`, `provisioning_container`, `done`,\n`failed`). `None` for members not created through that flow —\nthe UI falls back to the `status` column for those.", + "type": [ + "string", + "null" + ] + }, + "role": { + "type": "string" + }, + "status": { + "type": "string" + } + }, + "required": [ + "id", + "role", + "container_name", + "status", + "ordinal" + ], + "type": "object" + }, + "ServiceParameter": { + "properties": { + "choices": { + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + }, + "default_value": { + "type": [ + "string", + "null" + ] + }, + "description": { + "type": "string" + }, + "encrypted": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "validation_pattern": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "name", + "required", + "encrypted", + "description" + ], + "type": "object" + }, + "ServicePlan": { + "description": "Plan for migrating a single service (database, cache, etc.)", + "properties": { + "action": { + "$ref": "#/components/schemas/ServiceAction", + "description": "What to do with this service" + }, + "action_description": { + "description": "Human-readable explanation of what this action means", + "type": "string" + }, + "data_implications": { + "description": "Data implications specific to this service", + "items": { + "$ref": "#/components/schemas/DataImplication" + }, + "type": "array" + }, + "env_var_mappings": { + "additionalProperties": { + "type": "string" + }, + "description": "Environment variable key mappings: source_key -> temps_key\n\nFor example, Vercel's `POSTGRES_URL` might map to Temps' `DATABASE_URL`.\nBoth keys will be set during migration so the app works with either.", + "propertyNames": { + "type": "string" + }, + "type": "object" + }, + "name": { + "description": "Human-readable service name", + "type": "string" + }, + "parameters": { + "additionalProperties": {}, + "description": "Parameters for creating the service in Temps", + "propertyNames": { + "type": "string" + }, + "type": "object" + }, + "service_type": { + "description": "Service type (maps to temps-providers ServiceType)", + "type": "string" + }, + "version": { + "description": "Service version to create (e.g., \"16\" for Postgres 16)", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "name", + "service_type", + "action", + "action_description" + ], + "type": "object" + }, + "ServiceResourceLimits": { + "description": "Optional cgroup resource limits applied to a service container.\n\nAll fields are `Option`: `None` means \"no limit\" (the kernel default),\nmatching Docker's behavior when the corresponding `HostConfig` field is\nleft at zero. Operators opt in to limits explicitly through the\n`PATCH /external-services/{id}/resources` endpoint or by writing the\n`resources` block into `ServiceConfig::parameters` at create time.\n\nThese map directly onto bollard fields:\n- `memory_mb` → `HostConfig.memory` (bytes)\n- `memory_swap_mb`→ `HostConfig.memory_swap` (bytes; ≥ memory)\n- `nano_cpus` → `HostConfig.nano_cpus` (1e9 = 1 full CPU)\n- `cpu_shares` → `HostConfig.cpu_shares` (relative weight, default 1024)\n- `shm_size_mb` → `HostConfig.shm_size` (bytes; default 64 MiB)\n\nIMPORTANT: enabling hard memory limits causes the kernel OOM killer to\nterminate the container when the working set exceeds the limit. The\ncontainer will restart (RestartPolicy::ALWAYS) but in-flight queries\nfail. Surface this clearly in any UI that lets users set limits.", + "properties": { + "cpu_shares": { + "description": "Relative CPU weight (default 1024). Only used when `nano_cpus` is None.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "memory_mb": { + "description": "Hard memory limit in MiB. None = unlimited.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "memory_swap_mb": { + "description": "Memory + swap limit in MiB. None = unlimited.\nMUST be >= memory_mb when both are set; Docker rejects the request otherwise.\nSet equal to `memory_mb` to disable swap entirely.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "nano_cpus": { + "description": "CPU quota in nano-cpus. 1_000_000_000 = 1 full CPU core. None = unlimited.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "shm_size_mb": { + "description": "Shared memory (/dev/shm) size in MiB. None = Docker default (64 MiB).\nMaps to HostConfig.shm_size (bytes). PostgreSQL uses /dev/shm for parallel\nquery workers and large work_mem; the 64 MiB default causes \"could not\nresize shared memory segment ... No space left on device\" under load.\nNOTE: shm_size is fixed at container-create time — Docker's live update\nAPI cannot change it, so changing this value recreates the container.", + "format": "int64", + "type": [ + "integer", + "null" + ] + } + }, + "type": "object" + }, + "ServiceRuntimeReport": { + "description": "Aggregate runtime info for an external service. For standalone services,\n`members` has exactly one entry. For clusters, one entry per member.", + "properties": { + "members": { + "items": { + "$ref": "#/components/schemas/ContainerRuntimeInfo" + }, + "type": "array" + }, + "service_id": { + "format": "int32", + "type": "integer" + }, + "topology": { + "type": "string" + } + }, + "required": [ + "service_id", + "topology", + "members" + ], + "type": "object" + }, + "ServiceStatsReport": { + "properties": { + "members": { + "items": { + "$ref": "#/components/schemas/ContainerStatsSample" + }, + "type": "array" + }, + "service_id": { + "format": "int32", + "type": "integer" + }, + "topology": { + "type": "string" + } + }, + "required": [ + "service_id", + "topology", + "members" + ], + "type": "object" + }, + "ServiceTypeInfo": { + "properties": { + "parameters": { + "example": "[{\"name\": \"host\", \"required\": true, \"encrypted\": false, \"description\": \"Database host\"}]", + "items": { + "$ref": "#/components/schemas/ServiceParameter" + }, + "type": "array" + }, + "service_type": { + "$ref": "#/components/schemas/ServiceTypeRoute" + } + }, + "required": [ + "service_type", + "parameters" + ], + "type": "object" + }, + "ServiceTypeRoute": { + "enum": [ + "mariadb", + "mongodb", + "postgres", + "redis", + "s3", + "kv", + "blob", + "rustfs", + "minio" + ], + "type": "string" + }, + "ServiceUpdateAlertRuleRequest": { + "description": "Request body for updating an existing alert rule.\n\nDomain-prefixed schema name — see [`AlertRuleResponse`] for why.", + "properties": { + "comparator": { + "type": [ + "string", + "null" + ] + }, + "enabled": { + "type": [ + "boolean", + "null" + ] + }, + "for_duration_secs": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "metric_name": { + "type": [ + "string", + "null" + ] + }, + "name": { + "type": [ + "string", + "null" + ] + }, + "severity": { + "type": [ + "string", + "null" + ] + }, + "threshold": { + "format": "double", + "type": [ + "number", + "null" + ] + } + }, + "type": "object" + }, + "SesCredentialsRequest": { + "properties": { + "access_key_id": { + "example": "AKIAIOSFODNN7EXAMPLE", + "type": "string" + }, + "secret_access_key": { + "example": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "type": "string" + } + }, + "required": [ + "access_key_id", + "secret_access_key" + ], + "type": "object" + }, + "SessionDetails": { + "properties": { + "duration_seconds": { + "format": "int64", + "type": "integer" + }, + "ended_at": { + "example": "2024-01-01T00:00:00", + "format": "date-time", + "type": [ + "string", + "null" + ] + }, + "entry_path": { + "type": [ + "string", + "null" + ] + }, + "exit_path": { + "type": [ + "string", + "null" + ] + }, + "is_bounced": { + "type": "boolean" + }, + "is_engaged": { + "type": "boolean" + }, + "page_views": { + "format": "int64", + "type": "integer" + }, + "referrer": { + "type": [ + "string", + "null" + ] + }, + "session_id": { + "format": "int32", + "type": "integer" + }, + "started_at": { + "example": "2024-01-01T00:00:00", + "format": "date-time", + "type": "string" + }, + "visitor_id": { + "type": "string" + } + }, + "required": [ + "session_id", + "visitor_id", + "started_at", + "duration_seconds", + "is_bounced", + "is_engaged", + "page_views" + ], + "type": "object" + }, + "SessionDetailsQuery": { + "properties": { + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "project_id": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "project_id" + ], + "type": "object" + }, + "SessionEvent": { + "properties": { + "event_data": {}, + "event_name": { + "type": [ + "string", + "null" + ] + }, + "event_type": { + "type": [ + "string", + "null" + ] + }, + "id": { + "format": "int32", + "type": "integer" + }, + "page_title": { + "type": [ + "string", + "null" + ] + }, + "page_url": { + "type": [ + "string", + "null" + ] + }, + "timestamp": { + "type": "string" + } + }, + "required": [ + "id", + "timestamp" + ], + "type": "object" + }, + "SessionEventDto": { + "properties": { + "data": {}, + "event_type": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "id": { + "format": "int32", + "type": "integer" + }, + "session_id": { + "format": "int32", + "type": "integer" + }, + "timestamp": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "id", + "session_id", + "data", + "timestamp" + ], + "type": "object" + }, + "SessionEventsQuery": { + "properties": { + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "project_id": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "project_id" + ], + "type": "object" + }, + "SessionEventsResponse": { + "properties": { + "events": { + "items": { + "$ref": "#/components/schemas/SessionEvent" + }, + "type": "array" + }, + "limit": { + "format": "int32", + "type": "integer" + }, + "offset": { + "format": "int32", + "type": "integer" + }, + "session_id": { + "format": "int32", + "type": "integer" + }, + "total_count": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "session_id", + "events", + "total_count", + "offset", + "limit" + ], + "type": "object" + }, + "SessionLogsQuery": { + "properties": { + "end_date": { + "format": "date-time", + "type": [ + "string", + "null" + ] + }, + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "limit": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "offset": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "sort_order": { + "type": [ + "string", + "null" + ] + }, + "start_date": { + "format": "date-time", + "type": [ + "string", + "null" + ] + }, + "visitor_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + "required": [ + "project_id" + ], + "type": "object" + }, + "SessionLogsResponse": { + "properties": { + "limit": { + "format": "int32", + "type": "integer" + }, + "logs": { + "items": { + "$ref": "#/components/schemas/SessionRequestLog" + }, + "type": "array" + }, + "offset": { + "format": "int32", + "type": "integer" + }, + "session_id": { + "format": "int32", + "type": "integer" + }, + "total_count": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "session_id", + "logs", + "total_count", + "offset", + "limit" + ], + "type": "object" + }, + "SessionReplayEventsRequest": { + "properties": { + "events": { + "type": "string" + }, + "sessionId": { + "type": "string" + } + }, + "required": [ + "sessionId", + "events" + ], + "type": "object" + }, + "SessionReplayInfoDto": { + "properties": { + "created_at": { + "type": [ + "string", + "null" + ] + }, + "duration": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "id": { + "type": "string" + }, + "language": { + "type": [ + "string", + "null" + ] + }, + "screen_height": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "screen_width": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "timezone": { + "type": [ + "string", + "null" + ] + }, + "url": { + "type": [ + "string", + "null" + ] + }, + "user_agent": { + "type": [ + "string", + "null" + ] + }, + "viewport_height": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "viewport_width": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "visitor_id": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "id", + "visitor_id" + ], + "type": "object" + }, + "SessionReplayInitRequest": { + "properties": { + "colorDepth": { + "format": "int32", + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "language": { + "type": [ + "string", + "null" + ] + }, + "screenHeight": { + "format": "int32", + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "screenWidth": { + "format": "int32", + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "sessionId": { + "type": "string" + }, + "timestamp": { + "type": [ + "string", + "null" + ] + }, + "timezone": { + "type": [ + "string", + "null" + ] + }, + "url": { + "type": [ + "string", + "null" + ] + }, + "userAgent": { + "type": [ + "string", + "null" + ] + }, + "viewportHeight": { + "format": "int32", + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "viewportWidth": { + "format": "int32", + "minimum": 0, + "type": [ + "integer", + "null" + ] + } + }, + "required": [ + "sessionId" + ], + "type": "object" + }, + "SessionReplayInitResponse": { + "properties": { + "message": { + "type": "string" + }, + "session_id": { + "type": "string" + } + }, + "required": [ + "session_id", + "message" + ], + "type": "object" + }, + "SessionReplayWithEventsDto": { + "properties": { + "events": { + "items": { + "$ref": "#/components/schemas/SessionEventDto" + }, + "type": "array" + }, + "session": { + "$ref": "#/components/schemas/SessionReplayWithVisitorDto" + } + }, + "required": [ + "session", + "events" + ], + "type": "object" + }, + "SessionReplayWithVisitorDto": { + "properties": { + "browser": { + "type": [ + "string", + "null" + ] + }, + "browser_version": { + "type": [ + "string", + "null" + ] + }, + "created_at": { + "type": [ + "string", + "null" + ] + }, + "device_type": { + "type": [ + "string", + "null" + ] + }, + "duration": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "id": { + "format": "int32", + "type": "integer" + }, + "language": { + "type": [ + "string", + "null" + ] + }, + "operating_system": { + "type": [ + "string", + "null" + ] + }, + "operating_system_version": { + "type": [ + "string", + "null" + ] + }, + "screen_height": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "screen_width": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "session_replay_id": { + "type": "string" + }, + "timezone": { + "type": [ + "string", + "null" + ] + }, + "url": { + "type": [ + "string", + "null" + ] + }, + "user_agent": { + "type": [ + "string", + "null" + ] + }, + "viewport_height": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "viewport_width": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "visitor_city": { + "type": [ + "string", + "null" + ] + }, + "visitor_country": { + "type": [ + "string", + "null" + ] + }, + "visitor_country_code": { + "type": [ + "string", + "null" + ] + }, + "visitor_crawler_name": { + "type": [ + "string", + "null" + ] + }, + "visitor_custom_data": {}, + "visitor_environment_id": { + "format": "int32", + "type": "integer" + }, + "visitor_first_seen": { + "type": "string" + }, + "visitor_id": { + "format": "int32", + "type": "integer" + }, + "visitor_is_crawler": { + "type": "boolean" + }, + "visitor_last_seen": { + "type": "string" + }, + "visitor_project_id": { + "format": "int32", + "type": "integer" + }, + "visitor_region": { + "type": [ + "string", + "null" + ] + }, + "visitor_uuid": { + "type": "string" + } + }, + "required": [ + "id", + "session_replay_id", + "visitor_id", + "visitor_uuid", + "visitor_project_id", + "visitor_environment_id", + "visitor_first_seen", + "visitor_last_seen", + "visitor_is_crawler" + ], + "type": "object" + }, + "SessionRequestLog": { + "properties": { + "created_at": { + "example": "2024-01-01T00:00:00", + "format": "date-time", + "type": "string" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "method": { + "type": "string" + }, + "path": { + "type": "string" + }, + "referrer": { + "type": [ + "string", + "null" + ] + }, + "request_headers": { + "type": [ + "string", + "null" + ] + }, + "response_headers": { + "type": [ + "string", + "null" + ] + }, + "response_time_ms": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "status_code": { + "format": "int32", + "type": "integer" + }, + "user_agent": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "id", + "method", + "path", + "status_code", + "created_at" + ], + "type": "object" + }, + "SessionSummary": { + "properties": { + "duration_seconds": { + "format": "int64", + "type": "integer" + }, + "ended_at": { + "example": "2024-01-01T00:00:00", + "format": "date-time", + "type": [ + "string", + "null" + ] + }, + "entry_path": { + "type": [ + "string", + "null" + ] + }, + "events_count": { + "format": "int64", + "type": "integer" + }, + "exit_path": { + "type": [ + "string", + "null" + ] + }, + "is_bounced": { + "type": "boolean" + }, + "is_engaged": { + "type": "boolean" + }, + "page_views": { + "format": "int64", + "type": "integer" + }, + "referrer": { + "type": [ + "string", + "null" + ] + }, + "requests_count": { + "format": "int64", + "type": "integer" + }, + "session_id": { + "format": "int32", + "type": "integer" + }, + "started_at": { + "example": "2024-01-01T00:00:00", + "format": "date-time", + "type": "string" + } + }, + "required": [ + "session_id", + "started_at", + "duration_seconds", + "page_views", + "events_count", + "requests_count", + "is_bounced", + "is_engaged" + ], + "type": "object" + }, + "SetFlagEnvironmentRequest": { + "properties": { + "enabled": { + "description": "The kill switch. `false` makes the flag serve its default regardless of\nany override — and, once targeting exists, regardless of any rule.", + "type": [ + "boolean", + "null" + ] + }, + "value": { + "description": "Tri-state: absent leaves the override, `null` clears it (inherit the\nflag default), anything else sets it. Must match `value_type`." + } + }, + "type": "object" + }, + "SetPreviewPasswordBody": { + "properties": { + "password": { + "description": "Plaintext password to protect the sandbox's preview URLs. Hashed\nserver-side with argon2id — we never persist or echo this back.\nMust be between 8 and 256 characters.", + "type": "string" + } + }, + "required": [ + "password" + ], + "type": "object" + }, + "SetPreviewPasswordResponse": { + "properties": { + "preview_password_hint": { + "description": "Last 4 chars of the password we just stored. Surface in the UI so\nusers can confirm which password is live without re-entering it.", + "type": "string" + } + }, + "required": [ + "preview_password_hint" + ], + "type": "object" + }, + "SetRequest": { + "description": "Request to set a value", + "properties": { + "ex": { + "description": "Expire in seconds", + "example": 3600, + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "key": { + "description": "The key to set", + "example": "user:123", + "type": "string" + }, + "nx": { + "description": "Only set if key does not exist", + "type": "boolean" + }, + "project_id": { + "description": "Project ID (required for API key/session auth, optional for deployment tokens)", + "example": 1, + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "px": { + "description": "Expire in milliseconds", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "value": { + "description": "The value to store (can be any JSON value)" + }, + "xx": { + "description": "Only set if key exists", + "type": "boolean" + } + }, + "required": [ + "key", + "value" + ], + "type": "object" + }, + "SetResponse": { + "description": "Response for set operation", + "properties": { + "result": { + "description": "Always \"OK\" on success", + "example": "OK", + "type": "string" + } + }, + "required": [ + "result" + ], + "type": "object" + }, + "SettingsUpdateResponse": { + "description": "Response for successful settings update", + "properties": { + "message": { + "type": "string" + } + }, + "required": [ + "message" + ], + "type": "object" + }, + "SetupDnsChallengeRequest": { + "description": "Request to setup DNS challenge records using a configured DNS provider", + "properties": { + "dns_provider_id": { + "description": "The ID of the DNS provider to use for creating the TXT records", + "format": "int32", + "type": "integer" + } + }, + "required": [ + "dns_provider_id" + ], + "type": "object" + }, + "SetupDnsChallengeResponse": { + "description": "Response from DNS challenge setup operation", + "properties": { + "message": { + "description": "Human-readable summary message", + "type": "string" + }, + "records_created": { + "description": "Number of TXT records that were successfully created", + "format": "int32", + "minimum": 0, + "type": "integer" + }, + "results": { + "description": "Results for each individual TXT record", + "items": { + "$ref": "#/components/schemas/DnsChallengeRecordResult" + }, + "type": "array" + }, + "success": { + "description": "Overall success status (true if all records were created)", + "type": "boolean" + }, + "total_records": { + "description": "Total number of TXT records required for the challenge", + "format": "int32", + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "success", + "records_created", + "total_records", + "results", + "message" + ], + "type": "object" + }, + "SetupDnsRequest": { + "description": "Request to setup DNS records using a configured DNS provider", + "properties": { + "dns_provider_id": { + "description": "The ID of the DNS provider to use for creating records", + "format": "int32", + "type": "integer" + } + }, + "required": [ + "dns_provider_id" + ], + "type": "object" + }, + "SetupDnsResponse": { + "description": "Response from DNS setup operation", + "properties": { + "message": { + "description": "Human-readable summary message", + "type": "string" + }, + "records_created": { + "description": "Number of records that were successfully created", + "format": "int32", + "minimum": 0, + "type": "integer" + }, + "results": { + "description": "Results for each individual record", + "items": { + "$ref": "#/components/schemas/DnsRecordSetupResult" + }, + "type": "array" + }, + "success": { + "description": "Overall success status", + "type": "boolean" + }, + "total_records": { + "description": "Total number of records attempted", + "format": "int32", + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "success", + "records_created", + "total_records", + "results", + "message" + ], + "type": "object" + }, + "SiblingRef": { + "description": "A sibling project that shares the same `trace_id` and has opted in to\ncross-project trace sharing (`cross_project_trace_sharing = TRUE`).\n\nReturned by `CrossProjectTraceService::find_sibling_projects` and exposed\nby the Phase 1 `GET /otel/traces/cross-project/{trace_id}` endpoint.", + "properties": { + "first_seen": { + "format": "date-time", + "type": "string" + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "project_name": { + "type": "string" + }, + "project_slug": { + "description": "URL slug used to link into the sibling project's single-project trace view.", + "type": "string" + } + }, + "required": [ + "project_id", + "project_name", + "project_slug", + "first_seen" + ], + "type": "object" + }, + "SkillDefinitionResponse": { + "properties": { + "content": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "description": { + "type": [ + "string", + "null" + ] + }, + "has_archive": { + "type": "boolean" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "name": { + "type": "string" + }, + "project_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "slug": { + "type": "string" + }, + "updated_at": { + "type": "string" + } + }, + "required": [ + "id", + "slug", + "name", + "content", + "has_archive", + "created_at", + "updated_at" + ], + "type": "object" + }, + "SlackConfig": { + "properties": { + "channel": { + "type": [ + "string", + "null" + ] + }, + "webhook_url": { + "type": "string" + } + }, + "required": [ + "webhook_url" + ], + "type": "object" + }, + "SlowQueriesResponse": { + "description": "Response envelope for the slow-queries list endpoint.", + "properties": { + "page": { + "description": "Current page number (1-based).", + "format": "int32", + "minimum": 0, + "type": "integer" + }, + "page_size": { + "description": "Number of rows per page used for this request.", + "format": "int32", + "minimum": 0, + "type": "integer" + }, + "queries": { + "description": "Ordered list of query stats, slowest first by mean_exec_time_ms.", + "items": { + "$ref": "#/components/schemas/SlowQueryRow" + }, + "type": "array" + }, + "total_count": { + "description": "Total number of qualifying rows across all pages.", + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "queries", + "page", + "page_size", + "total_count" + ], + "type": "object" + }, + "SlowQueryRow": { + "description": "A single entry from `pg_stat_statements`, representing one normalized\nquery fingerprint and its aggregate execution stats.", + "properties": { + "cache_hit_ratio": { + "description": "Shared block cache hit ratio (0.0–1.0).\n`None` when total block accesses are zero (e.g. function-only queries).", + "format": "double", + "type": [ + "number", + "null" + ] + }, + "calls": { + "description": "Number of times this query was executed.", + "format": "int64", + "type": "integer" + }, + "database": { + "description": "Name of the database this query ran against. `(dropped database)`\nwhen the originating database no longer exists but\n`pg_stat_statements` still holds stats for it.", + "type": "string" + }, + "mean_exec_time_ms": { + "description": "Average wall-clock time per execution, in milliseconds.", + "format": "double", + "type": "number" + }, + "query": { + "description": "Normalized query text (parameter literals replaced with `$N`).", + "type": "string" + }, + "rows": { + "description": "Total number of rows returned or affected.", + "format": "int64", + "type": "integer" + }, + "total_exec_time_ms": { + "description": "Total wall-clock time spent executing this query, in milliseconds.", + "format": "double", + "type": "number" + } + }, + "required": [ + "query", + "database", + "calls", + "total_exec_time_ms", + "mean_exec_time_ms", + "rows" + ], + "type": "object" + }, + "SmartFilter": { + "description": "Smart filter presets for common funnel patterns", + "oneOf": [ + { + "description": "Match specific page path", + "properties": { + "type": { + "enum": [ + "page_path" + ], + "type": "string" + }, + "value": { + "description": "Match specific page path", + "type": "string" + } + }, + "required": [ + "value", + "type" + ], + "type": "object" + }, + { + "description": "Match specific hostname", + "properties": { + "type": { + "enum": [ + "hostname" + ], + "type": "string" + }, + "value": { + "description": "Match specific hostname", + "type": "string" + } + }, + "required": [ + "value", + "type" + ], + "type": "object" + }, + { + "description": "Match UTM source", + "properties": { + "type": { + "enum": [ + "utm_source" + ], + "type": "string" + }, + "value": { + "description": "Match UTM source", + "type": "string" + } + }, + "required": [ + "value", + "type" + ], + "type": "object" + }, + { + "description": "Match UTM campaign", + "properties": { + "type": { + "enum": [ + "utm_campaign" + ], + "type": "string" + }, + "value": { + "description": "Match UTM campaign", + "type": "string" + } + }, + "required": [ + "value", + "type" + ], + "type": "object" + }, + { + "description": "Match UTM medium", + "properties": { + "type": { + "enum": [ + "utm_medium" + ], + "type": "string" + }, + "value": { + "description": "Match UTM medium", + "type": "string" + } + }, + "required": [ + "value", + "type" + ], + "type": "object" + }, + { + "description": "Match referrer hostname", + "properties": { + "type": { + "enum": [ + "referrer_hostname" + ], + "type": "string" + }, + "value": { + "description": "Match referrer hostname", + "type": "string" + } + }, + "required": [ + "value", + "type" + ], + "type": "object" + }, + { + "description": "Match specific channel (organic, paid, direct, referral, etc.)", + "properties": { + "type": { + "enum": [ + "channel" + ], + "type": "string" + }, + "value": { + "description": "Match specific channel (organic, paid, direct, referral, etc.)", + "type": "string" + } + }, + "required": [ + "value", + "type" + ], + "type": "object" + }, + { + "description": "Match device type (mobile, desktop, tablet)", + "properties": { + "type": { + "enum": [ + "device_type" + ], + "type": "string" + }, + "value": { + "description": "Match device type (mobile, desktop, tablet)", + "type": "string" + } + }, + "required": [ + "value", + "type" + ], + "type": "object" + }, + { + "description": "Match browser", + "properties": { + "type": { + "enum": [ + "browser" + ], + "type": "string" + }, + "value": { + "description": "Match browser", + "type": "string" + } + }, + "required": [ + "value", + "type" + ], + "type": "object" + }, + { + "description": "Match operating system", + "properties": { + "type": { + "enum": [ + "operating_system" + ], + "type": "string" + }, + "value": { + "description": "Match operating system", + "type": "string" + } + }, + "required": [ + "value", + "type" + ], + "type": "object" + }, + { + "description": "Match language", + "properties": { + "type": { + "enum": [ + "language" + ], + "type": "string" + }, + "value": { + "description": "Match language", + "type": "string" + } + }, + "required": [ + "value", + "type" + ], + "type": "object" + }, + { + "description": "Match custom event_data by JSON path\nFormat: {\"path\": \"user.plan\", \"value\": \"premium\"}\nThis will match events where event_data->'user'->>'plan' = 'premium'", + "properties": { + "type": { + "enum": [ + "custom_data" + ], + "type": "string" + }, + "value": { + "description": "Match custom event_data by JSON path\nFormat: {\"path\": \"user.plan\", \"value\": \"premium\"}\nThis will match events where event_data->'user'->>'plan' = 'premium'", + "properties": { + "path": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "path", + "value" + ], + "type": "object" + } + }, + "required": [ + "value", + "type" + ], + "type": "object" + } + ] + }, + "SmokeTestResponse": { + "properties": { + "auth_info": { + "description": "Auth email / method", + "type": [ + "string", + "null" + ] + }, + "cli_authenticated": { + "description": "Claude CLI authenticated?", + "type": "boolean" + }, + "cli_installed": { + "description": "Claude CLI installed?", + "type": "boolean" + }, + "cli_version": { + "description": "Claude CLI version", + "type": [ + "string", + "null" + ] + }, + "detail": { + "description": "Full output for debugging", + "type": [ + "string", + "null" + ] + }, + "environment": { + "description": "Where the test ran: \"host\" or \"sandbox\"", + "type": "string" + }, + "passed": { + "description": "Whether the smoke test passed", + "type": "boolean" + }, + "setup_hint": { + "description": "What the user needs to do if the test failed", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "passed", + "environment", + "cli_installed", + "cli_authenticated" + ], + "type": "object" + }, + "SmtpCredentialsRequest": { + "description": "Generic SMTP credentials request body.\n\nWorks with any SMTP relay — AWS SES SMTP endpoints, Sendgrid, Mailgun,\nPostmark, or a self-hosted Postfix. Use this when you only have SMTP\ncredentials (i.e. you cannot create identities via the upstream API).", + "properties": { + "accept_invalid_certs": { + "description": "Accept self-signed certificates. Only safe for local testing.", + "type": "boolean" + }, + "encryption": { + "$ref": "#/components/schemas/SmtpEncryptionRoute", + "description": "TLS mode. Defaults to STARTTLS." + }, + "host": { + "description": "SMTP host, e.g. `email-smtp.eu-west-1.amazonaws.com`.", + "example": "email-smtp.eu-west-1.amazonaws.com", + "type": "string" + }, + "password": { + "description": "SMTP password / API token. Required when `username` is set.", + "type": [ + "string", + "null" + ] + }, + "port": { + "description": "SMTP port (587 for STARTTLS, 465 for implicit TLS, 25/1025 for plain).", + "example": 587, + "format": "int32", + "minimum": 0, + "type": "integer" + }, + "username": { + "description": "SMTP username. Leave empty for unauthenticated relays.", + "example": "AKIAIOSFODNN7EXAMPLE", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "host", + "port" + ], + "type": "object" + }, + "SmtpEncryptionRoute": { + "description": "TLS mode for the SMTP relay.", + "enum": [ + "starttls", + "tls", + "none" + ], + "type": "string" + }, + "SmtpResult": { + "description": "SMTP validation result", + "properties": { + "can_connect_smtp": { + "description": "Whether we could connect to the SMTP server", + "type": "boolean" + }, + "error": { + "description": "Error message if SMTP check failed", + "type": [ + "string", + "null" + ] + }, + "has_full_inbox": { + "description": "Whether the mailbox appears to have a full inbox", + "type": "boolean" + }, + "is_catch_all": { + "description": "Whether this is a catch-all domain", + "type": "boolean" + }, + "is_deliverable": { + "description": "Whether the email is deliverable", + "type": "boolean" + }, + "is_disabled": { + "description": "Whether the mailbox is disabled", + "type": "boolean" + } + }, + "required": [ + "can_connect_smtp", + "has_full_inbox", + "is_catch_all", + "is_deliverable", + "is_disabled" + ], + "type": "object" + }, + "SourceArchiveUpload": { + "properties": { + "file": { + "format": "binary", + "type": "string" + } + }, + "required": [ + "file" + ], + "type": "object" + }, + "SourceBackupEntry": { + "description": "Entry in the source backup index. Covers both DB-tracked backups\n(have a row in `backups`) and S3-scan discoveries (raw S3 objects with\nno DB row — used for disaster-recovery from another Temps instance).", + "properties": { + "backup_id": { + "description": "UUID identifier from the DB row. Empty for S3-scan entries.", + "example": "550e8400-e29b-41d4-a716-446655440000", + "type": "string" + }, + "backup_type": { + "description": "Backup variant as recorded by the backup pipeline (e.g. \"full\").", + "example": "full", + "type": "string" + }, + "created_at": { + "description": "When the backup was created. For S3-scan entries this is the\nobject's LastModified time.", + "example": "2024-01-15T14:30:00.123Z", + "type": "string" + }, + "engine": { + "description": "Engine that produced the backup (\"postgres\", \"redis\", \"mongodb\",\n\"s3\", \"rustfs\"). Used by the UI to mark engine-compat with the\ntarget service.", + "example": "postgres", + "type": [ + "string", + "null" + ] + }, + "format": { + "description": "Storage format: \"walg\" for continuous-archive (PITR-capable),\n\"pg_dump\" for point-in-time dumps, \"\" for non-postgres.", + "example": "walg", + "type": [ + "string", + "null" + ] + }, + "id": { + "description": "DB row id. Zero for S3-scan entries that have no DB row.", + "example": 1, + "format": "int32", + "type": "integer" + }, + "location": { + "description": "Raw S3 URL / key where the backup sits. For Postgres WAL-G backups\nthis starts with `s3://`; for pg_dump-style backups it's the\nrelative object key.", + "example": "s3://bucket/external_services/postgres/svc-name/walg", + "type": "string" + }, + "metadata_location": { + "description": "Sidecar metadata.json location, if any. Empty when none.", + "example": "", + "type": "string" + }, + "name": { + "description": "Human-friendly display name (\"postgres backup (svc-name)\" for DB\nrows, or a synthesized label derived from the S3 path for scans).", + "example": "postgres backup (postgres-n4ea)", + "type": "string" + }, + "origin_service_name": { + "description": "Name of the service that produced the backup. For S3-scan entries\nthis is parsed from the S3 path.", + "example": "postgres-n4ea", + "type": [ + "string", + "null" + ] + }, + "size_bytes": { + "description": "Size of the backup in bytes, if known.", + "example": 1024000, + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "source": { + "description": "Provenance: \"db\" for rows in this Temps, \"s3_scan\" for objects\ndiscovered by the S3 bucket walk (e.g., backups made by another\nTemps instance).", + "example": "db", + "type": "string" + }, + "state": { + "description": "Observed state (\"completed\", \"running\", \"failed\") — DB only.\nEmpty string for S3-scan entries.", + "example": "completed", + "type": "string" + } + }, + "required": [ + "id", + "backup_id", + "name", + "backup_type", + "created_at", + "location", + "metadata_location", + "source", + "state" + ], + "type": "object" + }, + "SourceBackupIndexResponse": { + "description": "Response type for source backup index", + "properties": { + "backups": { + "description": "List of backups in the source", + "items": { + "$ref": "#/components/schemas/SourceBackupEntry" + }, + "type": "array" + }, + "last_updated": { + "description": "When the index was last updated", + "example": "2024-01-15T14:30:00.123Z", + "type": "string" + } + }, + "required": [ + "backups", + "last_updated" + ], + "type": "object" + }, + "SourceBody": { + "description": "Initial content to seed into the sandbox work dir. Mirrors the\n`@vercel/sandbox` `source` option. `type` is one of:\n- `git` — clone `url`; optionally check out `revision`\n- `tarball` — download `url` (must be tar or tar.gz) and extract\n\nFor private git repos, pass credentials one of two ways:\n1. **Inline (SDK-compatible):** `username` + `password`. GitHub\n tokens use `username: \"x-access-token\"`.\n2. **Stored connection (temps-native):** `git_connection_id`\n references a row in the caller's git provider connections. Temps\n resolves the token server-side and injects it safely.\n\n`git_connection_id` is mutually exclusive with `username`/`password`.", + "oneOf": [ + { + "properties": { + "depth": { + "format": "int32", + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "git_connection_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "password": { + "type": [ + "string", + "null" + ] + }, + "revision": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "git" + ], + "type": "string" + }, + "url": { + "type": "string" + }, + "username": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "url", + "type" + ], + "type": "object" + }, + { + "properties": { + "type": { + "enum": [ + "tarball" + ], + "type": "string" + }, + "url": { + "type": "string" + } + }, + "required": [ + "url", + "type" + ], + "type": "object" + } + ] + }, + "SourceFileListResponse": { + "properties": { + "source_files": { + "items": { + "$ref": "#/components/schemas/SourceFileResponse" + }, + "type": "array" + }, + "total": { + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "source_files", + "total" + ], + "type": "object" + }, + "SourceFileResponse": { + "properties": { + "checksum": { + "type": [ + "string", + "null" + ] + }, + "created_at": { + "example": "2025-10-12T12:15:47.609192Z", + "type": "string" + }, + "file_path": { + "type": "string" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "release": { + "type": "string" + }, + "size_bytes": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "id", + "project_id", + "release", + "file_path", + "size_bytes", + "created_at" + ], + "type": "object" + }, + "SourceMapListResponse": { + "properties": { + "source_maps": { + "items": { + "$ref": "#/components/schemas/SourceMapResponse" + }, + "type": "array" + }, + "total": { + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "source_maps", + "total" + ], + "type": "object" + }, + "SourceMapResponse": { + "properties": { + "checksum": { + "type": [ + "string", + "null" + ] + }, + "created_at": { + "example": "2025-10-12T12:15:47.609192Z", + "type": "string" + }, + "dist": { + "type": [ + "string", + "null" + ] + }, + "file_path": { + "type": "string" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "release": { + "type": "string" + }, + "size_bytes": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "id", + "project_id", + "release", + "file_path", + "size_bytes", + "created_at" + ], + "type": "object" + }, + "SourceType": { + "description": "Source type for project deployments\n\nDetermines where the deployment artifacts come from:\n- `Git`: Source code from a Git repository (traditional flow)\n- `DockerImage`: Pre-built Docker image from external registry\n- `StaticFiles`: Pre-built static files uploaded as a bundle\n- `UploadedSource`: Source archive uploaded without a Git repository\n- `Manual`: Flexible type that accepts any deployment method", + "enum": [ + "git", + "docker_image", + "static_files", + "uploaded_source", + "manual" + ], + "type": "string" + }, + "SpanEvent": { + "description": "A span event (log-like annotation on a span).", + "properties": { + "attributes": { + "additionalProperties": { + "type": "string" + }, + "propertyNames": { + "type": "string" + }, + "type": "object" + }, + "name": { + "type": "string" + }, + "timestamp": { + "format": "date-time", + "type": "string" + } + }, + "required": [ + "timestamp", + "name", + "attributes" + ], + "type": "object" + }, + "SpanKind": { + "description": "Span kind.", + "enum": [ + "UNSPECIFIED", + "INTERNAL", + "SERVER", + "CLIENT", + "PRODUCER", + "CONSUMER" + ], + "type": "string" + }, + "SpanRecord": { + "description": "A single trace span ready for storage.", + "properties": { + "attributes": { + "additionalProperties": { + "type": "string" + }, + "description": "Raw key/value pairs exactly as reported by the instrumenting library.\nNumeric values are NOT guaranteed to share `duration_ms`'s unit — they\nmay be seconds, milliseconds, microseconds, or nanoseconds depending on\nthe exporter's own convention, and the unit is not labeled here.", + "propertyNames": { + "type": "string" + }, + "type": "object" + }, + "deployment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "duration_ms": { + "description": "Span duration in milliseconds. The only field on this struct guaranteed\nto be in milliseconds.", + "format": "double", + "type": "number" + }, + "end_time": { + "format": "date-time", + "type": "string" + }, + "events": { + "items": { + "$ref": "#/components/schemas/SpanEvent" + }, + "type": "array" + }, + "kind": { + "$ref": "#/components/schemas/SpanKind" + }, + "name": { + "type": "string" + }, + "parent_span_id": { + "type": [ + "string", + "null" + ] + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "resource": { + "$ref": "#/components/schemas/ResourceInfo" + }, + "span_id": { + "type": "string" + }, + "start_time": { + "format": "date-time", + "type": "string" + }, + "status_code": { + "$ref": "#/components/schemas/SpanStatusCode" + }, + "status_message": { + "type": "string" + }, + "trace_id": { + "type": "string" + } + }, + "required": [ + "project_id", + "resource", + "trace_id", + "span_id", + "name", + "kind", + "start_time", + "end_time", + "duration_ms", + "status_code", + "status_message", + "attributes", + "events" + ], + "type": "object" + }, + "SpanRow": { + "properties": { + "attributes": {}, + "attributes_truncated": { + "type": "boolean" + }, + "deployment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "duration_ms": { + "format": "double", + "type": [ + "number", + "null" + ] + }, + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "id": { + "type": "string" + }, + "operation": { + "type": "string" + }, + "parent_span_id": { + "type": [ + "string", + "null" + ] + }, + "service": { + "type": "string" + }, + "span_id": { + "type": "string" + }, + "status": { + "type": [ + "string", + "null" + ] + }, + "trace_id": { + "type": "string" + }, + "ts": { + "format": "date-time", + "type": "string" + } + }, + "required": [ + "id", + "ts", + "trace_id", + "span_id", + "service", + "operation", + "attributes", + "attributes_truncated" + ], + "type": "object" + }, + "SpanStats": { + "description": "Latency and error statistics for one operation, i.e. one\n`(project, service, span name)` triple over the queried window.", + "properties": { + "avg_duration_ms": { + "format": "double", + "type": "number" + }, + "coefficient_of_variation": { + "description": "`stddev / avg`, or `0` when `avg` is zero.", + "format": "double", + "type": "number" + }, + "count": { + "description": "Number of spans aggregated.", + "format": "int64", + "type": "integer" + }, + "error_count": { + "format": "int64", + "type": "integer" + }, + "error_rate": { + "description": "`error_count / count`, in `[0, 1]`.", + "format": "double", + "type": "number" + }, + "kind": { + "$ref": "#/components/schemas/SpanKind", + "description": "The most common span kind for this operation." + }, + "last_seen": { + "description": "Start time of the most recent span in this group.", + "format": "date-time", + "type": "string" + }, + "max_duration_ms": { + "format": "double", + "type": "number" + }, + "min_duration_ms": { + "format": "double", + "type": "number" + }, + "p50_duration_ms": { + "format": "double", + "type": "number" + }, + "p95_duration_ms": { + "format": "double", + "type": "number" + }, + "p99_duration_ms": { + "format": "double", + "type": "number" + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "service_name": { + "type": "string" + }, + "span_name": { + "description": "The span name, which is the operation identity: `GET /api/checkout`,\n`SELECT carts`, `payments.charge`.", + "type": "string" + }, + "stddev_duration_ms": { + "description": "Sample standard deviation. `0` when the operation has a single sample.", + "format": "double", + "type": "number" + }, + "tail_ratio": { + "description": "`p99 / p50`, or `0` when `p50` is zero.", + "format": "double", + "type": "number" + }, + "total_duration_ms": { + "description": "`SUM(duration_ms)` — total wall-clock attributable to this operation.", + "format": "double", + "type": "number" + } + }, + "required": [ + "project_id", + "service_name", + "span_name", + "kind", + "count", + "error_count", + "error_rate", + "total_duration_ms", + "min_duration_ms", + "max_duration_ms", + "avg_duration_ms", + "stddev_duration_ms", + "p50_duration_ms", + "p95_duration_ms", + "p99_duration_ms", + "coefficient_of_variation", + "tail_ratio", + "last_seen" + ], + "type": "object" + }, + "SpanStatsResponse": { + "description": "Response for `GET /otel/span-stats`.", + "properties": { + "data": { + "items": { + "$ref": "#/components/schemas/SpanStats" + }, + "type": "array" + }, + "end_time": { + "format": "date-time", + "type": "string" + }, + "start_time": { + "description": "The window actually aggregated, echoed back because it is defaulted\nserver-side when the caller omits it.", + "format": "date-time", + "type": "string" + }, + "total": { + "description": "Total number of distinct operations matching the filters, for pagination.", + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "data", + "total", + "start_time", + "end_time" + ], + "type": "object" + }, + "SpanStatusCode": { + "description": "Span status code.", + "enum": [ + "UNSET", + "OK", + "ERROR" + ], + "type": "string" + }, + "SpeedMetricsPayload": { + "description": "Speed metrics payload for recording web vitals", + "properties": { + "cls": { + "description": "Cumulative Layout Shift (score)", + "format": "float", + "type": [ + "number", + "null" + ] + }, + "fcp": { + "description": "First Contentful Paint (milliseconds)", + "format": "float", + "type": [ + "number", + "null" + ] + }, + "fid": { + "description": "First Input Delay (milliseconds)", + "format": "float", + "type": [ + "number", + "null" + ] + }, + "inp": { + "description": "Interaction to Next Paint (milliseconds)", + "format": "float", + "type": [ + "number", + "null" + ] + }, + "language": { + "description": "Browser language", + "type": [ + "string", + "null" + ] + }, + "lcp": { + "description": "Largest Contentful Paint (milliseconds)", + "format": "float", + "type": [ + "number", + "null" + ] + }, + "pathname": { + "description": "Page pathname", + "type": [ + "string", + "null" + ] + }, + "query": { + "description": "Query string", + "type": [ + "string", + "null" + ] + }, + "screenHeight": { + "description": "Screen height in pixels", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "screenWidth": { + "description": "Screen width in pixels", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "ttfb": { + "description": "Time to First Byte (milliseconds)", + "format": "float", + "type": [ + "number", + "null" + ] + }, + "viewportHeight": { + "description": "Viewport height in pixels", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "viewportWidth": { + "description": "Viewport width in pixels", + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + "type": "object" + }, + "SpeedSegmentFilters": { + "description": "Optional segment filters for the performance read endpoints, mirroring\nanalytics' `VisitorSegmentFilters`. Each filter narrows results to samples\nmatching the dimension value, so metrics can be scoped to e.g. one page,\none browser, or one country. Geographic filters resolve via\n`ip_geolocations`; the rest live directly on `performance_metrics`.", + "properties": { + "filter_browser": { + "description": "Browser name (matches `performance_metrics.browser`)", + "type": [ + "string", + "null" + ] + }, + "filter_city": { + "description": "Geolocation city (matches `ip_geolocations.city`)", + "type": [ + "string", + "null" + ] + }, + "filter_country": { + "description": "Geolocation country (matches `ip_geolocations.country`)", + "type": [ + "string", + "null" + ] + }, + "filter_operating_system": { + "description": "Operating system (matches `performance_metrics.operating_system`)", + "type": [ + "string", + "null" + ] + }, + "filter_path": { + "description": "Page pathname (matches `performance_metrics.pathname`)", + "type": [ + "string", + "null" + ] + }, + "filter_region": { + "description": "Geolocation region (matches `ip_geolocations.region`)", + "type": [ + "string", + "null" + ] + } + }, + "type": "object" + }, + "StaleSlot": { + "properties": { + "active": { + "type": "boolean" + }, + "retained_bytes": { + "format": "int64", + "type": "integer" + }, + "slot_name": { + "type": "string" + } + }, + "required": [ + "slot_name", + "active", + "retained_bytes" + ], + "type": "object" + }, + "StartAnalysisRequest": { + "properties": { + "branch": { + "description": "Branch to clone instead of the project's main branch.", + "type": [ + "string", + "null" + ] + }, + "error_group_id": { + "format": "int32", + "type": "integer" + }, + "max_turns": { + "description": "Per-run turn cap applied to every phase (1–200). Only enforced for\nCLIs with a turn flag (Claude Code). `None` uses the provider's\nconfigured defaults.", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "model": { + "description": "Model id for the chosen provider. `None` uses the provider's saved\ndefault model.", + "type": [ + "string", + "null" + ] + }, + "provider": { + "description": "AI provider id (\"claude_cli\", \"codex_cli\", \"opencode\"). `None` uses\nthe platform default provider.", + "type": [ + "string", + "null" + ] + }, + "user_context": { + "description": "Free-text notes for the model (extra context about the error, retry\nguidance, constraints). Included verbatim in the analysis prompt.", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "error_group_id" + ], + "type": "object" + }, + "StartPgUpgradeRequest": { + "properties": { + "from_image": { + "example": "postgres:16-bookworm", + "type": "string" + }, + "from_version": { + "example": "16", + "type": "string" + }, + "to_image": { + "example": "postgres:17-bookworm", + "type": "string" + }, + "to_version": { + "example": "17", + "type": "string" + } + }, + "required": [ + "from_version", + "to_version", + "from_image", + "to_image" + ], + "type": "object" + }, + "StartRestoreRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/RestoreRequestMode", + "description": "Requested restore mode. See `RestoreRequestMode`." + }, + { + "properties": { + "backup_engine": { + "description": "Engine of the backup when specified by `backup_location`\n(\"postgres\", \"redis\", \"mongodb\", \"s3\"). Ignored when `backup_id`\nis used — we infer from the DB row.", + "type": [ + "string", + "null" + ] + }, + "backup_id": { + "description": "DB id of the backup to restore from. Either `backup_id` or\n`backup_location` MUST be provided. Use `backup_id` when restoring\na backup this Temps instance recorded.", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "backup_location": { + "description": "Raw S3 URL / key of the backup — used when restoring a backup\ndiscovered by S3 scan (i.e., produced by another Temps instance).\nRequires `backup_engine` and `s3_source_id` to also be set.", + "type": [ + "string", + "null" + ] + }, + "s3_source_id": { + "description": "S3 source the `backup_location` lives in. Ignored when `backup_id`\nis used.", + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + "type": "object" + } + ] + }, + "StatResponse": { + "properties": { + "exists": { + "type": "boolean" + }, + "is_dir": { + "type": "boolean" + }, + "is_file": { + "type": "boolean" + }, + "path": { + "type": "string" + }, + "size": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "path", + "exists", + "is_dir", + "is_file", + "size" + ], + "type": "object" + }, + "StaticBundleResponse": { + "properties": { + "blob_path": { + "type": "string" + }, + "checksum": { + "type": [ + "string", + "null" + ] + }, + "content_type": { + "type": "string" + }, + "created_at": { + "example": "2025-10-12T12:15:47.609192Z", + "format": "date-time", + "type": "string" + }, + "format": { + "type": [ + "string", + "null" + ] + }, + "id": { + "format": "int32", + "type": "integer" + }, + "metadata": {}, + "original_filename": { + "type": [ + "string", + "null" + ] + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "size_bytes": { + "format": "int64", + "type": "integer" + }, + "uploaded_at": { + "example": "2025-10-12T12:15:47.609192Z", + "format": "date-time", + "type": "string" + } + }, + "required": [ + "id", + "project_id", + "blob_path", + "content_type", + "size_bytes", + "uploaded_at", + "created_at" + ], + "type": "object" + }, + "StaticParams": { + "description": "Static threshold detector: compare the aggregated `value` against `threshold`.", + "properties": { + "comparator": { + "$ref": "#/components/schemas/Comparator", + "description": "How `value` is compared against `threshold`." + }, + "threshold": { + "description": "The threshold the aggregated value is compared against.", + "format": "double", + "type": "number" + } + }, + "required": [ + "comparator", + "threshold" + ], + "type": "object" + }, + "StaticPresetConfig": { + "description": "Configuration for static site presets (Vite, Next.js, Docusaurus, etc.)\nThese presets build static sites that are served via a web server", + "properties": { + "buildCommand": { + "description": "Custom build command (overrides preset default)", + "example": "npm run build:production", + "type": [ + "string", + "null" + ] + }, + "buildContext": { + "description": "Custom build context path (relative to repository root)\nUseful for monorepo setups where the app is in a subdirectory", + "example": "./apps/frontend", + "type": [ + "string", + "null" + ] + }, + "installCommand": { + "description": "Custom install command (overrides auto-detected package manager)", + "example": "npm ci", + "type": [ + "string", + "null" + ] + }, + "outputDir": { + "description": "Custom output directory (overrides preset default)\nCommon values: \"dist\", \"build\", \".next\", \"out\"", + "example": "dist", + "type": [ + "string", + "null" + ] + } + }, + "type": "object" + }, + "StatsFilters": { + "description": "Filters for statistics queries", + "properties": { + "client_ip": { + "type": [ + "string", + "null" + ] + }, + "deployment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "device_type": { + "type": [ + "string", + "null" + ] + }, + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "has_project": { + "description": "When true, only count requests that matched a project (project_id IS NOT NULL).\nUsed by the health dashboard so totals match the per-project cards.", + "type": [ + "boolean", + "null" + ] + }, + "host": { + "type": [ + "string", + "null" + ] + }, + "is_bot": { + "type": [ + "boolean", + "null" + ] + }, + "method": { + "type": [ + "string", + "null" + ] + }, + "project_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "request_source": { + "type": [ + "string", + "null" + ] + }, + "routing_status": { + "type": [ + "string", + "null" + ] + }, + "status_code": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "status_code_class": { + "description": "Filter by status code class (e.g. \"2xx\", \"3xx\", \"4xx\", \"5xx\")", + "type": [ + "string", + "null" + ] + } + }, + "type": "object" + }, + "StatusBucket": { + "properties": { + "avg_response_time_ms": { + "format": "double", + "type": [ + "number", + "null" + ] + }, + "bucket_start": { + "format": "date-time", + "type": "string" + }, + "degraded_count": { + "format": "int64", + "type": "integer" + }, + "down_count": { + "format": "int64", + "type": "integer" + }, + "max_response_time_ms": { + "format": "double", + "type": [ + "number", + "null" + ] + }, + "min_response_time_ms": { + "format": "double", + "type": [ + "number", + "null" + ] + }, + "operational_count": { + "format": "int64", + "type": "integer" + }, + "p50_response_time_ms": { + "format": "double", + "type": [ + "number", + "null" + ] + }, + "p95_response_time_ms": { + "format": "double", + "type": [ + "number", + "null" + ] + }, + "p99_response_time_ms": { + "format": "double", + "type": [ + "number", + "null" + ] + }, + "status": { + "type": "string" + }, + "total_checks": { + "format": "int64", + "type": "integer" + }, + "uptime_percentage": { + "format": "double", + "type": "number" + } + }, + "required": [ + "bucket_start", + "status", + "total_checks", + "operational_count", + "degraded_count", + "down_count", + "uptime_percentage" + ], + "type": "object" + }, + "StatusBucketedResponse": { + "properties": { + "buckets": { + "items": { + "$ref": "#/components/schemas/StatusBucket" + }, + "type": "array" + }, + "interval": { + "type": "string" + }, + "monitor_id": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "monitor_id", + "interval", + "buckets" + ], + "type": "object" + }, + "StatusCodeCount": { + "properties": { + "count": { + "format": "int64", + "type": "integer" + }, + "percentage": { + "format": "double", + "type": "number" + }, + "status_code": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "status_code", + "count", + "percentage" + ], + "type": "object" + }, + "StatusCodesQuery": { + "properties": { + "deployment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "end_date": { + "format": "date-time", + "type": "string" + }, + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "limit": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "start_date": { + "format": "date-time", + "type": "string" + } + }, + "required": [ + "start_date", + "end_date", + "project_id" + ], + "type": "object" + }, + "StatusPageOverview": { + "properties": { + "monitors": { + "items": { + "$ref": "#/components/schemas/MonitorStatus" + }, + "type": "array" + }, + "recent_incidents": { + "items": { + "$ref": "#/components/schemas/IncidentResponse" + }, + "type": "array" + }, + "status": { + "type": "string" + } + }, + "required": [ + "status", + "monitors", + "recent_incidents" + ], + "type": "object" + }, + "StepConversionResponse": { + "properties": { + "average_time_to_complete_seconds": { + "format": "double", + "type": "number" + }, + "completions": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "conversion_rate": { + "format": "double", + "type": "number" + }, + "drop_off_rate": { + "format": "double", + "type": "number" + }, + "step_id": { + "format": "int32", + "type": "integer" + }, + "step_name": { + "type": "string" + }, + "step_order": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "step_id", + "step_name", + "step_order", + "completions", + "conversion_rate", + "drop_off_rate", + "average_time_to_complete_seconds" + ], + "type": "object" + }, + "StepResourceType": { + "description": "What kind of resource a migration step operates on", + "enum": [ + "project", + "environment", + "deployment", + "environment-variable", + "service", + "domain", + "git-link", + "other" + ], + "type": "string" + }, + "StepResult": { + "description": "Result of executing a single migration step", + "properties": { + "created_resources": { + "description": "Resources created by this step", + "items": { + "$ref": "#/components/schemas/CreatedResource" + }, + "type": "array" + }, + "duration_seconds": { + "description": "Duration of this step", + "format": "double", + "type": "number" + }, + "message": { + "description": "Human-readable message about what happened", + "type": "string" + }, + "skipped": { + "description": "Whether this step was skipped", + "type": "boolean" + }, + "step_id": { + "description": "Step ID (matches `MigrationStep.id`)", + "type": "string" + }, + "step_title": { + "description": "Step title (for display)", + "type": "string" + }, + "success": { + "description": "Whether this step succeeded", + "type": "boolean" + } + }, + "required": [ + "step_id", + "step_title", + "success", + "skipped", + "message", + "created_resources", + "duration_seconds" + ], + "type": "object" + }, + "StepUpResponse": { + "properties": { + "expires_at": { + "description": "ISO 8601 timestamp after which sensitive actions require verification\nagain.", + "format": "date-time", + "type": "string" + } + }, + "required": [ + "expires_at" + ], + "type": "object" + }, + "StopSequence": { + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ] + }, + "StorageQuota": { + "description": "Quota usage information for a project.", + "properties": { + "limit_bytes": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "logs_bytes": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "metrics_bytes": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "total_bytes": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "traces_bytes": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "usage_pct": { + "format": "double", + "type": "number" + } + }, + "required": [ + "project_id", + "metrics_bytes", + "traces_bytes", + "logs_bytes", + "total_bytes", + "limit_bytes", + "usage_pct" + ], + "type": "object" + }, + "StripeConfig": { + "properties": { + "include_unpriced_charges": { + "description": "When an allowlist is set, should we still ingest charges that\nlack a price reference (e.g. standalone `charge.succeeded` without\na subscription)? Default true — charges don't belong to a SKU.", + "type": "boolean" + }, + "metered_mode": { + "$ref": "#/components/schemas/MeteredMode", + "description": "How to compute MRR for metered / tiered / hybrid subscriptions." + }, + "price_allowlist": { + "description": "Only events tagged with one of these Stripe price IDs are ingested.\nEmpty = accept all prices.", + "items": { + "type": "string" + }, + "type": "array" + }, + "product_allowlist": { + "description": "Only events tagged with one of these Stripe product IDs are\ningested. Empty = accept all products. Combined with\n`price_allowlist` via OR — if either list has a match, accept.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "SyncedRepositoryListQuery": { + "properties": { + "direction": { + "type": [ + "string", + "null" + ] + }, + "git_provider_connection_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "language": { + "type": [ + "string", + "null" + ] + }, + "owner": { + "type": [ + "string", + "null" + ] + }, + "page": { + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "per_page": { + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "private": { + "type": [ + "boolean", + "null" + ] + }, + "search": { + "type": [ + "string", + "null" + ] + }, + "sort": { + "type": [ + "string", + "null" + ] + } + }, + "type": "object" + }, + "SyntaxResult": { + "description": "Syntax validation result", + "properties": { + "domain": { + "description": "The domain part of the email", + "example": "gmail.com", + "type": [ + "string", + "null" + ] + }, + "is_valid_syntax": { + "description": "Whether the email syntax is valid", + "type": "boolean" + }, + "suggestion": { + "description": "Suggested email correction if available", + "type": [ + "string", + "null" + ] + }, + "username": { + "description": "The username part of the email", + "example": "someone", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "is_valid_syntax" + ], + "type": "object" + }, + "TagInfo": { + "properties": { + "commit_sha": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "name", + "commit_sha" + ], + "type": "object" + }, + "TagListResponse": { + "properties": { + "tags": { + "items": { + "$ref": "#/components/schemas/TagInfo" + }, + "type": "array" + } + }, + "required": [ + "tags" + ], + "type": "object" + }, + "TailLogsRequest": { + "properties": { + "env": { + "type": "string" + }, + "external_service_id": { + "description": "When set, tail an imported/managed external service's logs instead of\na project's (`project_id` is ignored in this mode).", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "levels": { + "items": { + "type": "string" + }, + "type": "array" + }, + "project_id": { + "description": "Project ID (integer, as used by the rest of the platform)", + "format": "int32", + "type": "integer" + }, + "service": { + "type": "string" + }, + "text": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "project_id", + "service", + "env" + ], + "type": "object" + }, + "TargetRecommendation": { + "description": "The temps/Hetzner target sizing and savings estimate", + "properties": { + "fits_single_node": { + "description": "Whether the workloads fit a single recommended server. When `false`,\nthe rationale explains the multi-node option (temps worker nodes).", + "type": "boolean" + }, + "memory_gb": { + "description": "Memory (GB) of the recommended server", + "format": "int32", + "type": "integer" + }, + "monthly_eur": { + "description": "Estimated monthly price of the recommended server in EUR", + "format": "double", + "type": "number" + }, + "monthly_savings_usd": { + "description": "Estimated monthly savings in USD (current cost minus target cost,\ntreating EUR≈USD for the rough comparison — disclaimed in `notes`).\n`None` when the current cost is unknown.", + "format": "double", + "type": [ + "number", + "null" + ] + }, + "rationale": { + "description": "Human-readable recommendation summary", + "type": "string" + }, + "server_type": { + "description": "Recommended Hetzner server type (e.g. \"cpx32\")", + "type": "string" + }, + "sizing_basis": { + "description": "What the sizing was based on, e.g. \"2× measured usage + temps\nplatform overhead\" or \"resource requests (no metrics available)\"", + "type": "string" + }, + "vcpus": { + "description": "vCPUs of the recommended server", + "format": "int32", + "type": "integer" + }, + "yearly_savings_usd": { + "description": "`monthly_savings_usd × 12`", + "format": "double", + "type": [ + "number", + "null" + ] + } + }, + "required": [ + "server_type", + "vcpus", + "memory_gb", + "monthly_eur", + "fits_single_node", + "sizing_basis", + "rationale" + ], + "type": "object" + }, + "TeamListResponse": { + "properties": { + "page": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "page_size": { + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "teams": { + "items": { + "$ref": "#/components/schemas/TeamResponse" + }, + "type": "array" + }, + "total": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "teams", + "total", + "page", + "page_size" + ], + "type": "object" + }, + "TeamMemberResponse": { + "properties": { + "added_by": { + "format": "int32", + "type": "integer" + }, + "created_at": { + "example": "2026-07-30T12:15:47.609192Z", + "format": "date-time", + "type": "string" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "role": { + "$ref": "#/components/schemas/TeamRole", + "description": "The source of this member's project-scoped permissions, intersected\nwith `project_team_access.role`." + }, + "team_id": { + "format": "int32", + "type": "integer" + }, + "updated_at": { + "example": "2026-07-30T12:15:47.609192Z", + "format": "date-time", + "type": "string" + }, + "user_email": { + "description": "The member's email, joined from `users`.", + "type": [ + "string", + "null" + ] + }, + "user_id": { + "format": "int32", + "type": "integer" + }, + "user_name": { + "description": "The member's display name, joined from `users`. `None` if the\nreferenced user no longer exists.", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "id", + "team_id", + "user_id", + "role", + "added_by", + "created_at", + "updated_at" + ], + "type": "object" + }, + "TeamResponse": { + "properties": { + "created_at": { + "example": "2026-07-30T12:15:47.609192Z", + "format": "date-time", + "type": "string" + }, + "created_by": { + "format": "int32", + "type": "integer" + }, + "description": { + "type": [ + "string", + "null" + ] + }, + "id": { + "format": "int32", + "type": "integer" + }, + "name": { + "type": "string" + }, + "slug": { + "type": "string" + }, + "updated_at": { + "example": "2026-07-30T12:15:47.609192Z", + "format": "date-time", + "type": "string" + } + }, + "required": [ + "id", + "name", + "slug", + "created_by", + "created_at", + "updated_at" + ], + "type": "object" + }, + "TeamRole": { + "description": "Role a user holds within a team, or that a team holds on a project.\n\nNamed `TeamRole` rather than `Role` to keep it distinct from\n`temps_auth::permissions::Role`, which is the instance-wide role\n(Admin/User/…) attached to a session. The two are orthogonal: the\ninstance-wide role decides whether you may touch a resource *kind* at\nall, `TeamRole` decides what you may do *within a project* you have\nteam access to. See `temps_teams::fixed_role_permissions` for the\nproject-scoped permission set each variant maps to.\n\nStored as a `varchar(32)` rather than a Postgres enum so the role set\ncan evolve in pure migration code without a schema-level enum\nalteration blocking a downgrade.", + "enum": [ + "owner", + "admin", + "deployer", + "viewer" + ], + "type": "string" + }, + "TemplateResponse": { + "description": "Response type for a single template", + "properties": { + "description": { + "description": "Short description", + "type": [ + "string", + "null" + ] + }, + "env_vars": { + "description": "Environment variables template", + "items": { + "$ref": "#/components/schemas/EnvVarTemplateResponse" + }, + "type": "array" + }, + "exposed_port": { + "description": "Container port the prebuilt image listens on (image deploys only).", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "features": { + "description": "Feature highlights", + "items": { + "type": "string" + }, + "type": "array" + }, + "git": { + "$ref": "#/components/schemas/GitRefResponse", + "description": "Git repository reference" + }, + "health_check_path": { + "description": "HTTP health-check path probed after the container starts (image deploys).", + "type": [ + "string", + "null" + ] + }, + "image": { + "description": "Prebuilt Docker image reference. When set, the one-click deploy pulls and\nruns this image directly (no build); when absent it builds from `git`.", + "type": [ + "string", + "null" + ] + }, + "image_url": { + "description": "URL to template image/icon", + "type": [ + "string", + "null" + ] + }, + "is_featured": { + "description": "Whether the template is featured/promoted", + "type": "boolean" + }, + "name": { + "description": "Display name", + "type": "string" + }, + "preset": { + "description": "Framework/preset to use", + "type": "string" + }, + "screenshot_url": { + "description": "URL to a wide screenshot/banner preview of the deployed template.\nAbsent for templates that don't have one captured yet.", + "type": [ + "string", + "null" + ] + }, + "services": { + "description": "Required external services", + "items": { + "type": "string" + }, + "type": "array" + }, + "slug": { + "description": "Unique identifier for the template (used in URLs)", + "type": "string" + }, + "tags": { + "description": "Tags/categories for filtering", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "slug", + "name", + "git", + "preset", + "tags", + "features", + "services", + "env_vars", + "is_featured" + ], + "type": "object" + }, + "TestEmailRequest": { + "description": "Request body for testing an email provider", + "properties": { + "from": { + "description": "Sender email address (must be verified with the provider)", + "example": "test@example.com", + "type": "string" + }, + "from_name": { + "description": "Sender display name", + "example": "My App", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "from" + ], + "type": "object" + }, + "TestEmailResponse": { + "description": "Response for test email endpoint", + "properties": { + "error": { + "description": "Error message if the test failed", + "type": [ + "string", + "null" + ] + }, + "provider_message_id": { + "description": "Provider message ID if successful", + "type": [ + "string", + "null" + ] + }, + "sent_to": { + "description": "The email address the test was sent to", + "example": "user@example.com", + "type": "string" + }, + "success": { + "description": "Whether the test email was sent successfully", + "type": "boolean" + } + }, + "required": [ + "success", + "sent_to" + ], + "type": "object" + }, + "TestProviderKeyRequest": { + "properties": { + "api_key": { + "description": "The raw API key to test", + "type": "string" + }, + "base_url": { + "description": "Optional custom base URL", + "type": [ + "string", + "null" + ] + }, + "provider": { + "description": "Provider ID: \"openai\", \"anthropic\", \"xai\", \"gemini\"", + "type": "string" + } + }, + "required": [ + "provider", + "api_key" + ], + "type": "object" + }, + "TestProviderKeyResponse": { + "properties": { + "error": { + "description": "Error message if the test failed", + "type": [ + "string", + "null" + ] + }, + "latency_ms": { + "description": "Response time in milliseconds", + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "provider": { + "type": "string" + }, + "success": { + "type": "boolean" + } + }, + "required": [ + "success", + "provider", + "latency_ms" + ], + "type": "object" + }, + "TestProviderResponse": { + "properties": { + "message": { + "type": [ + "string", + "null" + ] + }, + "success": { + "type": "boolean" + } + }, + "required": [ + "success" + ], + "type": "object" + }, + "TimeBucketStats": { + "description": "Time bucket statistics response", + "properties": { + "avg_response_time_ms": { + "description": "Average response time in milliseconds", + "format": "double", + "type": "number" + }, + "bucket": { + "description": "Bucket timestamp in RFC3339 format", + "example": "2025-10-23T12:00:00Z", + "type": "string" + }, + "error_count": { + "description": "Number of errors (status >= 400)", + "format": "int64", + "type": "integer" + }, + "request_count": { + "description": "Total number of requests in this bucket", + "format": "int64", + "type": "integer" + }, + "total_request_bytes": { + "description": "Total request bytes", + "format": "int64", + "type": "integer" + }, + "total_response_bytes": { + "description": "Total response bytes", + "format": "int64", + "type": "integer" + } + }, + "required": [ + "bucket", + "request_count", + "avg_response_time_ms", + "error_count", + "total_request_bytes", + "total_response_bytes" + ], + "type": "object" + }, + "TimeBucketStatsResponse": { + "description": "Response for time bucket stats", + "properties": { + "bucket_interval": { + "type": "string" + }, + "end_time": { + "type": "string" + }, + "start_time": { + "type": "string" + }, + "stats": { + "items": { + "$ref": "#/components/schemas/TimeBucketStats" + }, + "type": "array" + } + }, + "required": [ + "stats", + "start_time", + "end_time", + "bucket_interval" + ], + "type": "object" + }, + "TimeseriesBucket": { + "properties": { + "avg_latency_ms": { + "format": "double", + "type": "number" + }, + "bucket": { + "description": "ISO 8601 timestamp", + "type": "string" + }, + "input_tokens": { + "format": "int64", + "type": "integer" + }, + "output_tokens": { + "format": "int64", + "type": "integer" + }, + "request_count": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "bucket", + "request_count", + "input_tokens", + "output_tokens", + "avg_latency_ms" + ], + "type": "object" + }, + "TimeseriesQueryParams": { + "properties": { + "bucket": { + "description": "Bucket size: \"hour\", \"day\", \"week\" (defaults to \"day\")", + "type": [ + "string", + "null" + ] + }, + "conversation_id": { + "description": "Filter by conversation ID", + "type": [ + "string", + "null" + ] + }, + "from": { + "description": "ISO 8601 start time (defaults to 24h ago)", + "type": [ + "string", + "null" + ] + }, + "model": { + "description": "Filter by model name", + "type": [ + "string", + "null" + ] + }, + "provider": { + "description": "Filter by provider name", + "type": [ + "string", + "null" + ] + }, + "tags": { + "description": "Filter by tags (comma-separated, AND logic)", + "type": [ + "string", + "null" + ] + }, + "to": { + "description": "ISO 8601 end time (defaults to now)", + "type": [ + "string", + "null" + ] + }, + "user_id": { + "description": "Filter by user ID", + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + "type": "object" + }, + "TlsMode": { + "enum": [ + "None", + "Starttls", + "Tls" + ], + "type": "string" + }, + "TodayStatsResponse": { + "description": "Today's stats response", + "properties": { + "date": { + "description": "Date for which stats are returned", + "example": "2025-10-23", + "type": "string" + }, + "total_requests": { + "description": "Total requests today", + "format": "int64", + "type": "integer" + } + }, + "required": [ + "total_requests", + "date" + ], + "type": "object" + }, + "ToggleAiDataAccessRequest": { + "properties": { + "enabled": { + "description": "Whether the AI assistant may read row data from this service.", + "example": false, + "type": "boolean" + } + }, + "required": [ + "enabled" + ], + "type": "object" + }, + "ToggleDeploymentMetricsRequest": { + "description": "Request body to toggle OTLP metric ingestion for a deployment.", + "properties": { + "enabled": { + "description": "Whether to enable (`true`) or disable (`false`) metric ingestion.", + "type": "boolean" + }, + "path": { + "description": "Prometheus scrape path (optional, defaults to `/metrics`).", + "type": [ + "string", + "null" + ] + }, + "port": { + "description": "Prometheus scrape port (optional).", + "format": "int32", + "minimum": 0, + "type": [ + "integer", + "null" + ] + } + }, + "required": [ + "enabled" + ], + "type": "object" + }, + "ToggleServiceMetricsRequest": { + "description": "Request body to toggle metric collection for an external service.", + "properties": { + "enabled": { + "description": "Whether to enable (`true`) or disable (`false`) metric collection.", + "type": "boolean" + } + }, + "required": [ + "enabled" + ], + "type": "object" + }, + "TokenRenewalRequest": { + "properties": { + "refresh_token": { + "type": "string" + } + }, + "required": [ + "refresh_token" + ], + "type": "object" + }, + "ToolCallEvent": { + "description": "Payload for the `tool_call` SSE event: the model is about to run a tool.\nSerialized as compact single-line JSON onto one `data:` line.", + "properties": { + "arguments": { + "description": "The raw JSON-args string the model emitted.", + "type": "string" + }, + "id": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "id", + "name", + "arguments" + ], + "type": "object" + }, + "ToolInfo": { + "description": "One persisted tool invocation + its result, attached to an assistant message.", + "properties": { + "arguments": { + "type": "string" + }, + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "result": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "id", + "name", + "arguments" + ], + "type": "object" + }, + "ToolResultEvent": { + "description": "Payload for the `tool_result` SSE event: a tool finished running. Serialized\nas compact single-line JSON; `content` is JSON-string-escaped so it stays on\none `data:` line even when long.", + "properties": { + "content": { + "type": "string" + }, + "id": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "id", + "name", + "content" + ], + "type": "object" + }, + "TopModelsQueryParams": { + "properties": { + "from": { + "description": "ISO 8601 start time (defaults to 24h ago)", + "type": [ + "string", + "null" + ] + }, + "limit": { + "description": "Max results (defaults to 10)", + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "tags": { + "description": "Filter by tags (comma-separated, AND logic)", + "type": [ + "string", + "null" + ] + }, + "to": { + "description": "ISO 8601 end time (defaults to now)", + "type": [ + "string", + "null" + ] + }, + "user_id": { + "description": "Filter by user ID", + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + "type": "object" + }, + "TraceProjectRef": { + "description": "All projects that contributed spans to a trace, including their sharing flag.\n\nReturned by `CrossProjectTraceService::find_trace_projects`.", + "properties": { + "first_seen": { + "format": "date-time", + "type": "string" + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "project_name": { + "type": "string" + }, + "project_slug": { + "description": "URL slug used to link into the project's single-project trace view.", + "type": "string" + }, + "sharing": { + "description": "Whether this project has `cross_project_trace_sharing = true`.", + "type": "boolean" + } + }, + "required": [ + "project_id", + "project_name", + "project_slug", + "first_seen", + "sharing" + ], + "type": "object" + }, + "TraceSummariesResponse": { + "properties": { + "data": { + "items": { + "$ref": "#/components/schemas/TraceSummary" + }, + "type": "array" + }, + "total": { + "description": "Total traces matching the filters, ignoring pagination. Omitted when\nthe request passed `include_total=false`, in which case the caller\nasked not to pay for the count — treat its absence as \"unknown\", not\nas zero.", + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + } + }, + "required": [ + "data" + ], + "type": "object" + }, + "TraceSummary": { + "description": "A trace summary for the list view — one row per trace, aggregated from spans.", + "properties": { + "deployment_environment": { + "description": "The deployment environment from the root span's resource attributes (e.g. \"production\").", + "type": [ + "string", + "null" + ] + }, + "duration_ms": { + "format": "double", + "type": "number" + }, + "error_count": { + "format": "int64", + "type": "integer" + }, + "kind": { + "$ref": "#/components/schemas/SpanKind" + }, + "root_span_name": { + "type": "string" + }, + "service_name": { + "type": "string" + }, + "span_count": { + "format": "int64", + "type": "integer" + }, + "start_time": { + "format": "date-time", + "type": "string" + }, + "status_code": { + "$ref": "#/components/schemas/SpanStatusCode" + }, + "trace_id": { + "type": "string" + } + }, + "required": [ + "trace_id", + "root_span_name", + "service_name", + "kind", + "status_code", + "start_time", + "duration_ms", + "span_count", + "error_count" + ], + "type": "object" + }, + "TracesResponse": { + "properties": { + "count": { + "minimum": 0, + "type": "integer" + }, + "data": { + "items": { + "$ref": "#/components/schemas/SpanRecord" + }, + "type": "array" + } + }, + "required": [ + "data", + "count" + ], + "type": "object" + }, + "TrackedLinkResponse": { + "description": "Tracked link with click count", + "properties": { + "click_count": { + "format": "int32", + "type": "integer" + }, + "link_index": { + "format": "int32", + "type": "integer" + }, + "original_url": { + "type": "string" + } + }, + "required": [ + "link_index", + "original_url", + "click_count" + ], + "type": "object" + }, + "TrackingEventResponse": { + "description": "Email tracking event", + "properties": { + "created_at": { + "type": "string" + }, + "email_id": { + "type": "string" + }, + "event_type": { + "type": "string" + }, + "id": { + "format": "int64", + "type": "integer" + }, + "ip_address": { + "type": [ + "string", + "null" + ] + }, + "link_index": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "link_url": { + "type": [ + "string", + "null" + ] + }, + "user_agent": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "id", + "email_id", + "event_type", + "created_at" + ], + "type": "object" + }, + "TriggerAgentRequest": { + "properties": { + "trigger_source_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "trigger_source_type": { + "type": [ + "string", + "null" + ] + }, + "user_context": { + "description": "Optional context from the user (e.g. a research topic, bug description, or instructions).", + "type": [ + "string", + "null" + ] + } + }, + "type": "object" + }, + "TriggerDigestResponse": { + "properties": { + "message": { + "type": "string" + }, + "success": { + "type": "boolean" + } + }, + "required": [ + "success", + "message" + ], + "type": "object" + }, + "TriggerPipelinePayload": { + "properties": { + "branch": { + "type": [ + "string", + "null" + ] + }, + "commit": { + "type": [ + "string", + "null" + ] + }, + "environment_id": { + "description": "Optional environment ID - if not provided, will use the project's preview environment", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "tag": { + "type": [ + "string", + "null" + ] + } + }, + "type": "object" + }, + "TriggerPipelineResponse": { + "properties": { + "branch": { + "type": [ + "string", + "null" + ] + }, + "commit": { + "type": [ + "string", + "null" + ] + }, + "environment_id": { + "format": "int32", + "type": "integer" + }, + "message": { + "type": "string" + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "tag": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "message", + "project_id", + "environment_id" + ], + "type": "object" + }, + "TriggerScanRequest": { + "properties": { + "environment_id": { + "description": "Environment ID to scan (uses the current deployment for this environment)", + "example": 1, + "format": "int32", + "type": "integer" + } + }, + "required": [ + "environment_id" + ], + "type": "object" + }, + "TriggerScanResponse": { + "properties": { + "message": { + "type": "string" + }, + "scan_id": { + "format": "int32", + "type": "integer" + }, + "status": { + "type": "string" + } + }, + "required": [ + "scan_id", + "status", + "message" + ], + "type": "object" + }, + "TtlRequest": { + "description": "Request to get TTL for a key", + "properties": { + "key": { + "description": "The key to check TTL for", + "example": "session:abc", + "type": "string" + }, + "project_id": { + "description": "Project ID (required for API key/session auth, optional for deployment tokens)", + "example": 1, + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + "required": [ + "key" + ], + "type": "object" + }, + "TtlResponse": { + "description": "Response for TTL operation", + "properties": { + "ttl": { + "description": "TTL in seconds, -1 if no expiration, -2 if key doesn't exist", + "example": 3600, + "format": "int64", + "type": "integer" + } + }, + "required": [ + "ttl" + ], + "type": "object" + }, + "TxtRecord": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "UiManifest": { + "description": "Describes the plugin's embedded UI bundle.", + "properties": { + "css": { + "description": "CSS files to load", + "items": { + "type": "string" + }, + "type": "array" + }, + "entry_js": { + "description": "JavaScript entry point filename relative to the bundle root", + "type": "string" + }, + "routes": { + "description": "Client-side routes the plugin handles", + "items": { + "$ref": "#/components/schemas/UiRoute" + }, + "type": "array" + } + }, + "required": [ + "entry_js" + ], + "type": "object" + }, + "UiRoute": { + "description": "A client-side route provided by the plugin UI.", + "properties": { + "path": { + "description": "Route path pattern (e.g., \"/my-plugin\", \"/my-plugin/:id\")", + "type": "string" + }, + "title": { + "description": "Page title for breadcrumbs", + "type": "string" + } + }, + "required": [ + "path", + "title" + ], + "type": "object" + }, + "UndrainNodeResponse": { + "description": "Response after undraining (reactivating) a node.", + "properties": { + "id": { + "format": "int32", + "type": "integer" + }, + "message": { + "type": "string" + }, + "name": { + "type": "string" + }, + "status": { + "type": "string" + } + }, + "required": [ + "id", + "name", + "status", + "message" + ], + "type": "object" + }, + "UnifiedTrace": { + "description": "Merged cross-project trace result (Phase 2 unified waterfall).\n\nSpans are sorted by `start_time ASC`. At most 20 projects and 10,000\nspans total are included; `truncated` / `truncated_projects` signal when\nthe caps were hit.", + "properties": { + "end_time": { + "format": "date-time", + "type": "string" + }, + "error_count": { + "minimum": 0, + "type": "integer" + }, + "has_redacted_spans": { + "description": "`true` when at least one project has `cross_project_trace_sharing = false`\nand its spans were therefore excluded from the result set.", + "type": "boolean" + }, + "projects": { + "description": "Projects that contributed spans to this result set.", + "items": { + "$ref": "#/components/schemas/ProjectRef" + }, + "type": "array" + }, + "span_count": { + "minimum": 0, + "type": "integer" + }, + "spans": { + "description": "Annotated, merged span list sorted by `start_time ASC`.", + "items": { + "$ref": "#/components/schemas/AnnotatedSpan" + }, + "type": "array" + }, + "start_time": { + "format": "date-time", + "type": "string" + }, + "total_duration_ms": { + "description": "Trace wall-clock duration in milliseconds (`end_time – start_time`).", + "format": "double", + "type": "number" + }, + "trace_id": { + "type": "string" + }, + "truncated": { + "description": "`true` when the 20-project or 10,000-span cap was hit.", + "type": "boolean" + }, + "truncated_projects": { + "description": "project_ids excluded due to truncation (most-recent first_seen dropped first).", + "items": { + "format": "int32", + "type": "integer" + }, + "type": "array" + } + }, + "required": [ + "trace_id", + "projects", + "spans", + "start_time", + "end_time", + "total_duration_ms", + "span_count", + "error_count", + "has_redacted_spans", + "truncated", + "truncated_projects" + ], + "type": "object" + }, + "UniqueCountsQuery": { + "description": "Query parameters for unique counts over time frame", + "properties": { + "deployment_id": { + "description": "Optional deployment filter", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "end_date": { + "description": "End date for the query range", + "format": "date-time", + "type": "string" + }, + "environment_id": { + "description": "Optional environment filter", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "metric": { + "description": "Metric to count: \"sessions\" (unique sessions), \"visitors\" (unique visitors),\n\"returning_visitors\" (visitors seen before the range), or \"page_views\"\n(total page views) (default: \"sessions\")", + "type": "string" + }, + "start_date": { + "description": "Start date for the query range", + "format": "date-time", + "type": "string" + } + }, + "required": [ + "start_date", + "end_date" + ], + "type": "object" + }, + "UniqueCountsResponse": { + "properties": { + "count": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "count" + ], + "type": "object" + }, + "UnsupportedFeature": { + "description": "A feature from the source platform that cannot be migrated", + "properties": { + "alternative": { + "description": "Suggested alternative in Temps (if any)", + "type": [ + "string", + "null" + ] + }, + "feature": { + "description": "Feature name (e.g., \"Edge Middleware\", \"Serverless Functions\", \"Cron Jobs\")", + "type": "string" + }, + "reason": { + "description": "Why it can't be migrated", + "type": "string" + } + }, + "required": [ + "feature", + "reason" + ], + "type": "object" + }, + "UpdateAdminGateRequest": { + "properties": { + "allowed_hosts": { + "items": { + "type": "string" + }, + "type": "array" + }, + "allowed_ips": { + "items": { + "type": "string" + }, + "type": "array" + }, + "trust_forwarded_for": { + "type": "boolean" + } + }, + "required": [ + "allowed_ips", + "allowed_hosts", + "trust_forwarded_for" + ], + "type": "object" + }, + "UpdateAiProviderRequest": { + "description": "Body for `PATCH /settings/ai-providers/{provider_id}` — updates\nprovider-scoped settings (just the default model for now) without\ntouching the credential. Keeping credentials out of this shape means\nthe UI can auto-save model changes on select, without forcing the user\nto re-paste their token or config file.\nName-spaced schema name avoids an OpenAPI collision with\n`temps-notifications::UpdateProviderRequest`, which has different fields.\nBoth are exposed as `utoipa::ToSchema`; without the override the merged\nOpenAPI doc would silently shadow one struct with the other and break\ngenerated CLI/web clients.", + "properties": { + "default_model": { + "description": "New default model id. `None` or an empty string clears the stored\nvalue so the CLI falls back to its own default.", + "type": [ + "string", + "null" + ] + }, + "max_turns_analysis": { + "description": "Default max turns for the autofixer analysis phase (1–200). `0`\nclears the stored value (built-in default applies); omitted/`None`\nleaves the current value unchanged — so a PATCH that only updates\n`default_model` doesn't wipe the turn settings.", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "max_turns_feedback": { + "description": "Default max turns for autofixer feedback rounds (1–200). `0` clears;\nomitted leaves unchanged.", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "max_turns_fix": { + "description": "Default max turns for the autofixer fix phase (1–200). `0` clears;\nomitted leaves unchanged.", + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + "type": "object" + }, + "UpdateAiProviderResponse": { + "properties": { + "default_model": { + "type": [ + "string", + "null" + ] + }, + "max_turns_analysis": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "max_turns_feedback": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "max_turns_fix": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "provider_id": { + "type": "string" + } + }, + "required": [ + "provider_id" + ], + "type": "object" + }, + "UpdateAlertRuleRequest": { + "properties": { + "cooldown_minutes": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "enabled": { + "type": [ + "boolean", + "null" + ] + }, + "environment_filter": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "error_level_filter": { + "type": [ + "string", + "null" + ] + }, + "name": { + "type": [ + "string", + "null" + ] + }, + "notification_priority": { + "type": [ + "string", + "null" + ] + }, + "trigger_config": {}, + "trigger_type": { + "type": [ + "string", + "null" + ] + } + }, + "type": "object" + }, + "UpdateApiKeyRequest": { + "properties": { + "expires_at": { + "example": "2024-12-31T23:59:59Z", + "format": "date-time", + "type": [ + "string", + "null" + ] + }, + "is_active": { + "type": [ + "boolean", + "null" + ] + }, + "name": { + "type": [ + "string", + "null" + ] + }, + "permissions": { + "example": [ + "projects:read", + "deployments:read" + ], + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + } + }, + "type": "object" + }, + "UpdateAutomaticDeployRequest": { + "properties": { + "automatic_deploy": { + "type": "boolean" + } + }, + "required": [ + "automatic_deploy" + ], + "type": "object" + }, + "UpdateBackupScheduleRequest": { + "description": "Request body for updating an existing backup schedule via `PATCH /api/backups/schedules/{id}`.\n\nAll fields are optional; only present fields are updated. Absent fields\nleave the corresponding column unchanged.", + "properties": { + "description": { + "description": "New human-readable description. Pass an empty string `\"\"` to clear.", + "type": [ + "string", + "null" + ] + }, + "enabled": { + "description": "Enable or disable the schedule. Skipped when `None`.", + "type": [ + "boolean", + "null" + ] + }, + "include_control_plane": { + "description": "Toggle whether the control-plane backup is produced on every run.", + "type": [ + "boolean", + "null" + ] + }, + "max_runtime_secs": { + "description": "Per-schedule wall-clock timeout override (seconds).\n\n- `None` (field absent) — leave current value unchanged\n- `Some(None)` (field present, JSON `null`) — clear override; fall back to engine default\n- `Some(Some(n))` — set to `n` seconds (must be >= 60)", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "name": { + "description": "New schedule name. Skipped when `None`. Must not be empty if provided.", + "type": [ + "string", + "null" + ] + }, + "retention_period": { + "description": "Days to retain backups produced by this schedule. Must be >= 1.", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "schedule_expression": { + "description": "New cron expression. When changed, `next_run` is recomputed.", + "type": [ + "string", + "null" + ] + }, + "tags": { + "description": "Replace the full tag list. Skipped when `None`.", + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + }, + "target_all_services": { + "description": "Toggle between \"back up every database\" (`true`) and \"back up only\nthe explicit list\" (`false`). When set to `true`, the server clears\nthe explicit membership rows for this schedule.", + "type": [ + "boolean", + "null" + ] + } + }, + "type": "object" + }, + "UpdateBlobRequest": { + "description": "Request to update Blob service configuration", + "properties": { + "docker_image": { + "description": "Docker image to use (e.g., \"rustfs/rustfs:1.0.0-alpha.98\")", + "example": "rustfs/rustfs:1.0.0-alpha.98", + "type": [ + "string", + "null" + ] + } + }, + "type": "object" + }, + "UpdateBlobResponse": { + "description": "Response after updating Blob service", + "properties": { + "message": { + "description": "Human-readable message", + "example": "Blob service updated successfully", + "type": "string" + }, + "status": { + "$ref": "#/components/schemas/BlobStatusResponse", + "description": "Current status" + }, + "success": { + "description": "Whether the operation succeeded", + "example": true, + "type": "boolean" + } + }, + "required": [ + "success", + "message", + "status" + ], + "type": "object" + }, + "UpdateCloudflareProviderRequest": { + "properties": { + "config": { + "$ref": "#/components/schemas/CloudflareConfig" + }, + "enabled": { + "type": [ + "boolean", + "null" + ] + }, + "name": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "config" + ], + "type": "object" + }, + "UpdateConfigBody": { + "properties": { + "config": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/ProviderConfig", + "description": "Typed provider configuration. Setting `config` to `null` clears\nthe stored config back to the accept-everything default. The\nconfig's `provider` tag must match the integration's provider." + } + ] + } + }, + "type": "object" + }, + "UpdateCustomDomainRequest": { + "properties": { + "branch": { + "type": [ + "string", + "null" + ] + }, + "domain": { + "type": [ + "string", + "null" + ] + }, + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "redirect_to": { + "type": [ + "string", + "null" + ] + }, + "service_name": { + "description": "Docker Compose service name this domain routes to (empty string clears it)", + "type": [ + "string", + "null" + ] + }, + "status_code": { + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + "type": "object" + }, + "UpdateDashboardRequest": { + "properties": { + "layout": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/DashboardLayout" + } + ] + }, + "name": { + "type": [ + "string", + "null" + ] + } + }, + "type": "object" + }, + "UpdateDeploymentConfigRequest": { + "properties": { + "automaticDeploy": { + "type": [ + "boolean", + "null" + ] + }, + "cpuLimit": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "cpuRequest": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "crossArchitectureBuilds": { + "description": "Build one image per architecture the eligible nodes run. Off by\ndefault; environments inherit this and may override it. Cross-builds\nare emulated on the control plane and substantially slower, so they are\nopted into rather than triggered by cluster topology.", + "type": [ + "boolean", + "null" + ] + }, + "exposedPort": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "memoryLimit": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "memoryRequest": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "performanceMetricsEnabled": { + "type": [ + "boolean", + "null" + ] + }, + "replicas": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "security": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/SecurityConfig" + } + ] + }, + "sessionRecordingEnabled": { + "type": [ + "boolean", + "null" + ] + } + }, + "type": "object" + }, + "UpdateDeploymentTokenRequest": { + "properties": { + "expires_at": { + "example": "2024-12-31T23:59:59Z", + "format": "date-time", + "type": [ + "string", + "null" + ] + }, + "is_active": { + "type": [ + "boolean", + "null" + ] + }, + "name": { + "type": [ + "string", + "null" + ] + }, + "permissions": { + "example": [ + "visitors:enrich", + "emails:send" + ], + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + } + }, + "type": "object" + }, + "UpdateDnsProviderRequest": { + "description": "Request to update a DNS provider", + "properties": { + "credentials": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/DnsProviderCredentials", + "description": "New credentials" + } + ] + }, + "description": { + "description": "New description", + "type": [ + "string", + "null" + ] + }, + "is_active": { + "description": "Active status", + "type": [ + "boolean", + "null" + ] + }, + "name": { + "description": "New name", + "type": [ + "string", + "null" + ] + } + }, + "type": "object" + }, + "UpdateEmailProviderRequest": { + "description": "Request body for `PATCH /email-providers/{id}`.\n\nAll fields are optional. Omit any field to leave it unchanged. The\n`provider_type` is immutable — to switch providers, delete the row and\ncreate a new one. For credentials, supplying any credential variant\nre-encrypts the stored blob; omitting them preserves the existing secret\n(so operators can rename without re-typing passwords).", + "properties": { + "is_active": { + "type": [ + "boolean", + "null" + ] + }, + "name": { + "example": "My AWS SES", + "type": [ + "string", + "null" + ] + }, + "region": { + "example": "us-east-1", + "type": [ + "string", + "null" + ] + }, + "scaleway_credentials": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/ScalewayCredentialsRequest" + } + ] + }, + "ses_credentials": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/SesCredentialsRequest" + } + ] + }, + "smtp_credentials": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/SmtpCredentialsRequest" + } + ] + }, + "sns_topic_arn": { + "description": "Rotate or clear the exact SNS topic allowed for this SES provider.\nOmit to preserve it, send `null` to clear it, or send a string to set it.", + "type": [ + "string", + "null" + ] + } + }, + "type": "object" + }, + "UpdateEnvironmentSettingsRequest": { + "properties": { + "anti_affinity": { + "description": "Anti-affinity: spread replicas across different nodes.\nWhen enabled, the scheduler avoids placing two replicas of the same\nenvironment on the same node. Defaults to `true`.", + "type": [ + "boolean", + "null" + ] + }, + "attack_mode": { + "description": "Per-environment CAPTCHA attack-mode override (tri-state):\n- absent → leave the current override unchanged\n- JSON `null` → clear the override (inherit the project-level setting)\n- `true`/`false` → override the project setting for this environment", + "type": [ + "boolean", + "null" + ] + }, + "automatic_deploy": { + "description": "Enable/disable automatic deployments for this environment", + "type": [ + "boolean", + "null" + ] + }, + "branch": { + "type": [ + "string", + "null" + ] + }, + "cpu_limit": { + "description": "Maximum (limit) CPU in microcores. Send JSON `null` to clear → \"no limit\".\nAbsent leaves the current value unchanged.", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "cpu_request": { + "description": "Minimum (request) CPU in microcores. Send JSON `null` to clear (no request).\nAbsent leaves the current value unchanged.", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "cross_architecture_builds": { + "description": "Build one image per architecture the eligible nodes run (overrides the\nproject-level setting). Off by default: cross-architecture builds are\nemulated on the control plane and substantially slower, so they are\nopted into per environment rather than triggered by cluster topology.", + "type": [ + "boolean", + "null" + ] + }, + "exposed_port": { + "description": "Port exposed by the container (overrides project-level port for this environment)\n\nPriority order for port resolution:\n1. Image EXPOSE directive (auto-detected from built image)\n2. This environment-level exposed_port (overrides project setting)\n3. Project-level exposed_port (fallback)\n4. Default: 3000", + "example": 8080, + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "force_https": { + "description": "Per-environment HTTP→HTTPS redirect override (tri-state):\n- absent → leave the current override unchanged\n- JSON `null` → clear the override (inherit the proxy default, which\n redirects only when the host has an active TLS certificate)\n- `true` → always redirect plain HTTP to HTTPS for this environment,\n even when no local certificate exists (TLS terminated upstream)\n- `false` → never redirect this environment, even when a certificate does\n exist\n\nRequests under `/.well-known/acme-challenge/` are never redirected\nregardless of this setting, so ACME HTTP-01 validation always completes.", + "type": [ + "boolean", + "null" + ] + }, + "idle_timeout_seconds": { + "description": "Seconds of inactivity before stopping containers (60-86400). Default: 300.", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "memory_limit": { + "description": "Maximum (limit) memory in MB. Send JSON `null` to clear → \"no limit\".\nAbsent leaves the current value unchanged.", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "memory_request": { + "description": "Minimum (request) memory in MB. Send JSON `null` to clear (no request).\nAbsent leaves the current value unchanged.", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "on_demand": { + "description": "Enable on-demand mode (scale-to-zero). Containers are stopped after\nidle_timeout_seconds of no traffic and started on the next request.", + "type": [ + "boolean", + "null" + ] + }, + "password": { + "description": "Set a password to protect this environment. The proxy will show an HTML\npassword form before allowing access. The password is bcrypt-hashed\nserver-side and never stored in plaintext.\nSend an empty string to remove password protection.", + "type": [ + "string", + "null" + ] + }, + "performance_metrics_enabled": { + "description": "Enable/disable performance metrics collection", + "type": [ + "boolean", + "null" + ] + }, + "protected": { + "description": "When true, git pushes do NOT auto-deploy to this environment.\nDeployments must be promoted from another environment.", + "type": [ + "boolean", + "null" + ] + }, + "replicas": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "security": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/SecurityConfig", + "description": "Security configuration for this environment (overrides project-level settings)" + } + ] + }, + "session_recording_enabled": { + "description": "Enable/disable session recording", + "type": [ + "boolean", + "null" + ] + }, + "target_labels": { + "description": "Label selector for node-based scheduling (overrides project-level setting).\nSame key with array value -> OR, different keys -> AND.\nExample: `{\"region\": [\"us\", \"asia\"], \"gpu\": \"true\"}`" + }, + "target_nodes": { + "description": "Optional list of node IDs to deploy to (overrides project-level setting)", + "items": { + "format": "int32", + "type": "integer" + }, + "type": [ + "array", + "null" + ] + }, + "wake_timeout_seconds": { + "description": "Max seconds to wait for containers to start on wake (5-120). Default: 30.", + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + "type": "object" + }, + "UpdateEnvironmentSubdomainRequest": { + "description": "Request to rename an environment's auto-managed subdomain.\n\nThe subdomain is the host label inserted in front of the platform's\npreview domain (e.g. `myapp` in `myapp.preview.temps.sh`). Renaming\nreplaces the previous subdomain entirely — the old hostname stops\nresolving immediately after this request succeeds.", + "properties": { + "subdomain": { + "description": "New subdomain label. Must be a DNS-safe slug (lowercase letters,\ndigits, and hyphens, 1-63 characters). The value is slugified\nserver-side, so casing and disallowed characters are normalized.", + "example": "myapp", + "type": "string" + } + }, + "required": [ + "subdomain" + ], + "type": "object" + }, + "UpdateEnvironmentVariableRequest": { + "properties": { + "environment_ids": { + "items": { + "format": "int32", + "type": "integer" + }, + "type": "array" + }, + "include_in_preview": { + "type": "boolean" + }, + "is_secret": { + "description": "Optional secret-flag transition.\n- `Some(true)` promotes a regular var to a secret.\n- `Some(false)` is rejected if the row is already secret (one-way flag).\n- `None` (omitted) leaves the flag unchanged.", + "type": [ + "boolean", + "null" + ] + }, + "key": { + "type": "string" + }, + "value": { + "description": "New plaintext value. `None` (omitted) keeps the existing ciphertext,\nwhich is the only way to edit a secret env var without re-typing its\nvalue (e.g. changing which environments it applies to).", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "key", + "environment_ids" + ], + "type": "object" + }, + "UpdateErrorGroupRequest": { + "properties": { + "assigned_to": { + "type": [ + "string", + "null" + ] + }, + "status": { + "type": "string" + } + }, + "required": [ + "status" + ], + "type": "object" + }, + "UpdateExternalServiceRequest": { + "properties": { + "docker_image": { + "description": "Docker image to use for the service (e.g., \"gotempsh/postgres-walg:18-bookworm\", \"timescale/timescaledb-ha:pg18\")\nWhen provided, the service will be recreated with the new image while preserving data", + "type": [ + "string", + "null" + ] + }, + "parameters": { + "additionalProperties": {}, + "propertyNames": { + "type": "string" + }, + "type": "object" + } + }, + "required": [ + "parameters" + ], + "type": "object" + }, + "UpdateFlagRequest": { + "properties": { + "client_visible": { + "type": [ + "boolean", + "null" + ] + }, + "default_value": { + "description": "Must match the flag's existing `value_type`." + }, + "description": { + "description": "Tri-state: absent leaves it, `null` clears it, a string sets it.", + "type": [ + "string", + "null" + ] + } + }, + "type": "object" + }, + "UpdateGitSettingsRequest": { + "properties": { + "directory": { + "type": "string" + }, + "git_provider_connection_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "git_url": { + "description": "Git clone URL for public repositories", + "type": [ + "string", + "null" + ] + }, + "is_public_repo": { + "description": "Whether this is a public repository (no git provider connection needed)", + "type": [ + "boolean", + "null" + ] + }, + "main_branch": { + "type": "string" + }, + "preset": { + "type": [ + "string", + "null" + ] + }, + "preset_config": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/PresetConfigSchema", + "description": "Preset-specific configuration (e.g., Dockerfile path for Docker preset)\n\nExample for Dockerfile preset:\n```json\n{\n \"dockerfilePath\": \"docker/Dockerfile\",\n \"buildContext\": \"./api\"\n}\n```" + } + ] + }, + "repo_name": { + "type": "string" + }, + "repo_owner": { + "type": "string" + } + }, + "required": [ + "main_branch", + "repo_owner", + "repo_name", + "directory" + ], + "type": "object" + }, + "UpdateIncidentStatusRequest": { + "properties": { + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + }, + "required": [ + "status", + "message" + ], + "type": "object" + }, + "UpdateIpAccessControlRequest": { + "description": "Request to update an IP access control rule", + "properties": { + "action": { + "description": "Optional new action", + "type": [ + "string", + "null" + ] + }, + "ip_address": { + "description": "Optional new IP address", + "type": [ + "string", + "null" + ] + }, + "reason": { + "description": "Optional new reason", + "type": [ + "string", + "null" + ] + } + }, + "type": "object" + }, + "UpdateKvRequest": { + "description": "Request to update KV service configuration", + "properties": { + "docker_image": { + "description": "Docker image to use (e.g., \"gotempsh/redis-walg:8-bookworm\")", + "example": "gotempsh/redis-walg:8-bookworm", + "type": [ + "string", + "null" + ] + } + }, + "type": "object" + }, + "UpdateKvResponse": { + "description": "Response after updating KV service", + "properties": { + "message": { + "description": "Status message", + "example": "KV service updated successfully", + "type": "string" + }, + "status": { + "$ref": "#/components/schemas/KvStatusResponse", + "description": "Current service status" + }, + "success": { + "description": "Whether the operation succeeded", + "type": "boolean" + } + }, + "required": [ + "success", + "message", + "status" + ], + "type": "object" + }, + "UpdateManagedDomainApiRequest": { + "description": "Request to update a managed domain's settings.", + "properties": { + "auto_manage": { + "description": "Toggle automatic DNS management for this domain.", + "type": [ + "boolean", + "null" + ] + }, + "generated_hostname_mode": { + "description": "`\"standard\"` or `\"flat\"`. Persisted as-is; switching to `\"flat\"` does not\nrecompute existing hostnames — use the apply endpoint for that.", + "type": [ + "string", + "null" + ] + }, + "sync_generated_records": { + "description": "Toggle DNS record sync for this domain.", + "type": [ + "boolean", + "null" + ] + } + }, + "type": "object" + }, + "UpdateMcpRequest": { + "properties": { + "config": { + "type": "object" + }, + "description": { + "type": [ + "string", + "null" + ] + }, + "name": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "config" + ], + "type": "object" + }, + "UpdateMemberRoleRequest": { + "description": "The new fixed role for an existing membership.", + "properties": { + "role": { + "$ref": "#/components/schemas/TeamRole" + } + }, + "required": [ + "role" + ], + "type": "object" + }, + "UpdateMetricAlertRequest": { + "properties": { + "aggregation": { + "type": [ + "string", + "null" + ] + }, + "detection_config": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/DetectionConfig", + "description": "Replaces the detector wholesale when present (absent = leave unchanged)." + } + ] + }, + "dynamic_alerts": { + "description": "Toggles per-series (\"dynamic\") alerting (absent = leave unchanged).", + "type": [ + "boolean", + "null" + ] + }, + "enabled": { + "type": [ + "boolean", + "null" + ] + }, + "for_duration_secs": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "group_by": { + "description": "Replaces the group_by keys wholesale when present (absent = leave unchanged).", + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + }, + "grouped_notification_threshold": { + "description": "Updates the notification-grouping threshold (absent = leave unchanged).", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "label_filters": { + "description": "Replaces the label filters wholesale when present (absent = leave unchanged).", + "items": { + "items": false, + "prefixItems": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "type": "array" + }, + "type": [ + "array", + "null" + ] + }, + "max_series": { + "description": "Updates the dynamic-alerting cardinality cap (absent = leave unchanged).", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "metric_name": { + "type": [ + "string", + "null" + ] + }, + "name": { + "type": [ + "string", + "null" + ] + }, + "severity": { + "type": [ + "string", + "null" + ] + }, + "window_secs": { + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + "type": "object" + }, + "UpdateNotificationEmailProviderRequest": { + "properties": { + "config": { + "$ref": "#/components/schemas/EmailConfig" + }, + "enabled": { + "type": [ + "boolean", + "null" + ] + }, + "name": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "config" + ], + "type": "object" + }, + "UpdateOidcProviderRequest": { + "properties": { + "client_id": { + "type": [ + "string", + "null" + ] + }, + "client_secret": { + "type": [ + "string", + "null" + ] + }, + "default_role": { + "type": [ + "string", + "null" + ] + }, + "enabled": { + "type": [ + "boolean", + "null" + ] + }, + "group_claim": { + "type": [ + "string", + "null" + ] + }, + "issuer_url": { + "type": [ + "string", + "null" + ] + }, + "jit_provisioning": { + "type": [ + "boolean", + "null" + ] + }, + "name": { + "type": [ + "string", + "null" + ] + }, + "role_claim": { + "type": [ + "string", + "null" + ] + }, + "scopes": { + "type": [ + "string", + "null" + ] + }, + "template": { + "type": [ + "string", + "null" + ] + }, + "trust_idp_email": { + "type": [ + "boolean", + "null" + ] + } + }, + "type": "object" + }, + "UpdatePreferencesRequest": { + "properties": { + "preferences": { + "$ref": "#/components/schemas/NotificationPreferencesResponse" + } + }, + "required": [ + "preferences" + ], + "type": "object" + }, + "UpdateProjectSecretRequest": { + "description": "Request to update a project secret. The `value` field is optional — omit it\nto rotate only the environment scoping / preview flag without touching the\nciphertext.", + "properties": { + "environment_ids": { + "items": { + "format": "int32", + "type": "integer" + }, + "type": "array" + }, + "include_in_preview": { + "type": "boolean" + }, + "value": { + "description": "New plaintext value, <= 1 MiB. Omit to keep the existing value.", + "type": [ + "string", + "null" + ] + } + }, + "type": "object" + }, + "UpdateProjectSettingsRequest": { + "properties": { + "ai_alert_summaries_enabled": { + "description": "Opt in to AI summarization of metric alert notifications (ADR-021).", + "type": [ + "boolean", + "null" + ] + }, + "ai_debug_chat_enabled": { + "description": "Opt in to AI debugging chat, e.g. on deployment failures (ADR-023).", + "type": [ + "boolean", + "null" + ] + }, + "ai_write_actions_enabled": { + "description": "Opt in to AI propose-then-confirm write capability.", + "type": [ + "boolean", + "null" + ] + }, + "attack_mode": { + "description": "Enable/disable attack mode (CAPTCHA protection) for all project environments", + "type": [ + "boolean", + "null" + ] + }, + "cross_project_trace_sharing": { + "description": "ADR-027 Phase 3 opt-out: set to false to suppress this project's traces\nfrom appearing in cross-project discovery results. Default true (consistent\nwith the OSS global-observability model). Omit to leave unchanged.", + "type": [ + "boolean", + "null" + ] + }, + "directory": { + "type": [ + "string", + "null" + ] + }, + "enable_preview_environments": { + "description": "Enable automatic preview environment creation for each branch", + "type": [ + "boolean", + "null" + ] + }, + "error_source_context_enabled": { + "description": "Opt in to native error-tracking source context (source-file upload +\nsource code shown in stack traces).", + "type": [ + "boolean", + "null" + ] + }, + "error_source_root": { + "description": "Set the auto-capture source root (relative to the checkout). Send an\nempty string to clear it back to the build-context default. Omit to\nleave unchanged.", + "type": [ + "string", + "null" + ] + }, + "git_provider_connection_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "main_branch": { + "type": [ + "string", + "null" + ] + }, + "preset": { + "type": [ + "string", + "null" + ] + }, + "preset_config": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/PresetConfigSchema", + "description": "Preset-specific configuration (e.g., Dockerfile path for Docker preset)\n\nExample for Dockerfile preset:\n```json\n{\n \"dockerfilePath\": \"docker/Dockerfile\",\n \"buildContext\": \"./api\"\n}\n```" + } + ] + }, + "preview_envs_idle_timeout_seconds": { + "description": "Idle timeout (seconds, 60..=86400) for on-demand preview environments.", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "preview_envs_on_demand": { + "description": "When true, newly-created preview environments default to on-demand mode.", + "type": [ + "boolean", + "null" + ] + }, + "preview_envs_wake_timeout_seconds": { + "description": "Wake timeout (seconds, 5..=120) for on-demand preview environments.", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "repo_name": { + "type": [ + "string", + "null" + ] + }, + "repo_owner": { + "type": [ + "string", + "null" + ] + }, + "slug": { + "type": [ + "string", + "null" + ] + } + }, + "type": "object" + }, + "UpdateProviderCredentialsRequest": { + "description": "Partial-update payload for provider credentials. Every field is optional;\nonly the fields the user re-enters are applied. The server validates that\nthe fields supplied make sense for the provider's current auth_method\n(e.g. `app_id` + `private_key` only apply to GitHub Apps).", + "properties": { + "app_id": { + "description": "Application ID (GitHub App integer as string; GitLab App string).", + "type": [ + "string", + "null" + ] + }, + "app_secret": { + "description": "GitLab App secret (not used by GitHub App — use `client_secret`).", + "type": [ + "string", + "null" + ] + }, + "client_id": { + "description": "OAuth client ID (GitLab OAuth, GitHub App).", + "type": [ + "string", + "null" + ] + }, + "client_secret": { + "description": "OAuth client secret (GitLab OAuth, GitHub App).", + "type": [ + "string", + "null" + ] + }, + "private_key": { + "description": "GitHub App private key (PEM).", + "type": [ + "string", + "null" + ] + }, + "redirect_uri": { + "description": "OAuth redirect URI (GitLab OAuth / GitLab App).", + "type": [ + "string", + "null" + ] + }, + "token": { + "description": "PAT for PAT-type providers.", + "type": [ + "string", + "null" + ] + }, + "webhook_secret": { + "description": "GitHub App webhook secret.", + "type": [ + "string", + "null" + ] + } + }, + "type": "object" + }, + "UpdateProviderKeyRequest": { + "properties": { + "api_key": { + "type": [ + "string", + "null" + ] + }, + "base_url": { + "description": "Double-Option: absent = leave unchanged, present-null = clear (revert to\nthe provider's default endpoint), present-value = set.", + "type": [ + "string", + "null" + ] + }, + "default_model": { + "description": "Double-Option: absent = leave unchanged, present-null = clear the pinned\nmodel (revert to the per-provider default), present-value = set.", + "type": [ + "string", + "null" + ] + }, + "display_name": { + "type": [ + "string", + "null" + ] + }, + "is_active": { + "type": [ + "boolean", + "null" + ] + } + }, + "type": "object" + }, + "UpdateProviderRequest": { + "properties": { + "config": {}, + "enabled": { + "type": [ + "boolean", + "null" + ] + }, + "name": { + "type": [ + "string", + "null" + ] + } + }, + "type": "object" + }, + "UpdateRouteRequest": { + "properties": { + "enabled": { + "type": "boolean" + }, + "host": { + "type": "string" + }, + "port": { + "format": "int32", + "type": "integer" + }, + "route_type": { + "description": "Route type: \"http\" (default) matches on HTTP Host header,\n\"tls\" matches on TLS SNI hostname for TCP passthrough", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "host", + "port", + "enabled" + ], + "type": "object" + }, + "UpdateS3SourceRequest": { + "properties": { + "access_key_id": { + "description": "Optional new access key ID", + "example": "AKIAXXXXXXXXXXXXXXXX", + "type": [ + "string", + "null" + ] + }, + "bucket_name": { + "description": "Optional new bucket name", + "type": [ + "string", + "null" + ] + }, + "bucket_path": { + "description": "Optional new bucket path", + "type": [ + "string", + "null" + ] + }, + "endpoint": { + "description": "Optional new endpoint URL for S3-compatible services", + "example": "http://minio.example.com:9000", + "type": [ + "string", + "null" + ] + }, + "force_path_style": { + "description": "Optional new path-style addressing setting", + "example": true, + "type": [ + "boolean", + "null" + ] + }, + "name": { + "description": "Optional new name for the source", + "type": [ + "string", + "null" + ] + }, + "region": { + "description": "Optional new region", + "type": [ + "string", + "null" + ] + }, + "secret_key": { + "description": "Optional new secret key", + "type": [ + "string", + "null" + ] + } + }, + "type": "object" + }, + "UpdateSecretBody": { + "properties": { + "signing_secret": { + "description": "New signing secret from the provider's dashboard. Encrypted at\nrest; never returned in any API response.", + "type": "string" + } + }, + "required": [ + "signing_secret" + ], + "type": "object" + }, + "UpdateSelfRequest": { + "properties": { + "email": { + "example": "john.doe@example.com", + "type": [ + "string", + "null" + ] + }, + "name": { + "example": "John Doe", + "type": [ + "string", + "null" + ] + } + }, + "type": "object" + }, + "UpdateSessionDurationRequest": { + "properties": { + "duration": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "duration" + ], + "type": "object" + }, + "UpdateSessionDurationResponse": { + "properties": { + "message": { + "type": "string" + } + }, + "required": [ + "message" + ], + "type": "object" + }, + "UpdateSkillRequest": { + "properties": { + "content": { + "type": [ + "string", + "null" + ] + }, + "description": { + "type": [ + "string", + "null" + ] + }, + "name": { + "type": [ + "string", + "null" + ] + } + }, + "type": "object" + }, + "UpdateSlackProviderRequest": { + "properties": { + "config": { + "$ref": "#/components/schemas/SlackConfig" + }, + "enabled": { + "type": [ + "boolean", + "null" + ] + }, + "name": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "config" + ], + "type": "object" + }, + "UpdateSpeedMetricsPayload": { + "description": "Update speed metrics payload for late-loading metrics", + "properties": { + "cls": { + "description": "Cumulative Layout Shift (score)", + "format": "float", + "type": [ + "number", + "null" + ] + }, + "inp": { + "description": "Interaction to Next Paint (milliseconds)", + "format": "float", + "type": [ + "number", + "null" + ] + } + }, + "type": "object" + }, + "UpdateStatusResponse": { + "description": "Result of the background release-update check, driving the web console's\nupgrade banner. All optional fields are set together iff\n`update_available` is true.", + "properties": { + "channel": { + "description": "Channel the install tracks: `stable` or `beta`.", + "type": [ + "string", + "null" + ] + }, + "checked_at": { + "description": "When the check that found the update ran (ISO 8601, UTC).", + "type": [ + "string", + "null" + ] + }, + "current_version": { + "description": "Version tag of the running binary, e.g. `v0.1.0-beta.45`.", + "type": [ + "string", + "null" + ] + }, + "docs_url": { + "description": "Docs page with upgrade instructions. Always present so the UI links\nthe same page regardless of update state.", + "type": "string" + }, + "latest_version": { + "description": "Newest published tag on this install's channel.", + "type": [ + "string", + "null" + ] + }, + "release_url": { + "description": "Release-notes page (GitHub release) for the newer version.", + "type": [ + "string", + "null" + ] + }, + "update_available": { + "description": "True when a newer release than the running binary has been published\non this install's channel.", + "type": "boolean" + } + }, + "required": [ + "update_available", + "docs_url" + ], + "type": "object" + }, + "UpdateTeamRequest": { + "properties": { + "description": { + "type": [ + "string", + "null" + ] + }, + "name": { + "type": [ + "string", + "null" + ] + } + }, + "type": "object" + }, + "UpdateTokenRequest": { + "properties": { + "access_token": { + "type": "string" + }, + "refresh_token": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "access_token" + ], + "type": "object" + }, + "UpdateTokenResponse": { + "properties": { + "connection_id": { + "format": "int32", + "type": "integer" + }, + "is_active": { + "type": "boolean" + }, + "message": { + "type": "string" + } + }, + "required": [ + "connection_id", + "message", + "is_active" + ], + "type": "object" + }, + "UpdateUserRequest": { + "properties": { + "email": { + "example": "john.doe@example.com", + "type": [ + "string", + "null" + ] + }, + "name": { + "example": "John Doe", + "type": [ + "string", + "null" + ] + } + }, + "type": "object" + }, + "UpdateWebhookProviderRequest": { + "properties": { + "config": { + "$ref": "#/components/schemas/WebhookConfig" + }, + "enabled": { + "type": [ + "boolean", + "null" + ] + }, + "name": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "config" + ], + "type": "object" + }, + "UpdateWebhookRequestBody": { + "properties": { + "enabled": { + "description": "Whether the webhook is enabled", + "type": [ + "boolean", + "null" + ] + }, + "events": { + "description": "Event types to subscribe to", + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + }, + "secret": { + "description": "Secret for HMAC signature verification", + "type": [ + "string", + "null" + ] + }, + "url": { + "description": "Target URL for webhook delivery", + "type": [ + "string", + "null" + ] + } + }, + "type": "object" + }, + "UpgradeExternalServiceRequest": { + "properties": { + "docker_image": { + "description": "Docker image to upgrade to (e.g., \"gotempsh/postgres-walg:18-bookworm\")\nThis will trigger pg_upgrade for PostgreSQL or equivalent upgrade procedures for other services", + "example": "gotempsh/postgres-walg:18-bookworm", + "type": "string" + } + }, + "required": [ + "docker_image" + ], + "type": "object" + }, + "UpgradeRequest": { + "properties": { + "image": { + "description": "Image reference to pull and run (e.g.\n`ghcr.io/gotempsh/temps-preview-gateway:latest`). Empty resets to default.", + "type": "string" + } + }, + "required": [ + "image" + ], + "type": "object" + }, + "UpsertAgentRequest": { + "properties": { + "ai_model": { + "description": "Preferred model identifier for the CLI. `Some(\"\")` clears the stored value.", + "type": [ + "string", + "null" + ] + }, + "ai_provider": { + "type": [ + "string", + "null" + ] + }, + "ai_provider_key_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "api_key": { + "description": "Plain-text API key — will be encrypted before storage", + "type": [ + "string", + "null" + ] + }, + "branch_prefix": { + "type": [ + "string", + "null" + ] + }, + "config_repo_branch": { + "description": "Branch of the config repo to use (default: \"main\").", + "type": [ + "string", + "null" + ] + }, + "config_repo_url": { + "description": "Private config repo containing .claude/ directory (skills, MCP, plugins).", + "type": [ + "string", + "null" + ] + }, + "cooldown_minutes": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "daily_budget_cents": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "deliverable": { + "type": [ + "string", + "null" + ] + }, + "description": { + "type": [ + "string", + "null" + ] + }, + "enabled": { + "type": [ + "boolean", + "null" + ] + }, + "max_turns": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "mcp_servers_config": { + "description": "MCP servers config (Claude Code settings.json mcpServers format).\nCredential-bearing legacy inline objects are write-only: normal reads\nmask them, and updates must omit this field to preserve existing values." + }, + "name": { + "type": [ + "string", + "null" + ] + }, + "prompt": { + "type": [ + "string", + "null" + ] + }, + "sandbox_enabled": { + "type": [ + "boolean", + "null" + ] + }, + "skills_config": { + "description": "Skills config as JSON array." + }, + "slug": { + "type": [ + "string", + "null" + ] + }, + "timeout_seconds": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "tools_config": { + "description": "Tools config as JSON array. Custom-tool webhook URLs and headers are\nwrite-only; omit this field on update to preserve them." + }, + "trigger_config": { + "description": "Trigger configuration JSON: { \"error\": { \"new_issue\": true, \"regression\": true }, \"manual\": true }" + } + }, + "type": "object" + }, + "UpsertSecretRequest": { + "properties": { + "description": { + "type": [ + "string", + "null" + ] + }, + "mount_path": { + "description": "Required for \"file\" type secrets — absolute path inside the sandbox", + "type": [ + "string", + "null" + ] + }, + "name": { + "type": "string" + }, + "secret_type": { + "description": "\"env\" (environment variable) or \"file\" (written to mount_path)", + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "UptimeDataPoint": { + "properties": { + "error_message": { + "type": [ + "string", + "null" + ] + }, + "response_time_ms": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "status": { + "type": "string" + }, + "timestamp": { + "format": "date-time", + "type": "string" + } + }, + "required": [ + "timestamp", + "status" + ], + "type": "object" + }, + "UptimeHistoryResponse": { + "properties": { + "monitor_id": { + "format": "int32", + "type": "integer" + }, + "uptime_data": { + "items": { + "$ref": "#/components/schemas/UptimeDataPoint" + }, + "type": "array" + } + }, + "required": [ + "monitor_id", + "uptime_data" + ], + "type": "object" + }, + "UsageFilter": { + "description": "Filters for querying AI usage data.\n\nCost bounds are expressed in microcents (the unit stored in\n`estimated_cost_microcents`). At most one of `gte`/`gt` and one of\n`lte`/`lt` is meaningful per query; if both are set the stricter wins\nnaturally because they are ANDead together.", + "properties": { + "conversation_id": { + "type": [ + "string", + "null" + ] + }, + "cost_gt": { + "description": "Cost strictly greater-than, in microcents.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "cost_gte": { + "description": "Cost greater-than-or-equal, in microcents.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "cost_lt": { + "description": "Cost strictly less-than, in microcents.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "cost_lte": { + "description": "Cost less-than-or-equal, in microcents.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "model": { + "type": [ + "string", + "null" + ] + }, + "provider": { + "type": [ + "string", + "null" + ] + }, + "status": { + "description": "Filter by HTTP status code (exact match).", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "tags": { + "description": "Comma-separated tags to filter by (AND logic).", + "type": [ + "string", + "null" + ] + }, + "tokens_gt": { + "description": "Total tokens (input + output) strictly greater-than.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "tokens_gte": { + "description": "Total tokens (input + output) greater-than-or-equal.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "tokens_lt": { + "description": "Total tokens (input + output) strictly less-than.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "tokens_lte": { + "description": "Total tokens (input + output) less-than-or-equal.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "user_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + "type": "object" + }, + "UsageInfo": { + "properties": { + "completion_tokens": { + "format": "int64", + "type": "integer" + }, + "prompt_tokens": { + "format": "int64", + "type": "integer" + }, + "total_tokens": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "prompt_tokens", + "completion_tokens", + "total_tokens" + ], + "type": "object" + }, + "UsageLogEntry": { + "properties": { + "conversation_id": { + "type": [ + "string", + "null" + ] + }, + "estimated_cost_microcents": { + "format": "int64", + "type": "integer" + }, + "id": { + "format": "int64", + "type": "integer" + }, + "input_tokens": { + "format": "int64", + "type": "integer" + }, + "is_byok": { + "type": "boolean" + }, + "is_streaming": { + "type": "boolean" + }, + "latency_ms": { + "format": "int32", + "type": "integer" + }, + "model": { + "type": "string" + }, + "output_tokens": { + "format": "int64", + "type": "integer" + }, + "provider": { + "type": "string" + }, + "request_id": { + "type": [ + "string", + "null" + ] + }, + "status": { + "format": "int32", + "type": "integer" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "timestamp": { + "type": "string" + }, + "trace_id": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "id", + "timestamp", + "provider", + "model", + "input_tokens", + "output_tokens", + "latency_ms", + "estimated_cost_microcents", + "status", + "is_streaming", + "is_byok", + "tags" + ], + "type": "object" + }, + "UsageLogPage": { + "description": "A page of recent usage log entries plus the total count for pagination.", + "properties": { + "entries": { + "description": "The usage log entries for the requested page.", + "items": { + "$ref": "#/components/schemas/UsageLogEntry" + }, + "type": "array" + }, + "total": { + "description": "Total number of entries matching the filter (across all pages).", + "format": "int64", + "type": "integer" + } + }, + "required": [ + "entries", + "total" + ], + "type": "object" + }, + "UsageQueryParams": { + "properties": { + "conversation_id": { + "description": "Filter by conversation ID", + "type": [ + "string", + "null" + ] + }, + "from": { + "description": "ISO 8601 start time (defaults to 24h ago)", + "type": [ + "string", + "null" + ] + }, + "model": { + "description": "Filter by model name", + "type": [ + "string", + "null" + ] + }, + "provider": { + "description": "Filter by provider name", + "type": [ + "string", + "null" + ] + }, + "tags": { + "description": "Filter by tags (comma-separated, AND logic)", + "type": [ + "string", + "null" + ] + }, + "to": { + "description": "ISO 8601 end time (defaults to now)", + "type": [ + "string", + "null" + ] + }, + "user_id": { + "description": "Filter by user ID", + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + "type": "object" + }, + "UsageSource": { + "description": "How the \"actual usage\" numbers were obtained", + "enum": [ + "metrics-api", + "requests-only", + "unavailable" + ], + "type": "string" + }, + "UsageSummary": { + "properties": { + "avg_latency_ms": { + "format": "double", + "type": "number" + }, + "byok_count": { + "format": "int64", + "type": "integer" + }, + "error_count": { + "format": "int64", + "type": "integer" + }, + "streaming_count": { + "format": "int64", + "type": "integer" + }, + "total_cost_microcents": { + "format": "int64", + "type": "integer" + }, + "total_input_tokens": { + "format": "int64", + "type": "integer" + }, + "total_output_tokens": { + "format": "int64", + "type": "integer" + }, + "total_requests": { + "format": "int64", + "type": "integer" + }, + "total_tokens": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "total_requests", + "total_input_tokens", + "total_output_tokens", + "total_tokens", + "avg_latency_ms", + "total_cost_microcents", + "error_count", + "streaming_count", + "byok_count" + ], + "type": "object" + }, + "UserResponse": { + "properties": { + "avatar_url": { + "type": "string" + }, + "email": { + "type": [ + "string", + "null" + ] + }, + "id": { + "format": "int32", + "type": "integer" + }, + "mfa_enabled": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "role": { + "description": "User's role (e.g., \"admin\", \"user\", \"demo\")", + "type": "string" + }, + "username": { + "type": "string" + } + }, + "required": [ + "id", + "username", + "name", + "avatar_url", + "mfa_enabled", + "role" + ], + "type": "object" + }, + "ValidateEmailRequest": { + "additionalProperties": false, + "description": "Request body for validating an email address", + "properties": { + "email": { + "description": "Email address to validate", + "example": "someone@gmail.com", + "type": "string" + } + }, + "required": [ + "email" + ], + "type": "object" + }, + "ValidateEmailResponse": { + "description": "Complete email validation response", + "properties": { + "email": { + "description": "The email address that was validated", + "example": "someone@gmail.com", + "type": "string" + }, + "is_reachable": { + "$ref": "#/components/schemas/ReachabilityStatus", + "description": "Overall reachability status: safe, risky, invalid, or unknown" + }, + "misc": { + "$ref": "#/components/schemas/MiscResult", + "description": "Miscellaneous validation result" + }, + "mx": { + "$ref": "#/components/schemas/MxResult", + "description": "MX record validation result" + }, + "smtp": { + "$ref": "#/components/schemas/SmtpResult", + "description": "SMTP validation result" + }, + "syntax": { + "$ref": "#/components/schemas/SyntaxResult", + "description": "Syntax validation result" + } + }, + "required": [ + "email", + "is_reachable", + "syntax", + "mx", + "misc", + "smtp" + ], + "type": "object" + }, + "ValidationLevel": { + "description": "Validation severity level", + "enum": [ + "info", + "warning", + "error", + "critical" + ], + "type": "string" + }, + "ValidationReport": { + "description": "Complete validation report", + "properties": { + "overall_status": { + "$ref": "#/components/schemas/ValidationStatus", + "description": "Overall status" + }, + "results": { + "description": "All validation results", + "items": { + "$ref": "#/components/schemas/ValidationResult" + }, + "type": "array" + }, + "summary": { + "$ref": "#/components/schemas/ValidationSummary", + "description": "Summary statistics" + } + }, + "required": [ + "results", + "overall_status", + "summary" + ], + "type": "object" + }, + "ValidationResponse": { + "properties": { + "connection_id": { + "format": "int32", + "type": "integer" + }, + "is_valid": { + "type": "boolean" + }, + "message": { + "type": "string" + } + }, + "required": [ + "connection_id", + "is_valid", + "message" + ], + "type": "object" + }, + "ValidationResult": { + "description": "Result of a validation check", + "properties": { + "affected_resources": { + "description": "Affected resources/fields", + "items": { + "type": "string" + }, + "type": "array" + }, + "level": { + "$ref": "#/components/schemas/ValidationLevel", + "description": "Validation level" + }, + "message": { + "description": "Message describing the result", + "type": "string" + }, + "passed": { + "description": "Whether the validation passed", + "type": "boolean" + }, + "remediation": { + "description": "Suggested remediation (if failed)", + "type": [ + "string", + "null" + ] + }, + "rule_id": { + "description": "Rule that was checked", + "type": "string" + }, + "rule_name": { + "description": "Human-readable rule name", + "type": "string" + } + }, + "required": [ + "rule_id", + "rule_name", + "level", + "passed", + "message", + "affected_resources" + ], + "type": "object" + }, + "ValidationStatus": { + "description": "Overall validation status", + "enum": [ + "passed", + "passed-with-warnings", + "failed-with-warnings", + "failed" + ], + "type": "string" + }, + "ValidationSummary": { + "description": "Validation summary statistics", + "properties": { + "critical_count": { + "description": "Critical-level results", + "minimum": 0, + "type": "integer" + }, + "error_count": { + "description": "Error-level results", + "minimum": 0, + "type": "integer" + }, + "failed_count": { + "description": "Validations that failed", + "minimum": 0, + "type": "integer" + }, + "info_count": { + "description": "Info-level results", + "minimum": 0, + "type": "integer" + }, + "passed_count": { + "description": "Validations that passed", + "minimum": 0, + "type": "integer" + }, + "total_count": { + "description": "Total validations run", + "minimum": 0, + "type": "integer" + }, + "warning_count": { + "description": "Warning-level results", + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "total_count", + "passed_count", + "failed_count", + "info_count", + "warning_count", + "error_count", + "critical_count" + ], + "type": "object" + }, + "VerifyMfaRequest": { + "properties": { + "code": { + "type": "string" + } + }, + "required": [ + "code" + ], + "type": "object" + }, + "VerifyStepUpRequest": { + "properties": { + "code": { + "description": "Current TOTP value or an unused recovery code.", + "type": "string" + } + }, + "required": [ + "code" + ], + "type": "object" + }, + "ViewItem": { + "properties": { + "label": { + "format": "date-time", + "type": "string" + }, + "value": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "label", + "value" + ], + "type": "object" + }, + "ViewsOverTime": { + "properties": { + "comparison_labels": { + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + }, + "comparison_plot": { + "items": { + "format": "int64", + "type": "integer" + }, + "type": [ + "array", + "null" + ] + }, + "full_intervals": { + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + }, + "items": { + "items": { + "$ref": "#/components/schemas/ViewItem" + }, + "type": "array" + }, + "metric": { + "type": "string" + }, + "present_index": { + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "items", + "metric", + "present_index" + ], + "type": "object" + }, + "ViewsOverTimeQuery": { + "properties": { + "deployment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "end_date": { + "format": "date-time", + "type": "string" + }, + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "start_date": { + "format": "date-time", + "type": "string" + } + }, + "required": [ + "start_date", + "end_date", + "project_id" + ], + "type": "object" + }, + "VisitorDetails": { + "properties": { + "city": { + "type": [ + "string", + "null" + ] + }, + "country": { + "type": [ + "string", + "null" + ] + }, + "country_code": { + "type": [ + "string", + "null" + ] + }, + "crawler_name": { + "type": [ + "string", + "null" + ] + }, + "custom_data": {}, + "environment_id": { + "format": "int32", + "type": "integer" + }, + "first_channel": { + "description": "Marketing channel from the first visit (e.g. \"Organic Search\", \"Direct\")", + "type": [ + "string", + "null" + ] + }, + "first_referrer": { + "description": "Full referrer URL from the visitor's first session", + "type": [ + "string", + "null" + ] + }, + "first_referrer_hostname": { + "description": "Hostname extracted from first_referrer", + "type": [ + "string", + "null" + ] + }, + "first_seen": { + "example": "2024-01-01T00:00:00", + "format": "date-time", + "type": "string" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "ip_address": { + "type": [ + "string", + "null" + ] + }, + "ip_address_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "is_crawler": { + "type": "boolean" + }, + "is_eu": { + "type": [ + "boolean", + "null" + ] + }, + "last_seen": { + "example": "2024-01-01T00:00:00", + "format": "date-time", + "type": "string" + }, + "latitude": { + "format": "double", + "type": [ + "number", + "null" + ] + }, + "longitude": { + "format": "double", + "type": [ + "number", + "null" + ] + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "region": { + "type": [ + "string", + "null" + ] + }, + "timezone": { + "type": [ + "string", + "null" + ] + }, + "user_agent": { + "type": [ + "string", + "null" + ] + }, + "visitor_id": { + "type": "string" + } + }, + "required": [ + "id", + "visitor_id", + "project_id", + "environment_id", + "first_seen", + "last_seen", + "is_crawler" + ], + "type": "object" + }, + "VisitorFacetValue": { + "description": "A single facet value with its visitor count. Used to populate filter\ndropdowns on the visitors page (e.g. \"Germany — 1,234 visitors\").", + "properties": { + "code": { + "description": "Optional secondary code for the value. Currently only populated for\nthe `country` facet, where it carries the 2-letter ISO country code\nso the UI can render a flag without re-mapping.", + "type": [ + "string", + "null" + ] + }, + "count": { + "description": "Distinct visitor count matching this value in the current segment.", + "format": "int64", + "type": "integer" + }, + "value": { + "description": "The dimension value (e.g. \"United States\", \"Chrome\", \"google.com\").\n`None` is encoded as the literal string \"Direct\" for referrer and as\nthe empty string for the rest.", + "type": "string" + } + }, + "required": [ + "value", + "count" + ], + "type": "object" + }, + "VisitorFacets": { + "description": "All filter dropdown contents in one response. Each list is the top N\nvalues for that dimension within the current date range and segment\n(excluding the dimension being queried so the dropdown still shows\nalternatives when a value is already selected).", + "properties": { + "channel": { + "items": { + "$ref": "#/components/schemas/VisitorFacetValue" + }, + "type": "array" + }, + "city": { + "items": { + "$ref": "#/components/schemas/VisitorFacetValue" + }, + "type": "array" + }, + "country": { + "items": { + "$ref": "#/components/schemas/VisitorFacetValue" + }, + "type": "array" + }, + "referrer": { + "items": { + "$ref": "#/components/schemas/VisitorFacetValue" + }, + "type": "array" + }, + "region": { + "items": { + "$ref": "#/components/schemas/VisitorFacetValue" + }, + "type": "array" + } + }, + "required": [ + "country", + "region", + "city", + "channel", + "referrer" + ], + "type": "object" + }, + "VisitorFacetsQuery": { + "allOf": [ + { + "$ref": "#/components/schemas/VisitorSegmentFilters" + }, + { + "properties": { + "end_date": { + "format": "date-time", + "type": "string" + }, + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "has_activity_only": { + "type": [ + "boolean", + "null" + ] + }, + "include_crawlers": { + "type": [ + "boolean", + "null" + ] + }, + "per_facet_limit": { + "description": "Maximum number of values returned per dimension (default: 50, max: 200).", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "start_date": { + "format": "date-time", + "type": "string" + } + }, + "required": [ + "start_date", + "end_date", + "project_id" + ], + "type": "object" + } + ], + "description": "Query parameters for the visitor-facets endpoint. Mirrors the shape of\n`VisitorsListQuery` so the same segment filters apply — facet counts are\nalways computed against the *currently filtered* visitor pool, minus the\ndimension being aggregated." + }, + "VisitorInfo": { + "properties": { + "city": { + "type": [ + "string", + "null" + ] + }, + "country": { + "type": [ + "string", + "null" + ] + }, + "country_code": { + "type": [ + "string", + "null" + ] + }, + "crawler_name": { + "type": [ + "string", + "null" + ] + }, + "current_page": { + "description": "Most recent page path visited by this visitor", + "type": [ + "string", + "null" + ] + }, + "custom_data": {}, + "environment_id": { + "format": "int32", + "type": "integer" + }, + "first_channel": { + "description": "Marketing channel from the first visit (e.g. \"Organic Search\", \"Direct\")", + "type": [ + "string", + "null" + ] + }, + "first_referrer": { + "description": "Full referrer URL from the visitor's first session", + "type": [ + "string", + "null" + ] + }, + "first_referrer_hostname": { + "description": "Hostname extracted from first_referrer", + "type": [ + "string", + "null" + ] + }, + "first_seen": { + "example": "2024-01-01T00:00:00", + "format": "date-time", + "type": "string" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "ip_address": { + "type": [ + "string", + "null" + ] + }, + "ip_address_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "is_crawler": { + "type": "boolean" + }, + "is_eu": { + "type": [ + "boolean", + "null" + ] + }, + "last_seen": { + "example": "2024-01-01T00:00:00", + "format": "date-time", + "type": "string" + }, + "latitude": { + "format": "double", + "type": [ + "number", + "null" + ] + }, + "longitude": { + "format": "double", + "type": [ + "number", + "null" + ] + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "region": { + "type": [ + "string", + "null" + ] + }, + "timezone": { + "type": [ + "string", + "null" + ] + }, + "user_agent": { + "type": [ + "string", + "null" + ] + }, + "visitor_id": { + "type": "string" + } + }, + "required": [ + "id", + "visitor_id", + "project_id", + "environment_id", + "first_seen", + "last_seen", + "is_crawler" + ], + "type": "object" + }, + "VisitorJourneyQuery": { + "properties": { + "limit_sessions": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "project_id": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "project_id" + ], + "type": "object" + }, + "VisitorJourneyResponse": { + "description": "Complete visitor journey response", + "properties": { + "sessions": { + "description": "Sessions with their events, ordered newest first", + "items": { + "$ref": "#/components/schemas/JourneySession" + }, + "type": "array" + }, + "total_events": { + "description": "Total number of events across all sessions", + "format": "int64", + "type": "integer" + }, + "total_sessions": { + "description": "Total number of sessions", + "format": "int64", + "type": "integer" + }, + "visitor_id": { + "description": "Visitor internal ID", + "format": "int32", + "type": "integer" + } + }, + "required": [ + "visitor_id", + "total_sessions", + "total_events", + "sessions" + ], + "type": "object" + }, + "VisitorLocationsQuery": { + "properties": { + "end_date": { + "format": "date-time", + "type": "string" + }, + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "granularity": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/LocationGranularity" + } + ] + }, + "limit": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "start_date": { + "format": "date-time", + "type": "string" + } + }, + "required": [ + "start_date", + "end_date", + "project_id" + ], + "type": "object" + }, + "VisitorRecord": { + "properties": { + "created_at": { + "example": "2024-01-01T00:00:00", + "format": "date-time", + "type": "string" + }, + "custom_data": {}, + "id": { + "format": "int32", + "type": "integer" + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "visitor_id": { + "type": "string" + } + }, + "required": [ + "id", + "visitor_id", + "project_id", + "created_at" + ], + "type": "object" + }, + "VisitorSegmentFilters": { + "description": "Optional segment filters for [`VisitorsListQuery`]. Each filter narrows the\nresult set to visitors who match the given dimension value within the date\nrange. All filters resolve against `visitor` / `ip_geolocations` — by\ndesign we never touch the events hypertable here so filtering stays fast\nregardless of event volume.", + "properties": { + "filter_channel": { + "description": "First-touch marketing channel (matches `visitor.first_channel`)", + "type": [ + "string", + "null" + ] + }, + "filter_city": { + "description": "Geolocation city (matches `ip_geolocations.city`)", + "type": [ + "string", + "null" + ] + }, + "filter_country": { + "description": "Geolocation country (matches `ip_geolocations.country`)", + "type": [ + "string", + "null" + ] + }, + "filter_referrer": { + "description": "First-touch referrer hostname (matches `visitor.first_referrer_hostname`)", + "type": [ + "string", + "null" + ] + }, + "filter_region": { + "description": "Geolocation region (matches `ip_geolocations.region`)", + "type": [ + "string", + "null" + ] + } + }, + "type": "object" + }, + "VisitorSessionsQuery": { + "properties": { + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "limit": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "project_id": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "project_id" + ], + "type": "object" + }, + "VisitorSessionsResponse": { + "properties": { + "sessions": { + "items": { + "$ref": "#/components/schemas/SessionSummary" + }, + "type": "array" + }, + "total_sessions": { + "format": "int64", + "type": "integer" + }, + "visitor_id": { + "type": "string" + } + }, + "required": [ + "visitor_id", + "sessions", + "total_sessions" + ], + "type": "object" + }, + "VisitorStats": { + "properties": { + "average_session_duration": { + "format": "double", + "type": "number" + }, + "bounce_rate": { + "format": "double", + "type": "number" + }, + "devices_used": { + "items": { + "type": "string" + }, + "type": "array" + }, + "engagement_rate": { + "format": "double", + "type": "number" + }, + "first_seen": { + "example": "2024-01-01T00:00:00", + "format": "date-time", + "type": "string" + }, + "last_seen": { + "example": "2024-01-01T00:00:00", + "format": "date-time", + "type": "string" + }, + "locations": { + "items": { + "$ref": "#/components/schemas/LocationInfo" + }, + "type": "array" + }, + "top_pages": { + "items": { + "$ref": "#/components/schemas/PageVisit" + }, + "type": "array" + }, + "top_referrers": { + "items": { + "type": "string" + }, + "type": "array" + }, + "total_events": { + "format": "int64", + "type": "integer" + }, + "total_page_views": { + "format": "int64", + "type": "integer" + }, + "total_sessions": { + "format": "int64", + "type": "integer" + }, + "visitor_id": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "visitor_id", + "first_seen", + "last_seen", + "total_sessions", + "total_page_views", + "total_events", + "average_session_duration", + "bounce_rate", + "engagement_rate", + "top_pages", + "top_referrers", + "devices_used", + "locations" + ], + "type": "object" + }, + "VisitorWithGeolocation": { + "properties": { + "city": { + "type": [ + "string", + "null" + ] + }, + "country": { + "type": [ + "string", + "null" + ] + }, + "country_code": { + "type": [ + "string", + "null" + ] + }, + "crawler_name": { + "type": [ + "string", + "null" + ] + }, + "custom_data": {}, + "environment_id": { + "format": "int32", + "type": "integer" + }, + "first_channel": { + "description": "Marketing channel from the first visit (e.g. \"Organic Search\", \"Direct\")", + "type": [ + "string", + "null" + ] + }, + "first_referrer": { + "description": "Full referrer URL from the visitor's first session", + "type": [ + "string", + "null" + ] + }, + "first_referrer_hostname": { + "description": "Hostname extracted from first_referrer", + "type": [ + "string", + "null" + ] + }, + "first_seen": { + "example": "2024-01-01T00:00:00", + "format": "date-time", + "type": "string" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "ip_address": { + "type": [ + "string", + "null" + ] + }, + "is_crawler": { + "type": "boolean" + }, + "is_eu": { + "type": [ + "boolean", + "null" + ] + }, + "last_seen": { + "example": "2024-01-01T00:00:00", + "format": "date-time", + "type": "string" + }, + "latitude": { + "format": "double", + "type": [ + "number", + "null" + ] + }, + "longitude": { + "format": "double", + "type": [ + "number", + "null" + ] + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "region": { + "type": [ + "string", + "null" + ] + }, + "timezone": { + "type": [ + "string", + "null" + ] + }, + "user_agent": { + "type": [ + "string", + "null" + ] + }, + "visitor_id": { + "type": "string" + } + }, + "required": [ + "id", + "visitor_id", + "project_id", + "environment_id", + "first_seen", + "last_seen", + "is_crawler" + ], + "type": "object" + }, + "VisitorsListQuery": { + "allOf": [ + { + "$ref": "#/components/schemas/VisitorSegmentFilters" + }, + { + "properties": { + "end_date": { + "format": "date-time", + "type": "string" + }, + "environment_id": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "has_activity_only": { + "description": "Filter to only include visitors with recorded activity (events/sessions).\nWhen true, excludes \"ghost\" visitors that have no events.", + "type": [ + "boolean", + "null" + ] + }, + "include_crawlers": { + "type": [ + "boolean", + "null" + ] + }, + "limit": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "offset": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "start_date": { + "format": "date-time", + "type": "string" + } + }, + "required": [ + "start_date", + "end_date", + "project_id" + ], + "type": "object" + } + ] + }, + "VisitorsResponse": { + "properties": { + "filtered_count": { + "format": "int64", + "type": "integer" + }, + "total_count": { + "format": "int64", + "type": "integer" + }, + "visitors": { + "items": { + "$ref": "#/components/schemas/VisitorInfo" + }, + "type": "array" + } + }, + "required": [ + "visitors", + "total_count", + "filtered_count" + ], + "type": "object" + }, + "VolumeMount": { + "description": "Volume mount in deployment", + "properties": { + "destination": { + "description": "Destination path in container", + "type": "string" + }, + "read_only": { + "description": "Read-only flag", + "type": "boolean" + }, + "source": { + "description": "Source (volume name or path)", + "type": "string" + }, + "type": { + "$ref": "#/components/schemas/VolumeType", + "description": "Volume type" + } + }, + "required": [ + "source", + "destination", + "read_only", + "type" + ], + "type": "object" + }, + "VolumeType": { + "description": "Volume type", + "enum": [ + "bind", + "volume", + "tmpfs" + ], + "type": "string" + }, + "VulnerabilityResponse": { + "properties": { + "class": { + "example": "os-pkgs", + "type": [ + "string", + "null" + ] + }, + "created_at": { + "example": "2025-12-08T12:15:47.609192Z", + "type": "string" + }, + "cvss_score": { + "format": "float", + "type": [ + "number", + "null" + ] + }, + "description": { + "type": [ + "string", + "null" + ] + }, + "fixed_version": { + "type": [ + "string", + "null" + ] + }, + "id": { + "format": "int32", + "type": "integer" + }, + "installed_version": { + "type": "string" + }, + "last_modified_date": { + "example": "2025-12-08T12:15:47.609192Z", + "type": [ + "string", + "null" + ] + }, + "package_name": { + "type": "string" + }, + "primary_url": { + "type": [ + "string", + "null" + ] + }, + "published_date": { + "example": "2025-12-08T12:15:47.609192Z", + "type": [ + "string", + "null" + ] + }, + "references": {}, + "scan_id": { + "format": "int32", + "type": "integer" + }, + "severity": { + "type": "string" + }, + "target": { + "example": "alpine:3.18 (alpine 3.18.0)", + "type": [ + "string", + "null" + ] + }, + "title": { + "type": "string" + }, + "type": { + "example": "alpine", + "type": [ + "string", + "null" + ] + }, + "vulnerability_id": { + "type": "string" + } + }, + "required": [ + "id", + "scan_id", + "vulnerability_id", + "package_name", + "installed_version", + "severity", + "title", + "created_at" + ], + "type": "object" + }, + "WalWarning": { + "description": "One actionable warning surfaced to the UI.\n\nEach variant carries the data needed to render a remediation hint without\nthe frontend re-querying anything.", + "oneOf": [ + { + "description": "`pg_wal` is significantly larger than `max_wal_size`.", + "properties": { + "kind": { + "enum": [ + "wal_bloat" + ], + "type": "string" + }, + "max_wal_size_bytes": { + "format": "int64", + "type": "integer" + }, + "pg_wal_bytes": { + "format": "int64", + "type": "integer" + }, + "ratio": { + "format": "double", + "type": "number" + } + }, + "required": [ + "pg_wal_bytes", + "max_wal_size_bytes", + "ratio", + "kind" + ], + "type": "object" + }, + { + "description": "A replication slot is holding WAL it's not consuming.", + "properties": { + "active": { + "type": "boolean" + }, + "kind": { + "enum": [ + "stale_slot" + ], + "type": "string" + }, + "retained_bytes": { + "format": "int64", + "type": "integer" + }, + "slot_name": { + "type": "string" + } + }, + "required": [ + "slot_name", + "retained_bytes", + "active", + "kind" + ], + "type": "object" + }, + { + "description": "`archive_status/*.ready` count exceeds threshold — `archive_command`\nis either failing or running slower than WAL generation.", + "properties": { + "kind": { + "enum": [ + "archive_backlog" + ], + "type": "string" + }, + "ready_count": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "ready_count", + "kind" + ], + "type": "object" + }, + { + "description": "`archive_mode = on` but `archive_command` is empty / `/bin/true`.\nWAL accumulates forever waiting for a destination that never accepts.", + "properties": { + "kind": { + "enum": [ + "archive_mode_without_command" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "type": "object" + }, + { + "description": "Oldest WAL segment is older than `WAL_NOT_RECYCLED_AGE_SECS`.\nIndependent signal: something is blocking recycling even if total\nsize hasn't exploded yet.", + "properties": { + "kind": { + "enum": [ + "wal_not_recycled" + ], + "type": "string" + }, + "oldest_age_secs": { + "format": "int64", + "type": "integer" + } + }, + "required": [ + "oldest_age_secs", + "kind" + ], + "type": "object" + } + ] + }, + "WalWarningSeverity": { + "enum": [ + "warning", + "critical" + ], + "type": "string" + }, + "WebhookConfig": { + "description": "Configuration for a generic webhook notification provider", + "properties": { + "headers": { + "additionalProperties": { + "type": "string" + }, + "description": "Custom headers to include in the request (e.g., for authentication tokens)", + "example": { + "Authorization": "Bearer your-token", + "X-Custom-Header": "custom-value" + }, + "propertyNames": { + "type": "string" + }, + "type": "object" + }, + "method": { + "description": "HTTP method to use (POST, PUT, PATCH). Defaults to POST.", + "example": "POST", + "type": "string" + }, + "timeout_secs": { + "description": "Request timeout in seconds. Defaults to 30.", + "example": 30, + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "url": { + "description": "The URL to send webhook requests to", + "example": "https://api.example.com/notifications", + "type": "string" + } + }, + "required": [ + "url" + ], + "type": "object" + }, + "WebhookDeliveryResponse": { + "properties": { + "attempt_number": { + "format": "int32", + "type": "integer" + }, + "created_at": { + "example": "2025-10-12T12:15:47.609192Z", + "format": "date-time", + "type": "string" + }, + "delivered_at": { + "format": "date-time", + "type": [ + "string", + "null" + ] + }, + "error_message": { + "type": [ + "string", + "null" + ] + }, + "event_id": { + "type": "string" + }, + "event_type": { + "type": "string" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "payload": { + "description": "JSON payload that was sent to the webhook endpoint", + "example": { + "data": { + "deployment_id": 123 + }, + "event_type": "deployment.succeeded" + }, + "type": "string" + }, + "status_code": { + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "success": { + "type": "boolean" + }, + "webhook_id": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "id", + "webhook_id", + "event_type", + "event_id", + "payload", + "success", + "attempt_number", + "created_at" + ], + "type": "object" + }, + "WebhookResponse": { + "properties": { + "created_at": { + "example": "2025-10-12T12:15:47.609192Z", + "format": "date-time", + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "events": { + "items": { + "type": "string" + }, + "type": "array" + }, + "has_secret": { + "type": "boolean" + }, + "id": { + "format": "int32", + "type": "integer" + }, + "project_id": { + "format": "int32", + "type": "integer" + }, + "updated_at": { + "example": "2025-10-12T12:15:47.609192Z", + "format": "date-time", + "type": "string" + }, + "url": { + "type": "string" + } + }, + "required": [ + "id", + "project_id", + "url", + "events", + "enabled", + "has_secret", + "created_at", + "updated_at" + ], + "type": "object" + }, + "WebhookTriggerRequest": { + "allOf": [ + { + "description": "Arbitrary JSON payload from the caller. Passed to the agent as user_context." + } + ] + }, + "WebhookTriggerResponse": { + "properties": { + "run_id": { + "format": "int32", + "type": "integer" + }, + "status": { + "type": "string" + } + }, + "required": [ + "run_id", + "status" + ], + "type": "object" + }, + "WorkflowDryRunRequest": { + "properties": { + "cpu_limit": { + "description": "Optional CPU override applied after parsing YAML (clamped server-side).\nWhen `Some`, this takes precedence over `cpu_limit` inside the YAML —\nlets the CLI pass `--cpu` without rewriting the YAML text.", + "format": "double", + "type": [ + "number", + "null" + ] + }, + "error_group_id": { + "description": "Optional error group to link this dry-run to. When set, the executor's\n`load_error_context` path injects `{{error_type}}` / `{{error_message}}`\n/ `{{stack_trace}}` into the prompt — same behaviour as a committed\nworkflow triggered with `trigger_source_type = \"error_group\"`. Must\nbelong to `project_id` (handler enforces).", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "memory_limit_mb": { + "description": "Optional memory override in MB (clamped server-side). Same precedence\nrule as `cpu_limit`.", + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "user_context": { + "description": "Optional context appended to the prompt (e.g. \"test against staging\nonly\"). Mirrors `TriggerAgentRequest.user_context`.", + "type": [ + "string", + "null" + ] + }, + "yaml": { + "description": "Full WorkflowYamlConfig as YAML text. Server validates and re-serializes\nbefore storing on the run row.", + "type": "string" + } + }, + "required": [ + "yaml" + ], + "type": "object" + }, + "WorkloadDescriptor": { + "description": "Brief descriptor for discovered workloads (used in listing)", + "properties": { + "created_at": { + "description": "Creation timestamp", + "format": "date-time", + "type": [ + "string", + "null" + ] + }, + "id": { + "$ref": "#/components/schemas/WorkloadId", + "description": "Unique ID in source system" + }, + "image": { + "description": "Image/build reference (for containers)", + "type": [ + "string", + "null" + ] + }, + "labels": { + "additionalProperties": { + "type": "string" + }, + "description": "Labels/tags from source system", + "propertyNames": { + "type": "string" + }, + "type": "object" + }, + "name": { + "description": "Workload name (if any)", + "type": [ + "string", + "null" + ] + }, + "status": { + "$ref": "#/components/schemas/WorkloadStatus", + "description": "Current status" + }, + "workload_type": { + "$ref": "#/components/schemas/WorkloadType", + "description": "Workload type (container, function, static-site, etc.)" + } + }, + "required": [ + "id", + "workload_type", + "status", + "labels" + ], + "type": "object" + }, + "WorkloadId": { + "description": "Unique identifier for a workload in the source system", + "type": "string" + }, + "WorkloadStatus": { + "description": "Workload status in source system", + "enum": [ + "running", + "paused", + "stopped", + "exited", + "failed", + "deployed", + "building", + "unknown" + ], + "type": "string" + }, + "WorkloadType": { + "description": "Workload type", + "enum": [ + "container", + "function", + "static-site", + "server-side-app", + "worker", + "database", + "message-queue", + "cache", + "cron-job", + "other" + ], + "type": "string" + }, + "WriteFileBody": { + "additionalProperties": false, + "properties": { + "contents_b64": { + "description": "File contents, base64-encoded. Required — lets callers ship binary\ndata over JSON without charset games.", + "type": "string" + }, + "mode": { + "description": "Unix permission mask (e.g. 0o644). Defaults to 0o644 when absent.", + "format": "int32", + "minimum": 0, + "type": [ + "integer", + "null" + ] + }, + "path": { + "description": "Absolute path inside the sandbox. Must start with `/`.", + "type": "string" + } + }, + "required": [ + "path", + "contents_b64" + ], + "type": "object" + }, + "WriteFilesBody": { + "additionalProperties": false, + "properties": { + "files": { + "description": "List of files to write. Each entry must include an absolute\n`path` and base64-encoded `contents_b64`. Empty list is a no-op.", + "items": { + "$ref": "#/components/schemas/WriteFileBody" + }, + "type": "array" + } + }, + "required": [ + "files" + ], + "type": "object" + }, + "WriteFilesResponse": { + "properties": { + "written": { + "description": "Number of files successfully written before the first failure\n(if any). On full success this equals `files.len()`.", + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "written" + ], + "type": "object" + }, + "ZoneListResponse": { + "description": "Zone list response", + "properties": { + "zones": { + "items": { + "$ref": "#/components/schemas/DnsZone" + }, + "type": "array" + } + }, + "required": [ + "zones" + ], + "type": "object" + } + }, + "securitySchemes": { + "bearer_auth": { + "description": "Bearer token authentication. Use format: `Bearer `. Supports API keys (starting with `tk_`), CLI tokens, and session tokens.", + "scheme": "bearer", + "type": "http" + } + } + }, + "info": { + "contact": { + "name": "Temps Support", + "url": "https://temps.sh" + }, + "description": "An API for managing projects, deployments, and infrastructure resources", + "title": "Temps", + "version": "1.0.0" + }, + "openapi": "3.1.0", + "paths": { + "/.well-known/temps.json": { + "get": { + "operationId": "get_platform_info", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PlatformInfo" + } + } + }, + "description": "Successfully retrieved platform information" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get platform information", + "tags": [ + "Platform" + ] + } + }, + "/0/organizations/{org_slug}/chunk-upload/": { + "get": { + "description": "sentry-cli checks this endpoint to determine if chunk-based upload is supported.\nWe return a response indicating that chunk upload is NOT supported, which forces\nsentry-cli to fall back to the standard file-by-file upload.", + "operationId": "chunk_upload_options", + "parameters": [ + { + "description": "Organization slug (ignored)", + "in": "path", + "name": "org_slug", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SentryChunkUploadResponse" + } + } + }, + "description": "Chunk upload options" + } + }, + "summary": "Chunk upload options (stub for sentry-cli compatibility).", + "tags": [ + "sentry-compat" + ] + } + }, + "/0/organizations/{org_slug}/releases/": { + "post": { + "description": "sentry-cli calls this before uploading files. Since Temps implicitly creates\nreleases when source maps are uploaded, this is a no-op that returns the\nexpected response format.", + "operationId": "create_release", + "parameters": [ + { + "description": "Organization slug (ignored in single-tenant mode)", + "in": "path", + "name": "org_slug", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SentryCreateReleaseRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SentryReleaseResponse" + } + } + }, + "description": "Release created" + }, + "401": { + "description": "Unauthorized" + } + }, + "summary": "Create a release (stub for sentry-cli compatibility).", + "tags": [ + "sentry-compat" + ] + } + }, + "/0/projects/{org_slug}/{project_slug}/releases/": { + "post": { + "description": "sentry-cli calls this endpoint (instead of /organizations/.../releases/) when\nboth SENTRY_ORG and SENTRY_PROJECT env vars are set. Behaves identically to\nthe organizations endpoint but validates the project slug.", + "operationId": "create_project_release", + "parameters": [ + { + "description": "Organization slug (ignored in single-tenant mode)", + "in": "path", + "name": "org_slug", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Project slug or numeric ID", + "in": "path", + "name": "project_slug", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SentryCreateReleaseRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SentryReleaseResponse" + } + } + }, + "description": "Release created" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Project not found" + } + }, + "summary": "Create a release for a specific project (stub for sentry-cli compatibility).", + "tags": [ + "sentry-compat" + ] + } + }, + "/0/projects/{org_slug}/{project_slug}/releases/{version}/": { + "put": { + "description": "sentry-cli calls `releases finalize` after uploading source maps. This sets\nthe dateReleased on the release. Since Temps stores source maps independently\nof releases, this is a no-op that returns the expected response.", + "operationId": "finalize_project_release", + "parameters": [ + { + "description": "Organization slug (ignored)", + "in": "path", + "name": "org_slug", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Project slug or numeric ID", + "in": "path", + "name": "project_slug", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Release version to finalize", + "in": "path", + "name": "version", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SentryReleaseResponse" + } + } + }, + "description": "Release finalized" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Project not found" + } + }, + "summary": "Finalize a release (stub for sentry-cli compatibility).", + "tags": [ + "sentry-compat" + ] + } + }, + "/0/projects/{org_slug}/{project_slug}/releases/{version}/files/": { + "get": { + "description": "Returns all source maps stored for a specific release in sentry-cli compatible format.", + "operationId": "list_release_files", + "parameters": [ + { + "description": "Organization slug (ignored)", + "in": "path", + "name": "org_slug", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Project slug or numeric ID", + "in": "path", + "name": "project_slug", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Release version", + "in": "path", + "name": "version", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/SentryReleaseFileResponse" + }, + "type": "array" + } + } + }, + "description": "List of release files" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Project not found" + } + }, + "summary": "List files for a release.", + "tags": [ + "sentry-compat" + ] + }, + "post": { + "description": "Accepts the same multipart format as the Sentry release files API.\nThe `name` field should be the URL path of the file (e.g., `~/dist/bundle.js.map`).\n\nThe route has a 50 MiB body limit applied at the router level (Fix #4).\nA per-field size check provides an additional defense-in-depth layer.", + "operationId": "upload_release_file", + "parameters": [ + { + "description": "Organization slug (ignored)", + "in": "path", + "name": "org_slug", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Project slug or numeric ID", + "in": "path", + "name": "project_slug", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Release version", + "in": "path", + "name": "version", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SentryReleaseFileResponse" + } + } + }, + "description": "File uploaded" + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Project not found" + }, + "413": { + "description": "Source map file exceeds the 50 MiB per-field limit" + } + }, + "summary": "Upload a source map file for a release.", + "tags": [ + "sentry-compat" + ] + } + }, + "/_temps/event": { + "post": { + "operationId": "record_event_metrics", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EventMetricsPayload" + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Event recorded successfully" + }, + "400": { + "description": "Bad request" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Record analytics event", + "tags": [ + "Metrics" + ] + } + }, + "/_temps/session-replay/events": { + "post": { + "operationId": "add_session_replay_events", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SessionReplayEventsRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AddEventsResponse" + } + } + }, + "description": "Events added successfully" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Bad request" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Session not found" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Internal server error" + } + }, + "summary": "Add events to existing session replay", + "tags": [ + "Analytics" + ] + } + }, + "/_temps/session-replay/init": { + "post": { + "operationId": "init_session_replay", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SessionReplayInitRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SessionReplayInitResponse" + } + } + }, + "description": "Session initialized successfully" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Bad request" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Internal server error" + } + }, + "summary": "Initialize session replay with metadata", + "tags": [ + "Analytics" + ] + } + }, + "/_temps/speed": { + "post": { + "operationId": "record_speed_metrics", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SpeedMetricsPayload" + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Metrics recorded successfully" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Bad request" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Host not found in route table" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Internal server error" + } + }, + "summary": "Record performance metrics from client", + "tags": [ + "Performance" + ] + } + }, + "/_temps/speed/update": { + "post": { + "operationId": "update_speed_metrics", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateSpeedMetricsPayload" + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Metrics updated successfully" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Bad request" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Host not found or metrics not found" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Internal server error" + } + }, + "summary": "Update late performance metrics", + "tags": [ + "Performance" + ] + } + }, + "/admin/gate-settings": { + "get": { + "operationId": "get_admin_gate", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AdminGateResponse" + } + } + }, + "description": "Current admin gate config" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "AdminGate" + ] + }, + "patch": { + "operationId": "patch_admin_gate", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateAdminGateRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AdminGateResponse" + } + } + }, + "description": "Updated admin gate config" + }, + "400": { + "description": "Invalid IP/CIDR/host" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "409": { + "description": "Env-overridden or would lock out caller" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "AdminGate" + ] + } + }, + "/admin/oidc/providers": { + "get": { + "operationId": "list_oidc_providers", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/OidcProviderResponse" + }, + "type": "array" + } + } + }, + "description": "OIDC providers" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Authentication" + ] + }, + "post": { + "operationId": "create_oidc_provider", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateOidcProviderRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OidcProviderResponse" + } + } + }, + "description": "OIDC provider created" + }, + "409": { + "description": "Another OIDC provider already uses that name" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Authentication" + ] + } + }, + "/admin/oidc/providers/{provider_id}": { + "delete": { + "operationId": "delete_oidc_provider", + "parameters": [ + { + "in": "path", + "name": "provider_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "OIDC provider deleted" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Authentication" + ] + }, + "patch": { + "operationId": "update_oidc_provider", + "parameters": [ + { + "in": "path", + "name": "provider_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateOidcProviderRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OidcProviderResponse" + } + } + }, + "description": "OIDC provider updated" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Authentication" + ] + } + }, + "/admin/oidc/providers/{provider_id}/role-mappings": { + "get": { + "operationId": "list_oidc_role_mappings", + "parameters": [ + { + "in": "path", + "name": "provider_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/OidcRoleMappingResponse" + }, + "type": "array" + } + } + }, + "description": "OIDC role mappings" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Authentication" + ] + }, + "post": { + "operationId": "create_oidc_role_mapping", + "parameters": [ + { + "in": "path", + "name": "provider_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateOidcRoleMappingRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OidcRoleMappingResponse" + } + } + }, + "description": "Role mapping created" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Authentication" + ] + } + }, + "/admin/oidc/providers/{provider_id}/test": { + "post": { + "operationId": "test_oidc_provider", + "parameters": [ + { + "in": "path", + "name": "provider_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OidcTestConnectionResponse" + } + } + }, + "description": "Connection test result" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Authentication" + ] + } + }, + "/admin/oidc/providers/{provider_id}/users": { + "get": { + "operationId": "list_oidc_provider_users", + "parameters": [ + { + "description": "OIDC provider ID", + "in": "path", + "name": "provider_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/OidcProviderUserResponse" + }, + "type": "array" + } + } + }, + "description": "Users authenticated via this OIDC provider" + }, + "404": { + "description": "Provider not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Authentication" + ] + } + }, + "/admin/oidc/role-mappings/{mapping_id}": { + "delete": { + "operationId": "delete_oidc_role_mapping", + "parameters": [ + { + "in": "path", + "name": "mapping_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "Role mapping deleted" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Authentication" + ] + } + }, + "/agents/webhook/{webhook_id}": { + "post": { + "description": "`POST /api/agents/webhook/{webhook_id}`\nHeader: `X-Webhook-Token: `\n\nThe `webhook_id` in the URL is a short non-secret identifier (safe to log).\nThe actual credential is the secret token in the header.\n\nAccepts any JSON body, which is passed as `user_context` to the agent run.", + "operationId": "webhook_trigger", + "parameters": [ + { + "description": "Webhook ID (non-secret)", + "in": "path", + "name": "webhook_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WebhookTriggerRequest" + } + } + }, + "required": true + }, + "responses": { + "202": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WebhookTriggerResponse" + } + } + }, + "description": "Agent run created" + }, + "401": { + "description": "Missing or invalid X-Webhook-Token header" + }, + "404": { + "description": "Invalid webhook ID" + }, + "422": { + "description": "Agent disabled" + } + }, + "summary": "Public webhook endpoint. Authenticated via `X-Webhook-Token` header.", + "tags": [ + "Agents" + ] + } + }, + "/ai/conversations": { + "get": { + "operationId": "list_all_conversations", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/GlobalConversationResponse" + }, + "type": "array" + } + } + }, + "description": "" + }, + "401": { + "description": "" + }, + "403": { + "description": "" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List every active conversation across all projects, most-recently-active\nfirst, annotated with project name/slug. Powers the unified \"all chats\"\nswitcher in the AI assistant dock.", + "tags": [ + "AI Chat" + ] + } + }, + "/ai/pricing": { + "get": { + "operationId": "get_pricing", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PricingResponse" + } + } + }, + "description": "Model pricing information" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "AI Gateway Pricing" + ] + } + }, + "/ai/providers": { + "get": { + "operationId": "list_provider_keys", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/ProviderKeyResponse" + }, + "type": "array" + } + } + }, + "description": "List of provider keys" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "AI Gateway Admin" + ] + }, + "post": { + "operationId": "create_provider_key", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateProviderKeyRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProviderKeyResponse" + } + } + }, + "description": "Provider key created" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Validation error" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "AI Gateway Admin" + ] + } + }, + "/ai/providers/test": { + "post": { + "operationId": "test_provider_key_inline", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TestProviderKeyRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TestProviderKeyResponse" + } + } + }, + "description": "Test result" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Validation error" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "AI Gateway Admin" + ] + } + }, + "/ai/providers/{id}": { + "delete": { + "operationId": "delete_provider_key", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "Provider key deleted" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "AI Gateway Admin" + ] + }, + "patch": { + "operationId": "update_provider_key", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateProviderKeyRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProviderKeyResponse" + } + } + }, + "description": "Provider key updated" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Validation error" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "AI Gateway Admin" + ] + } + }, + "/ai/providers/{id}/test": { + "post": { + "operationId": "test_provider_key_by_id", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TestProviderKeyResponse" + } + } + }, + "description": "Test result" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Provider key not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "AI Gateway Admin" + ] + } + }, + "/ai/usage/by-provider": { + "get": { + "operationId": "get_usage_by_provider", + "parameters": [ + { + "description": "ISO 8601 start time (defaults to 24h ago)", + "in": "query", + "name": "from", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "ISO 8601 end time (defaults to now)", + "in": "query", + "name": "to", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/ProviderUsage" + }, + "type": "array" + } + } + }, + "description": "Usage broken down by provider" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Invalid query parameters" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "AI Gateway Usage" + ] + } + }, + "/ai/usage/conversations": { + "get": { + "operationId": "get_conversations", + "parameters": [ + { + "description": "ISO 8601 start time (defaults to 24h ago)", + "in": "query", + "name": "from", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "ISO 8601 end time (defaults to now)", + "in": "query", + "name": "to", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Max results (defaults to 50, max 100)", + "in": "query", + "name": "limit", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + { + "description": "Filter by user ID", + "in": "query", + "name": "user_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Filter by tags (comma-separated)", + "in": "query", + "name": "tags", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter by model name", + "in": "query", + "name": "model", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/ConversationSummary" + }, + "type": "array" + } + } + }, + "description": "Conversation summaries" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Invalid query parameters" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "AI Gateway Usage" + ] + } + }, + "/ai/usage/conversations/{conversation_id}": { + "get": { + "operationId": "get_conversation_detail", + "parameters": [ + { + "description": "Conversation ID", + "in": "path", + "name": "conversation_id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Max results (defaults to 100)", + "in": "query", + "name": "limit", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/UsageLogEntry" + }, + "type": "array" + } + } + }, + "description": "Invocations within a conversation" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "AI Gateway Usage" + ] + } + }, + "/ai/usage/recent": { + "get": { + "operationId": "get_usage_recent", + "parameters": [ + { + "description": "Page size (defaults to 20, max 50)", + "in": "query", + "name": "limit", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + { + "description": "Number of results to skip for pagination (defaults to 0)", + "in": "query", + "name": "offset", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + { + "description": "Filter by provider name", + "in": "query", + "name": "provider", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter by model name", + "in": "query", + "name": "model", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter by HTTP status code (exact match)", + "in": "query", + "name": "status", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Cost greater-than-or-equal, in microcents", + "in": "query", + "name": "cost_gte", + "required": false, + "schema": { + "format": "int64", + "type": "integer" + } + }, + { + "description": "Cost strictly greater-than, in microcents", + "in": "query", + "name": "cost_gt", + "required": false, + "schema": { + "format": "int64", + "type": "integer" + } + }, + { + "description": "Cost less-than-or-equal, in microcents", + "in": "query", + "name": "cost_lte", + "required": false, + "schema": { + "format": "int64", + "type": "integer" + } + }, + { + "description": "Cost strictly less-than, in microcents", + "in": "query", + "name": "cost_lt", + "required": false, + "schema": { + "format": "int64", + "type": "integer" + } + }, + { + "description": "Total tokens greater-than-or-equal", + "in": "query", + "name": "tokens_gte", + "required": false, + "schema": { + "format": "int64", + "type": "integer" + } + }, + { + "description": "Total tokens strictly greater-than", + "in": "query", + "name": "tokens_gt", + "required": false, + "schema": { + "format": "int64", + "type": "integer" + } + }, + { + "description": "Total tokens less-than-or-equal", + "in": "query", + "name": "tokens_lte", + "required": false, + "schema": { + "format": "int64", + "type": "integer" + } + }, + { + "description": "Total tokens strictly less-than", + "in": "query", + "name": "tokens_lt", + "required": false, + "schema": { + "format": "int64", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UsageLogPage" + } + } + }, + "description": "Page of recent usage log entries" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "AI Gateway Usage" + ] + } + }, + "/ai/usage/summary": { + "get": { + "operationId": "get_usage_summary", + "parameters": [ + { + "description": "ISO 8601 start time (defaults to 24h ago)", + "in": "query", + "name": "from", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "ISO 8601 end time (defaults to now)", + "in": "query", + "name": "to", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UsageSummary" + } + } + }, + "description": "Usage summary for the time range" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Invalid query parameters" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "AI Gateway Usage" + ] + } + }, + "/ai/usage/timeseries": { + "get": { + "operationId": "get_usage_timeseries", + "parameters": [ + { + "description": "ISO 8601 start time (defaults to 24h ago)", + "in": "query", + "name": "from", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "ISO 8601 end time (defaults to now)", + "in": "query", + "name": "to", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Bucket size: hour, day, week (defaults to day)", + "in": "query", + "name": "bucket", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/TimeseriesBucket" + }, + "type": "array" + } + } + }, + "description": "Time-series usage data" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Invalid query parameters" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "AI Gateway Usage" + ] + } + }, + "/ai/usage/top-models": { + "get": { + "operationId": "get_usage_top_models", + "parameters": [ + { + "description": "ISO 8601 start time (defaults to 24h ago)", + "in": "query", + "name": "from", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "ISO 8601 end time (defaults to now)", + "in": "query", + "name": "to", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Max results (defaults to 10)", + "in": "query", + "name": "limit", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/ModelUsage" + }, + "type": "array" + } + } + }, + "description": "Top models by request count" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Invalid query parameters" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "AI Gateway Usage" + ] + } + }, + "/ai/v1/chat/completions": { + "post": { + "operationId": "chat_completions", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChatCompletionRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChatCompletionResponse" + } + } + }, + "description": "Chat completion response" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OpenAiErrorResponse" + } + } + }, + "description": "Invalid request" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OpenAiErrorResponse" + } + } + }, + "description": "Unauthorized" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OpenAiErrorResponse" + } + } + }, + "description": "Model not found" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OpenAiErrorResponse" + } + } + }, + "description": "Internal error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "AI Gateway" + ] + } + }, + "/ai/v1/embeddings": { + "post": { + "operationId": "embeddings", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EmbeddingRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EmbeddingResponse" + } + } + }, + "description": "Embedding response" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OpenAiErrorResponse" + } + } + }, + "description": "Invalid request" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OpenAiErrorResponse" + } + } + }, + "description": "Unauthorized" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OpenAiErrorResponse" + } + } + }, + "description": "Model not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "AI Gateway" + ] + } + }, + "/ai/v1/models": { + "get": { + "operationId": "list_models", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelListResponse" + } + } + }, + "description": "List of available models" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OpenAiErrorResponse" + } + } + }, + "description": "Unauthorized" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "AI Gateway" + ] + } + }, + "/analytics/active-visitors": { + "get": { + "operationId": "get_analytics_active_visitors", + "parameters": [ + { + "description": "Project ID", + "in": "query", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment ID (optional)", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Deployment ID (optional)", + "in": "query", + "name": "deployment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Time window in minutes for active visitors (default: 5)", + "in": "query", + "name": "window_minutes", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ActiveVisitorsResponse" + } + } + }, + "description": "Successfully retrieved active visitors" + }, + "400": { + "description": "Invalid parameters or project not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get detailed active visitors", + "tags": [ + "Analytics" + ] + } + }, + "/analytics/event-detail": { + "get": { + "operationId": "get_event_detail", + "parameters": [ + { + "description": "Event name to get details for", + "in": "query", + "name": "event_name", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Project ID", + "in": "query", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment ID (optional)", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Start date (ISO 8601)", + "in": "query", + "name": "start_date", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "End date (ISO 8601)", + "in": "query", + "name": "end_date", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Bucket interval: hour, day, week, month (default: auto)", + "in": "query", + "name": "bucket_interval", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EventDetailResponse" + } + } + }, + "description": "Successfully retrieved event details" + }, + "400": { + "description": "Invalid parameters" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get detailed analytics for a specific event", + "tags": [ + "Analytics" + ] + } + }, + "/analytics/event-entries": { + "get": { + "operationId": "get_event_entries", + "parameters": [ + { + "description": "Event name to list occurrences for", + "in": "query", + "name": "event_name", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Project ID", + "in": "query", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment ID (optional)", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Start date (ISO 8601)", + "in": "query", + "name": "start_date", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "End date (ISO 8601)", + "in": "query", + "name": "end_date", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Page number (1-based, default: 1)", + "in": "query", + "name": "page", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + { + "description": "Items per page (default: 20, max: 100)", + "in": "query", + "name": "per_page", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EventEntriesResponse" + } + } + }, + "description": "Successfully retrieved event entries" + }, + "400": { + "description": "Invalid parameters" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get paginated list of raw occurrences of a specific event, including custom JSON properties", + "tags": [ + "Analytics" + ] + } + }, + "/analytics/event-visitors": { + "get": { + "operationId": "get_event_visitors", + "parameters": [ + { + "description": "Event name to list visitors for", + "in": "query", + "name": "event_name", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Project ID", + "in": "query", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment ID (optional)", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Start date (ISO 8601)", + "in": "query", + "name": "start_date", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "End date (ISO 8601)", + "in": "query", + "name": "end_date", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Page number (1-based, default: 1)", + "in": "query", + "name": "page", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + { + "description": "Items per page (default: 20, max: 100)", + "in": "query", + "name": "per_page", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EventVisitorsResponse" + } + } + }, + "description": "Successfully retrieved event visitors" + }, + "400": { + "description": "Invalid parameters" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get paginated list of visitors who triggered a specific event", + "tags": [ + "Analytics" + ] + } + }, + "/analytics/events": { + "get": { + "operationId": "get_analytics_events_count", + "parameters": [ + { + "description": "Start date in format YYYY-MM-DD HH:MM:SS", + "in": "query", + "name": "start_date", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "End date in format YYYY-MM-DD HH:MM:SS", + "in": "query", + "name": "end_date", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Project ID or slug", + "in": "query", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Maximum number of results to return", + "in": "query", + "name": "limit", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment ID (optional)", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Only return custom events, excluding system events like page_view, page_leave, heartbeat (default: true)", + "in": "query", + "name": "custom_events_only", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "description": "Breakdown by geography: 'country', 'region', or 'city' (optional)", + "in": "query", + "name": "breakdown", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/EventCount" + }, + "type": "array" + } + } + }, + "description": "Successfully retrieved event counts" + }, + "400": { + "description": "Invalid date format, missing required parameters, or project not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Analytics" + ] + } + }, + "/analytics/general-stats": { + "get": { + "operationId": "get_general_stats", + "parameters": [ + { + "description": "Start date in format YYYY-MM-DD HH:MM:SS", + "in": "query", + "name": "start_date", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "End date in format YYYY-MM-DD HH:MM:SS", + "in": "query", + "name": "end_date", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Optional: Filter by specific project IDs (comma-separated)", + "in": "query", + "name": "project_ids", + "required": false, + "schema": { + "items": { + "format": "int32", + "type": "integer" + }, + "type": "array" + } + }, + { + "description": "Environment ID (optional)", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Whether to include per-project breakdown (default: false)", + "in": "query", + "name": "include_project_breakdown", + "required": false, + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GeneralStatsResponse" + } + } + }, + "description": "Successfully retrieved general statistics" + }, + "400": { + "description": "Invalid date format or parameters" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get general statistics across all projects for a time frame", + "tags": [ + "Analytics" + ] + } + }, + "/analytics/has-events": { + "get": { + "operationId": "check_analytics_has_events", + "parameters": [ + { + "description": "Project ID", + "in": "query", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment ID (optional)", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HasAnalyticsEventsResponse" + } + } + }, + "description": "Analytics events existence check" + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Project not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Analytics" + ] + } + }, + "/analytics/live-visitors": { + "get": { + "operationId": "get_live_visitors_list", + "parameters": [ + { + "description": "Project ID", + "in": "query", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment ID (optional)", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Time window in minutes for live visitors (default: 5)", + "in": "query", + "name": "window_minutes", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LiveVisitorsListResponse" + } + } + }, + "description": "Successfully retrieved live visitors list" + }, + "400": { + "description": "Invalid parameters or project not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get list of currently live visitors from visitor table", + "tags": [ + "Analytics" + ] + } + }, + "/analytics/page-flow": { + "get": { + "operationId": "get_page_flow", + "parameters": [ + { + "description": "Project ID", + "in": "query", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment ID (optional)", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Start date in ISO 8601 format", + "in": "query", + "name": "start_date", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "End date in ISO 8601 format", + "in": "query", + "name": "end_date", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Max entry/exit pages to return (default: 20, max: 100)", + "in": "query", + "name": "limit", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Max page transitions to return (default: 50, max: 200)", + "in": "query", + "name": "transitions_limit", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Minimum views for drop-off analysis (default: 5)", + "in": "query", + "name": "min_views_for_dropoff", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PageFlowResponse" + } + } + }, + "description": "Successfully retrieved page flow analytics" + }, + "400": { + "description": "Invalid parameters" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get page flow analytics: entry pages, exit pages, drop-off points, and page transitions", + "tags": [ + "Analytics" + ] + } + }, + "/analytics/page-hourly-sessions": { + "get": { + "operationId": "get_page_hourly_sessions", + "parameters": [ + { + "description": "The page path to get sessions for", + "in": "query", + "name": "page_path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Project ID", + "in": "query", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment ID (optional)", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Start time in format YYYY-MM-DD HH:MM:SS", + "in": "query", + "name": "start_time", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "End time in format YYYY-MM-DD HH:MM:SS", + "in": "query", + "name": "end_time", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Bucket interval: 'hour', 'day', 'week', or 'month' (default: auto-determined based on range)", + "in": "query", + "name": "bucket_interval", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PageHourlySessionsResponse" + } + } + }, + "description": "Successfully retrieved page sessions with time buckets" + }, + "400": { + "description": "Invalid parameters or project not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Analytics" + ] + } + }, + "/analytics/page-path-detail": { + "get": { + "operationId": "get_page_path_detail", + "parameters": [ + { + "description": "The page path to get details for (URL-encoded)", + "in": "query", + "name": "page_path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Project ID", + "in": "query", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment ID (optional)", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Start date in ISO 8601 format", + "in": "query", + "name": "start_date", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "End date in ISO 8601 format", + "in": "query", + "name": "end_date", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Bucket interval for time series: 'hour', 'day', 'week', 'month' (default: auto based on date range)", + "in": "query", + "name": "bucket_interval", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PagePathDetailResponse" + } + } + }, + "description": "Successfully retrieved page path detail analytics" + }, + "400": { + "description": "Invalid parameters or project not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get detailed analytics for a specific page path\nReturns visitors, page views, activity over time, geographic distribution, and referrers", + "tags": [ + "Analytics" + ] + } + }, + "/analytics/page-path-visitors": { + "get": { + "operationId": "get_page_path_visitors", + "parameters": [ + { + "description": "The page path to get visitors for (URL-encoded)", + "in": "query", + "name": "page_path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Project ID", + "in": "query", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment ID (optional)", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Start date in ISO 8601 format", + "in": "query", + "name": "start_date", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "End date in ISO 8601 format", + "in": "query", + "name": "end_date", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Page number (1-based, default: 1)", + "in": "query", + "name": "page", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + { + "description": "Items per page (default: 50, max: 100)", + "in": "query", + "name": "per_page", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PagePathVisitorsResponse" + } + } + }, + "description": "Successfully retrieved page path visitors" + }, + "400": { + "description": "Invalid parameters" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get individual visitor sessions for a specific page path", + "tags": [ + "Analytics" + ] + } + }, + "/analytics/page-paths": { + "get": { + "operationId": "get_page_paths", + "parameters": [ + { + "description": "Project ID or slug", + "in": "query", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment ID (optional)", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Start date in format YYYY-MM-DD HH:MM:SS (optional)", + "in": "query", + "name": "start_date", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "End date in format YYYY-MM-DD HH:MM:SS (optional)", + "in": "query", + "name": "end_date", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Maximum number of page paths to return (default: 100, max: 1000)", + "in": "query", + "name": "limit", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PagePathsResponse" + } + } + }, + "description": "Successfully retrieved page paths" + }, + "400": { + "description": "Invalid parameters or project not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Analytics" + ] + } + }, + "/analytics/page-paths-sparklines": { + "get": { + "operationId": "get_page_paths_sparklines", + "parameters": [ + { + "description": "Project ID", + "in": "query", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment ID (optional)", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Start time in ISO 8601 format", + "in": "query", + "name": "start_time", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "End time in ISO 8601 format", + "in": "query", + "name": "end_time", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Comma-separated list of page paths", + "in": "query", + "name": "page_paths", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PagePathsSparklineResponse" + } + } + }, + "description": "Sparkline data for all requested page paths" + }, + "400": { + "description": "Invalid parameters" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Analytics" + ] + } + }, + "/analytics/recent-activity": { + "get": { + "operationId": "get_recent_activity", + "parameters": [ + { + "description": "Project ID", + "in": "query", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment ID (optional)", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Return events with ID greater than this (cursor-based polling)", + "in": "query", + "name": "since_id", + "required": false, + "schema": { + "format": "int64", + "type": "integer" + } + }, + { + "description": "Max events to return (default: 50, max: 100)", + "in": "query", + "name": "limit", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RecentActivityResponse" + } + } + }, + "description": "Successfully retrieved recent activity events" + }, + "400": { + "description": "Invalid parameters" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get recent activity events for real-time activity feed", + "tags": [ + "Analytics" + ] + } + }, + "/analytics/sessions/{session_id}": { + "get": { + "operationId": "get_session_details", + "parameters": [ + { + "description": "Session ID", + "in": "path", + "name": "session_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Project ID or slug", + "in": "query", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment ID (optional)", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SessionDetails" + } + } + }, + "description": "Successfully retrieved session details" + }, + "400": { + "description": "Invalid parameters or project not found" + }, + "404": { + "description": "Session not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get detailed information about a specific session including events and request logs", + "tags": [ + "Analytics" + ] + } + }, + "/analytics/sessions/{session_id}/events": { + "get": { + "operationId": "get_analytics_session_events", + "parameters": [ + { + "description": "Session ID", + "in": "path", + "name": "session_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Project ID or slug", + "in": "query", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment ID (optional)", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Start date in format YYYY-MM-DD HH:MM:SS", + "in": "query", + "name": "start_date", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "End date in format YYYY-MM-DD HH:MM:SS", + "in": "query", + "name": "end_date", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Number of results to return (default: 100)", + "in": "query", + "name": "limit", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Number of results to skip (default: 0)", + "in": "query", + "name": "offset", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SessionEventsResponse" + } + } + }, + "description": "Successfully retrieved session events" + }, + "400": { + "description": "Invalid parameters or project not found" + }, + "404": { + "description": "Session not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Analytics" + ] + } + }, + "/analytics/sessions/{session_id}/logs": { + "get": { + "operationId": "get_session_logs", + "parameters": [ + { + "description": "Session ID", + "in": "path", + "name": "session_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Project ID or slug", + "in": "query", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment ID (optional)", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Start date in format YYYY-MM-DD HH:MM:SS", + "in": "query", + "name": "start_date", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "End date in format YYYY-MM-DD HH:MM:SS", + "in": "query", + "name": "end_date", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Number of results to return (default: 100)", + "in": "query", + "name": "limit", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Number of results to skip (default: 0)", + "in": "query", + "name": "offset", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SessionLogsResponse" + } + } + }, + "description": "Successfully retrieved session logs" + }, + "400": { + "description": "Invalid parameters or project not found" + }, + "404": { + "description": "Session not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Analytics" + ] + } + }, + "/analytics/visitor-facets": { + "get": { + "operationId": "get_visitor_facets", + "parameters": [ + { + "description": "Start date in format YYYY-MM-DD HH:MM:SS", + "in": "query", + "name": "start_date", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "End date in format YYYY-MM-DD HH:MM:SS", + "in": "query", + "name": "end_date", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Project ID or slug", + "in": "query", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment ID (optional)", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Include crawlers (default: false)", + "in": "query", + "name": "include_crawlers", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "description": "Hide ghost visitors (default: true)", + "in": "query", + "name": "has_activity_only", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "description": "Top N values per dimension (default: 50, max: 200)", + "in": "query", + "name": "per_facet_limit", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Geolocation country", + "in": "query", + "name": "filter_country", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Geolocation region", + "in": "query", + "name": "filter_region", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Geolocation city", + "in": "query", + "name": "filter_city", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "First-touch channel", + "in": "query", + "name": "filter_channel", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "First-touch referrer hostname (use 'Direct' for null)", + "in": "query", + "name": "filter_referrer", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VisitorFacets" + } + } + }, + "description": "Top values per dimension" + }, + "400": { + "description": "Invalid date format or project not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get filter dropdown contents for the visitors page. Returns the top\nvalues per dimension with distinct visitor counts so the UI can render\n\"Country — 1,234 visitors\" rows. Each dimension is computed against the\nsegment minus its own filter, so a selected value never collapses its\nown dropdown.", + "tags": [ + "Analytics" + ] + } + }, + "/analytics/visitors": { + "get": { + "operationId": "get_visitors", + "parameters": [ + { + "description": "Start date in format YYYY-MM-DD HH:MM:SS", + "in": "query", + "name": "start_date", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "End date in format YYYY-MM-DD HH:MM:SS", + "in": "query", + "name": "end_date", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Project ID or slug", + "in": "query", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment ID (optional)", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Include crawlers (default: false)", + "in": "query", + "name": "include_crawlers", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "description": "Maximum number of visitors to return (default: 50)", + "in": "query", + "name": "limit", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Number of visitors to skip (default: 0)", + "in": "query", + "name": "offset", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Filter to only include visitors with recorded activity (events/sessions). When true, excludes ghost visitors (default: true)", + "in": "query", + "name": "has_activity_only", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "description": "Geolocation country", + "in": "query", + "name": "filter_country", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Geolocation region", + "in": "query", + "name": "filter_region", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Geolocation city", + "in": "query", + "name": "filter_city", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "First-touch channel", + "in": "query", + "name": "filter_channel", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "First-touch referrer hostname (use 'Direct' for null)", + "in": "query", + "name": "filter_referrer", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VisitorsResponse" + } + } + }, + "description": "Successfully retrieved visitors" + }, + "400": { + "description": "Invalid date format, missing required parameters, or project not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get list of visitors with summary information", + "tags": [ + "Analytics" + ] + } + }, + "/analytics/visitors/guid/{visitor_id}": { + "get": { + "operationId": "get_visitor_by_guid", + "parameters": [ + { + "description": "Visitor GUID (supports enc_ prefix for encrypted IDs)", + "in": "path", + "name": "visitor_id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Project ID", + "in": "query", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment ID (optional)", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VisitorWithGeolocation" + } + } + }, + "description": "Successfully retrieved visitor with geolocation" + }, + "400": { + "description": "Invalid parameters or project not found" + }, + "404": { + "description": "Visitor not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get visitor by GUID with geolocation data", + "tags": [ + "Analytics" + ] + } + }, + "/analytics/visitors/id/{id}": { + "get": { + "operationId": "get_visitor_by_id", + "parameters": [ + { + "description": "Visitor numeric ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Project ID", + "in": "query", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment ID (optional)", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VisitorWithGeolocation" + } + } + }, + "description": "Successfully retrieved visitor with geolocation" + }, + "400": { + "description": "Invalid parameters or project not found" + }, + "404": { + "description": "Visitor not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get visitor by numeric ID with geolocation data", + "tags": [ + "Analytics" + ] + } + }, + "/analytics/visitors/{visitor_id}": { + "get": { + "operationId": "get_visitor_details", + "parameters": [ + { + "description": "Visitor numeric ID", + "in": "path", + "name": "visitor_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Project ID or slug", + "in": "query", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment ID (optional)", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VisitorDetails" + } + } + }, + "description": "Successfully retrieved visitor details" + }, + "400": { + "description": "Invalid parameters or project not found" + }, + "404": { + "description": "Visitor not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get detailed information about a specific visitor by numeric ID", + "tags": [ + "Analytics" + ] + } + }, + "/analytics/visitors/{visitor_id}/enrich": { + "put": { + "operationId": "enrich_visitor", + "parameters": [ + { + "description": "Visitor ID - can be numeric ID, GUID, or encrypted GUID (enc_xxx)", + "in": "path", + "name": "visitor_id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Project ID or slug", + "in": "query", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnrichVisitorRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnrichVisitorResponse" + } + } + }, + "description": "Successfully enriched visitor data" + }, + "400": { + "description": "Invalid parameters or project not found" + }, + "404": { + "description": "Visitor not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Analytics" + ] + } + }, + "/analytics/visitors/{visitor_id}/info": { + "get": { + "operationId": "get_visitor_info", + "parameters": [ + { + "description": "Visitor numeric ID", + "in": "path", + "name": "visitor_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Project ID or slug", + "in": "query", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VisitorRecord" + } + } + }, + "description": "Successfully retrieved visitor info" + }, + "400": { + "description": "Invalid parameters or project not found" + }, + "404": { + "description": "Visitor not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get visitor record from database", + "tags": [ + "Analytics" + ] + } + }, + "/analytics/visitors/{visitor_id}/journey": { + "get": { + "operationId": "get_visitor_journey", + "parameters": [ + { + "description": "Visitor numeric ID", + "in": "path", + "name": "visitor_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Project ID", + "in": "query", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Maximum number of sessions to return (default: 50)", + "in": "query", + "name": "limit_sessions", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VisitorJourneyResponse" + } + } + }, + "description": "Successfully retrieved visitor journey" + }, + "400": { + "description": "Invalid parameters" + }, + "404": { + "description": "Visitor not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get the complete visitor journey: all events across all sessions, grouped by session", + "tags": [ + "Analytics" + ] + } + }, + "/analytics/visitors/{visitor_id}/sessions": { + "get": { + "operationId": "get_analytics_visitor_sessions", + "parameters": [ + { + "description": "Visitor numeric ID", + "in": "path", + "name": "visitor_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Project ID or slug", + "in": "query", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment ID (optional)", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Maximum number of sessions to return (default: 100)", + "in": "query", + "name": "limit", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VisitorSessionsResponse" + } + } + }, + "description": "Successfully retrieved visitor sessions" + }, + "400": { + "description": "Invalid parameters or project not found" + }, + "404": { + "description": "Visitor not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get all sessions for a specific visitor by numeric ID", + "tags": [ + "Analytics" + ] + } + }, + "/analytics/visitors/{visitor_id}/stats": { + "get": { + "operationId": "get_visitor_stats", + "parameters": [ + { + "description": "Visitor numeric ID", + "in": "path", + "name": "visitor_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Project ID or slug", + "in": "query", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VisitorStats" + } + } + }, + "description": "Successfully retrieved visitor statistics" + }, + "400": { + "description": "Invalid parameters or project not found" + }, + "404": { + "description": "Visitor not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get visitor statistics", + "tags": [ + "Analytics" + ] + } + }, + "/api-keys": { + "get": { + "operationId": "list_api_keys", + "parameters": [ + { + "description": "Page number (default: 1)", + "in": "query", + "name": "page", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + { + "description": "Items per page (default: 20)", + "in": "query", + "name": "page_size", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiKeyListResponse" + } + } + }, + "description": "API keys retrieved successfully" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "API Keys" + ] + }, + "post": { + "operationId": "create_api_key", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateApiKeyRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateApiKeyResponse" + } + } + }, + "description": "API key created successfully" + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "409": { + "description": "Conflict - API key name already exists" + }, + "428": { + "description": "Recent MFA verification required" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "API Keys" + ] + } + }, + "/api-keys/permissions": { + "get": { + "operationId": "get_api_key_permissions", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AvailablePermissions" + } + } + }, + "description": "Available permissions and roles retrieved successfully" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "API Keys" + ] + } + }, + "/api-keys/{id}": { + "delete": { + "operationId": "delete_api_key", + "parameters": [ + { + "description": "API key ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "API key deleted successfully" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "API Keys" + ] + }, + "get": { + "operationId": "get_api_key", + "parameters": [ + { + "description": "API key ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiKeyResponse" + } + } + }, + "description": "API key retrieved successfully" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "API Keys" + ] + }, + "put": { + "operationId": "update_api_key", + "parameters": [ + { + "description": "API key ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateApiKeyRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiKeyResponse" + } + } + }, + "description": "API key updated successfully" + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Not found" + }, + "409": { + "description": "Conflict - API key name already exists" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "API Keys" + ] + } + }, + "/api-keys/{id}/activate": { + "post": { + "operationId": "activate_api_key", + "parameters": [ + { + "description": "API key ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiKeyResponse" + } + } + }, + "description": "API key activated successfully" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "API Keys" + ] + } + }, + "/api-keys/{id}/deactivate": { + "post": { + "operationId": "deactivate_api_key", + "parameters": [ + { + "description": "API key ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiKeyResponse" + } + } + }, + "description": "API key deactivated successfully" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "API Keys" + ] + } + }, + "/api-keys/{id}/rotate": { + "post": { + "operationId": "rotate_api_key", + "parameters": [ + { + "description": "API key ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateApiKeyResponse" + } + } + }, + "description": "API key rotated successfully; the response contains the new plaintext secret, shown only once" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Not found" + }, + "428": { + "description": "Recent MFA verification required" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "API Keys" + ] + } + }, + "/auth/cli/device/approve": { + "post": { + "operationId": "cli_device_approve", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CliDeviceApproveRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CliDeviceApproveResponse" + } + } + }, + "description": "Session approved; CLI can now claim the API key" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Browser session required" + }, + "404": { + "description": "Unknown user_code" + }, + "409": { + "description": "Already resolved" + }, + "410": { + "description": "Session expired" + }, + "428": { + "description": "Recent MFA verification required" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "session_token": [] + } + ], + "tags": [ + "Authentication" + ] + } + }, + "/auth/cli/device/deny": { + "post": { + "operationId": "cli_device_deny", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CliDeviceApproveRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CliDeviceApproveResponse" + } + } + }, + "description": "Session denied" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Unknown user_code" + }, + "409": { + "description": "Already resolved" + }, + "410": { + "description": "Session expired" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "session_token": [] + } + ], + "tags": [ + "Authentication" + ] + } + }, + "/auth/cli/device/lookup": { + "get": { + "operationId": "cli_device_lookup", + "parameters": [ + { + "description": "`user_code` as displayed in the CLI / pasted into the URL.", + "in": "query", + "name": "user_code", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CliDeviceLookupResponse" + } + } + }, + "description": "Device session metadata" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Unknown user_code" + }, + "410": { + "description": "Device session expired" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "session_token": [] + } + ], + "tags": [ + "Authentication" + ] + } + }, + "/auth/cli/device/poll": { + "post": { + "operationId": "cli_device_poll", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CliDevicePollRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CliDevicePollResponse" + } + } + }, + "description": "Poll result; check `status` field" + }, + "404": { + "description": "Unknown device_code" + }, + "500": { + "description": "Internal server error" + } + }, + "tags": [ + "Authentication" + ] + } + }, + "/auth/cli/device/start": { + "post": { + "operationId": "cli_device_start", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CliDeviceStartRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CliDeviceStartResponse" + } + } + }, + "description": "Device session created" + }, + "500": { + "description": "Internal server error" + } + }, + "tags": [ + "Authentication" + ] + } + }, + "/auth/cli/logout": { + "post": { + "operationId": "cli_logout", + "responses": { + "204": { + "description": "API key revoked" + }, + "401": { + "description": "Not authenticated" + }, + "403": { + "description": "Endpoint requires API key authentication" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Authentication" + ] + } + }, + "/auth/email-status": { + "get": { + "operationId": "email_status", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EmailStatusResponse" + } + } + }, + "description": "Email configuration status" + }, + "500": { + "description": "Internal server error" + } + }, + "tags": [ + "Authentication" + ] + } + }, + "/auth/login": { + "post": { + "operationId": "login", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LoginRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthResponse" + } + } + }, + "description": "Login successful, session cookie set" + }, + "401": { + "description": "Invalid credentials, or the account's role requires MFA enrollment that has not been completed" + }, + "500": { + "description": "Internal server error" + } + }, + "tags": [ + "Authentication" + ] + } + }, + "/auth/oidc/callback": { + "get": { + "operationId": "oidc_callback", + "parameters": [ + { + "in": "query", + "name": "code", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "in": "query", + "name": "state", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "in": "query", + "name": "error", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "in": "query", + "name": "error_description", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + } + ], + "responses": { + "302": { + "description": "Redirect to app with session cookie or login error" + } + }, + "tags": [ + "Authentication" + ] + } + }, + "/auth/oidc/login/{slug}": { + "get": { + "operationId": "start_oidc_login_by_slug", + "parameters": [ + { + "description": "OIDC provider slug (from /email-status or /auth/oidc/providers)", + "in": "path", + "name": "slug", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "return_to", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + } + ], + "responses": { + "302": { + "description": "Redirect to IdP authorize URL" + }, + "404": { + "description": "Provider not found" + }, + "503": { + "description": "OIDC provider unreachable" + } + }, + "tags": [ + "Authentication" + ] + } + }, + "/auth/oidc/providers": { + "get": { + "operationId": "list_public_providers", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OidcProvidersListResponse" + } + } + }, + "description": "Enabled OIDC providers for login page" + } + }, + "tags": [ + "Authentication" + ] + } + }, + "/auth/password-reset/request": { + "post": { + "operationId": "request_password_reset", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EmailRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthResponse" + } + } + }, + "description": "Reset email sent if account exists" + }, + "503": { + "description": "Email service not configured" + } + }, + "tags": [ + "Authentication" + ] + } + }, + "/auth/password-reset/verify": { + "post": { + "operationId": "reset_password", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResetPasswordRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthResponse" + } + } + }, + "description": "Password reset successful" + }, + "400": { + "description": "Invalid or expired token" + }, + "500": { + "description": "Internal server error" + } + }, + "tags": [ + "Authentication" + ] + } + }, + "/auth/step-up": { + "post": { + "operationId": "verify_step_up", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VerifyStepUpRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StepUpResponse" + } + } + }, + "description": "Session elevated for sensitive actions" + }, + "400": { + "description": "Verification code is empty" + }, + "401": { + "description": "Invalid code or expired session" + }, + "403": { + "description": "Browser session required" + }, + "428": { + "description": "MFA setup required" + }, + "429": { + "description": "Too many verification attempts" + }, + "500": { + "description": "Verification infrastructure failed" + } + }, + "security": [ + { + "session_token": [] + } + ], + "tags": [ + "Authentication" + ] + } + }, + "/auth/verify-email": { + "get": { + "operationId": "verify_email", + "parameters": [ + { + "description": "Email verification token", + "in": "query", + "name": "token", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthResponse" + } + } + }, + "description": "Email verified successfully" + }, + "400": { + "description": "Invalid or expired token" + }, + "500": { + "description": "Internal server error" + } + }, + "tags": [ + "Authentication" + ] + } + }, + "/auth/verify-mfa": { + "post": { + "operationId": "verify_mfa_challenge", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MfaVerificationRequest" + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "MFA verification successful" + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Invalid MFA code" + }, + "500": { + "description": "Internal server error" + } + }, + "tags": [ + "Authentication" + ] + } + }, + "/backups/alerts": { + "get": { + "description": "Returns all alerts that have not yet been resolved, ordered by `opened_at`\ndescending (newest first). The UI renders these as a banner above the\nBackups page content. Alerts are auto-opened by the watcher and\nauto-resolved when the triggering condition clears.\n\n**Schedule overdue** — the backup scheduler did not enqueue a job within\nthe expected window (1 hour past `next_run`). Usually means the scheduler\ntask is dead or wedged.\n\n**Job stalled** — a `backup_jobs` row has been in `state='pending'` for\nmore than 1 hour. The runner never claimed the job. Usually means the\nrunner task is dead or the runner concurrency cap is too low.", + "operationId": "list_backup_alerts", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BackupAlertListResponse" + } + } + }, + "description": "List of open backup alerts" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List open backup alerts.", + "tags": [ + "Backups" + ] + } + }, + "/backups/cleanup": { + "post": { + "operationId": "cleanup_expired_backups", + "parameters": [ + { + "description": "Return the backups selected by retention without deleting anything.", + "in": "query", + "name": "dry_run", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "description": "Limit cleanup to one backup schedule.", + "in": "query", + "name": "schedule_id", + "required": false, + "schema": { + "format": "int32", + "type": [ + "integer", + "null" + ] + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CleanupExpiredBackupsRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RetentionCleanupReport" + } + } + }, + "description": "Retention cleanup completed" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Missing or invalid preview candidate list" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Schedule or backup not found" + }, + "409": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Cleanup preview is stale" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Cleanup could not be started" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Preview or run retention using each selected schedule's configured retention days.", + "tags": [ + "Backups" + ] + } + }, + "/backups/external-services/{id}/run": { + "post": { + "description": "Enqueues the backup for asynchronous execution via the `BackupRunner`\n(ADR-014). Returns `202 Accepted` immediately: pending parent and child\nrows are inserted, and a `backup_jobs` row is enqueued for the resolved\nengine. Poll `GET /backups/{id}` to observe `pending → running → completed`.", + "operationId": "run_external_service_backup", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RunExternalServiceBackupRequest" + } + } + }, + "required": true + }, + "responses": { + "202": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExternalServiceBackupResponse" + } + } + }, + "description": "Backup enqueued for async execution" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Invalid request" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "External service or S3 source not found" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Run a backup for an external service manually.", + "tags": [ + "Backups" + ] + } + }, + "/backups/external-services/{service_id}/backups": { + "get": { + "description": "Returns a paginated list of backups that belong to this service.\nCompletes in <100 ms regardless of S3 endpoint latency because it\nnever touches S3.", + "operationId": "list_external_service_backups", + "parameters": [ + { + "description": "External service ID", + "in": "path", + "name": "service_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Page number (1-based). Defaults to 1.", + "in": "query", + "name": "page", + "required": false, + "schema": { + "format": "int64", + "type": "integer" + } + }, + { + "description": "Items per page. Defaults to 20, max 100.", + "in": "query", + "name": "page_size", + "required": false, + "schema": { + "format": "int64", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceBackupListResponse" + } + } + }, + "description": "Paginated list of backups for this service" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List all backups for a specific external service (DB-only, no S3 scan).", + "tags": [ + "Backups" + ] + } + }, + "/backups/external-services/{service_id}/schedules": { + "get": { + "operationId": "list_service_schedules", + "parameters": [ + { + "description": "External service ID", + "in": "path", + "name": "service_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/BackupScheduleResponse" + }, + "type": "array" + } + } + }, + "description": "Schedules backing up this service" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Service not found" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List the schedules that target a specific external service. Useful for\nthe service detail page (\"which schedules back this DB up?\").", + "tags": [ + "Backups" + ] + } + }, + "/backups/s3-sources": { + "get": { + "operationId": "list_s3_sources", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/S3SourceResponse" + }, + "type": "array" + } + } + }, + "description": "List of S3 sources" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List all S3 sources", + "tags": [ + "Backups" + ] + }, + "post": { + "operationId": "create_s3_source", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateS3SourceRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/S3SourceResponse" + } + } + }, + "description": "S3 source created" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Invalid request" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Create a new S3 source", + "tags": [ + "Backups" + ] + } + }, + "/backups/s3-sources/test": { + "post": { + "operationId": "test_s3_connection_preview", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateS3SourceRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/S3ConnectionTestResponse" + } + } + }, + "description": "Connection test result" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Invalid request" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Test S3 connectivity against a prospective source configuration (before creating it).\nThe credentials are NOT persisted. Useful for validating the form in the UI.", + "tags": [ + "Backups" + ] + } + }, + "/backups/s3-sources/{id}": { + "delete": { + "operationId": "delete_s3_source", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "S3 source deleted" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "S3 source not found" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Delete an S3 source", + "tags": [ + "Backups" + ] + }, + "get": { + "operationId": "get_s3_source", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/S3SourceResponse" + } + } + }, + "description": "S3 source details" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "S3 source not found" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get an S3 source by ID", + "tags": [ + "Backups" + ] + }, + "patch": { + "operationId": "update_s3_source", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateS3SourceRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/S3SourceResponse" + } + } + }, + "description": "S3 source updated" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "S3 source not found" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Update an S3 source", + "tags": [ + "Backups" + ] + } + }, + "/backups/s3-sources/{id}/backups": { + "get": { + "operationId": "list_source_backups", + "parameters": [ + { + "description": "When `true`, scan the S3 bucket for backups not tracked in the\nlocal database (useful after disaster-recovery from another Temps\ninstance). Defaults to `false` — the fast DB-only path.", + "in": "query", + "name": "include_s3_scan", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SourceBackupIndexResponse" + } + } + }, + "description": "List of all backups in the source" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "404": { + "description": "S3 source not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List all backups in an S3 source", + "tags": [ + "Backups" + ] + } + }, + "/backups/s3-sources/{id}/run": { + "post": { + "description": "Enqueues the backup for asynchronous execution via the `BackupRunner`\n(ADR-014). Returns `202 Accepted` immediately: a `backups` row is inserted\nwith `state='pending'` and a `backup_jobs` row is enqueued for the\n`ControlPlaneEngine`. Poll `GET /backups/{id}` to observe\n`pending → running → completed`.", + "operationId": "run_backup_for_source", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RunBackupRequest" + } + } + }, + "required": true + }, + "responses": { + "202": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BackupResponse" + } + } + }, + "description": "Backup enqueued for async execution" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Invalid request" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "S3 source not found" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Run a backup immediately for an S3 source.", + "tags": [ + "Backups" + ] + } + }, + "/backups/s3-sources/{id}/set-default": { + "post": { + "operationId": "set_default_s3_source", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/S3SourceResponse" + } + } + }, + "description": "S3 source marked as default" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "S3 source not found" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Mark an S3 source as the default. All new backups/schedules/services that do not\nexplicitly reference a source will use the default. Returns the updated source.", + "tags": [ + "Backups" + ] + } + }, + "/backups/s3-sources/{id}/test": { + "post": { + "operationId": "test_s3_source_connection", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/S3ConnectionTestResponse" + } + } + }, + "description": "Connection test result" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "S3 source not found" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Test connectivity to an existing S3 source using its stored credentials.", + "tags": [ + "Backups" + ] + } + }, + "/backups/schedule-runs/{id}/cancel": { + "post": { + "description": "Loops over `state IN ('pending','running')` children and flips each via\nthe same path as the per-backup cancel endpoint. The parent\n`schedule_runs.finished_at` is stamped automatically once no live\nchildren remain. Idempotent: cancelling a run with no live children is\na 200 with `cancelled = 0`.", + "operationId": "cancel_schedule_run", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int64", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CancelBackupResponse" + } + } + }, + "description": "Cancel processed (idempotent)" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Schedule run not found" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Cancel every non-terminal child backup belonging to a schedule run.", + "tags": [ + "Backups" + ] + } + }, + "/backups/schedule-runs/{id}/jobs": { + "get": { + "description": "Returns each child `backups` row joined with its external service name and\nthe most-recent `backup_jobs` engine key. Used by the schedule detail\naccordion to show per-job detail on row expand.\n\n`page_size` defaults to 50 and is capped at 200.", + "operationId": "list_schedule_run_jobs", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int64", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/ScheduleRunJobEntry" + }, + "type": "array" + } + } + }, + "description": "Jobs for this scheduler run" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List the individual backup jobs for a single scheduler run.", + "tags": [ + "Backups" + ] + } + }, + "/backups/schedules": { + "get": { + "operationId": "list_backup_schedules", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/BackupScheduleResponse" + }, + "type": "array" + } + } + }, + "description": "List of backup schedules" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List all backup schedules", + "tags": [ + "Backups" + ] + }, + "post": { + "operationId": "create_backup_schedule", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateBackupScheduleRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BackupScheduleResponse" + } + } + }, + "description": "Backup schedule created" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Create a new backup schedule", + "tags": [ + "Backups" + ] + } + }, + "/backups/schedules/{id}": { + "delete": { + "operationId": "delete_backup_schedule", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "Backup schedule deleted" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Backup schedule not found" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Delete a backup schedule", + "tags": [ + "Backups" + ] + }, + "get": { + "operationId": "get_backup_schedule", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BackupScheduleResponse" + } + } + }, + "description": "Backup schedule details" + }, + "404": { + "description": "Backup schedule not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get a backup schedule by ID", + "tags": [ + "Backups" + ] + }, + "patch": { + "description": "All request fields are optional; only fields that are present in the\nJSON body are updated. Absent fields leave the corresponding column\nunchanged. If `schedule_expression` is changed, `next_run` is\nrecomputed automatically.", + "operationId": "update_backup_schedule", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateBackupScheduleRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BackupScheduleResponse" + } + } + }, + "description": "Schedule updated" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Validation error" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Schedule not found" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Update a backup schedule (partial update).", + "tags": [ + "Backups" + ] + } + }, + "/backups/schedules/{id}/backups": { + "get": { + "operationId": "list_backups_for_schedule", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/BackupResponse" + }, + "type": "array" + } + } + }, + "description": "List of backups for the schedule" + }, + "404": { + "description": "Backup schedule not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List backups for a schedule", + "tags": [ + "Backups" + ] + } + }, + "/backups/schedules/{id}/disable": { + "patch": { + "operationId": "disable_backup_schedule", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BackupScheduleResponse" + } + } + }, + "description": "Backup schedule disabled" + }, + "404": { + "description": "Backup schedule not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Disable a backup schedule", + "tags": [ + "Backups" + ] + } + }, + "/backups/schedules/{id}/enable": { + "patch": { + "operationId": "enable_backup_schedule", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BackupScheduleResponse" + } + } + }, + "description": "Backup schedule enabled" + }, + "404": { + "description": "Backup schedule not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Enable a backup schedule", + "tags": [ + "Backups" + ] + } + }, + "/backups/schedules/{id}/run": { + "post": { + "description": "Creates one `schedule_runs` row, one control-plane backup job, and one\nbackup job per supported external service — all in a single transaction.\nReturns `202 Accepted` with a [`ScheduleRunResponse`] containing the new\n`schedule_run_id` and the list of enqueued jobs. Returns `409 Conflict` if\na run for this schedule is already in flight or if the schedule is disabled.", + "operationId": "run_schedule_now", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "202": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ScheduleRunResponse" + } + } + }, + "description": "Fan-out run enqueued for async execution" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Schedule not found" + }, + "409": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Run already in flight or schedule disabled" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Immediately fan-out a run for the given schedule (Run Now).", + "tags": [ + "Backups" + ] + } + }, + "/backups/schedules/{id}/runs": { + "get": { + "description": "Returns one [`ScheduleRunSummary`] per scheduler tick, with child backup\ncounts aggregated in a single SQL round-trip. Legacy `backups` rows (pre-\nfan-out) are surfaced as synthetic single-job runs so history does not\ndisappear. Ordered by `started_at DESC` (newest first).\n\nUse `GET /backups/schedule-runs/{run_id}/jobs` to drill into a single run.", + "operationId": "list_schedule_runs", + "parameters": [ + { + "description": "Page number (1-based, defaults to 1, clamped to 1 if < 1).", + "in": "query", + "name": "page", + "required": false, + "schema": { + "format": "int64", + "type": "integer" + } + }, + { + "description": "Items per page (defaults to 20, clamped to 100 if > 100).", + "in": "query", + "name": "page_size", + "required": false, + "schema": { + "format": "int64", + "type": "integer" + } + }, + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ScheduleRunSummaryList" + } + } + }, + "description": "Paginated run history for the schedule" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Schedule not found" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Paginated run history for a backup schedule (one row per scheduler tick).", + "tags": [ + "Backups" + ] + } + }, + "/backups/schedules/{id}/services": { + "get": { + "operationId": "list_schedule_services", + "parameters": [ + { + "description": "Schedule ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/ExternalServiceSummary" + }, + "type": "array" + } + } + }, + "description": "Services attached to this schedule" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Schedule not found" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List the external services attached to a backup schedule.", + "tags": [ + "Backups" + ] + }, + "post": { + "operationId": "attach_schedule_services", + "parameters": [ + { + "description": "Schedule ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AttachScheduleServicesRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AttachScheduleServicesResponse" + } + } + }, + "description": "Services attached" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Validation error" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Schedule not found" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Attach one or more external services to a backup schedule. Idempotent —\nservices that are already attached are silently skipped (`ON CONFLICT\nDO NOTHING`). Returns the count of newly inserted rows + the total\nmembership after the operation.", + "tags": [ + "Backups" + ] + } + }, + "/backups/schedules/{id}/services/{service_id}": { + "delete": { + "operationId": "detach_schedule_service", + "parameters": [ + { + "description": "Schedule ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "External service ID", + "in": "path", + "name": "service_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "Service detached (or was not attached)" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Detach a single external service from a backup schedule. Idempotent —\nreturns `204` whether or not a row was actually removed.", + "tags": [ + "Backups" + ] + } + }, + "/backups/{id}": { + "delete": { + "operationId": "delete_backup", + "parameters": [ + { + "description": "Backup UUID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Backup deleted" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Backup artifact cannot be safely attributed" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Backup not found" + }, + "409": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Backup is running, referenced, or lacks safe artifact identity" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Object storage or database error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Permanently delete one terminal backup from object storage and the database.", + "tags": [ + "Backups" + ] + }, + "get": { + "operationId": "get_backup", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BackupResponse" + } + } + }, + "description": "Backup details" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Backup not found" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get a backup by ID", + "tags": [ + "Backups" + ] + } + }, + "/backups/{id}/cancel": { + "post": { + "description": "Flips the parent `backups` row + its latest `backup_jobs` row to\n`failed` with reason `\"cancelled by user \"`. The in-process\n`CancellationToken` is observed on the next heartbeat tick (≤5s), so the\nengine exits cleanly and rollback reaps the sidecar. Idempotent: cancelling\nan already-terminal backup is a 200 with `cancelled = 0`.", + "operationId": "cancel_backup", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CancelBackupResponse" + } + } + }, + "description": "Cancel processed (idempotent)" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Backup not found" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Cancel a single in-flight backup.", + "tags": [ + "Backups" + ] + } + }, + "/backups/{id}/children": { + "get": { + "description": "Each entry in `children` corresponds to one `external_service_backups` row,\njoined with `external_services` so the caller receives the service name and\ntype without a second request.\n\nReturns an empty `{ \"children\": [] }` — **not 404** — when the parent\nbackup exists but has no children (e.g. control-plane backups).\nReturns 404 when the parent backup itself does not exist.", + "operationId": "list_backup_children", + "parameters": [ + { + "description": "Integer row id of the parent backup", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChildBackupListResponse" + } + } + }, + "description": "Child backup list (may be empty)" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Parent backup not found" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List the external-service child backups that belong to a parent backup.", + "tags": [ + "Backups" + ] + } + }, + "/blob": { + "delete": { + "operationId": "blob_delete", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeleteBlobRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeleteBlobResponse" + } + } + }, + "description": "Blobs deleted successfully" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Delete blobs", + "tags": [ + "Blob" + ] + }, + "get": { + "operationId": "blob_list", + "parameters": [ + { + "description": "Maximum number of items to return", + "in": "query", + "name": "limit", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Prefix to filter by", + "in": "query", + "name": "prefix", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Continuation token for pagination", + "in": "query", + "name": "cursor", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListBlobsResponse" + } + } + }, + "description": "List of blobs" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List blobs", + "tags": [ + "Blob" + ] + }, + "post": { + "operationId": "blob_put", + "requestBody": { + "content": { + "application/octet-stream": { + "schema": { + "type": "string" + } + } + }, + "description": "Binary blob data", + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BlobResponse" + } + } + }, + "description": "Blob uploaded successfully" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Invalid request" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Upload a blob", + "tags": [ + "Blob" + ] + } + }, + "/blob/copy": { + "post": { + "operationId": "blob_copy", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CopyBlobRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BlobResponse" + } + } + }, + "description": "Blob copied successfully" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Invalid request" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Source blob not found" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Copy a blob to a new location", + "tags": [ + "Blob" + ] + } + }, + "/blob/disable": { + "delete": { + "operationId": "blob_disable", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DisableBlobResponse" + } + } + }, + "description": "Blob service disabled" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Blob service not enabled" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Disable Blob service", + "tags": [ + "Blob Management" + ] + } + }, + "/blob/enable": { + "post": { + "operationId": "blob_enable", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnableBlobRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnableBlobResponse" + } + } + }, + "description": "Blob service enabled" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Enable Blob service", + "tags": [ + "Blob Management" + ] + } + }, + "/blob/status": { + "get": { + "operationId": "blob_status", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BlobStatusResponse" + } + } + }, + "description": "Blob service status" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get Blob service status", + "tags": [ + "Blob Management" + ] + } + }, + "/blob/update": { + "patch": { + "operationId": "blob_update", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateBlobRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateBlobResponse" + } + } + }, + "description": "Blob service updated" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Blob service not enabled" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Update Blob service configuration", + "tags": [ + "Blob Management" + ] + } + }, + "/blob/{project_id}/{path}": { + "get": { + "operationId": "blob_download", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Blob path", + "in": "path", + "name": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Blob content" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Blob not found" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Download a blob", + "tags": [ + "Blob" + ] + }, + "head": { + "operationId": "blob_head", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Blob path", + "in": "path", + "name": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Blob metadata in headers" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Blob not found" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get blob metadata", + "tags": [ + "Blob" + ] + } + }, + "/dashboard/projects-analytics": { + "get": { + "description": "Returns unique visitor counts and hourly sparkline data for all requested projects\nusing only 2 SQL queries instead of 2×N per-project queries.", + "operationId": "get_dashboard_projects_analytics", + "parameters": [ + { + "description": "Comma-separated list of project IDs", + "in": "query", + "name": "project_ids", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Start date for filtering", + "in": "query", + "name": "start_date", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "End date for filtering", + "in": "query", + "name": "end_date", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DashboardProjectsAnalyticsResponse" + } + } + }, + "description": "Successfully retrieved batch analytics" + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get dashboard analytics for multiple projects in a single batch request", + "tags": [ + "Events" + ] + } + }, + "/deployments/activity-graph": { + "get": { + "operationId": "get_activity_graph", + "parameters": [ + { + "description": "Filter by project ID (optional)", + "in": "query", + "name": "project_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Filter by environment ID (optional)", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Number of days to include (default: 365)", + "in": "query", + "name": "days", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ActivityGraphResponse" + } + } + }, + "description": "Successfully retrieved activity graph" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get deployment activity graph showing daily deployment counts\nSimilar to GitHub's contribution graph", + "tags": [ + "Deployments" + ] + } + }, + "/deployments/{deployment_id}/vulnerability-scan": { + "get": { + "operationId": "get_scan_by_deployment", + "parameters": [ + { + "description": "Deployment ID", + "in": "path", + "name": "deployment_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ScanResponse" + } + } + }, + "description": "Scan for the specified deployment" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "No scan found for deployment" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Vulnerability Scans" + ] + } + }, + "/deployments/{id}/metrics": { + "get": { + "operationId": "DeploymentMetricsGetRange", + "parameters": [ + { + "description": "Deployment ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Metric name, e.g. `\"pg.connections_active\"`.", + "in": "query", + "name": "metric", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Time window: `\"1h\"` | `\"6h\"` | `\"24h\"` | `\"7d\"`.", + "in": "query", + "name": "range", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Optional histogram percentile (0–100). When provided, the endpoint\nfetches histogram buckets and computes the requested quantile.", + "in": "query", + "name": "percentile", + "required": false, + "schema": { + "format": "double", + "type": [ + "number", + "null" + ] + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/MetricDataPoint" + }, + "type": "array" + } + } + }, + "description": "Metric time series data points" + }, + "400": { + "description": "Invalid query parameters" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + }, + "503": { + "description": "Metrics store not available" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Fetch a time-series range for a single metric on a deployment.", + "tags": [ + "Metrics" + ] + } + }, + "/deployments/{id}/metrics/enable": { + "patch": { + "description": "When `enabled=true`, seeds the default container alert rules for the\ndeployment via [`temps_monitoring::seed_default_container_rules`] (idempotent).", + "operationId": "DeploymentMetricsToggle", + "parameters": [ + { + "description": "Deployment ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ToggleDeploymentMetricsRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Metrics toggle applied" + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Enable or disable OTLP metric ingestion for a deployment.", + "tags": [ + "Metrics" + ] + } + }, + "/deployments/{id}/metrics/latest": { + "get": { + "operationId": "DeploymentMetricsGetLatest", + "parameters": [ + { + "description": "Deployment ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "additionalProperties": { + "format": "double", + "type": "number" + }, + "propertyNames": { + "type": "string" + }, + "type": "object" + } + } + }, + "description": "Map of metric name to latest value" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + }, + "503": { + "description": "Metrics store not available" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Fetch the most-recent metric values for a deployment.", + "tags": [ + "Metrics" + ] + } + }, + "/dns-providers": { + "get": { + "operationId": "list_dns_providers", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/DnsProviderResponse" + }, + "type": "array" + } + } + }, + "description": "List of DNS providers" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List all DNS providers", + "tags": [ + "DNS Providers" + ] + }, + "post": { + "description": "The provider's credentials will be tested before creation.\nIf the connection test fails, the provider will not be created.", + "operationId": "create_dns_provider", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateDnsProviderRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DnsProviderResponse" + } + } + }, + "description": "DNS provider created" + }, + "400": { + "description": "Invalid request or connection test failed" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Create a new DNS provider", + "tags": [ + "DNS Providers" + ] + } + }, + "/dns-providers/{id}": { + "delete": { + "operationId": "delete_dns_provider", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "DNS provider deleted" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Provider not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Delete a DNS provider", + "tags": [ + "DNS Providers" + ] + }, + "get": { + "operationId": "get_dns_provider", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DnsProviderResponse" + } + } + }, + "description": "DNS provider details" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Provider not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get a DNS provider by ID", + "tags": [ + "DNS Providers" + ] + }, + "put": { + "description": "If new credentials are supplied, they are tested before the update is\npersisted (same as creation) -- otherwise a provider's credentials (and,\nfor Pebble, its target URL) could be swapped for something invalid or\nunsafe without ever going through validation.", + "operationId": "update_provider", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateDnsProviderRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DnsProviderResponse" + } + } + }, + "description": "DNS provider updated" + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Provider not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Update a DNS provider", + "tags": [ + "DNS Providers" + ] + } + }, + "/dns-providers/{id}/domains": { + "get": { + "operationId": "list_managed_domains", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/ManagedDomainResponse" + }, + "type": "array" + } + } + }, + "description": "List of managed domains" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Provider not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List managed domains for a provider", + "tags": [ + "DNS Providers" + ] + }, + "post": { + "operationId": "add_managed_domain", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AddManagedDomainApiRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ManagedDomainResponse" + } + } + }, + "description": "Managed domain added" + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Provider not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Add a managed domain to a provider", + "tags": [ + "DNS Providers" + ] + } + }, + "/dns-providers/{id}/test": { + "post": { + "operationId": "test_provider_connection", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ConnectionTestResult" + } + } + }, + "description": "Connection test result" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Provider not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Test provider connection", + "tags": [ + "DNS Providers" + ] + } + }, + "/dns-providers/{id}/zones": { + "get": { + "operationId": "list_provider_zones", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ZoneListResponse" + } + } + }, + "description": "List of zones" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Provider not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List zones available in a provider", + "tags": [ + "DNS Providers" + ] + } + }, + "/dns-providers/{provider_id}/domains/{domain}": { + "delete": { + "operationId": "remove_managed_domain", + "parameters": [ + { + "in": "path", + "name": "provider_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "in": "path", + "name": "domain", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Managed domain removed" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Domain not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Remove a managed domain", + "tags": [ + "DNS Providers" + ] + }, + "patch": { + "operationId": "update_managed_domain", + "parameters": [ + { + "in": "path", + "name": "provider_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "in": "path", + "name": "domain", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateManagedDomainApiRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ManagedDomainResponse" + } + } + }, + "description": "Managed domain updated" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Domain not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Update a managed domain's settings (hostname mode, sync opt-in, auto-manage).", + "tags": [ + "DNS Providers" + ] + } + }, + "/dns-providers/{provider_id}/domains/{domain}/apply-hostname-mode": { + "post": { + "operationId": "apply_hostname_mode", + "parameters": [ + { + "in": "path", + "name": "provider_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "in": "path", + "name": "domain", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApplyHostnameModeRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HostnamePreviewResponse" + } + } + }, + "description": "Hostname mode applied" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions or token lacks zone access" + }, + "404": { + "description": "Domain not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Apply a hostname mode to a managed domain (persist + optional DNS sync +\nroute reload).", + "tags": [ + "DNS Providers" + ] + } + }, + "/dns-providers/{provider_id}/domains/{domain}/hostname-preview": { + "get": { + "operationId": "preview_hostname_mode", + "parameters": [ + { + "description": "Target mode: standard|flat", + "in": "query", + "name": "mode", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Include DNS record changes", + "in": "query", + "name": "sync", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "in": "path", + "name": "provider_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "in": "path", + "name": "domain", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HostnamePreviewResponse" + } + } + }, + "description": "Hostname mode preview" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Domain not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Preview the impact of switching a managed domain's hostname mode.", + "tags": [ + "DNS Providers" + ] + } + }, + "/dns-providers/{provider_id}/domains/{domain}/verify": { + "post": { + "operationId": "verify_managed_domain", + "parameters": [ + { + "in": "path", + "name": "provider_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "in": "path", + "name": "domain", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ManagedDomainResponse" + } + } + }, + "description": "Domain verification result" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Domain not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Verify a managed domain", + "tags": [ + "DNS Providers" + ] + } + }, + "/dns/lookup": { + "get": { + "operationId": "lookup_dns_a_records", + "parameters": [ + { + "description": "Domain name to lookup", + "in": "query", + "name": "domain", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DnsLookupResponse" + } + } + }, + "description": "Successfully retrieved DNS A records" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DnsLookupError" + } + } + }, + "description": "Invalid domain name or lookup failed" + } + }, + "summary": "Lookup DNS A records for a domain", + "tags": [ + "DNS" + ] + } + }, + "/domains": { + "get": { + "operationId": "list_domains", + "parameters": [ + { + "description": "Page number (1-indexed)", + "example": 1, + "in": "query", + "name": "page", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + } + }, + { + "description": "Number of items per page (max 100)", + "example": 20, + "in": "query", + "name": "page_size", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + } + }, + { + "description": "Search domains by name (substring match)", + "example": "example.com", + "in": "query", + "name": "search", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListDomainsResponse" + } + } + }, + "description": "Domains retrieved successfully" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List all domains", + "tags": [ + "Domains" + ] + }, + "post": { + "description": "Creates a new domain and automatically requests a Let's Encrypt challenge.\nYou can specify the challenge type (HTTP-01 or DNS-01) in the request.\n\n- **HTTP-01**: Validates domain ownership by placing a file on your web server at `/.well-known/acme-challenge/`\n- **DNS-01**: Validates domain ownership by adding a TXT record to your DNS (required for wildcard domains)", + "operationId": "create_domain", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateDomainRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DomainResponse" + } + } + }, + "description": "Domain created successfully" + }, + "400": { + "description": "Invalid input" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Create a new domain", + "tags": [ + "Domains" + ] + } + }, + "/domains/by-host/{hostname}": { + "get": { + "operationId": "get_domain_by_host", + "parameters": [ + { + "description": "Domain hostname", + "in": "path", + "name": "hostname", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DomainResponse" + } + } + }, + "description": "Domain details retrieved successfully" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Domain not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get domain details by hostname", + "tags": [ + "Domains" + ] + } + }, + "/domains/by-host/{hostname}/cert-status": { + "get": { + "description": "Returns the current cert lifecycle state for a single hostname (from the\n`domains` row) plus the most recent on-demand issuance attempt (from the\n`on_demand_cert_attempts` audit log). This is the operator's first-line\ndiagnostic, surfaced by `temps domain cert-status` (ADR-018 §5). Returns the\nhostname with `None` fields when no on-demand activity exists for it (never a\n404, so the CLI can render \"no attempts recorded\").", + "operationId": "get_on_demand_cert_status", + "parameters": [ + { + "description": "Domain hostname", + "in": "path", + "name": "hostname", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CertStatusResponse" + } + } + }, + "description": "On-demand cert status retrieved successfully" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get on-demand TLS certificate status for a hostname", + "tags": [ + "Domains" + ] + } + }, + "/domains/on-demand-certs": { + "get": { + "description": "Returns rows from the append-only `on_demand_cert_attempts` audit log\n(ADR-018 §5), newest first, each joined with the current authoritative cert\nstate (`status`, `expiration_time`, `backoff_until`) from the `domains` row.\nThis backs the console \"Certificates\" surface. No certificate or private-key\nmaterial is returned — only audit metadata.", + "operationId": "list_on_demand_certs", + "parameters": [ + { + "description": "Page number (1-indexed)", + "example": 1, + "in": "query", + "name": "page", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + } + }, + { + "description": "Number of items per page (max 100)", + "example": 20, + "in": "query", + "name": "page_size", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListOnDemandCertsResponse" + } + } + }, + "description": "On-demand cert attempts retrieved successfully" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List on-demand TLS certificate attempts", + "tags": [ + "Domains" + ] + } + }, + "/domains/{domain_id}/order": { + "delete": { + "description": "Cancels the current ACME order for a domain and clears all challenge data.\nThis allows you to start over with a new order if the previous one failed or got stuck.", + "operationId": "cancel_domain_order", + "parameters": [ + { + "description": "Domain ID", + "in": "path", + "name": "domain_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DomainResponse" + } + } + }, + "description": "Order cancelled successfully" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Domain not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Cancel ACME order for a domain", + "tags": [ + "Domains" + ] + }, + "get": { + "operationId": "get_domain_order", + "parameters": [ + { + "description": "Domain ID", + "in": "path", + "name": "domain_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AcmeOrderResponse" + } + } + }, + "description": "Order retrieved successfully" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Order not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get ACME order for a domain", + "tags": [ + "Domains" + ] + }, + "post": { + "description": "Creates a new ACME order with Let's Encrypt for the specified domain.\nIf an order already exists, you should cancel it first using the cancel-order endpoint.\nReturns the challenge details that need to be fulfilled (DNS record or HTTP token).", + "operationId": "create_or_recreate_order", + "parameters": [ + { + "description": "Domain ID", + "in": "path", + "name": "domain_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DomainChallengeResponse" + } + } + }, + "description": "Order created successfully" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Domain not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Create or recreate ACME order for a domain", + "tags": [ + "Domains" + ] + } + }, + "/domains/{domain_id}/order/finalize": { + "post": { + "description": "Finalizes the ACME order by completing the challenge validation and requesting the certificate.\nThis should be called after the challenge has been set up (DNS record added or HTTP token served).", + "operationId": "finalize_order", + "parameters": [ + { + "description": "Domain ID", + "in": "path", + "name": "domain_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DomainResponse" + } + } + }, + "description": "Order finalized successfully" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Domain or order not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Finalize ACME order for a domain", + "tags": [ + "Domains" + ] + } + }, + "/domains/{domain_id}/setup-dns": { + "post": { + "description": "This endpoint automatically creates the required DNS TXT records for ACME DNS-01 challenge\nvalidation using a configured DNS provider. The domain must have an active DNS challenge\npending (created via POST /domains/{id}/order with dns-01 challenge type).\n\nThis is similar to how email domain DNS records are auto-provisioned.", + "operationId": "setup_dns_challenge", + "parameters": [ + { + "description": "Domain ID", + "in": "path", + "name": "domain_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SetupDnsChallengeRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SetupDnsChallengeResponse" + } + } + }, + "description": "DNS records created successfully" + }, + "400": { + "description": "Bad request - DNS provider not configured or no challenge pending" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Domain or DNS provider not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Setup DNS challenge records automatically using a DNS provider", + "tags": [ + "Domains" + ] + } + }, + "/domains/{domain}": { + "delete": { + "operationId": "delete_domain", + "parameters": [ + { + "description": "Domain name", + "in": "path", + "name": "domain", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Domain deleted successfully" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Domain not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Delete a domain", + "tags": [ + "Domains" + ] + }, + "get": { + "operationId": "get_domain_by_id", + "parameters": [ + { + "description": "Domain ID", + "in": "path", + "name": "domain", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DomainResponse" + } + } + }, + "description": "Domain retrieved successfully" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Domain not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get domain by ID", + "tags": [ + "Domains" + ] + } + }, + "/domains/{domain}/challenge-token": { + "get": { + "operationId": "get_challenge_token", + "parameters": [ + { + "description": "Domain name", + "in": "path", + "name": "domain", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + }, + "description": "Challenge token retrieved successfully" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Challenge not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get challenge token for a domain (returns plain text token)", + "tags": [ + "Domains" + ] + } + }, + "/domains/{domain}/http-challenge-debug": { + "get": { + "description": "Returns detailed debug information for HTTP-01 challenge including:\n- Whether a challenge exists for the domain\n- The challenge token and URL that Let's Encrypt will access\n- DNS resolution information showing where the domain currently points\n\nThis is useful for debugging why HTTP-01 challenges fail.", + "operationId": "get_http_challenge_debug", + "parameters": [ + { + "description": "Domain name", + "in": "path", + "name": "domain", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HttpChallengeDebugResponse" + } + } + }, + "description": "Debug information retrieved successfully" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get HTTP challenge debug information", + "tags": [ + "Domains" + ] + } + }, + "/domains/{domain}/provision": { + "post": { + "operationId": "provision_domain", + "parameters": [ + { + "description": "Domain name", + "in": "path", + "name": "domain", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProvisionResponse" + } + } + }, + "description": "Certificate provisioning initiated" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Domain not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Provision a domain certificate", + "tags": [ + "Domains" + ] + } + }, + "/domains/{domain}/renew": { + "post": { + "description": "For HTTP-01 domains: Automatically renews the certificate\nFor DNS-01 domains (wildcards): Creates a new ACME order and returns challenge data", + "operationId": "renew_domain", + "parameters": [ + { + "description": "Domain name", + "in": "path", + "name": "domain", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProvisionResponse" + } + } + }, + "description": "Certificate renewal initiated" + }, + "202": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DomainChallengeResponse" + } + } + }, + "description": "DNS challenge created - manual action required" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Domain not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Renew domain certificate", + "tags": [ + "Domains" + ] + } + }, + "/domains/{domain}/status": { + "get": { + "operationId": "check_domain_status", + "parameters": [ + { + "description": "Domain ID", + "in": "path", + "name": "domain", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DomainResponse" + } + } + }, + "description": "Domain status retrieved successfully" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Domain not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Check domain status", + "tags": [ + "Domains" + ] + } + }, + "/drop/inspect": { + "post": { + "operationId": "inspect_drop_archive", + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "$ref": "#/components/schemas/DropArchiveUpload" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DropInspectionResponse" + } + } + }, + "description": "Detected deployable project roots" + }, + "400": { + "description": "Invalid or unsupported archive" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Inspect a source ZIP without creating a project or retaining the upload.", + "tags": [ + "Projects" + ] + } + }, + "/email-domains": { + "get": { + "operationId": "list_email_domains", + "parameters": [ + { + "description": "Only return domains belonging to this provider", + "in": "query", + "name": "provider_id", + "required": false, + "schema": { + "format": "int32", + "type": [ + "integer", + "null" + ] + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/EmailDomainResponse" + }, + "type": "array" + } + } + }, + "description": "List of email domains" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List all email domains", + "tags": [ + "Email Domains" + ] + }, + "post": { + "operationId": "create_email_domain", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateEmailDomainRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EmailDomainWithDnsResponse" + } + } + }, + "description": "Domain created successfully" + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Create a new email domain", + "tags": [ + "Email Domains" + ] + } + }, + "/email-domains/by-domain/{domain}": { + "get": { + "operationId": "get_domain_by_name", + "parameters": [ + { + "description": "Domain name (e.g., 'mail.example.com')", + "in": "path", + "name": "domain", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EmailDomainWithDnsResponse" + } + } + }, + "description": "Email domain details with DNS records" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Domain not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get an email domain by domain name with DNS records", + "tags": [ + "Email Domains" + ] + } + }, + "/email-domains/{id}": { + "delete": { + "operationId": "delete_email_domain", + "parameters": [ + { + "description": "Domain ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "Domain deleted" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Domain not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Delete an email domain", + "tags": [ + "Email Domains" + ] + }, + "get": { + "operationId": "get_domain", + "parameters": [ + { + "description": "Domain ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EmailDomainWithDnsResponse" + } + } + }, + "description": "Email domain details with DNS records" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Domain not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get an email domain by ID with DNS records", + "tags": [ + "Email Domains" + ] + } + }, + "/email-domains/{id}/dns-records": { + "get": { + "operationId": "get_domain_dns_records", + "parameters": [ + { + "description": "Domain ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/DnsRecordResponse" + }, + "type": "array" + } + } + }, + "description": "DNS records for the domain" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Domain not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get DNS records for an email domain", + "tags": [ + "Email Domains" + ] + } + }, + "/email-domains/{id}/setup-dns": { + "post": { + "operationId": "setup_dns", + "parameters": [ + { + "description": "Email Domain ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SetupDnsRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SetupDnsResponse" + } + } + }, + "description": "DNS records setup result" + }, + "400": { + "description": "Invalid request or DNS provider not configured" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Domain not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Setup DNS records for an email domain using a configured DNS provider", + "tags": [ + "Email Domains" + ] + } + }, + "/email-domains/{id}/verify": { + "post": { + "operationId": "verify_domain", + "parameters": [ + { + "description": "Domain ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EmailDomainWithDnsResponse" + } + } + }, + "description": "Domain verification result with DNS records" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Domain not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Verify an email domain's DNS configuration", + "tags": [ + "Email Domains" + ] + } + }, + "/email-providers": { + "get": { + "operationId": "list_email_providers", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/EmailProviderResponse" + }, + "type": "array" + } + } + }, + "description": "List of email providers" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List all email providers", + "tags": [ + "Email Providers" + ] + }, + "post": { + "operationId": "create_email_provider", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateEmailProviderRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EmailProviderResponse" + } + } + }, + "description": "Provider created successfully" + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Create a new email provider", + "tags": [ + "Email Providers" + ] + } + }, + "/email-providers/{id}": { + "delete": { + "operationId": "delete_email_provider", + "parameters": [ + { + "description": "Provider ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "Provider deleted" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Provider not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Delete an email provider", + "tags": [ + "Email Providers" + ] + }, + "get": { + "operationId": "get_email_provider", + "parameters": [ + { + "description": "Provider ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EmailProviderResponse" + } + } + }, + "description": "Email provider details" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Provider not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get an email provider by ID", + "tags": [ + "Email Providers" + ] + }, + "patch": { + "description": "Partial update — any field left out keeps its current value. Most importantly,\nomitting the credential block (`ses_credentials`/`scaleway_credentials`/`smtp_credentials`)\npreserves the stored secret, so operators can rename a provider without re-typing\npasswords. `provider_type` is immutable; to switch providers, delete and recreate.", + "operationId": "update_email_provider", + "parameters": [ + { + "description": "Provider ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateEmailProviderRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EmailProviderResponse" + } + } + }, + "description": "Provider updated" + }, + "400": { + "description": "Validation error" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Provider not found" + }, + "409": { + "description": "Provider type mismatch" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Update an email provider", + "tags": [ + "Email Providers" + ] + } + }, + "/email-providers/{id}/test": { + "post": { + "operationId": "test_provider", + "parameters": [ + { + "description": "Provider ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TestEmailRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TestEmailResponse" + } + } + }, + "description": "Test email result" + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Provider not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Test an email provider by sending a test email to the logged-in user", + "tags": [ + "Email Providers" + ] + } + }, + "/email-providers/{id}/tracking/setup": { + "post": { + "operationId": "setup_email_tracking", + "parameters": [ + { + "description": "Provider ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EmailTrackingSetupResponse" + } + } + }, + "description": "Setup completed" + }, + "400": { + "description": "Provider does not support event tracking" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Provider not found" + }, + "502": { + "description": "An AWS call failed — the response detail names the failed step" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "One-click AWS-side setup of SES event tracking (SNS topic + webhook\nsubscription + SESv2 event destination), using the provider's stored\ncredentials.", + "tags": [ + "Email Providers" + ] + } + }, + "/email-providers/{id}/tracking/status": { + "get": { + "operationId": "get_email_tracking_status", + "parameters": [ + { + "description": "Provider ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EmailTrackingStatusResponse" + } + } + }, + "description": "Event tracking status" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Provider not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Live status of SES event tracking for a provider", + "tags": [ + "Email Providers" + ] + } + }, + "/emails": { + "get": { + "operationId": "list_emails", + "parameters": [ + { + "in": "query", + "name": "domain_id", + "required": false, + "schema": { + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + { + "in": "query", + "name": "project_id", + "required": false, + "schema": { + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + { + "in": "query", + "name": "status", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "in": "query", + "name": "from_address", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "in": "query", + "name": "page", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + } + }, + { + "in": "query", + "name": "page_size", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PaginatedEmailsResponse" + } + } + }, + "description": "List of emails" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List emails with optional filtering", + "tags": [ + "Emails" + ] + }, + "post": { + "operationId": "send_email", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SendEmailRequestBody" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SendEmailResponseBody" + } + } + }, + "description": "Email sent successfully" + }, + "400": { + "description": "Invalid request or domain not verified" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Send an email", + "tags": [ + "Emails" + ] + } + }, + "/emails/events": { + "get": { + "operationId": "get_global_events", + "parameters": [ + { + "description": "Filter by event type (open, click)", + "in": "query", + "name": "event_type", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Page number (default: 1)", + "in": "query", + "name": "page", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + { + "description": "Page size (default: 20, max: 100)", + "in": "query", + "name": "page_size", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PaginatedEventsResponse" + } + } + }, + "description": "Paginated tracking events" + }, + "401": { + "description": "Unauthorized" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "GET /emails/events", + "tags": [ + "Email Tracking" + ] + } + }, + "/emails/events/stats": { + "get": { + "operationId": "get_global_event_stats", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GlobalEventStatsResponse" + } + } + }, + "description": "Global tracking statistics" + }, + "401": { + "description": "Unauthorized" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "GET /emails/events/stats", + "tags": [ + "Email Tracking" + ] + } + }, + "/emails/stats": { + "get": { + "operationId": "get_email_stats", + "parameters": [ + { + "description": "Optional domain ID to filter stats", + "in": "query", + "name": "domain_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EmailStatsResponse" + } + } + }, + "description": "Email statistics" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get email statistics", + "tags": [ + "Emails" + ] + } + }, + "/emails/validate": { + "post": { + "operationId": "validate_email", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidateEmailRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidateEmailResponse" + } + } + }, + "description": "Email validation result" + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Validate an email address", + "tags": [ + "Email Validation" + ] + } + }, + "/emails/{email_id}/track/click/{link_index}": { + "get": { + "description": "This endpoint replaces original links in tracked emails.\nNo authentication required - it's called when the recipient clicks a link.", + "operationId": "track_click", + "parameters": [ + { + "description": "Email ID (UUID)", + "in": "path", + "name": "email_id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Link index", + "in": "path", + "name": "link_index", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "302": { + "description": "Redirect to original URL" + }, + "404": { + "description": "Link not found" + } + }, + "summary": "Track email link click - redirects to original URL", + "tags": [ + "Email Tracking" + ] + } + }, + "/emails/{email_id}/track/open": { + "get": { + "description": "This endpoint is embedded as an tag in emails.\nNo authentication required - it's called by the email client.", + "operationId": "track_open", + "parameters": [ + { + "description": "Email ID (UUID)", + "in": "path", + "name": "email_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "1x1 transparent tracking pixel" + }, + "404": { + "description": "Email not found" + } + }, + "summary": "Track email open - returns a 1x1 transparent GIF", + "tags": [ + "Email Tracking" + ] + } + }, + "/emails/{id}": { + "get": { + "operationId": "get_email", + "parameters": [ + { + "description": "Email ID (UUID)", + "in": "path", + "name": "id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EmailResponse" + } + } + }, + "description": "Email details" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Email not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get an email by ID", + "tags": [ + "Emails" + ] + } + }, + "/emails/{id}/tracking": { + "get": { + "operationId": "get_email_tracking", + "parameters": [ + { + "description": "Email ID (UUID)", + "in": "path", + "name": "id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EmailTrackingResponse" + } + } + }, + "description": "Tracking summary" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Email not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get email tracking summary", + "tags": [ + "Email Tracking" + ] + } + }, + "/emails/{id}/tracking/events": { + "get": { + "operationId": "get_email_events", + "parameters": [ + { + "description": "Email ID (UUID)", + "in": "path", + "name": "id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Filter by event type (open, click)", + "in": "query", + "name": "event_type", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/TrackingEventResponse" + }, + "type": "array" + } + } + }, + "description": "Tracking events" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Email not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get email tracking events", + "tags": [ + "Email Tracking" + ] + } + }, + "/emails/{id}/tracking/links": { + "get": { + "operationId": "get_email_links", + "parameters": [ + { + "description": "Email ID (UUID)", + "in": "path", + "name": "id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/TrackedLinkResponse" + }, + "type": "array" + } + } + }, + "description": "Tracked links" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Email not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get tracked links for an email", + "tags": [ + "Email Tracking" + ] + } + }, + "/external-services": { + "get": { + "operationId": "list_services", + "parameters": [ + { + "description": "Page number (1-indexed)", + "example": 1, + "in": "query", + "name": "page", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + } + }, + { + "description": "Number of items per page (max 100)", + "example": 20, + "in": "query", + "name": "page_size", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + } + }, + { + "in": "query", + "name": "sort_by", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "in": "query", + "name": "sort_order", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/ExternalServiceInfo" + }, + "type": "array" + } + } + }, + "description": "List of external services" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Get all external services", + "tags": [ + "External Services" + ] + }, + "post": { + "operationId": "create_service", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateExternalServiceRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExternalServiceInfo" + } + } + }, + "description": "Service created successfully" + }, + "400": { + "description": "Invalid request" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Create new external service", + "tags": [ + "External Services" + ] + } + }, + "/external-services/available-containers": { + "get": { + "operationId": "list_available_containers", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/AvailableContainerInfo" + }, + "type": "array" + } + } + }, + "description": "List of available containers" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List available Docker containers that can be imported as services", + "tags": [ + "External Services" + ] + } + }, + "/external-services/by-slug/{slug}": { + "get": { + "operationId": "get_service_by_slug", + "parameters": [ + { + "description": "External service slug", + "in": "path", + "name": "slug", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExternalServiceDetails" + } + } + }, + "description": "External service details" + }, + "404": { + "description": "Service not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Get external service details by slug", + "tags": [ + "External Services" + ] + } + }, + "/external-services/health-status-batch": { + "get": { + "description": "Powers the status dot on the Storage list page. Pass a comma-separated\nlist of service IDs via `?ids=1,2,3`. Omit to get every service.", + "operationId": "list_service_health_statuses", + "parameters": [ + { + "description": "Comma-separated service IDs. Omit for all services.", + "in": "query", + "name": "ids", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceHealthStatusBatchResponse" + } + } + }, + "description": "Batch of current health statuses" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Current health status for many services at once", + "tags": [ + "External Services" + ] + } + }, + "/external-services/import": { + "post": { + "operationId": "import_external_service", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ImportExternalServiceRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExternalServiceInfo" + } + } + }, + "description": "Service imported successfully" + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Import an existing Docker container as a managed external service", + "tags": [ + "External Services" + ] + } + }, + "/external-services/projects/{project_id}": { + "get": { + "operationId": "list_project_services", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Page number (1-indexed)", + "example": 1, + "in": "query", + "name": "page", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + } + }, + { + "description": "Number of items per page (max 100)", + "example": 20, + "in": "query", + "name": "page_size", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + } + }, + { + "in": "query", + "name": "sort_by", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "in": "query", + "name": "sort_order", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/ProjectServiceInfo" + }, + "type": "array" + } + } + }, + "description": "List of services linked to project" + }, + "404": { + "description": "Project not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "List services linked to a project", + "tags": [ + "External Services" + ] + } + }, + "/external-services/projects/{project_id}/environment": { + "get": { + "operationId": "get_project_service_environment_variables", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "additionalProperties": { + "additionalProperties": { + "type": "string" + }, + "propertyNames": { + "type": "string" + }, + "type": "object" + }, + "propertyNames": { + "format": "int32", + "type": "integer" + }, + "type": "object" + } + } + }, + "description": "Map of service IDs to their environment variables" + }, + "404": { + "description": "Project not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Get all environment variables for all services linked to a project", + "tags": [ + "External Services" + ] + } + }, + "/external-services/providers/metadata": { + "get": { + "operationId": "get_providers_metadata", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/ProviderMetadata" + }, + "type": "array" + } + } + }, + "description": "List of provider metadata" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Get provider metadata (display names, icons, descriptions)", + "tags": [ + "External Services" + ] + } + }, + "/external-services/providers/metadata/{service_type}": { + "get": { + "operationId": "get_provider_metadata", + "parameters": [ + { + "description": "Service type (mongodb, postgres, redis, s3)", + "in": "path", + "name": "service_type", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProviderMetadata" + } + } + }, + "description": "Provider metadata" + }, + "404": { + "description": "Provider not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Get metadata for a specific provider", + "tags": [ + "External Services" + ] + } + }, + "/external-services/types": { + "get": { + "operationId": "get_service_types", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/ServiceTypeRoute" + }, + "type": "array" + } + } + }, + "description": "List of available service types" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Get available service types", + "tags": [ + "External Services" + ] + } + }, + "/external-services/types/{service_type}/parameters": { + "get": { + "operationId": "get_service_type_parameters", + "parameters": [ + { + "description": "Service type", + "in": "path", + "name": "service_type", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Service type parameter schema" + }, + "404": { + "description": "Service type not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Get parameter schema for a specific service type", + "tags": [ + "External Services" + ] + } + }, + "/external-services/{id}": { + "delete": { + "operationId": "delete_service", + "parameters": [ + { + "description": "External service ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "Service deleted successfully" + }, + "400": { + "description": "Cannot delete: service is still linked to projects" + }, + "404": { + "description": "Service not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Delete external service", + "tags": [ + "External Services" + ] + }, + "get": { + "operationId": "get_service", + "parameters": [ + { + "description": "External service ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExternalServiceDetails" + } + } + }, + "description": "External service details" + }, + "404": { + "description": "Service not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Get external service details", + "tags": [ + "External Services" + ] + }, + "put": { + "operationId": "update_service", + "parameters": [ + { + "description": "External service ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateExternalServiceRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExternalServiceInfo" + } + } + }, + "description": "Service updated successfully" + }, + "400": { + "description": "Invalid request" + }, + "404": { + "description": "Service not found" + }, + "409": { + "description": "A major upgrade is in progress for this service" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Update external service", + "tags": [ + "External Services" + ] + } + }, + "/external-services/{id}/cluster-health": { + "get": { + "description": "Reads pg_auto_failover's `pgautofailover.node` table from the cluster's\nmonitor (TLS, autoctl_node) and joins each member with its\n`pg_stat_replication` row from the current primary. Returns one row per\ndata member with role/state, sync state, and replay lag.\n\nReturns `200` with `monitor_error` set when the monitor is briefly\nunreachable (UI surfaces it as a banner above the table); the table\nitself is empty in that case. Returns `400` for non-cluster services.", + "operationId": "get_cluster_health", + "parameters": [ + { + "description": "External service ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ClusterHealthReportResponse" + } + } + }, + "description": "Per-member cluster health report" + }, + "400": { + "description": "Service is not a cluster" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Service not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Per-member health for a Postgres HA cluster.", + "tags": [ + "External Services" + ] + } + }, + "/external-services/{id}/health-check": { + "post": { + "description": "Triggers the same engine-specific probe as the background monitor, writes\na history row, updates the denormalized fields on `external_services`, and\nfires alerts on the Nth consecutive failure (so consecutive-failure state\nstays honest). Returns the fresh snapshot the UI can display immediately.", + "operationId": "trigger_service_health_check", + "parameters": [ + { + "description": "External service ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceHealthResponse" + } + } + }, + "description": "Fresh health snapshot after probing" + }, + "404": { + "description": "Service not found" + }, + "500": { + "description": "Internal server error" + }, + "503": { + "description": "Health monitor not running on this node" + } + }, + "summary": "Run a health check for one service right now", + "tags": [ + "External Services" + ] + } + }, + "/external-services/{id}/health-status": { + "get": { + "description": "Returns the latest health probe result recorded by\n`ExternalServiceHealthMonitor`, plus recent check history for sparklines\nand a 24-hour uptime percentage. Safe to poll from the UI every 30s.", + "operationId": "get_service_health_status", + "parameters": [ + { + "description": "External service ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Max number of recent checks (default 50, max 200)", + "in": "query", + "name": "limit", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceHealthResponse" + } + } + }, + "description": "Current health + recent history" + }, + "404": { + "description": "Service not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Persisted health status for an external service", + "tags": [ + "External Services" + ] + } + }, + "/external-services/{id}/members": { + "post": { + "description": "Currently only `replica` members can be added at runtime. The\nresponse is **202 Accepted** as soon as the validation passes and\nthe placeholder `service_members` row is inserted. The actual\ncontainer provisioning + DNS registration runs in the background;\npoll `GET /external-services/{id}/members/{member_id}` to watch\n`provisioning_step` advance through the phases.", + "operationId": "add_cluster_member", + "parameters": [ + { + "description": "External service ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AddClusterMemberRequest" + } + } + }, + "required": true + }, + "responses": { + "202": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceMemberInfo" + } + } + }, + "description": "Cluster member provisioning started" + }, + "400": { + "description": "Validation failed (wrong topology, status, or role)" + }, + "404": { + "description": "Service not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Begin adding a single new member to a running cluster.", + "tags": [ + "External Services" + ] + } + }, + "/external-services/{id}/members/{member_id}": { + "delete": { + "description": "Refuses to remove the monitor (singleton), the current primary\n(failover first), or any member if the cluster would drop below the\n2-data-member quorum required for HA. Stops + removes the container,\ndeletes the row, and drops the Tier-2 DNS record.", + "operationId": "remove_cluster_member", + "parameters": [ + { + "description": "External service ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Cluster member ID", + "in": "path", + "name": "member_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "Cluster member removed" + }, + "400": { + "description": "Validation failed (monitor, primary, or quorum violation)" + }, + "404": { + "description": "Service or member not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Remove a single member from a running cluster.", + "tags": [ + "External Services" + ] + }, + "get": { + "description": "Used by the add-member page to poll the row every second while the\nbackground provisioning task walks through its phases. The\n`provisioning_step` field advances through `inserting_row` →\n`provisioning_container` → `registering_dns` → `done` (or `failed`\nwith `provisioning_error` set).", + "operationId": "get_cluster_member", + "parameters": [ + { + "description": "External service ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Cluster member ID", + "in": "path", + "name": "member_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceMemberInfo" + } + } + }, + "description": "Cluster member details" + }, + "404": { + "description": "Service or member not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get a single cluster member's current state.", + "tags": [ + "External Services" + ] + } + }, + "/external-services/{id}/members/{member_id}/promote": { + "post": { + "operationId": "promote_cluster_member", + "parameters": [ + { + "description": "External service ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Cluster member ID", + "in": "path", + "name": "member_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "202": { + "description": "Promotion initiated" + }, + "400": { + "description": "Validation failed (monitor, already primary, not running, etc.)" + }, + "404": { + "description": "Service or member not found" + }, + "500": { + "description": "pg_autoctl perform promotion failed" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Promote a replica to primary by triggering a pg_auto_failover\nfailover. The monitor demotes the current primary and the chosen\nreplica transitions to primary; the role reconciler then refreshes\nthe role-aliased VIPs (≤30s).", + "tags": [ + "External Services" + ] + } + }, + "/external-services/{id}/metrics": { + "get": { + "description": "Pass `percentile` to compute a histogram quantile instead of a plain\ngauge/counter average.", + "operationId": "ExternalServiceMetricsGetRange", + "parameters": [ + { + "description": "External service ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Metric name, e.g. `\"pg.connections_active\"`.", + "in": "query", + "name": "metric", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Time window: `\"1h\"` | `\"6h\"` | `\"24h\"` | `\"7d\"`.", + "in": "query", + "name": "range", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Optional histogram percentile (0–100). When provided, the endpoint\nfetches histogram buckets and computes the requested quantile.", + "in": "query", + "name": "percentile", + "required": false, + "schema": { + "format": "double", + "type": [ + "number", + "null" + ] + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/MetricDataPoint" + }, + "type": "array" + } + } + }, + "description": "Metric time series data points" + }, + "400": { + "description": "Invalid query parameters" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + }, + "503": { + "description": "Metrics store not available" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Fetch a time-series range for a single metric on an external service.", + "tags": [ + "Metrics" + ] + } + }, + "/external-services/{id}/metrics/alert-rules": { + "get": { + "operationId": "ExternalServiceMetricsGetAlertRules", + "parameters": [ + { + "description": "External service ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/ServiceAlertRuleResponse" + }, + "type": "array" + } + } + }, + "description": "List of alert rules" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List all monitoring alert rules for an external service.", + "tags": [ + "Metrics" + ] + }, + "post": { + "description": "If metric collection is enabled and the service engine has default rules,\nseeding is idempotent (ON CONFLICT DO NOTHING).", + "operationId": "ExternalServiceMetricsCreateAlertRule", + "parameters": [ + { + "description": "External service ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceCreateAlertRuleRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceAlertRuleResponse" + } + } + }, + "description": "Alert rule created" + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Create a monitoring alert rule for an external service.", + "tags": [ + "Metrics" + ] + } + }, + "/external-services/{id}/metrics/alert-rules/{rule_id}": { + "delete": { + "operationId": "ExternalServiceMetricsDeleteAlertRule", + "parameters": [ + { + "description": "External service ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Alert rule ID", + "in": "path", + "name": "rule_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "Alert rule deleted" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Alert rule not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Delete a monitoring alert rule for an external service.", + "tags": [ + "Metrics" + ] + }, + "put": { + "operationId": "ExternalServiceMetricsUpdateAlertRule", + "parameters": [ + { + "description": "External service ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Alert rule ID", + "in": "path", + "name": "rule_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceUpdateAlertRuleRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceAlertRuleResponse" + } + } + }, + "description": "Updated alert rule" + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Alert rule not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Update an existing monitoring alert rule for an external service.", + "tags": [ + "Metrics" + ] + } + }, + "/external-services/{id}/metrics/by-database": { + "get": { + "description": "Groups `pg_stat_database` / size metrics by `datname` so the UI can show a\nbreakdown table (each database with its own size, cache-hit ratio, etc.)\nrather than collapsing every database into one value.", + "operationId": "ExternalServiceMetricsByDatabase", + "parameters": [ + { + "description": "External service ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DatabaseMetricsResponse" + } + } + }, + "description": "Per-database metric breakdown" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + }, + "503": { + "description": "Metrics not available" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Return the latest per-database metric values for a Postgres service.", + "tags": [ + "Metrics" + ] + } + }, + "/external-services/{id}/metrics/enable": { + "patch": { + "description": "When `enabled=true`, seeds the default alert rules for the service's engine\nvia [`temps_monitoring::seed_default_rules`] (idempotent).", + "operationId": "ExternalServiceMetricsToggle", + "parameters": [ + { + "description": "External service ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ToggleServiceMetricsRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Metrics toggle applied" + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Service not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Enable or disable metric collection for an external service.", + "tags": [ + "Metrics" + ] + } + }, + "/external-services/{id}/metrics/latest": { + "get": { + "operationId": "ExternalServiceMetricsGetLatest", + "parameters": [ + { + "description": "External service ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "additionalProperties": { + "format": "double", + "type": "number" + }, + "propertyNames": { + "type": "string" + }, + "type": "object" + } + } + }, + "description": "Map of metric name to latest value" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + }, + "503": { + "description": "Metrics store not available" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Fetch the most-recent value for every tracked metric on an external service.", + "tags": [ + "Metrics" + ] + } + }, + "/external-services/{id}/metrics/status": { + "get": { + "description": "Cheap O(1) lookup against `service_metrics_status` — used by the UI to show\n\"last received at …\" without scanning the metrics hypertable.", + "operationId": "ExternalServiceMetricsStatus", + "parameters": [ + { + "description": "External service ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MetricsStatusResponse" + } + } + }, + "description": "Metrics freshness status" + }, + "503": { + "description": "Metrics not available" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Return the freshness status (last-received timestamp) for a service.", + "tags": [ + "Metrics" + ] + } + }, + "/external-services/{id}/parameters/{param_name}": { + "get": { + "operationId": "reveal_service_parameter", + "parameters": [ + { + "description": "External service ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Sensitive parameter name", + "in": "path", + "name": "param_name", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SensitiveValueResponse" + } + } + }, + "description": "Sensitive parameter value" + }, + "400": { + "description": "Parameter is not sensitive" + }, + "403": { + "description": "Caller cannot access a project linked to this service" + }, + "404": { + "description": "Service or parameter not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Reveal one sensitive service parameter. Service detail responses never\ncontain plaintext values; every successful reveal is recorded separately.", + "tags": [ + "External Services" + ] + } + }, + "/external-services/{id}/preview-environment-masked": { + "get": { + "operationId": "get_service_preview_environment_variables_masked", + "parameters": [ + { + "description": "External service ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "additionalProperties": { + "type": "string" + }, + "propertyNames": { + "type": "string" + }, + "type": "object" + } + } + }, + "description": "Preview of environment variables with sensitive values masked as ***" + }, + "404": { + "description": "Service not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Get environment variables preview with masked sensitive values", + "tags": [ + "External Services" + ] + } + }, + "/external-services/{id}/preview-environment-names": { + "get": { + "operationId": "get_service_preview_environment_variable_names", + "parameters": [ + { + "description": "External service ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "type": "string" + }, + "type": "array" + } + } + }, + "description": "List of environment variable names that would be provided" + }, + "404": { + "description": "Service not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Get environment variable names preview (safe - no sensitive values)", + "tags": [ + "External Services" + ] + } + }, + "/external-services/{id}/projects": { + "get": { + "operationId": "list_service_projects", + "parameters": [ + { + "description": "External service ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Page number (1-indexed)", + "example": 1, + "in": "query", + "name": "page", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + } + }, + { + "description": "Number of items per page (max 100)", + "example": 20, + "in": "query", + "name": "page_size", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + } + }, + { + "in": "query", + "name": "sort_by", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "in": "query", + "name": "sort_order", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/ProjectServiceInfo" + }, + "type": "array" + } + } + }, + "description": "List of linked projects" + }, + "404": { + "description": "Service not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "List projects linked to service", + "tags": [ + "External Services" + ] + }, + "post": { + "operationId": "link_service_to_project", + "parameters": [ + { + "description": "External service ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LinkServiceRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProjectServiceInfo" + } + } + }, + "description": "Service linked to project successfully" + }, + "404": { + "description": "Service or project not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Link service to project", + "tags": [ + "External Services" + ] + } + }, + "/external-services/{id}/projects/{project_id}": { + "delete": { + "operationId": "unlink_service_from_project", + "parameters": [ + { + "description": "External service ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "Service unlinked from project successfully" + }, + "404": { + "description": "Service link not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Unlink service from project", + "tags": [ + "External Services" + ] + } + }, + "/external-services/{id}/projects/{project_id}/environment": { + "get": { + "operationId": "get_service_environment_variables", + "parameters": [ + { + "description": "External service ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/EnvironmentVariableInfo" + }, + "type": "array" + } + } + }, + "description": "List of environment variables" + }, + "404": { + "description": "Service or project not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Get all environment variables for a service-project pair", + "tags": [ + "External Services" + ] + } + }, + "/external-services/{id}/projects/{project_id}/environment/{var_name}": { + "get": { + "operationId": "get_service_environment_variable", + "parameters": [ + { + "description": "External service ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment variable name", + "in": "path", + "name": "var_name", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnvironmentVariableInfo" + } + } + }, + "description": "Environment variable value" + }, + "403": { + "description": "Plaintext secret access is not permitted" + }, + "404": { + "description": "Service, project, or variable not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Get specific environment variable for a service-project pair", + "tags": [ + "External Services" + ] + } + }, + "/external-services/{id}/resources": { + "patch": { + "description": "Persists the new caps to the encrypted config AND live-applies them\nvia Docker's update API. Memory and CPU can be hot-changed without a\nrestart on running containers; stopped containers also accept the\nupdate and pick up the new caps on next start.\n\nPass `null` (or omit) any field to leave it unlimited. A request where\nevery field is `null` removes any existing limits.\n\nThe response includes a per-container `applied[]` list so the caller\ncan tell which members got the update and which were skipped (e.g.,\ncontainer not yet created, or `docker update` rejected because the\nnew memory cap is below current usage).", + "operationId": "update_service_resources", + "parameters": [ + { + "description": "External service ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceResourceLimits" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceLimitsUpdateResponse" + } + } + }, + "description": "Updated resource limits" + }, + "400": { + "description": "Invalid resource limits" + }, + "404": { + "description": "Service not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Update a service's resource limits (memory, CPU caps).", + "tags": [ + "External Services" + ] + } + }, + "/external-services/{id}/restore": { + "post": { + "operationId": "start_restore", + "parameters": [ + { + "description": "External service id (source for the restore)", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StartRestoreRequest" + } + } + }, + "required": true + }, + "responses": { + "202": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RestoreRunView" + } + } + }, + "description": "Restore run started" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Validation error" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Backup or service not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Restore" + ] + } + }, + "/external-services/{id}/restore-capabilities": { + "get": { + "operationId": "get_restore_capabilities", + "parameters": [ + { + "description": "External service id", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RestoreCapabilitiesResponse" + } + } + }, + "description": "Capabilities declared by the service" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Service not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Restore" + ] + } + }, + "/external-services/{id}/restore-plan": { + "post": { + "operationId": "plan_restore", + "parameters": [ + { + "description": "Target service id", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StartRestoreRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RestorePlan" + } + } + }, + "description": "Preview of what the restore will do" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Validation error" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Backup or service not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Restore" + ] + } + }, + "/external-services/{id}/restore-runs": { + "get": { + "operationId": "list_restore_runs_for_service", + "parameters": [ + { + "description": "External service id", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/RestoreRunView" + }, + "type": "array" + } + } + }, + "description": "Recent restore runs for the service" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Restore" + ] + } + }, + "/external-services/{id}/retry": { + "post": { + "description": "Cleans up any leftover containers from the previous attempt and\nre-runs cluster initialization with the provided member specifications.", + "operationId": "retry_cluster", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RetryClusterRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExternalServiceInfo" + } + } + }, + "description": "Cluster retry initiated" + }, + "400": { + "description": "Service is not a failed cluster" + }, + "404": { + "description": "Service not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Retry a failed cluster service initialization.", + "tags": [ + "External Services" + ] + } + }, + "/external-services/{id}/runtime": { + "get": { + "operationId": "get_service_runtime", + "parameters": [ + { + "description": "External service ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceRuntimeReport" + } + } + }, + "description": "Container runtime snapshot" + }, + "404": { + "description": "Service not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Inspect a service's container(s): status, restart count, OOM-killed flag,\nexit code, and the cgroup limits actually applied.", + "tags": [ + "External Services" + ] + } + }, + "/external-services/{id}/start": { + "post": { + "operationId": "start_service", + "parameters": [ + { + "description": "External service ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExternalServiceInfo" + } + } + }, + "description": "Service started successfully" + }, + "404": { + "description": "Service not found" + }, + "409": { + "description": "A Postgres major upgrade is in progress for this service" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Start an external service", + "tags": [ + "External Services" + ] + } + }, + "/external-services/{id}/stats": { + "get": { + "operationId": "get_service_stats", + "parameters": [ + { + "description": "External service ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceStatsReport" + } + } + }, + "description": "Container stats snapshot" + }, + "404": { + "description": "Service not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Sample current CPU/memory usage from each of a service's containers.\nOne-shot sample, no streaming. Cheap to call (single Docker round-trip\nper member) so the UI can poll on a 5–10s interval.", + "tags": [ + "External Services" + ] + } + }, + "/external-services/{id}/stop": { + "post": { + "operationId": "stop_service", + "parameters": [ + { + "description": "External service ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExternalServiceInfo" + } + } + }, + "description": "Service stopped successfully" + }, + "404": { + "description": "Service not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Stop an external service", + "tags": [ + "External Services" + ] + } + }, + "/external-services/{id}/upgrade": { + "post": { + "operationId": "upgrade_service", + "parameters": [ + { + "description": "External service ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpgradeExternalServiceRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExternalServiceInfo" + } + } + }, + "description": "Service upgraded successfully" + }, + "400": { + "description": "Invalid request or upgrade not supported" + }, + "404": { + "description": "Service not found" + }, + "409": { + "description": "A major upgrade is already in progress for this service" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Upgrade external service to new Docker image with data migration\nThis endpoint uses service-specific upgrade procedures (e.g., pg_upgrade for PostgreSQL)", + "tags": [ + "External Services" + ] + } + }, + "/external-services/{id}/wal-health": { + "get": { + "description": "Returns the latest WAL/archive health snapshot recorded by the background\nhealth monitor for a Postgres external service. Powers the warning banner\non the service detail page when the disk is filling up due to stale\nreplication slots, archive backlog, or misconfigured `archive_command`.\n\nReturns 404 when no snapshot exists yet (probe hasn't run, or the service\nisn't Postgres).", + "operationId": "getPostgresWalHealth", + "parameters": [ + { + "description": "External service ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PostgresWalHealth" + } + } + }, + "description": "Latest WAL health snapshot" + }, + "404": { + "description": "Service not found, or no WAL snapshot available" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Postgres WAL & archive health snapshot", + "tags": [ + "External Services" + ] + } + }, + "/external-services/{service_id}/pg-stat-statements/enable": { + "post": { + "description": "Stops the container and restarts it so that the\n`shared_preload_libraries=pg_stat_statements` CMD flag (baked into every\nnew standalone Postgres container) takes effect. The named data volume is\nreused unchanged — no data is lost.\n\n**Clustered (HA) services are rejected** with 422 — a blind single-container\nrestart bypasses controlled failover. For clustered services the response\nbody describes the manual rolling-restart steps.\n\nConfirmation is the caller's responsibility (UI dialog / CLI `--yes` flag)\nbefore invoking this endpoint.", + "operationId": "ExternalServiceEnablePgStatStatements", + "parameters": [ + { + "description": "ID of the provisioned standalone Postgres service", + "in": "path", + "name": "service_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnablePgStatStatementsResponse" + } + } + }, + "description": "Container restarted; pg_stat_statements now active" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions (requires external_services:write)" + }, + "404": { + "description": "Service not found" + }, + "422": { + "description": "Service is not standalone Postgres (cluster or wrong type)" + }, + "500": { + "description": "Restart failed" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Enable `pg_stat_statements` on a standalone Postgres service.", + "tags": [ + "External Services" + ] + } + }, + "/external-services/{service_id}/pg-stat-statements/reset": { + "post": { + "operationId": "ExternalServiceResetPgStatStatements", + "parameters": [ + { + "description": "ID of the provisioned Postgres service", + "in": "path", + "name": "service_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResetPgStatStatementsRequest" + } + } + }, + "description": "Explicit confirmation of the global, irreversible reset", + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResetPgStatStatementsResponse" + } + } + }, + "description": "All accumulated pg_stat_statements statistics cleared" + }, + "400": { + "description": "Missing or invalid reset confirmation" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions (requires external_services:write)" + }, + "404": { + "description": "Service not found" + }, + "422": { + "description": "Service is not Postgres" + }, + "502": { + "description": "Target Postgres rejected or failed the reset operation" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Reset all statistics accumulated by `pg_stat_statements` for a Postgres\nservice. This affects every user, database, and normalized query tracked by\nthe target Postgres instance and cannot be undone.", + "tags": [ + "External Services" + ] + } + }, + "/external-services/{service_id}/pg-stat-statements/slow-queries": { + "get": { + "operationId": "get_slow_queries", + "parameters": [ + { + "description": "ID of the provisioned Postgres service", + "in": "path", + "name": "service_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Page number (1-based). Defaults to 1.", + "in": "query", + "name": "page", + "required": false, + "schema": { + "format": "int32", + "minimum": 0, + "type": [ + "integer", + "null" + ] + } + }, + { + "description": "Number of rows per page (1–100). Defaults to 20.", + "in": "query", + "name": "page_size", + "required": false, + "schema": { + "format": "int32", + "minimum": 0, + "type": [ + "integer", + "null" + ] + } + }, + { + "description": "Column to sort by: one of `calls`, `total_exec_time_ms`,\n`mean_exec_time_ms`, `rows`, `cache_hit_ratio`. Defaults to\n`mean_exec_time_ms`. Applied server-side so ordering stays\nconsistent across pages.", + "in": "query", + "name": "sort_by", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "description": "Sort direction: `asc` or `desc`. Defaults to `desc`.", + "in": "query", + "name": "sort_order", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SlowQueriesResponse" + } + } + }, + "description": "Paginated slow queries from pg_stat_statements" + }, + "400": { + "description": "Invalid pagination or sort parameters" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions (requires external_services:read)" + }, + "404": { + "description": "Service not found" + }, + "422": { + "description": "Service is not a Postgres service" + }, + "503": { + "description": "pg_stat_statements extension not available (container restart required)" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "External Services" + ] + } + }, + "/external-services/{service_id}/query/ai-data-access": { + "get": { + "description": "Always answers (rather than 404-ing when disabled) so the console can render\nthe capability with an \"off — here's how to turn it on\" state instead of\nhiding it, and so the agent can tell \"not set up\" apart from \"not supported\".", + "operationId": "get_ai_data_access", + "parameters": [ + { + "description": "External service id", + "in": "path", + "name": "service_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiDataAccessResponse" + } + } + }, + "description": "Current AI data access setting" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Service not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Report whether the AI assistant may read row data from this service.", + "tags": [ + "External Services - Query" + ] + }, + "patch": { + "description": "Off by default. Row contents can include password hashes, API tokens and\npersonal data, and enabling this sends them to the configured AI provider —\nso it is a deliberate, audited, per-service decision by the operator.", + "operationId": "set_ai_data_access", + "parameters": [ + { + "description": "External service id", + "in": "path", + "name": "service_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ToggleAiDataAccessRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiDataAccessResponse" + } + } + }, + "description": "Setting applied" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Service not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Enable or disable AI assistant access to this service's row data.", + "tags": [ + "External Services - Query" + ] + } + }, + "/external-services/{service_id}/query/containers": { + "get": { + "operationId": "list_root_containers", + "parameters": [ + { + "in": "path", + "name": "service_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/ContainerResponse" + }, + "type": "array" + } + } + }, + "description": "List of root containers" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Service not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List containers at the root level (databases, keyspaces, etc.)", + "tags": [ + "External Services - Query" + ] + } + }, + "/external-services/{service_id}/query/containers/{path}": { + "get": { + "operationId": "list_containers_at_path", + "parameters": [ + { + "in": "path", + "name": "service_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "in": "path", + "name": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/ContainerResponse" + }, + "type": "array" + } + } + }, + "description": "List of containers" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Service or container not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List containers at a specific path\nPath segments are separated by forward slashes\nExample: /external-services/1/query/containers/mydb lists schemas in database \"mydb\"", + "tags": [ + "External Services - Query" + ] + } + }, + "/external-services/{service_id}/query/containers/{path}/entities": { + "get": { + "operationId": "list_entities", + "parameters": [ + { + "description": "Maximum number of entities to return (default: 100, max: 1000)", + "in": "query", + "name": "limit", + "required": false, + "schema": { + "minimum": 0, + "type": "integer" + } + }, + { + "description": "Continuation token for pagination", + "in": "query", + "name": "token", + "required": false, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "service_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "in": "path", + "name": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PaginatedEntitiesResponse" + } + } + }, + "description": "Paginated list of entities" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Service or container not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List entities (tables, collections, etc.) in a container\nExample: /external-services/1/query/containers/mydb/public/entities lists tables in the public schema", + "tags": [ + "External Services - Query" + ] + } + }, + "/external-services/{service_id}/query/containers/{path}/entities/{entity}": { + "get": { + "operationId": "get_entity_info", + "parameters": [ + { + "in": "path", + "name": "service_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "in": "path", + "name": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "entity", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EntityInfoResponse" + } + } + }, + "description": "Entity details" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Service, container, or entity not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get detailed information about an entity (table schema)", + "tags": [ + "External Services - Query" + ] + } + }, + "/external-services/{service_id}/query/containers/{path}/entities/{entity}/data": { + "get": { + "description": "Gated for AI callers by the service's `ai_data_access` opt-in — see\n[`temps_core::ai_tool_call::AiToolCall`].", + "operationId": "read_entity_rows", + "parameters": [ + { + "description": "External service id", + "in": "path", + "name": "service_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Container path, slash-separated (e.g. `mydb/public`)", + "in": "path", + "name": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Table, collection, key or object name", + "in": "path", + "name": "entity", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "JSON-encoded backend-specific filter", + "in": "query", + "name": "filter", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Maximum rows to return", + "in": "query", + "name": "limit", + "required": false, + "schema": { + "minimum": 0, + "type": "integer" + } + }, + { + "description": "Rows to skip", + "in": "query", + "name": "offset", + "required": false, + "schema": { + "minimum": 0, + "type": "integer" + } + }, + { + "description": "Field to sort by", + "in": "query", + "name": "sort_by", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "asc or desc", + "in": "query", + "name": "sort_order", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/QueryDataResponse" + } + } + }, + "description": "Query results" + }, + "400": { + "description": "Invalid query or filter" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions, or AI data access not enabled for this service" + }, + "404": { + "description": "Service, container, or entity not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Read rows from an entity (read-only `GET`; see [`query_data`] for the\n`POST` form used by the console).", + "tags": [ + "External Services - Query" + ] + }, + "post": { + "operationId": "query_data", + "parameters": [ + { + "in": "path", + "name": "service_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "in": "path", + "name": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "entity", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/QueryDataRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/QueryDataResponse" + } + } + }, + "description": "Query results" + }, + "400": { + "description": "Invalid query" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Service, container, or entity not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Query data from an entity with optional filters, pagination, and sorting", + "tags": [ + "External Services - Query" + ] + } + }, + "/external-services/{service_id}/query/containers/{path}/entities/{entity}/download": { + "get": { + "operationId": "download_object", + "parameters": [ + { + "in": "path", + "name": "service_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "in": "path", + "name": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "entity", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/octet-stream": {} + }, + "description": "Object data stream" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Object not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Download an object (S3 only) as a streaming response", + "tags": [ + "External Services - Query" + ] + } + }, + "/external-services/{service_id}/query/containers/{path}/info": { + "get": { + "operationId": "get_query_container_info", + "parameters": [ + { + "in": "path", + "name": "service_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "in": "path", + "name": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContainerResponse" + } + } + }, + "description": "Container information" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Service or container not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get information about a specific container", + "tags": [ + "External Services - Query" + ] + } + }, + "/external-services/{service_id}/query/explorer-support": { + "get": { + "operationId": "check_explorer_support", + "parameters": [ + { + "in": "path", + "name": "service_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExplorerSupportResponse" + } + } + }, + "description": "Explorer support information" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Service not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Check if a service supports query explorer functionality", + "tags": [ + "External Services - Query" + ] + } + }, + "/external-services/{service_id}/upgrades": { + "get": { + "operationId": "list_pg_upgrades", + "parameters": [ + { + "description": "External service id", + "in": "path", + "name": "service_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/PgUpgradeResponse" + }, + "type": "array" + } + } + }, + "description": "Recent upgrades" + }, + "500": { + "description": "Internal error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List recent upgrades for a single service (newest first, page size 50).", + "tags": [ + "Postgres Upgrades" + ] + }, + "post": { + "operationId": "start_pg_upgrade", + "parameters": [ + { + "description": "External service id", + "in": "path", + "name": "service_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StartPgUpgradeRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PgUpgradeResponse" + } + } + }, + "description": "Upgrade started" + }, + "400": { + "description": "Invalid request" + }, + "409": { + "description": "An upgrade is already running for this service" + }, + "412": { + "description": "No default S3 source configured" + }, + "500": { + "description": "Internal error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Start a new PostgreSQL major-version upgrade for a service.", + "tags": [ + "Postgres Upgrades" + ] + } + }, + "/external-services/{service_id}/upgrades/{id}": { + "get": { + "operationId": "get_pg_upgrade", + "parameters": [ + { + "description": "External service id", + "in": "path", + "name": "service_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Upgrade id", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PgUpgradeResponse" + } + } + }, + "description": "Upgrade" + }, + "404": { + "description": "Not found" + }, + "500": { + "description": "Internal error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get a single upgrade by id, scoped to a service.", + "tags": [ + "Postgres Upgrades" + ] + } + }, + "/external-services/{service_id}/upgrades/{id}/cancel": { + "post": { + "operationId": "cancel_pg_upgrade", + "parameters": [ + { + "description": "External service id", + "in": "path", + "name": "service_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Upgrade id", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PgUpgradeResponse" + } + } + }, + "description": "Cancellation requested" + }, + "404": { + "description": "Not found" + }, + "409": { + "description": "Upgrade already terminal" + }, + "500": { + "description": "Internal error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Cancel an in-flight upgrade. The orchestrator stops at its next phase\nboundary; already-terminal upgrades return 409.", + "tags": [ + "Postgres Upgrades" + ] + } + }, + "/external-services/{service_id}/upgrades/{id}/logs": { + "get": { + "operationId": "get_pg_upgrade_logs", + "parameters": [ + { + "description": "External service id", + "in": "path", + "name": "service_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Upgrade id", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PgUpgradeLogResponse" + } + } + }, + "description": "Log content" + }, + "404": { + "description": "Not found" + }, + "500": { + "description": "Internal error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get the accumulated JSONL log content for an upgrade (for dashboard display).", + "tags": [ + "Postgres Upgrades" + ] + } + }, + "/external-services/{service_id}/upgrades/{id}/retry": { + "post": { + "operationId": "retry_pg_upgrade", + "parameters": [ + { + "description": "External service id", + "in": "path", + "name": "service_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Upgrade id", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PgUpgradeResponse" + } + } + }, + "description": "Retry scheduled" + }, + "400": { + "description": "Upgrade is not in a retriable state" + }, + "404": { + "description": "Not found" + }, + "500": { + "description": "Internal error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Retry a failed upgrade. The phase is preserved, so the state machine\nresumes from where it failed.", + "tags": [ + "Postgres Upgrades" + ] + } + }, + "/external-services/{service_id}/upgrades/{id}/rollback": { + "post": { + "operationId": "rollback_pg_upgrade", + "parameters": [ + { + "description": "External service id", + "in": "path", + "name": "service_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Upgrade id", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PgUpgradeResponse" + } + } + }, + "description": "Rollback complete" + }, + "404": { + "description": "Not found" + }, + "409": { + "description": "Upgrade is not in a rollbackable state (not completed, volume swept, or retention expired)" + }, + "500": { + "description": "Internal error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Roll a completed upgrade back to its pre-upgrade PGDATA volume and old image.\nOnly valid while the rollback retention window is still open (see\n`ROLLBACK_RETENTION_DAYS`) and the rollback volume has not been swept.", + "tags": [ + "Postgres Upgrades" + ] + } + }, + "/files/{file_path}": { + "get": { + "operationId": "get_file", + "parameters": [ + { + "description": "Relative path to the file from static directory", + "in": "path", + "name": "file_path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/octet-stream": {} + }, + "description": "File content retrieved successfully" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Access denied - path outside static directory or insufficient permissions" + }, + "404": { + "description": "File not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Files" + ] + } + }, + "/flags/exposure": { + "post": { + "description": "This is what makes `last_evaluated_at` mean something. The snapshot\nendpoint hands the SDK every flag in the environment and evaluation then\nhappens locally, so the control plane cannot otherwise tell a flag that is\nreferenced by live code from one nothing has called in a year. Stamping on\nsnapshot fetch would mark every flag as freshly used and defeat the point.\n\nScope comes from the deployment token, never the body. The endpoint writes\nonly `last_evaluated_at` — never a flag's value — so \"a deployment token\ncannot change what a flag serves\" still holds despite this being a write.", + "operationId": "record_flag_exposure", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RecordExposureRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RecordExposureResponse" + } + } + }, + "description": "Exposure recorded" + }, + "400": { + "description": "Deployment token required" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Record which flags a running app actually evaluated.", + "tags": [ + "Feature Flags" + ] + } + }, + "/flags/snapshot": { + "get": { + "description": "Scope comes from the deployment token, never from the URL: a container's\nbaked-in `TEMPS_API_TOKEN` identifies exactly one project (and usually one\nenvironment), so a compromised app cannot read another tenant's flags by\nchanging a path parameter.\n\nSupports `If-None-Match`, so the SDK's background poll is a 304 in the\ncommon case.", + "operationId": "get_flag_snapshot", + "parameters": [ + { + "description": "Required only when the calling token is project-wide rather than scoped\nto a single environment.", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": [ + "integer", + "null" + ] + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FlagSnapshotResponse" + } + } + }, + "description": "Snapshot for the environment" + }, + "304": { + "description": "Snapshot unchanged" + }, + "400": { + "description": "Environment could not be determined" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Every flag for the caller's environment, collapsed to what the evaluator\nneeds.", + "tags": [ + "Feature Flags" + ] + } + }, + "/geo/{ip}": { + "get": { + "operationId": "get_ip_geolocation", + "parameters": [ + { + "description": "IP address to geolocate (IPv4 or IPv6)", + "in": "path", + "name": "ip", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GeoLocationResponse" + } + } + }, + "description": "Geolocation information retrieved" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Invalid IP address" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Authentication required" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "IP address not found in database" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get geolocation information for an IP address", + "tags": [ + "geo" + ] + } + }, + "/git-connections": { + "get": { + "operationId": "list_connections", + "parameters": [ + { + "description": "Page number for pagination (default: 1)", + "in": "query", + "name": "page", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + { + "description": "Number of items per page (default: 30, max: 100)", + "in": "query", + "name": "per_page", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + { + "description": "Sort field (created_at, updated_at, account_name)", + "in": "query", + "name": "sort", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Sort direction (asc, desc), default: desc", + "in": "query", + "name": "direction", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ConnectionListResponse" + } + } + }, + "description": "List of connections" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List user's git provider connections", + "tags": [ + "Git Providers" + ] + } + }, + "/git-connections/{connection_id}": { + "delete": { + "operationId": "delete_connection", + "parameters": [ + { + "description": "Connection ID", + "in": "path", + "name": "connection_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "Connection deleted successfully" + }, + "400": { + "description": "Connection is in use by projects and cannot be deleted" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Connection not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Permanently delete a git provider connection", + "tags": [ + "Git Providers" + ] + } + }, + "/git-connections/{connection_id}/activate": { + "post": { + "operationId": "activate_connection", + "parameters": [ + { + "description": "Connection ID", + "in": "path", + "name": "connection_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "Connection activated successfully" + }, + "400": { + "description": "Provider is deactivated and connection cannot be activated" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Connection not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Activate a git provider connection", + "tags": [ + "Git Providers" + ] + } + }, + "/git-connections/{connection_id}/deactivate": { + "post": { + "operationId": "deactivate_connection", + "parameters": [ + { + "description": "Connection ID", + "in": "path", + "name": "connection_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "Connection deactivated successfully" + }, + "400": { + "description": "Connection is in use by projects and cannot be deactivated" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Connection not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Deactivate a git provider connection", + "tags": [ + "Git Providers" + ] + } + }, + "/git-connections/{connection_id}/health-check": { + "post": { + "description": "Probes the upstream (GitHub App, PAT, or OAuth token), persists the result,\nand fires admin notifications on status transitions. Returns the updated\nconnection.", + "operationId": "run_connection_health_check", + "parameters": [ + { + "description": "Connection ID", + "in": "path", + "name": "connection_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ConnectionResponse" + } + } + }, + "description": "Health check completed" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Connection not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Run an on-demand health check for a git connection.", + "tags": [ + "Git Provider Connections" + ] + } + }, + "/git-connections/{connection_id}/repositories": { + "get": { + "description": "Fetches repositories from the connected git provider with support for pagination, search, and filtering.\nThis endpoint calls the provider's API directly to get the most up-to-date repository list.", + "operationId": "list_repositories_by_connection", + "parameters": [ + { + "description": "Connection ID", + "in": "path", + "name": "connection_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Page number for pagination", + "in": "query", + "name": "page", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + { + "description": "Number of items per page (max 100)", + "in": "query", + "name": "per_page", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + { + "description": "Sort field (name, created_at, updated_at, stars, etc.)", + "in": "query", + "name": "sort", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Sort direction (asc, desc)", + "in": "query", + "name": "direction", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Search term to filter repositories", + "in": "query", + "name": "search", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter by repository owner", + "in": "query", + "name": "owner", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter by programming language", + "in": "query", + "name": "language", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter by private status (true/false)", + "in": "query", + "name": "private", + "required": false, + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RepositoryListResponse" + } + } + }, + "description": "List of repositories" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Connection not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List repositories for a specific connection", + "tags": [ + "Git Providers" + ] + } + }, + "/git-connections/{connection_id}/sync": { + "post": { + "description": "Kicks off a background sync of the connection's repositories from the\nprovider. Returns `202 Accepted` immediately — the caller should poll\nthe connection endpoint for `syncing` / `synced_repository_count`\nupdates rather than waiting on this response. The sync is guarded by\na hard deadline and always releases the `syncing` flag on exit, so a\nclient that disconnects mid-sync will not leave the connection stuck.", + "operationId": "sync_repositories", + "parameters": [ + { + "description": "Connection ID", + "in": "path", + "name": "connection_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "202": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RepositorySyncStartedResponse" + } + } + }, + "description": "Repository sync started in background" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Connection not found" + }, + "409": { + "description": "Sync already in progress" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Start a repository sync for a connection", + "tags": [ + "Git Providers" + ] + } + }, + "/git-connections/{connection_id}/update-token": { + "post": { + "operationId": "update_connection_token", + "parameters": [ + { + "description": "Connection ID", + "in": "path", + "name": "connection_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateTokenRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateTokenResponse" + } + } + }, + "description": "Token updated successfully" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Connection not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Update access token for a connection (when tokens expire or are rotated)", + "tags": [ + "Git Provider Connections" + ] + } + }, + "/git-connections/{connection_id}/validate": { + "get": { + "operationId": "validate_connection", + "parameters": [ + { + "description": "Connection ID", + "in": "path", + "name": "connection_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationResponse" + } + } + }, + "description": "Connection validation result" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Connection not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Validate a connection by testing the access token", + "tags": [ + "Git Provider Connections" + ] + } + }, + "/git-providers": { + "get": { + "operationId": "list_git_providers", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/ProviderResponse" + }, + "type": "array" + } + } + }, + "description": "List of providers" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List all git providers", + "tags": [ + "Git Providers" + ] + }, + "post": { + "operationId": "create_git_provider", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateProviderRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProviderResponse" + } + } + }, + "description": "Provider created successfully" + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Create a new git provider configuration", + "tags": [ + "Git Providers" + ] + } + }, + "/git-providers/bitbucket": { + "post": { + "operationId": "create_bitbucket_provider", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateBitbucketRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProviderResponse" + } + } + }, + "description": "Bitbucket provider created successfully" + }, + "400": { + "description": "Bad request — missing or invalid auth fields" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Create a Bitbucket Cloud provider with access token or app password authentication", + "tags": [ + "Git Providers" + ] + } + }, + "/git-providers/generic": { + "post": { + "operationId": "create_generic_provider", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateGenericRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProviderResponse" + } + } + }, + "description": "Generic git provider created successfully" + }, + "400": { + "description": "Bad request — invalid clone URL or missing fields" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Create a Generic git provider for self-hosted or arbitrary HTTPS git hosts.\nSupports public repositories (no token) and private repositories (token-based).", + "tags": [ + "Git Providers" + ] + } + }, + "/git-providers/gitea/pat": { + "post": { + "operationId": "create_gitea_pat_provider", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateGiteaPATRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProviderResponse" + } + } + }, + "description": "Gitea PAT provider created successfully" + }, + "400": { + "description": "Bad request — invalid URL or missing fields" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Create a Gitea Personal Access Token provider", + "tags": [ + "Git Providers" + ] + } + }, + "/git-providers/github/pat": { + "post": { + "operationId": "create_github_pat_provider", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateGitHubPATRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProviderResponse" + } + } + }, + "description": "GitHub PAT provider created successfully" + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Create a GitHub Personal Access Token provider", + "tags": [ + "Git Providers" + ] + } + }, + "/git-providers/gitlab/oauth": { + "post": { + "operationId": "create_gitlab_oauth_provider", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateGitLabOAuthRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProviderResponse" + } + } + }, + "description": "GitLab OAuth provider created successfully" + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Create a GitLab OAuth provider", + "tags": [ + "Git Providers" + ] + } + }, + "/git-providers/gitlab/pat": { + "post": { + "operationId": "create_gitlab_pat_provider", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateGitLabPATRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProviderResponse" + } + } + }, + "description": "GitLab PAT provider created successfully" + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Create a GitLab PAT provider", + "tags": [ + "Git Providers" + ] + } + }, + "/git-providers/{provider_id}": { + "delete": { + "operationId": "delete_git_provider", + "parameters": [ + { + "description": "Provider ID", + "in": "path", + "name": "provider_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "Provider deleted successfully" + }, + "400": { + "description": "Provider has connections and cannot be deleted" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Provider not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Permanently delete a git provider", + "tags": [ + "Git Providers" + ] + }, + "get": { + "operationId": "get_git_provider", + "parameters": [ + { + "description": "Provider ID", + "in": "path", + "name": "provider_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProviderResponse" + } + } + }, + "description": "Provider details" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Provider not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get a specific git provider", + "tags": [ + "Git Providers" + ] + } + }, + "/git-providers/{provider_id}/activate": { + "post": { + "operationId": "activate_provider", + "parameters": [ + { + "description": "Provider ID", + "in": "path", + "name": "provider_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "Provider activated successfully" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Provider not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Activate a git provider", + "tags": [ + "Git Providers" + ] + } + }, + "/git-providers/{provider_id}/callback": { + "get": { + "operationId": "handle_git_provider_oauth_callback", + "parameters": [ + { + "description": "Git provider ID", + "in": "path", + "name": "provider_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "OAuth authorization code", + "in": "query", + "name": "code", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "CSRF state token", + "in": "query", + "name": "state", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "302": { + "description": "Redirect to success page" + }, + "400": { + "description": "Bad request" + }, + "404": { + "description": "Provider not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Handle OAuth callback for a git provider", + "tags": [ + "Git Providers" + ] + } + }, + "/git-providers/{provider_id}/connections": { + "get": { + "operationId": "get_provider_connections", + "parameters": [ + { + "description": "Provider ID to get connections for", + "in": "path", + "name": "provider_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/ConnectionResponse" + }, + "type": "array" + } + } + }, + "description": "List of connections for the provider" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Provider not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get connections for a specific git provider", + "tags": [ + "Git Providers" + ] + } + }, + "/git-providers/{provider_id}/credentials": { + "patch": { + "operationId": "update_git_provider_credentials", + "parameters": [ + { + "description": "Git provider ID", + "in": "path", + "name": "provider_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateProviderCredentialsRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProviderResponse" + } + } + }, + "description": "Credentials updated" + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Provider not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Partially update credentials for an existing git provider. Only the fields\nyou send are replaced; omitted fields keep their stored values. Fields that\ndon't apply to the provider's auth method are ignored on the service side.", + "tags": [ + "Git Providers" + ] + } + }, + "/git-providers/{provider_id}/deactivate": { + "post": { + "operationId": "deactivate_provider", + "parameters": [ + { + "description": "Provider ID", + "in": "path", + "name": "provider_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "Provider deactivated successfully" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Provider not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Deactivate a git provider", + "tags": [ + "Git Providers" + ] + } + }, + "/git-providers/{provider_id}/deletion-check": { + "get": { + "operationId": "check_provider_deletion_safety", + "parameters": [ + { + "description": "Git provider ID", + "in": "path", + "name": "provider_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProviderDeletionCheckResponse" + } + } + }, + "description": "Deletion check result" + }, + "404": { + "description": "Provider not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Check if a git provider can be safely deleted", + "tags": [ + "Git Providers" + ] + } + }, + "/git-providers/{provider_id}/oauth/authorize": { + "get": { + "operationId": "start_git_provider_oauth", + "parameters": [ + { + "description": "Git provider ID", + "in": "path", + "name": "provider_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "302": { + "description": "Redirect to OAuth provider" + }, + "404": { + "description": "Provider not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Start OAuth flow for a git provider", + "tags": [ + "Git Providers" + ] + } + }, + "/git-providers/{provider_id}/repositories": { + "get": { + "description": "Lists repositories synced to the database across every connection under\nthis provider, with the same pagination/filtering as `/repositories`.", + "operationId": "list_repositories_by_provider", + "parameters": [ + { + "description": "Provider ID", + "in": "path", + "name": "provider_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Page number for pagination", + "in": "query", + "name": "page", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + { + "description": "Number of items per page (max 100)", + "in": "query", + "name": "per_page", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + { + "description": "Sort field (name, created_at, updated_at, stars, watchers, size, issues)", + "in": "query", + "name": "sort", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Sort direction (asc, desc)", + "in": "query", + "name": "direction", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Search term to filter repositories", + "in": "query", + "name": "search", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter by repository owner", + "in": "query", + "name": "owner", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter by programming language", + "in": "query", + "name": "language", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter by private status (true/false)", + "in": "query", + "name": "private", + "required": false, + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RepositoryListResponse" + } + } + }, + "description": "List of repositories" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Provider not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List all repositories for a specific provider", + "tags": [ + "Git Providers" + ] + } + }, + "/git-providers/{provider_id}/safe-delete": { + "delete": { + "operationId": "delete_provider_safely", + "parameters": [ + { + "description": "Git provider ID", + "in": "path", + "name": "provider_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "Provider successfully deleted" + }, + "400": { + "description": "Cannot delete provider because it's in use" + }, + "404": { + "description": "Provider not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Safely delete a git provider (only if no projects are using it)", + "tags": [ + "Git Providers" + ] + } + }, + "/git/public/{provider}/{owner}/{repo}": { + "get": { + "operationId": "get_public_repository", + "parameters": [ + { + "description": "Git provider (github or gitlab)", + "in": "path", + "name": "provider", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Repository owner", + "in": "path", + "name": "owner", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Repository name", + "in": "path", + "name": "repo", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicRepositoryInfo" + } + } + }, + "description": "Repository information" + }, + "400": { + "description": "Provider not supported" + }, + "404": { + "description": "Repository not found" + }, + "429": { + "description": "API rate limit exceeded" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Get information about a public repository (supports GitHub and GitLab)", + "tags": [ + "Public Repositories" + ] + } + }, + "/git/public/{provider}/{owner}/{repo}/branches": { + "get": { + "operationId": "get_public_branches", + "parameters": [ + { + "description": "Git provider (github or gitlab)", + "in": "path", + "name": "provider", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Repository owner", + "in": "path", + "name": "owner", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Repository name", + "in": "path", + "name": "repo", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Force fetch fresh data, bypassing cache (default: false)", + "in": "query", + "name": "fresh", + "required": false, + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BranchListResponse" + } + } + }, + "description": "List of branches" + }, + "400": { + "description": "Provider not supported" + }, + "404": { + "description": "Repository not found" + }, + "429": { + "description": "API rate limit exceeded" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Get branches for a public repository (supports GitHub and GitLab)", + "tags": [ + "Public Repositories" + ] + } + }, + "/git/public/{provider}/{owner}/{repo}/presets": { + "get": { + "operationId": "detect_public_presets", + "parameters": [ + { + "description": "Git provider (github or gitlab)", + "in": "path", + "name": "provider", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Repository owner", + "in": "path", + "name": "owner", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Repository name", + "in": "path", + "name": "repo", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Branch name to detect presets for (default: repository's default branch)", + "in": "query", + "name": "branch", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "description": "Force fetch fresh data, bypassing cache (default: false)", + "in": "query", + "name": "fresh", + "required": false, + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicPresetResponse" + } + } + }, + "description": "Detected presets" + }, + "400": { + "description": "Provider not supported" + }, + "404": { + "description": "Repository or branch not found" + }, + "429": { + "description": "API rate limit exceeded" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Detect presets for a public repository (supports GitHub and GitLab)", + "tags": [ + "Public Repositories" + ] + } + }, + "/imports/discover": { + "post": { + "operationId": "discover_workloads", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DiscoverRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DiscoverResponse" + } + } + }, + "description": "List of discovered workloads" + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Discover workloads from a source", + "tags": [ + "Imports" + ] + } + }, + "/imports/execute": { + "post": { + "operationId": "execute_import", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExecuteImportRequest" + } + } + }, + "required": true + }, + "responses": { + "202": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExecuteImportResponse" + } + } + }, + "description": "Import execution started" + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Execute an import", + "tags": [ + "Imports" + ] + } + }, + "/imports/plan": { + "post": { + "operationId": "create_plan", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreatePlanRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreatePlanResponse" + } + } + }, + "description": "Import plan created" + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Create an import plan", + "tags": [ + "Imports" + ] + } + }, + "/imports/sources": { + "get": { + "operationId": "list_sources", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/ImportSourceInfo" + }, + "type": "array" + } + } + }, + "description": "List of available import sources" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List available import sources", + "tags": [ + "Imports" + ] + } + }, + "/imports/{session_id}": { + "get": { + "operationId": "get_import_status", + "parameters": [ + { + "description": "Import session ID", + "in": "path", + "name": "session_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ImportStatusResponse" + } + } + }, + "description": "Import status" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Import session not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get import status", + "tags": [ + "Imports" + ] + } + }, + "/incidents/{incident_id}": { + "get": { + "operationId": "get_incident", + "parameters": [ + { + "description": "Incident ID", + "in": "path", + "name": "incident_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IncidentResponse" + } + } + }, + "description": "Successfully retrieved incident" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Incident not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get an incident by ID", + "tags": [ + "Status Page" + ] + } + }, + "/incidents/{incident_id}/status": { + "patch": { + "operationId": "update_incident_status", + "parameters": [ + { + "description": "Incident ID", + "in": "path", + "name": "incident_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateIncidentStatusRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IncidentResponse" + } + } + }, + "description": "Incident status updated successfully" + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Incident not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Update incident status", + "tags": [ + "Status Page" + ] + } + }, + "/incidents/{incident_id}/updates": { + "get": { + "operationId": "get_incident_updates", + "parameters": [ + { + "description": "Incident ID", + "in": "path", + "name": "incident_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/IncidentUpdateResponse" + }, + "type": "array" + } + } + }, + "description": "Successfully retrieved incident updates" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Incident not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get incident updates", + "tags": [ + "Status Page" + ] + } + }, + "/internal/nodes": { + "get": { + "operationId": "admin_list_nodes", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NodeListResponse" + } + } + }, + "description": "List of nodes" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List all registered nodes (admin — session auth via RequireAuth)", + "tags": [ + "Nodes" + ] + } + }, + "/internal/nodes/register": { + "post": { + "operationId": "register_node", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RegisterNodeApiRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RegisterNodeResponse" + } + } + }, + "description": "Node reconnected successfully" + }, + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RegisterNodeResponse" + } + } + }, + "description": "Node registered successfully" + }, + "400": { + "description": "Validation error" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Register a new worker node or reconnect an existing one", + "tags": [ + "Nodes" + ] + } + }, + "/internal/nodes/{node_id}": { + "delete": { + "operationId": "admin_remove_node", + "parameters": [ + { + "description": "Node ID", + "in": "path", + "name": "node_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RemoveNodeResponse" + } + } + }, + "description": "Node removed" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Node not found" + }, + "409": { + "description": "Node still has active containers" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Remove a node from the cluster entirely. The node should be drained first\nto ensure containers have been rescheduled. If the node still has active\ncontainers, it will be drained automatically before removal.", + "tags": [ + "Nodes" + ] + }, + "get": { + "operationId": "admin_get_node", + "parameters": [ + { + "description": "Node ID", + "in": "path", + "name": "node_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NodeInfoResponse" + } + } + }, + "description": "Node details" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Node not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get a specific node by ID (admin — session auth via RequireAuth)", + "tags": [ + "Nodes" + ] + } + }, + "/internal/nodes/{node_id}/containers": { + "get": { + "operationId": "admin_list_node_containers", + "parameters": [ + { + "description": "Node ID", + "in": "path", + "name": "node_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NodeContainerListResponse" + } + } + }, + "description": "Containers on this node" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Node not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List all containers running on a specific node", + "tags": [ + "Nodes" + ] + } + }, + "/internal/nodes/{node_id}/dns/ack": { + "post": { + "operationId": "post_dns_ack", + "parameters": [ + { + "description": "Node id, must match the bearer token's node", + "in": "path", + "name": "node_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DnsAckRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DnsAckResponse" + } + } + }, + "description": "ACK accepted" + }, + "400": { + "description": "ACK higher than server generation" + }, + "401": { + "description": "Missing or invalid bearer token" + }, + "404": { + "description": "Node not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "`POST /internal/nodes/{node_id}/dns/ack`", + "tags": [ + "Internal DNS" + ] + } + }, + "/internal/nodes/{node_id}/dns/changes": { + "get": { + "operationId": "get_dns_changes", + "parameters": [ + { + "description": "Node id, must match the bearer token's node", + "in": "path", + "name": "node_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Highest generation the agent has already applied. Pass `0` to\nrequest a full zone snapshot. Defaults to `0` if omitted.", + "in": "query", + "name": "since", + "required": false, + "schema": { + "format": "int64", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DnsChangesResponse" + } + } + }, + "description": "Diff or full snapshot" + }, + "401": { + "description": "Missing or invalid bearer token" + }, + "404": { + "description": "Node not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "`GET /internal/nodes/{node_id}/dns/changes?since=N`", + "tags": [ + "Internal DNS" + ] + } + }, + "/internal/nodes/{node_id}/drain": { + "delete": { + "operationId": "admin_undrain_node", + "parameters": [ + { + "description": "Node ID", + "in": "path", + "name": "node_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UndrainNodeResponse" + } + } + }, + "description": "Node reactivated" + }, + "400": { + "description": "Node not in drainable state" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Node not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Undrain (reactivate) a node so it can accept new deployments again.\nOnly works for nodes in \"draining\" or \"drained\" status.", + "tags": [ + "Nodes" + ] + }, + "get": { + "description": "Returns container counts and whether the drain is complete.\nCan be polled to track drain progress.", + "operationId": "admin_drain_status", + "parameters": [ + { + "description": "Node ID", + "in": "path", + "name": "node_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DrainStatusResponse" + } + } + }, + "description": "Drain status" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Node not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get the drain status for a node, including migration progress.", + "tags": [ + "Nodes" + ] + }, + "post": { + "operationId": "admin_drain_node", + "parameters": [ + { + "description": "Node ID", + "in": "path", + "name": "node_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DrainNodeResponse" + } + } + }, + "description": "Node drain initiated" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Node not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Drain a node: mark it as \"draining\" so no new replicas are scheduled on it,\nand trigger redeployment of all affected environments so their containers\nare rescheduled to healthy nodes.", + "tags": [ + "Nodes" + ] + } + }, + "/internal/nodes/{node_id}/heartbeat": { + "post": { + "operationId": "node_heartbeat", + "parameters": [ + { + "description": "Node ID", + "in": "path", + "name": "node_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HeartbeatApiRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HeartbeatResponse" + } + } + }, + "description": "Heartbeat received" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Node not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Receive a heartbeat from a worker node", + "tags": [ + "Nodes" + ] + } + }, + "/internal/nodes/{node_id}/network/peers": { + "get": { + "operationId": "list_peers", + "parameters": [ + { + "description": "Node id, must match the bearer token's node", + "in": "path", + "name": "node_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PeerListResponse" + } + } + }, + "description": "Peer list and self-allocation" + }, + "401": { + "description": "Missing or invalid bearer token" + }, + "404": { + "description": "Node not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "`GET /internal/nodes/{node_id}/network/peers`", + "tags": [ + "Nodes" + ] + } + }, + "/internal/nodes/{node_id}/s3-credentials/{s3_source_id}": { + "get": { + "description": "Agents call this endpoint to receive the S3 credentials they need to upload\nor download backups. The credentials are decrypted from the stored S3 source\nand returned over the authenticated TLS/WireGuard channel.", + "operationId": "get_s3_credentials", + "parameters": [ + { + "description": "Node ID", + "in": "path", + "name": "node_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "S3 source ID", + "in": "path", + "name": "s3_source_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/S3CredentialsResponse" + } + } + }, + "description": "S3 credentials" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "S3 source not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Get decrypted S3 credentials for a backup/restore operation.", + "tags": [ + "Nodes" + ] + } + }, + "/ip-access-control": { + "get": { + "operationId": "list_ip_access_control", + "parameters": [ + { + "description": "Filter by action (\"block\" or \"allow\")", + "in": "query", + "name": "action", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/IpAccessControlResponse" + }, + "type": "array" + } + } + }, + "description": "List of IP access control rules" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List all IP access control rules", + "tags": [ + "IP Access Control" + ] + }, + "post": { + "operationId": "create_ip_access_control", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateIpAccessControlRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IpAccessControlResponse" + } + } + }, + "description": "IP access control rule created" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Invalid request" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "409": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Duplicate IP address" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Create a new IP access control rule", + "tags": [ + "IP Access Control" + ] + } + }, + "/ip-access-control/check/{ip}": { + "get": { + "operationId": "check_ip_blocked", + "parameters": [ + { + "description": "IP address to check", + "in": "path", + "name": "ip", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "IP block status" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Check if an IP address is blocked", + "tags": [ + "IP Access Control" + ] + } + }, + "/ip-access-control/{id}": { + "delete": { + "operationId": "delete_ip_access_control", + "parameters": [ + { + "description": "IP access control rule ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "IP access control rule deleted" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "IP access control rule not found" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Delete an IP access control rule", + "tags": [ + "IP Access Control" + ] + }, + "get": { + "operationId": "get_ip_access_control", + "parameters": [ + { + "description": "IP access control rule ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IpAccessControlResponse" + } + } + }, + "description": "IP access control rule details" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "IP access control rule not found" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get a single IP access control rule by ID", + "tags": [ + "IP Access Control" + ] + }, + "patch": { + "operationId": "update_ip_access_control", + "parameters": [ + { + "description": "IP access control rule ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateIpAccessControlRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IpAccessControlResponse" + } + } + }, + "description": "IP access control rule updated" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Invalid request" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "IP access control rule not found" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Update an IP access control rule", + "tags": [ + "IP Access Control" + ] + } + }, + "/kv/del": { + "post": { + "operationId": "kv_del", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DelRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DelResponse" + } + } + }, + "description": "Keys deleted" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Delete one or more keys", + "tags": [ + "KV Store" + ] + } + }, + "/kv/disable": { + "delete": { + "operationId": "kv_disable", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DisableKvResponse" + } + } + }, + "description": "KV service disabled" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "KV service not enabled" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Disable KV service", + "tags": [ + "KV Management" + ] + } + }, + "/kv/enable": { + "post": { + "operationId": "kv_enable", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnableKvRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnableKvResponse" + } + } + }, + "description": "KV service enabled" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Enable KV service", + "tags": [ + "KV Management" + ] + } + }, + "/kv/expire": { + "post": { + "operationId": "kv_expire", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExpireRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExpireResponse" + } + } + }, + "description": "Expiration set" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Set expiration on a key", + "tags": [ + "KV Store" + ] + } + }, + "/kv/get": { + "post": { + "operationId": "kv_get", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetResponse" + } + } + }, + "description": "Value retrieved" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get a value by key", + "tags": [ + "KV Store" + ] + } + }, + "/kv/incr": { + "post": { + "operationId": "kv_incr", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IncrRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IncrResponse" + } + } + }, + "description": "Value incremented" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Increment a numeric value", + "tags": [ + "KV Store" + ] + } + }, + "/kv/keys": { + "post": { + "operationId": "kv_keys", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/KeysRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/KeysResponse" + } + } + }, + "description": "Keys retrieved" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get keys matching a pattern", + "tags": [ + "KV Store" + ] + } + }, + "/kv/set": { + "post": { + "operationId": "kv_set", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SetRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SetResponse" + } + } + }, + "description": "Value set" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Set a value with optional expiration", + "tags": [ + "KV Store" + ] + } + }, + "/kv/status": { + "get": { + "operationId": "kv_status", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/KvStatusResponse" + } + } + }, + "description": "KV service status" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get KV service status", + "tags": [ + "KV Management" + ] + } + }, + "/kv/ttl": { + "post": { + "operationId": "kv_ttl", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TtlRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TtlResponse" + } + } + }, + "description": "TTL retrieved" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get time-to-live for a key", + "tags": [ + "KV Store" + ] + } + }, + "/kv/update": { + "patch": { + "operationId": "kv_update", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateKvRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateKvResponse" + } + } + }, + "description": "KV service updated" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "KV service not enabled" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Update KV service configuration", + "tags": [ + "KV Management" + ] + } + }, + "/lb/routes": { + "get": { + "operationId": "list_routes", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/RouteResponse" + }, + "type": "array" + } + } + }, + "description": "List of routes" + }, + "500": { + "description": "Internal server error" + } + }, + "tags": [ + "Load Balancer" + ] + }, + "post": { + "operationId": "create_route", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateRouteRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RouteResponse" + } + } + }, + "description": "Route created successfully" + }, + "400": { + "description": "Invalid request" + } + }, + "tags": [ + "Load Balancer" + ] + } + }, + "/lb/routes/{domain}": { + "delete": { + "operationId": "delete_route", + "parameters": [ + { + "in": "path", + "name": "domain", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Route deleted successfully" + }, + "404": { + "description": "Route not found" + } + }, + "tags": [ + "Load Balancer" + ] + }, + "get": { + "operationId": "get_route", + "parameters": [ + { + "in": "path", + "name": "domain", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RouteResponse" + } + } + }, + "description": "Route found" + }, + "404": { + "description": "Route not found" + } + }, + "tags": [ + "Load Balancer" + ] + }, + "put": { + "operationId": "update_route", + "parameters": [ + { + "in": "path", + "name": "domain", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateRouteRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RouteResponse" + } + } + }, + "description": "Route updated successfully" + }, + "404": { + "description": "Route not found" + } + }, + "tags": [ + "Load Balancer" + ] + } + }, + "/logout": { + "post": { + "operationId": "logout", + "responses": { + "200": { + "description": "Successfully logged out" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "session_token": [] + } + ], + "tags": [ + "Authentication" + ] + } + }, + "/logs/context": { + "get": { + "operationId": "get_log_context", + "parameters": [ + { + "description": "Chunk ID", + "in": "query", + "name": "chunk_id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Line offset within the chunk", + "in": "query", + "name": "line_offset", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Context lines before and after (default: 25)", + "in": "query", + "name": "lines", + "required": false, + "schema": { + "format": "int32", + "minimum": 0, + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContextLogsResponse" + } + } + }, + "description": "Context lines" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Invalid parameters" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Chunk not found" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get context lines surrounding a specific log line", + "tags": [ + "Logs" + ] + } + }, + "/logs/search": { + "post": { + "operationId": "search_logs", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SearchLogsRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SearchLogsResponse" + } + } + }, + "description": "Search results" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Invalid search parameters" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Search logs with structured filters and full text search", + "tags": [ + "Logs" + ] + } + }, + "/logs/tail": { + "get": { + "operationId": "tail_logs", + "parameters": [ + { + "description": "Project ID", + "in": "query", + "name": "project_id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Service name", + "in": "query", + "name": "service", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Environment", + "in": "query", + "name": "env", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Optional level filters", + "in": "query", + "name": "levels", + "required": true, + "schema": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + { + "description": "Optional text filter", + "in": "query", + "name": "text", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "SSE stream of log lines" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Live tail logs via Server-Sent Events", + "tags": [ + "Logs" + ] + } + }, + "/monitors-health/projects": { + "get": { + "operationId": "get_projects_monitor_health", + "parameters": [ + { + "description": "Comma-separated list of project IDs", + "in": "query", + "name": "project_ids", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProjectsMonitorHealthResponse" + } + } + }, + "description": "Health summaries per project" + }, + "400": { + "description": "Invalid parameters" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get monitor-based health summaries for multiple projects in a single query", + "tags": [ + "Status Page" + ] + } + }, + "/monitors/{monitor_id}": { + "delete": { + "operationId": "delete_monitor", + "parameters": [ + { + "description": "Monitor ID", + "in": "path", + "name": "monitor_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "Monitor deleted successfully" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Monitor not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Delete a monitor", + "tags": [ + "Status Page" + ] + }, + "get": { + "operationId": "get_monitor", + "parameters": [ + { + "description": "Monitor ID", + "in": "path", + "name": "monitor_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MonitorResponse" + } + } + }, + "description": "Successfully retrieved monitor" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Monitor not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get a monitor by ID", + "tags": [ + "Status Page" + ] + } + }, + "/monitors/{monitor_id}/bucketed": { + "get": { + "operationId": "get_bucketed_status", + "parameters": [ + { + "description": "Monitor ID", + "in": "path", + "name": "monitor_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Bucket interval: '5min', 'hourly', or 'daily' (default: hourly)", + "in": "query", + "name": "interval", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Start time (ISO 8601) (default: 24 hours ago)", + "in": "query", + "name": "start_time", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "End time (ISO 8601) (default: now)", + "in": "query", + "name": "end_time", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StatusBucketedResponse" + } + } + }, + "description": "Successfully retrieved bucketed status data" + }, + "400": { + "description": "Invalid parameters" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Monitor not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get bucketed status data for a monitor using TimescaleDB", + "tags": [ + "Status Page" + ] + } + }, + "/monitors/{monitor_id}/current-status": { + "get": { + "operationId": "get_current_monitor_status", + "parameters": [ + { + "description": "Monitor ID", + "in": "path", + "name": "monitor_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Custom start time (ISO 8601) - overrides timeframe", + "in": "query", + "name": "start_time", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Custom end time (ISO 8601)", + "in": "query", + "name": "end_time", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CurrentStatusResponse" + } + } + }, + "description": "Successfully retrieved current status" + }, + "400": { + "description": "Invalid time parameters" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Monitor not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get current status and uptime metrics for a monitor", + "tags": [ + "Status Page" + ] + } + }, + "/monitors/{monitor_id}/uptime": { + "get": { + "operationId": "get_uptime_history", + "parameters": [ + { + "description": "Monitor ID", + "in": "path", + "name": "monitor_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Number of days of history (default: 60) - ignored if start_time/end_time provided", + "in": "query", + "name": "days", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Start time (ISO 8601) - overrides days parameter", + "in": "query", + "name": "start_time", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "End time (ISO 8601) - defaults to now", + "in": "query", + "name": "end_time", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UptimeHistoryResponse" + } + } + }, + "description": "Successfully retrieved uptime history" + }, + "400": { + "description": "Invalid time parameters" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Monitor not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get uptime history for a monitor", + "tags": [ + "Status Page" + ] + } + }, + "/nodes/{id}/metrics": { + "get": { + "operationId": "NodeMetricsGetRange", + "parameters": [ + { + "description": "Node ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Metric name, e.g. `\"pg.connections_active\"`.", + "in": "query", + "name": "metric", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Time window: `\"1h\"` | `\"6h\"` | `\"24h\"` | `\"7d\"`.", + "in": "query", + "name": "range", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Optional histogram percentile (0–100). When provided, the endpoint\nfetches histogram buckets and computes the requested quantile.", + "in": "query", + "name": "percentile", + "required": false, + "schema": { + "format": "double", + "type": [ + "number", + "null" + ] + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/MetricDataPoint" + }, + "type": "array" + } + } + }, + "description": "Metric time series data points" + }, + "400": { + "description": "Invalid query parameters" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + }, + "503": { + "description": "Metrics store not available" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Fetch a time-series range for a single metric on a node.", + "tags": [ + "Metrics" + ] + } + }, + "/notification-preferences": { + "delete": { + "operationId": "delete_preferences", + "responses": { + "204": { + "description": "Successfully deleted preferences" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Delete notification preferences", + "tags": [ + "Notification Preferences" + ] + }, + "get": { + "operationId": "get_preferences", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationPreferencesResponse" + } + } + }, + "description": "Successfully retrieved preferences" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get notification preferences", + "tags": [ + "Notification Preferences" + ] + }, + "put": { + "operationId": "update_preferences", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdatePreferencesRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationPreferencesResponse" + } + } + }, + "description": "Successfully updated preferences" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Update notification preferences", + "tags": [ + "Notification Preferences" + ] + } + }, + "/notification-providers": { + "get": { + "operationId": "list_notification_providers", + "parameters": [ + { + "description": "Page number (1-indexed)", + "example": 1, + "in": "query", + "name": "page", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + } + }, + { + "description": "Number of items per page (max 100)", + "example": 20, + "in": "query", + "name": "page_size", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + } + }, + { + "in": "query", + "name": "sort_by", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "in": "query", + "name": "sort_order", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/NotificationProviderResponse" + }, + "type": "array" + } + } + }, + "description": "Successfully retrieved providers" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List all notification providers", + "tags": [ + "Notification Providers" + ] + }, + "post": { + "operationId": "create_notification_provider", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateProviderRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationProviderResponse" + } + } + }, + "description": "Successfully created provider" + }, + "400": { + "description": "Invalid request" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Create a new notification provider", + "tags": [ + "Notification Providers" + ] + } + }, + "/notification-providers/cloudflare": { + "post": { + "operationId": "create_cloudflare_provider", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateCloudflareProviderRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationProviderResponse" + } + } + }, + "description": "Successfully created Cloudflare provider" + }, + "400": { + "description": "Invalid request" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Create a new Cloudflare Email Sending notification provider", + "tags": [ + "Notification Providers" + ] + } + }, + "/notification-providers/cloudflare/{id}": { + "put": { + "operationId": "update_cloudflare_provider", + "parameters": [ + { + "description": "Provider ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateCloudflareProviderRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationProviderResponse" + } + } + }, + "description": "Successfully updated Cloudflare provider" + }, + "404": { + "description": "Provider not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Update a Cloudflare Email Sending notification provider", + "tags": [ + "Notification Providers" + ] + } + }, + "/notification-providers/email": { + "post": { + "operationId": "create_notification_email_provider", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateNotificationEmailProviderRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationProviderResponse" + } + } + }, + "description": "Successfully created Email provider" + }, + "400": { + "description": "Invalid request" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Create a new Email notification provider", + "tags": [ + "Notification Providers" + ] + } + }, + "/notification-providers/email/{id}": { + "put": { + "operationId": "update_notification_email_provider", + "parameters": [ + { + "description": "Provider ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateNotificationEmailProviderRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationProviderResponse" + } + } + }, + "description": "Successfully updated Email provider" + }, + "404": { + "description": "Provider not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Update an Email notification provider", + "tags": [ + "Notification Providers" + ] + } + }, + "/notification-providers/slack": { + "post": { + "operationId": "create_slack_provider", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateSlackProviderRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationProviderResponse" + } + } + }, + "description": "Successfully created Slack provider" + }, + "400": { + "description": "Invalid request" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Create a new Slack notification provider", + "tags": [ + "Notification Providers" + ] + } + }, + "/notification-providers/slack/{id}": { + "put": { + "operationId": "update_slack_provider", + "parameters": [ + { + "description": "Provider ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateSlackProviderRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationProviderResponse" + } + } + }, + "description": "Successfully updated Slack provider" + }, + "404": { + "description": "Provider not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Update a Slack notification provider", + "tags": [ + "Notification Providers" + ] + } + }, + "/notification-providers/webhook": { + "post": { + "description": "Webhook providers send notifications as JSON payloads to any HTTP endpoint.\nYou can configure custom headers for authentication (Bearer tokens, API keys, etc.).\nThe webhook will receive a JSON payload with notification details including:\nid, title, message, type, priority, severity, timestamp, and metadata.", + "operationId": "create_webhook_provider", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateWebhookProviderRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationProviderResponse" + } + } + }, + "description": "Successfully created Webhook provider" + }, + "400": { + "description": "Invalid request" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Create a new Webhook notification provider", + "tags": [ + "Notification Providers" + ] + } + }, + "/notification-providers/webhook/{id}": { + "put": { + "operationId": "update_webhook_provider", + "parameters": [ + { + "description": "Provider ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateWebhookProviderRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationProviderResponse" + } + } + }, + "description": "Successfully updated Webhook provider" + }, + "404": { + "description": "Provider not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Update a Webhook notification provider", + "tags": [ + "Notification Providers" + ] + } + }, + "/notification-providers/{id}": { + "delete": { + "operationId": "delete_notification_provider", + "parameters": [ + { + "description": "Provider ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "Successfully deleted provider" + }, + "404": { + "description": "Provider not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Delete a notification provider", + "tags": [ + "Notification Providers" + ] + }, + "get": { + "operationId": "get_notification_provider", + "parameters": [ + { + "description": "Provider ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationProviderResponse" + } + } + }, + "description": "Successfully retrieved provider" + }, + "404": { + "description": "Provider not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get a single notification provider", + "tags": [ + "Notification Providers" + ] + }, + "put": { + "operationId": "update_notification_provider", + "parameters": [ + { + "description": "Provider ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateProviderRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationProviderResponse" + } + } + }, + "description": "Successfully updated provider" + }, + "400": { + "description": "Invalid masked provider configuration" + }, + "404": { + "description": "Provider not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Update a notification provider", + "tags": [ + "Notification Providers" + ] + } + }, + "/notification-providers/{id}/config/{field}": { + "get": { + "operationId": "reveal_notification_provider_config", + "parameters": [ + { + "description": "Provider ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Sensitive field, such as password or headers.Authorization", + "in": "path", + "name": "field", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SensitiveConfigValueResponse" + } + } + }, + "description": "Sensitive provider configuration value" + }, + "400": { + "description": "Field is not revealable" + }, + "403": { + "description": "Missing secrets:read permission" + }, + "404": { + "description": "Provider or field not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Notification Providers" + ] + } + }, + "/notification-providers/{id}/test": { + "post": { + "operationId": "test_notification_provider", + "parameters": [ + { + "description": "Provider ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TestProviderResponse" + } + } + }, + "description": "Test result" + }, + "404": { + "description": "Provider not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Test a notification provider", + "tags": [ + "Notification Providers" + ] + } + }, + "/orders": { + "get": { + "operationId": "list_orders", + "parameters": [ + { + "description": "Page number (1-indexed)", + "example": 1, + "in": "query", + "name": "page", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + } + }, + { + "description": "Number of items per page (max 100)", + "example": 20, + "in": "query", + "name": "page_size", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + } + }, + { + "in": "query", + "name": "sort_by", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "in": "query", + "name": "sort_order", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListOrdersResponse" + } + } + }, + "description": "Orders retrieved successfully" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List all ACME orders", + "tags": [ + "Domains" + ] + } + }, + "/otel/alerts": { + "get": { + "operationId": "list_alerts", + "parameters": [ + { + "description": "Project ID", + "in": "query", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Page number (default: 1)", + "in": "query", + "name": "page", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + { + "description": "Page size (default: 20, max: 100)", + "in": "query", + "name": "page_size", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OtelMetricAlertsResponse" + } + } + }, + "description": "Alert rules for the project" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List alert rules for a project (newest first, paginated).", + "tags": [ + "Alerts" + ] + }, + "post": { + "operationId": "create_alert", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateMetricAlertRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OtelMetricAlertRuleResponse" + } + } + }, + "description": "Alert rule created" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Validation error" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Create a new alert rule for a project.", + "tags": [ + "Alerts" + ] + } + }, + "/otel/alerts/preview": { + "post": { + "description": "Replays the metric against the same band the evaluator would use, returning\nthe per-bucket band + which points would have fired. Powers the form's\n\"would this have fired?\" preview and the explorer band overlay. Read-only.", + "operationId": "preview_alert", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AnomalyPreviewRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AnomalyPreviewResponse" + } + } + }, + "description": "Per-bucket band + breach points" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Not an anomaly detector / bad input" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Backtest an anomaly detector over a time range without saving a rule.", + "tags": [ + "Alerts" + ] + } + }, + "/otel/alerts/{id}": { + "delete": { + "operationId": "delete_alert", + "parameters": [ + { + "description": "Alert rule ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Owning project ID (scopes the delete)", + "in": "query", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "Alert rule deleted" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Alert rule not found" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Delete an alert rule.", + "tags": [ + "Alerts" + ] + }, + "get": { + "operationId": "get_alert", + "parameters": [ + { + "description": "Alert rule ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Owning project ID (scopes the lookup)", + "in": "query", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OtelMetricAlertRuleResponse" + } + } + }, + "description": "Alert rule" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Alert rule not found" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Fetch a single alert rule by id.", + "tags": [ + "Alerts" + ] + }, + "patch": { + "operationId": "update_alert", + "parameters": [ + { + "description": "Alert rule ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Owning project ID (scopes the update)", + "in": "query", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateMetricAlertRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OtelMetricAlertRuleResponse" + } + } + }, + "description": "Alert rule updated" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Validation error" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Alert rule not found" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Update an alert rule's fields.", + "tags": [ + "Alerts" + ] + } + }, + "/otel/dashboards": { + "get": { + "operationId": "list_dashboards", + "parameters": [ + { + "description": "Project ID", + "in": "query", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Page number (default: 1)", + "in": "query", + "name": "page", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + { + "description": "Page size (default: 20, max: 100)", + "in": "query", + "name": "page_size", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OtelDashboardsResponse" + } + } + }, + "description": "Dashboards for the project" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List dashboards for a project (newest first, paginated).", + "tags": [ + "Dashboards" + ] + }, + "post": { + "operationId": "create_dashboard", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateDashboardRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OtelDashboardResponse" + } + } + }, + "description": "Dashboard created" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Validation error" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Create a new dashboard for a project.", + "tags": [ + "Dashboards" + ] + } + }, + "/otel/dashboards/{id}": { + "delete": { + "operationId": "delete_dashboard", + "parameters": [ + { + "description": "Dashboard ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Owning project ID (scopes the delete)", + "in": "query", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "Dashboard deleted" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Dashboard not found" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Delete a dashboard.", + "tags": [ + "Dashboards" + ] + }, + "get": { + "operationId": "get_dashboard", + "parameters": [ + { + "description": "Dashboard ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Owning project ID (scopes the lookup)", + "in": "query", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OtelDashboardResponse" + } + } + }, + "description": "Dashboard" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Dashboard not found" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Fetch a single dashboard by id.", + "tags": [ + "Dashboards" + ] + }, + "patch": { + "operationId": "update_dashboard", + "parameters": [ + { + "description": "Dashboard ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Owning project ID (scopes the update)", + "in": "query", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateDashboardRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OtelDashboardResponse" + } + } + }, + "description": "Dashboard updated" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Validation error" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Dashboard not found" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Update a dashboard's name and/or layout.", + "tags": [ + "Dashboards" + ] + } + }, + "/otel/genai/traces": { + "get": { + "description": "`duration_ms` is the only field guaranteed to be milliseconds. `gen_ai.*`\nspan attributes (e.g. time-to-first-token, token latency) often follow the\nOTel GenAI semantic conventions, which use **seconds** (a fractional\ndouble), not milliseconds — do not read them as ms without converting.", + "operationId": "query_genai_traces", + "parameters": [ + { + "description": "Project ID", + "in": "query", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Filter by service name", + "in": "query", + "name": "service_name", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter by AI system (openai, anthropic, etc.)", + "in": "query", + "name": "gen_ai_system", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter by model (gpt-4, claude-sonnet-4-20250514, etc.)", + "in": "query", + "name": "gen_ai_model", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Start time (RFC 3339)", + "in": "query", + "name": "start_time", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "End time (RFC 3339)", + "in": "query", + "name": "end_time", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Max traces to return (default: 50, max: 100)", + "in": "query", + "name": "limit", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + { + "description": "Offset for pagination", + "in": "query", + "name": "offset", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GenAiTraceSummariesResponse" + } + } + }, + "description": "GenAI trace summaries" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Query GenAI trace summaries — traces containing spans with `gen_ai.*` attributes.", + "tags": [ + "GenAI" + ] + } + }, + "/otel/genai/traces/{project_id}/{trace_id}": { + "get": { + "description": "`duration_ms` is the only field guaranteed to be milliseconds. `gen_ai.*`\nspan attributes (e.g. time-to-first-token, token latency) often follow the\nOTel GenAI semantic conventions, which use **seconds** (a fractional\ndouble), not milliseconds — do not read them as ms without converting.", + "operationId": "get_genai_trace", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Trace ID (hex)", + "in": "path", + "name": "trace_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GenAiTraceDetailResponse" + } + } + }, + "description": "GenAI trace span details" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get GenAI span details for a specific trace.", + "tags": [ + "GenAI" + ] + } + }, + "/otel/global/traces/{trace_id}": { + "get": { + "description": "Fans out to every project that holds spans for `trace_id` (up to 20\nprojects, 10,000 total spans). Spans are annotated with\n`project_id`/`project_name` and sorted by `start_time ASC`.\n`truncated: true` signals a hit on either cap; `truncated_projects`\nlists the dropped project IDs. See ADR-027 §4 for the full design.", + "operationId": "getUnifiedTrace", + "parameters": [ + { + "description": "Trace ID (32 lowercase hex characters)", + "in": "path", + "name": "trace_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnifiedTrace" + } + } + }, + "description": "Unified cross-project trace waterfall" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "trace_id is not 32 lowercase hex characters" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions or deployment token" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Assemble a unified cross-project span waterfall (Phase 2).", + "tags": [ + "Traces" + ] + } + }, + "/otel/health/{project_id}": { + "get": { + "operationId": "get_health", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Filter by environment ID", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HealthResponse" + } + } + }, + "description": "Health summaries" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get health summaries for a project.", + "tags": [ + "OTel" + ] + } + }, + "/otel/insights/{project_id}": { + "get": { + "operationId": "list_insights", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Filter by status (active, resolved)", + "in": "query", + "name": "status", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Max insights to return (default: 20, max: 100)", + "in": "query", + "name": "limit", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + { + "description": "Offset for pagination", + "in": "query", + "name": "offset", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InsightsResponse" + } + } + }, + "description": "Insights list" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List anomaly insights for a project.", + "tags": [ + "Insights" + ] + } + }, + "/otel/logs": { + "get": { + "operationId": "query_logs", + "parameters": [ + { + "description": "Project ID", + "in": "query", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Filter by severity (TRACE, DEBUG, INFO, WARN, ERROR, FATAL)", + "in": "query", + "name": "severity", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter by service name", + "in": "query", + "name": "service_name", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Full-text search in log body (ILIKE)", + "in": "query", + "name": "search", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter by correlated trace ID", + "in": "query", + "name": "trace_id", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Start time (RFC 3339)", + "in": "query", + "name": "start_time", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "End time (RFC 3339)", + "in": "query", + "name": "end_time", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Max logs to return (default: 100, max: 1000)", + "in": "query", + "name": "limit", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + { + "description": "Offset for pagination", + "in": "query", + "name": "offset", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LogsResponse" + } + } + }, + "description": "Log records" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Query log records with optional filters.", + "tags": [ + "Telemetry Logs" + ] + } + }, + "/otel/metric-label-keys": { + "get": { + "operationId": "list_metric_label_keys", + "parameters": [ + { + "description": "Project ID", + "in": "query", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Metric to inspect", + "in": "query", + "name": "metric_name", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Window start (RFC 3339); defaults to 24h before end", + "in": "query", + "name": "start_time", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Window end (RFC 3339); defaults to now", + "in": "query", + "name": "end_time", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OtelMetricLabelKeysResponse" + } + } + }, + "description": "Distinct label keys" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List the attribute (label) keys observed on a metric — powers the\nlabel-filter key autocomplete.", + "tags": [ + "Telemetry Metrics" + ] + } + }, + "/otel/metric-label-values": { + "get": { + "operationId": "list_metric_label_values", + "parameters": [ + { + "description": "Project ID", + "in": "query", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Metric to inspect", + "in": "query", + "name": "metric_name", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Label key whose values to list (must match [a-zA-Z0-9_.:-])", + "in": "query", + "name": "label_key", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Window start (RFC 3339); defaults to 24h before end", + "in": "query", + "name": "start_time", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Window end (RFC 3339); defaults to now", + "in": "query", + "name": "end_time", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OtelMetricLabelValuesResponse" + } + } + }, + "description": "Distinct label values" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Invalid label key" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List the distinct values seen for a label key on a metric — powers value\nautocomplete once a key is chosen.", + "tags": [ + "Telemetry Metrics" + ] + } + }, + "/otel/metric-names/{project_id}": { + "get": { + "operationId": "list_metric_names", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OtelMetricNamesResponse" + } + } + }, + "description": "List of metric names" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List distinct metric names for a project.", + "tags": [ + "Telemetry Metrics" + ] + } + }, + "/otel/metrics": { + "get": { + "operationId": "query_metrics", + "parameters": [ + { + "description": "Project ID", + "in": "query", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Filter by metric name", + "in": "query", + "name": "metric_name", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter by service name", + "in": "query", + "name": "service_name", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter by deployment environment", + "in": "query", + "name": "environment", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Start time (RFC 3339)", + "in": "query", + "name": "start_time", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "End time (RFC 3339)", + "in": "query", + "name": "end_time", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Bucket interval (e.g. '1 hour', '5 minutes')", + "in": "query", + "name": "bucket_interval", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Max buckets to return (default: 1000)", + "in": "query", + "name": "limit", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + { + "description": "Filter by metric type (gauge, sum, histogram, exponential_histogram, summary)", + "in": "query", + "name": "metric_type", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Per-bucket aggregation: avg (default), sum, min, max, count, rate, p50/p95/p99, quantile:0.95", + "in": "query", + "name": "aggregation", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Comma-separated key=value data-point label filters (keys must match [a-zA-Z0-9_.:-])", + "in": "query", + "name": "label_filters", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Comma-separated label keys to group series by", + "in": "query", + "name": "group_by", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OtelMetricsResponse" + } + } + }, + "description": "Metrics data" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Invalid label key" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Query metrics with time bucketing.", + "tags": [ + "Telemetry Metrics" + ] + } + }, + "/otel/pipeline-stats": { + "get": { + "operationId": "get_pipeline_stats", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PipelineStatsResponse" + } + } + }, + "description": "Pipeline statistics" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get OTel pipeline statistics (admin/system view).", + "tags": [ + "OTel" + ] + } + }, + "/otel/quota/{project_id}": { + "get": { + "operationId": "get_quota", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/QuotaResponse" + } + } + }, + "description": "Storage quota" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get storage quota for a project.", + "tags": [ + "OTel" + ] + } + }, + "/otel/span-stats": { + "get": { + "description": "Groups spans by `(project, service, span name)` over a bounded window and\nreturns count, error rate, total/min/max/avg/stddev duration, p50/p95/p99,\nand two variability ratios per operation. Sorting is what makes it useful:\n\n- `sort_by=total_time` (default) — where the wall-clock actually goes.\n- `sort_by=p95` / `p99` — what users actually feel.\n- `sort_by=variability` or `tail_ratio` — operations whose *spread* is the\n problem: the ones that take 40ms most of the time and 4s the rest.\n- `span_name=payments.charge` — the worst this one operation ever got, in\n `max_duration_ms`.\n\nPair the variability sorts with `min_count` — a ratio computed from three\nsamples is noise, and without a floor it outranks every real signal.\n\nTwo bounds are enforced rather than clamped, so a result never claims to\ncover more than it does: at most 50 projects, and a window no wider than\n31 days. Both return 400. Unlike the trace list this report has no early\nexit — it aggregates every span in the window before it can rank anything.", + "operationId": "query_span_stats", + "parameters": [ + { + "description": "Single project to report on", + "in": "query", + "name": "project_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Comma-separated project ids, e.g. `4,5,6` (max 50)", + "in": "query", + "name": "project_ids", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Window start (RFC 3339); defaults to 24h before end_time. The window may not exceed 31 days", + "in": "query", + "name": "start_time", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Window end (RFC 3339); defaults to now", + "in": "query", + "name": "end_time", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Restrict to one service", + "in": "query", + "name": "service_name", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Restrict to one operation by exact span name", + "in": "query", + "name": "span_name", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Case-insensitive substring match on the span name", + "in": "query", + "name": "name_pattern", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "server | client | internal | producer | consumer", + "in": "query", + "name": "kind", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "ok | error | unset", + "in": "query", + "name": "status", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Restrict to one environment", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Restrict to one deployment", + "in": "query", + "name": "deployment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Comma-separated key=value span attribute filters", + "in": "query", + "name": "attributes", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Ignore spans faster than this", + "in": "query", + "name": "min_duration_ms", + "required": false, + "schema": { + "format": "double", + "type": "number" + } + }, + { + "description": "Drop operations with fewer samples than this", + "in": "query", + "name": "min_count", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + { + "description": "total_time | p50 | p95 | p99 | max | avg | stddev | count | errors | error_rate | variability | tail_ratio", + "in": "query", + "name": "sort_by", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "asc | desc (default)", + "in": "query", + "name": "sort_order", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Page size (default 20, max 100)", + "in": "query", + "name": "limit", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + { + "description": "Page offset", + "in": "query", + "name": "offset", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SpanStatsResponse" + } + } + }, + "description": "Per-operation latency statistics" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Invalid query (no project, empty window)" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Rank operations by latency, volume, or inconsistency.", + "tags": [ + "Traces" + ] + } + }, + "/otel/trace-summaries": { + "get": { + "operationId": "query_trace_summaries", + "parameters": [ + { + "description": "Project ID", + "in": "query", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Filter by trace ID", + "in": "query", + "name": "trace_id", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter by service name", + "in": "query", + "name": "service_name", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter by status (OK, ERROR)", + "in": "query", + "name": "status", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Minimum trace duration in ms", + "in": "query", + "name": "min_duration_ms", + "required": false, + "schema": { + "format": "double", + "type": "number" + } + }, + { + "description": "Start time (RFC 3339)", + "in": "query", + "name": "start_time", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "End time (RFC 3339)", + "in": "query", + "name": "end_time", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter by environment ID", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Filter by deployment ID", + "in": "query", + "name": "deployment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Filter by span name pattern (ILIKE)", + "in": "query", + "name": "name_pattern", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Sort field: 'start_time' (default) or 'duration'", + "in": "query", + "name": "sort_by", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Sort direction: 'asc' or 'desc' (default)", + "in": "query", + "name": "sort_order", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Compute the `total` count (default: true). Set false to skip the second aggregation when only the page is needed", + "in": "query", + "name": "include_total", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "description": "Max traces to return (default: 50, max: 100)", + "in": "query", + "name": "limit", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + { + "description": "Offset for pagination", + "in": "query", + "name": "offset", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TraceSummariesResponse" + } + } + }, + "description": "Trace summaries" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Query trace summaries — one row per trace with span count, error count,\nroot span info, and proper trace-level pagination.", + "tags": [ + "Traces" + ] + } + }, + "/otel/traces": { + "get": { + "description": "Each returned span has a `duration_ms` field (float, milliseconds) — this is\nthe ONLY field guaranteed to be in milliseconds. Spans also carry an\n`attributes` map of raw key/value pairs exactly as reported by the\ninstrumenting library: numeric attribute values may be seconds, milliseconds,\nmicroseconds, or nanoseconds depending on that library's convention, and\nnothing in this response labels the unit. Never assume an attribute's\nnumeric value shares `duration_ms`'s unit, and never state a duration in\nmilliseconds unless it came from a `duration_ms` field.", + "operationId": "query_traces", + "parameters": [ + { + "description": "Project ID", + "in": "query", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Filter by trace ID", + "in": "query", + "name": "trace_id", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter by service name", + "in": "query", + "name": "service_name", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter by status (OK, ERROR, UNSET)", + "in": "query", + "name": "status", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Minimum span duration in ms", + "in": "query", + "name": "min_duration_ms", + "required": false, + "schema": { + "format": "double", + "type": "number" + } + }, + { + "description": "Start time (RFC 3339)", + "in": "query", + "name": "start_time", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "End time (RFC 3339)", + "in": "query", + "name": "end_time", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter by environment ID", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Filter by deployment ID", + "in": "query", + "name": "deployment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Max spans to return (default: 100, max: 1000)", + "in": "query", + "name": "limit", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + { + "description": "Offset for pagination", + "in": "query", + "name": "offset", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TracesResponse" + } + } + }, + "description": "Trace spans" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Query trace spans with optional filters.", + "tags": [ + "Traces" + ] + } + }, + "/otel/traces/cross-project/{trace_id}": { + "get": { + "description": "Returns an empty `siblings` list when the trace is single-project — never\n404. Project names are included so the UI can render navigation links\nwithout a second round-trip. See ADR-027 §3 for the full auth model and\ntopology-disclosure trade-offs.", + "operationId": "getCrossProjectTraceSiblings", + "parameters": [ + { + "description": "Trace ID (32 lowercase hex characters)", + "in": "path", + "name": "trace_id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Project ID to exclude (the caller's own project) so the UI does not render a self-link", + "in": "query", + "name": "exclude_project_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CrossProjectTraceResponse" + } + } + }, + "description": "Sibling projects sharing this trace" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "trace_id is not 32 lowercase hex characters" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions or deployment token" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Discover sibling projects that share the same `trace_id` (Phase 1 banner).", + "tags": [ + "Traces" + ] + } + }, + "/otel/traces/{project_id}/{trace_id}": { + "get": { + "description": "Each span has a `duration_ms` field (float, milliseconds) — the ONLY field\nguaranteed to be in milliseconds — plus an `attributes` map of raw\nkey/value pairs exactly as the instrumenting library reported them.\nNumeric attribute values (e.g. connection-pool wait times, queue delays)\nmay be in seconds, milliseconds, microseconds, or nanoseconds depending on\nthat library's own convention; this response never labels the unit. When\nexplaining what a span spent time on, only quote milliseconds from\n`duration_ms` (or from `start_time`/`end_time` deltas) — never assume a raw\nattribute number is already in milliseconds.", + "operationId": "get_trace", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Trace ID (hex)", + "in": "path", + "name": "trace_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TracesResponse" + } + } + }, + "description": "Trace spans tree" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get all spans for a specific trace.", + "tags": [ + "Traces" + ] + } + }, + "/otel/v1/logs": { + "post": { + "description": "Authenticates via API key in header, decompresses, decodes protobuf,\nchecks rate limit and storage quota, routes high-severity logs\nto DB and all logs to S3.", + "operationId": "ingest_logs", + "requestBody": { + "content": { + "application/x-protobuf": { + "schema": { + "type": "string" + } + } + }, + "description": "OTLP ExportLogsServiceRequest (protobuf, optionally gzip/zstd compressed)", + "required": true + }, + "responses": { + "200": { + "description": "Logs accepted (OTLP protobuf response)" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Invalid payload" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Missing or invalid API key" + }, + "413": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Storage quota exceeded" + }, + "429": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Rate limit exceeded" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "api_key": [] + } + ], + "summary": "Ingest log records via OTLP/HTTP protobuf.", + "tags": [ + "OTel Ingest" + ] + } + }, + "/otel/v1/metrics": { + "post": { + "description": "Authenticates via API key in header, decompresses, decodes protobuf,\nchecks rate limit and storage quota, then stores.", + "operationId": "ingest_metrics", + "requestBody": { + "content": { + "application/x-protobuf": { + "schema": { + "type": "string" + } + } + }, + "description": "OTLP ExportMetricsServiceRequest (protobuf, optionally gzip/zstd compressed)", + "required": true + }, + "responses": { + "200": { + "description": "Metrics accepted (OTLP protobuf response)" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Invalid payload" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Missing or invalid API key" + }, + "413": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Storage quota exceeded" + }, + "429": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Rate limit exceeded" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "api_key": [] + } + ], + "summary": "Ingest metrics via OTLP/HTTP protobuf.", + "tags": [ + "OTel Ingest" + ] + } + }, + "/otel/v1/traces": { + "post": { + "description": "Authenticates via API key in header, decompresses, decodes protobuf,\nchecks rate limit and storage quota, then stores spans.", + "operationId": "ingest_traces", + "requestBody": { + "content": { + "application/x-protobuf": { + "schema": { + "type": "string" + } + } + }, + "description": "OTLP ExportTraceServiceRequest (protobuf, optionally gzip/zstd compressed)", + "required": true + }, + "responses": { + "200": { + "description": "Traces accepted (OTLP protobuf response)" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Invalid payload" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Missing or invalid API key" + }, + "413": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Storage quota exceeded" + }, + "429": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Rate limit exceeded" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "api_key": [] + } + ], + "summary": "Ingest trace spans via OTLP/HTTP protobuf.", + "tags": [ + "OTel Ingest" + ] + } + }, + "/otel/v1/{project_id}/{environment_id}/{deployment_id}/logs": { + "post": { + "operationId": "ingest_logs_by_path", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment ID", + "in": "path", + "name": "environment_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Deployment ID", + "in": "path", + "name": "deployment_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/x-protobuf": { + "schema": { + "type": "string" + } + } + }, + "description": "OTLP ExportLogsServiceRequest (protobuf, optionally gzip/zstd compressed)", + "required": true + }, + "responses": { + "200": { + "description": "Logs accepted (OTLP protobuf response)" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Invalid payload" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Missing or invalid API key" + }, + "413": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Storage quota exceeded" + }, + "429": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Rate limit exceeded" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "api_key": [] + } + ], + "summary": "Ingest log records with project/environment/deployment in the URL path.", + "tags": [ + "OTel Ingest" + ] + } + }, + "/otel/v1/{project_id}/{environment_id}/{deployment_id}/metrics": { + "post": { + "operationId": "ingest_metrics_by_path", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment ID", + "in": "path", + "name": "environment_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Deployment ID", + "in": "path", + "name": "deployment_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/x-protobuf": { + "schema": { + "type": "string" + } + } + }, + "description": "OTLP ExportMetricsServiceRequest (protobuf, optionally gzip/zstd compressed)", + "required": true + }, + "responses": { + "200": { + "description": "Metrics accepted (OTLP protobuf response)" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Invalid payload" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Missing or invalid API key" + }, + "413": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Storage quota exceeded" + }, + "429": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Rate limit exceeded" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "api_key": [] + } + ], + "summary": "Ingest metrics with project/environment/deployment in the URL path.", + "tags": [ + "OTel Ingest" + ] + } + }, + "/otel/v1/{project_id}/{environment_id}/{deployment_id}/traces": { + "post": { + "operationId": "ingest_traces_by_path", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment ID", + "in": "path", + "name": "environment_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Deployment ID", + "in": "path", + "name": "deployment_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/x-protobuf": { + "schema": { + "type": "string" + } + } + }, + "description": "OTLP ExportTraceServiceRequest (protobuf, optionally gzip/zstd compressed)", + "required": true + }, + "responses": { + "200": { + "description": "Traces accepted (OTLP protobuf response)" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Invalid payload" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Missing or invalid API key" + }, + "413": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Storage quota exceeded" + }, + "429": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Rate limit exceeded" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "api_key": [] + } + ], + "summary": "Ingest trace spans with project/environment/deployment in the URL path.", + "tags": [ + "OTel Ingest" + ] + } + }, + "/performance/has-metrics": { + "get": { + "operationId": "has_performance_metrics", + "parameters": [ + { + "description": "Project ID", + "in": "query", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HasMetricsResponse" + } + } + }, + "description": "Successfully checked performance metrics availability" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Authentication required" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Insufficient permissions" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Check if performance metrics exist for a project", + "tags": [ + "Performance" + ] + } + }, + "/performance/metrics": { + "get": { + "operationId": "get_performance_metrics", + "parameters": [ + { + "description": "Start date in format YYYY-MM-DD HH:MM:SS", + "in": "query", + "name": "start_date", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "End date in format YYYY-MM-DD HH:MM:SS", + "in": "query", + "name": "end_date", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Project ID or slug", + "in": "query", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment ID (optional)", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Deployment ID (optional)", + "in": "query", + "name": "deployment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Device type filter: desktop or mobile (optional)", + "in": "query", + "name": "device_type", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Include crawler/datacenter bot samples (default false)", + "in": "query", + "name": "include_bots", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "description": "Filter to one page pathname (optional)", + "in": "query", + "name": "filter_path", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter to one country (optional)", + "in": "query", + "name": "filter_country", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter to one region (optional)", + "in": "query", + "name": "filter_region", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter to one city (optional)", + "in": "query", + "name": "filter_city", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter to one browser (optional)", + "in": "query", + "name": "filter_browser", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter to one operating system (optional)", + "in": "query", + "name": "filter_operating_system", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PerformanceMetricsResponse" + } + } + }, + "description": "Successfully retrieved performance metrics" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Invalid date format or missing parameters" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Authentication required" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Insufficient permissions" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get performance metrics", + "tags": [ + "Performance" + ] + } + }, + "/performance/metrics-over-time": { + "get": { + "operationId": "get_metrics_over_time", + "parameters": [ + { + "description": "Start date in format YYYY-MM-DDTHH:MM:SSZ", + "in": "query", + "name": "start_date", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "End date in format YYYY-MM-DDTHH:MM:SSZ", + "in": "query", + "name": "end_date", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Project ID or slug", + "in": "query", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment ID (optional)", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Deployment ID (optional)", + "in": "query", + "name": "deployment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Device type filter: desktop or mobile (optional)", + "in": "query", + "name": "device_type", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Include crawler/datacenter bot samples (default false)", + "in": "query", + "name": "include_bots", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "description": "Filter to one page pathname (optional)", + "in": "query", + "name": "filter_path", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter to one country (optional)", + "in": "query", + "name": "filter_country", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter to one region (optional)", + "in": "query", + "name": "filter_region", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter to one city (optional)", + "in": "query", + "name": "filter_city", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter to one browser (optional)", + "in": "query", + "name": "filter_browser", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter to one operating system (optional)", + "in": "query", + "name": "filter_operating_system", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MetricsOverTimeResponse" + } + } + }, + "description": "Successfully retrieved metrics over time" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Invalid date format or missing parameters" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Authentication required" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Insufficient permissions" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get metrics over time", + "tags": [ + "Performance" + ] + } + }, + "/performance/page-metrics": { + "get": { + "operationId": "get_grouped_page_metrics", + "parameters": [ + { + "description": "Start date in format YYYY-MM-DDTHH:MM:SSZ", + "in": "query", + "name": "start_date", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "End date in format YYYY-MM-DDTHH:MM:SSZ", + "in": "query", + "name": "end_date", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Project ID or slug", + "in": "query", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment ID (optional)", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Deployment ID (optional)", + "in": "query", + "name": "deployment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Group by: path, country, region, city, device_type, browser, operating_system", + "in": "query", + "name": "group_by", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Device type filter: desktop or mobile (optional)", + "in": "query", + "name": "device_type", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Include crawler/datacenter bot samples (default false)", + "in": "query", + "name": "include_bots", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "description": "Filter to one page pathname (optional)", + "in": "query", + "name": "filter_path", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter to one country (optional)", + "in": "query", + "name": "filter_country", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter to one region (optional)", + "in": "query", + "name": "filter_region", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter to one city (optional)", + "in": "query", + "name": "filter_city", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter to one browser (optional)", + "in": "query", + "name": "filter_browser", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter to one operating system (optional)", + "in": "query", + "name": "filter_operating_system", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GroupedPageMetricsResponse" + } + } + }, + "description": "Successfully retrieved grouped page metrics" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Invalid date format, missing parameters, or invalid group_by value" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Authentication required" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Insufficient permissions" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get grouped page metrics", + "tags": [ + "Performance" + ] + } + }, + "/platform/access-info": { + "get": { + "description": "Returns details about the server's access mode, public IP address, private IP address,\nand domain creation capabilities. Both IP addresses are always included when available.", + "operationId": "get_access_info", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceAccessInfo" + } + } + }, + "description": "Service access information" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get information about how the service is being accessed", + "tags": [ + "Platform" + ] + } + }, + "/platform/private-ip": { + "get": { + "operationId": "get_private_ip", + "responses": { + "200": { + "description": "Successfully retrieved private IP address" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get private/local IP address of the server", + "tags": [ + "Platform" + ] + } + }, + "/platform/public-ip": { + "get": { + "operationId": "get_public_ip", + "responses": { + "200": { + "description": "Successfully retrieved public IP address" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get public IP address of the server", + "tags": [ + "Platform" + ] + } + }, + "/presets": { + "get": { + "operationId": "list_presets", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListPresetsResponse" + } + } + }, + "description": "List of available presets" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List all available presets", + "tags": [ + "Presets" + ] + } + }, + "/presets/{slug}/dockerfile": { + "post": { + "description": "Returns the Dockerfile content and build arguments for a given preset slug.\nThe CLI can use this to build Docker images locally without needing a Dockerfile\nin the project directory, enabling zero-config deployments.", + "operationId": "generate_preset_dockerfile", + "parameters": [ + { + "description": "Preset slug (e.g., nextjs, vite, python)", + "in": "path", + "name": "slug", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GenerateDockerfileRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GenerateDockerfileResponse" + } + } + }, + "description": "Generated Dockerfile" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Preset not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Generate a Dockerfile from a preset", + "tags": [ + "Presets" + ] + } + }, + "/preview-gateway/logs": { + "get": { + "operationId": "get_preview_gateway_logs", + "parameters": [ + { + "description": "Lines to tail (default 200, max 2000)", + "in": "query", + "name": "tail", + "required": false, + "schema": { + "minimum": 0, + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LogsResponse" + } + } + }, + "description": "" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Preview Gateway" + ] + } + }, + "/preview-gateway/restart": { + "post": { + "operationId": "restart_preview_gateway", + "responses": { + "204": { + "description": "Gateway restarted" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Preview Gateway" + ] + } + }, + "/preview-gateway/settings": { + "get": { + "operationId": "get_preview_gateway_settings", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PreviewGatewaySettingsResponse" + } + } + }, + "description": "" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Preview Gateway" + ] + }, + "patch": { + "operationId": "patch_preview_gateway_settings", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PatchSettingsRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PreviewGatewaySettingsResponse" + } + } + }, + "description": "" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Preview Gateway" + ] + } + }, + "/preview-gateway/status": { + "get": { + "operationId": "get_preview_gateway_status", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GatewayStatus" + } + } + }, + "description": "" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Preview Gateway" + ] + } + }, + "/preview-gateway/upgrade": { + "post": { + "operationId": "upgrade_preview_gateway", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpgradeRequest" + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Gateway upgraded" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Preview Gateway" + ] + } + }, + "/projects": { + "get": { + "operationId": "get_projects", + "parameters": [ + { + "description": "Page number (1-based)", + "in": "query", + "name": "page", + "required": false, + "schema": { + "format": "int64", + "type": "integer" + } + }, + { + "description": "Number of items per page", + "in": "query", + "name": "per_page", + "required": false, + "schema": { + "format": "int64", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PaginatedProjectList" + } + } + }, + "description": "List of projects" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get a list of all projects", + "tags": [ + "Projects" + ] + }, + "post": { + "operationId": "create_project", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateProjectRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProjectResponse" + } + } + }, + "description": "Project created successfully" + }, + "400": { + "description": "Invalid input" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Create a new project", + "tags": [ + "Projects" + ] + } + }, + "/projects/by-slug/{slug}": { + "get": { + "operationId": "get_project_by_slug", + "parameters": [ + { + "description": "Project slug", + "in": "path", + "name": "slug", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProjectResponse" + } + } + }, + "description": "Project details" + }, + "404": { + "description": "Project not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get details of a specific project by slug", + "tags": [ + "Projects" + ] + } + }, + "/projects/from-template": { + "post": { + "description": "Creates a new repository from a template and sets up the project with the\nspecified configuration. The template is cloned to a new repository under\nthe authenticated user's account or specified organization.", + "operationId": "create_project_from_template", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateProjectFromTemplateRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateProjectFromTemplateResponse" + } + } + }, + "description": "Project created successfully" + }, + "400": { + "description": "Invalid input" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Template not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Create a new project from a template", + "tags": [ + "Projects" + ] + } + }, + "/projects/statistics": { + "get": { + "operationId": "get_project_statistics", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProjectStatisticsResponse" + } + } + }, + "description": "Project statistics" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get project statistics", + "tags": [ + "Projects" + ] + } + }, + "/projects/{id}": { + "delete": { + "operationId": "delete_project", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "Project deleted successfully" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Project not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Projects" + ] + }, + "get": { + "operationId": "get_project", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProjectResponse" + } + } + }, + "description": "Project details" + }, + "404": { + "description": "Project not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get details of a specific project", + "tags": [ + "Projects" + ] + }, + "put": { + "operationId": "update_project", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateProjectRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProjectResponse" + } + } + }, + "description": "Project updated successfully" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Project not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Projects" + ] + } + }, + "/projects/{id}/deployments": { + "get": { + "operationId": "get_project_deployments", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Page number", + "in": "query", + "name": "page", + "required": false, + "schema": { + "format": "int64", + "type": "integer" + } + }, + { + "description": "Items per page", + "in": "query", + "name": "per_page", + "required": false, + "schema": { + "format": "int64", + "type": "integer" + } + }, + { + "description": "Environment ID filter", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeploymentListResponse" + } + } + }, + "description": "List of deployments" + }, + "404": { + "description": "Project not found" + } + }, + "tags": [ + "Projects" + ] + } + }, + "/projects/{id}/last-deployment": { + "get": { + "operationId": "get_last_deployment", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeploymentResponse" + } + } + }, + "description": "Last deployment details" + }, + "404": { + "description": "Project not found or no deployments" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Get the last deployment for a specific project", + "tags": [ + "Deployments" + ] + } + }, + "/projects/{id}/source": { + "patch": { + "operationId": "change_project_source", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChangeProjectSourceRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProjectResponse" + } + } + }, + "description": "Source type changed" + }, + "400": { + "description": "Invalid source type change (e.g. switching to Git here)" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Project not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Change a project's source type to a Git-less type (docker_image /\nstatic_files / manual). Switching TO Git is done via the Git settings\nendpoint (`POST /projects/{id}/git`), which also supplies the repository and\nprovider connection.", + "tags": [ + "Projects" + ] + } + }, + "/projects/{id}/trigger-pipeline": { + "post": { + "operationId": "trigger_project_pipeline", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TriggerPipelinePayload" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TriggerPipelineResponse" + } + } + }, + "description": "Pipeline triggered successfully" + }, + "400": { + "description": "Invalid request" + }, + "404": { + "description": "Project not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Trigger pipeline for a specific project", + "tags": [ + "Projects" + ] + } + }, + "/projects/{project_id}/access": { + "get": { + "operationId": "list_project_access", + "parameters": [ + { + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/ProjectAccessResponse" + }, + "type": "array" + } + } + }, + "description": "Access grants" + }, + "403": { + "description": "Insufficient permissions or no access to this project" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Teams" + ] + }, + "post": { + "operationId": "grant_project_access", + "parameters": [ + { + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateProjectAccessRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProjectAccessResponse" + } + } + }, + "description": "Access granted (idempotent upsert)" + }, + "403": { + "description": "Insufficient permissions or no access to this project" + }, + "404": { + "description": "Team not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Teams" + ] + } + }, + "/projects/{project_id}/access/{team_id}": { + "delete": { + "operationId": "revoke_project_access", + "parameters": [ + { + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "in": "path", + "name": "team_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "Access revoked" + }, + "403": { + "description": "Insufficient permissions or no access to this project" + }, + "404": { + "description": "Grant not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Teams" + ] + } + }, + "/projects/{project_id}/active-visitors": { + "get": { + "operationId": "get_active_visitors", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Filter by environment ID", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Filter by deployment ID", + "in": "query", + "name": "deployment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ActiveVisitorsResponse" + } + } + }, + "description": "Successfully retrieved active visitors count" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get active visitors count", + "tags": [ + "Events" + ] + } + }, + "/projects/{project_id}/agents": { + "get": { + "operationId": "list_agents", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListAgentsResponse" + } + } + }, + "description": "List of agents for project" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Agents" + ] + }, + "post": { + "operationId": "create_agent", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpsertAgentRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentConfigResponse" + } + } + }, + "description": "Agent created" + }, + "400": { + "description": "Validation error" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Agents" + ] + } + }, + "/projects/{project_id}/agents/cli-status": { + "get": { + "operationId": "get_cli_status", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "AI provider: claude_cli or codex_cli", + "in": "query", + "name": "provider", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "CLI status" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Agents" + ] + } + }, + "/projects/{project_id}/agents/runs": { + "get": { + "operationId": "list_all_runs", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Page number (1-based)", + "in": "query", + "name": "page", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + { + "description": "Page size (max 100)", + "in": "query", + "name": "page_size", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListRunsResponse" + } + } + }, + "description": "List of all agent runs for a project" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Agents" + ] + } + }, + "/projects/{project_id}/agents/runs/latest-for-source": { + "get": { + "operationId": "latest_run_for_source", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Trigger source type, e.g. 'error_group'", + "in": "query", + "name": "trigger_source_type", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Trigger source ID", + "in": "query", + "name": "trigger_source_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/AgentRunResponse" + } + ] + } + } + }, + "description": "Latest matching run, or null if none" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Agents" + ] + } + }, + "/projects/{project_id}/agents/runs/{run_id}": { + "get": { + "operationId": "get_run_with_logs", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Run ID", + "in": "path", + "name": "run_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentRunWithLogsResponse" + } + } + }, + "description": "Run with logs" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Run not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Agents" + ] + } + }, + "/projects/{project_id}/agents/runs/{run_id}/cancel": { + "post": { + "operationId": "cancel_run", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Agent run ID to cancel", + "in": "path", + "name": "run_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentRunResponse" + } + } + }, + "description": "Run cancelled" + }, + "400": { + "description": "Run is already in a terminal state" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Run not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Agents" + ] + } + }, + "/projects/{project_id}/agents/runs/{run_id}/retry": { + "post": { + "operationId": "retry_run", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Run ID to retry", + "in": "path", + "name": "run_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "202": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentRunResponse" + } + } + }, + "description": "New run created from retry" + }, + "400": { + "description": "Run is still active" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Run not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Retry a completed, failed, cancelled, or no_fix run with the same trigger context.\nCreates a new run record and spawns the executor.", + "tags": [ + "Agents" + ] + } + }, + "/projects/{project_id}/agents/runs/{run_id}/stream": { + "get": { + "operationId": "stream_run_events", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Agent run ID", + "in": "path", + "name": "run_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "text/event-stream": {} + }, + "description": "Server-Sent Events stream of run log events and terminal status" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Run not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "SSE endpoint for real-time streaming of run events.\nPolls the agent_run_logs table every 500ms for new entries and streams them.\nCloses when the run reaches a terminal status.", + "tags": [ + "Agents" + ] + } + }, + "/projects/{project_id}/agents/sandbox-status": { + "get": { + "operationId": "get_sandbox_status", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SandboxStatusResponse" + } + } + }, + "description": "Project-scoped sandbox readiness (Docker + agent image)" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Agents" + ] + } + }, + "/projects/{project_id}/agents/smoke-test": { + "post": { + "operationId": "smoke_test_agent", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Provider id to test; defaults to the globally active provider", + "in": "query", + "name": "provider_id", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SmokeTestResponse" + } + } + }, + "description": "Smoke test result for the AI CLI in the agent's execution environment" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Run a smoke test to verify the selected AI CLI works in the environment\nwhere agents will actually execute (host or sandbox container). If no\n`provider_id` is supplied the globally active provider is tested.", + "tags": [ + "Agents" + ] + } + }, + "/projects/{project_id}/agents/{slug}": { + "delete": { + "operationId": "delete_agent", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Agent slug", + "in": "path", + "name": "slug", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Agent deleted" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Agent not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Agents" + ] + }, + "get": { + "operationId": "get_agent", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Agent slug", + "in": "path", + "name": "slug", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentConfigResponse" + } + } + }, + "description": "Agent config" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Agent not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Agents" + ] + }, + "put": { + "operationId": "update_agent", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Agent slug", + "in": "path", + "name": "slug", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpsertAgentRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentConfigResponse" + } + } + }, + "description": "Agent updated" + }, + "400": { + "description": "Validation error" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Agent not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Agents" + ] + } + }, + "/projects/{project_id}/agents/{slug}/runs": { + "get": { + "operationId": "list_agent_runs", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Agent slug", + "in": "path", + "name": "slug", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Page number (1-based)", + "in": "query", + "name": "page", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + { + "description": "Page size (max 100)", + "in": "query", + "name": "page_size", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListRunsResponse" + } + } + }, + "description": "List of runs for a specific agent" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Agent not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Agents" + ] + } + }, + "/projects/{project_id}/agents/{slug}/trigger": { + "post": { + "operationId": "trigger_agent", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Agent slug", + "in": "path", + "name": "slug", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TriggerAgentRequest" + } + } + }, + "required": true + }, + "responses": { + "202": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentRunResponse" + } + } + }, + "description": "Agent run created and queued" + }, + "400": { + "description": "Validation error" + }, + "401": { + "description": "Unauthorized" + }, + "402": { + "description": "Daily budget exceeded" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Agent not found" + }, + "422": { + "description": "AI CLI not installed" + }, + "429": { + "description": "Cooldown active" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Agents" + ] + } + }, + "/projects/{project_id}/aggregated-buckets": { + "get": { + "operationId": "get_aggregated_buckets", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Start date for the query range", + "in": "query", + "name": "start_date", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "End date for the query range", + "in": "query", + "name": "end_date", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Optional environment filter", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Optional deployment filter", + "in": "query", + "name": "deployment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Aggregation level: events, sessions, or visitors (default: events)", + "in": "query", + "name": "aggregation_level", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Time bucket size: '1 hour', '1 day', '1 week', etc. (default: '1 hour')", + "in": "query", + "name": "bucket_size", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AggregatedBucketsResponse" + } + } + }, + "description": "Successfully retrieved aggregated buckets" + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get aggregated metrics by time bucket", + "tags": [ + "Events" + ] + } + }, + "/projects/{project_id}/ai/conversations": { + "get": { + "operationId": "find_conversation", + "parameters": [ + { + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "in": "query", + "name": "context_type", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "context_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/ConversationResponse" + } + ] + } + } + }, + "description": "" + }, + "401": { + "description": "" + }, + "403": { + "description": "" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Find the existing chat for a context (returns `null` if none yet). Requires\nthe per-project `ai_debug_chat_enabled` toggle to be on; returns 403 when the\nfeature is disabled so revoking it consistently hides existing chat content.", + "tags": [ + "AI Chat" + ] + }, + "post": { + "operationId": "create_conversation", + "parameters": [ + { + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateConversationRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ConversationResponse" + } + } + }, + "description": "" + }, + "401": { + "description": "" + }, + "403": { + "description": "" + }, + "404": { + "description": "" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get-or-create the chat for a context (seeds it on first open).", + "tags": [ + "AI Chat" + ] + } + }, + "/projects/{project_id}/ai/conversations/list": { + "get": { + "operationId": "list_conversations", + "parameters": [ + { + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/ConversationResponse" + }, + "type": "array" + } + } + }, + "description": "" + }, + "401": { + "description": "" + }, + "403": { + "description": "" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List all active conversations for a project, most-recently-active first.\nPowers the conversation switcher in the AI assistant sidebar.", + "tags": [ + "AI Chat" + ] + } + }, + "/projects/{project_id}/ai/conversations/{public_id}": { + "get": { + "operationId": "get_conversation", + "parameters": [ + { + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "in": "path", + "name": "public_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ConversationDetailResponse" + } + } + }, + "description": "" + }, + "401": { + "description": "" + }, + "403": { + "description": "" + }, + "404": { + "description": "" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Full conversation history (excluding the internal system seed).", + "tags": [ + "AI Chat" + ] + }, + "patch": { + "operationId": "rename_conversation", + "parameters": [ + { + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "in": "path", + "name": "public_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RenameConversationRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ConversationResponse" + } + } + }, + "description": "" + }, + "400": { + "description": "" + }, + "401": { + "description": "" + }, + "403": { + "description": "" + }, + "404": { + "description": "" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Rename a conversation (set its human-facing title).", + "tags": [ + "AI Chat" + ] + } + }, + "/projects/{project_id}/ai/conversations/{public_id}/archive": { + "post": { + "operationId": "archive_conversation", + "parameters": [ + { + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "in": "path", + "name": "public_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "" + }, + "401": { + "description": "" + }, + "403": { + "description": "" + }, + "404": { + "description": "" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Archive (soft-delete) a conversation.", + "tags": [ + "AI Chat" + ] + } + }, + "/projects/{project_id}/ai/conversations/{public_id}/messages": { + "post": { + "operationId": "send_message", + "parameters": [ + { + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "in": "path", + "name": "public_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SendMessageRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "text/event-stream": {} + }, + "description": "SSE stream of assistant text deltas" + }, + "401": { + "description": "" + }, + "403": { + "description": "" + }, + "404": { + "description": "" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Send a user message; stream the assistant reply as Server-Sent Events.", + "tags": [ + "AI Chat" + ] + } + }, + "/projects/{project_id}/ai/conversations/{public_id}/pending-actions": { + "get": { + "operationId": "list_pending_actions", + "parameters": [ + { + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Conversation public id", + "in": "path", + "name": "public_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/PendingActionResponse" + }, + "type": "array" + } + } + }, + "description": "" + }, + "401": { + "description": "" + }, + "403": { + "description": "" + }, + "404": { + "description": "" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List all pending actions for a conversation (most-recently-proposed first).", + "tags": [ + "AI Chat" + ] + } + }, + "/projects/{project_id}/ai/pending-actions/{action_public_id}": { + "get": { + "operationId": "get_pending_action", + "parameters": [ + { + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "in": "path", + "name": "action_public_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PendingActionResponse" + } + } + }, + "description": "" + }, + "401": { + "description": "" + }, + "403": { + "description": "" + }, + "404": { + "description": "" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get a single pending action by its public id (scoped to the project).", + "tags": [ + "AI Chat" + ] + } + }, + "/projects/{project_id}/ai/pending-actions/{action_public_id}/confirm": { + "post": { + "operationId": "confirm_pending_action", + "parameters": [ + { + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "in": "path", + "name": "action_public_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PendingActionResponse" + } + } + }, + "description": "" + }, + "401": { + "description": "" + }, + "403": { + "description": "" + }, + "404": { + "description": "" + }, + "409": { + "description": "" + }, + "503": { + "description": "" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Confirm a proposed AI action: validate permission, atomically claim, execute,\npersist outcome. The execution uses the CONFIRMING user's auth — never the model's.", + "tags": [ + "AI Chat" + ] + } + }, + "/projects/{project_id}/ai/pending-actions/{action_public_id}/reject": { + "post": { + "operationId": "reject_pending_action", + "parameters": [ + { + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "in": "path", + "name": "action_public_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PendingActionResponse" + } + } + }, + "description": "" + }, + "401": { + "description": "" + }, + "403": { + "description": "" + }, + "404": { + "description": "" + }, + "409": { + "description": "" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Reject a proposed AI action (no execution). Status transitions to \"rejected\".", + "tags": [ + "AI Chat" + ] + } + }, + "/projects/{project_id}/ai/readiness": { + "get": { + "description": "Read-only and cheap, so the UI can decide up front whether to show a working\nentry point, an onboarding path, or nothing — instead of letting the user\nclick something that fails with a 409 they can't act on.", + "operationId": "get_chat_readiness", + "parameters": [ + { + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChatReadinessResponse" + } + } + }, + "description": "Which AI prerequisites are met" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Project not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Report which AI prerequisites this project satisfies.", + "tags": [ + "AI Chat" + ] + } + }, + "/projects/{project_id}/alarms": { + "get": { + "operationId": "listProjectAlarms", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Filter by alarm type (e.g. `container_restart`, `outage`).", + "in": "query", + "name": "alarm_type", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "description": "Filter by status: `firing`, `acknowledged`, or `resolved`.", + "in": "query", + "name": "status", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "description": "Filter by severity: `info`, `warning`, or `critical`.", + "in": "query", + "name": "severity", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "description": "Filter by environment ID.", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + { + "description": "Filter by deployment ID.", + "in": "query", + "name": "deployment_id", + "required": false, + "schema": { + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + { + "description": "Filter by external service ID.", + "in": "query", + "name": "service_id", + "required": false, + "schema": { + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + { + "description": "Page number (1-based, default 1).", + "in": "query", + "name": "page", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + } + }, + { + "description": "Items per page (default 20, max 100).", + "in": "query", + "name": "page_size", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AlarmListResponse" + } + } + }, + "description": "Paginated list of alarms" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List alarms for a project with optional filters.", + "tags": [ + "Alarms" + ] + } + }, + "/projects/{project_id}/alarms/summary": { + "get": { + "operationId": "getProjectAlarmsSummary", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AlarmSummaryResponse" + } + } + }, + "description": "Alarm summary counts" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get alarm counts by status/severity/type for a project (dashboard summary widget).", + "tags": [ + "Alarms" + ] + } + }, + "/projects/{project_id}/alarms/{alarm_id}/acknowledge": { + "post": { + "operationId": "acknowledgeAlarm", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Alarm ID", + "in": "path", + "name": "alarm_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "Alarm acknowledged" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Alarm not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Acknowledge a firing alarm (marks it as seen but not resolved).", + "tags": [ + "Alarms" + ] + } + }, + "/projects/{project_id}/alarms/{alarm_id}/resolve": { + "post": { + "operationId": "resolveAlarm", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Alarm ID", + "in": "path", + "name": "alarm_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "Alarm resolved" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Alarm not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Resolve an alarm.", + "tags": [ + "Alarms" + ] + } + }, + "/projects/{project_id}/autofixer/analyze": { + "post": { + "operationId": "start_analysis", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StartAnalysisRequest" + } + } + }, + "required": true + }, + "responses": { + "202": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AutofixerRunResponse" + } + } + }, + "description": "Analysis started; returns run_id for streaming" + }, + "400": { + "description": "Validation error" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Start an autofixer analysis run for the given error group.\nCreates the run record immediately and spawns analysis in the background.", + "tags": [ + "Autofixer" + ] + } + }, + "/projects/{project_id}/autofixer/runs/{run_id}": { + "get": { + "operationId": "get_run", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Run ID", + "in": "path", + "name": "run_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AutofixerRunWithLogsResponse" + } + } + }, + "description": "Run with logs" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Run not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get a single autofixer run with its logs.", + "tags": [ + "Autofixer" + ] + } + }, + "/projects/{project_id}/autofixer/runs/{run_id}/add-context": { + "post": { + "operationId": "add_context", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Run ID", + "in": "path", + "name": "run_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AddContextRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Context appended" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Run not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Append a user message to the run's context field.", + "tags": [ + "Autofixer" + ] + } + }, + "/projects/{project_id}/autofixer/runs/{run_id}/cancel": { + "post": { + "operationId": "cancel", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Run ID", + "in": "path", + "name": "run_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "Run cancelled" + }, + "400": { + "description": "Run is already in a terminal state" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Run not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Cancel an autofixer run and clean up the work directory.", + "tags": [ + "Autofixer" + ] + } + }, + "/projects/{project_id}/autofixer/runs/{run_id}/create-pr": { + "post": { + "operationId": "create_pr", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Run ID", + "in": "path", + "name": "run_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreatePrResponse" + } + } + }, + "description": "PR created" + }, + "400": { + "description": "Run not in fix_ready phase" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Run not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Push the fix branch and create a pull request.\nRequires phase == \"fix_ready\".", + "tags": [ + "Autofixer" + ] + } + }, + "/projects/{project_id}/autofixer/runs/{run_id}/fix": { + "post": { + "operationId": "start_fix", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Run ID", + "in": "path", + "name": "run_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "202": { + "description": "Fix generation started" + }, + "400": { + "description": "Run not in analyzed phase" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Run not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Transition from analysis to fix phase.\nRequires phase == \"analyzed\".", + "tags": [ + "Autofixer" + ] + } + }, + "/projects/{project_id}/autofixer/runs/{run_id}/re-analyze": { + "post": { + "operationId": "re_analyze", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Run ID", + "in": "path", + "name": "run_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "202": { + "description": "Conversation continued with feedback" + }, + "400": { + "description": "Run not in analyzed phase" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Run not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Continue the conversation with user feedback.\nUses the same Claude session (--continue) in the existing work directory.\nRequires phase == \"analyzed\".", + "tags": [ + "Autofixer" + ] + } + }, + "/projects/{project_id}/autofixer/runs/{run_id}/stream": { + "get": { + "operationId": "stream_events", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Autofixer run ID", + "in": "path", + "name": "run_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "text/event-stream": {} + }, + "description": "Server-Sent Events stream of autofixer run logs and status updates" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Run not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "SSE endpoint: streams run log events in real-time.\nPolls every 500 ms. Keeps the connection open through \"analyzed\" and \"fix_ready\"\nwaiting states; closes only on terminal statuses.", + "tags": [ + "Agents" + ] + } + }, + "/projects/{project_id}/automatic-deploy": { + "post": { + "operationId": "update_automatic_deploy", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateAutomaticDeployRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProjectResponse" + } + } + }, + "description": "Automatic deployment setting updated successfully" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Project not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Update automatic deployment setting for a project", + "tags": [ + "Projects" + ] + } + }, + "/projects/{project_id}/custom-domains": { + "get": { + "operationId": "list_custom_domains_for_project", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListCustomDomainsResponse" + } + } + }, + "description": "Custom domains retrieved successfully" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List all custom domains for a project", + "tags": [ + "Custom Domains" + ] + }, + "post": { + "operationId": "create_custom_domain", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomDomainRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomDomainResponse" + } + } + }, + "description": "Custom domain created successfully" + }, + "400": { + "description": "Invalid input" + }, + "401": { + "description": "Unauthorized" + }, + "409": { + "description": "Domain already exists" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Create a custom domain for a project", + "tags": [ + "Custom Domains" + ] + } + }, + "/projects/{project_id}/custom-domains/{domain_id}": { + "delete": { + "operationId": "delete_custom_domain", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Custom domain ID", + "in": "path", + "name": "domain_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "Custom domain deleted successfully" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Custom domain not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Delete a custom domain", + "tags": [ + "Custom Domains" + ] + }, + "get": { + "operationId": "get_custom_domain", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Custom domain ID", + "in": "path", + "name": "domain_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomDomainResponse" + } + } + }, + "description": "Custom domain retrieved successfully" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Custom domain not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get a custom domain by ID", + "tags": [ + "Custom Domains" + ] + }, + "put": { + "operationId": "update_custom_domain", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Custom domain ID", + "in": "path", + "name": "domain_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateCustomDomainRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomDomainResponse" + } + } + }, + "description": "Custom domain updated successfully" + }, + "400": { + "description": "Invalid input" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Custom domain not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Update a custom domain", + "tags": [ + "Custom Domains" + ] + } + }, + "/projects/{project_id}/custom-domains/{domain_id}/link-certificate/{certificate_id}": { + "post": { + "operationId": "link_custom_domain_to_certificate", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Custom domain ID", + "in": "path", + "name": "domain_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Certificate ID", + "in": "path", + "name": "certificate_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CustomDomainResponse" + } + } + }, + "description": "Custom domain linked to certificate successfully" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Custom domain or certificate not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Link a custom domain to a certificate", + "tags": [ + "Custom Domains" + ] + } + }, + "/projects/{project_id}/deployment-config": { + "patch": { + "operationId": "update_project_deployment_config", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateDeploymentConfigRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProjectResponse" + } + } + }, + "description": "Deployment configuration updated successfully" + }, + "400": { + "description": "Invalid deployment configuration" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Project not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Update deployment configuration for a project", + "tags": [ + "Projects" + ] + } + }, + "/projects/{project_id}/deployment-tokens": { + "get": { + "operationId": "list_deployment_tokens", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Page number (default: 1)", + "in": "query", + "name": "page", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + { + "description": "Page size (default: 20, max: 100)", + "in": "query", + "name": "page_size", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeploymentTokenListResponse" + } + } + }, + "description": "List of deployment tokens" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List all deployment tokens for a project", + "tags": [ + "Deployment Tokens" + ] + }, + "post": { + "operationId": "create_deployment_token", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateDeploymentTokenRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateDeploymentTokenResponse" + } + } + }, + "description": "Deployment token created successfully" + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "409": { + "description": "Token with this name already exists" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Create a new deployment token for a project", + "tags": [ + "Deployment Tokens" + ] + } + }, + "/projects/{project_id}/deployment-tokens/{token_id}": { + "delete": { + "operationId": "delete_deployment_token", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Deployment token ID", + "in": "path", + "name": "token_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "Deployment token deleted successfully" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Deployment token not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Delete a deployment token", + "tags": [ + "Deployment Tokens" + ] + }, + "get": { + "operationId": "get_deployment_token", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Deployment token ID", + "in": "path", + "name": "token_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeploymentTokenResponse" + } + } + }, + "description": "Deployment token details" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Deployment token not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get a specific deployment token", + "tags": [ + "Deployment Tokens" + ] + }, + "patch": { + "operationId": "update_deployment_token", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Deployment token ID", + "in": "path", + "name": "token_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateDeploymentTokenRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeploymentTokenResponse" + } + } + }, + "description": "Deployment token updated successfully" + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Deployment token not found" + }, + "409": { + "description": "Token with this name already exists" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Update a deployment token", + "tags": [ + "Deployment Tokens" + ] + } + }, + "/projects/{project_id}/deployment-tokens/{token_id}/rotate": { + "post": { + "operationId": "rotate_deployment_token", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Deployment token ID", + "in": "path", + "name": "token_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateDeploymentTokenResponse" + } + } + }, + "description": "Deployment token rotated successfully; the response contains the new plaintext token, shown only once" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Deployment token not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Rotate a deployment token, invalidating its old secret and issuing a new one", + "tags": [ + "Deployment Tokens" + ] + } + }, + "/projects/{project_id}/deployments/{deployment_id}": { + "get": { + "operationId": "get_deployment", + "parameters": [ + { + "description": "Project ID or slug", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Deployment ID", + "in": "path", + "name": "deployment_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeploymentResponse" + } + } + }, + "description": "Deployment details" + }, + "404": { + "description": "Project or deployment not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Get a specific deployment by ID for a project (identified by ID or slug)", + "tags": [ + "Deployments" + ] + } + }, + "/projects/{project_id}/deployments/{deployment_id}/cancel": { + "post": { + "operationId": "cancel_deployment", + "parameters": [ + { + "description": "Project ID or slug", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Deployment ID", + "in": "path", + "name": "deployment_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeploymentStateResponse" + } + } + }, + "description": "Deployment cancelled successfully" + }, + "400": { + "description": "Deployment cannot be cancelled (already completed, failed, or cancelled)" + }, + "404": { + "description": "Project or deployment not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Cancel a deployment", + "tags": [ + "Projects" + ] + } + }, + "/projects/{project_id}/deployments/{deployment_id}/container-logs": { + "get": { + "description": "Container runtime logs are normally only available live from the running\ncontainer. When a deployment is superseded its containers are torn down and\nthose logs would be lost — so just before teardown we capture each\ncontainer's logs to durable storage. This endpoint lists what was captured\nfor a given (often older) deployment, so a user can read the logs of a\ncontainer that no longer exists.", + "operationId": "list_deployment_container_logs", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Deployment ID", + "in": "path", + "name": "deployment_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeploymentContainerLogsListResponse" + } + } + }, + "description": "Captured container logs for the deployment" + }, + "404": { + "description": "Deployment not found in this project" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_token": [] + } + ], + "summary": "List the captured (historical) container-log dumps for a deployment.", + "tags": [ + "Deployments" + ] + } + }, + "/projects/{project_id}/deployments/{deployment_id}/container-logs/{log_id}": { + "get": { + "operationId": "get_deployment_container_log_content", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Deployment ID", + "in": "path", + "name": "deployment_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Captured log ID", + "in": "path", + "name": "log_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeploymentContainerLogContentResponse" + } + } + }, + "description": "Captured container log content" + }, + "404": { + "description": "Captured log not found in this project" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_token": [] + } + ], + "summary": "Get the captured text content of a single historical container-log dump.", + "tags": [ + "Deployments" + ] + } + }, + "/projects/{project_id}/deployments/{deployment_id}/jobs": { + "get": { + "description": "Returns all jobs (workflow tasks) for a deployment, ordered by execution order.\nThis replaces the old deployment stages endpoint.", + "operationId": "get_deployment_jobs", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Deployment ID", + "in": "path", + "name": "deployment_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeploymentJobsResponse" + } + } + }, + "description": "Jobs retrieved successfully" + }, + "404": { + "description": "Deployment not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Get jobs for a specific deployment", + "tags": [ + "Deployments" + ] + } + }, + "/projects/{project_id}/deployments/{deployment_id}/jobs/{job_id}/logs": { + "get": { + "operationId": "get_deployment_job_logs", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Deployment ID", + "in": "path", + "name": "deployment_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Job ID", + "in": "path", + "name": "job_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + }, + "description": "Job logs retrieved successfully" + }, + "404": { + "description": "Job or logs not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_token": [] + } + ], + "summary": "Get logs for a specific deployment job", + "tags": [ + "Deployments" + ] + } + }, + "/projects/{project_id}/deployments/{deployment_id}/jobs/{job_id}/logs/tail": { + "get": { + "description": "**WebSocket Streaming**: Logs are sent as raw text, one line per WebSocket message.\n\n**Authentication**: Requires authentication via session cookie (browser clients)\nor API key (API clients). For browser-based WebSocket connections, ensure the user\nis logged in - the browser automatically includes session cookies in the WebSocket\nupgrade request.\n\n**API Client Authentication**: Include API key in Authorization header:\n```text\nAuthorization: Bearer tk_your_api_key_here\n```", + "operationId": "tail_deployment_job_logs", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Deployment ID", + "in": "path", + "name": "deployment_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Job ID", + "in": "path", + "name": "job_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "101": { + "description": "WebSocket connection established for streaming deployment job logs" + }, + "404": { + "description": "Job or logs not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_token": [] + } + ], + "summary": "Tail logs for a specific deployment job in real-time via WebSocket", + "tags": [ + "Deployments" + ] + } + }, + "/projects/{project_id}/deployments/{deployment_id}/operations": { + "get": { + "operationId": "get_deployment_operations", + "parameters": [ + { + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "in": "path", + "name": "deployment_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OperationResultsResponse" + } + } + }, + "description": "List of operations" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Deployment not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get all operations for a deployment", + "tags": [ + "Deployments" + ] + }, + "post": { + "operationId": "execute_deployment_operation", + "parameters": [ + { + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "in": "path", + "name": "deployment_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExecuteOperationRequest" + } + } + }, + "required": true + }, + "responses": { + "202": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OperationResultResponse" + } + } + }, + "description": "Operation executed" + }, + "400": { + "description": "Invalid operation" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Deployment not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Execute a deployment operation (deploy, mark_complete, take_screenshot)", + "tags": [ + "Deployments" + ] + } + }, + "/projects/{project_id}/deployments/{deployment_id}/operations/{operation_type}": { + "get": { + "operationId": "get_deployment_operation_status", + "parameters": [ + { + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "in": "path", + "name": "deployment_id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "operation_type", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OperationResultResponse" + } + } + }, + "description": "Operation status" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Operation not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get the status of a specific operation type", + "tags": [ + "Deployments" + ] + } + }, + "/projects/{project_id}/deployments/{deployment_id}/pause": { + "post": { + "operationId": "pause_deployment", + "parameters": [ + { + "description": "Project ID or slug", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Deployment ID", + "in": "path", + "name": "deployment_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeploymentStateResponse" + } + } + }, + "description": "Deployment paused successfully" + }, + "404": { + "description": "Project or deployment not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Pause a deployment", + "tags": [ + "Projects" + ] + } + }, + "/projects/{project_id}/deployments/{deployment_id}/promote": { + "post": { + "description": "Creates a new deployment in the target environment using the source deployment's\nDocker image. Useful for promoting a validated preview/staging deployment to production.", + "operationId": "promote_deployment", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Source deployment ID to promote", + "in": "path", + "name": "deployment_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PromoteDeploymentRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeploymentResponse" + } + } + }, + "description": "Promotion initiated successfully" + }, + "400": { + "description": "Invalid deployment state for promotion" + }, + "404": { + "description": "Project, deployment, or target environment not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Promote a deployment to another environment", + "tags": [ + "Deployments" + ] + } + }, + "/projects/{project_id}/deployments/{deployment_id}/resume": { + "post": { + "operationId": "resume_deployment", + "parameters": [ + { + "description": "Project ID or slug", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Deployment ID", + "in": "path", + "name": "deployment_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeploymentStateResponse" + } + } + }, + "description": "Deployment resumed successfully" + }, + "404": { + "description": "Project or deployment not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Resume a deployment", + "tags": [ + "Projects" + ] + } + }, + "/projects/{project_id}/deployments/{deployment_id}/rollback": { + "post": { + "operationId": "rollback_to_deployment", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Deployment ID to rollback to", + "in": "path", + "name": "deployment_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeploymentResponse" + } + } + }, + "description": "Rollback initiated successfully" + }, + "404": { + "description": "Project or deployment not found" + }, + "500": { + "description": "Internal server error" + } + }, + "tags": [ + "Projects" + ] + } + }, + "/projects/{project_id}/deployments/{deployment_id}/teardown": { + "delete": { + "operationId": "teardown_deployment", + "parameters": [ + { + "description": "Project ID or slug", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Deployment ID", + "in": "path", + "name": "deployment_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "Deployment torn down successfully" + }, + "404": { + "description": "Project or deployment not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Teardown a specific deployment", + "tags": [ + "Projects" + ] + } + }, + "/projects/{project_id}/dsns": { + "get": { + "operationId": "list_dsns", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/ProjectDSNResponse" + }, + "type": "array" + } + } + }, + "description": "List of DSNs" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List all DSNs for a project", + "tags": [] + }, + "post": { + "operationId": "create_dsn", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateDSNRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProjectDSNResponse" + } + } + }, + "description": "DSN created" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Project not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Create a new DSN for a project", + "tags": [] + } + }, + "/projects/{project_id}/dsns/get-or-create": { + "post": { + "operationId": "get_or_create_dsn", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetOrCreateDSNRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProjectDSNResponse" + } + } + }, + "description": "DSN retrieved or created" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Project not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get or create DSN for a project/environment/deployment combination", + "tags": [] + } + }, + "/projects/{project_id}/dsns/{dsn_id}/regenerate": { + "post": { + "operationId": "regenerate_dsn", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "DSN ID", + "in": "path", + "name": "dsn_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RegenerateDSNRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProjectDSNResponse" + } + } + }, + "description": "DSN keys regenerated" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "DSN not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Regenerate DSN keys (rotate keys)", + "tags": [] + } + }, + "/projects/{project_id}/dsns/{dsn_id}/revoke": { + "post": { + "operationId": "revoke_dsn", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "DSN ID", + "in": "path", + "name": "dsn_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "DSN revoked" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "DSN not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Revoke (deactivate) a DSN", + "tags": [] + } + }, + "/projects/{project_id}/env-vars": { + "get": { + "operationId": "get_environment_variables", + "parameters": [ + { + "description": "Project ID or slug", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Optional environment ID to filter by", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/EnvironmentVariableResponse" + }, + "type": "array" + } + } + }, + "description": "List of environment variables" + }, + "404": { + "description": "Project not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Get environment variables for a project, optionally filtered by environment", + "tags": [ + "Projects" + ] + }, + "post": { + "operationId": "create_environment_variable", + "parameters": [ + { + "description": "Project ID or slug", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateEnvironmentVariableRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnvironmentVariableResponse" + } + } + }, + "description": "Environment variables created successfully" + }, + "400": { + "description": "Invalid input" + }, + "404": { + "description": "Project not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Create a new environment variable", + "tags": [ + "Projects" + ] + } + }, + "/projects/{project_id}/env-vars/resolved": { + "get": { + "description": "Returns the effective set of environment variables a deployment would see,\ncombining manually-defined vars with those contributed by linked external\nservices (Postgres, Redis, S3, etc.). Each entry is tagged with its source\nso the UI can render an integration icon, and manual entries that shadow an\nintegration key carry a reference to the integration they override.\n\nValues are always returned as a masked preview. Use the per-key reveal\nendpoint for plaintext (audit-logged).", + "operationId": "get_resolved_environment_variables", + "parameters": [ + { + "description": "Project ID or slug", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Optional environment ID to filter manual vars by", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/ResolvedEnvVarResponse" + }, + "type": "array" + } + } + }, + "description": "Resolved environment variables" + }, + "404": { + "description": "Project not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Resolved env vars for a project (manual + integration-sourced, merged).", + "tags": [ + "Projects" + ] + } + }, + "/projects/{project_id}/env-vars/resolved/{key}/value": { + "get": { + "description": "Mirrors `GET /projects/{id}/env-vars/{key}/value` but handles keys sourced\nfrom linked integrations (which are not stored in the `env_vars` table).\nResolution order mirrors the merged view:\n\n1. Manual env var with this key — this endpoint reads the manual store when\n the key exists there, then writes its own reveal audit event so callers\n can safely use one endpoint regardless of source.\n2. Integration env var supplied by a linked external service.\n\nReturns 404 when neither a manual var nor an integration produces the key.", + "operationId": "get_resolved_environment_variable_value", + "parameters": [ + { + "description": "Project ID or slug", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment variable key", + "in": "path", + "name": "key", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Optional environment ID", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Exact manual environment-variable row ID", + "in": "query", + "name": "var_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Integration service ID shown by the resolved list", + "in": "query", + "name": "service_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnvironmentVariableValueResponse" + } + } + }, + "description": "Resolved environment variable value" + }, + "403": { + "description": "Plaintext secret access is not permitted" + }, + "404": { + "description": "Project, key, or integration not found" + }, + "409": { + "description": "Environment variable key is ambiguous" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Reveal the plaintext value of a resolved environment variable.", + "tags": [ + "Projects" + ] + } + }, + "/projects/{project_id}/env-vars/{key}/value": { + "get": { + "operationId": "get_environment_variable_value", + "parameters": [ + { + "description": "Project ID or slug", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment variable key", + "in": "path", + "name": "key", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Optional environment ID", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Exact environment-variable row ID", + "in": "query", + "name": "var_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnvironmentVariableValueResponse" + } + } + }, + "description": "Environment variable value" + }, + "403": { + "description": "Plaintext secret access is not permitted" + }, + "404": { + "description": "Project or variable not found" + }, + "409": { + "description": "Environment variable key is ambiguous" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Get environment variable value by key", + "tags": [ + "Projects" + ] + } + }, + "/projects/{project_id}/env-vars/{var_id}": { + "delete": { + "operationId": "delete_environment_variable", + "parameters": [ + { + "description": "Project ID or slug", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment variable ID", + "in": "path", + "name": "var_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "Environment variable deleted successfully" + }, + "404": { + "description": "Project or variable not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Delete an environment variable", + "tags": [ + "Projects" + ] + }, + "put": { + "operationId": "update_environment_variable", + "parameters": [ + { + "description": "Project ID or slug", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment variable ID", + "in": "path", + "name": "var_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateEnvironmentVariableRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnvironmentVariableResponse" + } + } + }, + "description": "Environment variables updated successfully" + }, + "400": { + "description": "Invalid input" + }, + "404": { + "description": "Project or variable not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Update an environment variable", + "tags": [ + "Projects" + ] + } + }, + "/projects/{project_id}/environments": { + "get": { + "operationId": "get_environments", + "parameters": [ + { + "description": "Project ID or slug", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/EnvironmentResponse" + }, + "type": "array" + } + } + }, + "description": "List of environments" + }, + "404": { + "description": "Project not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Get all environments for a project", + "tags": [ + "Projects" + ] + }, + "post": { + "operationId": "create_environment", + "parameters": [ + { + "description": "Project ID or slug", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateEnvironmentRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnvironmentResponse" + } + } + }, + "description": "Environment created successfully" + }, + "400": { + "description": "Invalid input" + }, + "404": { + "description": "Project not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Create a new environment for a project", + "tags": [ + "Projects" + ] + } + }, + "/projects/{project_id}/environments/{env_id}": { + "delete": { + "description": "Permanently deletes an environment and all related data. Cannot delete:\n- Production environments (name = \"Production\")\n\nWarning: This action is permanent and cannot be undone.\nActive deployments are automatically cancelled before deletion.", + "operationId": "delete_environment", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment ID", + "in": "path", + "name": "env_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "Environment permanently deleted" + }, + "400": { + "description": "Cannot delete production environment" + }, + "404": { + "description": "Project or environment not found" + }, + "428": { + "description": "Recent MFA verification required" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Delete an environment permanently", + "tags": [ + "Projects" + ] + }, + "get": { + "operationId": "get_environment", + "parameters": [ + { + "description": "Project ID or slug", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment ID or slug", + "in": "path", + "name": "env_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnvironmentResponse" + } + } + }, + "description": "Environment details" + }, + "404": { + "description": "Project or environment not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Get a specific environment by ID or slug", + "tags": [ + "Projects" + ] + } + }, + "/projects/{project_id}/environments/{env_id}/crons": { + "get": { + "operationId": "get_environment_crons", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment ID", + "in": "path", + "name": "env_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/CronInfo" + }, + "type": "array" + } + } + }, + "description": "List of cron jobs" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "tags": [ + "Crons" + ] + } + }, + "/projects/{project_id}/environments/{env_id}/crons/{cron_id}": { + "get": { + "operationId": "get_cron_by_id", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment ID", + "in": "path", + "name": "env_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Cron Job ID", + "in": "path", + "name": "cron_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CronInfo" + } + } + }, + "description": "Cron job details" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Cron job not found" + }, + "500": { + "description": "Internal server error" + } + }, + "tags": [ + "Crons" + ] + } + }, + "/projects/{project_id}/environments/{env_id}/crons/{cron_id}/executions": { + "get": { + "operationId": "get_cron_executions", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment ID", + "in": "path", + "name": "env_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Cron Job ID", + "in": "path", + "name": "cron_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Page number (default: 1)", + "in": "query", + "name": "page", + "required": false, + "schema": { + "format": "int64", + "type": "integer" + } + }, + { + "description": "Items per page (default: 20)", + "in": "query", + "name": "per_page", + "required": false, + "schema": { + "format": "int64", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/CronExecutionInfo" + }, + "type": "array" + } + } + }, + "description": "List of cron job executions" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Cron job not found" + }, + "500": { + "description": "Internal server error" + } + }, + "tags": [ + "Crons" + ] + } + }, + "/projects/{project_id}/environments/{env_id}/domains": { + "get": { + "operationId": "get_environment_domains", + "parameters": [ + { + "description": "Project ID or slug", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment ID or slug", + "in": "path", + "name": "env_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/EnvironmentDomainResponse" + }, + "type": "array" + } + } + }, + "description": "List of environment domains" + }, + "404": { + "description": "Project or environment not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Get all environment domains for a specific environment", + "tags": [ + "Projects" + ] + }, + "post": { + "operationId": "add_environment_domain", + "parameters": [ + { + "description": "Project ID or slug", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment ID or slug", + "in": "path", + "name": "env_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AddEnvironmentDomainRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnvironmentDomainResponse" + } + } + }, + "description": "Domain added successfully" + }, + "400": { + "description": "Invalid input" + }, + "404": { + "description": "Project or environment not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Add a new environment domain", + "tags": [ + "Projects" + ] + } + }, + "/projects/{project_id}/environments/{env_id}/domains/{domain_id}": { + "delete": { + "operationId": "delete_environment_domain", + "parameters": [ + { + "description": "Project ID or slug", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment ID or slug", + "in": "path", + "name": "env_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Domain ID", + "in": "path", + "name": "domain_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "Domain deleted successfully" + }, + "404": { + "description": "Project, environment, or domain not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Delete an environment domain", + "tags": [ + "Projects" + ] + } + }, + "/projects/{project_id}/environments/{env_id}/settings": { + "put": { + "operationId": "update_environment_settings", + "parameters": [ + { + "description": "Project ID or slug", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment ID or slug", + "in": "path", + "name": "env_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateEnvironmentSettingsRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnvironmentResponse" + } + } + }, + "description": "Environment settings updated successfully" + }, + "404": { + "description": "Project or environment not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Update environment settings", + "tags": [ + "Projects" + ] + } + }, + "/projects/{project_id}/environments/{env_id}/sleep": { + "post": { + "description": "Manually put an on-demand environment to sleep. Stops containers and sets\n`sleeping = true`. If no OnDemandWaker is available, falls back to DB flag only.", + "operationId": "sleep_environment", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment ID", + "in": "path", + "name": "env_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnvironmentResponse" + } + } + }, + "description": "Environment put to sleep" + }, + "400": { + "description": "On-demand not enabled for this environment" + }, + "404": { + "description": "Environment not found" + }, + "429": { + "description": "Too many state transitions, retry after cooldown" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Sleep an on-demand environment", + "tags": [ + "Environments" + ] + } + }, + "/projects/{project_id}/environments/{env_id}/subdomain": { + "patch": { + "description": "Replaces the environment's previous subdomain entirely — the old\nhostname stops resolving once the proxy reloads its route table.\nCustom domains attached to the environment are unaffected.", + "operationId": "update_environment_subdomain", + "parameters": [ + { + "description": "Project ID or slug", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment ID or slug", + "in": "path", + "name": "env_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateEnvironmentSubdomainRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnvironmentResponse" + } + } + }, + "description": "Subdomain updated successfully" + }, + "400": { + "description": "Invalid subdomain or conflict with another environment" + }, + "404": { + "description": "Project or environment not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Rename the auto-managed subdomain for an environment.", + "tags": [ + "Projects" + ] + } + }, + "/projects/{project_id}/environments/{env_id}/teardown": { + "delete": { + "operationId": "teardown_environment", + "parameters": [ + { + "description": "Project ID or slug", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment ID or slug", + "in": "path", + "name": "env_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "Environment torn down successfully" + }, + "404": { + "description": "Project or environment not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Teardown an environment and all its active deployments", + "tags": [ + "Projects" + ] + } + }, + "/projects/{project_id}/environments/{env_id}/wake": { + "post": { + "description": "Manually wake an environment that has been put to sleep by the on-demand\nidle timeout. Starts containers, waits for health checks, then sets\n`sleeping = false`. If no OnDemandWaker is available (proxy not running\nin same process), falls back to setting the DB flag only.", + "operationId": "wake_environment", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment ID", + "in": "path", + "name": "env_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnvironmentResponse" + } + } + }, + "description": "Environment woken up" + }, + "400": { + "description": "On-demand not enabled for this environment" + }, + "404": { + "description": "Environment not found" + }, + "429": { + "description": "Too many state transitions, retry after cooldown" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Wake a sleeping on-demand environment", + "tags": [ + "Environments" + ] + } + }, + "/projects/{project_id}/environments/{environment_id}/container-logs": { + "get": { + "operationId": "get_container_logs", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment ID", + "in": "path", + "name": "environment_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Start date for logs", + "in": "query", + "name": "start_date", + "required": false, + "schema": { + "format": "int64", + "type": "integer" + } + }, + { + "description": "End date for logs", + "in": "query", + "name": "end_date", + "required": false, + "schema": { + "format": "int64", + "type": "integer" + } + }, + { + "description": "Number of lines to tail (or 'all')", + "in": "query", + "name": "tail", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Optional container name (defaults to first/primary container)", + "in": "query", + "name": "container_name", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Include timestamps in log output (default: false)", + "in": "query", + "name": "timestamps", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "description": "Follow log output in real-time (default: true)", + "in": "query", + "name": "follow", + "required": false, + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "101": { + "description": "WebSocket connection established for streaming container logs" + }, + "400": { + "description": "Not a server-type project" + }, + "404": { + "description": "Project, deployment, or container not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get logs for a container in an environment via WebSocket", + "tags": [ + "Deployments" + ] + } + }, + "/projects/{project_id}/environments/{environment_id}/containers": { + "get": { + "operationId": "list_containers", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment ID", + "in": "path", + "name": "environment_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContainerListResponse" + } + } + }, + "description": "List of containers" + }, + "400": { + "description": "Not a server-type project" + }, + "404": { + "description": "Project or environment not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List all containers for an environment", + "tags": [ + "Deployments" + ] + } + }, + "/projects/{project_id}/environments/{environment_id}/containers/{container_id}": { + "get": { + "operationId": "get_container_detail", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment ID", + "in": "path", + "name": "environment_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Container ID", + "in": "path", + "name": "container_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContainerDetailResponse" + } + } + }, + "description": "Container details" + }, + "404": { + "description": "Container not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get detailed information about a specific container", + "tags": [ + "Containers" + ] + } + }, + "/projects/{project_id}/environments/{environment_id}/containers/{container_id}/environment/{variable_name}": { + "get": { + "operationId": "get_container_environment_variable", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment ID", + "in": "path", + "name": "environment_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Container ID", + "in": "path", + "name": "container_id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Environment variable name", + "in": "path", + "name": "variable_name", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContainerEnvironmentVariableValueResponse" + } + } + }, + "description": "Environment variable value" + }, + "403": { + "description": "Plaintext secret access is not permitted" + }, + "404": { + "description": "Container or environment variable not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Containers" + ] + } + }, + "/projects/{project_id}/environments/{environment_id}/containers/{container_id}/logs": { + "get": { + "operationId": "get_container_logs_by_id", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment ID", + "in": "path", + "name": "environment_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Container ID", + "in": "path", + "name": "container_id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Start date for logs", + "in": "query", + "name": "start_date", + "required": false, + "schema": { + "format": "int64", + "type": "integer" + } + }, + { + "description": "End date for logs", + "in": "query", + "name": "end_date", + "required": false, + "schema": { + "format": "int64", + "type": "integer" + } + }, + { + "description": "Number of lines to tail (or 'all')", + "in": "query", + "name": "tail", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Include timestamps in log output (default: false)", + "in": "query", + "name": "timestamps", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "description": "Follow log output in real-time (default: true)", + "in": "query", + "name": "follow", + "required": false, + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "101": { + "description": "WebSocket connection established for streaming container logs" + }, + "400": { + "description": "Not a server-type project" + }, + "404": { + "description": "Project, environment, or container not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get logs for a specific container by container ID via WebSocket", + "tags": [ + "Deployments" + ] + } + }, + "/projects/{project_id}/environments/{environment_id}/containers/{container_id}/metrics": { + "get": { + "operationId": "get_container_metrics", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment ID", + "in": "path", + "name": "environment_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Container ID", + "in": "path", + "name": "container_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContainerMetricsResponse" + } + } + }, + "description": "Container metrics retrieved successfully" + }, + "404": { + "description": "Container not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Get metrics/stats for a specific container", + "tags": [ + "Containers" + ] + } + }, + "/projects/{project_id}/environments/{environment_id}/containers/{container_id}/metrics/history": { + "get": { + "description": "Useful metric names: `container.cpu_percent`,\n`container.cpu_utilization_percent`, `container.memory_used_bytes`,\n`container.memory_percent`, `container.network_rx_bytes_delta`,\n`container.network_tx_bytes_delta`.", + "operationId": "ContainerMetricsGetHistory", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment ID", + "in": "path", + "name": "environment_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Container ID", + "in": "path", + "name": "container_id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Dotted metric name, e.g. `container.cpu_percent` or\n`container.memory_used_bytes`.", + "in": "query", + "name": "metric", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Time window: `1h`, `6h`, `24h`, or `7d` (defaults to `1h`).", + "in": "query", + "name": "range", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/ContainerMetricHistoryPoint" + }, + "type": "array" + } + } + }, + "description": "Metric time series data points" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Container not found" + }, + "500": { + "description": "Internal server error" + }, + "503": { + "description": "Metrics store not available" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Fetch a time-series range for a single container resource metric\n(recorded by the container health monitor every ~30s).", + "tags": [ + "Containers" + ] + } + }, + "/projects/{project_id}/environments/{environment_id}/containers/{container_id}/metrics/stream": { + "get": { + "operationId": "stream_container_metrics", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment ID", + "in": "path", + "name": "environment_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Container ID", + "in": "path", + "name": "container_id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Update interval in milliseconds (default: 1000)", + "in": "query", + "name": "interval", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "Metrics stream established (Server-Sent Events)" + }, + "404": { + "description": "Container not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Stream container metrics via Server-Sent Events (SSE)", + "tags": [ + "Containers" + ] + } + }, + "/projects/{project_id}/environments/{environment_id}/containers/{container_id}/restart": { + "post": { + "operationId": "restart_container", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment ID", + "in": "path", + "name": "environment_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Container ID", + "in": "path", + "name": "container_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContainerActionResponse" + } + } + }, + "description": "Container restarted successfully" + }, + "404": { + "description": "Container not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Restart a container", + "tags": [ + "Containers" + ] + } + }, + "/projects/{project_id}/environments/{environment_id}/containers/{container_id}/start": { + "post": { + "operationId": "start_container", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment ID", + "in": "path", + "name": "environment_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Container ID", + "in": "path", + "name": "container_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContainerActionResponse" + } + } + }, + "description": "Container started successfully" + }, + "404": { + "description": "Container not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Start a container", + "tags": [ + "Containers" + ] + } + }, + "/projects/{project_id}/environments/{environment_id}/containers/{container_id}/stop": { + "post": { + "operationId": "stop_container", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment ID", + "in": "path", + "name": "environment_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Container ID", + "in": "path", + "name": "container_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContainerActionResponse" + } + } + }, + "description": "Container stopped successfully" + }, + "404": { + "description": "Container not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Stop a specific container", + "tags": [ + "Containers" + ] + } + }, + "/projects/{project_id}/environments/{environment_id}/deploy/image": { + "post": { + "description": "Triggers a deployment using a pre-built Docker image from an external registry.\nThe image will be pulled and deployed to the specified environment.", + "operationId": "deploy_from_image", + "parameters": [ + { + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "in": "path", + "name": "environment_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeployFromImageRequest" + } + } + }, + "required": true + }, + "responses": { + "202": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RemoteDeploymentResponse" + } + } + }, + "description": "Deployment started" + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Project or environment not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Deploy from an external Docker image", + "tags": [ + "Deployments" + ] + } + }, + "/projects/{project_id}/environments/{environment_id}/deploy/image-upload": { + "post": { + "description": "Uploads a Docker image tarball (from `docker save`) and deploys it directly.\nThe image is imported using `docker load` and then deployed to the specified environment.\nThis is useful when you want to deploy an image without pushing to a registry first.\n\nThe uploaded file should be a tarball created by `docker save myimage:tag > image.tar`\nor `docker save myimage:tag | gzip > image.tar.gz` (gzip compressed tarballs are also supported).", + "operationId": "deploy_from_image_upload", + "parameters": [ + { + "description": "Tag to apply to the imported image (e.g., \"myapp:v1.0\")\nIf not provided, a unique tag will be generated", + "in": "query", + "name": "tag", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "description": "Optional HTTP health-check path override (e.g. \"/api/healthz\").\nMust start with '/'. When omitted, defaults to \"/\".", + "in": "query", + "name": "health_check_path", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "in": "path", + "name": "environment_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "202": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RemoteDeploymentResponse" + } + } + }, + "description": "Image imported and deployment started" + }, + "400": { + "description": "Invalid request or unsupported format" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Project or environment not found" + }, + "413": { + "description": "Image tarball too large" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Deploy from an uploaded Docker image tarball", + "tags": [ + "Deployments" + ] + } + }, + "/projects/{project_id}/environments/{environment_id}/deploy/source": { + "post": { + "operationId": "deploy_from_uploaded_source", + "parameters": [ + { + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "in": "path", + "name": "environment_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "$ref": "#/components/schemas/SourceArchiveUpload" + } + } + }, + "required": true + }, + "responses": { + "202": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RemoteDeploymentResponse" + } + } + }, + "description": "Source deployment started" + }, + "400": { + "description": "Invalid source archive" + }, + "404": { + "description": "Project or environment not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Upload source code and immediately start a preset-based deployment.", + "tags": [ + "Deployments" + ] + } + }, + "/projects/{project_id}/environments/{environment_id}/deploy/static": { + "post": { + "description": "Triggers a deployment using a previously uploaded static file bundle.", + "operationId": "deploy_from_static", + "parameters": [ + { + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "in": "path", + "name": "environment_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeployFromStaticRequest" + } + } + }, + "required": true + }, + "responses": { + "202": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RemoteDeploymentResponse" + } + } + }, + "description": "Deployment started" + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Project, environment, or bundle not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Deploy from an uploaded static bundle", + "tags": [ + "Deployments" + ] + } + }, + "/projects/{project_id}/error-alert-rules": { + "get": { + "operationId": "list_alert_rules", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/AlertRuleResponse" + }, + "type": "array" + } + } + }, + "description": "List of alert rules" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "List all alert rules for a project", + "tags": [ + "error-alert-rules" + ] + }, + "post": { + "operationId": "create_alert_rule", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateAlertRuleRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AlertRuleResponse" + } + } + }, + "description": "Alert rule created" + }, + "400": { + "description": "Validation error" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Create a new alert rule", + "tags": [ + "error-alert-rules" + ] + } + }, + "/projects/{project_id}/error-alert-rules/{rule_id}": { + "delete": { + "operationId": "delete_alert_rule", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Alert rule ID", + "in": "path", + "name": "rule_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "Alert rule deleted" + }, + "404": { + "description": "Alert rule not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Delete an alert rule", + "tags": [ + "error-alert-rules" + ] + }, + "get": { + "operationId": "get_alert_rule", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Alert rule ID", + "in": "path", + "name": "rule_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AlertRuleResponse" + } + } + }, + "description": "Alert rule details" + }, + "404": { + "description": "Alert rule not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Get a specific alert rule", + "tags": [ + "error-alert-rules" + ] + }, + "put": { + "operationId": "update_alert_rule", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Alert rule ID", + "in": "path", + "name": "rule_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateAlertRuleRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AlertRuleResponse" + } + } + }, + "description": "Alert rule updated" + }, + "400": { + "description": "Validation error" + }, + "404": { + "description": "Alert rule not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Update an existing alert rule", + "tags": [ + "error-alert-rules" + ] + } + }, + "/projects/{project_id}/error-dashboard-stats": { + "get": { + "operationId": "get_error_dashboard_stats", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "in": "query", + "name": "start_time", + "required": true, + "schema": { + "format": "date-time", + "type": "string" + } + }, + { + "in": "query", + "name": "end_time", + "required": true, + "schema": { + "format": "date-time", + "type": "string" + } + }, + { + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + { + "in": "query", + "name": "compare_to_previous", + "required": false, + "schema": { + "type": [ + "boolean", + "null" + ] + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDashboardStatsResponse" + } + } + }, + "description": "Error dashboard statistics" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Get error dashboard statistics", + "tags": [ + "error-tracking" + ] + } + }, + "/projects/{project_id}/error-groups": { + "get": { + "operationId": "list_error_groups", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "in": "query", + "name": "page", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + { + "in": "query", + "name": "page_size", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + { + "in": "query", + "name": "status", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + { + "in": "query", + "name": "start_date", + "required": false, + "schema": { + "format": "date-time", + "type": [ + "string", + "null" + ] + } + }, + { + "in": "query", + "name": "end_date", + "required": false, + "schema": { + "format": "date-time", + "type": [ + "string", + "null" + ] + } + }, + { + "in": "query", + "name": "sort_by", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "in": "query", + "name": "sort_order", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PaginatedErrorGroupsResponse" + } + } + }, + "description": "Paginated list of error groups" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "List error groups for a project", + "tags": [ + "error-tracking" + ] + } + }, + "/projects/{project_id}/error-groups/{group_id}": { + "get": { + "operationId": "get_error_group", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Error group ID", + "in": "path", + "name": "group_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorGroupResponse" + } + } + }, + "description": "Error group details" + }, + "404": { + "description": "Error group not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Get a specific error group", + "tags": [ + "error-tracking" + ] + }, + "put": { + "operationId": "update_error_group", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Error group ID", + "in": "path", + "name": "group_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateErrorGroupRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Error group updated successfully" + }, + "404": { + "description": "Error group not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Update error group status", + "tags": [ + "error-tracking" + ] + } + }, + "/projects/{project_id}/error-groups/{group_id}/events": { + "get": { + "operationId": "list_error_events", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Error group ID", + "in": "path", + "name": "group_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "in": "query", + "name": "page", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + { + "in": "query", + "name": "page_size", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PaginatedErrorEventsResponse" + } + } + }, + "description": "Paginated list of error events" + }, + "404": { + "description": "Error group not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "List error events for a specific group", + "tags": [ + "error-tracking" + ] + } + }, + "/projects/{project_id}/error-groups/{group_id}/events/{event_id}": { + "get": { + "operationId": "get_error_event", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Error group ID", + "in": "path", + "name": "group_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Error event ID", + "in": "path", + "name": "event_id", + "required": true, + "schema": { + "format": "int64", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorEventResponse" + } + } + }, + "description": "Error event details" + }, + "404": { + "description": "Event not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Get a specific error event", + "tags": [ + "error-tracking" + ] + } + }, + "/projects/{project_id}/error-stats": { + "get": { + "operationId": "get_error_stats", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorGroupStatsResponse" + } + } + }, + "description": "Error statistics" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Get error statistics for a project", + "tags": [ + "error-tracking" + ] + } + }, + "/projects/{project_id}/error-time-series": { + "get": { + "operationId": "get_error_time_series", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "in": "query", + "name": "start_time", + "required": true, + "schema": { + "format": "date-time", + "type": "string" + } + }, + { + "in": "query", + "name": "end_time", + "required": true, + "schema": { + "format": "date-time", + "type": "string" + } + }, + { + "description": "Time bucket size (e.g., \"1h\", \"15m\", \"1d\", \"1 hour\", \"30 minutes\")", + "in": "query", + "name": "bucket", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/ErrorTimeSeriesDataResponse" + }, + "type": "array" + } + } + }, + "description": "Error time series data" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Get error time series data for charts", + "tags": [ + "error-tracking" + ] + } + }, + "/projects/{project_id}/events": { + "get": { + "operationId": "get_events_count", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Start date for filtering events", + "in": "query", + "name": "start_date", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "End date for filtering events", + "in": "query", + "name": "end_date", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Filter by environment ID", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Maximum number of events to return (default: 20, max: 100)", + "in": "query", + "name": "limit", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Only return custom events, excluding system events like page_view, page_leave, heartbeat (default: true)", + "in": "query", + "name": "custom_events_only", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "description": "Aggregation level: events, sessions, or visitors (default: events)", + "in": "query", + "name": "aggregation_level", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/EventCount" + }, + "type": "array" + } + } + }, + "description": "Successfully retrieved event counts" + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get event counts with filtering", + "tags": [ + "Events" + ] + } + }, + "/projects/{project_id}/events/breakdown": { + "get": { + "operationId": "get_event_type_breakdown", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Start date for filtering events", + "in": "query", + "name": "start_date", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "End date for filtering events", + "in": "query", + "name": "end_date", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Filter by environment ID", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Aggregation level: events, sessions, or visitors (default: events)", + "in": "query", + "name": "aggregation_level", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/EventTypeBreakdown" + }, + "type": "array" + } + } + }, + "description": "Successfully retrieved event type breakdown" + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get event type breakdown", + "tags": [ + "Events" + ] + } + }, + "/projects/{project_id}/events/ingest": { + "post": { + "description": "The app backend forwards the user's encrypted Temps cookies, so visitor/session\nidentity is resolved automatically by middleware. No geolocation or user-agent\nenrichment is performed — this is a lightweight server-side ingestion path.", + "operationId": "record_console_event", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ConsoleEventPayload" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Event recorded successfully" + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Record an analytics event via the console API with explicit project ID.", + "tags": [ + "Events" + ] + } + }, + "/projects/{project_id}/events/properties/breakdown": { + "get": { + "operationId": "get_property_breakdown", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Start date in '%Y-%m-%d %H:%M:%S' format", + "in": "query", + "name": "start_date", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "End date in '%Y-%m-%d %H:%M:%S' format", + "in": "query", + "name": "end_date", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Column to group by (channel, device_type, browser, etc.)", + "in": "query", + "name": "group_by", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Filter by environment ID", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Filter by deployment ID", + "in": "query", + "name": "deployment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Filter by event name", + "in": "query", + "name": "event_name", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Aggregation level: events, sessions, or visitors - default: events", + "in": "query", + "name": "aggregation_level", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Maximum number of results (default: 20, max: 100)", + "in": "query", + "name": "limit", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Filter by country (for region/city drill-downs)", + "in": "query", + "name": "filter_country", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter by region (for city drill-downs)", + "in": "query", + "name": "filter_region", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter by browser name (for version drill-downs)", + "in": "query", + "name": "filter_browser", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter by OS name (for version drill-downs)", + "in": "query", + "name": "filter_os", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter by channel name (for channel drill-downs)", + "in": "query", + "name": "filter_channel", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter by referrer hostname (for referrer drill-downs)", + "in": "query", + "name": "filter_referrer", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PropertyBreakdownResponse" + } + } + }, + "description": "Successfully retrieved property breakdown" + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get property breakdown by grouping events by a column", + "tags": [ + "Events" + ] + } + }, + "/projects/{project_id}/events/properties/timeline": { + "get": { + "operationId": "get_property_timeline", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Start date in '%Y-%m-%d %H:%M:%S' format", + "in": "query", + "name": "start_date", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "End date in '%Y-%m-%d %H:%M:%S' format", + "in": "query", + "name": "end_date", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Column to group by (channel, device_type, browser, etc.)", + "in": "query", + "name": "group_by", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Filter by environment ID", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Filter by deployment ID", + "in": "query", + "name": "deployment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Filter by event name", + "in": "query", + "name": "event_name", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Aggregation level: events, sessions, or visitors - default: events", + "in": "query", + "name": "aggregation_level", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Time bucket: hour, day, week, month (default: auto-detect)", + "in": "query", + "name": "bucket_size", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PropertyTimelineResponse" + } + } + }, + "description": "Successfully retrieved property timeline" + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get property timeline by grouping events by a column over time", + "tags": [ + "Events" + ] + } + }, + "/projects/{project_id}/events/timeline": { + "get": { + "operationId": "get_events_timeline", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Start date for filtering events", + "in": "query", + "name": "start_date", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "End date for filtering events", + "in": "query", + "name": "end_date", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Filter by environment ID", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Filter by specific event name", + "in": "query", + "name": "event_name", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Bucket size: hour, day, or week (auto-detected if not specified)", + "in": "query", + "name": "bucket_size", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Aggregation level: events, sessions, or visitors (default: events)", + "in": "query", + "name": "aggregation_level", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/EventTimeline" + }, + "type": "array" + } + } + }, + "description": "Successfully retrieved events timeline" + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get events timeline", + "tags": [ + "Events" + ] + } + }, + "/projects/{project_id}/events/unique": { + "get": { + "operationId": "get_unique_events", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Page number (default: 1)", + "in": "query", + "name": "page", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + { + "description": "Items per page (default: 50, max: 100)", + "in": "query", + "name": "page_size", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EventTypesResponse" + } + } + }, + "description": "Unique event types retrieved successfully" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get all unique/distinct event types for a project (paginated)", + "tags": [ + "Funnels" + ] + } + }, + "/projects/{project_id}/external-images": { + "get": { + "operationId": "list_remote_external_images", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Page number (default: 1)", + "in": "query", + "name": "page", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + { + "description": "Items per page (default: 20)", + "in": "query", + "name": "page_size", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PaginatedExternalImagesResponse" + } + } + }, + "description": "List of external images" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List external images for a project", + "tags": [ + "External Images" + ] + }, + "post": { + "description": "Registers an external Docker image reference without triggering a deployment.\nThe image can be deployed later using the deploy/image endpoint.", + "operationId": "register_external_image", + "parameters": [ + { + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RegisterImageRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExternalImageResponse" + } + } + }, + "description": "Image registered successfully" + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Project not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Register an external Docker image", + "tags": [ + "External Images" + ] + } + }, + "/projects/{project_id}/external-images/{image_id}": { + "delete": { + "operationId": "delete_external_image", + "parameters": [ + { + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "in": "path", + "name": "image_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "Image deleted" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Image not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Delete an external image", + "tags": [ + "External Images" + ] + }, + "get": { + "operationId": "get_remote_external_image", + "parameters": [ + { + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "in": "path", + "name": "image_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExternalImageResponse" + } + } + }, + "description": "Image details" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Image not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get details of a specific external image", + "tags": [ + "External Images" + ] + } + }, + "/projects/{project_id}/flags": { + "get": { + "operationId": "list_flags", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Include archived flags. Defaults to false.", + "in": "query", + "name": "include_archived", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "description": "1-indexed page number. Defaults to 1.", + "in": "query", + "name": "page", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + } + }, + { + "description": "Items per page. Defaults to 20, capped at 100.", + "in": "query", + "name": "page_size", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FlagListResponse" + } + } + }, + "description": "Flags listed" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Feature Flags" + ] + }, + "post": { + "operationId": "create_flag", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateFlagRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FlagResponse" + } + } + }, + "description": "Flag created" + }, + "400": { + "description": "Validation error" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "409": { + "description": "Flag key already exists" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Feature Flags" + ] + } + }, + "/projects/{project_id}/flags/{key}": { + "delete": { + "operationId": "archive_flag", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Flag key", + "in": "path", + "name": "key", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ArchiveFlagResponse" + } + } + }, + "description": "Flag archived" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Flag not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Feature Flags" + ] + }, + "get": { + "operationId": "get_flag", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Flag key", + "in": "path", + "name": "key", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FlagResponse" + } + } + }, + "description": "Flag retrieved" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Flag not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Feature Flags" + ] + }, + "patch": { + "operationId": "update_flag", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Flag key", + "in": "path", + "name": "key", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateFlagRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FlagResponse" + } + } + }, + "description": "Flag updated" + }, + "400": { + "description": "Validation error" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Flag not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Feature Flags" + ] + } + }, + "/projects/{project_id}/flags/{key}/environments/{environment_id}": { + "put": { + "operationId": "set_flag_environment", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Flag key", + "in": "path", + "name": "key", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Environment ID", + "in": "path", + "name": "environment_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SetFlagEnvironmentRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FlagEnvironmentResponse" + } + } + }, + "description": "Environment value set" + }, + "400": { + "description": "Validation error" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Flag or environment not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Set a flag's value in one environment, and/or flip its kill switch.", + "tags": [ + "Feature Flags" + ] + } + }, + "/projects/{project_id}/flags/{key}/restore": { + "post": { + "description": "Archiving is otherwise one-way: the key stays reserved so the flag cannot\neven be re-created under the same name, which makes an accidental archive\nunrecoverable through the API.", + "operationId": "restore_flag", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Flag key", + "in": "path", + "name": "key", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FlagResponse" + } + } + }, + "description": "Flag restored" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Flag not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Bring an archived flag back.", + "tags": [ + "Feature Flags" + ] + } + }, + "/projects/{project_id}/funnels": { + "get": { + "operationId": "list_funnels", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/FunnelResponse" + }, + "type": "array" + } + } + }, + "description": "Funnels retrieved successfully" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List all funnels for a project", + "tags": [ + "Funnels" + ] + }, + "post": { + "operationId": "create_funnel", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateFunnelRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateFunnelResponse" + } + } + }, + "description": "Funnel created successfully" + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Create a new funnel", + "tags": [ + "Funnels" + ] + } + }, + "/projects/{project_id}/funnels/preview": { + "post": { + "operationId": "preview_funnel_metrics", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateFunnelRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FunnelMetricsResponse" + } + } + }, + "description": "Funnel metrics preview" + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Preview funnel metrics without creating the funnel", + "tags": [ + "Funnels" + ] + } + }, + "/projects/{project_id}/funnels/{funnel_id}": { + "delete": { + "operationId": "delete_funnel", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Funnel ID", + "in": "path", + "name": "funnel_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "Funnel deleted successfully" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Funnel not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Delete a funnel", + "tags": [ + "Funnels" + ] + }, + "put": { + "operationId": "update_funnel", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Funnel ID", + "in": "path", + "name": "funnel_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateFunnelRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Funnel updated successfully" + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Funnel not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Update a funnel", + "tags": [ + "Funnels" + ] + } + }, + "/projects/{project_id}/funnels/{funnel_id}/metrics": { + "get": { + "operationId": "get_funnel_metrics", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Funnel ID", + "in": "path", + "name": "funnel_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment ID filter", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Country code filter", + "in": "query", + "name": "country_code", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Start date filter (ISO 8601)", + "in": "query", + "name": "start_date", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "End date filter (ISO 8601)", + "in": "query", + "name": "end_date", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FunnelMetricsResponse" + } + } + }, + "description": "Funnel metrics retrieved successfully" + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Funnel not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get funnel metrics", + "tags": [ + "Funnels" + ] + } + }, + "/projects/{project_id}/git": { + "post": { + "operationId": "update_git_settings", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateGitSettingsRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProjectResponse" + } + } + }, + "description": "Git settings updated successfully" + }, + "400": { + "description": "Invalid git configuration or branch does not exist" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Project not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Update git settings for a project", + "tags": [ + "Projects" + ] + } + }, + "/projects/{project_id}/gitlab/reinstall-webhook": { + "post": { + "description": "Removes the existing webhook (if any) and installs a fresh one.\nUse this when a webhook has been manually deleted on the GitLab side\nand automatic deployments have stopped working.", + "operationId": "reinstall_gitlab_webhook", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ReinstallWebhookResponse" + } + } + }, + "description": "Webhook reinstalled" + }, + "400": { + "description": "Project is not connected to a GitLab repository" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Project not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Reinstall the GitLab webhook for a project", + "tags": [ + "Projects" + ] + } + }, + "/projects/{project_id}/has-error-groups": { + "get": { + "operationId": "has_error_groups", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HasErrorGroupsResponse" + } + } + }, + "description": "Error groups existence check" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Check if project has any error groups", + "tags": [ + "error-tracking" + ] + } + }, + "/projects/{project_id}/has-events": { + "get": { + "operationId": "has_analytics_events", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HasEventsResponse" + } + } + }, + "description": "Successfully checked for events" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Check if project has any analytics events", + "tags": [ + "Events" + ] + } + }, + "/projects/{project_id}/hourly-visits": { + "get": { + "operationId": "get_hourly_visits", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Start date for filtering visits", + "in": "query", + "name": "start_date", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "End date for filtering visits", + "in": "query", + "name": "end_date", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Filter by environment ID", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Aggregation level: events (page views), sessions (unique sessions), or visitors (unique visitors) - default: events", + "in": "query", + "name": "aggregation_level", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/EventTimeline" + }, + "type": "array" + } + } + }, + "description": "Successfully retrieved hourly visits" + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get hourly visits", + "tags": [ + "Events" + ] + } + }, + "/projects/{project_id}/images": { + "get": { + "operationId": "list_external_images", + "parameters": [ + { + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/PushedExternalImageResponse" + }, + "type": "array" + } + } + }, + "description": "List of external images" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List all external images for a project", + "tags": [ + "External Images" + ] + } + }, + "/projects/{project_id}/images/push": { + "post": { + "operationId": "push_external_image", + "parameters": [ + { + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PushImageRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PushedExternalImageResponse" + } + } + }, + "description": "Image pushed successfully" + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Push an external Docker image", + "tags": [ + "External Images" + ] + } + }, + "/projects/{project_id}/images/{image_id}": { + "get": { + "operationId": "get_external_image", + "parameters": [ + { + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "in": "path", + "name": "image_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PushedExternalImageResponse" + } + } + }, + "description": "Image details" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Image not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get details of a specific external image", + "tags": [ + "External Images" + ] + } + }, + "/projects/{project_id}/incidents": { + "get": { + "operationId": "list_incidents", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Filter by environment ID", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Filter by status", + "in": "query", + "name": "status", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Page number", + "in": "query", + "name": "page", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + { + "description": "Items per page", + "in": "query", + "name": "page_size", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved incidents" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List incidents for a project", + "tags": [ + "Status Page" + ] + }, + "post": { + "operationId": "create_incident", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateIncidentRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IncidentResponse" + } + } + }, + "description": "Incident created successfully" + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Create a new incident", + "tags": [ + "Status Page" + ] + } + }, + "/projects/{project_id}/incidents/bucketed": { + "get": { + "operationId": "get_bucketed_incidents", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Filter by environment ID", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Bucket interval: '5min', 'hourly', or 'daily' (default: hourly)", + "in": "query", + "name": "interval", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Start time (ISO 8601) (default: 7 days ago)", + "in": "query", + "name": "start_time", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "End time (ISO 8601) (default: now)", + "in": "query", + "name": "end_time", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IncidentBucketedResponse" + } + } + }, + "description": "Successfully retrieved bucketed incident data" + }, + "400": { + "description": "Invalid parameters" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get bucketed incident data for a project", + "tags": [ + "Status Page" + ] + } + }, + "/projects/{project_id}/logs": { + "delete": { + "operationId": "purge_project_logs", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PurgeLogsRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Purge completed" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Invalid parameters" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Purge all logs for a project before a given timestamp", + "tags": [ + "Logs" + ] + } + }, + "/projects/{project_id}/mcp-servers": { + "get": { + "operationId": "list_mcps", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListMcpsResponse" + } + } + }, + "description": "" + }, + "401": { + "description": "Unauthorized" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Agents" + ] + }, + "post": { + "operationId": "create_mcp", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateMcpRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/McpDefinitionResponse" + } + } + }, + "description": "" + }, + "401": { + "description": "Unauthorized" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Agents" + ] + } + }, + "/projects/{project_id}/mcp-servers/{slug}": { + "delete": { + "operationId": "delete_mcp", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "MCP server slug", + "in": "path", + "name": "slug", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "MCP server deleted" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "MCP server not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Agents" + ] + }, + "get": { + "operationId": "get_mcp", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "MCP server slug", + "in": "path", + "name": "slug", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/McpDefinitionResponse" + } + } + }, + "description": "" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "MCP server not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Agents" + ] + }, + "put": { + "operationId": "update_mcp", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "MCP server slug", + "in": "path", + "name": "slug", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateMcpRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/McpDefinitionResponse" + } + } + }, + "description": "" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "MCP server not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Agents" + ] + } + }, + "/projects/{project_id}/mcp-servers/{slug}/config/{field}": { + "get": { + "operationId": "reveal_mcp_config", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "MCP server slug", + "in": "path", + "name": "slug", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Sensitive field path, such as url or env.API_TOKEN", + "in": "path", + "name": "field", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SensitiveMcpConfigValueResponse" + } + } + }, + "description": "" + }, + "400": { + "description": "Field is not revealable" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Missing secrets:read permission" + }, + "404": { + "description": "MCP server or field not found" + }, + "500": { + "description": "Configuration read or audit failed" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Agents" + ] + } + }, + "/projects/{project_id}/monitors": { + "get": { + "operationId": "list_monitors", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Filter by environment ID", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/MonitorResponse" + }, + "type": "array" + } + } + }, + "description": "Successfully retrieved monitors" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List monitors for a project", + "tags": [ + "Status Page" + ] + }, + "post": { + "operationId": "create_monitor", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateMonitorRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MonitorResponse" + } + } + }, + "description": "Monitor created successfully" + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Create a new monitor", + "tags": [ + "Status Page" + ] + } + }, + "/projects/{project_id}/observe/events": { + "get": { + "description": "Each row carries everything the side panel needs to render — no\nfollow-up fetch is required for the common case. Heavy fields\n(stacktraces, headers, span attributes) are truncated server-side and\nexpose a `*_truncated` flag; clients fetch the full row from the\n`/full` endpoint only when the user explicitly clicks \"Show full\".", + "operationId": "observability_list_events", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Comma-separated kinds: `log,request,span,error,revenue`. Empty or\nmissing returns every kind.", + "in": "query", + "name": "kinds", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Inclusive lower bound on event timestamp (ISO 8601, `Z` suffix).", + "in": "query", + "name": "from", + "required": false, + "schema": { + "format": "date-time", + "type": "string" + } + }, + { + "description": "Inclusive upper bound on event timestamp.", + "in": "query", + "name": "to", + "required": false, + "schema": { + "format": "date-time", + "type": "string" + } + }, + { + "in": "query", + "name": "deployment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Free-text substring matched against per-kind summary fields\n(request path / error class / revenue event_type).", + "in": "query", + "name": "search", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Page size (default 50, max 200).", + "in": "query", + "name": "limit", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + { + "description": "When `true`, exclude bot/crawler request rows. When `false`, only\ninclude bot rows. Omitted means \"include everything\" (default).\nOnly affects the `Request` kind.", + "in": "query", + "name": "hide_bots", + "required": false, + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EventsResponse" + } + } + }, + "description": "Merged event page" + }, + "400": { + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + }, + "description": "Invalid filter (kinds, time range, …)" + }, + "401": { + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + }, + "description": "Insufficient permissions" + }, + "500": { + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List a merged page of observability events for a project.", + "tags": [ + "Observability" + ] + } + }, + "/projects/{project_id}/observe/events/{kind}/{event_id}/full": { + "get": { + "operationId": "observability_full_event", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Event kind discriminator", + "in": "path", + "name": "kind", + "required": true, + "schema": { + "$ref": "#/components/schemas/EventKind" + } + }, + { + "description": "Per-kind identity: request_id for requests, `{trace_id}:{span_id}` for spans, serial id for errors/revenue", + "in": "path", + "name": "event_id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "The row's event timestamp as returned by the list endpoint. Optional,\nbut strongly recommended: it bounds the lookup to the storage\npartitions/chunks around that instant instead of scanning the whole\nretention window.", + "in": "query", + "name": "ts", + "required": false, + "schema": { + "format": "date-time", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FullEvent" + } + } + }, + "description": "Full row" + }, + "401": { + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + }, + "description": "Insufficient permissions" + }, + "404": { + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + }, + "description": "Event not found in project" + }, + "500": { + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Fetch the un-truncated form of one event by `(kind, id)`. Side panel\n\"Show full\" action calls this — the list response carries truncated\npreviews + a `*_truncated` flag to let the UI decide whether to fetch.", + "tags": [ + "Observability" + ] + } + }, + "/projects/{project_id}/releases/{release}/source-files": { + "delete": { + "operationId": "delete_release_source_files", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Release version", + "in": "path", + "name": "release", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeleteResponse" + } + } + }, + "description": "Source files deleted" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Delete all uploaded source files for a release.", + "tags": [ + "source-maps" + ] + }, + "get": { + "operationId": "list_source_files", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Release version", + "in": "path", + "name": "release", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SourceFileListResponse" + } + } + }, + "description": "List of source files" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List uploaded source files for a release (metadata only).", + "tags": [ + "source-maps" + ] + }, + "post": { + "description": "Accepts a multipart form with:\n- `file`: the source file bytes (required)\n- `file_path`: the path of the file as it appears in stack frames (required;\n derived from the uploaded filename if omitted). Normalized with the `~`\n prefix convention, matching source-map storage.\n\nRequires the project's `error_source_context_enabled` toggle to be on.\nUpserts on (project, release, file_path).", + "operationId": "upload_source_file", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Release version", + "in": "path", + "name": "release", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SourceFileResponse" + } + } + }, + "description": "Source file uploaded" + }, + "400": { + "description": "Missing fields" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "409": { + "description": "Source context disabled for project" + }, + "413": { + "description": "Source file too large" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Upload a raw source file for a release (native symbolication).", + "tags": [ + "source-maps" + ] + } + }, + "/projects/{project_id}/releases/{release}/source-maps": { + "delete": { + "operationId": "delete_release_source_maps", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Release version", + "in": "path", + "name": "release", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeleteResponse" + } + } + }, + "description": "Source maps deleted" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Delete all source maps for a specific release", + "tags": [ + "source-maps" + ] + }, + "get": { + "operationId": "list_source_maps", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Release version", + "in": "path", + "name": "release", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SourceMapListResponse" + } + } + }, + "description": "List of source maps" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List all source maps for a specific release", + "tags": [ + "source-maps" + ] + }, + "post": { + "description": "Accepts a multipart form with:\n- `file`: The .map file (required)\n- `file_path`: The URL path of the minified file as it appears in stack traces (required).\n Uses the ~ prefix convention (e.g., \"~/assets/main.js\").\n If a full URL is provided, it will be normalized automatically.\n- `dist`: Optional distribution identifier\n\nIf a source map already exists for the same (project, release, file_path), it is replaced.", + "operationId": "upload_source_map", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Release version", + "in": "path", + "name": "release", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SourceMapResponse" + } + } + }, + "description": "Source map uploaded" + }, + "400": { + "description": "Invalid source map or missing fields" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "413": { + "description": "Source map too large" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Upload a source map for a release.", + "tags": [ + "source-maps" + ] + } + }, + "/projects/{project_id}/revenue/events": { + "get": { + "operationId": "revenue_recent_events", + "parameters": [ + { + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/RecentEventResponse" + }, + "type": "array" + } + } + }, + "description": "" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Recent ingested events for the activity feed.", + "tags": [ + "Revenue" + ] + } + }, + "/projects/{project_id}/revenue/integrations": { + "get": { + "operationId": "revenue_list_integrations", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/IntegrationResponse" + }, + "type": "array" + } + } + }, + "description": "" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List revenue integrations for a project.", + "tags": [ + "Revenue" + ] + }, + "post": { + "operationId": "revenue_create_integration", + "parameters": [ + { + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateIntegrationBody" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IntegrationResponse" + } + } + }, + "description": "" + }, + "400": { + "description": "Validation error" + }, + "409": { + "description": "Already connected" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Create a new revenue integration. Response contains the generated\nwebhook path that the user must paste into their provider's dashboard.", + "tags": [ + "Revenue" + ] + } + }, + "/projects/{project_id}/revenue/integrations/{integration_id}": { + "delete": { + "operationId": "revenue_delete_integration", + "parameters": [ + { + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "in": "path", + "name": "integration_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Delete a revenue integration (permanent — use rotate_token to refresh\ncredentials without breaking history).", + "tags": [ + "Revenue" + ] + } + }, + "/projects/{project_id}/revenue/integrations/{integration_id}/config": { + "post": { + "operationId": "revenue_update_config", + "parameters": [ + { + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "in": "path", + "name": "integration_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateConfigBody" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IntegrationResponse" + } + } + }, + "description": "" + }, + "400": { + "description": "Validation error" + }, + "404": { + "description": "Integration not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Replace the typed provider config on an integration. Passing `null`\nclears the config back to the accept-everything default. The config's\nprovider tag must match the integration's provider.", + "tags": [ + "Revenue" + ] + } + }, + "/projects/{project_id}/revenue/integrations/{integration_id}/import/invoices": { + "post": { + "operationId": "revenue_import_invoices_csv", + "parameters": [ + { + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "in": "path", + "name": "integration_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ImportOutcomeResponse" + } + } + }, + "description": "" + }, + "400": { + "description": "Malformed CSV or wrong provider" + }, + "404": { + "description": "Integration not found" + }, + "413": { + "description": "CSV too large" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Import a Stripe invoices CSV export. Each paid invoice becomes an\n`invoice.paid` event so historical MRR/charge totals populate the\ntimeseries. Ingestion is idempotent: re-uploading the same file is a\nno-op.", + "tags": [ + "Revenue" + ] + } + }, + "/projects/{project_id}/revenue/integrations/{integration_id}/import/subscriptions": { + "post": { + "operationId": "revenue_import_subscriptions_csv", + "parameters": [ + { + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "in": "path", + "name": "integration_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ImportOutcomeResponse" + } + } + }, + "description": "" + }, + "400": { + "description": "Malformed CSV or wrong provider" + }, + "404": { + "description": "Integration not found" + }, + "413": { + "description": "CSV too large" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Import a Stripe subscriptions CSV export. Use this to backfill MRR /\nactive subscriptions when migrating from Stripe without providing\nAPI keys. Webhooks remain the source of truth for live updates —\nCSV rows never overwrite newer webhook state.", + "tags": [ + "Revenue" + ] + } + }, + "/projects/{project_id}/revenue/integrations/{integration_id}/rotate-token": { + "post": { + "operationId": "revenue_rotate_token", + "parameters": [ + { + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "in": "path", + "name": "integration_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IntegrationResponse" + } + } + }, + "description": "" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Rotate the webhook path token. Returns the new integration state —\nthe user must paste the new URL into their provider's dashboard.", + "tags": [ + "Revenue" + ] + } + }, + "/projects/{project_id}/revenue/integrations/{integration_id}/update-secret": { + "post": { + "operationId": "revenue_update_secret", + "parameters": [ + { + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "in": "path", + "name": "integration_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateSecretBody" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IntegrationResponse" + } + } + }, + "description": "" + }, + "400": { + "description": "Validation error" + }, + "404": { + "description": "Integration not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Replace the stored signing secret without rotating the webhook URL.\nUse this after rotating the secret in the provider's dashboard.", + "tags": [ + "Revenue" + ] + } + }, + "/projects/{project_id}/revenue/metrics/customers": { + "get": { + "operationId": "revenue_metrics_customers", + "parameters": [ + { + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/CustomerMovementResponse" + }, + "type": "array" + } + } + }, + "description": "" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "New + churned customers per bucket.", + "tags": [ + "Revenue" + ] + } + }, + "/projects/{project_id}/revenue/metrics/mrr": { + "get": { + "operationId": "revenue_metrics_mrr", + "parameters": [ + { + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/MrrBucketResponse" + }, + "type": "array" + } + } + }, + "description": "" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Bucketed MRR timeseries for the revenue chart.", + "tags": [ + "Revenue" + ] + } + }, + "/projects/{project_id}/revenue/metrics/summary": { + "get": { + "operationId": "revenue_metrics_summary", + "parameters": [ + { + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MetricsSummaryResponse" + } + } + }, + "description": "" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Current MRR / ARR / churn / ARPU for a project, in one currency.", + "tags": [ + "Revenue" + ] + } + }, + "/projects/{project_id}/secrets": { + "get": { + "operationId": "listProjectSecrets", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Optional environment filter", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/ProjectSecretResponse" + }, + "type": "array" + } + } + }, + "description": "List of secrets (metadata only, no values)" + }, + "404": { + "description": "Project not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "List project secrets (metadata only — values never returned).", + "tags": [ + "Secrets" + ] + }, + "post": { + "operationId": "createProjectSecret", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateProjectSecretRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProjectSecretResponse" + } + } + }, + "description": "Secret created" + }, + "400": { + "description": "Invalid key or value too large" + }, + "409": { + "description": "Key already exists in project" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Create a new secret. The value is encrypted before storage and will be\nmounted as a file at `/run/secrets/` on the next deployment.\nThe plaintext value is NOT returned — the response carries only metadata.", + "tags": [ + "Secrets" + ] + } + }, + "/projects/{project_id}/secrets/{secret_id}": { + "delete": { + "operationId": "deleteProjectSecret", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Secret ID", + "in": "path", + "name": "secret_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "Secret deleted" + }, + "404": { + "description": "Secret not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Delete a project secret. Running containers keep their mounted secret files\nuntil they are redeployed.", + "tags": [ + "Secrets" + ] + }, + "put": { + "operationId": "updateProjectSecret", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Secret ID", + "in": "path", + "name": "secret_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateProjectSecretRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProjectSecretResponse" + } + } + }, + "description": "Secret updated" + }, + "400": { + "description": "Value too large" + }, + "404": { + "description": "Secret not found" + }, + "500": { + "description": "Internal server error" + } + }, + "summary": "Update a project secret. Value rotation requires a redeploy to take effect —\nrunning containers keep their currently-mounted values until the next\ndeployment.", + "tags": [ + "Secrets" + ] + } + }, + "/projects/{project_id}/settings": { + "post": { + "operationId": "update_project_settings", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateProjectSettingsRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProjectResponse" + } + } + }, + "description": "Project settings updated successfully" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Project not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Update project settings", + "tags": [ + "Projects" + ] + } + }, + "/projects/{project_id}/skills": { + "get": { + "operationId": "list_skills", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListSkillsResponse" + } + } + }, + "description": "" + }, + "401": { + "description": "Unauthorized" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Agents" + ] + }, + "post": { + "operationId": "create_skill", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateSkillRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SkillDefinitionResponse" + } + } + }, + "description": "" + }, + "401": { + "description": "Unauthorized" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Agents" + ] + } + }, + "/projects/{project_id}/skills/upload": { + "post": { + "operationId": "upload_skill", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "type": "string" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SkillDefinitionResponse" + } + } + }, + "description": "" + }, + "401": { + "description": "Unauthorized" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Upload a skill with an archive (tar.gz) — project-scoped.", + "tags": [ + "Agents" + ] + } + }, + "/projects/{project_id}/skills/{slug}": { + "delete": { + "operationId": "delete_skill", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Skill slug", + "in": "path", + "name": "slug", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Skill deleted" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Skill not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Agents" + ] + }, + "get": { + "operationId": "get_skill", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Skill slug", + "in": "path", + "name": "slug", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SkillDefinitionResponse" + } + } + }, + "description": "" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Skill not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Agents" + ] + }, + "put": { + "operationId": "update_skill", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Skill slug", + "in": "path", + "name": "slug", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateSkillRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SkillDefinitionResponse" + } + } + }, + "description": "" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Skill not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Agents" + ] + } + }, + "/projects/{project_id}/skills/{slug}/archive": { + "get": { + "operationId": "download_skill_archive", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Skill slug", + "in": "path", + "name": "slug", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/gzip": {} + }, + "description": "Skill archive tar.gz" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Skill not found or has no archive" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Download a skill's archive (tar.gz) — project-scoped.", + "tags": [ + "Agents" + ] + } + }, + "/projects/{project_id}/source-map-releases": { + "get": { + "operationId": "list_releases", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ReleaseListResponse" + } + } + }, + "description": "List of releases" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List all releases that have source maps for a project", + "tags": [ + "source-maps" + ] + } + }, + "/projects/{project_id}/source-maps/{source_map_id}": { + "delete": { + "operationId": "delete_source_map", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Source map ID", + "in": "path", + "name": "source_map_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "Source map deleted" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Source map not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Delete a specific source map by ID", + "tags": [ + "source-maps" + ] + } + }, + "/projects/{project_id}/static-bundles": { + "get": { + "operationId": "list_static_bundles", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Page number (default: 1)", + "in": "query", + "name": "page", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + { + "description": "Items per page (default: 20)", + "in": "query", + "name": "page_size", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PaginatedStaticBundlesResponse" + } + } + }, + "description": "List of static bundles" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List static bundles for a project", + "tags": [ + "Static Bundles" + ] + } + }, + "/projects/{project_id}/static-bundles/{bundle_id}": { + "delete": { + "operationId": "delete_static_bundle", + "parameters": [ + { + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "in": "path", + "name": "bundle_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "Bundle deleted" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Bundle not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Delete a static bundle", + "tags": [ + "Static Bundles" + ] + }, + "get": { + "operationId": "get_static_bundle", + "parameters": [ + { + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "in": "path", + "name": "bundle_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StaticBundleResponse" + } + } + }, + "description": "Bundle details" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Bundle not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get details of a specific static bundle", + "tags": [ + "Static Bundles" + ] + } + }, + "/projects/{project_id}/status": { + "get": { + "operationId": "get_status_overview", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Filter by environment ID", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StatusPageOverview" + } + } + }, + "description": "Successfully retrieved status overview" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get status page overview", + "tags": [ + "Status Page" + ] + } + }, + "/projects/{project_id}/unique-counts": { + "get": { + "operationId": "get_unique_counts", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Start date in '%Y-%m-%d %H:%M:%S' format", + "in": "query", + "name": "start_date", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "End date in '%Y-%m-%d %H:%M:%S' format", + "in": "query", + "name": "end_date", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Filter by environment ID", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Filter by deployment ID", + "in": "query", + "name": "deployment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Metric to count: 'sessions' (unique sessions), 'visitors' (unique visitors), 'returning_visitors' (visitors seen before the range), or 'page_views' (total page views) (default: 'sessions')", + "in": "query", + "name": "metric", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UniqueCountsResponse" + } + } + }, + "description": "Successfully retrieved count" + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get unique counts over time frame", + "tags": [ + "Events" + ] + } + }, + "/projects/{project_id}/upload/static": { + "post": { + "description": "Uploads a tar.gz or zip file containing static assets. The bundle can be\ndeployed later using the deploy/static endpoint.", + "operationId": "upload_static_bundle", + "parameters": [ + { + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StaticBundleResponse" + } + } + }, + "description": "Bundle uploaded successfully" + }, + "400": { + "description": "Invalid request or unsupported format" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Project not found" + }, + "413": { + "description": "Bundle too large" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Upload a static bundle for later deployment", + "tags": [ + "Static Bundles" + ] + } + }, + "/projects/{project_id}/vulnerability-scans": { + "get": { + "operationId": "list_project_scans", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Page number (default: 1)", + "in": "query", + "name": "page", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + { + "description": "Page size (default: 20, max: 100)", + "in": "query", + "name": "page_size", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/ScanResponse" + }, + "type": "array" + } + } + }, + "description": "List of vulnerability scans" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Vulnerability Scans" + ] + }, + "post": { + "operationId": "trigger_scan", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TriggerScanRequest" + } + } + }, + "required": true + }, + "responses": { + "202": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TriggerScanResponse" + } + } + }, + "description": "Scan triggered successfully" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Invalid request" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Vulnerability Scans" + ] + } + }, + "/projects/{project_id}/vulnerability-scans/environments": { + "get": { + "operationId": "get_latest_scans_per_environment", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/ScanResponse" + }, + "type": "array" + } + } + }, + "description": "Latest scans per environment for current deployments" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Vulnerability Scans" + ] + } + }, + "/projects/{project_id}/vulnerability-scans/latest": { + "get": { + "operationId": "get_latest_scan", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Filter by environment ID", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ScanResponse" + } + } + }, + "description": "Latest scan for project" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "No scans found" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Vulnerability Scans" + ] + } + }, + "/projects/{project_id}/webhooks": { + "get": { + "operationId": "list_webhooks", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Page number (1-indexed)", + "example": 1, + "in": "query", + "name": "page", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + } + }, + { + "description": "Number of items per page (max 100)", + "example": 20, + "in": "query", + "name": "page_size", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + } + }, + { + "in": "query", + "name": "sort_by", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "in": "query", + "name": "sort_order", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/WebhookResponse" + }, + "type": "array" + } + } + }, + "description": "List of webhooks" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List all webhooks for a project", + "tags": [ + "Webhooks" + ] + }, + "post": { + "operationId": "create_webhook", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateWebhookRequestBody" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WebhookResponse" + } + } + }, + "description": "Webhook created" + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Create a new webhook", + "tags": [ + "Webhooks" + ] + } + }, + "/projects/{project_id}/webhooks/{webhook_id}": { + "delete": { + "operationId": "delete_webhook", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Webhook ID", + "in": "path", + "name": "webhook_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "Webhook deleted" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Webhook not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Delete a webhook", + "tags": [ + "Webhooks" + ] + }, + "get": { + "operationId": "get_webhook", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Webhook ID", + "in": "path", + "name": "webhook_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WebhookResponse" + } + } + }, + "description": "Webhook details" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Webhook not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get a specific webhook", + "tags": [ + "Webhooks" + ] + }, + "put": { + "operationId": "update_webhook", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Webhook ID", + "in": "path", + "name": "webhook_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateWebhookRequestBody" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WebhookResponse" + } + } + }, + "description": "Webhook updated" + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Webhook not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Update a webhook", + "tags": [ + "Webhooks" + ] + } + }, + "/projects/{project_id}/webhooks/{webhook_id}/deliveries": { + "get": { + "operationId": "list_deliveries", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Webhook ID", + "in": "path", + "name": "webhook_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Number of deliveries to return (default: 50)", + "in": "query", + "name": "limit", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/WebhookDeliveryResponse" + }, + "type": "array" + } + } + }, + "description": "List of deliveries" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List webhook deliveries", + "tags": [ + "Webhook Deliveries" + ] + } + }, + "/projects/{project_id}/webhooks/{webhook_id}/deliveries/{delivery_id}": { + "get": { + "operationId": "get_delivery", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Webhook ID", + "in": "path", + "name": "webhook_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Delivery ID", + "in": "path", + "name": "delivery_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WebhookDeliveryResponse" + } + } + }, + "description": "Delivery details including full payload" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Delivery not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get a specific webhook delivery by ID", + "tags": [ + "Webhook Deliveries" + ] + } + }, + "/projects/{project_id}/webhooks/{webhook_id}/deliveries/{delivery_id}/retry": { + "post": { + "operationId": "retry_delivery", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Webhook ID", + "in": "path", + "name": "webhook_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Delivery ID", + "in": "path", + "name": "delivery_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WebhookDeliveryResponse" + } + } + }, + "description": "Delivery retried" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Delivery not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Retry a failed delivery", + "tags": [ + "Webhook Deliveries" + ] + } + }, + "/projects/{project_id}/workflows/dry-run": { + "post": { + "operationId": "workflow_dry_run", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WorkflowDryRunRequest" + } + } + }, + "required": true + }, + "responses": { + "202": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AgentRunResponse" + } + } + }, + "description": "Ephemeral run created and queued" + }, + "400": { + "description": "Validation error (bad YAML, oversized payload, capped limits exceeded)" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Project not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Workflows" + ] + } + }, + "/proxy-logs": { + "get": { + "operationId": "get_proxy_logs", + "parameters": [ + { + "description": "Filter by project ID", + "in": "query", + "name": "project_id", + "required": false, + "schema": { + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + { + "description": "Filter by environment ID", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + { + "description": "Filter by deployment ID", + "in": "query", + "name": "deployment_id", + "required": false, + "schema": { + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + { + "description": "Filter by session ID", + "in": "query", + "name": "session_id", + "required": false, + "schema": { + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + { + "description": "Filter by visitor ID", + "in": "query", + "name": "visitor_id", + "required": false, + "schema": { + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + { + "description": "Start date for filtering (ISO 8601 format).\n\n**Defaults to 1 hour before `end_date` (or before now) when omitted.**\nThe listing is always time-bounded: an unbounded query would have to\nconsider the entire retention window — 100M+ rows on a busy deployment —\nto return a single page. Pass an explicit `start_date` to widen the\nwindow, up to the configured retention horizon.\n\nThe maximum span between `start_date` and `end_date` is 7 days when\n`project_id` is omitted, or 30 days when a single `project_id` is set —\na project-scoped query is bounded by that project's own row count\nrather than the whole deployment's. A wider request is rejected with a\n400 naming the applicable cap.", + "in": "query", + "name": "start_date", + "required": false, + "schema": { + "format": "date-time", + "type": [ + "string", + "null" + ] + } + }, + { + "description": "End date for filtering (ISO 8601 format). Defaults to now.", + "in": "query", + "name": "end_date", + "required": false, + "schema": { + "format": "date-time", + "type": [ + "string", + "null" + ] + } + }, + { + "description": "Filter by HTTP method (GET, POST, etc.)", + "in": "query", + "name": "method", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "description": "Filter by host header", + "in": "query", + "name": "host", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "description": "Filter by path (supports partial match)", + "in": "query", + "name": "path", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "description": "Filter by client IP address", + "in": "query", + "name": "client_ip", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "description": "Filter by HTTP status code", + "in": "query", + "name": "status_code", + "required": false, + "schema": { + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + { + "description": "Filter by minimum response time in ms", + "in": "query", + "name": "response_time_min", + "required": false, + "schema": { + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + { + "description": "Filter by maximum response time in ms", + "in": "query", + "name": "response_time_max", + "required": false, + "schema": { + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + { + "description": "Filter by routing status (routed, no_project, error, pending)", + "in": "query", + "name": "routing_status", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "description": "Filter by request source (proxy, api, console, cli)", + "in": "query", + "name": "request_source", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "description": "Filter by system request flag", + "in": "query", + "name": "is_system_request", + "required": false, + "schema": { + "type": [ + "boolean", + "null" + ] + } + }, + { + "description": "Filter by user agent string (partial match)", + "in": "query", + "name": "user_agent", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "description": "Filter by browser name", + "in": "query", + "name": "browser", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "description": "Filter by operating system", + "in": "query", + "name": "operating_system", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "description": "Filter by device type (mobile, desktop, tablet)", + "in": "query", + "name": "device_type", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "description": "Filter by bot detection", + "in": "query", + "name": "is_bot", + "required": false, + "schema": { + "type": [ + "boolean", + "null" + ] + } + }, + { + "description": "When `true`, exclude rows flagged as bots while KEEPING rows whose\n`is_bot` is NULL (older rows without detection metadata). This is the\ntri-state complement of `is_bot=false`, which matches only rows\nexplicitly detected as non-bots. `false`/omitted is a no-op.", + "in": "query", + "name": "exclude_bots", + "required": false, + "schema": { + "type": [ + "boolean", + "null" + ] + } + }, + { + "description": "Filter by bot name", + "in": "query", + "name": "bot_name", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "description": "Filter by AI provider (e.g. `OpenAI`, `Anthropic`, `Perplexity`). Matches\nthe canonical provider returned by the AI agent detector.", + "in": "query", + "name": "ai_provider", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "description": "Filter by AI agent name (e.g. `GPTBot`, `ChatGPT-User`). Equivalent to\nfiltering `bot_name` against a known AI taxonomy.", + "in": "query", + "name": "ai_agent", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "description": "When `true`, only return requests classified as known AI agents\n(regardless of provider/agent). Mutually compatible with the above.", + "in": "query", + "name": "is_ai_agent", + "required": false, + "schema": { + "type": [ + "boolean", + "null" + ] + } + }, + { + "description": "Filter by minimum request size in bytes", + "in": "query", + "name": "request_size_min", + "required": false, + "schema": { + "format": "int64", + "type": [ + "integer", + "null" + ] + } + }, + { + "description": "Filter by maximum request size in bytes", + "in": "query", + "name": "request_size_max", + "required": false, + "schema": { + "format": "int64", + "type": [ + "integer", + "null" + ] + } + }, + { + "description": "Filter by minimum response size in bytes", + "in": "query", + "name": "response_size_min", + "required": false, + "schema": { + "format": "int64", + "type": [ + "integer", + "null" + ] + } + }, + { + "description": "Filter by maximum response size in bytes", + "in": "query", + "name": "response_size_max", + "required": false, + "schema": { + "format": "int64", + "type": [ + "integer", + "null" + ] + } + }, + { + "description": "Filter by cache status", + "in": "query", + "name": "cache_status", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "description": "Filter by container ID", + "in": "query", + "name": "container_id", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "description": "Filter by upstream host", + "in": "query", + "name": "upstream_host", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "description": "Filter by presence of error message", + "in": "query", + "name": "has_error", + "required": false, + "schema": { + "type": [ + "boolean", + "null" + ] + } + }, + { + "description": "Page number (default: 1)", + "in": "query", + "name": "page", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + } + }, + { + "description": "Page size (default: 20, max: 100)", + "in": "query", + "name": "page_size", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + } + }, + { + "description": "Sort by field (default: timestamp)", + "in": "query", + "name": "sort_by", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "description": "Sort order (asc or desc, default: desc)", + "in": "query", + "name": "sort_order", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProxyLogsPaginatedResponse" + } + } + }, + "description": "List of proxy logs" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get proxy logs with optional filters and pagination", + "tags": [ + "Proxy Logs" + ] + } + }, + "/proxy-logs/ai-agents/known": { + "get": { + "description": "Returned in the same order as the internal taxonomy so the UI can use it as\na stable dropdown.", + "operationId": "list_known_ai_agents", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/KnownAiAgentsResponse" + } + } + }, + "description": "Known AI agents" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List every AI agent the detector knows how to classify.", + "tags": [ + "Proxy Logs" + ] + } + }, + "/proxy-logs/request/{request_id}": { + "get": { + "operationId": "get_proxy_log_by_request_id", + "parameters": [ + { + "description": "Request ID from pingora", + "in": "path", + "name": "request_id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Event time of the log row (ISO 8601). When provided, the lookup is\nbounded to the hypertable chunks around this instant instead of\nscanning (and decompressing) the whole retention window. The list\nendpoint already returns this value per row — always pass it when\nnavigating from a list.", + "in": "query", + "name": "timestamp", + "required": false, + "schema": { + "format": "date-time", + "type": [ + "string", + "null" + ] + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProxyLogResponse" + } + } + }, + "description": "Proxy log found" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Proxy log not found" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get a proxy log by request ID (for tracing)", + "tags": [ + "Proxy Logs" + ] + } + }, + "/proxy-logs/stats/ai-agent-pages": { + "get": { + "description": "Returns page paths ranked by request count, scoped to a single canonical\nagent name (e.g. `ChatGPT-User`). Use `GET /proxy-logs/ai-agents/known` to\nlist all valid agent names. Unknown agent names return an empty items array.", + "operationId": "get_ai_agent_pages", + "parameters": [ + { + "description": "Canonical agent name to filter by (e.g. `ChatGPT-User`, `ClaudeBot`).\nMust be a name returned by `GET /proxy-logs/ai-agents/known`.", + "in": "query", + "name": "agent", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Filter by project ID.", + "in": "query", + "name": "project_id", + "required": false, + "schema": { + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + { + "description": "Filter by environment ID.", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + { + "description": "Start time (ISO 8601). Defaults to `end_time - 7d`.", + "example": "2026-05-22T00:00:00Z", + "in": "query", + "name": "start_time", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "description": "End time (ISO 8601). Defaults to now.", + "example": "2026-05-29T00:00:00Z", + "in": "query", + "name": "end_time", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "description": "Maximum rows to return. Capped at 100 server-side.", + "in": "query", + "name": "limit", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiAgentPagesResponse" + } + } + }, + "description": "Pages breakdown for the requested agent" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Invalid parameters" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get the top pages accessed by a specific AI agent over a time window.", + "tags": [ + "Proxy Logs" + ] + } + }, + "/proxy-logs/stats/ai-agents": { + "get": { + "operationId": "get_ai_agent_breakdown", + "parameters": [ + { + "description": "Filter by project ID (recommended for per-project analytics).", + "in": "query", + "name": "project_id", + "required": false, + "schema": { + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + { + "description": "Filter by environment ID.", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + { + "description": "Start time (ISO 8601). Defaults to `end_time - 7d`.", + "example": "2026-05-22T00:00:00Z", + "in": "query", + "name": "start_time", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "description": "End time (ISO 8601). Defaults to now.", + "example": "2026-05-29T00:00:00Z", + "in": "query", + "name": "end_time", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "description": "Maximum rows to return. Capped at 100 server-side.", + "in": "query", + "name": "limit", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + } + }, + { + "description": "Optional exact path filter. Only used by the AI pages breakdown — when\nset, returns the single matching page so callers can ask \"how many AI\nagents hit this page?\".", + "in": "query", + "name": "path", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiAgentBreakdownResponse" + } + } + }, + "description": "AI agent breakdown" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Invalid parameters" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get the per-AI-agent breakdown for a project over a time window.", + "tags": [ + "Proxy Logs" + ] + } + }, + "/proxy-logs/stats/ai-agents/timeline": { + "get": { + "description": "Powers the \"AI agents over time\" stacked chart. Same data source as the AI\nagent breakdown (request logs), just bucketed.", + "operationId": "get_ai_agent_timeline", + "parameters": [ + { + "description": "Filter by project ID.", + "in": "query", + "name": "project_id", + "required": false, + "schema": { + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + { + "description": "Filter by environment ID.", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + { + "description": "Start time (ISO 8601). Defaults to `end_time - 7d`.", + "example": "2026-05-22T00:00:00Z", + "in": "query", + "name": "start_time", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "description": "End time (ISO 8601). Defaults to now.", + "example": "2026-05-29T00:00:00Z", + "in": "query", + "name": "end_time", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "description": "Grouping dimension: `provider` (default) or `agent`.", + "example": "provider", + "in": "query", + "name": "group_by", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "description": "Bucket interval override (e.g. `1 hour`, `1 day`). Auto-selected from the\nwindow width when omitted.", + "example": "1 hour", + "in": "query", + "name": "bucket", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiAgentTimelineResponse" + } + } + }, + "description": "AI agent timeline" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Invalid parameters" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Time-bucketed AI-agent request volume, split by provider or agent.", + "tags": [ + "Proxy Logs" + ] + } + }, + "/proxy-logs/stats/ai-pages": { + "get": { + "operationId": "get_ai_page_breakdown", + "parameters": [ + { + "description": "Filter by project ID (recommended for per-project analytics).", + "in": "query", + "name": "project_id", + "required": false, + "schema": { + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + { + "description": "Filter by environment ID.", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + { + "description": "Start time (ISO 8601). Defaults to `end_time - 7d`.", + "example": "2026-05-22T00:00:00Z", + "in": "query", + "name": "start_time", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "description": "End time (ISO 8601). Defaults to now.", + "example": "2026-05-29T00:00:00Z", + "in": "query", + "name": "end_time", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "description": "Maximum rows to return. Capped at 100 server-side.", + "in": "query", + "name": "limit", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + } + }, + { + "description": "Optional exact path filter. Only used by the AI pages breakdown — when\nset, returns the single matching page so callers can ask \"how many AI\nagents hit this page?\".", + "in": "query", + "name": "path", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiPageBreakdownResponse" + } + } + }, + "description": "AI page breakdown" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Invalid parameters" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get the top pages crawled by AI agents over a time window.", + "tags": [ + "Proxy Logs" + ] + } + }, + "/proxy-logs/stats/ai-status": { + "get": { + "operationId": "get_ai_status_breakdown", + "parameters": [ + { + "description": "Filter by project ID (recommended for per-project analytics).", + "in": "query", + "name": "project_id", + "required": false, + "schema": { + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + { + "description": "Filter by environment ID.", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + { + "description": "Start time (ISO 8601). Defaults to `end_time - 7d`.", + "example": "2026-05-22T00:00:00Z", + "in": "query", + "name": "start_time", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "description": "End time (ISO 8601). Defaults to now.", + "example": "2026-05-29T00:00:00Z", + "in": "query", + "name": "end_time", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "description": "Maximum rows to return. Capped at 100 server-side.", + "in": "query", + "name": "limit", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": [ + "integer", + "null" + ] + } + }, + { + "description": "Optional exact path filter. Only used by the AI pages breakdown — when\nset, returns the single matching page so callers can ask \"how many AI\nagents hit this page?\".", + "in": "query", + "name": "path", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiStatusBreakdownResponse" + } + } + }, + "description": "AI status breakdown" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Invalid parameters" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "HTTP status-class breakdown for AI-agent traffic — are bots being served\n(2xx) or hitting broken/blocked pages (4xx/5xx)?", + "tags": [ + "Proxy Logs" + ] + } + }, + "/proxy-logs/stats/projects-health": { + "get": { + "operationId": "get_projects_health", + "parameters": [ + { + "description": "Comma-separated list of project IDs", + "in": "query", + "name": "project_ids", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Optional start time (ISO 8601). Defaults to `end_time - 1h`.", + "example": "2025-10-23T00:00:00Z", + "in": "query", + "name": "start_time", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "description": "Optional end time (ISO 8601). Defaults to now.", + "example": "2025-10-23T23:59:59Z", + "in": "query", + "name": "end_time", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "description": "Filter by bot detection. Pass `false` to exclude bots, `true` for bots only.", + "in": "query", + "name": "is_bot", + "required": false, + "schema": { + "type": [ + "boolean", + "null" + ] + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProjectsHealthResponse" + } + } + }, + "description": "Health summaries per project" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Invalid parameters" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get health summaries for multiple projects (last 1 hour)", + "tags": [ + "Proxy Logs" + ] + } + }, + "/proxy-logs/stats/time-buckets": { + "get": { + "operationId": "get_time_bucket_stats", + "parameters": [ + { + "description": "Start time (ISO 8601 format)", + "example": "2025-10-23T00:00:00Z", + "in": "query", + "name": "start_time", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "End time (ISO 8601 format)", + "example": "2025-10-23T23:59:59Z", + "in": "query", + "name": "end_time", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Bucket interval (e.g., \"1 hour\", \"1 day\", \"5 minutes\")", + "in": "query", + "name": "bucket_interval", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter by HTTP method", + "in": "query", + "name": "method", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter by client IP", + "in": "query", + "name": "client_ip", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter by project ID", + "in": "query", + "name": "project_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Filter by environment ID", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Filter by deployment ID", + "in": "query", + "name": "deployment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Filter by host", + "in": "query", + "name": "host", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter by status code", + "in": "query", + "name": "status_code", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Filter by status code class (e.g. \"2xx\", \"3xx\", \"4xx\", \"5xx\")", + "in": "query", + "name": "status_code_class", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter by routing status", + "in": "query", + "name": "routing_status", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter by request source", + "in": "query", + "name": "request_source", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter by bot detection", + "in": "query", + "name": "is_bot", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "description": "Filter by device type", + "in": "query", + "name": "device_type", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "When true, only count requests that matched a project\n(project_id IS NOT NULL). Makes chart totals line up with the\nper-project health cards.", + "in": "query", + "name": "has_project", + "required": false, + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TimeBucketStatsResponse" + } + } + }, + "description": "Time-bucketed statistics" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Invalid parameters" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get time-bucketed statistics with optional filters", + "tags": [ + "Proxy Logs" + ] + } + }, + "/proxy-logs/stats/today": { + "get": { + "operationId": "get_today_stats", + "parameters": [ + { + "description": "Filter by HTTP method", + "in": "query", + "name": "method", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "description": "Filter by client IP", + "in": "query", + "name": "client_ip", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "description": "Filter by project ID", + "in": "query", + "name": "project_id", + "required": false, + "schema": { + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + { + "description": "Filter by environment ID", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + { + "description": "Filter by deployment ID", + "in": "query", + "name": "deployment_id", + "required": false, + "schema": { + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + { + "description": "Filter by host", + "in": "query", + "name": "host", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "description": "Filter by status code", + "in": "query", + "name": "status_code", + "required": false, + "schema": { + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + { + "description": "Filter by status code class (e.g. \"2xx\", \"3xx\", \"4xx\", \"5xx\")", + "in": "query", + "name": "status_code_class", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "description": "Filter by routing status", + "in": "query", + "name": "routing_status", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "description": "Filter by request source", + "in": "query", + "name": "request_source", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + }, + { + "description": "Filter by bot detection", + "in": "query", + "name": "is_bot", + "required": false, + "schema": { + "type": [ + "boolean", + "null" + ] + } + }, + { + "description": "Filter by device type", + "in": "query", + "name": "device_type", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TodayStatsResponse" + } + } + }, + "description": "Today's request count" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get today's request count with optional filters", + "tags": [ + "Proxy Logs" + ] + } + }, + "/proxy-logs/{id}": { + "get": { + "operationId": "get_proxy_log_by_id", + "parameters": [ + { + "description": "Proxy log ID", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Event time of the log row (ISO 8601). When provided, the lookup is\nbounded to the hypertable chunks around this instant instead of\nscanning (and decompressing) the whole retention window. The list\nendpoint already returns this value per row — always pass it when\nnavigating from a list.", + "in": "query", + "name": "timestamp", + "required": false, + "schema": { + "format": "date-time", + "type": [ + "string", + "null" + ] + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProxyLogResponse" + } + } + }, + "description": "Proxy log found" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Proxy log not found" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get a single proxy log by ID", + "tags": [ + "Proxy Logs" + ] + } + }, + "/repositories": { + "get": { + "description": "Lists repositories that have been synced to the database with filtering options.\nThis provides fast access to repository metadata with filtering by connection, search, and other criteria.", + "operationId": "list_synced_repositories", + "parameters": [ + { + "description": "Page number for pagination", + "in": "query", + "name": "page", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + { + "description": "Number of items per page (max 100)", + "in": "query", + "name": "per_page", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + { + "description": "Sort field (name, created_at, updated_at, stars, watchers, size, issues)", + "in": "query", + "name": "sort", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Sort direction (asc, desc)", + "in": "query", + "name": "direction", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Search term to filter repositories", + "in": "query", + "name": "search", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter by repository owner", + "in": "query", + "name": "owner", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter by programming language", + "in": "query", + "name": "language", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter by private status (true/false)", + "in": "query", + "name": "private", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "description": "Filter by git provider connection ID", + "in": "query", + "name": "git_provider_connection_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RepositoryListResponse" + } + } + }, + "description": "List of synced repositories" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List synced repositories with advanced filtering", + "tags": [ + "Git Providers" + ] + } + }, + "/repositories/{owner}/{name}": { + "get": { + "operationId": "get_repository_by_name", + "parameters": [ + { + "description": "Repository owner", + "in": "path", + "name": "owner", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Repository name", + "in": "path", + "name": "name", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Optional specific connection ID to search", + "in": "query", + "name": "connection_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RepositoryResponse" + } + } + }, + "description": "Repository found" + }, + "404": { + "description": "Repository not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get repository by owner and name from any connection", + "tags": [ + "Git Providers" + ] + } + }, + "/repositories/{owner}/{name}/all": { + "get": { + "operationId": "get_all_repositories_by_name", + "parameters": [ + { + "description": "Repository owner", + "in": "path", + "name": "owner", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Repository name", + "in": "path", + "name": "name", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/RepositoryResponse" + }, + "type": "array" + } + } + }, + "description": "Repositories found from all providers" + }, + "404": { + "description": "No repositories found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get all repositories with same owner/name from all git providers", + "tags": [ + "Git Providers" + ] + } + }, + "/repositories/{owner}/{name}/preset": { + "get": { + "operationId": "get_repository_preset_by_name", + "parameters": [ + { + "description": "Repository owner", + "in": "path", + "name": "owner", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Repository name", + "in": "path", + "name": "name", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Git branch to check (defaults to repository's default branch)", + "in": "query", + "name": "branch", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RepositoryPresetResponse" + } + } + }, + "description": "Repository preset calculated successfully" + }, + "404": { + "description": "Repository not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get repository preset by owner and name", + "tags": [ + "Git Providers" + ] + } + }, + "/repositories/{owner}/{repo}/branches": { + "get": { + "operationId": "get_repository_branches", + "parameters": [ + { + "description": "Repository owner", + "in": "path", + "name": "owner", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Repository name", + "in": "path", + "name": "repo", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Git provider connection ID (required when multiple connections have the same repo)", + "in": "query", + "name": "connection_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Force fetch fresh data, bypassing cache (default: false)", + "in": "query", + "name": "fresh", + "required": false, + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BranchListResponse" + } + } + }, + "description": "List of branches" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Repository not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get repository branches", + "tags": [ + "Repositories" + ] + } + }, + "/repositories/{owner}/{repo}/tags": { + "get": { + "operationId": "get_repository_tags", + "parameters": [ + { + "description": "Repository owner", + "in": "path", + "name": "owner", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Repository name", + "in": "path", + "name": "repo", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Git provider connection ID (required when multiple connections have the same repo)", + "in": "query", + "name": "connection_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Force fetch fresh data, bypassing cache (default: false)", + "in": "query", + "name": "fresh", + "required": false, + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagListResponse" + } + } + }, + "description": "List of tags" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Repository not found" + }, + "429": { + "description": "Fresh tag lookup rate limit exceeded" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get repository tags", + "tags": [ + "Repositories" + ] + } + }, + "/repositories/{repository_id}/preset/live": { + "get": { + "operationId": "get_repository_preset_live", + "parameters": [ + { + "description": "Repository ID", + "in": "path", + "name": "repository_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Git branch to check (defaults to repository's default branch)", + "in": "query", + "name": "branch", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RepositoryPresetResponse" + } + } + }, + "description": "Repository presets calculated successfully - includes root preset and projects in subdirectories" + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "The git provider rejected the stored credential - the connection must be re-authorized" + }, + "404": { + "description": "Repository not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Git Providers" + ] + } + }, + "/repository/{repository_id}": { + "get": { + "operationId": "get_repository_by_id", + "parameters": [ + { + "description": "Repository ID", + "in": "path", + "name": "repository_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RepositoryResponse" + } + } + }, + "description": "Repository found" + }, + "404": { + "description": "Repository not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get repository by ID", + "tags": [ + "Git Providers" + ] + } + }, + "/repository/{repository_id}/branches": { + "get": { + "operationId": "get_branches_by_repository_id", + "parameters": [ + { + "description": "Repository ID", + "in": "path", + "name": "repository_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Force fetch fresh data, bypassing cache (default: false)", + "in": "query", + "name": "fresh", + "required": false, + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BranchListResponse" + } + } + }, + "description": "List of branches" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Repository not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get repository branches by repository ID", + "tags": [ + "Repositories" + ] + } + }, + "/repository/{repository_id}/commits": { + "get": { + "operationId": "list_commits_by_repository_id", + "parameters": [ + { + "description": "Repository ID", + "in": "path", + "name": "repository_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Branch name to list commits for", + "in": "query", + "name": "branch", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Number of commits to return (default: 20, max: 100)", + "in": "query", + "name": "per_page", + "required": false, + "schema": { + "format": "int32", + "minimum": 0, + "type": [ + "integer", + "null" + ] + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CommitListResponse" + } + } + }, + "description": "List of commits" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Repository not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List recent commits for a repository branch", + "tags": [ + "Repositories" + ] + } + }, + "/repository/{repository_id}/commits/{commit_sha}": { + "get": { + "operationId": "check_commit_exists", + "parameters": [ + { + "description": "Repository ID", + "in": "path", + "name": "repository_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Commit SHA to check", + "in": "path", + "name": "commit_sha", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CommitExistsResponse" + } + } + }, + "description": "Commit existence check result" + }, + "400": { + "description": "Invalid commit SHA" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Repository not found" + }, + "429": { + "description": "Commit lookup rate limit exceeded" + }, + "500": { + "description": "Internal server error" + }, + "502": { + "description": "Git provider request failed" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Check if a commit exists in a repository", + "tags": [ + "Repositories" + ] + } + }, + "/repository/{repository_id}/tags": { + "get": { + "operationId": "get_tags_by_repository_id", + "parameters": [ + { + "description": "Repository ID", + "in": "path", + "name": "repository_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Force fetch fresh data, bypassing cache (default: false)", + "in": "query", + "name": "fresh", + "required": false, + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagListResponse" + } + } + }, + "description": "List of tags" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Repository not found" + }, + "429": { + "description": "Fresh tag lookup rate limit exceeded" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get repository tags by repository ID", + "tags": [ + "Repositories" + ] + } + }, + "/restore-runs/{id}": { + "get": { + "operationId": "get_restore_run", + "parameters": [ + { + "description": "Restore run id", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RestoreRunView" + } + } + }, + "description": "Restore run progress" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Restore run not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Restore" + ] + } + }, + "/revenue/events": { + "get": { + "operationId": "revenue_global_events", + "parameters": [ + { + "description": "Filter to a single project", + "in": "query", + "name": "project_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Lower bound (inclusive), ISO-8601", + "in": "query", + "name": "from", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Upper bound (inclusive), ISO-8601", + "in": "query", + "name": "to", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Comma-separated event types (e.g. `invoice.paid,charge.succeeded`)", + "in": "query", + "name": "event_types", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Max rows, default 100, max 500", + "in": "query", + "name": "limit", + "required": false, + "schema": { + "format": "int64", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/GlobalRecentEventResponse" + }, + "type": "array" + } + } + }, + "description": "" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Org-wide revenue events across every project. Powers the revenue\ntransactions page. Supports filtering by project, date range, and\nevent type.", + "tags": [ + "Revenue" + ] + } + }, + "/revenue/metrics/global-mrr": { + "get": { + "operationId": "revenue_metrics_global_mrr", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GlobalMrrResponse" + } + } + }, + "description": "" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Org-wide MRR total, summed across every project in the install.\nPowers the single-number MRR card on the main dashboard.", + "tags": [ + "Revenue" + ] + } + }, + "/revenue/metrics/global-summary": { + "get": { + "operationId": "revenue_metrics_global_summary", + "parameters": [ + { + "description": "ISO-4217 currency code, default USD", + "in": "query", + "name": "currency", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GlobalRevenueSummaryResponse" + } + } + }, + "description": "" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Org-wide revenue summary: MRR, paid cash (30d + all-time), refunds,\nactive subscriptions/customers, and transaction count. Powers the\nheader on the Revenue transactions page.", + "tags": [ + "Revenue" + ] + } + }, + "/revenue/providers": { + "get": { + "operationId": "revenue_list_providers", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/ProviderDescriptor" + }, + "type": "array" + } + } + }, + "description": "" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List registered providers (what the UI needs to render the \"Connect\"\ndropdown + its wizard instructions).", + "tags": [ + "Revenue" + ] + } + }, + "/session-replays": { + "get": { + "operationId": "get_project_session_replays", + "parameters": [ + { + "description": "Project ID", + "in": "query", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Environment ID (optional)", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Page number (1-based)", + "in": "query", + "name": "page", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + { + "description": "Items per page", + "in": "query", + "name": "per_page", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetProjectSessionReplaysResponse" + } + } + }, + "description": "Session replays retrieved successfully" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Bad request" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Authentication required" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Insufficient permissions" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get session replays for a project", + "tags": [ + "Analytics" + ] + } + }, + "/sessions/{session_id}/events": { + "get": { + "operationId": "get_session_events", + "parameters": [ + { + "description": "Session ID", + "in": "path", + "name": "session_id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Filter by environment ID", + "in": "query", + "name": "environment_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AnalyticsSessionEventsResponse" + } + } + }, + "description": "Successfully retrieved session events" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Session not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get events for a specific session", + "tags": [ + "Events" + ] + } + }, + "/settings": { + "get": { + "operationId": "get_settings", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AppSettingsResponse" + } + } + }, + "description": "Application settings with masked sensitive fields" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get application settings", + "tags": [ + "Settings" + ] + }, + "put": { + "operationId": "update_settings", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AppSettings" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SettingsUpdateResponse" + } + } + }, + "description": "Settings updated successfully" + }, + "400": { + "description": "Bad request - invalid settings" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Update application settings", + "tags": [ + "Settings" + ] + } + }, + "/settings/agent-token": { + "post": { + "operationId": "save_agent_token", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SaveAgentTokenRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SaveAgentTokenResponse" + } + } + }, + "description": "Token encrypted and persisted" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Encryption or database error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Save an encrypted AI provider token for use in sandbox containers.", + "tags": [ + "Agents" + ] + } + }, + "/settings/ai-providers": { + "get": { + "operationId": "list_ai_providers", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProviderCatalogResponse" + } + } + }, + "description": "" + }, + "401": { + "description": "Unauthorized" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List the AI provider catalog. Includes per-provider \"is a credential\nconfigured?\" so the settings UI can render configured/not-configured\nbadges without leaking the encrypted credential.", + "tags": [ + "Agents" + ] + } + }, + "/settings/ai-providers/{provider_id}": { + "patch": { + "operationId": "update_ai_provider", + "parameters": [ + { + "description": "AI provider ID", + "in": "path", + "name": "provider_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateAiProviderRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateAiProviderResponse" + } + } + }, + "description": "" + }, + "400": { + "description": "Unknown provider" + }, + "401": { + "description": "Unauthorized" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Update provider-scoped settings without touching the saved credential.\nToday that means just `default_model`; future per-provider settings\n(base URL overrides, request headers, etc.) can land here too without\nchanging the shape of `save_credential`.", + "tags": [ + "Agents" + ] + } + }, + "/settings/ai-providers/{provider_id}/activate": { + "post": { + "operationId": "activate_ai_provider", + "parameters": [ + { + "description": "AI provider ID", + "in": "path", + "name": "provider_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ActivateProviderResponse" + } + } + }, + "description": "" + }, + "400": { + "description": "Provider not configured" + }, + "401": { + "description": "Unauthorized" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Activate a provider as the platform-wide default. Refuses to activate a\nprovider that doesn't have a credential saved yet — the UI enforces the\nsame rule on the button, but we re-check server-side so a stale tab\ncan't bypass it.", + "tags": [ + "Agents" + ] + } + }, + "/settings/ai-providers/{provider_id}/credential": { + "post": { + "description": "The plaintext shape depends on the flavor's `credential_format`:\n - `ApiKey` / `OauthToken`: the key/token string.\n - `ConfigFile`: the full file body (e.g. OpenCode's `auth.json`).", + "operationId": "save_ai_provider_credential", + "parameters": [ + { + "description": "AI provider ID", + "in": "path", + "name": "provider_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SaveCredentialRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SaveCredentialResponse" + } + } + }, + "description": "" + }, + "400": { + "description": "Validation error" + }, + "401": { + "description": "Unauthorized" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Save (or replace) a provider's credential. The credential is encrypted\nwith `EncryptionService` and stored inside\n`agent_sandbox.providers[provider_id].credentials_encrypted`.", + "tags": [ + "Agents" + ] + } + }, + "/settings/disk-status": { + "get": { + "description": "Returns live disk usage for the monitored path along with any disks that\nmeet or exceed the configured alert threshold. Read-only — does not send\nnotifications. Used by the dashboard to surface a low-disk-space warning.", + "operationId": "get_disk_status", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DiskSpaceCheckResult" + } + } + }, + "description": "Current disk usage and threshold alerts" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get current disk usage for the control-plane server", + "tags": [ + "Settings" + ] + } + }, + "/settings/enrollment-tokens": { + "get": { + "operationId": "list_enrollment_tokens", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnrollmentTokenListResponse" + } + } + }, + "description": "Active enrollment tokens" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List currently-valid node enrollment tokens (hashes elided).", + "tags": [ + "Settings" + ] + }, + "post": { + "operationId": "mint_enrollment_token", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MintEnrollmentTokenRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MintEnrollmentTokenResponse" + } + } + }, + "description": "Enrollment token minted" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Mint a short-lived, single-use node enrollment token.", + "tags": [ + "Settings" + ] + } + }, + "/settings/enrollment-tokens/{id}": { + "delete": { + "operationId": "revoke_enrollment_token", + "parameters": [ + { + "description": "Enrollment token id", + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SettingsUpdateResponse" + } + } + }, + "description": "Enrollment token revoked" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Enrollment token not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Revoke a node enrollment token by id.", + "tags": [ + "Settings" + ] + } + }, + "/settings/join-token": { + "delete": { + "description": "Removes the stored join token hash, allowing any node to register\n(if no other authentication is in place).", + "operationId": "revoke_join_token", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SettingsUpdateResponse" + } + } + }, + "description": "Join token revoked" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Revoke the current join token", + "tags": [ + "Settings" + ] + } + }, + "/settings/join-token/generate": { + "post": { + "description": "Creates a random 32-byte hex token, stores the SHA-256 hash in settings,\nand returns the plaintext exactly once. If a token already exists, it is replaced.", + "operationId": "generate_join_token", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GenerateJoinTokenResponse" + } + } + }, + "description": "Join token generated" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Generate a new join token for multi-node cluster registration", + "tags": [ + "Settings" + ] + } + }, + "/settings/join-token/status": { + "get": { + "operationId": "get_join_token_status", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/JoinTokenStatusResponse" + } + } + }, + "description": "Join token status" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Check whether a join token is currently configured", + "tags": [ + "Settings" + ] + } + }, + "/settings/mcp-servers": { + "get": { + "operationId": "list_global_mcps", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListMcpsResponse" + } + } + }, + "description": "" + }, + "401": { + "description": "Unauthorized" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Agents" + ] + }, + "post": { + "operationId": "create_global_mcp", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateMcpRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/McpDefinitionResponse" + } + } + }, + "description": "" + }, + "401": { + "description": "Unauthorized" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Agents" + ] + } + }, + "/settings/mcp-servers/{slug}": { + "delete": { + "operationId": "delete_global_mcp", + "parameters": [ + { + "description": "MCP server slug", + "in": "path", + "name": "slug", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "MCP server deleted" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "MCP server not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Agents" + ] + }, + "get": { + "operationId": "get_global_mcp", + "parameters": [ + { + "description": "MCP server slug", + "in": "path", + "name": "slug", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/McpDefinitionResponse" + } + } + }, + "description": "" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "MCP server not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Agents" + ] + }, + "put": { + "operationId": "update_global_mcp", + "parameters": [ + { + "description": "MCP server slug", + "in": "path", + "name": "slug", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateMcpRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/McpDefinitionResponse" + } + } + }, + "description": "" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "MCP server not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Agents" + ] + } + }, + "/settings/mcp-servers/{slug}/config/{field}": { + "get": { + "operationId": "reveal_global_mcp_config", + "parameters": [ + { + "description": "MCP server slug", + "in": "path", + "name": "slug", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Sensitive field path, such as url or env.API_TOKEN", + "in": "path", + "name": "field", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SensitiveMcpConfigValueResponse" + } + } + }, + "description": "" + }, + "400": { + "description": "Field is not revealable" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Missing secrets:read permission" + }, + "404": { + "description": "MCP server or field not found" + }, + "500": { + "description": "Configuration read or audit failed" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Agents" + ] + } + }, + "/settings/routes/refresh": { + "post": { + "description": "Reloads all routes from the database into the in-memory proxy cache.\nUseful as a workaround when routes are out of sync.", + "operationId": "refresh_route_table", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RouteRefreshResponse" + } + } + }, + "description": "Route table refreshed" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Manually refresh the proxy route table", + "tags": [ + "Settings" + ] + } + }, + "/settings/sandbox-rebuild": { + "post": { + "operationId": "rebuild_sandbox_image", + "responses": { + "200": { + "content": { + "text/event-stream": {} + }, + "description": "Server-Sent Events stream of rebuild progress; final event `{\"type\":\"done\",\"success\":bool,...}`" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Agents" + ] + } + }, + "/settings/sandbox-status": { + "get": { + "operationId": "get_global_sandbox_status", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SandboxStatusResponse" + } + } + }, + "description": "Global sandbox readiness for the settings page" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Agents" + ] + } + }, + "/settings/secrets": { + "get": { + "operationId": "list_secrets", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListSecretsResponse" + } + } + }, + "description": "List of global agent secrets" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Secrets" + ] + }, + "post": { + "operationId": "upsert_secret", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpsertSecretRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SecretResponse" + } + } + }, + "description": "Secret created/updated" + }, + "400": { + "description": "Validation error" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Secrets" + ] + } + }, + "/settings/secrets/{name}": { + "delete": { + "operationId": "delete_secret", + "parameters": [ + { + "description": "Secret name", + "in": "path", + "name": "name", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Secret deleted" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Secret not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Secrets" + ] + } + }, + "/settings/skills": { + "get": { + "operationId": "list_global_skills", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListSkillsResponse" + } + } + }, + "description": "" + }, + "401": { + "description": "Unauthorized" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Agents" + ] + }, + "post": { + "operationId": "create_global_skill", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateSkillRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SkillDefinitionResponse" + } + } + }, + "description": "" + }, + "401": { + "description": "Unauthorized" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Agents" + ] + } + }, + "/settings/skills/upload": { + "post": { + "operationId": "upload_global_skill", + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "type": "string" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SkillDefinitionResponse" + } + } + }, + "description": "" + }, + "401": { + "description": "Unauthorized" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Upload a skill with an archive (tar.gz) — global.", + "tags": [ + "Agents" + ] + } + }, + "/settings/skills/{slug}": { + "delete": { + "operationId": "delete_global_skill", + "parameters": [ + { + "description": "Skill slug", + "in": "path", + "name": "slug", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Skill deleted" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Skill not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Agents" + ] + }, + "get": { + "operationId": "get_global_skill", + "parameters": [ + { + "description": "Skill slug", + "in": "path", + "name": "slug", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SkillDefinitionResponse" + } + } + }, + "description": "" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Skill not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Agents" + ] + }, + "put": { + "operationId": "update_global_skill", + "parameters": [ + { + "description": "Skill slug", + "in": "path", + "name": "slug", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateSkillRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SkillDefinitionResponse" + } + } + }, + "description": "" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Skill not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Agents" + ] + } + }, + "/settings/skills/{slug}/archive": { + "get": { + "operationId": "download_global_skill_archive", + "parameters": [ + { + "description": "Skill slug", + "in": "path", + "name": "slug", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/gzip": {} + }, + "description": "Skill archive tar.gz" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Skill not found or has no archive" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Download a skill's archive (tar.gz) — global.", + "tags": [ + "Agents" + ] + } + }, + "/settings/update-status": { + "get": { + "operationId": "get_update_status", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateStatusResponse" + } + } + }, + "description": "Release update status for this install" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Report whether a newer temps release is available for this install.", + "tags": [ + "Settings" + ] + } + }, + "/teams": { + "get": { + "operationId": "list_teams", + "parameters": [ + { + "description": "1-indexed page", + "in": "query", + "name": "page", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + { + "description": "default 20, max 100", + "in": "query", + "name": "page_size", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TeamListResponse" + } + } + }, + "description": "Paginated teams" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Teams" + ] + }, + "post": { + "operationId": "create_team", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateTeamRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TeamResponse" + } + } + }, + "description": "Team created" + }, + "400": { + "description": "Validation error" + }, + "403": { + "description": "Insufficient permissions" + }, + "409": { + "description": "Slug already taken" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Teams" + ] + } + }, + "/teams/{team_id}": { + "delete": { + "operationId": "delete_team", + "parameters": [ + { + "description": "Team id", + "in": "path", + "name": "team_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "Team deleted" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Team not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Teams" + ] + }, + "get": { + "operationId": "get_team", + "parameters": [ + { + "description": "Team id", + "in": "path", + "name": "team_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TeamResponse" + } + } + }, + "description": "Team" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Team not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Teams" + ] + }, + "patch": { + "operationId": "update_team", + "parameters": [ + { + "description": "Team id", + "in": "path", + "name": "team_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateTeamRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TeamResponse" + } + } + }, + "description": "Updated team" + }, + "400": { + "description": "Validation error" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Team not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Teams" + ] + } + }, + "/teams/{team_id}/members": { + "get": { + "operationId": "list_team_members", + "parameters": [ + { + "in": "path", + "name": "team_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/TeamMemberResponse" + }, + "type": "array" + } + } + }, + "description": "Members" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Team not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Teams" + ] + }, + "post": { + "operationId": "add_team_member", + "parameters": [ + { + "in": "path", + "name": "team_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateTeamMemberRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TeamMemberResponse" + } + } + }, + "description": "Member added" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Team not found" + }, + "409": { + "description": "User already a member" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Teams" + ] + } + }, + "/teams/{team_id}/members/{user_id}": { + "delete": { + "operationId": "remove_team_member", + "parameters": [ + { + "in": "path", + "name": "team_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "in": "path", + "name": "user_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "Member removed" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Member not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Teams" + ] + }, + "patch": { + "operationId": "update_team_member_role", + "parameters": [ + { + "in": "path", + "name": "team_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "in": "path", + "name": "user_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateMemberRoleRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TeamMemberResponse" + } + } + }, + "description": "Updated membership" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Member not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Teams" + ] + } + }, + "/teams/{team_id}/projects": { + "get": { + "operationId": "list_team_projects", + "parameters": [ + { + "in": "path", + "name": "team_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/ProjectAccessResponse" + }, + "type": "array" + } + } + }, + "description": "Projects this team has access to" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Team not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Teams" + ] + } + }, + "/templates": { + "get": { + "description": "Returns a list of all public templates, optionally filtered by tag or featured status.", + "operationId": "list_project_templates", + "parameters": [ + { + "description": "Filter templates by tag", + "in": "query", + "name": "tag", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Only return featured templates", + "in": "query", + "name": "featured", + "required": false, + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListTemplatesResponse" + } + } + }, + "description": "List of templates" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List all available templates", + "tags": [ + "Templates" + ] + } + }, + "/templates/tags": { + "get": { + "description": "Returns a list of all unique tags used by public templates.", + "operationId": "list_project_template_tags", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListTagsResponse" + } + } + }, + "description": "List of tags" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List all available template tags", + "tags": [ + "Templates" + ] + } + }, + "/templates/{slug}": { + "get": { + "description": "Returns detailed information about a single template.", + "operationId": "get_project_template", + "parameters": [ + { + "description": "Template slug", + "in": "path", + "name": "slug", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TemplateResponse" + } + } + }, + "description": "Template details" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Template not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get a specific template by slug", + "tags": [ + "Templates" + ] + } + }, + "/user/me": { + "get": { + "operationId": "get_current_user", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserResponse" + } + } + }, + "description": "Successfully retrieved user information" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "session_token": [] + } + ], + "tags": [ + "Authentication" + ] + } + }, + "/users": { + "get": { + "operationId": "list_users", + "parameters": [ + { + "description": "Include deleted users in the response", + "in": "query", + "name": "include_deleted", + "required": true, + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/RouteUserWithRoles" + }, + "type": "array" + } + } + }, + "description": "List all users with their roles" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Users" + ] + }, + "post": { + "operationId": "create_user", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateUserRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RouteUserWithRoles" + } + } + }, + "description": "User created successfully" + }, + "400": { + "description": "Invalid input" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Create a new user with roles", + "tags": [ + "Users" + ] + } + }, + "/users/me": { + "patch": { + "operationId": "update_self", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateSelfRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RouteUserWithRoles" + } + } + }, + "description": "User updated successfully" + }, + "400": { + "description": "Invalid input" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Update current user's information", + "tags": [ + "Users" + ] + } + }, + "/users/me/mfa": { + "delete": { + "operationId": "disable_mfa", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DisableMfaRequest" + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "MFA disabled" + }, + "400": { + "description": "Invalid verification code" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Users" + ] + } + }, + "/users/me/mfa/setup": { + "post": { + "operationId": "setup_mfa", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MfaSetupResponse" + } + } + }, + "description": "MFA setup data" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Users" + ] + } + }, + "/users/me/mfa/verify": { + "post": { + "operationId": "verify_and_enable_mfa", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VerifyMfaRequest" + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "MFA verified and enabled" + }, + "400": { + "description": "Invalid code" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Users" + ] + } + }, + "/users/me/password": { + "post": { + "operationId": "change_password_self", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChangePasswordRequest" + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Password updated" + }, + "400": { + "description": "Validation error (weak password, same as current, MFA missing)" + }, + "401": { + "description": "Current password incorrect or MFA code invalid" + }, + "403": { + "description": "Account has no password set (SSO only)" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Users" + ] + } + }, + "/users/{user_id}": { + "delete": { + "operationId": "delete_user", + "parameters": [ + { + "description": "User ID", + "in": "path", + "name": "user_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "User deleted successfully" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - Cannot delete yourself or non-admin attempt" + }, + "404": { + "description": "User not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Delete a user", + "tags": [ + "Users" + ] + }, + "patch": { + "operationId": "update_user", + "parameters": [ + { + "description": "User ID", + "in": "path", + "name": "user_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateUserRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RouteUserWithRoles" + } + } + }, + "description": "User updated successfully" + }, + "400": { + "description": "Invalid input" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - Non-admin attempt" + }, + "404": { + "description": "User not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Update user information (admin only)", + "tags": [ + "Users" + ] + } + }, + "/users/{user_id}/restore": { + "post": { + "operationId": "restore_user", + "parameters": [ + { + "description": "User ID", + "in": "path", + "name": "user_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RouteUserWithRoles" + } + } + }, + "description": "User restored successfully" + }, + "400": { + "description": "User is not deleted" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - Non-admin attempt" + }, + "404": { + "description": "User not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Users" + ] + } + }, + "/users/{user_id}/roles": { + "post": { + "operationId": "assign_role", + "parameters": [ + { + "description": "User ID", + "in": "path", + "name": "user_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AssignRoleRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Role assigned successfully" + }, + "400": { + "description": "Invalid role type" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Admin role required or self-modification forbidden" + }, + "404": { + "description": "User or role not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Users" + ] + } + }, + "/users/{user_id}/roles/{role_type}": { + "delete": { + "operationId": "remove_role", + "parameters": [ + { + "description": "User ID", + "in": "path", + "name": "user_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Role type to remove", + "in": "path", + "name": "role_type", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Role removed successfully" + }, + "400": { + "description": "Invalid role type" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - Cannot modify own roles or non-admin attempt" + }, + "404": { + "description": "User or role not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Users" + ] + } + }, + "/v1/sandboxes": { + "get": { + "operationId": "list_sandboxes", + "parameters": [ + { + "description": "Page (1-indexed)", + "in": "query", + "name": "page", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + { + "description": "Items per page (default 20, max 100)", + "in": "query", + "name": "page_size", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListSandboxesResponse" + } + } + }, + "description": "List sandboxes" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Sandboxes" + ] + }, + "post": { + "operationId": "create_sandbox", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateSandboxBody" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SandboxResponse" + } + } + }, + "description": "Sandbox created" + }, + "400": { + "description": "Validation error" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Sandboxes" + ] + } + }, + "/v1/sandboxes/rootfs": { + "get": { + "operationId": "rootfs_report", + "responses": { + "200": { + "description": "Rootfs storage report" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Inspect rootfs storage: the Firecracker digest-keyed cache (with which\nsandboxes reference each entry) and per-VM disks. Empty on Docker-only\nhosts. Admin/read scope — this exposes host storage layout.", + "tags": [ + "Sandboxes" + ] + } + }, + "/v1/sandboxes/rootfs/gc": { + "post": { + "operationId": "rootfs_gc", + "responses": { + "200": { + "description": "Reclaimed cache entries" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Reclaim rootfs cache entries not backing any live sandbox. Idempotent;\nsafe to call any time (live VMs hold their own per-VM disks).", + "tags": [ + "Sandboxes" + ] + } + }, + "/v1/sandboxes/{id}": { + "get": { + "operationId": "get_sandbox", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SandboxResponse" + } + } + }, + "description": "Sandbox details" + }, + "404": { + "description": "Not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Sandboxes" + ] + } + }, + "/v1/sandboxes/{id}/cmd": { + "post": { + "description": "`wait=false` (default) returns `{ command: {..., exitCode: null} }`\nimmediately once the background task is spawned.\n\n`wait=true` streams `application/x-ndjson`: the first line is the\nrunning envelope, the second is the finished envelope with `exitCode`.", + "operationId": "cmd", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CmdBody" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CmdResponse" + } + } + }, + "description": "Command started (wait=false) or finished (wait=true)" + }, + "404": { + "description": "Sandbox not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Run a command inside the sandbox (`@vercel/sandbox`-compatible).", + "tags": [ + "Sandboxes" + ] + } + }, + "/v1/sandboxes/{id}/cmd/{cmd_id}": { + "get": { + "operationId": "get_cmd", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "cmd_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CmdResponse" + } + } + }, + "description": "Command snapshot" + }, + "404": { + "description": "Sandbox or command not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Sandboxes" + ] + } + }, + "/v1/sandboxes/{id}/cmd/{cmd_id}/logs": { + "get": { + "operationId": "cmd_logs", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "cmd_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "NDJSON stream of log events" + }, + "404": { + "description": "Sandbox or command not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Stream a command's stdout/stderr as `application/x-ndjson`\n(`@vercel/sandbox`-compatible). Each line is either\n`{stream:\"stdout\"|\"stderr\", data:\"...\"}` or\n`{stream:\"error\", data:{code, message}}`.", + "tags": [ + "Sandboxes" + ] + } + }, + "/v1/sandboxes/{id}/destroy": { + "post": { + "operationId": "destroy_sandbox", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Sandbox destroyed (alias for `/stop` with an explicit verb)" + }, + "404": { + "description": "Not found" + }, + "409": { + "description": "Sandbox belongs to an active agent run — stop the run instead" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Sandboxes" + ] + } + }, + "/v1/sandboxes/{id}/domain": { + "get": { + "operationId": "domain", + "parameters": [ + { + "description": "Port inside the sandbox (1..=65535)", + "in": "query", + "name": "port", + "required": true, + "schema": { + "format": "int32", + "minimum": 0, + "type": "integer" + } + }, + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SandboxDomainResponse" + } + } + }, + "description": "Preview URL for the port" + }, + "400": { + "description": "Invalid port" + }, + "404": { + "description": "Sandbox not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Sandboxes" + ] + } + }, + "/v1/sandboxes/{id}/events": { + "get": { + "operationId": "list_events", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SandboxEventsResponse" + } + } + }, + "description": "Operations timeline" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "The operations timeline for a sandbox (lifecycle events only — never\nshell/exec activity), newest first.", + "tags": [ + "Sandboxes" + ] + } + }, + "/v1/sandboxes/{id}/exec": { + "post": { + "operationId": "exec", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExecBody" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExecResponse" + } + } + }, + "description": "Command finished (non-zero exit is NOT an error)" + }, + "404": { + "description": "Sandbox not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Sandboxes" + ] + } + }, + "/v1/sandboxes/{id}/exec-detached": { + "post": { + "operationId": "exec_detached", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExecBody" + } + } + }, + "required": true + }, + "responses": { + "202": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExecDetachedResponse" + } + } + }, + "description": "Command accepted; poll /jobs/{job_id}" + }, + "404": { + "description": "Sandbox not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Sandboxes" + ] + } + }, + "/v1/sandboxes/{id}/extend-timeout": { + "post": { + "operationId": "extend_timeout", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExtendTimeoutBody" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SandboxResponse" + } + } + }, + "description": "Timeout extended" + }, + "400": { + "description": "Validation error" + }, + "404": { + "description": "Not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Sandboxes" + ] + } + }, + "/v1/sandboxes/{id}/fs/mkdir": { + "post": { + "operationId": "mkdir", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MkdirBody" + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Directory created (or already existed)" + }, + "400": { + "description": "Validation error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Sandboxes" + ] + } + }, + "/v1/sandboxes/{id}/fs/read": { + "get": { + "operationId": "read_file", + "parameters": [ + { + "description": "Absolute file path inside the sandbox", + "in": "query", + "name": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ReadFileResponse" + } + } + }, + "description": "File contents (base64)" + }, + "400": { + "description": "Validation error" + }, + "404": { + "description": "Sandbox or file not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Sandboxes" + ] + } + }, + "/v1/sandboxes/{id}/fs/stat": { + "get": { + "operationId": "stat_path", + "parameters": [ + { + "description": "Absolute path inside the sandbox", + "in": "query", + "name": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StatResponse" + } + } + }, + "description": "Stat info (exists=false when missing — not an error)" + }, + "400": { + "description": "Validation error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Sandboxes" + ] + } + }, + "/v1/sandboxes/{id}/fs/write": { + "post": { + "description": "- **`application/json`** (temps-native): `{path, contents_b64, mode}`\n — one file, base64-encoded.\n- **`application/gzip`** (`@vercel/sandbox`): a gzipped tarball of\n one-or-more entries, with the target extract dir carried in the\n `x-cwd` header. The SDK's `writeFile` and `writeFiles` both post\n here; they differ only in how many entries the tarball contains.\n\nWhy merge them on one route: the SDK is hardcoded to\n`POST /fs/write`, so splitting tar uploads onto a separate path would\nforce us to break SDK compat. Instead we dispatch on Content-Type,\npreserve JSON for native callers, and add tar for SDK callers.", + "operationId": "write_file", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WriteFileBody" + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "File(s) written" + }, + "400": { + "description": "Validation error or invalid base64" + }, + "404": { + "description": "Sandbox not found" + }, + "415": { + "description": "Unsupported Content-Type (expected application/json or application/gzip)" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Write a file into the sandbox. Accepts two body shapes — the SDK\npicks one based on `Content-Type`:", + "tags": [ + "Sandboxes" + ] + } + }, + "/v1/sandboxes/{id}/fs/write-batch": { + "post": { + "operationId": "write_files", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WriteFilesBody" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WriteFilesResponse" + } + } + }, + "description": "All files written" + }, + "400": { + "description": "Validation error or invalid base64" + }, + "404": { + "description": "Sandbox not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Batch-write multiple files in a single request. Mirrors\n`@vercel/sandbox` `writeFiles()`. Semantics are fail-fast: if any\nfile errors, previously-written entries are left in place and the\nerror describes which file broke.", + "tags": [ + "Sandboxes" + ] + } + }, + "/v1/sandboxes/{id}/jobs": { + "get": { + "operationId": "list_jobs", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListJobsResponse" + } + } + }, + "description": "Detached jobs for this sandbox" + }, + "404": { + "description": "Sandbox not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Sandboxes" + ] + } + }, + "/v1/sandboxes/{id}/jobs/{job_id}": { + "get": { + "operationId": "job_status", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "job_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/JobStatusResponse" + } + } + }, + "description": "Job status snapshot" + }, + "404": { + "description": "Sandbox or job not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Sandboxes" + ] + } + }, + "/v1/sandboxes/{id}/jobs/{job_id}/kill": { + "post": { + "operationId": "kill_job", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "job_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/KillJobBody" + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Job killed" + }, + "404": { + "description": "Sandbox or job not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Terminate a detached job. Aborts the server-side tracking task and\nsends SIGTERM (or SIGKILL if `force=true`) to any matching processes\ninside the sandbox container. Returns 204 on success; 404 if the\nsandbox or job is unknown.", + "tags": [ + "Sandboxes" + ] + } + }, + "/v1/sandboxes/{id}/jobs/{job_id}/logs": { + "get": { + "description": "Late subscribers only see events produced after they connect. The\nJobState snapshot (`GET /jobs/{job_id}`) covers the history.\n\nA \"done\" sentinel event fires when the broadcast channel closes\n(the exec task has exited and dropped the sender), signalling\ncallers they can stop reading.", + "operationId": "job_logs", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "job_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "SSE stream of log events" + }, + "404": { + "description": "Sandbox or job not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "SSE endpoint streaming each stdout/stderr line from a detached job\nas it's produced. Mirrors the `Command.logs()` async iterator shape\non `@vercel/sandbox` — events carry `{ stream, data }`.", + "tags": [ + "Sandboxes" + ] + } + }, + "/v1/sandboxes/{id}/pause": { + "post": { + "operationId": "pause_sandbox", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SandboxResponse" + } + } + }, + "description": "Sandbox paused (container stopped, state preserved)" + }, + "404": { + "description": "Not found" + }, + "409": { + "description": "Sandbox is in an incompatible state (e.g. already destroyed)" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Sandboxes" + ] + } + }, + "/v1/sandboxes/{id}/preview-link": { + "post": { + "description": "`GET /domain` returns the bare preview URL, which is useless to anyone who\ndoes not already hold the sandbox's preview password — so sharing a\nprotected preview meant sharing that password, which is the same secret for\nevery recipient and can only be withdrawn by rotating it for all of them.\n\nThis returns the same URL carrying a short-lived, sandbox-scoped grant. The\nrecipient's browser exchanges it for the ordinary preview cookie and lands\non `path`. The grant never reaches the sandbox, so preview application code\ncannot read it and re-share it.\n\nAnyone holding the returned URL can view the preview until it expires;\nthere is no per-link revocation short of rotating the preview password.", + "operationId": "sandbox_create_preview_link", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PreviewShareLinkBody" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PreviewShareLinkResponse" + } + } + }, + "description": "Shareable preview link" + }, + "400": { + "description": "Invalid port" + }, + "404": { + "description": "Sandbox not found" + }, + "409": { + "description": "Sandbox has no preview password" + }, + "500": { + "description": "Preview grant minting failed" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Mint a shareable link to a sandbox preview.", + "tags": [ + "Sandboxes" + ] + } + }, + "/v1/sandboxes/{id}/preview-password": { + "delete": { + "operationId": "clear_preview_password", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Preview password removed (sandbox is now URL-only protected)" + }, + "404": { + "description": "Sandbox not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Sandboxes" + ] + }, + "put": { + "operationId": "set_preview_password", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SetPreviewPasswordBody" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SetPreviewPasswordResponse" + } + } + }, + "description": "Preview password set or rotated" + }, + "400": { + "description": "Password too short or too long" + }, + "404": { + "description": "Sandbox not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Sandboxes" + ] + } + }, + "/v1/sandboxes/{id}/resize": { + "post": { + "operationId": "resize_sandbox", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResizeSandboxBody" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SandboxResponse" + } + } + }, + "description": "Resized" + }, + "400": { + "description": "Invalid size or unsupported backend" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Grow a Firecracker sandbox's root disk. Offline resize — the VM reboots\n(filesystem/data persist) rather than resizing fully live.", + "tags": [ + "Sandboxes" + ] + } + }, + "/v1/sandboxes/{id}/restart": { + "post": { + "operationId": "restart_sandbox", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SandboxResponse" + } + } + }, + "description": "Sandbox container restarted in place" + }, + "404": { + "description": "Not found" + }, + "409": { + "description": "Sandbox is stopped (use /resume) or already destroyed" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Sandboxes" + ] + } + }, + "/v1/sandboxes/{id}/resume": { + "post": { + "operationId": "resume_sandbox", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SandboxResponse" + } + } + }, + "description": "Sandbox resumed; expires_at refreshed" + }, + "404": { + "description": "Not found" + }, + "409": { + "description": "Sandbox is not in a resumable state" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Sandboxes" + ] + } + }, + "/v1/sandboxes/{id}/source": { + "post": { + "operationId": "source_sandbox", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SourceBody" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SandboxResponse" + } + } + }, + "description": "Source content seeded into the sandbox work dir" + }, + "400": { + "description": "Validation error (embedded creds, conflicting fields, etc.)" + }, + "404": { + "description": "Sandbox not found" + }, + "409": { + "description": "Sandbox is not running" + }, + "500": { + "description": "Source seed failed inside sandbox" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Sandboxes" + ] + } + }, + "/v1/sandboxes/{id}/stop": { + "post": { + "operationId": "stop_sandbox", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Sandbox stopped and destroyed" + }, + "404": { + "description": "Not found" + }, + "409": { + "description": "Sandbox belongs to an active agent run — stop the run instead" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Sandboxes" + ] + } + }, + "/v1/sandboxes/{id}/{cmd_id}/kill": { + "post": { + "operationId": "cmd_kill", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "cmd_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CmdKillBody" + } + } + } + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CmdResponse" + } + } + }, + "description": "Command killed; returns final snapshot" + }, + "404": { + "description": "Sandbox or command not found" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Kill a running command (`@vercel/sandbox`-compatible). The SDK\ncalls `POST /v1/sandboxes/{id}/{cmdId}/kill` — note the path has the\ncommand ID directly under the sandbox, NOT under `/jobs/` or `/cmd/`.", + "tags": [ + "Sandboxes" + ] + } + }, + "/visitors/{visitor_id}/session-replays": { + "get": { + "operationId": "get_visitor_sessions", + "parameters": [ + { + "description": "Visitor ID", + "in": "path", + "name": "visitor_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Page number (1-based)", + "in": "query", + "name": "page", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + { + "description": "Items per page", + "in": "query", + "name": "per_page", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetVisitorSessionsResponse" + } + } + }, + "description": "Session replays retrieved successfully" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Authentication required" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Insufficient permissions" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get session replays for a visitor", + "tags": [ + "Analytics" + ] + } + }, + "/visitors/{visitor_id}/session-replays/{session_id}": { + "delete": { + "operationId": "delete_session_replay", + "parameters": [ + { + "description": "Visitor ID", + "in": "path", + "name": "visitor_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Session ID", + "in": "path", + "name": "session_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Session replay deleted successfully" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Authentication required" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Insufficient permissions" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Session not found" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Delete a session replay", + "tags": [ + "Analytics" + ] + }, + "get": { + "operationId": "get_session_replay", + "parameters": [ + { + "description": "Visitor ID", + "in": "path", + "name": "visitor_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Session ID", + "in": "path", + "name": "session_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetSessionReplayResponse" + } + } + }, + "description": "Session replay retrieved successfully" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Authentication required" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Insufficient permissions" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Session not found" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get session replay data with visitor info (without events)", + "tags": [ + "Analytics" + ] + } + }, + "/visitors/{visitor_id}/session-replays/{session_id}/duration": { + "put": { + "operationId": "update_session_duration", + "parameters": [ + { + "description": "Visitor ID", + "in": "path", + "name": "visitor_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Session ID", + "in": "path", + "name": "session_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateSessionDurationRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateSessionDurationResponse" + } + } + }, + "description": "Session duration updated successfully" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Authentication required" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Insufficient permissions" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Session not found" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Update session duration", + "tags": [ + "Analytics" + ] + } + }, + "/visitors/{visitor_id}/session-replays/{session_id}/events": { + "get": { + "operationId": "get_session_replay_events", + "parameters": [ + { + "description": "Visitor ID", + "in": "path", + "name": "visitor_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Session ID", + "in": "path", + "name": "session_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SessionReplayWithEventsDto" + } + } + }, + "description": "Session replay with events retrieved successfully" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Authentication required" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Insufficient permissions" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Session not found" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Get session replay events (with session and visitor metadata)", + "tags": [ + "Analytics" + ] + }, + "post": { + "operationId": "add_events", + "parameters": [ + { + "description": "Visitor ID", + "in": "path", + "name": "visitor_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Session ID", + "in": "path", + "name": "session_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AddEventsRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AddEventsResponse" + } + } + }, + "description": "Events added successfully" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Bad request" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Authentication required" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Insufficient permissions" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Session not found" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Add events to an existing session", + "tags": [ + "Analytics" + ] + } + }, + "/vulnerability-scans/{scan_id}": { + "delete": { + "operationId": "delete_scan", + "parameters": [ + { + "description": "Scan ID", + "in": "path", + "name": "scan_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "204": { + "description": "Scan deleted" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Scan not found" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Vulnerability Scans" + ] + }, + "get": { + "operationId": "get_scan", + "parameters": [ + { + "description": "Scan ID", + "in": "path", + "name": "scan_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ScanResponse" + } + } + }, + "description": "Scan details" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Scan not found" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Vulnerability Scans" + ] + } + }, + "/vulnerability-scans/{scan_id}/vulnerabilities": { + "get": { + "operationId": "get_scan_vulnerabilities", + "parameters": [ + { + "description": "Scan ID", + "in": "path", + "name": "scan_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Page number (default: 1)", + "in": "query", + "name": "page", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + { + "description": "Page size (default: 20, max: 100)", + "in": "query", + "name": "page_size", + "required": false, + "schema": { + "format": "int64", + "minimum": 0, + "type": "integer" + } + }, + { + "description": "Filter by severity (CRITICAL, HIGH, MEDIUM, LOW)", + "in": "query", + "name": "severity", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/VulnerabilityResponse" + }, + "type": "array" + } + } + }, + "description": "List of vulnerabilities" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Insufficient permissions" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Scan not found" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "Vulnerability Scans" + ] + } + }, + "/webhook-event-types": { + "get": { + "operationId": "list_event_types", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/EventTypeResponse" + }, + "type": "array" + } + } + }, + "description": "List of available event types" + } + }, + "summary": "List available event types", + "tags": [ + "Webhooks" + ] + } + }, + "/weekly-digest/trigger": { + "post": { + "operationId": "trigger_weekly_digest", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TriggerDigestResponse" + } + } + }, + "description": "Weekly digest triggered successfully" + }, + "500": { + "description": "Failed to generate digest" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Trigger weekly digest generation manually", + "tags": [ + "Notification Preferences" + ] + } + }, + "/x/plugins": { + "get": { + "description": "Requires only a valid session/token (no specific permission) since the\nmanifest drives sidebar navigation rendering for every authenticated\nuser, not just admins.", + "operationId": "list_external_plugins", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/PluginManifest" + }, + "type": "array" + } + } + }, + "description": "List of all running external plugins" + }, + "401": { + "description": "Unauthorized" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "List all running external plugins and their manifests.", + "tags": [ + "External Plugins" + ] + } + }, + "/x/plugins/reload": { + "post": { + "description": "Stops all running plugin processes, re-scans the plugins directory,\nstarts any discovered binaries, and hot-swaps the proxy router so new\nand removed plugins take effect immediately without a server restart.\n\nRequires `SystemAdmin` permission.", + "operationId": "reload_plugins", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ReloadResponse" + } + } + }, + "description": "Plugins reloaded successfully" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Reload all external plugins.", + "tags": [ + "External Plugins" + ] + } + }, + "/{project_id}/envelope/": { + "post": { + "operationId": "ingest_sentry_envelope", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/octet-stream": { + "schema": { + "type": "string" + } + } + }, + "description": "Sentry envelope as binary data", + "required": true + }, + "responses": { + "200": { + "description": "Envelope ingested" + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "413": { + "description": "Request body too large (exceeds 2 MiB)" + } + }, + "summary": "Ingest a Sentry envelope (binary payload)", + "tags": [ + "sentry-ingestor" + ] + } + }, + "/{project_id}/store/": { + "post": { + "operationId": "ingest_sentry_event", + "parameters": [ + { + "description": "Project ID", + "in": "path", + "name": "project_id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SentryEventRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SentryEventResponse" + } + } + }, + "description": "Event ingested" + }, + "400": { + "description": "Bad request" + }, + "401": { + "description": "Unauthorized" + }, + "413": { + "description": "Request body too large (exceeds 2 MiB)" + } + }, + "summary": "Ingest a Sentry event (JSON payload)", + "tags": [ + "sentry-ingestor" + ] + } + }, + "audit/logs": { + "get": { + "operationId": "list_audit_logs", + "parameters": [ + { + "description": "Filter logs by operation type (omit for all)", + "example": "user.login", + "in": "query", + "name": "operation_type", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Filter logs by user ID (omit for all users)", + "example": 1, + "in": "query", + "name": "user_id", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Start timestamp (milliseconds since epoch)", + "example": 1, + "in": "query", + "name": "from", + "required": false, + "schema": { + "format": "date-time", + "type": "string" + } + }, + { + "description": "End timestamp (milliseconds since epoch)", + "example": 1, + "in": "query", + "name": "to", + "required": false, + "schema": { + "format": "date-time", + "type": "string" + } + }, + { + "description": "Maximum number of logs to return", + "example": 100, + "in": "query", + "name": "limit", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + }, + { + "description": "Number of logs to skip", + "example": 0, + "in": "query", + "name": "offset", + "required": false, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/AuditLogResponse" + }, + "type": "array" + } + } + }, + "description": "List of audit logs" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "api_key": [] + } + ], + "summary": "List audit logs with optional filtering", + "tags": [ + "Audit Logs" + ] + } + }, + "audit/logs/{id}": { + "get": { + "operationId": "get_audit_log", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "format": "int32", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuditLogResponse" + } + } + }, + "description": "Audit log details" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Audit log not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "api_key": [] + } + ], + "summary": "Get a specific audit log entry by ID", + "tags": [ + "Audit Logs" + ] + } + } + }, + "servers": [ + { + "description": "Base path for all API endpoints", + "url": "/api" + } + ], + "tags": [ + { + "description": "Analytics events tracking endpoints", + "name": "Events" + }, + { + "description": "Analytics metrics collection endpoints including performance web vitals", + "name": "Metrics" + }, + { + "description": "Funnel management endpoints", + "name": "Funnels" + }, + { + "description": "Analytics and session replay management", + "name": "Analytics" + }, + { + "description": "Performance metrics management", + "name": "Performance" + }, + { + "description": "Geolocation API endpoints", + "name": "geo" + }, + { + "description": "Platform information and compatibility", + "name": "Platform" + }, + { + "description": "Teams and project-scoped access", + "name": "Teams" + }, + { + "description": "Git provider management endpoints", + "name": "Git Providers" + }, + { + "description": "Repository management endpoints", + "name": "Repositories" + }, + { + "description": "Endpoints for accessing public repositories without authentication. Supports GitHub and GitLab.", + "name": "Public Repositories" + }, + { + "description": "Notification provider management endpoints", + "name": "Notification Providers" + }, + { + "description": "User notification preferences and settings", + "name": "Notification Preferences" + }, + { + "description": "DNS provider management endpoints", + "name": "DNS Providers" + }, + { + "description": "Per-node DNS resolver sync (ADR-011)", + "name": "Internal DNS" + }, + { + "description": "Domain management endpoints", + "name": "Domains" + }, + { + "description": "Email provider management endpoints", + "name": "Email Providers" + }, + { + "description": "Email domain management and verification", + "name": "Email Domains" + }, + { + "description": "Email sending and retrieval", + "name": "Emails" + }, + { + "description": "Email open and click tracking", + "name": "Email Tracking" + }, + { + "description": "Email address validation and verification", + "name": "Email Validation" + }, + { + "description": "Webhook management endpoints", + "name": "Webhooks" + }, + { + "description": "Webhook delivery history and retry endpoints", + "name": "Webhook Deliveries" + }, + { + "description": "External service integration endpoints", + "name": "External Services" + }, + { + "description": "Data querying and exploration endpoints", + "name": "External Services - Query" + }, + { + "description": "Time-series metrics and alert rule endpoints", + "name": "Metrics" + }, + { + "description": "Key-Value storage operations", + "name": "KV Store" + }, + { + "description": "KV service management operations", + "name": "KV Management" + }, + { + "description": "Blob storage operations", + "name": "Blob" + }, + { + "description": "Blob service management operations", + "name": "Blob Management" + }, + { + "description": "Runtime configuration that changes without a redeploy", + "name": "Feature Flags" + }, + { + "description": "Environment management operations", + "name": "Environments" + }, + { + "description": "File-mounted secrets (/run/secrets/)", + "name": "Secrets" + }, + { + "description": "Project management endpoints", + "name": "Projects" + }, + { + "description": "Available deployment presets", + "name": "Presets" + }, + { + "description": "Project template endpoints", + "name": "Templates" + }, + { + "description": "Custom domain management for projects", + "name": "Custom Domains" + }, + { + "description": "Error tracking data fetching endpoints", + "name": "error-tracking" + }, + { + "description": "Vulnerability scan management endpoints", + "name": "Vulnerability Scans" + }, + { + "description": "Autonomous AI agents, autofixer (interactive AI debugging), skills/MCP definitions, and preview gateway management.", + "name": "Agents" + }, + { + "description": "Cron jobs management API", + "name": "Crons" + }, + { + "description": "Standalone sandbox API (`/v1/sandboxes/*`) for running isolated containers.", + "name": "Sandboxes" + }, + { + "description": "Log search, context, live tail, and retention management", + "name": "Logs" + }, + { + "description": "Import workloads from external sources", + "name": "Imports" + }, + { + "description": "Status page and monitoring endpoints", + "name": "Status Page" + }, + { + "description": "OTLP/HTTP ingest endpoints (protobuf)", + "name": "OTel Ingest" + }, + { + "description": "Query endpoints for the monitoring UI", + "name": "OTel" + }, + { + "description": "GenAI agent activity tracing endpoints", + "name": "GenAI" + }, + { + "description": "Unified alarm history — list, summarise, acknowledge, resolve", + "name": "Alarms" + }, + { + "description": "Authentication and authorization endpoints", + "name": "Authentication" + }, + { + "description": "User management endpoints", + "name": "Users" + }, + { + "description": "Backup management endpoints", + "name": "Backups" + }, + { + "description": "External service restore operations", + "name": "Restore" + }, + { + "description": "Per-project revenue tracking integrations and analytics", + "name": "Revenue" + }, + { + "description": "Unified observability event stream — runtime logs, requests, spans, errors, revenue", + "name": "Observability" + }, + { + "description": "OpenAI-compatible chat, embeddings, and model endpoints", + "name": "AI Gateway" + }, + { + "description": "Provider key management endpoints", + "name": "AI Gateway Admin" + }, + { + "description": "Usage analytics and reporting endpoints", + "name": "AI Gateway Usage" + }, + { + "description": "Model pricing endpoints", + "name": "AI Gateway Pricing" + }, + { + "description": "API key management endpoints", + "name": "API Keys" + }, + { + "description": "Load balancer management endpoints", + "name": "Load Balancer" + }, + { + "description": "IP access control management endpoints", + "name": "IP Access Control" + }, + { + "description": "Static file serving endpoints", + "name": "Files" + }, + { + "description": "External plugin management and discovery", + "name": "External Plugins" + } + ] +} From d7ef97873c2ce096361590123803a17d8368e63d Mon Sep 17 00:00:00 2001 From: David Viejo Date: Fri, 7 Aug 2026 12:01:49 +0200 Subject: [PATCH 6/7] build(cli): add spec:update to refresh openapi.json canonically Refreshing the CLI spec by hand (curl > openapi.json) replaced a 92,000-line formatted file with the server's minified one-liner, so every such pull request reported ~-92,000 deletions and the real change was invisible. spec:update fetches the spec, sorts keys recursively, indents by two and keeps the trailing newline, and refuses to write a document with no paths so a half-booted server cannot wipe the committed client. Document the rule and the merge-conflict procedure in CLAUDE.md and AGENTS.md. --- AGENTS.md | 58 ++++++++++++++++ CLAUDE.md | 31 +++++++++ apps/temps-cli/package.json | 1 + apps/temps-cli/scripts/update-openapi.ts | 88 ++++++++++++++++++++++++ 4 files changed, 178 insertions(+) create mode 100644 apps/temps-cli/scripts/update-openapi.ts diff --git a/AGENTS.md b/AGENTS.md index fbeb8e204..645ce37c3 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -60,6 +60,64 @@ The shortest way to spot a missing step: TypeScript compile errors in `web/src/` that say "Module ... has no exported member ...". That means the SDK is stale. +## Never overwrite `apps/temps-cli/openapi.json` with the raw server response + +The CLI's SDK is generated from a **committed** copy of the spec at +`apps/temps-cli/openapi.json`. That file is ~92,000 lines of formatted +JSON; the server serves the same document minified on one line, with +keys in whatever order serde produced. + +So `curl .../openapi.json > apps/temps-cli/openapi.json` turns a +92,000-line file into a 1-line file, and the pull request reports +**-92,000 deletions** — burying the actual change and making the diff +unreviewable. Pretty-printing alone is not enough either: key order is +not stable between builds, so an unsorted dump reorders huge blocks for +no reason. + +Use the script, which fetches, sorts keys recursively, indents by two +and keeps the trailing newline: + +```bash +cd apps/temps-cli +TEMPS_API_KEY=tk_... bun run spec:update --url http://localhost:8080/api/api-docs/openapi.json +bun run generate:api # regenerate the client from the file +bun run scripts/generate-docs.ts --output docs/CLI.md +bun run scripts/generate-docs.ts --format mdx --output docs/CLI.mdx +``` + +Sanity check before committing — a few new endpoints should be a few +hundred changed lines, never tens of thousands: + +```bash +git diff --numstat -- apps/temps-cli/openapi.json +``` + +`web/src/api/client/` has no committed spec; it is generated straight +from the live server by `bun run openapi-ts` (see above), so it does not +have this failure mode. + +## Resolving merge conflicts in generated clients + +Conflicts in `web/src/api/client/**`, `apps/temps-cli/src/api/**` or +`apps/temps-cli/openapi.json` are conflicts in **build output**. Do not +hand-merge them, and do not hand-pick hunks — the result is a client +that matches neither side's spec. + +Take either side to clear the conflict, then regenerate from a server +built off the merged source: + +```bash +git checkout --ours -- web/src/api/client apps/temps-cli/src/api apps/temps-cli/openapi.json +git add web/src/api/client apps/temps-cli/src/api apps/temps-cli/openapi.json +# build + start the merged server, then: +cd apps/temps-cli && bun run spec:update --url /api/api-docs/openapi.json && bun run generate:api +cd ../../web && bun run openapi-ts +``` + +Then `bun run typecheck` (or `npx tsc --noEmit`) in both `web/` and +`apps/temps-cli/`. A clean typecheck is what proves the regenerated +client still satisfies every caller on both sides of the merge. + ## Scope Docker usage on shared hosts This host may already be running a live Temps instance or other diff --git a/CLAUDE.md b/CLAUDE.md index 5820aa12f..5675d0194 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -21,6 +21,7 @@ Guidance for Claude Code when working with the Temps codebase. - Leave the project in non-compilable state - Use `#[tokio::main]` when integrating with pingora - Use plain text logging -- ALWAYS use structured JSONL logging +- Overwrite `apps/temps-cli/openapi.json` with the raw server response (`curl ... > openapi.json`) -- the committed file is ~92,000 lines of sorted, indented JSON and the server serves it minified on one line, so a direct write reports **-92,000 deletions** and buries the real change. ALWAYS use `cd apps/temps-cli && bun run spec:update` (see [Regenerating the OpenAPI clients](#regenerating-the-openapi-clients)) - Create markdown documentation files unless explicitly requested - Mark Docker tests with `#[ignore]` -- they MUST skip gracefully at runtime instead - Create error types with generic messages -- ALWAYS include IDs, names, and operation context @@ -731,6 +732,36 @@ async fn create_backup( - Convert entities to response DTOs via `From` trait - Register all handlers in `ApiDoc` with `#[openapi(...)]` +### Regenerating the OpenAPI clients + +Two generated clients consume the spec, and they are refreshed differently: + +| Client | Source of truth | Refresh with | +|---|---|---| +| `web/src/api/client/` | the **live server** | `cd web && bun run openapi-ts` | +| `apps/temps-cli/src/api/` | the **committed** `apps/temps-cli/openapi.json` | `cd apps/temps-cli && bun run spec:update && bun run generate:api` | + +After any change to handlers, request/response shapes, schemas or routes: +restart `temps serve`, then refresh both. Commit the regenerated files -- +they are tracked so reviewers see the API delta. + +`apps/temps-cli/openapi.json` must stay in its canonical shape: **keys sorted +recursively, two-space indent, trailing newline**. `bun run spec:update` is the +only supported way to write it. Sorting is what keeps a diff proportional to +the API change instead of to serde's iteration order, which is not stable +between builds. + +Verify before committing -- adding a few endpoints is a few hundred changed +lines, never tens of thousands: + +```bash +git diff --numstat -- apps/temps-cli/openapi.json +``` + +Merge conflicts in either client are conflicts in build output. Never +hand-merge them: take one side to clear the conflict, then regenerate from a +server built off the merged source and typecheck both packages. + ### Permission System ```rust diff --git a/apps/temps-cli/package.json b/apps/temps-cli/package.json index ba6aa1f4a..e182a6cd2 100644 --- a/apps/temps-cli/package.json +++ b/apps/temps-cli/package.json @@ -15,6 +15,7 @@ "prepublishOnly": "bun run clean && bun run build", "build": "bun build src/index.ts --outdir dist --target node && sed -i '' '1s|#!/usr/bin/env bun|#!/usr/bin/env node|' dist/index.js && chmod +x dist/index.js", "build:bin": "bun build src/index.ts --compile --outfile bin/temps", + "spec:update": "bun run scripts/update-openapi.ts", "generate:api": "bun openapi-ts", "generate:docs": "bun run scripts/generate-docs.ts", "generate:docs:mdx": "bun run scripts/generate-docs.ts --format mdx", diff --git a/apps/temps-cli/scripts/update-openapi.ts b/apps/temps-cli/scripts/update-openapi.ts new file mode 100644 index 000000000..70db52190 --- /dev/null +++ b/apps/temps-cli/scripts/update-openapi.ts @@ -0,0 +1,88 @@ +#!/usr/bin/env bun +/** + * Refresh `openapi.json` from a running temps server, in a canonical shape. + * + * Why this exists: the server emits the spec minified and with whatever key + * order serde produced. Writing that straight to disk replaces a ~92,000-line + * pretty-printed file with a single line, so the pull request reports ~-92,000 + * deletions and the real change is invisible to reviewers. Key order is not + * stable across builds either, so even a pretty-printed dump reorders large + * blocks for no reason. + * + * Canonical form is therefore: keys sorted, two-space indent, trailing + * newline. Sorting is what makes the diff proportional to the API change + * rather than to serde's iteration order. + * + * Usage: + * bun run scripts/update-openapi.ts # localhost:8080 + * bun run scripts/update-openapi.ts --url http://localhost:8220/api/api-docs/openapi.json + * TEMPS_API_KEY=tk_... bun run scripts/update-openapi.ts # if the server requires auth + * + * Then regenerate the client from the file: + * bun run generate:api + */ + +const DEFAULT_URL = 'http://localhost:8080/api/api-docs/openapi.json' +const OUTPUT = new URL('../openapi.json', import.meta.url).pathname + +/** Recursively sort object keys so the on-disk order never depends on the server. */ +function canonicalize(value: unknown): unknown { + if (Array.isArray(value)) { + // Array order is meaningful in OpenAPI (parameter lists, enum values) — + // sort the contents, never the sequence. + return value.map(canonicalize) + } + if (value && typeof value === 'object') { + const source = value as Record + return Object.fromEntries( + Object.keys(source) + .sort() + .map((key) => [key, canonicalize(source[key])]) + ) + } + return value +} + +function parseArgs(argv: string[]): { url: string } { + const index = argv.indexOf('--url') + if (index !== -1) { + const url = argv[index + 1] + if (!url) { + console.error('--url requires a value') + process.exit(1) + } + return { url } + } + return { url: process.env.TEMPS_OPENAPI_URL ?? DEFAULT_URL } +} + +const { url } = parseArgs(process.argv.slice(2)) +const apiKey = process.env.TEMPS_API_KEY + +const response = await fetch(url, { + headers: apiKey ? { Authorization: `Bearer ${apiKey}` } : {}, +}).catch((error: unknown) => { + console.error(`Could not reach ${url}: ${String(error)}`) + console.error('Start a temps server first, or pass --url.') + process.exit(1) +}) + +if (!response.ok) { + console.error(`${url} returned ${response.status}`) + if (response.status === 401 || response.status === 403) { + console.error('Set TEMPS_API_KEY to an admin key; the spec endpoint is authenticated.') + } + process.exit(1) +} + +const spec = await response.json() +if (!spec?.paths || Object.keys(spec.paths).length === 0) { + // A spec with no paths means the server answered but the doc was not + // assembled — writing it would silently delete the entire committed client. + console.error('Refusing to write: the fetched spec has no paths.') + process.exit(1) +} + +await Bun.write(OUTPUT, `${JSON.stringify(canonicalize(spec), null, 2)}\n`) +console.log(`Wrote ${OUTPUT} (${Object.keys(spec.paths).length} paths)`) +console.log('Now run: bun run generate:api') From 85ffff9691d1d93e3fcc2502d943c6341ba9d1e6 Mon Sep 17 00:00:00 2001 From: David Viejo Date: Fri, 7 Aug 2026 12:01:57 +0200 Subject: [PATCH 7/7] chore(cli): regenerate openapi spec and client Adds the platform update endpoints (/settings/update, /settings/update/check) and picks up spec drift already on main that was never regenerated (/auth/password-change-required, the analytics property-breakdown and MFA-setup shapes). self_update becomes nullable so an omitted field on a whole-document PUT preserves the stored value instead of re-enabling it. --- apps/temps-cli/openapi.json | 659 +++++++++++++++++++++++++++- apps/temps-cli/src/api/types.gen.ts | 11 +- 2 files changed, 657 insertions(+), 13 deletions(-) diff --git a/apps/temps-cli/openapi.json b/apps/temps-cli/openapi.json index f319005a3..0f0cc9519 100644 --- a/apps/temps-cli/openapi.json +++ b/apps/temps-cli/openapi.json @@ -2423,6 +2423,18 @@ } ] }, + "self_update": { + "default": null, + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/SelfUpdateSettings", + "description": "One-click \"Update now\" from the console. Enabled by default; an admin\ncan turn it off here to keep upgrades on the CLI/config-management path.\n\nThis is the *soft* switch — it is stored in the database, so whoever can\nwrite settings can also turn it back on. Operators who need an upgrade\npath that no console session can re-open should start the server with\n`--disable-self-update`, which wins over this field unconditionally.\n`None` means the client did not express an opinion, NOT \"reset to\ndefault\". Every other field on this struct is safe to re-default on a\npartial write, but this one gates whether the server may replace its own\nbinary — silently flipping it back on because an older client PUT a\nsettings document without it would undo a deliberate security decision.\nThe update handler preserves the stored value when this is absent; read\nit through `self_update()`." + } + ] + }, "setup_complete": { "default": false, "description": "Set to `true` by `temps setup` (all modes) once initial configuration\nhas been applied. The web onboarding wizard reads this from the server\nand skips itself when true, preventing the \"Configure Base Domain\" wall\nfrom appearing on installs that were already configured via the CLI.", @@ -2539,6 +2551,10 @@ "security_headers": { "$ref": "#/components/schemas/SecurityHeadersSettings" }, + "self_update": { + "$ref": "#/components/schemas/SelfUpdateSettings", + "description": "Whether admins may apply a release from the console. This is the\ndatabase-backed toggle only — a server started with\n`--disable-self-update` refuses regardless of what this says, which\n`GET /settings/update` reports as the authoritative answer." + }, "setup_complete": { "description": "Whether `temps setup` has been run at least once. The web onboarding\nwizard checks this field on load and skips itself when true.", "type": "boolean" @@ -2568,7 +2584,8 @@ "require_mfa_for_admins", "cluster_dns", "build_limits", - "ai_chat_limits" + "ai_chat_limits", + "self_update" ], "type": "object" }, @@ -2840,9 +2857,25 @@ "message": { "type": "string" }, + "mfa_enrollment_required": { + "type": "boolean" + }, "mfa_required": { "type": "boolean" }, + "mfa_setup": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/MfaSetupResponse" + } + ] + }, + "password_change_required": { + "type": "boolean" + }, "success": { "type": "boolean" }, @@ -2857,7 +2890,9 @@ "required": [ "success", "message", - "mfa_required" + "mfa_required", + "mfa_enrollment_required", + "password_change_required" ], "type": "object" }, @@ -8264,6 +8299,9 @@ "null" ] }, + "must_change_password": { + "type": "boolean" + }, "password": { "type": [ "string", @@ -9802,6 +9840,28 @@ "null" ] }, + "sourceBundleContentType": { + "description": "Uploaded source archive content type.", + "type": [ + "string", + "null" + ] + }, + "sourceBundleId": { + "description": "Uploaded source archive ID. Source archives are extracted before the\nregular preset build pipeline and do not require Git metadata.", + "format": "int32", + "type": [ + "integer", + "null" + ] + }, + "sourceBundlePath": { + "description": "Uploaded source archive path in the Temps data directory.", + "type": [ + "string", + "null" + ] + }, "staticBundleContentType": { "description": "Static bundle content type (for proper extraction: application/gzip or application/zip)", "type": [ @@ -27496,6 +27556,13 @@ "$ref": "#/components/schemas/PropertyColumn", "description": "Property column to group by" }, + "include_crawlers": { + "description": "Include crawler/bot traffic (default: false). Off by default so the\nbreakdown percentages share a denominator with the headline counts,\nwhich always exclude crawlers.", + "type": [ + "boolean", + "null" + ] + }, "limit": { "description": "Maximum number of results to return (default: 20, max: 100)", "format": "int32", @@ -27631,6 +27698,13 @@ "$ref": "#/components/schemas/PropertyColumn", "description": "Property column to group by" }, + "include_crawlers": { + "description": "Include crawler/bot traffic (default: false). See\n[`PropertyBreakdownQuery::include_crawlers`].", + "type": [ + "boolean", + "null" + ] + }, "start_date": { "description": "Start date for the query range", "format": "date-time", @@ -28576,7 +28650,7 @@ "type": "integer" }, "truncated": { - "description": "Whether rows were dropped from this response to stay inside the byte budget.\n\n`returned_count` is always the number of rows actually present, so a truncated page is still internally consistent — but a caller comparing it against the requested limit would otherwise conclude the table simply ended. Reported explicitly so a partial page is never mistaken for a complete one, by a human, a script, or a model reading a tool result.", + "description": "Whether rows were dropped from this response to stay inside the byte\nbudget.\n\n`returned_count` is always the number of rows actually present, so a\ntruncated page is still internally consistent — but a caller comparing\nit against the requested limit would otherwise conclude the table simply\nended. Reported explicitly so a partial page is never mistaken for a\ncomplete one, by a human, a script, or a model reading a tool result.", "example": false, "type": "boolean" } @@ -29365,6 +29439,43 @@ ], "type": "object" }, + "ReleaseCheckResult": { + "description": "Outcome of an operator-triggered release check.", + "properties": { + "channel": { + "description": "Channel that was queried.", + "type": "string" + }, + "current_version": { + "description": "Version tag of the running binary.", + "type": "string" + }, + "latest_version": { + "description": "Newest release published on that channel, if any could be resolved.", + "type": [ + "string", + "null" + ] + }, + "release_url": { + "description": "Release-notes page for `latest_version`.", + "type": [ + "string", + "null" + ] + }, + "update_available": { + "description": "True when `latest_version` is strictly newer than what is running.\nFalse on a channel whose newest release is older — which is normal and\nexpected right after switching a nightly box onto stable.", + "type": "boolean" + } + }, + "required": [ + "channel", + "current_version", + "update_available" + ], + "type": "object" + }, "ReleaseListResponse": { "properties": { "releases": { @@ -29798,6 +29909,51 @@ ], "type": "object" }, + "RequiredPasswordChangeRequest": { + "properties": { + "new_password": { + "type": "string" + } + }, + "required": [ + "new_password" + ], + "type": "object" + }, + "RequiredPasswordChangeResponse": { + "properties": { + "message": { + "type": "string" + }, + "mfa_enrollment_required": { + "type": "boolean" + }, + "mfa_setup": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/MfaSetupResponse" + } + ] + }, + "success": { + "type": "boolean" + }, + "user_id": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "success", + "message", + "user_id", + "mfa_enrollment_required" + ], + "type": "object" + }, "ResetPasswordRequest": { "properties": { "new_password": { @@ -30883,6 +31039,9 @@ "mfa_enabled": { "type": "boolean" }, + "must_change_password": { + "type": "boolean" + }, "name": { "type": "string" }, @@ -30903,6 +31062,7 @@ "image", "mfa_enabled", "email_verified", + "must_change_password", "created_at", "updated_at" ], @@ -32200,6 +32360,131 @@ }, "type": "object" }, + "SelfUpdateAttempt": { + "description": "A single update attempt. Persisted to `/self-update.json` so the\nresult survives the restart it causes.", + "properties": { + "error": { + "description": "Operator-facing failure reason. Always set when `status` is `Failed`.", + "type": [ + "string", + "null" + ] + }, + "finished_at": { + "description": "When the outcome was decided. `None` while still `Pending`.", + "format": "date-time", + "type": [ + "string", + "null" + ] + }, + "from_version": { + "description": "Version the attempt started from.", + "type": "string" + }, + "previous_binary_path": { + "description": "Where the replaced binary was kept, so a bad release can be reverted by\nhand (`mv `). Set once the swap completes.", + "type": [ + "string", + "null" + ] + }, + "started_at": { + "example": "2026-08-06T09:12:31Z", + "format": "date-time", + "type": "string" + }, + "status": { + "$ref": "#/components/schemas/SelfUpdateStatus" + }, + "to_version": { + "description": "Version the attempt targeted. `None` if it failed before resolving one.", + "type": [ + "string", + "null" + ] + }, + "triggered_by_user_id": { + "description": "User who clicked the button. `None` for attempts started by the CLI.", + "format": "int32", + "type": [ + "integer", + "null" + ] + } + }, + "required": [ + "from_version", + "status", + "started_at" + ], + "type": "object" + }, + "SelfUpdateBlocker": { + "description": "Why a one-click update is unavailable. Exactly one is reported — the most\nfundamental blocker wins, so the operator fixes the real problem first\nrather than clearing one only to hit the next.", + "enum": [ + "disabled_by_flag", + "disabled_by_setting", + "not_supported", + "binary_not_writable", + "unsupported_platform", + "in_progress" + ], + "type": "string" + }, + "SelfUpdatePhase": { + "description": "Where an in-flight update has got to. Polled by the console so a long\ndownload shows progress instead of an indefinite spinner.", + "enum": [ + "idle", + "resolving", + "downloading", + "verifying", + "installing", + "restarting", + "pending_restart", + "failed" + ], + "type": "string" + }, + "SelfUpdateRestartMode": { + "description": "What happens to the running process once the new binary is in place.", + "enum": [ + "automatic", + "manual" + ], + "type": "string" + }, + "SelfUpdateSettings": { + "description": "Controls the console's one-click \"Update now\" action.", + "properties": { + "channel": { + "default": null, + "description": "Release channel this install tracks: `stable`, `beta` or `nightly`.\n\n`None` (the default) means \"infer from the running version tag\", which\nis what the CLI has always done — a `-nightly.` build tracks nightly, a\n`-beta.N` build tracks beta, a plain tag tracks stable. Setting it\nexplicitly pins the channel, so an operator can move a nightly box back\nonto stable without reinstalling.", + "example": "stable", + "type": [ + "string", + "null" + ] + }, + "enabled": { + "default": true, + "description": "Allow admins to apply a release and restart the server from the console.\n`true` by default: the action is permission-gated, audited, and only\never installs an official release whose published SHA-256 matches.\n\nTurning this off hides nothing — the console still shows the update\nbanner and the manual command, it just refuses to run it for you.", + "example": true, + "type": "boolean" + } + }, + "type": "object" + }, + "SelfUpdateStatus": { + "description": "Outcome of an update attempt, as persisted in the journal.", + "enum": [ + "pending", + "succeeded", + "installed_pending_restart", + "failed" + ], + "type": "string" + }, "SendEmailRequestBody": { "properties": { "bcc": { @@ -35992,6 +36277,48 @@ } ] }, + "StartUpdateRequest": { + "description": "Optional pin for the version to install.", + "properties": { + "version": { + "description": "Release tag to install (e.g. `v0.2.0`). Omit to take the newest release\non the channel this install already tracks.", + "type": [ + "string", + "null" + ] + } + }, + "type": "object" + }, + "StartUpdateResponse": { + "description": "Acknowledgement that an update was accepted and is running.", + "properties": { + "current_version": { + "description": "Version the server is running as it accepts this request.", + "type": "string" + }, + "estimated_restart_secs": { + "description": "How long to allow for the server to come back before treating the\nrestart as failed. `0` when nothing restarts.", + "format": "int64", + "minimum": 0, + "type": "integer" + }, + "message": { + "type": "string" + }, + "restart_mode": { + "$ref": "#/components/schemas/SelfUpdateRestartMode", + "description": "`automatic` (temps restarts itself) or `manual` (installed only)." + } + }, + "required": [ + "current_version", + "estimated_restart_secs", + "restart_mode", + "message" + ], + "type": "object" + }, "StatResponse": { "properties": { "exists": { @@ -36629,6 +36956,16 @@ }, "type": "object" }, + "SupervisorKind": { + "description": "What (if anything) will restart the process after it exits.", + "enum": [ + "systemd", + "launchd", + "container", + "none" + ], + "type": "string" + }, "SyncedRepositoryListQuery": { "properties": { "direction": { @@ -38536,6 +38873,107 @@ ], "type": "object" }, + "UpdateCapabilityResponse": { + "description": "Whether this install can apply a release update on request, and how the last\nattempt went.\n\nDeliberately answerable even when the answer is \"no\": an operator who cannot\nuse the button still needs to know *why* and what to run instead, so this\nnever 404s or returns an empty body when the feature is unavailable.", + "properties": { + "allowed": { + "description": "Whether the *caller* holds `platform:update`. Distinct from `can_apply`,\nwhich describes the server: the console shows the action only when both\nare true, so a reader is never offered a button that would 403.", + "type": "boolean" + }, + "binary_path": { + "description": "Binary that would be replaced.", + "type": "string" + }, + "blocker": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/SelfUpdateBlocker", + "description": "Machine-readable reason `can_apply` is false (`disabled_by_flag`,\n`disabled_by_setting`, `container`, `no_supervisor`, `binary_not_writable`,\n`unsupported_platform`, `in_progress`)." + } + ] + }, + "can_apply": { + "description": "True only when a request would actually download, install and restart.", + "type": "boolean" + }, + "caveat": { + "description": "Non-blocking warning to show with the confirmation (split topology).", + "type": [ + "string", + "null" + ] + }, + "channel": { + "description": "Channel actually tracked, after applying the configured override or\nfalling back to inference from the running version tag.", + "type": "string" + }, + "channel_is_pinned": { + "description": "True when `channel` was set explicitly in settings rather than inferred.", + "type": "boolean" + }, + "current_version": { + "description": "Version tag of the running binary. Always present — the version page\nneeds it whether or not an update exists.", + "type": "string" + }, + "last_attempt": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/SelfUpdateAttempt", + "description": "Most recent attempt, including one resolved during this boot — this is\nhow the console reports the outcome of an update that restarted it." + } + ] + }, + "manual_command": { + "description": "The equivalent command to run by hand. Always present.", + "type": "string" + }, + "phase": { + "$ref": "#/components/schemas/SelfUpdatePhase", + "description": "Phase of an in-flight attempt: `idle` when none is running." + }, + "phase_error": { + "description": "Failure detail while `phase` is `failed`.", + "type": [ + "string", + "null" + ] + }, + "reason": { + "description": "Operator-facing explanation of `blocker`.", + "type": [ + "string", + "null" + ] + }, + "restart_mode": { + "$ref": "#/components/schemas/SelfUpdateRestartMode", + "description": "`automatic` when applying an update also restarts temps; `manual` when\nit only installs the binary and the operator restarts on their own\nschedule. Lets the console set expectations before the click." + }, + "supervisor": { + "$ref": "#/components/schemas/SupervisorKind", + "description": "What would restart the process: `systemd`, `launchd`, `container`, `none`." + } + }, + "required": [ + "can_apply", + "allowed", + "manual_command", + "current_version", + "channel", + "channel_is_pinned", + "supervisor", + "restart_mode", + "binary_path", + "phase" + ], + "type": "object" + }, "UpdateCloudflareProviderRequest": { "properties": { "config": { @@ -48472,6 +48910,45 @@ ] } }, + "/auth/password-change-required": { + "post": { + "operationId": "change_required_password", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RequiredPasswordChangeRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RequiredPasswordChangeResponse" + } + } + }, + "description": "Required password change completed" + }, + "400": { + "description": "Password does not meet requirements" + }, + "401": { + "description": "Password-change session is missing or expired" + }, + "500": { + "description": "Internal server error" + } + }, + "tags": [ + "Authentication" + ] + } + }, "/auth/password-reset/request": { "post": { "operationId": "request_password_reset", @@ -77631,6 +78108,15 @@ "type": "integer" } }, + { + "description": "Include crawler/bot traffic (default: false)", + "in": "query", + "name": "include_crawlers", + "required": false, + "schema": { + "type": "boolean" + } + }, { "description": "Filter by country (for region/city drill-downs)", "in": "query", @@ -77805,6 +78291,15 @@ "schema": { "type": "string" } + }, + { + "description": "Include crawler/bot traffic (default: false)", + "in": "query", + "name": "include_crawlers", + "required": false, + "schema": { + "type": "boolean" + } } ], "responses": { @@ -82468,6 +82963,16 @@ } } ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "$ref": "#/components/schemas/SourceArchiveUpload" + } + } + }, + "required": true + }, "responses": { "201": { "content": { @@ -87968,6 +88473,99 @@ ] } }, + "/settings/update": { + "get": { + "operationId": "get_update_capability", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateCapabilityResponse" + } + } + }, + "description": "Self-update capability for this install" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Report whether a release update can be applied from the console.", + "tags": [ + "Settings" + ] + }, + "post": { + "description": "Returns as soon as the attempt is accepted: the download and swap run in the\nbackground and the process then exits so its supervisor restarts it on the\nnew binary. Poll `GET /settings/update` for progress — after the restart,\n`last_attempt` carries the outcome.", + "operationId": "start_update", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StartUpdateRequest" + } + } + }, + "required": true + }, + "responses": { + "202": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StartUpdateResponse" + } + } + }, + "description": "Update accepted; the server will restart" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "409": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "Update unavailable or already running" + }, + "501": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "This process cannot apply updates" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Install a release and restart the server.", + "tags": [ + "Settings" + ] + } + }, "/settings/update-status": { "get": { "operationId": "get_update_status", @@ -88000,6 +88598,58 @@ ] } }, + "/settings/update/check": { + "post": { + "operationId": "check_for_update", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ReleaseCheckResult" + } + } + }, + "description": "Result of the release check" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Insufficient permissions" + }, + "501": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "This process cannot check for updates" + }, + "502": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + }, + "description": "The release API could not be reached" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "summary": "Ask the release API for the newest version on this install's channel, now,\ninstead of waiting for the background notifier's next pass.", + "tags": [ + "Settings" + ] + } + }, "/teams": { "get": { "operationId": "list_teams", @@ -88819,6 +89469,9 @@ "401": { "description": "Unauthorized" }, + "409": { + "description": "MFA is already enabled; verify and disable it before re-enrollment" + }, "500": { "description": "Internal server error" } diff --git a/apps/temps-cli/src/api/types.gen.ts b/apps/temps-cli/src/api/types.gen.ts index a00e376ca..a654cb468 100644 --- a/apps/temps-cli/src/api/types.gen.ts +++ b/apps/temps-cli/src/api/types.gen.ts @@ -1105,16 +1105,7 @@ export type AppSettings = { require_mfa_for_admins?: boolean; screenshots?: ScreenshotSettings; security_headers?: SecurityHeadersSettings; - /** - * One-click "Update now" from the console. Enabled by default; an admin - * can turn it off here to keep upgrades on the CLI/config-management path. - * - * This is the *soft* switch — it is stored in the database, so whoever can - * write settings can also turn it back on. Operators who need an upgrade - * path that no console session can re-open should start the server with - * `--disable-self-update`, which wins over this field unconditionally. - */ - self_update?: SelfUpdateSettings; + self_update?: null | SelfUpdateSettings; /** * Set to `true` by `temps setup` (all modes) once initial configuration * has been applied. The web onboarding wizard reads this from the server